(window["webpackJsonpGUI"] = window["webpackJsonpGUI"] || []).push([["vendors~editor~embed~fullscreen~player"],{ /***/ "./node_modules/@babel/runtime/helpers/interopRequireDefault.js": /*!**********************************************************************!*\ !*** ./node_modules/@babel/runtime/helpers/interopRequireDefault.js ***! \**********************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } module.exports = _interopRequireDefault; /***/ }), /***/ "./node_modules/@scratch/paper/dist/paper-full.js": /*!********************************************************!*\ !*** ./node_modules/@scratch/paper/dist/paper-full.js ***! \********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! * Paper.js v0.12.7 - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * * Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey * http://juerglehni.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * * All rights reserved. * * Date: Tue Jul 28 15:52:11 2020 -0400 * *** * * Straps.js - Class inheritance library with support for bean-style accessors * * Copyright (c) 2006 - 2020 Jürg Lehni * http://juerglehni.com/ * * Distributed under the MIT license. * *** * * Acorn.js * https://marijnhaverbeke.nl/acorn/ * * Acorn is a tiny, fast JavaScript parser written in JavaScript, * created by Marijn Haverbeke and released under an MIT license. * */ var paper = function(self, undefined) { self = self || __webpack_require__(/*! ./node/self.js */ 6); var window = self.window ? self.window : self, document = self.document; var Base = new function() { var hidden = /^(statics|enumerable|beans|preserve)$/, array = [], slice = array.slice, create = Object.create, describe = Object.getOwnPropertyDescriptor, define = Object.defineProperty, forEach = array.forEach || function(iter, bind) { for (var i = 0, l = this.length; i < l; i++) { iter.call(bind, this[i], i, this); } }, forIn = function(iter, bind) { for (var i in this) { if (this.hasOwnProperty(i)) iter.call(bind, this[i], i, this); } }, set = Object.assign || function(dst) { for (var i = 1, l = arguments.length; i < l; i++) { var src = arguments[i]; for (var key in src) { if (src.hasOwnProperty(key)) dst[key] = src[key]; } } return dst; }, each = function(obj, iter, bind) { if (obj) { var desc = describe(obj, 'length'); (desc && typeof desc.value === 'number' ? forEach : forIn) .call(obj, iter, bind = bind || obj); } return bind; }; function inject(dest, src, enumerable, beans, preserve) { var beansNames = {}; function field(name, val) { val = val || (val = describe(src, name)) && (val.get ? val : val.value); if (typeof val === 'string' && val[0] === '#') val = dest[val.substring(1)] || val; var isFunc = typeof val === 'function', res = val, prev = preserve || isFunc && !val.base ? (val && val.get ? name in dest : dest[name]) : null, bean; if (!preserve || !prev) { if (isFunc && prev) val.base = prev; if (isFunc && beans !== false && (bean = name.match(/^([gs]et|is)(([A-Z])(.*))$/))) beansNames[bean[3].toLowerCase() + bean[4]] = bean[2]; if (!res || isFunc || !res.get || typeof res.get !== 'function' || !Base.isPlainObject(res)) { res = { value: res, writable: true }; } if ((describe(dest, name) || { configurable: true }).configurable) { res.configurable = true; res.enumerable = enumerable != null ? enumerable : !bean; } define(dest, name, res); } } if (src) { for (var name in src) { if (src.hasOwnProperty(name) && !hidden.test(name)) field(name); } for (var name in beansNames) { var part = beansNames[name], set = dest['set' + part], get = dest['get' + part] || set && dest['is' + part]; if (get && (beans === true || get.length === 0)) field(name, { get: get, set: set }); } } return dest; } function Base() { for (var i = 0, l = arguments.length; i < l; i++) { var src = arguments[i]; if (src) set(this, src); } return this; } return inject(Base, { inject: function(src) { if (src) { var statics = src.statics === true ? src : src.statics, beans = src.beans, preserve = src.preserve; if (statics !== src) inject(this.prototype, src, src.enumerable, beans, preserve); inject(this, statics, null, beans, preserve); } for (var i = 1, l = arguments.length; i < l; i++) this.inject(arguments[i]); return this; }, extend: function() { var base = this, ctor, proto; for (var i = 0, obj, l = arguments.length; i < l && !(ctor && proto); i++) { obj = arguments[i]; ctor = ctor || obj.initialize; proto = proto || obj.prototype; } ctor = ctor || function() { base.apply(this, arguments); }; proto = ctor.prototype = proto || create(this.prototype); define(proto, 'constructor', { value: ctor, writable: true, configurable: true }); inject(ctor, this); if (arguments.length) this.inject.apply(ctor, arguments); ctor.base = base; return ctor; } }).inject({ enumerable: false, initialize: Base, set: Base, inject: function() { for (var i = 0, l = arguments.length; i < l; i++) { var src = arguments[i]; if (src) { inject(this, src, src.enumerable, src.beans, src.preserve); } } return this; }, extend: function() { var res = create(this); return res.inject.apply(res, arguments); }, each: function(iter, bind) { return each(this, iter, bind); }, clone: function() { return new this.constructor(this); }, statics: { set: set, each: each, create: create, define: define, describe: describe, clone: function(obj) { return set(new obj.constructor(), obj); }, isPlainObject: function(obj) { var ctor = obj != null && obj.constructor; return ctor && (ctor === Object || ctor === Base || ctor.name === 'Object'); }, pick: function(a, b) { return a !== undefined ? a : b; }, slice: function(list, begin, end) { return slice.call(list, begin, end); } } }); }; if (true) module.exports = Base; Base.inject({ enumerable: false, toString: function() { return this._id != null ? (this._class || 'Object') + (this._name ? " '" + this._name + "'" : ' @' + this._id) : '{ ' + Base.each(this, function(value, key) { if (!/^_/.test(key)) { var type = typeof value; this.push(key + ': ' + (type === 'number' ? Formatter.instance.number(value) : type === 'string' ? "'" + value + "'" : value)); } }, []).join(', ') + ' }'; }, getClassName: function() { return this._class || ''; }, importJSON: function(json) { return Base.importJSON(json, this); }, exportJSON: function(options) { return Base.exportJSON(this, options); }, toJSON: function() { return Base.serialize(this); }, set: function(props, exclude) { if (props) Base.filter(this, props, exclude, this._prioritize); return this; } }, { beans: false, statics: { exports: {}, extend: function extend() { var res = extend.base.apply(this, arguments), name = res.prototype._class; if (name && !Base.exports[name]) Base.exports[name] = res; return res; }, equals: function(obj1, obj2) { if (obj1 === obj2) return true; if (obj1 && obj1.equals) return obj1.equals(obj2); if (obj2 && obj2.equals) return obj2.equals(obj1); if (obj1 && obj2 && typeof obj1 === 'object' && typeof obj2 === 'object') { if (Array.isArray(obj1) && Array.isArray(obj2)) { var length = obj1.length; if (length !== obj2.length) return false; while (length--) { if (!Base.equals(obj1[length], obj2[length])) return false; } } else { var keys = Object.keys(obj1), length = keys.length; if (length !== Object.keys(obj2).length) return false; while (length--) { var key = keys[length]; if (!(obj2.hasOwnProperty(key) && Base.equals(obj1[key], obj2[key]))) return false; } } return true; } return false; }, read: function(list, start, options, amount) { if (this === Base) { var value = this.peek(list, start); list.__index++; return value; } var proto = this.prototype, readIndex = proto._readIndex, begin = start || readIndex && list.__index || 0, length = list.length, obj = list[begin]; amount = amount || length - begin; if (obj instanceof this || options && options.readNull && obj == null && amount <= 1) { if (readIndex) list.__index = begin + 1; return obj && options && options.clone ? obj.clone() : obj; } obj = Base.create(proto); if (readIndex) obj.__read = true; obj = obj.initialize.apply(obj, begin > 0 || begin + amount < length ? Base.slice(list, begin, begin + amount) : list) || obj; if (readIndex) { list.__index = begin + obj.__read; var filtered = obj.__filtered; if (filtered) { list.__filtered = filtered; obj.__filtered = undefined; } obj.__read = undefined; } return obj; }, peek: function(list, start) { return list[list.__index = start || list.__index || 0]; }, remain: function(list) { return list.length - (list.__index || 0); }, readList: function(list, start, options, amount) { var res = [], entry, begin = start || 0, end = amount ? begin + amount : list.length; for (var i = begin; i < end; i++) { res.push(Array.isArray(entry = list[i]) ? this.read(entry, 0, options) : this.read(list, i, options, 1)); } return res; }, readNamed: function(list, name, start, options, amount) { var value = this.getNamed(list, name), hasValue = value !== undefined; if (hasValue) { var filtered = list.__filtered; if (!filtered) { var source = this.getSource(list); filtered = list.__filtered = Base.create(source); filtered.__unfiltered = source; } filtered[name] = undefined; } return this.read(hasValue ? [value] : list, start, options, amount); }, readSupported: function(list, dest) { var source = this.getSource(list), that = this, read = false; if (source) { Object.keys(source).forEach(function(key) { if (key in dest) { var value = that.readNamed(list, key); if (value !== undefined) { dest[key] = value; } read = true; } }); } return read; }, getSource: function(list) { var source = list.__source; if (source === undefined) { var arg = list.length === 1 && list[0]; source = list.__source = arg && Base.isPlainObject(arg) ? arg : null; } return source; }, getNamed: function(list, name) { var source = this.getSource(list); if (source) { return name ? source[name] : list.__filtered || source; } }, hasNamed: function(list, name) { return !!this.getNamed(list, name); }, filter: function(dest, source, exclude, prioritize) { var processed; function handleKey(key) { if (!(exclude && key in exclude) && !(processed && key in processed)) { var value = source[key]; if (value !== undefined) dest[key] = value; } } if (prioritize) { var keys = {}; for (var i = 0, key, l = prioritize.length; i < l; i++) { if ((key = prioritize[i]) in source) { handleKey(key); keys[key] = true; } } processed = keys; } Object.keys(source.__unfiltered || source).forEach(handleKey); return dest; }, isPlainValue: function(obj, asString) { return Base.isPlainObject(obj) || Array.isArray(obj) || asString && typeof obj === 'string'; }, serialize: function(obj, options, compact, dictionary) { options = options || {}; var isRoot = !dictionary, res; if (isRoot) { options.formatter = new Formatter(options.precision); dictionary = { length: 0, definitions: {}, references: {}, add: function(item, create) { var id = '#' + item._id, ref = this.references[id]; if (!ref) { this.length++; var res = create.call(item), name = item._class; if (name && res[0] !== name) res.unshift(name); this.definitions[id] = res; ref = this.references[id] = [id]; } return ref; } }; } if (obj && obj._serialize) { res = obj._serialize(options, dictionary); var name = obj._class; if (name && !obj._compactSerialize && (isRoot || !compact) && res[0] !== name) { res.unshift(name); } } else if (Array.isArray(obj)) { res = []; for (var i = 0, l = obj.length; i < l; i++) res[i] = Base.serialize(obj[i], options, compact, dictionary); } else if (Base.isPlainObject(obj)) { res = {}; var keys = Object.keys(obj); for (var i = 0, l = keys.length; i < l; i++) { var key = keys[i]; res[key] = Base.serialize(obj[key], options, compact, dictionary); } } else if (typeof obj === 'number') { res = options.formatter.number(obj, options.precision); } else { res = obj; } return isRoot && dictionary.length > 0 ? [['dictionary', dictionary.definitions], res] : res; }, deserialize: function(json, create, _data, _setDictionary, _isRoot) { var res = json, isFirst = !_data, hasDictionary = isFirst && json && json.length && json[0][0] === 'dictionary'; _data = _data || {}; if (Array.isArray(json)) { var type = json[0], isDictionary = type === 'dictionary'; if (json.length == 1 && /^#/.test(type)) { return _data.dictionary[type]; } type = Base.exports[type]; res = []; for (var i = type ? 1 : 0, l = json.length; i < l; i++) { res.push(Base.deserialize(json[i], create, _data, isDictionary, hasDictionary)); } if (type) { var args = res; if (create) { res = create(type, args, isFirst || _isRoot); } else { res = new type(args); } } } else if (Base.isPlainObject(json)) { res = {}; if (_setDictionary) _data.dictionary = res; for (var key in json) res[key] = Base.deserialize(json[key], create, _data); } return hasDictionary ? res[1] : res; }, exportJSON: function(obj, options) { var json = Base.serialize(obj, options); return options && options.asString == false ? json : JSON.stringify(json); }, importJSON: function(json, target) { return Base.deserialize( typeof json === 'string' ? JSON.parse(json) : json, function(ctor, args, isRoot) { var useTarget = isRoot && target && target.constructor === ctor, obj = useTarget ? target : Base.create(ctor.prototype); if (args.length === 1 && obj instanceof Item && (useTarget || !(obj instanceof Layer))) { var arg = args[0]; if (Base.isPlainObject(arg)) { arg.insert = false; if (useTarget) { args = args.concat([{ insert: true }]); } } } (useTarget ? obj.set : ctor).apply(obj, args); if (useTarget) target = null; return obj; }); }, push: function(list, items) { var itemsLength = items.length; if (itemsLength < 4096) { list.push.apply(list, items); } else { var startLength = list.length; list.length += itemsLength; for (var i = 0; i < itemsLength; i++) { list[startLength + i] = items[i]; } } return list; }, splice: function(list, items, index, remove) { var amount = items && items.length, append = index === undefined; index = append ? list.length : index; if (index > list.length) index = list.length; for (var i = 0; i < amount; i++) items[i]._index = index + i; if (append) { Base.push(list, items); return []; } else { var args = [index, remove]; if (items) Base.push(args, items); var removed = list.splice.apply(list, args); for (var i = 0, l = removed.length; i < l; i++) removed[i]._index = undefined; for (var i = index + amount, l = list.length; i < l; i++) list[i]._index = i; return removed; } }, capitalize: function(str) { return str.replace(/\b[a-z]/g, function(match) { return match.toUpperCase(); }); }, camelize: function(str) { return str.replace(/-(.)/g, function(match, chr) { return chr.toUpperCase(); }); }, hyphenate: function(str) { return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); } }}); var Emitter = { on: function(type, func) { if (typeof type !== 'string') { Base.each(type, function(value, key) { this.on(key, value); }, this); } else { var types = this._eventTypes, entry = types && types[type], handlers = this._callbacks = this._callbacks || {}; handlers = handlers[type] = handlers[type] || []; if (handlers.indexOf(func) === -1) { handlers.push(func); if (entry && entry.install && handlers.length === 1) entry.install.call(this, type); } } return this; }, off: function(type, func) { if (typeof type !== 'string') { Base.each(type, function(value, key) { this.off(key, value); }, this); return; } var types = this._eventTypes, entry = types && types[type], handlers = this._callbacks && this._callbacks[type], index; if (handlers) { if (!func || (index = handlers.indexOf(func)) !== -1 && handlers.length === 1) { if (entry && entry.uninstall) entry.uninstall.call(this, type); delete this._callbacks[type]; } else if (index !== -1) { handlers.splice(index, 1); } } return this; }, once: function(type, func) { return this.on(type, function handler() { func.apply(this, arguments); this.off(type, handler); }); }, emit: function(type, event) { var handlers = this._callbacks && this._callbacks[type]; if (!handlers) return false; var args = Base.slice(arguments, 1), setTarget = event && event.target && !event.currentTarget; handlers = handlers.slice(); if (setTarget) event.currentTarget = this; for (var i = 0, l = handlers.length; i < l; i++) { if (handlers[i].apply(this, args) == false) { if (event && event.stop) event.stop(); break; } } if (setTarget) delete event.currentTarget; return true; }, responds: function(type) { return !!(this._callbacks && this._callbacks[type]); }, attach: '#on', detach: '#off', fire: '#emit', _installEvents: function(install) { var types = this._eventTypes, handlers = this._callbacks, key = install ? 'install' : 'uninstall'; if (types) { for (var type in handlers) { if (handlers[type].length > 0) { var entry = types[type], func = entry && entry[key]; if (func) func.call(this, type); } } } }, statics: { inject: function inject(src) { var events = src._events; if (events) { var types = {}; Base.each(events, function(entry, key) { var isString = typeof entry === 'string', name = isString ? entry : key, part = Base.capitalize(name), type = name.substring(2).toLowerCase(); types[type] = isString ? {} : entry; name = '_' + name; src['get' + part] = function() { return this[name]; }; src['set' + part] = function(func) { var prev = this[name]; if (prev) this.off(type, prev); if (func) this.on(type, func); this[name] = func; }; }); src._eventTypes = types; } return inject.base.apply(this, arguments); } } }; var PaperScope = Base.extend({ _class: 'PaperScope', initialize: function PaperScope() { paper = this; this.settings = new Base({ applyMatrix: true, insertItems: true, handleSize: 4, hitTolerance: 0 }); this.project = null; this.projects = []; this.tools = []; this._id = PaperScope._id++; PaperScope._scopes[this._id] = this; var proto = PaperScope.prototype; if (!this.support) { var ctx = CanvasProvider.getContext(1, 1) || {}; proto.support = { nativeDash: 'setLineDash' in ctx || 'mozDash' in ctx, nativeBlendModes: BlendMode.nativeModes }; CanvasProvider.release(ctx); } if (!this.agent) { var user = self.navigator.userAgent.toLowerCase(), os = (/(darwin|win|mac|linux|freebsd|sunos)/.exec(user)||[])[0], platform = os === 'darwin' ? 'mac' : os, agent = proto.agent = proto.browser = { platform: platform }; if (platform) agent[platform] = true; user.replace( /(opera|chrome|safari|webkit|firefox|msie|trident|atom|node|jsdom)\/?\s*([.\d]+)(?:.*version\/([.\d]+))?(?:.*rv\:v?([.\d]+))?/g, function(match, n, v1, v2, rv) { if (!agent.chrome) { var v = n === 'opera' ? v2 : /^(node|trident)$/.test(n) ? rv : v1; agent.version = v; agent.versionNumber = parseFloat(v); n = { trident: 'msie', jsdom: 'node' }[n] || n; agent.name = n; agent[n] = true; } } ); if (agent.chrome) delete agent.webkit; if (agent.atom) delete agent.chrome; } }, version: "0.12.7", getView: function() { var project = this.project; return project && project._view; }, getPaper: function() { return this; }, execute: function(code, options) { var exports = paper.PaperScript.execute(code, this, options); View.updateFocus(); return exports; }, install: function(scope) { var that = this; Base.each(['project', 'view', 'tool'], function(key) { Base.define(scope, key, { configurable: true, get: function() { return that[key]; } }); }); for (var key in this) if (!/^_/.test(key) && this[key]) scope[key] = this[key]; }, setup: function(element) { paper = this; this.project = new Project(element); return this; }, createCanvas: function(width, height) { return CanvasProvider.getCanvas(width, height); }, activate: function() { paper = this; }, clear: function() { var projects = this.projects, tools = this.tools; for (var i = projects.length - 1; i >= 0; i--) projects[i].remove(); for (var i = tools.length - 1; i >= 0; i--) tools[i].remove(); }, remove: function() { this.clear(); delete PaperScope._scopes[this._id]; }, statics: new function() { function handleAttribute(name) { name += 'Attribute'; return function(el, attr) { return el[name](attr) || el[name]('data-paper-' + attr); }; } return { _scopes: {}, _id: 0, get: function(id) { return this._scopes[id] || null; }, getAttribute: handleAttribute('get'), hasAttribute: handleAttribute('has') }; } }); var PaperScopeItem = Base.extend(Emitter, { initialize: function(activate) { this._scope = paper; this._index = this._scope[this._list].push(this) - 1; if (activate || !this._scope[this._reference]) this.activate(); }, activate: function() { if (!this._scope) return false; var prev = this._scope[this._reference]; if (prev && prev !== this) prev.emit('deactivate'); this._scope[this._reference] = this; this.emit('activate', prev); return true; }, isActive: function() { return this._scope[this._reference] === this; }, remove: function() { if (this._index == null) return false; Base.splice(this._scope[this._list], null, this._index, 1); if (this._scope[this._reference] == this) this._scope[this._reference] = null; this._scope = null; return true; }, getView: function() { return this._scope.getView(); } }); var CollisionDetection = { findItemBoundsCollisions: function(items1, items2, tolerance) { function getBounds(items) { var bounds = new Array(items.length); for (var i = 0; i < items.length; i++) { var rect = items[i].getBounds(); bounds[i] = [rect.left, rect.top, rect.right, rect.bottom]; } return bounds; } var bounds1 = getBounds(items1), bounds2 = !items2 || items2 === items1 ? bounds1 : getBounds(items2); return this.findBoundsCollisions(bounds1, bounds2, tolerance || 0); }, findCurveBoundsCollisions: function(curves1, curves2, tolerance, bothAxis) { function getBounds(curves) { var min = Math.min, max = Math.max, bounds = new Array(curves.length); for (var i = 0; i < curves.length; i++) { var v = curves[i]; bounds[i] = [ min(v[0], v[2], v[4], v[6]), min(v[1], v[3], v[5], v[7]), max(v[0], v[2], v[4], v[6]), max(v[1], v[3], v[5], v[7]) ]; } return bounds; } var bounds1 = getBounds(curves1), bounds2 = !curves2 || curves2 === curves1 ? bounds1 : getBounds(curves2); if (bothAxis) { var hor = this.findBoundsCollisions( bounds1, bounds2, tolerance || 0, false, true), ver = this.findBoundsCollisions( bounds1, bounds2, tolerance || 0, true, true), list = []; for (var i = 0, l = hor.length; i < l; i++) { list[i] = { hor: hor[i], ver: ver[i] }; } return list; } return this.findBoundsCollisions(bounds1, bounds2, tolerance || 0); }, findBoundsCollisions: function(boundsA, boundsB, tolerance, sweepVertical, onlySweepAxisCollisions) { var self = !boundsB || boundsA === boundsB, allBounds = self ? boundsA : boundsA.concat(boundsB), lengthA = boundsA.length, lengthAll = allBounds.length; function binarySearch(indices, coord, value) { var lo = 0, hi = indices.length; while (lo < hi) { var mid = (hi + lo) >>> 1; if (allBounds[indices[mid]][coord] < value) { lo = mid + 1; } else { hi = mid; } } return lo - 1; } var pri0 = sweepVertical ? 1 : 0, pri1 = pri0 + 2, sec0 = sweepVertical ? 0 : 1, sec1 = sec0 + 2; var allIndicesByPri0 = new Array(lengthAll); for (var i = 0; i < lengthAll; i++) { allIndicesByPri0[i] = i; } allIndicesByPri0.sort(function(i1, i2) { return allBounds[i1][pri0] - allBounds[i2][pri0]; }); var activeIndicesByPri1 = [], allCollisions = new Array(lengthA); for (var i = 0; i < lengthAll; i++) { var curIndex = allIndicesByPri0[i], curBounds = allBounds[curIndex], origIndex = self ? curIndex : curIndex - lengthA, isCurrentA = curIndex < lengthA, isCurrentB = self || !isCurrentA, curCollisions = isCurrentA ? [] : null; if (activeIndicesByPri1.length) { var pruneCount = binarySearch(activeIndicesByPri1, pri1, curBounds[pri0] - tolerance) + 1; activeIndicesByPri1.splice(0, pruneCount); if (self && onlySweepAxisCollisions) { curCollisions = curCollisions.concat(activeIndicesByPri1); for (var j = 0; j < activeIndicesByPri1.length; j++) { var activeIndex = activeIndicesByPri1[j]; allCollisions[activeIndex].push(origIndex); } } else { var curSec1 = curBounds[sec1], curSec0 = curBounds[sec0]; for (var j = 0; j < activeIndicesByPri1.length; j++) { var activeIndex = activeIndicesByPri1[j], activeBounds = allBounds[activeIndex], isActiveA = activeIndex < lengthA, isActiveB = self || activeIndex >= lengthA; if ( onlySweepAxisCollisions || ( isCurrentA && isActiveB || isCurrentB && isActiveA ) && ( curSec1 >= activeBounds[sec0] - tolerance && curSec0 <= activeBounds[sec1] + tolerance ) ) { if (isCurrentA && isActiveB) { curCollisions.push( self ? activeIndex : activeIndex - lengthA); } if (isCurrentB && isActiveA) { allCollisions[activeIndex].push(origIndex); } } } } } if (isCurrentA) { if (boundsA === boundsB) { curCollisions.push(curIndex); } allCollisions[curIndex] = curCollisions; } if (activeIndicesByPri1.length) { var curPri1 = curBounds[pri1], index = binarySearch(activeIndicesByPri1, pri1, curPri1); activeIndicesByPri1.splice(index + 1, 0, curIndex); } else { activeIndicesByPri1.push(curIndex); } } for (var i = 0; i < allCollisions.length; i++) { var collisions = allCollisions[i]; if (collisions) { collisions.sort(function(i1, i2) { return i1 - i2; }); } } return allCollisions; } }; var Formatter = Base.extend({ initialize: function(precision) { this.precision = Base.pick(precision, 5); this.multiplier = Math.pow(10, this.precision); }, number: function(val) { return this.precision < 16 ? Math.round(val * this.multiplier) / this.multiplier : val; }, pair: function(val1, val2, separator) { return this.number(val1) + (separator || ',') + this.number(val2); }, point: function(val, separator) { return this.number(val.x) + (separator || ',') + this.number(val.y); }, size: function(val, separator) { return this.number(val.width) + (separator || ',') + this.number(val.height); }, rectangle: function(val, separator) { return this.point(val, separator) + (separator || ',') + this.size(val, separator); } }); Formatter.instance = new Formatter(); var Numerical = new function() { var abscissas = [ [ 0.5773502691896257645091488], [0,0.7745966692414833770358531], [ 0.3399810435848562648026658,0.8611363115940525752239465], [0,0.5384693101056830910363144,0.9061798459386639927976269], [ 0.2386191860831969086305017,0.6612093864662645136613996,0.9324695142031520278123016], [0,0.4058451513773971669066064,0.7415311855993944398638648,0.9491079123427585245261897], [ 0.1834346424956498049394761,0.5255324099163289858177390,0.7966664774136267395915539,0.9602898564975362316835609], [0,0.3242534234038089290385380,0.6133714327005903973087020,0.8360311073266357942994298,0.9681602395076260898355762], [ 0.1488743389816312108848260,0.4333953941292471907992659,0.6794095682990244062343274,0.8650633666889845107320967,0.9739065285171717200779640], [0,0.2695431559523449723315320,0.5190961292068118159257257,0.7301520055740493240934163,0.8870625997680952990751578,0.9782286581460569928039380], [ 0.1252334085114689154724414,0.3678314989981801937526915,0.5873179542866174472967024,0.7699026741943046870368938,0.9041172563704748566784659,0.9815606342467192506905491], [0,0.2304583159551347940655281,0.4484927510364468528779129,0.6423493394403402206439846,0.8015780907333099127942065,0.9175983992229779652065478,0.9841830547185881494728294], [ 0.1080549487073436620662447,0.3191123689278897604356718,0.5152486363581540919652907,0.6872929048116854701480198,0.8272013150697649931897947,0.9284348836635735173363911,0.9862838086968123388415973], [0,0.2011940939974345223006283,0.3941513470775633698972074,0.5709721726085388475372267,0.7244177313601700474161861,0.8482065834104272162006483,0.9372733924007059043077589,0.9879925180204854284895657], [ 0.0950125098376374401853193,0.2816035507792589132304605,0.4580167776572273863424194,0.6178762444026437484466718,0.7554044083550030338951012,0.8656312023878317438804679,0.9445750230732325760779884,0.9894009349916499325961542] ]; var weights = [ [1], [0.8888888888888888888888889,0.5555555555555555555555556], [0.6521451548625461426269361,0.3478548451374538573730639], [0.5688888888888888888888889,0.4786286704993664680412915,0.2369268850561890875142640], [0.4679139345726910473898703,0.3607615730481386075698335,0.1713244923791703450402961], [0.4179591836734693877551020,0.3818300505051189449503698,0.2797053914892766679014678,0.1294849661688696932706114], [0.3626837833783619829651504,0.3137066458778872873379622,0.2223810344533744705443560,0.1012285362903762591525314], [0.3302393550012597631645251,0.3123470770400028400686304,0.2606106964029354623187429,0.1806481606948574040584720,0.0812743883615744119718922], [0.2955242247147528701738930,0.2692667193099963550912269,0.2190863625159820439955349,0.1494513491505805931457763,0.0666713443086881375935688], [0.2729250867779006307144835,0.2628045445102466621806889,0.2331937645919904799185237,0.1862902109277342514260976,0.1255803694649046246346943,0.0556685671161736664827537], [0.2491470458134027850005624,0.2334925365383548087608499,0.2031674267230659217490645,0.1600783285433462263346525,0.1069393259953184309602547,0.0471753363865118271946160], [0.2325515532308739101945895,0.2262831802628972384120902,0.2078160475368885023125232,0.1781459807619457382800467,0.1388735102197872384636018,0.0921214998377284479144218,0.0404840047653158795200216], [0.2152638534631577901958764,0.2051984637212956039659241,0.1855383974779378137417166,0.1572031671581935345696019,0.1215185706879031846894148,0.0801580871597602098056333,0.0351194603317518630318329], [0.2025782419255612728806202,0.1984314853271115764561183,0.1861610000155622110268006,0.1662692058169939335532009,0.1395706779261543144478048,0.1071592204671719350118695,0.0703660474881081247092674,0.0307532419961172683546284], [0.1894506104550684962853967,0.1826034150449235888667637,0.1691565193950025381893121,0.1495959888165767320815017,0.1246289712555338720524763,0.0951585116824927848099251,0.0622535239386478928628438,0.0271524594117540948517806] ]; var abs = Math.abs, sqrt = Math.sqrt, pow = Math.pow, log2 = Math.log2 || function(x) { return Math.log(x) * Math.LOG2E; }, EPSILON = 1e-12, MACHINE_EPSILON = 1.12e-16; function clamp(value, min, max) { return value < min ? min : value > max ? max : value; } function getDiscriminant(a, b, c) { function split(v) { var x = v * 134217729, y = v - x, hi = y + x, lo = v - hi; return [hi, lo]; } var D = b * b - a * c, E = b * b + a * c; if (abs(D) * 3 < E) { var ad = split(a), bd = split(b), cd = split(c), p = b * b, dp = (bd[0] * bd[0] - p + 2 * bd[0] * bd[1]) + bd[1] * bd[1], q = a * c, dq = (ad[0] * cd[0] - q + ad[0] * cd[1] + ad[1] * cd[0]) + ad[1] * cd[1]; D = (p - q) + (dp - dq); } return D; } function getNormalizationFactor() { var norm = Math.max.apply(Math, arguments); return norm && (norm < 1e-8 || norm > 1e8) ? pow(2, -Math.round(log2(norm))) : 0; } return { EPSILON: EPSILON, MACHINE_EPSILON: MACHINE_EPSILON, CURVETIME_EPSILON: 1e-8, GEOMETRIC_EPSILON: 1e-7, TRIGONOMETRIC_EPSILON: 1e-8, KAPPA: 4 * (sqrt(2) - 1) / 3, isZero: function(val) { return val >= -EPSILON && val <= EPSILON; }, isMachineZero: function(val) { return val >= -MACHINE_EPSILON && val <= MACHINE_EPSILON; }, clamp: clamp, integrate: function(f, a, b, n) { var x = abscissas[n - 2], w = weights[n - 2], A = (b - a) * 0.5, B = A + a, i = 0, m = (n + 1) >> 1, sum = n & 1 ? w[i++] * f(B) : 0; while (i < m) { var Ax = A * x[i]; sum += w[i++] * (f(B + Ax) + f(B - Ax)); } return A * sum; }, findRoot: function(f, df, x, a, b, n, tolerance) { for (var i = 0; i < n; i++) { var fx = f(x), dx = fx / df(x), nx = x - dx; if (abs(dx) < tolerance) { x = nx; break; } if (fx > 0) { b = x; x = nx <= a ? (a + b) * 0.5 : nx; } else { a = x; x = nx >= b ? (a + b) * 0.5 : nx; } } return clamp(x, a, b); }, solveQuadratic: function(a, b, c, roots, min, max) { var x1, x2 = Infinity; if (abs(a) < EPSILON) { if (abs(b) < EPSILON) return abs(c) < EPSILON ? -1 : 0; x1 = -c / b; } else { b *= -0.5; var D = getDiscriminant(a, b, c); if (D && abs(D) < MACHINE_EPSILON) { var f = getNormalizationFactor(abs(a), abs(b), abs(c)); if (f) { a *= f; b *= f; c *= f; D = getDiscriminant(a, b, c); } } if (D >= -MACHINE_EPSILON) { var Q = D < 0 ? 0 : sqrt(D), R = b + (b < 0 ? -Q : Q); if (R === 0) { x1 = c / a; x2 = -x1; } else { x1 = R / a; x2 = c / R; } } } var count = 0, boundless = min == null, minB = min - EPSILON, maxB = max + EPSILON; if (isFinite(x1) && (boundless || x1 > minB && x1 < maxB)) roots[count++] = boundless ? x1 : clamp(x1, min, max); if (x2 !== x1 && isFinite(x2) && (boundless || x2 > minB && x2 < maxB)) roots[count++] = boundless ? x2 : clamp(x2, min, max); return count; }, solveCubic: function(a, b, c, d, roots, min, max) { var f = getNormalizationFactor(abs(a), abs(b), abs(c), abs(d)), x, b1, c2, qd, q; if (f) { a *= f; b *= f; c *= f; d *= f; } function evaluate(x0) { x = x0; var tmp = a * x; b1 = tmp + b; c2 = b1 * x + c; qd = (tmp + b1) * x + c2; q = c2 * x + d; } if (abs(a) < EPSILON) { a = b; b1 = c; c2 = d; x = Infinity; } else if (abs(d) < EPSILON) { b1 = b; c2 = c; x = 0; } else { evaluate(-(b / a) / 3); var t = q / a, r = pow(abs(t), 1/3), s = t < 0 ? -1 : 1, td = -qd / a, rd = td > 0 ? 1.324717957244746 * Math.max(r, sqrt(td)) : r, x0 = x - s * rd; if (x0 !== x) { do { evaluate(x0); x0 = qd === 0 ? x : x - q / qd / (1 + MACHINE_EPSILON); } while (s * x0 > s * x); if (abs(a) * x * x > abs(d / x)) { c2 = -d / x; b1 = (c2 - c) / x; } } } var count = Numerical.solveQuadratic(a, b1, c2, roots, min, max), boundless = min == null; if (isFinite(x) && (count === 0 || count > 0 && x !== roots[0] && x !== roots[1]) && (boundless || x > min - EPSILON && x < max + EPSILON)) roots[count++] = boundless ? x : clamp(x, min, max); return count; } }; }; var UID = { _id: 1, _pools: {}, get: function(name) { if (name) { var pool = this._pools[name]; if (!pool) pool = this._pools[name] = { _id: 1 }; return pool._id++; } else { return this._id++; } } }; var Point = Base.extend({ _class: 'Point', _readIndex: true, initialize: function Point(arg0, arg1) { var type = typeof arg0, reading = this.__read, read = 0; if (type === 'number') { var hasY = typeof arg1 === 'number'; this._set(arg0, hasY ? arg1 : arg0); if (reading) read = hasY ? 2 : 1; } else if (type === 'undefined' || arg0 === null) { this._set(0, 0); if (reading) read = arg0 === null ? 1 : 0; } else { var obj = type === 'string' ? arg0.split(/[\s,]+/) || [] : arg0; read = 1; if (Array.isArray(obj)) { this._set(+obj[0], +(obj.length > 1 ? obj[1] : obj[0])); } else if ('x' in obj) { this._set(obj.x || 0, obj.y || 0); } else if ('width' in obj) { this._set(obj.width || 0, obj.height || 0); } else if ('angle' in obj) { this._set(obj.length || 0, 0); this.setAngle(obj.angle || 0); } else { this._set(0, 0); read = 0; } } if (reading) this.__read = read; return this; }, set: '#initialize', _set: function(x, y) { this.x = x; this.y = y; return this; }, equals: function(point) { return this === point || point && (this.x === point.x && this.y === point.y || Array.isArray(point) && this.x === point[0] && this.y === point[1]) || false; }, clone: function() { return new Point(this.x, this.y); }, toString: function() { var f = Formatter.instance; return '{ x: ' + f.number(this.x) + ', y: ' + f.number(this.y) + ' }'; }, _serialize: function(options) { var f = options.formatter; return [f.number(this.x), f.number(this.y)]; }, getLength: function() { return Math.sqrt(this.x * this.x + this.y * this.y); }, setLength: function(length) { if (this.isZero()) { var angle = this._angle || 0; this._set( Math.cos(angle) * length, Math.sin(angle) * length ); } else { var scale = length / this.getLength(); if (Numerical.isZero(scale)) this.getAngle(); this._set( this.x * scale, this.y * scale ); } }, getAngle: function() { return this.getAngleInRadians.apply(this, arguments) * 180 / Math.PI; }, setAngle: function(angle) { this.setAngleInRadians.call(this, angle * Math.PI / 180); }, getAngleInDegrees: '#getAngle', setAngleInDegrees: '#setAngle', getAngleInRadians: function() { if (!arguments.length) { return this.isZero() ? this._angle || 0 : this._angle = Math.atan2(this.y, this.x); } else { var point = Point.read(arguments), div = this.getLength() * point.getLength(); if (Numerical.isZero(div)) { return NaN; } else { var a = this.dot(point) / div; return Math.acos(a < -1 ? -1 : a > 1 ? 1 : a); } } }, setAngleInRadians: function(angle) { this._angle = angle; if (!this.isZero()) { var length = this.getLength(); this._set( Math.cos(angle) * length, Math.sin(angle) * length ); } }, getQuadrant: function() { return this.x >= 0 ? this.y >= 0 ? 1 : 4 : this.y >= 0 ? 2 : 3; } }, { beans: false, getDirectedAngle: function() { var point = Point.read(arguments); return Math.atan2(this.cross(point), this.dot(point)) * 180 / Math.PI; }, getDistance: function() { var args = arguments, point = Point.read(args), x = point.x - this.x, y = point.y - this.y, d = x * x + y * y, squared = Base.read(args); return squared ? d : Math.sqrt(d); }, normalize: function(length) { if (length === undefined) length = 1; var current = this.getLength(), scale = current !== 0 ? length / current : 0, point = new Point(this.x * scale, this.y * scale); if (scale >= 0) point._angle = this._angle; return point; }, rotate: function(angle, center) { if (angle === 0) return this.clone(); angle = angle * Math.PI / 180; var point = center ? this.subtract(center) : this, sin = Math.sin(angle), cos = Math.cos(angle); point = new Point( point.x * cos - point.y * sin, point.x * sin + point.y * cos ); return center ? point.add(center) : point; }, transform: function(matrix) { return matrix ? matrix._transformPoint(this) : this; }, add: function() { var point = Point.read(arguments); return new Point(this.x + point.x, this.y + point.y); }, subtract: function() { var point = Point.read(arguments); return new Point(this.x - point.x, this.y - point.y); }, multiply: function() { var point = Point.read(arguments); return new Point(this.x * point.x, this.y * point.y); }, divide: function() { var point = Point.read(arguments); return new Point(this.x / point.x, this.y / point.y); }, modulo: function() { var point = Point.read(arguments); return new Point(this.x % point.x, this.y % point.y); }, negate: function() { return new Point(-this.x, -this.y); }, isInside: function() { return Rectangle.read(arguments).contains(this); }, isClose: function() { var args = arguments, point = Point.read(args), tolerance = Base.read(args); return this.getDistance(point) <= tolerance; }, isCollinear: function() { var point = Point.read(arguments); return Point.isCollinear(this.x, this.y, point.x, point.y); }, isColinear: '#isCollinear', isOrthogonal: function() { var point = Point.read(arguments); return Point.isOrthogonal(this.x, this.y, point.x, point.y); }, isZero: function() { var isZero = Numerical.isZero; return isZero(this.x) && isZero(this.y); }, isNaN: function() { return isNaN(this.x) || isNaN(this.y); }, isInQuadrant: function(q) { return this.x * (q > 1 && q < 4 ? -1 : 1) >= 0 && this.y * (q > 2 ? -1 : 1) >= 0; }, dot: function() { var point = Point.read(arguments); return this.x * point.x + this.y * point.y; }, cross: function() { var point = Point.read(arguments); return this.x * point.y - this.y * point.x; }, project: function() { var point = Point.read(arguments), scale = point.isZero() ? 0 : this.dot(point) / point.dot(point); return new Point( point.x * scale, point.y * scale ); }, statics: { min: function() { var args = arguments, point1 = Point.read(args), point2 = Point.read(args); return new Point( Math.min(point1.x, point2.x), Math.min(point1.y, point2.y) ); }, max: function() { var args = arguments, point1 = Point.read(args), point2 = Point.read(args); return new Point( Math.max(point1.x, point2.x), Math.max(point1.y, point2.y) ); }, random: function() { return new Point(Math.random(), Math.random()); }, isCollinear: function(x1, y1, x2, y2) { return Math.abs(x1 * y2 - y1 * x2) <= Math.sqrt((x1 * x1 + y1 * y1) * (x2 * x2 + y2 * y2)) * 1e-8; }, isOrthogonal: function(x1, y1, x2, y2) { return Math.abs(x1 * x2 + y1 * y2) <= Math.sqrt((x1 * x1 + y1 * y1) * (x2 * x2 + y2 * y2)) * 1e-8; } } }, Base.each(['round', 'ceil', 'floor', 'abs'], function(key) { var op = Math[key]; this[key] = function() { return new Point(op(this.x), op(this.y)); }; }, {})); var LinkedPoint = Point.extend({ initialize: function Point(x, y, owner, setter) { this._x = x; this._y = y; this._owner = owner; this._setter = setter; }, _set: function(x, y, _dontNotify) { this._x = x; this._y = y; if (!_dontNotify) this._owner[this._setter](this); return this; }, getX: function() { return this._x; }, setX: function(x) { this._x = x; this._owner[this._setter](this); }, getY: function() { return this._y; }, setY: function(y) { this._y = y; this._owner[this._setter](this); }, isSelected: function() { return !!(this._owner._selection & this._getSelection()); }, setSelected: function(selected) { this._owner._changeSelection(this._getSelection(), selected); }, _getSelection: function() { return this._setter === 'setPosition' ? 4 : 0; } }); var Size = Base.extend({ _class: 'Size', _readIndex: true, initialize: function Size(arg0, arg1) { var type = typeof arg0, reading = this.__read, read = 0; if (type === 'number') { var hasHeight = typeof arg1 === 'number'; this._set(arg0, hasHeight ? arg1 : arg0); if (reading) read = hasHeight ? 2 : 1; } else if (type === 'undefined' || arg0 === null) { this._set(0, 0); if (reading) read = arg0 === null ? 1 : 0; } else { var obj = type === 'string' ? arg0.split(/[\s,]+/) || [] : arg0; read = 1; if (Array.isArray(obj)) { this._set(+obj[0], +(obj.length > 1 ? obj[1] : obj[0])); } else if ('width' in obj) { this._set(obj.width || 0, obj.height || 0); } else if ('x' in obj) { this._set(obj.x || 0, obj.y || 0); } else { this._set(0, 0); read = 0; } } if (reading) this.__read = read; return this; }, set: '#initialize', _set: function(width, height) { this.width = width; this.height = height; return this; }, equals: function(size) { return size === this || size && (this.width === size.width && this.height === size.height || Array.isArray(size) && this.width === size[0] && this.height === size[1]) || false; }, clone: function() { return new Size(this.width, this.height); }, toString: function() { var f = Formatter.instance; return '{ width: ' + f.number(this.width) + ', height: ' + f.number(this.height) + ' }'; }, _serialize: function(options) { var f = options.formatter; return [f.number(this.width), f.number(this.height)]; }, add: function() { var size = Size.read(arguments); return new Size(this.width + size.width, this.height + size.height); }, subtract: function() { var size = Size.read(arguments); return new Size(this.width - size.width, this.height - size.height); }, multiply: function() { var size = Size.read(arguments); return new Size(this.width * size.width, this.height * size.height); }, divide: function() { var size = Size.read(arguments); return new Size(this.width / size.width, this.height / size.height); }, modulo: function() { var size = Size.read(arguments); return new Size(this.width % size.width, this.height % size.height); }, negate: function() { return new Size(-this.width, -this.height); }, isZero: function() { var isZero = Numerical.isZero; return isZero(this.width) && isZero(this.height); }, isNaN: function() { return isNaN(this.width) || isNaN(this.height); }, statics: { min: function(size1, size2) { return new Size( Math.min(size1.width, size2.width), Math.min(size1.height, size2.height)); }, max: function(size1, size2) { return new Size( Math.max(size1.width, size2.width), Math.max(size1.height, size2.height)); }, random: function() { return new Size(Math.random(), Math.random()); } } }, Base.each(['round', 'ceil', 'floor', 'abs'], function(key) { var op = Math[key]; this[key] = function() { return new Size(op(this.width), op(this.height)); }; }, {})); var LinkedSize = Size.extend({ initialize: function Size(width, height, owner, setter) { this._width = width; this._height = height; this._owner = owner; this._setter = setter; }, _set: function(width, height, _dontNotify) { this._width = width; this._height = height; if (!_dontNotify) this._owner[this._setter](this); return this; }, getWidth: function() { return this._width; }, setWidth: function(width) { this._width = width; this._owner[this._setter](this); }, getHeight: function() { return this._height; }, setHeight: function(height) { this._height = height; this._owner[this._setter](this); } }); var Rectangle = Base.extend({ _class: 'Rectangle', _readIndex: true, beans: true, initialize: function Rectangle(arg0, arg1, arg2, arg3) { var args = arguments, type = typeof arg0, read; if (type === 'number') { this._set(arg0, arg1, arg2, arg3); read = 4; } else if (type === 'undefined' || arg0 === null) { this._set(0, 0, 0, 0); read = arg0 === null ? 1 : 0; } else if (args.length === 1) { if (Array.isArray(arg0)) { this._set.apply(this, arg0); read = 1; } else if (arg0.x !== undefined || arg0.width !== undefined) { this._set(arg0.x || 0, arg0.y || 0, arg0.width || 0, arg0.height || 0); read = 1; } else if (arg0.from === undefined && arg0.to === undefined) { this._set(0, 0, 0, 0); if (Base.readSupported(args, this)) { read = 1; } } } if (read === undefined) { var frm = Point.readNamed(args, 'from'), next = Base.peek(args), x = frm.x, y = frm.y, width, height; if (next && next.x !== undefined || Base.hasNamed(args, 'to')) { var to = Point.readNamed(args, 'to'); width = to.x - x; height = to.y - y; if (width < 0) { x = to.x; width = -width; } if (height < 0) { y = to.y; height = -height; } } else { var size = Size.read(args); width = size.width; height = size.height; } this._set(x, y, width, height); read = args.__index; } var filtered = args.__filtered; if (filtered) this.__filtered = filtered; if (this.__read) this.__read = read; return this; }, set: '#initialize', _set: function(x, y, width, height) { this.x = x; this.y = y; this.width = width; this.height = height; return this; }, clone: function() { return new Rectangle(this.x, this.y, this.width, this.height); }, equals: function(rect) { var rt = Base.isPlainValue(rect) ? Rectangle.read(arguments) : rect; return rt === this || rt && this.x === rt.x && this.y === rt.y && this.width === rt.width && this.height === rt.height || false; }, toString: function() { var f = Formatter.instance; return '{ x: ' + f.number(this.x) + ', y: ' + f.number(this.y) + ', width: ' + f.number(this.width) + ', height: ' + f.number(this.height) + ' }'; }, _serialize: function(options) { var f = options.formatter; return [f.number(this.x), f.number(this.y), f.number(this.width), f.number(this.height)]; }, getPoint: function(_dontLink) { var ctor = _dontLink ? Point : LinkedPoint; return new ctor(this.x, this.y, this, 'setPoint'); }, setPoint: function() { var point = Point.read(arguments); this.x = point.x; this.y = point.y; }, getSize: function(_dontLink) { var ctor = _dontLink ? Size : LinkedSize; return new ctor(this.width, this.height, this, 'setSize'); }, _fw: 1, _fh: 1, setSize: function() { var size = Size.read(arguments), sx = this._sx, sy = this._sy, w = size.width, h = size.height; if (sx) { this.x += (this.width - w) * sx; } if (sy) { this.y += (this.height - h) * sy; } this.width = w; this.height = h; this._fw = this._fh = 1; }, getLeft: function() { return this.x; }, setLeft: function(left) { if (!this._fw) { var amount = left - this.x; this.width -= this._sx === 0.5 ? amount * 2 : amount; } this.x = left; this._sx = this._fw = 0; }, getTop: function() { return this.y; }, setTop: function(top) { if (!this._fh) { var amount = top - this.y; this.height -= this._sy === 0.5 ? amount * 2 : amount; } this.y = top; this._sy = this._fh = 0; }, getRight: function() { return this.x + this.width; }, setRight: function(right) { if (!this._fw) { var amount = right - this.x; this.width = this._sx === 0.5 ? amount * 2 : amount; } this.x = right - this.width; this._sx = 1; this._fw = 0; }, getBottom: function() { return this.y + this.height; }, setBottom: function(bottom) { if (!this._fh) { var amount = bottom - this.y; this.height = this._sy === 0.5 ? amount * 2 : amount; } this.y = bottom - this.height; this._sy = 1; this._fh = 0; }, getCenterX: function() { return this.x + this.width / 2; }, setCenterX: function(x) { if (this._fw || this._sx === 0.5) { this.x = x - this.width / 2; } else { if (this._sx) { this.x += (x - this.x) * 2 * this._sx; } this.width = (x - this.x) * 2; } this._sx = 0.5; this._fw = 0; }, getCenterY: function() { return this.y + this.height / 2; }, setCenterY: function(y) { if (this._fh || this._sy === 0.5) { this.y = y - this.height / 2; } else { if (this._sy) { this.y += (y - this.y) * 2 * this._sy; } this.height = (y - this.y) * 2; } this._sy = 0.5; this._fh = 0; }, getCenter: function(_dontLink) { var ctor = _dontLink ? Point : LinkedPoint; return new ctor(this.getCenterX(), this.getCenterY(), this, 'setCenter'); }, setCenter: function() { var point = Point.read(arguments); this.setCenterX(point.x); this.setCenterY(point.y); return this; }, getArea: function() { return this.width * this.height; }, isEmpty: function() { return this.width === 0 || this.height === 0; }, contains: function(arg) { return arg && arg.width !== undefined || (Array.isArray(arg) ? arg : arguments).length === 4 ? this._containsRectangle(Rectangle.read(arguments)) : this._containsPoint(Point.read(arguments)); }, _containsPoint: function(point) { var x = point.x, y = point.y; return x >= this.x && y >= this.y && x <= this.x + this.width && y <= this.y + this.height; }, _containsRectangle: function(rect) { var x = rect.x, y = rect.y; return x >= this.x && y >= this.y && x + rect.width <= this.x + this.width && y + rect.height <= this.y + this.height; }, intersects: function() { var rect = Rectangle.read(arguments), epsilon = Base.read(arguments) || 0; return rect.x + rect.width > this.x - epsilon && rect.y + rect.height > this.y - epsilon && rect.x < this.x + this.width + epsilon && rect.y < this.y + this.height + epsilon; }, intersect: function() { var rect = Rectangle.read(arguments), x1 = Math.max(this.x, rect.x), y1 = Math.max(this.y, rect.y), x2 = Math.min(this.x + this.width, rect.x + rect.width), y2 = Math.min(this.y + this.height, rect.y + rect.height); return new Rectangle(x1, y1, x2 - x1, y2 - y1); }, unite: function() { var rect = Rectangle.read(arguments), x1 = Math.min(this.x, rect.x), y1 = Math.min(this.y, rect.y), x2 = Math.max(this.x + this.width, rect.x + rect.width), y2 = Math.max(this.y + this.height, rect.y + rect.height); return new Rectangle(x1, y1, x2 - x1, y2 - y1); }, include: function() { var point = Point.read(arguments); var x1 = Math.min(this.x, point.x), y1 = Math.min(this.y, point.y), x2 = Math.max(this.x + this.width, point.x), y2 = Math.max(this.y + this.height, point.y); return new Rectangle(x1, y1, x2 - x1, y2 - y1); }, expand: function() { var amount = Size.read(arguments), hor = amount.width, ver = amount.height; return new Rectangle(this.x - hor / 2, this.y - ver / 2, this.width + hor, this.height + ver); }, scale: function(hor, ver) { return this.expand(this.width * hor - this.width, this.height * (ver === undefined ? hor : ver) - this.height); } }, Base.each([ ['Top', 'Left'], ['Top', 'Right'], ['Bottom', 'Left'], ['Bottom', 'Right'], ['Left', 'Center'], ['Top', 'Center'], ['Right', 'Center'], ['Bottom', 'Center'] ], function(parts, index) { var part = parts.join(''), xFirst = /^[RL]/.test(part); if (index >= 4) parts[1] += xFirst ? 'Y' : 'X'; var x = parts[xFirst ? 0 : 1], y = parts[xFirst ? 1 : 0], getX = 'get' + x, getY = 'get' + y, setX = 'set' + x, setY = 'set' + y, get = 'get' + part, set = 'set' + part; this[get] = function(_dontLink) { var ctor = _dontLink ? Point : LinkedPoint; return new ctor(this[getX](), this[getY](), this, set); }; this[set] = function() { var point = Point.read(arguments); this[setX](point.x); this[setY](point.y); }; }, { beans: true } )); var LinkedRectangle = Rectangle.extend({ initialize: function Rectangle(x, y, width, height, owner, setter) { this._set(x, y, width, height, true); this._owner = owner; this._setter = setter; }, _set: function(x, y, width, height, _dontNotify) { this._x = x; this._y = y; this._width = width; this._height = height; if (!_dontNotify) this._owner[this._setter](this); return this; } }, new function() { var proto = Rectangle.prototype; return Base.each(['x', 'y', 'width', 'height'], function(key) { var part = Base.capitalize(key), internal = '_' + key; this['get' + part] = function() { return this[internal]; }; this['set' + part] = function(value) { this[internal] = value; if (!this._dontNotify) this._owner[this._setter](this); }; }, Base.each(['Point', 'Size', 'Center', 'Left', 'Top', 'Right', 'Bottom', 'CenterX', 'CenterY', 'TopLeft', 'TopRight', 'BottomLeft', 'BottomRight', 'LeftCenter', 'TopCenter', 'RightCenter', 'BottomCenter'], function(key) { var name = 'set' + key; this[name] = function() { this._dontNotify = true; proto[name].apply(this, arguments); this._dontNotify = false; this._owner[this._setter](this); }; }, { isSelected: function() { return !!(this._owner._selection & 2); }, setSelected: function(selected) { var owner = this._owner; if (owner._changeSelection) { owner._changeSelection(2, selected); } } }) ); }); var Matrix = Base.extend({ _class: 'Matrix', initialize: function Matrix(arg, _dontNotify) { var args = arguments, count = args.length, ok = true; if (count >= 6) { this._set.apply(this, args); } else if (count === 1 || count === 2) { if (arg instanceof Matrix) { this._set(arg._a, arg._b, arg._c, arg._d, arg._tx, arg._ty, _dontNotify); } else if (Array.isArray(arg)) { this._set.apply(this, _dontNotify ? arg.concat([_dontNotify]) : arg); } else { ok = false; } } else if (!count) { this.reset(); } else { ok = false; } if (!ok) { throw new Error('Unsupported matrix parameters'); } return this; }, set: '#initialize', _set: function(a, b, c, d, tx, ty, _dontNotify) { this._a = a; this._b = b; this._c = c; this._d = d; this._tx = tx; this._ty = ty; if (!_dontNotify) this._changed(); return this; }, _serialize: function(options, dictionary) { return Base.serialize(this.getValues(), options, true, dictionary); }, _changed: function() { var owner = this._owner; if (owner) { if (owner._applyMatrix) { owner.transform(null, true); } else { owner._changed(25); } } }, clone: function() { return new Matrix(this._a, this._b, this._c, this._d, this._tx, this._ty); }, equals: function(mx) { return mx === this || mx && this._a === mx._a && this._b === mx._b && this._c === mx._c && this._d === mx._d && this._tx === mx._tx && this._ty === mx._ty; }, toString: function() { var f = Formatter.instance; return '[[' + [f.number(this._a), f.number(this._c), f.number(this._tx)].join(', ') + '], [' + [f.number(this._b), f.number(this._d), f.number(this._ty)].join(', ') + ']]'; }, reset: function(_dontNotify) { this._a = this._d = 1; this._b = this._c = this._tx = this._ty = 0; if (!_dontNotify) this._changed(); return this; }, apply: function(recursively, _setApplyMatrix) { var owner = this._owner; if (owner) { owner.transform(null, Base.pick(recursively, true), _setApplyMatrix); return this.isIdentity(); } return false; }, translate: function() { var point = Point.read(arguments), x = point.x, y = point.y; this._tx += x * this._a + y * this._c; this._ty += x * this._b + y * this._d; this._changed(); return this; }, scale: function() { var args = arguments, scale = Point.read(args), center = Point.read(args, 0, { readNull: true }); if (center) this.translate(center); this._a *= scale.x; this._b *= scale.x; this._c *= scale.y; this._d *= scale.y; if (center) this.translate(center.negate()); this._changed(); return this; }, rotate: function(angle ) { angle *= Math.PI / 180; var center = Point.read(arguments, 1), x = center.x, y = center.y, cos = Math.cos(angle), sin = Math.sin(angle), tx = x - x * cos + y * sin, ty = y - x * sin - y * cos, a = this._a, b = this._b, c = this._c, d = this._d; this._a = cos * a + sin * c; this._b = cos * b + sin * d; this._c = -sin * a + cos * c; this._d = -sin * b + cos * d; this._tx += tx * a + ty * c; this._ty += tx * b + ty * d; this._changed(); return this; }, shear: function() { var args = arguments, shear = Point.read(args), center = Point.read(args, 0, { readNull: true }); if (center) this.translate(center); var a = this._a, b = this._b; this._a += shear.y * this._c; this._b += shear.y * this._d; this._c += shear.x * a; this._d += shear.x * b; if (center) this.translate(center.negate()); this._changed(); return this; }, skew: function() { var args = arguments, skew = Point.read(args), center = Point.read(args, 0, { readNull: true }), toRadians = Math.PI / 180, shear = new Point(Math.tan(skew.x * toRadians), Math.tan(skew.y * toRadians)); return this.shear(shear, center); }, append: function(mx, _dontNotify) { if (mx) { var a1 = this._a, b1 = this._b, c1 = this._c, d1 = this._d, a2 = mx._a, b2 = mx._c, c2 = mx._b, d2 = mx._d, tx2 = mx._tx, ty2 = mx._ty; this._a = a2 * a1 + c2 * c1; this._c = b2 * a1 + d2 * c1; this._b = a2 * b1 + c2 * d1; this._d = b2 * b1 + d2 * d1; this._tx += tx2 * a1 + ty2 * c1; this._ty += tx2 * b1 + ty2 * d1; if (!_dontNotify) this._changed(); } return this; }, prepend: function(mx, _dontNotify) { if (mx) { var a1 = this._a, b1 = this._b, c1 = this._c, d1 = this._d, tx1 = this._tx, ty1 = this._ty, a2 = mx._a, b2 = mx._c, c2 = mx._b, d2 = mx._d, tx2 = mx._tx, ty2 = mx._ty; this._a = a2 * a1 + b2 * b1; this._c = a2 * c1 + b2 * d1; this._b = c2 * a1 + d2 * b1; this._d = c2 * c1 + d2 * d1; this._tx = a2 * tx1 + b2 * ty1 + tx2; this._ty = c2 * tx1 + d2 * ty1 + ty2; if (!_dontNotify) this._changed(); } return this; }, appended: function(mx) { return this.clone().append(mx); }, prepended: function(mx) { return this.clone().prepend(mx); }, invert: function() { var a = this._a, b = this._b, c = this._c, d = this._d, tx = this._tx, ty = this._ty, det = a * d - b * c, res = null; if (det && !isNaN(det) && isFinite(tx) && isFinite(ty)) { this._a = d / det; this._b = -b / det; this._c = -c / det; this._d = a / det; this._tx = (c * ty - d * tx) / det; this._ty = (b * tx - a * ty) / det; res = this; } return res; }, inverted: function() { return this.clone().invert(); }, concatenate: '#append', preConcatenate: '#prepend', chain: '#appended', _shiftless: function() { return new Matrix(this._a, this._b, this._c, this._d, 0, 0); }, _orNullIfIdentity: function() { return this.isIdentity() ? null : this; }, isIdentity: function() { return this._a === 1 && this._b === 0 && this._c === 0 && this._d === 1 && this._tx === 0 && this._ty === 0; }, isInvertible: function() { var det = this._a * this._d - this._c * this._b; return det && !isNaN(det) && isFinite(this._tx) && isFinite(this._ty); }, isSingular: function() { return !this.isInvertible(); }, transform: function( src, dst, count) { return arguments.length < 3 ? this._transformPoint(Point.read(arguments)) : this._transformCoordinates(src, dst, count); }, _transformPoint: function(point, dest, _dontNotify) { var x = point.x, y = point.y; if (!dest) dest = new Point(); return dest._set( x * this._a + y * this._c + this._tx, x * this._b + y * this._d + this._ty, _dontNotify); }, _transformCoordinates: function(src, dst, count) { for (var i = 0, max = 2 * count; i < max; i += 2) { var x = src[i], y = src[i + 1]; dst[i] = x * this._a + y * this._c + this._tx; dst[i + 1] = x * this._b + y * this._d + this._ty; } return dst; }, _transformCorners: function(rect) { var x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height, coords = [ x1, y1, x2, y1, x2, y2, x1, y2 ]; return this._transformCoordinates(coords, coords, 4); }, _transformBounds: function(bounds, dest, _dontNotify) { var coords = this._transformCorners(bounds), min = coords.slice(0, 2), max = min.slice(); for (var i = 2; i < 8; i++) { var val = coords[i], j = i & 1; if (val < min[j]) { min[j] = val; } else if (val > max[j]) { max[j] = val; } } if (!dest) dest = new Rectangle(); return dest._set(min[0], min[1], max[0] - min[0], max[1] - min[1], _dontNotify); }, inverseTransform: function() { return this._inverseTransform(Point.read(arguments)); }, _inverseTransform: function(point, dest, _dontNotify) { var a = this._a, b = this._b, c = this._c, d = this._d, tx = this._tx, ty = this._ty, det = a * d - b * c, res = null; if (det && !isNaN(det) && isFinite(tx) && isFinite(ty)) { var x = point.x - this._tx, y = point.y - this._ty; if (!dest) dest = new Point(); res = dest._set( (x * d - y * c) / det, (y * a - x * b) / det, _dontNotify); } return res; }, decompose: function() { var a = this._a, b = this._b, c = this._c, d = this._d, det = a * d - b * c, sqrt = Math.sqrt, atan2 = Math.atan2, degrees = 180 / Math.PI, rotate, scale, skew; if (a !== 0 || b !== 0) { var r = sqrt(a * a + b * b); rotate = Math.acos(a / r) * (b > 0 ? 1 : -1); scale = [r, det / r]; skew = [atan2(a * c + b * d, r * r), 0]; } else if (c !== 0 || d !== 0) { var s = sqrt(c * c + d * d); rotate = Math.asin(c / s) * (d > 0 ? 1 : -1); scale = [det / s, s]; skew = [0, atan2(a * c + b * d, s * s)]; } else { rotate = 0; skew = scale = [0, 0]; } return { translation: this.getTranslation(), rotation: rotate * degrees, scaling: new Point(scale), skewing: new Point(skew[0] * degrees, skew[1] * degrees) }; }, getValues: function() { return [ this._a, this._b, this._c, this._d, this._tx, this._ty ]; }, getTranslation: function() { return new Point(this._tx, this._ty); }, getScaling: function() { return this.decompose().scaling; }, getRotation: function() { return this.decompose().rotation; }, applyToContext: function(ctx) { if (!this.isIdentity()) { ctx.transform(this._a, this._b, this._c, this._d, this._tx, this._ty); } } }, Base.each(['a', 'b', 'c', 'd', 'tx', 'ty'], function(key) { var part = Base.capitalize(key), prop = '_' + key; this['get' + part] = function() { return this[prop]; }; this['set' + part] = function(value) { this[prop] = value; this._changed(); }; }, {})); var Line = Base.extend({ _class: 'Line', initialize: function Line(arg0, arg1, arg2, arg3, arg4) { var asVector = false; if (arguments.length >= 4) { this._px = arg0; this._py = arg1; this._vx = arg2; this._vy = arg3; asVector = arg4; } else { this._px = arg0.x; this._py = arg0.y; this._vx = arg1.x; this._vy = arg1.y; asVector = arg2; } if (!asVector) { this._vx -= this._px; this._vy -= this._py; } }, getPoint: function() { return new Point(this._px, this._py); }, getVector: function() { return new Point(this._vx, this._vy); }, getLength: function() { return this.getVector().getLength(); }, intersect: function(line, isInfinite) { return Line.intersect( this._px, this._py, this._vx, this._vy, line._px, line._py, line._vx, line._vy, true, isInfinite); }, getSide: function(point, isInfinite) { return Line.getSide( this._px, this._py, this._vx, this._vy, point.x, point.y, true, isInfinite); }, getDistance: function(point) { return Math.abs(this.getSignedDistance(point)); }, getSignedDistance: function(point) { return Line.getSignedDistance(this._px, this._py, this._vx, this._vy, point.x, point.y, true); }, isCollinear: function(line) { return Point.isCollinear(this._vx, this._vy, line._vx, line._vy); }, isOrthogonal: function(line) { return Point.isOrthogonal(this._vx, this._vy, line._vx, line._vy); }, statics: { intersect: function(p1x, p1y, v1x, v1y, p2x, p2y, v2x, v2y, asVector, isInfinite) { if (!asVector) { v1x -= p1x; v1y -= p1y; v2x -= p2x; v2y -= p2y; } var cross = v1x * v2y - v1y * v2x; if (!Numerical.isMachineZero(cross)) { var dx = p1x - p2x, dy = p1y - p2y, u1 = (v2x * dy - v2y * dx) / cross, u2 = (v1x * dy - v1y * dx) / cross, epsilon = 1e-12, uMin = -epsilon, uMax = 1 + epsilon; if (isInfinite || uMin < u1 && u1 < uMax && uMin < u2 && u2 < uMax) { if (!isInfinite) { u1 = u1 <= 0 ? 0 : u1 >= 1 ? 1 : u1; } return new Point( p1x + u1 * v1x, p1y + u1 * v1y); } } }, getSide: function(px, py, vx, vy, x, y, asVector, isInfinite) { if (!asVector) { vx -= px; vy -= py; } var v2x = x - px, v2y = y - py, ccw = v2x * vy - v2y * vx; if (!isInfinite && Numerical.isMachineZero(ccw)) { ccw = (v2x * vx + v2x * vx) / (vx * vx + vy * vy); if (ccw >= 0 && ccw <= 1) ccw = 0; } return ccw < 0 ? -1 : ccw > 0 ? 1 : 0; }, getSignedDistance: function(px, py, vx, vy, x, y, asVector) { if (!asVector) { vx -= px; vy -= py; } return vx === 0 ? (vy > 0 ? x - px : px - x) : vy === 0 ? (vx < 0 ? y - py : py - y) : ((x - px) * vy - (y - py) * vx) / ( vy > vx ? vy * Math.sqrt(1 + (vx * vx) / (vy * vy)) : vx * Math.sqrt(1 + (vy * vy) / (vx * vx)) ); }, getDistance: function(px, py, vx, vy, x, y, asVector) { return Math.abs( Line.getSignedDistance(px, py, vx, vy, x, y, asVector)); } } }); var Project = PaperScopeItem.extend({ _class: 'Project', _list: 'projects', _reference: 'project', _compactSerialize: true, initialize: function Project(element) { PaperScopeItem.call(this, true); this._children = []; this._namedChildren = {}; this._activeLayer = null; this._currentStyle = new Style(null, null, this); this._view = View.create(this, element || CanvasProvider.getCanvas(1, 1)); this._selectionItems = {}; this._selectionCount = 0; this._updateVersion = 0; }, _serialize: function(options, dictionary) { return Base.serialize(this._children, options, true, dictionary); }, _changed: function(flags, item) { if (flags & 1) { var view = this._view; if (view) { view._needsUpdate = true; if (!view._requested && view._autoUpdate) view.requestUpdate(); } } var changes = this._changes; if (changes && item) { var changesById = this._changesById, id = item._id, entry = changesById[id]; if (entry) { entry.flags |= flags; } else { changes.push(changesById[id] = { item: item, flags: flags }); } } }, clear: function() { var children = this._children; for (var i = children.length - 1; i >= 0; i--) children[i].remove(); }, isEmpty: function() { return !this._children.length; }, remove: function remove() { if (!remove.base.call(this)) return false; if (this._view) this._view.remove(); return true; }, getView: function() { return this._view; }, getCurrentStyle: function() { return this._currentStyle; }, setCurrentStyle: function(style) { this._currentStyle.set(style); }, getIndex: function() { return this._index; }, getOptions: function() { return this._scope.settings; }, getLayers: function() { return this._children; }, getActiveLayer: function() { return this._activeLayer || new Layer({ project: this, insert: true }); }, getSymbolDefinitions: function() { var definitions = [], ids = {}; this.getItems({ class: SymbolItem, match: function(item) { var definition = item._definition, id = definition._id; if (!ids[id]) { ids[id] = true; definitions.push(definition); } return false; } }); return definitions; }, getSymbols: 'getSymbolDefinitions', getSelectedItems: function() { var selectionItems = this._selectionItems, items = []; for (var id in selectionItems) { var item = selectionItems[id], selection = item._selection; if ((selection & 1) && item.isInserted()) { items.push(item); } else if (!selection) { this._updateSelection(item); } } return items; }, _updateSelection: function(item) { var id = item._id, selectionItems = this._selectionItems; if (item._selection) { if (selectionItems[id] !== item) { this._selectionCount++; selectionItems[id] = item; } } else if (selectionItems[id] === item) { this._selectionCount--; delete selectionItems[id]; } }, selectAll: function() { var children = this._children; for (var i = 0, l = children.length; i < l; i++) children[i].setFullySelected(true); }, deselectAll: function() { var selectionItems = this._selectionItems; for (var i in selectionItems) selectionItems[i].setFullySelected(false); }, addLayer: function(layer) { return this.insertLayer(undefined, layer); }, insertLayer: function(index, layer) { if (layer instanceof Layer) { layer._remove(false, true); Base.splice(this._children, [layer], index, 0); layer._setProject(this, true); var name = layer._name; if (name) layer.setName(name); if (this._changes) layer._changed(5); if (!this._activeLayer) this._activeLayer = layer; } else { layer = null; } return layer; }, _insertItem: function(index, item, _created) { item = this.insertLayer(index, item) || (this._activeLayer || this._insertItem(undefined, new Layer(Item.NO_INSERT), true)) .insertChild(index, item); if (_created && item.activate) item.activate(); return item; }, getItems: function(options) { return Item._getItems(this, options); }, getItem: function(options) { return Item._getItems(this, options, null, null, true)[0] || null; }, importJSON: function(json) { this.activate(); var layer = this._activeLayer; return Base.importJSON(json, layer && layer.isEmpty() && layer); }, removeOn: function(type) { var sets = this._removeSets; if (sets) { if (type === 'mouseup') sets.mousedrag = null; var set = sets[type]; if (set) { for (var id in set) { var item = set[id]; for (var key in sets) { var other = sets[key]; if (other && other != set) delete other[item._id]; } item.remove(); } sets[type] = null; } } }, draw: function(ctx, matrix, pixelRatio) { this._updateVersion++; ctx.save(); matrix.applyToContext(ctx); var children = this._children, param = new Base({ offset: new Point(0, 0), pixelRatio: pixelRatio, viewMatrix: matrix.isIdentity() ? null : matrix, matrices: [new Matrix()], updateMatrix: true }); for (var i = 0, l = children.length; i < l; i++) { children[i].draw(ctx, param); } ctx.restore(); if (this._selectionCount > 0) { ctx.save(); ctx.strokeWidth = 1; var items = this._selectionItems, size = this._scope.settings.handleSize, version = this._updateVersion; for (var id in items) { items[id]._drawSelection(ctx, matrix, size, items, version); } ctx.restore(); } } }); var Item = Base.extend(Emitter, { statics: { extend: function extend(src) { if (src._serializeFields) src._serializeFields = Base.set({}, this.prototype._serializeFields, src._serializeFields); return extend.base.apply(this, arguments); }, NO_INSERT: { insert: false } }, _class: 'Item', _name: null, _applyMatrix: true, _canApplyMatrix: true, _canScaleStroke: false, _pivot: null, _visible: true, _blendMode: 'normal', _opacity: 1, _locked: false, _guide: false, _clipMask: false, _selection: 0, _selectBounds: true, _selectChildren: false, _serializeFields: { name: null, applyMatrix: null, matrix: new Matrix(), pivot: null, visible: true, blendMode: 'normal', opacity: 1, locked: false, guide: false, clipMask: false, selected: false, data: {} }, _prioritize: ['applyMatrix'] }, new function() { var handlers = ['onMouseDown', 'onMouseUp', 'onMouseDrag', 'onClick', 'onDoubleClick', 'onMouseMove', 'onMouseEnter', 'onMouseLeave']; return Base.each(handlers, function(name) { this._events[name] = { install: function(type) { this.getView()._countItemEvent(type, 1); }, uninstall: function(type) { this.getView()._countItemEvent(type, -1); } }; }, { _events: { onFrame: { install: function() { this.getView()._animateItem(this, true); }, uninstall: function() { this.getView()._animateItem(this, false); } }, onLoad: {}, onError: {} }, statics: { _itemHandlers: handlers } } ); }, { initialize: function Item() { }, _initialize: function(props, point) { var hasProps = props && Base.isPlainObject(props), internal = hasProps && props.internal === true, matrix = this._matrix = new Matrix(), project = hasProps && props.project || paper.project, settings = paper.settings; this._id = internal ? null : UID.get(); this._parent = this._index = null; this._applyMatrix = this._canApplyMatrix && settings.applyMatrix; if (point) matrix.translate(point); matrix._owner = this; this._style = new Style(project._currentStyle, this, project); if (internal || hasProps && props.insert == false || !settings.insertItems && !(hasProps && props.insert === true)) { this._setProject(project); } else { (hasProps && props.parent || project) ._insertItem(undefined, this, true); } if (hasProps && props !== Item.NO_INSERT) { this.set(props, { internal: true, insert: true, project: true, parent: true }); } return hasProps; }, _serialize: function(options, dictionary) { var props = {}, that = this; function serialize(fields) { for (var key in fields) { var value = that[key]; if (!Base.equals(value, key === 'leading' ? fields.fontSize * 1.2 : fields[key])) { props[key] = Base.serialize(value, options, key !== 'data', dictionary); } } } serialize(this._serializeFields); if (!(this instanceof Group)) serialize(this._style._defaults); return [ this._class, props ]; }, _changed: function(flags) { var symbol = this._symbol, cacheParent = this._parent || symbol, project = this._project; if (flags & 8) { this._bounds = this._position = this._decomposed = undefined; } if (flags & 16) { this._globalMatrix = undefined; } if (cacheParent && (flags & 72)) { Item._clearBoundsCache(cacheParent); } if (flags & 2) { Item._clearBoundsCache(this); } if (project) project._changed(flags, this); if (symbol) symbol._changed(flags); }, getId: function() { return this._id; }, getName: function() { return this._name; }, setName: function(name) { if (this._name) this._removeNamed(); if (name === (+name) + '') throw new Error( 'Names consisting only of numbers are not supported.'); var owner = this._getOwner(); if (name && owner) { var children = owner._children, namedChildren = owner._namedChildren; (namedChildren[name] = namedChildren[name] || []).push(this); if (!(name in children)) children[name] = this; } this._name = name || undefined; this._changed(256); }, getStyle: function() { return this._style; }, setStyle: function(style) { this.getStyle().set(style); } }, Base.each(['locked', 'visible', 'blendMode', 'opacity', 'guide'], function(name) { var part = Base.capitalize(name), key = '_' + name, flags = { locked: 256, visible: 265 }; this['get' + part] = function() { return this[key]; }; this['set' + part] = function(value) { if (value != this[key]) { this[key] = value; this._changed(flags[name] || 257); } }; }, {}), { beans: true, getSelection: function() { return this._selection; }, setSelection: function(selection) { if (selection !== this._selection) { this._selection = selection; var project = this._project; if (project) { project._updateSelection(this); this._changed(257); } } }, _changeSelection: function(flag, selected) { var selection = this._selection; this.setSelection(selected ? selection | flag : selection & ~flag); }, isSelected: function() { if (this._selectChildren) { var children = this._children; for (var i = 0, l = children.length; i < l; i++) if (children[i].isSelected()) return true; } return !!(this._selection & 1); }, setSelected: function(selected) { if (this._selectChildren) { var children = this._children; for (var i = 0, l = children.length; i < l; i++) children[i].setSelected(selected); } this._changeSelection(1, selected); }, isFullySelected: function() { var children = this._children, selected = !!(this._selection & 1); if (children && selected) { for (var i = 0, l = children.length; i < l; i++) if (!children[i].isFullySelected()) return false; return true; } return selected; }, setFullySelected: function(selected) { var children = this._children; if (children) { for (var i = 0, l = children.length; i < l; i++) children[i].setFullySelected(selected); } this._changeSelection(1, selected); }, isClipMask: function() { return this._clipMask; }, setClipMask: function(clipMask) { if (this._clipMask != (clipMask = !!clipMask)) { this._clipMask = clipMask; if (clipMask) { this.setFillColor(null); this.setStrokeColor(null); } this._changed(257); if (this._parent) this._parent._changed(2048); } }, getData: function() { if (!this._data) this._data = {}; return this._data; }, setData: function(data) { this._data = data; }, getPosition: function(_dontLink) { var ctor = _dontLink ? Point : LinkedPoint; var position = this._position || (this._position = this._getPositionFromBounds()); return new ctor(position.x, position.y, this, 'setPosition'); }, setPosition: function() { this.translate(Point.read(arguments).subtract(this.getPosition(true))); }, _getPositionFromBounds: function(bounds) { return this._pivot ? this._matrix._transformPoint(this._pivot) : (bounds || this.getBounds()).getCenter(true); }, getPivot: function() { var pivot = this._pivot; return pivot ? new LinkedPoint(pivot.x, pivot.y, this, 'setPivot') : null; }, setPivot: function() { this._pivot = Point.read(arguments, 0, { clone: true, readNull: true }); this._position = undefined; } }, Base.each({ getStrokeBounds: { stroke: true }, getHandleBounds: { handle: true }, getInternalBounds: { internal: true }, getDrawnBounds: { stroke: true, drawnTextBounds: true }, }, function(options, key) { this[key] = function(matrix) { return this.getBounds(matrix, options); }; }, { beans: true, getBounds: function(matrix, options) { var hasMatrix = options || matrix instanceof Matrix, opts = Base.set({}, hasMatrix ? options : matrix, this._boundsOptions); if (!opts.stroke || this.getStrokeScaling()) opts.cacheItem = this; var rect = this._getCachedBounds(hasMatrix && matrix, opts).rect; return !arguments.length ? new LinkedRectangle(rect.x, rect.y, rect.width, rect.height, this, 'setBounds') : rect; }, setBounds: function() { var rect = Rectangle.read(arguments), bounds = this.getBounds(), _matrix = this._matrix, matrix = new Matrix(), center = rect.getCenter(); matrix.translate(center); if (rect.width != bounds.width || rect.height != bounds.height) { if (!_matrix.isInvertible()) { _matrix.set(_matrix._backup || new Matrix().translate(_matrix.getTranslation())); bounds = this.getBounds(); } matrix.scale( bounds.width !== 0 ? rect.width / bounds.width : 0, bounds.height !== 0 ? rect.height / bounds.height : 0); } center = bounds.getCenter(); matrix.translate(-center.x, -center.y); this.transform(matrix); }, _getBounds: function(matrix, options) { var children = this._children; if (!children || !children.length) return new Rectangle(); Item._updateBoundsCache(this, options.cacheItem); return Item._getBounds(children, matrix, options); }, _getBoundsCacheKey: function(options, internal) { return [ options.stroke ? 1 : 0, options.handle ? 1 : 0, options.drawnTextBounds? 1 : 0, internal ? 1 : 0 ].join(''); }, _getCachedBounds: function(matrix, options, noInternal) { matrix = matrix && matrix._orNullIfIdentity(); var internal = options.internal && !noInternal, cacheItem = options.cacheItem, _matrix = internal ? null : this._matrix._orNullIfIdentity(), cacheKey = cacheItem && (!matrix || matrix.equals(_matrix)) && this._getBoundsCacheKey(options, internal), bounds = this._bounds; Item._updateBoundsCache(this._parent || this._symbol, cacheItem); if (cacheKey && bounds && cacheKey in bounds) { var cached = bounds[cacheKey]; return { rect: cached.rect.clone(), nonscaling: cached.nonscaling }; } var res = this._getBounds(matrix || _matrix, options), rect = res.rect || res, style = this._style, nonscaling = res.nonscaling || style.hasStroke() && !style.getStrokeScaling(); if (cacheKey) { if (!bounds) { this._bounds = bounds = {}; } var cached = bounds[cacheKey] = { rect: rect.clone(), nonscaling: nonscaling, internal: internal }; } return { rect: rect, nonscaling: nonscaling }; }, _getStrokeMatrix: function(matrix, options) { var parent = this.getStrokeScaling() ? null : options && options.internal ? this : this._parent || this._symbol && this._symbol._item, mx = parent ? parent.getViewMatrix().invert() : matrix; return mx && mx._shiftless(); }, statics: { _updateBoundsCache: function(parent, item) { if (parent && item) { var id = item._id, ref = parent._boundsCache = parent._boundsCache || { ids: {}, list: [] }; if (!ref.ids[id]) { ref.list.push(item); ref.ids[id] = item; } } }, _clearBoundsCache: function(item) { var cache = item._boundsCache; if (cache) { item._bounds = item._position = item._boundsCache = undefined; for (var i = 0, list = cache.list, l = list.length; i < l; i++){ var other = list[i]; if (other !== item) { other._bounds = other._position = undefined; if (other._boundsCache) Item._clearBoundsCache(other); } } } }, _getBounds: function(items, matrix, options) { var x1 = Infinity, x2 = -x1, y1 = x1, y2 = x2, nonscaling = false; options = options || {}; for (var i = 0, l = items.length; i < l; i++) { var item = items[i]; if (item._visible && !item.isEmpty(true)) { var bounds = item._getCachedBounds( matrix && matrix.appended(item._matrix), options, true), rect = bounds.rect; x1 = Math.min(rect.x, x1); y1 = Math.min(rect.y, y1); x2 = Math.max(rect.x + rect.width, x2); y2 = Math.max(rect.y + rect.height, y2); if (bounds.nonscaling) nonscaling = true; } } return { rect: isFinite(x1) ? new Rectangle(x1, y1, x2 - x1, y2 - y1) : new Rectangle(), nonscaling: nonscaling }; } } }), { beans: true, _decompose: function() { return this._applyMatrix ? null : this._decomposed || (this._decomposed = this._matrix.decompose()); }, getRotation: function() { var decomposed = this._decompose(); return decomposed ? decomposed.rotation : 0; }, setRotation: function(rotation) { var current = this.getRotation(); if (current != null && rotation != null) { var decomposed = this._decomposed; this.rotate(rotation - current); if (decomposed) { decomposed.rotation = rotation; this._decomposed = decomposed; } } }, getScaling: function() { var decomposed = this._decompose(), s = decomposed && decomposed.scaling; return new LinkedPoint(s ? s.x : 1, s ? s.y : 1, this, 'setScaling'); }, setScaling: function() { var current = this.getScaling(), scaling = Point.read(arguments, 0, { clone: true, readNull: true }); if (current && scaling && !current.equals(scaling)) { var rotation = this.getRotation(), decomposed = this._decomposed, matrix = new Matrix(), center = this.getPosition(true); matrix.translate(center); if (rotation) matrix.rotate(rotation); matrix.scale(scaling.x / current.x, scaling.y / current.y); if (rotation) matrix.rotate(-rotation); matrix.translate(center.negate()); this.transform(matrix); if (decomposed) { decomposed.scaling = scaling; this._decomposed = decomposed; } } }, getMatrix: function() { return this._matrix; }, setMatrix: function() { var matrix = this._matrix; matrix.initialize.apply(matrix, arguments); }, getGlobalMatrix: function(_dontClone) { var matrix = this._globalMatrix; if (matrix) { var parent = this._parent; var parents = []; while (parent) { if (!parent._globalMatrix) { matrix = null; for (var i = 0, l = parents.length; i < l; i++) { parents[i]._globalMatrix = null; } break; } parents.push(parent); parent = parent._parent; } } if (!matrix) { matrix = this._globalMatrix = this._matrix.clone(); var parent = this._parent; if (parent) matrix.prepend(parent.getGlobalMatrix(true)); } return _dontClone ? matrix : matrix.clone(); }, getViewMatrix: function() { return this.getGlobalMatrix().prepend(this.getView()._matrix); }, getApplyMatrix: function() { return this._applyMatrix; }, setApplyMatrix: function(apply) { if (this._applyMatrix = this._canApplyMatrix && !!apply) this.transform(null, true); }, getTransformContent: '#getApplyMatrix', setTransformContent: '#setApplyMatrix', }, { getProject: function() { return this._project; }, _setProject: function(project, installEvents) { if (this._project !== project) { if (this._project) this._installEvents(false); this._project = project; var children = this._children; for (var i = 0, l = children && children.length; i < l; i++) children[i]._setProject(project); installEvents = true; } if (installEvents) this._installEvents(true); }, getView: function() { return this._project._view; }, _installEvents: function _installEvents(install) { _installEvents.base.call(this, install); var children = this._children; for (var i = 0, l = children && children.length; i < l; i++) children[i]._installEvents(install); }, getLayer: function() { var parent = this; while (parent = parent._parent) { if (parent instanceof Layer) return parent; } return null; }, getParent: function() { return this._parent; }, setParent: function(item) { return item.addChild(this); }, _getOwner: '#getParent', getChildren: function() { return this._children; }, setChildren: function(items) { this.removeChildren(); this.addChildren(items); }, getFirstChild: function() { return this._children && this._children[0] || null; }, getLastChild: function() { return this._children && this._children[this._children.length - 1] || null; }, getNextSibling: function() { var owner = this._getOwner(); return owner && owner._children[this._index + 1] || null; }, getPreviousSibling: function() { var owner = this._getOwner(); return owner && owner._children[this._index - 1] || null; }, getIndex: function() { return this._index; }, equals: function(item) { return item === this || item && this._class === item._class && this._style.equals(item._style) && this._matrix.equals(item._matrix) && this._locked === item._locked && this._visible === item._visible && this._blendMode === item._blendMode && this._opacity === item._opacity && this._clipMask === item._clipMask && this._guide === item._guide && this._equals(item) || false; }, _equals: function(item) { return Base.equals(this._children, item._children); }, clone: function(options) { var copy = new this.constructor(Item.NO_INSERT), children = this._children, insert = Base.pick(options ? options.insert : undefined, options === undefined || options === true), deep = Base.pick(options ? options.deep : undefined, true); if (children) copy.copyAttributes(this); if (!children || deep) copy.copyContent(this); if (!children) copy.copyAttributes(this); if (insert) copy.insertAbove(this); var name = this._name, parent = this._parent; if (name && parent) { var children = parent._children, orig = name, i = 1; while (children[name]) name = orig + ' ' + (i++); if (name !== orig) copy.setName(name); } return copy; }, copyContent: function(source) { var children = source._children; for (var i = 0, l = children && children.length; i < l; i++) { this.addChild(children[i].clone(false), true); } }, copyAttributes: function(source, excludeMatrix) { this.setStyle(source._style); var keys = ['_locked', '_visible', '_blendMode', '_opacity', '_clipMask', '_guide']; for (var i = 0, l = keys.length; i < l; i++) { var key = keys[i]; if (source.hasOwnProperty(key)) this[key] = source[key]; } if (!excludeMatrix) this._matrix.set(source._matrix, true); this.setApplyMatrix(source._applyMatrix); this.setPivot(source._pivot); this.setSelection(source._selection); var data = source._data, name = source._name; this._data = data ? Base.clone(data) : null; if (name) this.setName(name); }, rasterize: function(resolution, insert, boundRect) { var bounds = boundRect ? boundRect : this.getStrokeBounds(), scale = (resolution || this.getView().getResolution()) / 72, topLeft = bounds.getTopLeft().floor(), bottomRight = bounds.getBottomRight().ceil(), size = new Size(bottomRight.subtract(topLeft)), raster = new Raster(Item.NO_INSERT); if (!size.isZero()) { var canvas = CanvasProvider.getCanvas(size.multiply(scale)), ctx = canvas.getContext('2d'), matrix = new Matrix().scale(scale).translate(topLeft.negate()); ctx.imageSmoothingEnabled = false; ctx.save(); matrix.applyToContext(ctx); this.draw(ctx, new Base({ matrices: [matrix] })); ctx.restore(); raster.setCanvas(canvas); } raster.transform(new Matrix().translate(topLeft.add(size.divide(2))) .scale(1 / scale)); if (insert === undefined || insert) raster.insertAbove(this); return raster; }, contains: function() { var matrix = this._matrix; return ( matrix.isInvertible() && !!this._contains(matrix._inverseTransform(Point.read(arguments))) ); }, _contains: function(point) { var children = this._children; if (children) { for (var i = children.length - 1; i >= 0; i--) { if (children[i].contains(point)) return true; } return false; } return point.isInside(this.getInternalBounds()); }, isInside: function() { return Rectangle.read(arguments).contains(this.getBounds()); }, _asPathItem: function() { return new Path.Rectangle({ rectangle: this.getInternalBounds(), matrix: this._matrix, insert: false, }); }, intersects: function(item, _matrix) { if (!(item instanceof Item)) return false; return this._asPathItem().getIntersections(item._asPathItem(), null, _matrix, true).length > 0; } }, new function() { function hitTest() { var args = arguments; return this._hitTest( Point.read(args), HitResult.getOptions(args)); } function hitTestAll() { var args = arguments, point = Point.read(args), options = HitResult.getOptions(args), all = []; this._hitTest(point, new Base({ all: all }, options)); return all; } function hitTestChildren(point, options, viewMatrix, _exclude) { var children = this._children; if (children) { for (var i = children.length - 1; i >= 0; i--) { var child = children[i]; var res = child !== _exclude && child._hitTest(point, options, viewMatrix); if (res && !options.all) return res; } } return null; } Project.inject({ hitTest: hitTest, hitTestAll: hitTestAll, _hitTest: hitTestChildren }); return { hitTest: hitTest, hitTestAll: hitTestAll, _hitTestChildren: hitTestChildren, }; }, { _hitTest: function(point, options, parentViewMatrix) { if (this._locked || !this._visible || this._guide && !options.guides || this.isEmpty()) { return null; } var matrix = this._matrix, viewMatrix = parentViewMatrix ? parentViewMatrix.appended(matrix) : this.getGlobalMatrix().prepend(this.getView()._matrix), tolerance = Math.max(options.tolerance, 1e-12), tolerancePadding = options._tolerancePadding = new Size( Path._getStrokePadding(tolerance, matrix._shiftless().invert())); point = matrix._inverseTransform(point); if (!point || !this._children && !this.getBounds({ internal: true, stroke: true, handle: true }) .expand(tolerancePadding.multiply(2))._containsPoint(point)) { return null; } var checkSelf = !(options.guides && !this._guide || options.selected && !this.isSelected() || options.type && options.type !== Base.hyphenate(this._class) || options.class && !(this instanceof options.class)), match = options.match, that = this, bounds, res; function filter(hit) { if (hit && match && !match(hit)) hit = null; if (hit && options.all) options.all.push(hit); return hit; } function checkPoint(type, part) { var pt = part ? bounds['get' + part]() : that.getPosition(); if (point.subtract(pt).divide(tolerancePadding).length <= 1) { return new HitResult(type, that, { name: part ? Base.hyphenate(part) : type, point: pt }); } } var checkPosition = options.position, checkCenter = options.center, checkBounds = options.bounds; if (checkSelf && this._parent && (checkPosition || checkCenter || checkBounds)) { if (checkCenter || checkBounds) { bounds = this.getInternalBounds(); } res = checkPosition && checkPoint('position') || checkCenter && checkPoint('center', 'Center'); if (!res && checkBounds) { var points = [ 'TopLeft', 'TopRight', 'BottomLeft', 'BottomRight', 'LeftCenter', 'TopCenter', 'RightCenter', 'BottomCenter' ]; for (var i = 0; i < 8 && !res; i++) { res = checkPoint('bounds', points[i]); } } res = filter(res); } if (!res) { res = this._hitTestChildren(point, options, viewMatrix) || checkSelf && filter(this._hitTestSelf(point, options, viewMatrix, this.getStrokeScaling() ? null : viewMatrix._shiftless().invert())) || null; } if (res && res.point) { res.point = matrix.transform(res.point); } return res; }, _hitTestSelf: function(point, options) { if (options.fill && this.hasFill() && this._contains(point)) return new HitResult('fill', this); }, matches: function(name, compare) { function matchObject(obj1, obj2) { for (var i in obj1) { if (obj1.hasOwnProperty(i)) { var val1 = obj1[i], val2 = obj2[i]; if (Base.isPlainObject(val1) && Base.isPlainObject(val2)) { if (!matchObject(val1, val2)) return false; } else if (!Base.equals(val1, val2)) { return false; } } } return true; } var type = typeof name; if (type === 'object') { for (var key in name) { if (name.hasOwnProperty(key) && !this.matches(key, name[key])) return false; } return true; } else if (type === 'function') { return name(this); } else if (name === 'match') { return compare(this); } else { var value = /^(empty|editable)$/.test(name) ? this['is' + Base.capitalize(name)]() : name === 'type' ? Base.hyphenate(this._class) : this[name]; if (name === 'class') { if (typeof compare === 'function') return this instanceof compare; value = this._class; } if (typeof compare === 'function') { return !!compare(value); } else if (compare) { if (compare.test) { return compare.test(value); } else if (Base.isPlainObject(compare)) { return matchObject(compare, value); } } return Base.equals(value, compare); } }, getItems: function(options) { return Item._getItems(this, options, this._matrix); }, getItem: function(options) { return Item._getItems(this, options, this._matrix, null, true)[0] || null; }, statics: { _getItems: function _getItems(item, options, matrix, param, firstOnly) { if (!param) { var obj = typeof options === 'object' && options, overlapping = obj && obj.overlapping, inside = obj && obj.inside, bounds = overlapping || inside, rect = bounds && Rectangle.read([bounds]); param = { items: [], recursive: obj && obj.recursive !== false, inside: !!inside, overlapping: !!overlapping, rect: rect, path: overlapping && new Path.Rectangle({ rectangle: rect, insert: false }) }; if (obj) { options = Base.filter({}, options, { recursive: true, inside: true, overlapping: true }); } } var children = item._children, items = param.items, rect = param.rect; matrix = rect && (matrix || new Matrix()); for (var i = 0, l = children && children.length; i < l; i++) { var child = children[i], childMatrix = matrix && matrix.appended(child._matrix), add = true; if (rect) { var bounds = child.getBounds(childMatrix); if (!rect.intersects(bounds)) continue; if (!(rect.contains(bounds) || param.overlapping && (bounds.contains(rect) || param.path.intersects(child, childMatrix)))) add = false; } if (add && child.matches(options)) { items.push(child); if (firstOnly) break; } if (param.recursive !== false) { _getItems(child, options, childMatrix, param, firstOnly); } if (firstOnly && items.length > 0) break; } return items; } } }, { importJSON: function(json) { var res = Base.importJSON(json, this); return res !== this ? this.addChild(res) : res; }, addChild: function(item) { return this.insertChild(undefined, item); }, insertChild: function(index, item) { var res = item ? this.insertChildren(index, [item]) : null; return res && res[0]; }, addChildren: function(items) { return this.insertChildren(this._children.length, items); }, insertChildren: function(index, items) { var children = this._children; if (children && items && items.length > 0) { items = Base.slice(items); var inserted = {}; for (var i = items.length - 1; i >= 0; i--) { var item = items[i], id = item && item._id; if (!item || inserted[id]) { items.splice(i, 1); } else { item._remove(false, true); inserted[id] = true; } } Base.splice(children, items, index, 0); var project = this._project, notifySelf = project._changes; for (var i = 0, l = items.length; i < l; i++) { var item = items[i], name = item._name; item._parent = this; item._setProject(project, true); if (name) item.setName(name); if (notifySelf) item._changed(5); } this._changed(11); } else { items = null; } return items; }, _insertItem: '#insertChild', _insertAt: function(item, offset) { var owner = item && item._getOwner(), res = item !== this && owner ? this : null; if (res) { res._remove(false, true); owner._insertItem(item._index + offset, res); } return res; }, insertAbove: function(item) { return this._insertAt(item, 1); }, insertBelow: function(item) { return this._insertAt(item, 0); }, sendToBack: function() { var owner = this._getOwner(); return owner ? owner._insertItem(0, this) : null; }, bringToFront: function() { var owner = this._getOwner(); return owner ? owner._insertItem(undefined, this) : null; }, appendTop: '#addChild', appendBottom: function(item) { return this.insertChild(0, item); }, moveAbove: '#insertAbove', moveBelow: '#insertBelow', addTo: function(owner) { return owner._insertItem(undefined, this); }, copyTo: function(owner) { return this.clone(false).addTo(owner); }, reduce: function(options) { var children = this._children; if (children && children.length === 1) { var child = children[0].reduce(options); if (this._parent) { child.insertAbove(this); this.remove(); } else { child.remove(); } return child; } return this; }, _removeNamed: function() { var owner = this._getOwner(); if (owner) { var children = owner._children, namedChildren = owner._namedChildren, name = this._name, namedArray = namedChildren[name], index = namedArray ? namedArray.indexOf(this) : -1; if (index !== -1) { if (children[name] == this) delete children[name]; namedArray.splice(index, 1); if (namedArray.length) { children[name] = namedArray[0]; } else { delete namedChildren[name]; } } } }, _remove: function(notifySelf, notifyParent) { var owner = this._getOwner(), project = this._project, index = this._index; if (this._style) this._style._dispose(); if (owner) { if (this._name) this._removeNamed(); if (index != null) { if (project._activeLayer === this) project._activeLayer = this.getNextSibling() || this.getPreviousSibling(); Base.splice(owner._children, null, index, 1); } this._installEvents(false); if (notifySelf && project._changes) this._changed(5); if (notifyParent) owner._changed(11, this); this._parent = null; return true; } return false; }, remove: function() { return this._remove(true, true); }, replaceWith: function(item) { var ok = item && item.insertBelow(this); if (ok) this.remove(); return ok; }, removeChildren: function(start, end) { if (!this._children) return null; start = start || 0; end = Base.pick(end, this._children.length); var removed = Base.splice(this._children, null, start, end - start); for (var i = removed.length - 1; i >= 0; i--) { removed[i]._remove(true, false); } if (removed.length > 0) this._changed(11); return removed; }, clear: '#removeChildren', reverseChildren: function() { if (this._children) { this._children.reverse(); for (var i = 0, l = this._children.length; i < l; i++) this._children[i]._index = i; this._changed(11); } }, isEmpty: function(recursively) { var children = this._children; var numChildren = children ? children.length : 0; if (recursively) { for (var i = 0; i < numChildren; i++) { if (!children[i].isEmpty(recursively)) { return false; } } return true; } return !numChildren; }, isEditable: function() { var item = this; while (item) { if (!item._visible || item._locked) return false; item = item._parent; } return true; }, hasFill: function() { return this.getStyle().hasFill(); }, hasStroke: function() { return this.getStyle().hasStroke(); }, hasShadow: function() { return this.getStyle().hasShadow(); }, _getOrder: function(item) { function getList(item) { var list = []; do { list.unshift(item); } while (item = item._parent); return list; } var list1 = getList(this), list2 = getList(item); for (var i = 0, l = Math.min(list1.length, list2.length); i < l; i++) { if (list1[i] != list2[i]) { return list1[i]._index < list2[i]._index ? 1 : -1; } } return 0; }, hasChildren: function() { return this._children && this._children.length > 0; }, isInserted: function() { return this._parent ? this._parent.isInserted() : false; }, isAbove: function(item) { return this._getOrder(item) === -1; }, isBelow: function(item) { return this._getOrder(item) === 1; }, isParent: function(item) { return this._parent === item; }, isChild: function(item) { return item && item._parent === this; }, isDescendant: function(item) { var parent = this; while (parent = parent._parent) { if (parent === item) return true; } return false; }, isAncestor: function(item) { return item ? item.isDescendant(this) : false; }, isSibling: function(item) { return this._parent === item._parent; }, isGroupedWith: function(item) { var parent = this._parent; while (parent) { if (parent._parent && /^(Group|Layer|CompoundPath)$/.test(parent._class) && item.isDescendant(parent)) return true; parent = parent._parent; } return false; }, }, Base.each(['rotate', 'scale', 'shear', 'skew'], function(key) { var rotate = key === 'rotate'; this[key] = function() { var args = arguments, value = (rotate ? Base : Point).read(args), center = Point.read(args, 0, { readNull: true }); return this.transform(new Matrix()[key](value, center || this.getPosition(true))); }; }, { translate: function() { var mx = new Matrix(); return this.transform(mx.translate.apply(mx, arguments)); }, transform: function(matrix, _applyRecursively, _setApplyMatrix) { var _matrix = this._matrix, transformMatrix = matrix && !matrix.isIdentity(), applyMatrix = ( _setApplyMatrix && this._canApplyMatrix || this._applyMatrix && ( transformMatrix || !_matrix.isIdentity() || _applyRecursively && this._children ) ); if (!transformMatrix && !applyMatrix) return this; if (transformMatrix) { if (!matrix.isInvertible() && _matrix.isInvertible()) _matrix._backup = _matrix.getValues(); _matrix.prepend(matrix, true); var style = this._style, fillColor = style.getFillColor(true), strokeColor = style.getStrokeColor(true); if (fillColor) fillColor.transform(matrix); if (strokeColor) strokeColor.transform(matrix); } if (applyMatrix && (applyMatrix = this._transformContent( _matrix, _applyRecursively, _setApplyMatrix))) { var pivot = this._pivot; if (pivot) _matrix._transformPoint(pivot, pivot, true); _matrix.reset(true); if (_setApplyMatrix && this._canApplyMatrix) this._applyMatrix = true; } var bounds = this._bounds, position = this._position; if (transformMatrix || applyMatrix) { this._changed(25); } var decomp = transformMatrix && bounds && matrix.decompose(); if (decomp && decomp.skewing.isZero() && decomp.rotation % 90 === 0) { for (var key in bounds) { var cache = bounds[key]; if (cache.nonscaling) { delete bounds[key]; } else if (applyMatrix || !cache.internal) { var rect = cache.rect; matrix._transformBounds(rect, rect); } } this._bounds = bounds; var cached = bounds[this._getBoundsCacheKey( this._boundsOptions || {})]; if (cached) { this._position = this._getPositionFromBounds(cached.rect); } } else if (transformMatrix && position && this._pivot) { this._position = matrix._transformPoint(position, position); } return this; }, _transformContent: function(matrix, applyRecursively, setApplyMatrix) { var children = this._children; if (children) { for (var i = 0, l = children.length; i < l; i++) { children[i].transform(matrix, applyRecursively, setApplyMatrix); } return true; } }, globalToLocal: function() { return this.getGlobalMatrix(true)._inverseTransform( Point.read(arguments)); }, localToGlobal: function() { return this.getGlobalMatrix(true)._transformPoint( Point.read(arguments)); }, parentToLocal: function() { return this._matrix._inverseTransform(Point.read(arguments)); }, localToParent: function() { return this._matrix._transformPoint(Point.read(arguments)); }, fitBounds: function(rectangle, fill) { rectangle = Rectangle.read(arguments); var bounds = this.getBounds(), itemRatio = bounds.height / bounds.width, rectRatio = rectangle.height / rectangle.width, scale = (fill ? itemRatio > rectRatio : itemRatio < rectRatio) ? rectangle.width / bounds.width : rectangle.height / bounds.height, newBounds = new Rectangle(new Point(), new Size(bounds.width * scale, bounds.height * scale)); newBounds.setCenter(rectangle.getCenter()); this.setBounds(newBounds); } }), { _setStyles: function(ctx, param, viewMatrix, strokeMatrix) { var style = this._style, matrix = this._matrix; if (style.hasFill()) { ctx.fillStyle = style.getFillColor().toCanvasStyle(ctx, matrix, strokeMatrix); } if (style.hasStroke()) { ctx.strokeStyle = style.getStrokeColor().toCanvasStyle(ctx, matrix, strokeMatrix); ctx.lineWidth = style.getStrokeWidth(); var strokeJoin = style.getStrokeJoin(), strokeCap = style.getStrokeCap(), miterLimit = style.getMiterLimit(); if (strokeJoin) ctx.lineJoin = strokeJoin; if (strokeCap) ctx.lineCap = strokeCap; if (miterLimit) ctx.miterLimit = miterLimit; if (paper.support.nativeDash) { var dashArray = style.getDashArray(), dashOffset = style.getDashOffset(); if (dashArray && dashArray.length) { if ('setLineDash' in ctx) { ctx.setLineDash(dashArray); ctx.lineDashOffset = dashOffset; } else { ctx.mozDash = dashArray; ctx.mozDashOffset = dashOffset; } } } } if (style.hasShadow()) { var pixelRatio = param.pixelRatio || 1, mx = viewMatrix._shiftless().prepend( new Matrix().scale(pixelRatio, pixelRatio)), blur = mx.transform(new Point(style.getShadowBlur(), 0)), offset = mx.transform(this.getShadowOffset()); ctx.shadowColor = style.getShadowColor().toCanvasStyle(ctx); ctx.shadowBlur = blur.getLength(); ctx.shadowOffsetX = offset.x; ctx.shadowOffsetY = offset.y; } }, draw: function(ctx, param, parentStrokeMatrix) { var updateVersion = this._updateVersion = this._project._updateVersion; if (!this._visible || this._opacity === 0) return; var matrices = param.matrices, viewMatrix = param.viewMatrix, matrix = this._matrix, globalMatrix = matrices[matrices.length - 1].appended(matrix); if (!globalMatrix.isInvertible()) return; viewMatrix = viewMatrix ? viewMatrix.appended(globalMatrix) : globalMatrix; matrices.push(globalMatrix); if (param.updateMatrix) { this._globalMatrix = globalMatrix; } var blendMode = this._blendMode, opacity = Numerical.clamp(this._opacity, 0, 1), normalBlend = blendMode === 'normal', nativeBlend = BlendMode.nativeModes[blendMode], direct = normalBlend && opacity === 1 || param.dontStart || param.clip || (nativeBlend || normalBlend && opacity < 1) && this._canComposite(), pixelRatio = param.pixelRatio || 1, mainCtx, itemOffset, prevOffset; if (!direct) { var bounds = this.getStrokeBounds(viewMatrix); if (!bounds.width || !bounds.height) { matrices.pop(); return; } prevOffset = param.offset; itemOffset = param.offset = bounds.getTopLeft().floor(); mainCtx = ctx; ctx = CanvasProvider.getContext(bounds.getSize().ceil().add(1) .multiply(pixelRatio)); if (pixelRatio !== 1) ctx.scale(pixelRatio, pixelRatio); } ctx.save(); var strokeMatrix = parentStrokeMatrix ? parentStrokeMatrix.appended(matrix) : this._canScaleStroke && !this.getStrokeScaling(true) && viewMatrix, clip = !direct && param.clipItem, transform = !strokeMatrix || clip; if (direct) { ctx.globalAlpha = opacity; if (nativeBlend) ctx.globalCompositeOperation = blendMode; } else if (transform) { ctx.translate(-itemOffset.x, -itemOffset.y); } if (transform) { (direct ? matrix : viewMatrix).applyToContext(ctx); } if (clip) { param.clipItem.draw(ctx, param.extend({ clip: true })); } if (strokeMatrix) { ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); var offset = param.offset; if (offset) ctx.translate(-offset.x, -offset.y); } this._draw(ctx, param, viewMatrix, strokeMatrix); ctx.restore(); matrices.pop(); if (param.clip && !param.dontFinish) { ctx.clip(this.getFillRule()); } if (!direct) { BlendMode.process(blendMode, ctx, mainCtx, opacity, itemOffset.subtract(prevOffset).multiply(pixelRatio)); CanvasProvider.release(ctx); param.offset = prevOffset; } }, _isUpdated: function(updateVersion) { var parent = this._parent; if (parent instanceof CompoundPath) return parent._isUpdated(updateVersion); var updated = this._updateVersion === updateVersion; if (!updated && parent && parent._visible && parent._isUpdated(updateVersion)) { this._updateVersion = updateVersion; updated = true; } return updated; }, _drawSelection: function(ctx, matrix, size, selectionItems, updateVersion) { var selection = this._selection, itemSelected = selection & 1, boundsSelected = selection & 2 || itemSelected && this._selectBounds, positionSelected = selection & 4; if (!this._drawSelected) itemSelected = false; if ((itemSelected || boundsSelected || positionSelected) && this._isUpdated(updateVersion)) { var layer, color = this.getSelectedColor(true) || (layer = this.getLayer()) && layer.getSelectedColor(true), mx = matrix.appended(this.getGlobalMatrix(true)), half = size / 2; ctx.strokeStyle = ctx.fillStyle = color ? color.toCanvasStyle(ctx) : '#009dec'; ctx.lineWidth=2.5; if (itemSelected) this._drawSelected(ctx, mx, selectionItems); if (positionSelected) { var pos = this.getPosition(true), parent = this._parent, point = parent ? parent.localToGlobal(pos) : pos, x = point.x, y = point.y; ctx.beginPath(); ctx.arc(x, y, half, 0, Math.PI * 2, true); ctx.stroke(); var deltas = [[0, -1], [1, 0], [0, 1], [-1, 0]], start = half, end = size + 1; for (var i = 0; i < 4; i++) { var delta = deltas[i], dx = delta[0], dy = delta[1]; ctx.moveTo(x + dx * start, y + dy * start); ctx.lineTo(x + dx * end, y + dy * end); ctx.stroke(); } } if (boundsSelected) { var coords = mx._transformCorners(this.getInternalBounds()); ctx.beginPath(); for (var i = 0; i < 8; i++) { ctx[!i ? 'moveTo' : 'lineTo'](coords[i], coords[++i]); } ctx.closePath(); ctx.stroke(); for (var i = 0; i < 8; i++) { ctx.fillRect(coords[i] - half, coords[++i] - half, size, size); } } } }, _canComposite: function() { return false; } }, Base.each(['down', 'drag', 'up', 'move'], function(key) { this['removeOn' + Base.capitalize(key)] = function() { var hash = {}; hash[key] = true; return this.removeOn(hash); }; }, { removeOn: function(obj) { for (var name in obj) { if (obj[name]) { var key = 'mouse' + name, project = this._project, sets = project._removeSets = project._removeSets || {}; sets[key] = sets[key] || {}; sets[key][this._id] = this; } } return this; } }), { tween: function(from, to, options) { if (!options) { options = to; to = from; from = null; if (!options) { options = to; to = null; } } var easing = options && options.easing, start = options && options.start, duration = options != null && ( typeof options === 'number' ? options : options.duration ), tween = new Tween(this, from, to, duration, easing, start); function onFrame(event) { tween._handleFrame(event.time * 1000); if (!tween.running) { this.off('frame', onFrame); } } if (duration) { this.on('frame', onFrame); } return tween; }, tweenTo: function(to, options) { return this.tween(null, to, options); }, tweenFrom: function(from, options) { return this.tween(from, null, options); } }); var Group = Item.extend({ _class: 'Group', _selectBounds: false, _selectChildren: true, _serializeFields: { children: [] }, initialize: function Group(arg) { this._children = []; this._namedChildren = {}; if (!this._initialize(arg)) this.addChildren(Array.isArray(arg) ? arg : arguments); }, _changed: function _changed(flags) { _changed.base.call(this, flags); if (flags & 2050) { this._clipItem = undefined; } }, _getClipItem: function() { var clipItem = this._clipItem; if (clipItem === undefined) { clipItem = null; var children = this._children; for (var i = 0, l = children.length; i < l; i++) { if (children[i]._clipMask) { clipItem = children[i]; break; } } this._clipItem = clipItem; } return clipItem; }, isClipped: function() { return !!this._getClipItem(); }, setClipped: function(clipped) { var child = this.getFirstChild(); if (child) child.setClipMask(clipped); }, _getBounds: function _getBounds(matrix, options) { var clipItem = this._getClipItem(); return clipItem ? clipItem._getCachedBounds(clipItem._matrix.prepended(matrix), Base.set({}, options, { stroke: false })) : _getBounds.base.call(this, matrix, options); }, _hitTestChildren: function _hitTestChildren(point, options, viewMatrix) { var clipItem = this._getClipItem(); return (!clipItem || clipItem.contains(point)) && _hitTestChildren.base.call(this, point, options, viewMatrix, clipItem); }, _draw: function(ctx, param) { var clip = param.clip, clipItem = !clip && this._getClipItem(); param = param.extend({ clipItem: clipItem, clip: false }); if (clip) { ctx.beginPath(); param.dontStart = param.dontFinish = true; } else if (clipItem) { clipItem.draw(ctx, param.extend({ clip: true })); } var children = this._children; for (var i = 0, l = children.length; i < l; i++) { var item = children[i]; if (item !== clipItem) item.draw(ctx, param); } } }); var Layer = Group.extend({ _class: 'Layer', initialize: function Layer() { Group.apply(this, arguments); }, _getOwner: function() { return this._parent || this._index != null && this._project; }, isInserted: function isInserted() { return this._parent ? isInserted.base.call(this) : this._index != null; }, activate: function() { this._project._activeLayer = this; }, _hitTestSelf: function() { } }); var Shape = Item.extend({ _class: 'Shape', _applyMatrix: false, _canApplyMatrix: false, _canScaleStroke: true, _serializeFields: { type: null, size: null, radius: null }, initialize: function Shape(props, point) { this._initialize(props, point); }, _equals: function(item) { return this._type === item._type && this._size.equals(item._size) && Base.equals(this._radius, item._radius); }, copyContent: function(source) { this.setType(source._type); this.setSize(source._size); this.setRadius(source._radius); }, getType: function() { return this._type; }, setType: function(type) { this._type = type; }, getShape: '#getType', setShape: '#setType', getSize: function() { var size = this._size; return new LinkedSize(size.width, size.height, this, 'setSize'); }, setSize: function() { var size = Size.read(arguments); if (!this._size) { this._size = size.clone(); } else if (!this._size.equals(size)) { var type = this._type, width = size.width, height = size.height; if (type === 'rectangle') { this._radius.set(Size.min(this._radius, size.divide(2).abs())); } else if (type === 'circle') { width = height = (width + height) / 2; this._radius = width / 2; } else if (type === 'ellipse') { this._radius._set(width / 2, height / 2); } this._size._set(width, height); this._changed(9); } }, getRadius: function() { var rad = this._radius; return this._type === 'circle' ? rad : new LinkedSize(rad.width, rad.height, this, 'setRadius'); }, setRadius: function(radius) { var type = this._type; if (type === 'circle') { if (radius === this._radius) return; var size = radius * 2; this._radius = radius; this._size._set(size, size); } else { radius = Size.read(arguments); if (!this._radius) { this._radius = radius.clone(); } else { if (this._radius.equals(radius)) return; this._radius.set(radius); if (type === 'rectangle') { var size = Size.max(this._size, radius.multiply(2)); this._size.set(size); } else if (type === 'ellipse') { this._size._set(radius.width * 2, radius.height * 2); } } } this._changed(9); }, isEmpty: function() { return false; }, toPath: function(insert) { var path = new Path[Base.capitalize(this._type)]({ center: new Point(), size: this._size, radius: this._radius, insert: false }); path.copyAttributes(this); if (paper.settings.applyMatrix) path.setApplyMatrix(true); if (insert === undefined || insert) path.insertAbove(this); return path; }, toShape: '#clone', _asPathItem: function() { return this.toPath(false); }, _draw: function(ctx, param, viewMatrix, strokeMatrix) { var style = this._style, hasFill = style.hasFill(), hasStroke = style.hasStroke(), dontPaint = param.dontFinish || param.clip, untransformed = !strokeMatrix; if (hasFill || hasStroke || dontPaint) { var type = this._type, radius = this._radius, isCircle = type === 'circle'; if (!param.dontStart) ctx.beginPath(); if (untransformed && isCircle) { ctx.arc(0, 0, radius, 0, Math.PI * 2, true); } else { var rx = isCircle ? radius : radius.width, ry = isCircle ? radius : radius.height, size = this._size, width = size.width, height = size.height; if (untransformed && type === 'rectangle' && rx === 0 && ry === 0) { ctx.rect(-width / 2, -height / 2, width, height); } else { var x = width / 2, y = height / 2, kappa = 1 - 0.5522847498307936, cx = rx * kappa, cy = ry * kappa, c = [ -x, -y + ry, -x, -y + cy, -x + cx, -y, -x + rx, -y, x - rx, -y, x - cx, -y, x, -y + cy, x, -y + ry, x, y - ry, x, y - cy, x - cx, y, x - rx, y, -x + rx, y, -x + cx, y, -x, y - cy, -x, y - ry ]; if (strokeMatrix) strokeMatrix.transform(c, c, 32); ctx.moveTo(c[0], c[1]); ctx.bezierCurveTo(c[2], c[3], c[4], c[5], c[6], c[7]); if (x !== rx) ctx.lineTo(c[8], c[9]); ctx.bezierCurveTo(c[10], c[11], c[12], c[13], c[14], c[15]); if (y !== ry) ctx.lineTo(c[16], c[17]); ctx.bezierCurveTo(c[18], c[19], c[20], c[21], c[22], c[23]); if (x !== rx) ctx.lineTo(c[24], c[25]); ctx.bezierCurveTo(c[26], c[27], c[28], c[29], c[30], c[31]); } } ctx.closePath(); } if (!dontPaint && (hasFill || hasStroke)) { this._setStyles(ctx, param, viewMatrix, strokeMatrix); if (hasFill) { ctx.fill(style.getFillRule()); ctx.shadowColor = 'rgba(0,0,0,0)'; } if (hasStroke) ctx.stroke(); } }, _canComposite: function() { return !(this.hasFill() && this.hasStroke()); }, _getBounds: function(matrix, options) { var rect = new Rectangle(this._size).setCenter(0, 0), style = this._style, strokeWidth = options.stroke && style.hasStroke() && style.getStrokeWidth(); if (matrix) rect = matrix._transformBounds(rect); return strokeWidth ? rect.expand(Path._getStrokePadding(strokeWidth, this._getStrokeMatrix(matrix, options))) : rect; } }, new function() { function getCornerCenter(that, point, expand) { var radius = that._radius; if (!radius.isZero()) { var halfSize = that._size.divide(2); for (var q = 1; q <= 4; q++) { var dir = new Point(q > 1 && q < 4 ? -1 : 1, q > 2 ? -1 : 1), corner = dir.multiply(halfSize), center = corner.subtract(dir.multiply(radius)), rect = new Rectangle( expand ? corner.add(dir.multiply(expand)) : corner, center); if (rect.contains(point)) return { point: center, quadrant: q }; } } } function isOnEllipseStroke(point, radius, padding, quadrant) { var vector = point.divide(radius); return (!quadrant || vector.isInQuadrant(quadrant)) && vector.subtract(vector.normalize()).multiply(radius) .divide(padding).length <= 1; } return { _contains: function _contains(point) { if (this._type === 'rectangle') { var center = getCornerCenter(this, point); return center ? point.subtract(center.point).divide(this._radius) .getLength() <= 1 : _contains.base.call(this, point); } else { return point.divide(this.size).getLength() <= 0.5; } }, _hitTestSelf: function _hitTestSelf(point, options, viewMatrix, strokeMatrix) { var hit = false, style = this._style, hitStroke = options.stroke && style.hasStroke(), hitFill = options.fill && style.hasFill(); if (hitStroke || hitFill) { var type = this._type, radius = this._radius, strokeRadius = hitStroke ? style.getStrokeWidth() / 2 : 0, strokePadding = options._tolerancePadding.add( Path._getStrokePadding(strokeRadius, !style.getStrokeScaling() && strokeMatrix)); if (type === 'rectangle') { var padding = strokePadding.multiply(2), center = getCornerCenter(this, point, padding); if (center) { hit = isOnEllipseStroke(point.subtract(center.point), radius, strokePadding, center.quadrant); } else { var rect = new Rectangle(this._size).setCenter(0, 0), outer = rect.expand(padding), inner = rect.expand(padding.negate()); hit = outer._containsPoint(point) && !inner._containsPoint(point); } } else { hit = isOnEllipseStroke(point, radius, strokePadding); } } return hit ? new HitResult(hitStroke ? 'stroke' : 'fill', this) : _hitTestSelf.base.apply(this, arguments); } }; }, { statics: new function() { function createShape(type, point, size, radius, args) { var item = Base.create(Shape.prototype); item._type = type; item._size = size; item._radius = radius; item._initialize(Base.getNamed(args), point); return item; } return { Circle: function() { var args = arguments, center = Point.readNamed(args, 'center'), radius = Base.readNamed(args, 'radius'); return createShape('circle', center, new Size(radius * 2), radius, args); }, Rectangle: function() { var args = arguments, rect = Rectangle.readNamed(args, 'rectangle'), radius = Size.min(Size.readNamed(args, 'radius'), rect.getSize(true).divide(2)); return createShape('rectangle', rect.getCenter(true), rect.getSize(true), radius, args); }, Ellipse: function() { var args = arguments, ellipse = Shape._readEllipse(args), radius = ellipse.radius; return createShape('ellipse', ellipse.center, radius.multiply(2), radius, args); }, _readEllipse: function(args) { var center, radius; if (Base.hasNamed(args, 'radius')) { center = Point.readNamed(args, 'center'); radius = Size.readNamed(args, 'radius'); } else { var rect = Rectangle.readNamed(args, 'rectangle'); center = rect.getCenter(true); radius = rect.getSize(true).divide(2); } return { center: center, radius: radius }; } }; }}); var Raster = Item.extend({ _class: 'Raster', _applyMatrix: false, _canApplyMatrix: false, _boundsOptions: { stroke: false, handle: false }, _serializeFields: { crossOrigin: null, source: null }, _prioritize: ['crossOrigin'], _smoothing: false, beans: true, initialize: function Raster(source, position) { if (!this._initialize(source, position !== undefined && Point.read(arguments))) { var image, type = typeof source, object = type === 'string' ? document.getElementById(source) : type === 'object' ? source : null; if (object && object !== Item.NO_INSERT) { if (object.getContext || object.naturalHeight != null) { image = object; } else if (object) { var size = Size.read(arguments); if (!size.isZero()) { image = CanvasProvider.getCanvas(size); } } } if (image) { this.setImage(image); } else { this.setSource(source); } } if (!this._size) { this._size = new Size(); this._loaded = false; } }, _equals: function(item) { return this.getSource() === item.getSource(); }, copyContent: function(source) { var image = source._image, canvas = source._canvas; if (image) { this._setImage(image); } else if (canvas) { var copyCanvas = CanvasProvider.getCanvas(source._size); copyCanvas.getContext('2d').drawImage(canvas, 0, 0); this._setImage(copyCanvas); } this._crossOrigin = source._crossOrigin; }, getSize: function() { var size = this._size; return new LinkedSize(size ? size.width : 0, size ? size.height : 0, this, 'setSize'); }, setSize: function() { var size = Size.read(arguments); if (!size.equals(this._size)) { if (size.width > 0 && size.height > 0) { var element = this.getElement(); this._setImage(CanvasProvider.getCanvas(size)); if (element) this.getContext(true).drawImage(element, 0, 0, size.width, size.height); } else { if (this._canvas) CanvasProvider.release(this._canvas); this._size = size.clone(); } } }, getWidth: function() { return this._size ? this._size.width : 0; }, setWidth: function(width) { this.setSize(width, this.getHeight()); }, getHeight: function() { return this._size ? this._size.height : 0; }, setHeight: function(height) { this.setSize(this.getWidth(), height); }, getLoaded: function() { return this._loaded; }, isEmpty: function() { var size = this._size; return !size || size.width === 0 && size.height === 0; }, getResolution: function() { var matrix = this._matrix, orig = new Point(0, 0).transform(matrix), u = new Point(1, 0).transform(matrix).subtract(orig), v = new Point(0, 1).transform(matrix).subtract(orig); return new Size( 72 / u.getLength(), 72 / v.getLength() ); }, getPpi: '#getResolution', getImage: function() { return this._image; }, setImage: function(image) { var that = this; function emit(event) { var view = that.getView(), type = event && event.type || 'load'; if (view && that.responds(type)) { paper = view._scope; that.emit(type, new Event(event)); } } this._setImage(image); if (this._loaded) { setTimeout(emit, 0); } else if (image) { DomEvent.add(image, { load: function(event) { that._setImage(image); emit(event); }, error: emit }); } }, _setImage: function(image) { if (this._canvas) CanvasProvider.release(this._canvas); if (image && image.getContext) { this._image = null; this._canvas = image; this._loaded = true; } else { this._image = image; this._canvas = null; this._loaded = !!(image && image.src && image.complete); } this._size = new Size( image ? image.naturalWidth || image.width : 0, image ? image.naturalHeight || image.height : 0); this._context = null; this._changed(1033); }, getCanvas: function() { if (!this._canvas) { var ctx = CanvasProvider.getContext(this._size); try { if (this._image) ctx.drawImage(this._image, 0, 0); this._canvas = ctx.canvas; } catch (e) { CanvasProvider.release(ctx); } } return this._canvas; }, setCanvas: '#setImage', getContext: function(_change) { if (!this._context) this._context = this.getCanvas().getContext('2d'); if (_change) { this._image = null; this._changed(1025); } return this._context; }, setContext: function(context) { this._context = context; }, getSource: function() { var image = this._image; return image && image.src || this.toDataURL(); }, setSource: function(src) { var image = new self.Image(), crossOrigin = this._crossOrigin; if (crossOrigin) image.crossOrigin = crossOrigin; if (src) image.src = src; this.setImage(image); }, getCrossOrigin: function() { var image = this._image; return image && image.crossOrigin || this._crossOrigin || ''; }, setCrossOrigin: function(crossOrigin) { this._crossOrigin = crossOrigin; var image = this._image; if (image) image.crossOrigin = crossOrigin; }, getSmoothing: function() { return this._smoothing; }, setSmoothing: function(smoothing) { this._smoothing = smoothing; this._changed(257); }, getElement: function() { return this._canvas || this._loaded && this._image; } }, { beans: false, getSubCanvas: function() { var rect = Rectangle.read(arguments), ctx = CanvasProvider.getContext(rect.getSize()); var clippedStartX = Math.max(0, rect.x); var clippedStartY = Math.max(0, rect.y); var clippedEndX = Math.min(this.getCanvas().width, rect.x + rect.width); var clippedEndY = Math.min(this.getCanvas().height, rect.y + rect.height); ctx.drawImage(this.getCanvas(), clippedStartX, clippedStartY, clippedEndX - clippedStartX, clippedEndY - clippedStartY, clippedStartX - rect.x, clippedStartY - rect.y, clippedEndX - clippedStartX, clippedEndY - clippedStartY ); return ctx.canvas; }, getSubRaster: function() { var rect = Rectangle.read(arguments), raster = new Raster(Item.NO_INSERT); raster._setImage(this.getSubCanvas(rect)); raster.translate(rect.getCenter().subtract(this.getSize().divide(2))); raster._matrix.prepend(this._matrix); raster.insertAbove(this); return raster; }, toDataURL: function() { var image = this._image, src = image && image.src; if (/^data:/.test(src)) return src; var canvas = this.getCanvas(); return canvas ? canvas.toDataURL.apply(canvas, arguments) : null; }, drawImage: function(image ) { var point = Point.read(arguments, 1); this.getContext(true).drawImage(image, point.x, point.y); }, getAverageColor: function(object) { var bounds, path; if (!object) { bounds = this.getBounds(); } else if (object instanceof PathItem) { path = object; bounds = object.getBounds(); } else if (typeof object === 'object') { if ('width' in object) { bounds = new Rectangle(object); } else if ('x' in object) { bounds = new Rectangle(object.x - 0.5, object.y - 0.5, 1, 1); } } if (!bounds) return null; var sampleSize = 32, width = Math.min(bounds.width, sampleSize), height = Math.min(bounds.height, sampleSize); var ctx = Raster._sampleContext; if (!ctx) { ctx = Raster._sampleContext = CanvasProvider.getContext( new Size(sampleSize)); } else { ctx.clearRect(0, 0, sampleSize + 1, sampleSize + 1); } ctx.save(); var matrix = new Matrix() .scale(width / bounds.width, height / bounds.height) .translate(-bounds.x, -bounds.y); matrix.applyToContext(ctx); if (path) path.draw(ctx, new Base({ clip: true, matrices: [matrix] })); this._matrix.applyToContext(ctx); var element = this.getElement(), size = this._size; if (element) ctx.drawImage(element, -size.width / 2, -size.height / 2); ctx.restore(); var pixels = ctx.getImageData(0.5, 0.5, Math.ceil(width), Math.ceil(height)).data, channels = [0, 0, 0], total = 0; for (var i = 0, l = pixels.length; i < l; i += 4) { var alpha = pixels[i + 3]; total += alpha; alpha /= 255; channels[0] += pixels[i] * alpha; channels[1] += pixels[i + 1] * alpha; channels[2] += pixels[i + 2] * alpha; } for (var i = 0; i < 3; i++) channels[i] /= total; return total ? Color.read(channels) : null; }, getPixel: function() { var point = Point.read(arguments); var data = this.getContext().getImageData(point.x, point.y, 1, 1).data; return new Color('rgb', [data[0] / 255, data[1] / 255, data[2] / 255], data[3] / 255); }, setPixel: function() { var args = arguments, point = Point.read(args), color = Color.read(args), components = color._convert('rgb'), alpha = color._alpha, ctx = this.getContext(true), imageData = ctx.createImageData(1, 1), data = imageData.data; data[0] = components[0] * 255; data[1] = components[1] * 255; data[2] = components[2] * 255; data[3] = alpha != null ? alpha * 255 : 255; ctx.putImageData(imageData, point.x, point.y); }, clear: function() { var size = this._size; this.getContext(true).clearRect(0, 0, size.width + 1, size.height + 1); }, createImageData: function() { var size = Size.read(arguments); return this.getContext().createImageData(size.width, size.height); }, getImageData: function() { var rect = Rectangle.read(arguments); if (rect.isEmpty()) rect = new Rectangle(this._size); return this.getContext().getImageData(rect.x, rect.y, rect.width, rect.height); }, setImageData: function(data ) { var point = Point.read(arguments, 1); this.getContext(true).putImageData(data, point.x, point.y); }, _getBounds: function(matrix, options) { var rect = new Rectangle(this._size).setCenter(0, 0); return matrix ? matrix._transformBounds(rect) : rect; }, _hitTestSelf: function(point) { if (this._contains(point)) { var that = this; return new HitResult('pixel', that, { offset: point.add(that._size.divide(2)).round(), color: { get: function() { return that.getPixel(this.offset); } } }); } }, _draw: function(ctx, param, viewMatrix) { var element = this.getElement(); if (element && element.width > 0 && element.height > 0) { ctx.globalAlpha = Numerical.clamp(this._opacity, 0, 1); this._setStyles(ctx, param, viewMatrix); DomElement.setPrefixed( ctx, 'imageSmoothingEnabled', this._smoothing ); ctx.drawImage(element, -this._size.width / 2, -this._size.height / 2); } }, _canComposite: function() { return true; } }); var SymbolItem = Item.extend({ _class: 'SymbolItem', _applyMatrix: false, _canApplyMatrix: false, _boundsOptions: { stroke: true }, _serializeFields: { symbol: null }, initialize: function SymbolItem(arg0, arg1) { if (!this._initialize(arg0, arg1 !== undefined && Point.read(arguments, 1))) this.setDefinition(arg0 instanceof SymbolDefinition ? arg0 : new SymbolDefinition(arg0)); }, _equals: function(item) { return this._definition === item._definition; }, copyContent: function(source) { this.setDefinition(source._definition); }, getDefinition: function() { return this._definition; }, setDefinition: function(definition) { this._definition = definition; this._changed(9); }, getSymbol: '#getDefinition', setSymbol: '#setDefinition', isEmpty: function() { return this._definition._item.isEmpty(); }, _getBounds: function(matrix, options) { var item = this._definition._item; return item._getCachedBounds(item._matrix.prepended(matrix), options); }, _hitTestSelf: function(point, options, viewMatrix) { var opts = options.extend({ all: false }); var res = this._definition._item._hitTest(point, opts, viewMatrix); if (res) res.item = this; return res; }, _draw: function(ctx, param) { this._definition._item.draw(ctx, param); } }); var SymbolDefinition = Base.extend({ _class: 'SymbolDefinition', initialize: function SymbolDefinition(item, dontCenter) { this._id = UID.get(); this.project = paper.project; if (item) this.setItem(item, dontCenter); }, _serialize: function(options, dictionary) { return dictionary.add(this, function() { return Base.serialize([this._class, this._item], options, false, dictionary); }); }, _changed: function(flags) { if (flags & 8) Item._clearBoundsCache(this); if (flags & 1) this.project._changed(flags); }, getItem: function() { return this._item; }, setItem: function(item, _dontCenter) { if (item._symbol) item = item.clone(); if (this._item) this._item._symbol = null; this._item = item; item.remove(); item.setSelected(false); if (!_dontCenter) item.setPosition(new Point()); item._symbol = this; this._changed(9); }, getDefinition: '#getItem', setDefinition: '#setItem', place: function(position) { return new SymbolItem(this, position); }, clone: function() { return new SymbolDefinition(this._item.clone(false)); }, equals: function(symbol) { return symbol === this || symbol && this._item.equals(symbol._item) || false; } }); var HitResult = Base.extend({ _class: 'HitResult', initialize: function HitResult(type, item, values) { this.type = type; this.item = item; if (values) this.inject(values); }, statics: { getOptions: function(args) { var options = args && Base.read(args); return new Base({ type: null, tolerance: paper.settings.hitTolerance, fill: !options, stroke: !options, segments: !options, handles: false, ends: false, position: false, center: false, bounds: false, guides: false, selected: false }, options); } } }); var Segment = Base.extend({ _class: 'Segment', beans: true, _selection: 0, initialize: function Segment(arg0, arg1, arg2, arg3, arg4, arg5) { var count = arguments.length, point, handleIn, handleOut, selection; if (count > 0) { if (arg0 == null || typeof arg0 === 'object') { if (count === 1 && arg0 && 'point' in arg0) { point = arg0.point; handleIn = arg0.handleIn; handleOut = arg0.handleOut; selection = arg0.selection; } else { point = arg0; handleIn = arg1; handleOut = arg2; selection = arg3; } } else { point = [ arg0, arg1 ]; handleIn = arg2 !== undefined ? [ arg2, arg3 ] : null; handleOut = arg4 !== undefined ? [ arg4, arg5 ] : null; } } new SegmentPoint(point, this, '_point'); new SegmentPoint(handleIn, this, '_handleIn'); new SegmentPoint(handleOut, this, '_handleOut'); if (selection) this.setSelection(selection); }, _serialize: function(options, dictionary) { var point = this._point, selection = this._selection, obj = selection || this.hasHandles() ? [point, this._handleIn, this._handleOut] : point; if (selection) obj.push(selection); return Base.serialize(obj, options, true, dictionary); }, _changed: function(point) { var path = this._path; if (!path) return; var curves = path._curves, index = this._index, curve; if (curves) { if ((!point || point === this._point || point === this._handleIn) && (curve = index > 0 ? curves[index - 1] : path._closed ? curves[curves.length - 1] : null)) curve._changed(); if ((!point || point === this._point || point === this._handleOut) && (curve = curves[index])) curve._changed(); } path._changed(41); }, getPoint: function() { return this._point; }, setPoint: function() { this._point.set(Point.read(arguments)); }, getHandleIn: function() { return this._handleIn; }, setHandleIn: function() { this._handleIn.set(Point.read(arguments)); }, getHandleOut: function() { return this._handleOut; }, setHandleOut: function() { this._handleOut.set(Point.read(arguments)); }, hasHandles: function() { return !this._handleIn.isZero() || !this._handleOut.isZero(); }, isSmooth: function() { var handleIn = this._handleIn, handleOut = this._handleOut; return !handleIn.isZero() && !handleOut.isZero() && handleIn.isCollinear(handleOut); }, clearHandles: function() { this._handleIn._set(0, 0); this._handleOut._set(0, 0); }, getSelection: function() { return this._selection; }, setSelection: function(selection) { var oldSelection = this._selection, path = this._path; this._selection = selection = selection || 0; if (path && selection !== oldSelection) { path._updateSelection(this, oldSelection, selection); path._changed(257); } }, _changeSelection: function(flag, selected) { var selection = this._selection; this.setSelection(selected ? selection | flag : selection & ~flag); }, isSelected: function() { return !!(this._selection & 7); }, setSelected: function(selected) { this._changeSelection(7, selected); }, getIndex: function() { return this._index !== undefined ? this._index : null; }, getPath: function() { return this._path || null; }, getCurve: function() { var path = this._path, index = this._index; if (path) { if (index > 0 && !path._closed && index === path._segments.length - 1) index--; return path.getCurves()[index] || null; } return null; }, getLocation: function() { var curve = this.getCurve(); return curve ? new CurveLocation(curve, this === curve._segment1 ? 0 : 1) : null; }, getNext: function() { var segments = this._path && this._path._segments; return segments && (segments[this._index + 1] || this._path._closed && segments[0]) || null; }, smooth: function(options, _first, _last) { var opts = options || {}, type = opts.type, factor = opts.factor, prev = this.getPrevious(), next = this.getNext(), p0 = (prev || this)._point, p1 = this._point, p2 = (next || this)._point, d1 = p0.getDistance(p1), d2 = p1.getDistance(p2); if (!type || type === 'catmull-rom') { var a = factor === undefined ? 0.5 : factor, d1_a = Math.pow(d1, a), d1_2a = d1_a * d1_a, d2_a = Math.pow(d2, a), d2_2a = d2_a * d2_a; if (!_first && prev) { var A = 2 * d2_2a + 3 * d2_a * d1_a + d1_2a, N = 3 * d2_a * (d2_a + d1_a); this.setHandleIn(N !== 0 ? new Point( (d2_2a * p0._x + A * p1._x - d1_2a * p2._x) / N - p1._x, (d2_2a * p0._y + A * p1._y - d1_2a * p2._y) / N - p1._y) : new Point()); } if (!_last && next) { var A = 2 * d1_2a + 3 * d1_a * d2_a + d2_2a, N = 3 * d1_a * (d1_a + d2_a); this.setHandleOut(N !== 0 ? new Point( (d1_2a * p2._x + A * p1._x - d2_2a * p0._x) / N - p1._x, (d1_2a * p2._y + A * p1._y - d2_2a * p0._y) / N - p1._y) : new Point()); } } else if (type === 'geometric') { if (prev && next) { var vector = p0.subtract(p2), t = factor === undefined ? 0.4 : factor, k = t * d1 / (d1 + d2); if (!_first) this.setHandleIn(vector.multiply(k)); if (!_last) this.setHandleOut(vector.multiply(k - t)); } } else { throw new Error('Smoothing method \'' + type + '\' not supported.'); } }, getPrevious: function() { var segments = this._path && this._path._segments; return segments && (segments[this._index - 1] || this._path._closed && segments[segments.length - 1]) || null; }, isFirst: function() { return !this._index; }, isLast: function() { var path = this._path; return path && this._index === path._segments.length - 1 || false; }, reverse: function() { var handleIn = this._handleIn, handleOut = this._handleOut, tmp = handleIn.clone(); handleIn.set(handleOut); handleOut.set(tmp); }, reversed: function() { return new Segment(this._point, this._handleOut, this._handleIn); }, remove: function() { return this._path ? !!this._path.removeSegment(this._index) : false; }, clone: function() { return new Segment(this._point, this._handleIn, this._handleOut); }, equals: function(segment) { return segment === this || segment && this._class === segment._class && this._point.equals(segment._point) && this._handleIn.equals(segment._handleIn) && this._handleOut.equals(segment._handleOut) || false; }, toString: function() { var parts = [ 'point: ' + this._point ]; if (!this._handleIn.isZero()) parts.push('handleIn: ' + this._handleIn); if (!this._handleOut.isZero()) parts.push('handleOut: ' + this._handleOut); return '{ ' + parts.join(', ') + ' }'; }, transform: function(matrix) { this._transformCoordinates(matrix, new Array(6), true); this._changed(); }, interpolate: function(from, to, factor) { var u = 1 - factor, v = factor, point1 = from._point, point2 = to._point, handleIn1 = from._handleIn, handleIn2 = to._handleIn, handleOut2 = to._handleOut, handleOut1 = from._handleOut; this._point._set( u * point1._x + v * point2._x, u * point1._y + v * point2._y, true); this._handleIn._set( u * handleIn1._x + v * handleIn2._x, u * handleIn1._y + v * handleIn2._y, true); this._handleOut._set( u * handleOut1._x + v * handleOut2._x, u * handleOut1._y + v * handleOut2._y, true); this._changed(); }, _transformCoordinates: function(matrix, coords, change) { var point = this._point, handleIn = !change || !this._handleIn.isZero() ? this._handleIn : null, handleOut = !change || !this._handleOut.isZero() ? this._handleOut : null, x = point._x, y = point._y, i = 2; coords[0] = x; coords[1] = y; if (handleIn) { coords[i++] = handleIn._x + x; coords[i++] = handleIn._y + y; } if (handleOut) { coords[i++] = handleOut._x + x; coords[i++] = handleOut._y + y; } if (matrix) { matrix._transformCoordinates(coords, coords, i / 2); x = coords[0]; y = coords[1]; if (change) { point._x = x; point._y = y; i = 2; if (handleIn) { handleIn._x = coords[i++] - x; handleIn._y = coords[i++] - y; } if (handleOut) { handleOut._x = coords[i++] - x; handleOut._y = coords[i++] - y; } } else { if (!handleIn) { coords[i++] = x; coords[i++] = y; } if (!handleOut) { coords[i++] = x; coords[i++] = y; } } } return coords; } }); var SegmentPoint = Point.extend({ initialize: function SegmentPoint(point, owner, key) { var x, y, selected; if (!point) { x = y = 0; } else if ((x = point[0]) !== undefined) { y = point[1]; } else { var pt = point; if ((x = pt.x) === undefined) { pt = Point.read(arguments); x = pt.x; } y = pt.y; selected = pt.selected; } this._x = x; this._y = y; this._owner = owner; owner[key] = this; if (selected) this.setSelected(true); }, _set: function(x, y) { this._x = x; this._y = y; this._owner._changed(this); return this; }, getX: function() { return this._x; }, setX: function(x) { this._x = x; this._owner._changed(this); }, getY: function() { return this._y; }, setY: function(y) { this._y = y; this._owner._changed(this); }, isZero: function() { var isZero = Numerical.isZero; return isZero(this._x) && isZero(this._y); }, isSelected: function() { return !!(this._owner._selection & this._getSelection()); }, setSelected: function(selected) { this._owner._changeSelection(this._getSelection(), selected); }, _getSelection: function() { var owner = this._owner; return this === owner._point ? 1 : this === owner._handleIn ? 2 : this === owner._handleOut ? 4 : 0; } }); var Curve = Base.extend({ _class: 'Curve', beans: true, initialize: function Curve(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) { var count = arguments.length, seg1, seg2, point1, point2, handle1, handle2; if (count === 3) { this._path = arg0; seg1 = arg1; seg2 = arg2; } else if (!count) { seg1 = new Segment(); seg2 = new Segment(); } else if (count === 1) { if ('segment1' in arg0) { seg1 = new Segment(arg0.segment1); seg2 = new Segment(arg0.segment2); } else if ('point1' in arg0) { point1 = arg0.point1; handle1 = arg0.handle1; handle2 = arg0.handle2; point2 = arg0.point2; } else if (Array.isArray(arg0)) { point1 = [arg0[0], arg0[1]]; point2 = [arg0[6], arg0[7]]; handle1 = [arg0[2] - arg0[0], arg0[3] - arg0[1]]; handle2 = [arg0[4] - arg0[6], arg0[5] - arg0[7]]; } } else if (count === 2) { seg1 = new Segment(arg0); seg2 = new Segment(arg1); } else if (count === 4) { point1 = arg0; handle1 = arg1; handle2 = arg2; point2 = arg3; } else if (count === 8) { point1 = [arg0, arg1]; point2 = [arg6, arg7]; handle1 = [arg2 - arg0, arg3 - arg1]; handle2 = [arg4 - arg6, arg5 - arg7]; } this._segment1 = seg1 || new Segment(point1, null, handle1); this._segment2 = seg2 || new Segment(point2, handle2, null); }, _serialize: function(options, dictionary) { return Base.serialize(this.hasHandles() ? [this.getPoint1(), this.getHandle1(), this.getHandle2(), this.getPoint2()] : [this.getPoint1(), this.getPoint2()], options, true, dictionary); }, _changed: function() { this._length = this._bounds = undefined; }, clone: function() { return new Curve(this._segment1, this._segment2); }, toString: function() { var parts = [ 'point1: ' + this._segment1._point ]; if (!this._segment1._handleOut.isZero()) parts.push('handle1: ' + this._segment1._handleOut); if (!this._segment2._handleIn.isZero()) parts.push('handle2: ' + this._segment2._handleIn); parts.push('point2: ' + this._segment2._point); return '{ ' + parts.join(', ') + ' }'; }, classify: function() { return Curve.classify(this.getValues()); }, remove: function() { var removed = false; if (this._path) { var segment2 = this._segment2, handleOut = segment2._handleOut; removed = segment2.remove(); if (removed) this._segment1._handleOut.set(handleOut); } return removed; }, getPoint1: function() { return this._segment1._point; }, setPoint1: function() { this._segment1._point.set(Point.read(arguments)); }, getPoint2: function() { return this._segment2._point; }, setPoint2: function() { this._segment2._point.set(Point.read(arguments)); }, getHandle1: function() { return this._segment1._handleOut; }, setHandle1: function() { this._segment1._handleOut.set(Point.read(arguments)); }, getHandle2: function() { return this._segment2._handleIn; }, setHandle2: function() { this._segment2._handleIn.set(Point.read(arguments)); }, getSegment1: function() { return this._segment1; }, getSegment2: function() { return this._segment2; }, getPath: function() { return this._path; }, getIndex: function() { return this._segment1._index; }, getNext: function() { var curves = this._path && this._path._curves; return curves && (curves[this._segment1._index + 1] || this._path._closed && curves[0]) || null; }, getPrevious: function() { var curves = this._path && this._path._curves; return curves && (curves[this._segment1._index - 1] || this._path._closed && curves[curves.length - 1]) || null; }, isFirst: function() { return !this._segment1._index; }, isLast: function() { var path = this._path; return path && this._segment1._index === path._curves.length - 1 || false; }, isSelected: function() { return this.getPoint1().isSelected() && this.getHandle1().isSelected() && this.getHandle2().isSelected() && this.getPoint2().isSelected(); }, setSelected: function(selected) { this.getPoint1().setSelected(selected); this.getHandle1().setSelected(selected); this.getHandle2().setSelected(selected); this.getPoint2().setSelected(selected); }, getValues: function(matrix) { return Curve.getValues(this._segment1, this._segment2, matrix); }, getPoints: function() { var coords = this.getValues(), points = []; for (var i = 0; i < 8; i += 2) points.push(new Point(coords[i], coords[i + 1])); return points; } }, { getLength: function() { if (this._length == null) this._length = Curve.getLength(this.getValues(), 0, 1); return this._length; }, getArea: function() { return Curve.getArea(this.getValues()); }, getLine: function() { return new Line(this._segment1._point, this._segment2._point); }, getPart: function(from, to) { return new Curve(Curve.getPart(this.getValues(), from, to)); }, getPartLength: function(from, to) { return Curve.getLength(this.getValues(), from, to); }, divideAt: function(location) { return this.divideAtTime(location && location.curve === this ? location.time : this.getTimeAt(location)); }, divideAtTime: function(time, _setHandles) { var tMin = 1e-8, tMax = 1 - tMin, res = null; if (time >= tMin && time <= tMax) { var parts = Curve.subdivide(this.getValues(), time), left = parts[0], right = parts[1], setHandles = _setHandles || this.hasHandles(), seg1 = this._segment1, seg2 = this._segment2, path = this._path; if (setHandles) { seg1._handleOut._set(left[2] - left[0], left[3] - left[1]); seg2._handleIn._set(right[4] - right[6],right[5] - right[7]); } var x = left[6], y = left[7], segment = new Segment(new Point(x, y), setHandles && new Point(left[4] - x, left[5] - y), setHandles && new Point(right[2] - x, right[3] - y)); if (path) { path.insert(seg1._index + 1, segment); res = this.getNext(); } else { this._segment2 = segment; this._changed(); res = new Curve(segment, seg2); } } return res; }, splitAt: function(location) { var path = this._path; return path ? path.splitAt(location) : null; }, splitAtTime: function(time) { return this.splitAt(this.getLocationAtTime(time)); }, divide: function(offset, isTime) { return this.divideAtTime(offset === undefined ? 0.5 : isTime ? offset : this.getTimeAt(offset)); }, split: function(offset, isTime) { return this.splitAtTime(offset === undefined ? 0.5 : isTime ? offset : this.getTimeAt(offset)); }, reversed: function() { return new Curve(this._segment2.reversed(), this._segment1.reversed()); }, clearHandles: function() { this._segment1._handleOut._set(0, 0); this._segment2._handleIn._set(0, 0); }, statics: { getValues: function(segment1, segment2, matrix, straight) { var p1 = segment1._point, h1 = segment1._handleOut, h2 = segment2._handleIn, p2 = segment2._point, x1 = p1.x, y1 = p1.y, x2 = p2.x, y2 = p2.y, values = straight ? [ x1, y1, x1, y1, x2, y2, x2, y2 ] : [ x1, y1, x1 + h1._x, y1 + h1._y, x2 + h2._x, y2 + h2._y, x2, y2 ]; if (matrix) matrix._transformCoordinates(values, values, 4); return values; }, subdivide: function(v, t) { var x0 = v[0], y0 = v[1], x1 = v[2], y1 = v[3], x2 = v[4], y2 = v[5], x3 = v[6], y3 = v[7]; if (t === undefined) t = 0.5; var u = 1 - t, x4 = u * x0 + t * x1, y4 = u * y0 + t * y1, x5 = u * x1 + t * x2, y5 = u * y1 + t * y2, x6 = u * x2 + t * x3, y6 = u * y2 + t * y3, x7 = u * x4 + t * x5, y7 = u * y4 + t * y5, x8 = u * x5 + t * x6, y8 = u * y5 + t * y6, x9 = u * x7 + t * x8, y9 = u * y7 + t * y8; return [ [x0, y0, x4, y4, x7, y7, x9, y9], [x9, y9, x8, y8, x6, y6, x3, y3] ]; }, getMonoCurves: function(v, dir) { var curves = [], io = dir ? 0 : 1, o0 = v[io + 0], o1 = v[io + 2], o2 = v[io + 4], o3 = v[io + 6]; if ((o0 >= o1) === (o1 >= o2) && (o1 >= o2) === (o2 >= o3) || Curve.isStraight(v)) { curves.push(v); } else { var a = 3 * (o1 - o2) - o0 + o3, b = 2 * (o0 + o2) - 4 * o1, c = o1 - o0, tMin = 1e-8, tMax = 1 - tMin, roots = [], n = Numerical.solveQuadratic(a, b, c, roots, tMin, tMax); if (!n) { curves.push(v); } else { roots.sort(); var t = roots[0], parts = Curve.subdivide(v, t); curves.push(parts[0]); if (n > 1) { t = (roots[1] - t) / (1 - t); parts = Curve.subdivide(parts[1], t); curves.push(parts[0]); } curves.push(parts[1]); } } return curves; }, solveCubic: function (v, coord, val, roots, min, max) { var v0 = v[coord], v1 = v[coord + 2], v2 = v[coord + 4], v3 = v[coord + 6], res = 0; if ( !(v0 < val && v3 < val && v1 < val && v2 < val || v0 > val && v3 > val && v1 > val && v2 > val)) { var c = 3 * (v1 - v0), b = 3 * (v2 - v1) - c, a = v3 - v0 - c - b; res = Numerical.solveCubic(a, b, c, v0 - val, roots, min, max); } return res; }, getTimeOf: function(v, point) { var p0 = new Point(v[0], v[1]), p3 = new Point(v[6], v[7]), epsilon = 1e-12, geomEpsilon = 1e-7, t = point.isClose(p0, epsilon) ? 0 : point.isClose(p3, epsilon) ? 1 : null; if (t === null) { var coords = [point.x, point.y], roots = []; for (var c = 0; c < 2; c++) { var count = Curve.solveCubic(v, c, coords[c], roots, 0, 1); for (var i = 0; i < count; i++) { var u = roots[i]; if (point.isClose(Curve.getPoint(v, u), geomEpsilon)) return u; } } } return point.isClose(p0, geomEpsilon) ? 0 : point.isClose(p3, geomEpsilon) ? 1 : null; }, getNearestTime: function(v, point) { if (Curve.isStraight(v)) { var x0 = v[0], y0 = v[1], x3 = v[6], y3 = v[7], vx = x3 - x0, vy = y3 - y0, det = vx * vx + vy * vy; if (det === 0) return 0; var u = ((point.x - x0) * vx + (point.y - y0) * vy) / det; return u < 1e-12 ? 0 : u > 0.999999999999 ? 1 : Curve.getTimeOf(v, new Point(x0 + u * vx, y0 + u * vy)); } var count = 100, minDist = Infinity, minT = 0; function refine(t) { if (t >= 0 && t <= 1) { var dist = point.getDistance(Curve.getPoint(v, t), true); if (dist < minDist) { minDist = dist; minT = t; return true; } } } for (var i = 0; i <= count; i++) refine(i / count); var step = 1 / (count * 2); while (step > 1e-8) { if (!refine(minT - step) && !refine(minT + step)) step /= 2; } return minT; }, getPart: function(v, from, to) { var flip = from > to; if (flip) { var tmp = from; from = to; to = tmp; } if (from > 0) v = Curve.subdivide(v, from)[1]; if (to < 1) v = Curve.subdivide(v, (to - from) / (1 - from))[0]; return flip ? [v[6], v[7], v[4], v[5], v[2], v[3], v[0], v[1]] : v; }, isFlatEnough: function(v, flatness) { var x0 = v[0], y0 = v[1], x1 = v[2], y1 = v[3], x2 = v[4], y2 = v[5], x3 = v[6], y3 = v[7], ux = 3 * x1 - 2 * x0 - x3, uy = 3 * y1 - 2 * y0 - y3, vx = 3 * x2 - 2 * x3 - x0, vy = 3 * y2 - 2 * y3 - y0; return Math.max(ux * ux, vx * vx) + Math.max(uy * uy, vy * vy) <= 16 * flatness * flatness; }, getArea: function(v) { var x0 = v[0], y0 = v[1], x1 = v[2], y1 = v[3], x2 = v[4], y2 = v[5], x3 = v[6], y3 = v[7]; return 3 * ((y3 - y0) * (x1 + x2) - (x3 - x0) * (y1 + y2) + y1 * (x0 - x2) - x1 * (y0 - y2) + y3 * (x2 + x0 / 3) - x3 * (y2 + y0 / 3)) / 20; }, getBounds: function(v) { var min = v.slice(0, 2), max = min.slice(), roots = [0, 0]; for (var i = 0; i < 2; i++) Curve._addBounds(v[i], v[i + 2], v[i + 4], v[i + 6], i, 0, min, max, roots); return new Rectangle(min[0], min[1], max[0] - min[0], max[1] - min[1]); }, _addBounds: function(v0, v1, v2, v3, coord, padding, min, max, roots) { function add(value, padding) { var left = value - padding, right = value + padding; if (left < min[coord]) min[coord] = left; if (right > max[coord]) max[coord] = right; } padding /= 2; var minPad = min[coord] - padding, maxPad = max[coord] + padding; if ( v0 < minPad || v1 < minPad || v2 < minPad || v3 < minPad || v0 > maxPad || v1 > maxPad || v2 > maxPad || v3 > maxPad) { if (v1 < v0 != v1 < v3 && v2 < v0 != v2 < v3) { add(v0, padding); add(v3, padding); } else { var a = 3 * (v1 - v2) - v0 + v3, b = 2 * (v0 + v2) - 4 * v1, c = v1 - v0, count = Numerical.solveQuadratic(a, b, c, roots), tMin = 1e-8, tMax = 1 - tMin; add(v3, 0); for (var i = 0; i < count; i++) { var t = roots[i], u = 1 - t; if (tMin <= t && t <= tMax) add(u * u * u * v0 + 3 * u * u * t * v1 + 3 * u * t * t * v2 + t * t * t * v3, padding); } } } } }}, Base.each( ['getBounds', 'getStrokeBounds', 'getHandleBounds'], function(name) { this[name] = function() { if (!this._bounds) this._bounds = {}; var bounds = this._bounds[name]; if (!bounds) { bounds = this._bounds[name] = Path[name]( [this._segment1, this._segment2], false, this._path); } return bounds.clone(); }; }, { }), Base.each({ isStraight: function(p1, h1, h2, p2) { if (h1.isZero() && h2.isZero()) { return true; } else { var v = p2.subtract(p1); if (v.isZero()) { return false; } else if (v.isCollinear(h1) && v.isCollinear(h2)) { var l = new Line(p1, p2), epsilon = 1e-7; if (l.getDistance(p1.add(h1)) < epsilon && l.getDistance(p2.add(h2)) < epsilon) { var div = v.dot(v), s1 = v.dot(h1) / div, s2 = v.dot(h2) / div; return s1 >= 0 && s1 <= 1 && s2 <= 0 && s2 >= -1; } } } return false; }, isLinear: function(p1, h1, h2, p2) { var third = p2.subtract(p1).divide(3); return h1.equals(third) && h2.negate().equals(third); } }, function(test, name) { this[name] = function(epsilon) { var seg1 = this._segment1, seg2 = this._segment2; return test(seg1._point, seg1._handleOut, seg2._handleIn, seg2._point, epsilon); }; this.statics[name] = function(v, epsilon) { var x0 = v[0], y0 = v[1], x3 = v[6], y3 = v[7]; return test( new Point(x0, y0), new Point(v[2] - x0, v[3] - y0), new Point(v[4] - x3, v[5] - y3), new Point(x3, y3), epsilon); }; }, { statics: {}, hasHandles: function() { return !this._segment1._handleOut.isZero() || !this._segment2._handleIn.isZero(); }, hasLength: function(epsilon) { return (!this.getPoint1().equals(this.getPoint2()) || this.hasHandles()) && this.getLength() > (epsilon || 0); }, isCollinear: function(curve) { return curve && this.isStraight() && curve.isStraight() && this.getLine().isCollinear(curve.getLine()); }, isHorizontal: function() { return this.isStraight() && Math.abs(this.getTangentAtTime(0.5).y) < 1e-8; }, isVertical: function() { return this.isStraight() && Math.abs(this.getTangentAtTime(0.5).x) < 1e-8; } }), { beans: false, getLocationAt: function(offset, _isTime) { return this.getLocationAtTime( _isTime ? offset : this.getTimeAt(offset)); }, getLocationAtTime: function(t) { return t != null && t >= 0 && t <= 1 ? new CurveLocation(this, t) : null; }, getTimeAt: function(offset, start) { return Curve.getTimeAt(this.getValues(), offset, start); }, getParameterAt: '#getTimeAt', getTimesWithTangent: function () { var tangent = Point.read(arguments); return tangent.isZero() ? [] : Curve.getTimesWithTangent(this.getValues(), tangent); }, getOffsetAtTime: function(t) { return this.getPartLength(0, t); }, getLocationOf: function() { return this.getLocationAtTime(this.getTimeOf(Point.read(arguments))); }, getOffsetOf: function() { var loc = this.getLocationOf.apply(this, arguments); return loc ? loc.getOffset() : null; }, getTimeOf: function() { return Curve.getTimeOf(this.getValues(), Point.read(arguments)); }, getParameterOf: '#getTimeOf', getNearestLocation: function() { var point = Point.read(arguments), values = this.getValues(), t = Curve.getNearestTime(values, point), pt = Curve.getPoint(values, t); return new CurveLocation(this, t, pt, null, point.getDistance(pt)); }, getNearestPoint: function() { var loc = this.getNearestLocation.apply(this, arguments); return loc ? loc.getPoint() : loc; } }, new function() { var methods = ['getPoint', 'getTangent', 'getNormal', 'getWeightedTangent', 'getWeightedNormal', 'getCurvature']; return Base.each(methods, function(name) { this[name + 'At'] = function(location, _isTime) { var values = this.getValues(); return Curve[name](values, _isTime ? location : Curve.getTimeAt(values, location)); }; this[name + 'AtTime'] = function(time) { return Curve[name](this.getValues(), time); }; }, { statics: { _evaluateMethods: methods } } ); }, new function() { function getLengthIntegrand(v) { var x0 = v[0], y0 = v[1], x1 = v[2], y1 = v[3], x2 = v[4], y2 = v[5], x3 = v[6], y3 = v[7], ax = 9 * (x1 - x2) + 3 * (x3 - x0), bx = 6 * (x0 + x2) - 12 * x1, cx = 3 * (x1 - x0), ay = 9 * (y1 - y2) + 3 * (y3 - y0), by = 6 * (y0 + y2) - 12 * y1, cy = 3 * (y1 - y0); return function(t) { var dx = (ax * t + bx) * t + cx, dy = (ay * t + by) * t + cy; return Math.sqrt(dx * dx + dy * dy); }; } function getIterations(a, b) { return Math.max(2, Math.min(16, Math.ceil(Math.abs(b - a) * 32))); } function evaluate(v, t, type, normalized) { if (t == null || t < 0 || t > 1) return null; var x0 = v[0], y0 = v[1], x1 = v[2], y1 = v[3], x2 = v[4], y2 = v[5], x3 = v[6], y3 = v[7], isZero = Numerical.isZero; if (isZero(x1 - x0) && isZero(y1 - y0)) { x1 = x0; y1 = y0; } if (isZero(x2 - x3) && isZero(y2 - y3)) { x2 = x3; y2 = y3; } var cx = 3 * (x1 - x0), bx = 3 * (x2 - x1) - cx, ax = x3 - x0 - cx - bx, cy = 3 * (y1 - y0), by = 3 * (y2 - y1) - cy, ay = y3 - y0 - cy - by, x, y; if (type === 0) { x = t === 0 ? x0 : t === 1 ? x3 : ((ax * t + bx) * t + cx) * t + x0; y = t === 0 ? y0 : t === 1 ? y3 : ((ay * t + by) * t + cy) * t + y0; } else { var tMin = 1e-8, tMax = 1 - tMin; if (t < tMin) { x = cx; y = cy; } else if (t > tMax) { x = 3 * (x3 - x2); y = 3 * (y3 - y2); } else { x = (3 * ax * t + 2 * bx) * t + cx; y = (3 * ay * t + 2 * by) * t + cy; } if (normalized) { if (x === 0 && y === 0 && (t < tMin || t > tMax)) { x = x2 - x1; y = y2 - y1; } var len = Math.sqrt(x * x + y * y); if (len) { x /= len; y /= len; } } if (type === 3) { var x2 = 6 * ax * t + 2 * bx, y2 = 6 * ay * t + 2 * by, d = Math.pow(x * x + y * y, 3 / 2); x = d !== 0 ? (x * y2 - y * x2) / d : 0; y = 0; } } return type === 2 ? new Point(y, -x) : new Point(x, y); } return { statics: { classify: function(v) { var x0 = v[0], y0 = v[1], x1 = v[2], y1 = v[3], x2 = v[4], y2 = v[5], x3 = v[6], y3 = v[7], a1 = x0 * (y3 - y2) + y0 * (x2 - x3) + x3 * y2 - y3 * x2, a2 = x1 * (y0 - y3) + y1 * (x3 - x0) + x0 * y3 - y0 * x3, a3 = x2 * (y1 - y0) + y2 * (x0 - x1) + x1 * y0 - y1 * x0, d3 = 3 * a3, d2 = d3 - a2, d1 = d2 - a2 + a1, l = Math.sqrt(d1 * d1 + d2 * d2 + d3 * d3), s = l !== 0 ? 1 / l : 0, isZero = Numerical.isZero, serpentine = 'serpentine'; d1 *= s; d2 *= s; d3 *= s; function type(type, t1, t2) { var hasRoots = t1 !== undefined, t1Ok = hasRoots && t1 > 0 && t1 < 1, t2Ok = hasRoots && t2 > 0 && t2 < 1; if (hasRoots && (!(t1Ok || t2Ok) || type === 'loop' && !(t1Ok && t2Ok))) { type = 'arch'; t1Ok = t2Ok = false; } return { type: type, roots: t1Ok || t2Ok ? t1Ok && t2Ok ? t1 < t2 ? [t1, t2] : [t2, t1] : [t1Ok ? t1 : t2] : null }; } if (isZero(d1)) { return isZero(d2) ? type(isZero(d3) ? 'line' : 'quadratic') : type(serpentine, d3 / (3 * d2)); } var d = 3 * d2 * d2 - 4 * d1 * d3; if (isZero(d)) { return type('cusp', d2 / (2 * d1)); } var f1 = d > 0 ? Math.sqrt(d / 3) : Math.sqrt(-d), f2 = 2 * d1; return type(d > 0 ? serpentine : 'loop', (d2 + f1) / f2, (d2 - f1) / f2); }, getLength: function(v, a, b, ds) { if (a === undefined) a = 0; if (b === undefined) b = 1; if (Curve.isStraight(v)) { var c = v; if (b < 1) { c = Curve.subdivide(c, b)[0]; a /= b; } if (a > 0) { c = Curve.subdivide(c, a)[1]; } var dx = c[6] - c[0], dy = c[7] - c[1]; return Math.sqrt(dx * dx + dy * dy); } return Numerical.integrate(ds || getLengthIntegrand(v), a, b, getIterations(a, b)); }, getTimeAt: function(v, offset, start) { if (start === undefined) start = offset < 0 ? 1 : 0; if (offset === 0) return start; var abs = Math.abs, epsilon = 1e-12, forward = offset > 0, a = forward ? start : 0, b = forward ? 1 : start, ds = getLengthIntegrand(v), rangeLength = Curve.getLength(v, a, b, ds), diff = abs(offset) - rangeLength; if (abs(diff) < epsilon) { return forward ? b : a; } else if (diff > epsilon) { return null; } var guess = offset / rangeLength, length = 0; function f(t) { length += Numerical.integrate(ds, start, t, getIterations(start, t)); start = t; return length - offset; } return Numerical.findRoot(f, ds, start + guess, a, b, 32, 1e-12); }, getPoint: function(v, t) { return evaluate(v, t, 0, false); }, getTangent: function(v, t) { return evaluate(v, t, 1, true); }, getWeightedTangent: function(v, t) { return evaluate(v, t, 1, false); }, getNormal: function(v, t) { return evaluate(v, t, 2, true); }, getWeightedNormal: function(v, t) { return evaluate(v, t, 2, false); }, getCurvature: function(v, t) { return evaluate(v, t, 3, false).x; }, getPeaks: function(v) { var x0 = v[0], y0 = v[1], x1 = v[2], y1 = v[3], x2 = v[4], y2 = v[5], x3 = v[6], y3 = v[7], ax = -x0 + 3 * x1 - 3 * x2 + x3, bx = 3 * x0 - 6 * x1 + 3 * x2, cx = -3 * x0 + 3 * x1, ay = -y0 + 3 * y1 - 3 * y2 + y3, by = 3 * y0 - 6 * y1 + 3 * y2, cy = -3 * y0 + 3 * y1, tMin = 1e-8, tMax = 1 - tMin, roots = []; Numerical.solveCubic( 9 * (ax * ax + ay * ay), 9 * (ax * bx + by * ay), 2 * (bx * bx + by * by) + 3 * (cx * ax + cy * ay), (cx * bx + by * cy), roots, tMin, tMax); return roots.sort(); } }}; }, new function() { function addLocation(locations, include, c1, t1, c2, t2, overlap) { var excludeStart = !overlap && c1.getPrevious() === c2, excludeEnd = !overlap && c1 !== c2 && c1.getNext() === c2, tMin = 1e-8, tMax = 1 - tMin; if (t1 !== null && t1 >= (excludeStart ? tMin : 0) && t1 <= (excludeEnd ? tMax : 1)) { if (t2 !== null && t2 >= (excludeEnd ? tMin : 0) && t2 <= (excludeStart ? tMax : 1)) { var loc1 = new CurveLocation(c1, t1, null, overlap), loc2 = new CurveLocation(c2, t2, null, overlap); loc1._intersection = loc2; loc2._intersection = loc1; if (!include || include(loc1)) { CurveLocation.insert(locations, loc1, true); } } } } function addCurveIntersections(v1, v2, c1, c2, locations, include, flip, recursion, calls, tMin, tMax, uMin, uMax) { if (++calls >= 4096 || ++recursion >= 40) return calls; var fatLineEpsilon = 1e-9, q0x = v2[0], q0y = v2[1], q3x = v2[6], q3y = v2[7], getSignedDistance = Line.getSignedDistance, d1 = getSignedDistance(q0x, q0y, q3x, q3y, v2[2], v2[3]), d2 = getSignedDistance(q0x, q0y, q3x, q3y, v2[4], v2[5]), factor = d1 * d2 > 0 ? 3 / 4 : 4 / 9, dMin = factor * Math.min(0, d1, d2), dMax = factor * Math.max(0, d1, d2), dp0 = getSignedDistance(q0x, q0y, q3x, q3y, v1[0], v1[1]), dp1 = getSignedDistance(q0x, q0y, q3x, q3y, v1[2], v1[3]), dp2 = getSignedDistance(q0x, q0y, q3x, q3y, v1[4], v1[5]), dp3 = getSignedDistance(q0x, q0y, q3x, q3y, v1[6], v1[7]), hull = getConvexHull(dp0, dp1, dp2, dp3), top = hull[0], bottom = hull[1], tMinClip, tMaxClip; if (d1 === 0 && d2 === 0 && dp0 === 0 && dp1 === 0 && dp2 === 0 && dp3 === 0 || (tMinClip = clipConvexHull(top, bottom, dMin, dMax)) == null || (tMaxClip = clipConvexHull(top.reverse(), bottom.reverse(), dMin, dMax)) == null) return calls; var tMinNew = tMin + (tMax - tMin) * tMinClip, tMaxNew = tMin + (tMax - tMin) * tMaxClip; if (Math.max(uMax - uMin, tMaxNew - tMinNew) < fatLineEpsilon) { var t = (tMinNew + tMaxNew) / 2, u = (uMin + uMax) / 2; addLocation(locations, include, flip ? c2 : c1, flip ? u : t, flip ? c1 : c2, flip ? t : u); } else { v1 = Curve.getPart(v1, tMinClip, tMaxClip); var uDiff = uMax - uMin; if (tMaxClip - tMinClip > 0.8) { if (tMaxNew - tMinNew > uDiff) { var parts = Curve.subdivide(v1, 0.5), t = (tMinNew + tMaxNew) / 2; calls = addCurveIntersections( v2, parts[0], c2, c1, locations, include, !flip, recursion, calls, uMin, uMax, tMinNew, t); calls = addCurveIntersections( v2, parts[1], c2, c1, locations, include, !flip, recursion, calls, uMin, uMax, t, tMaxNew); } else { var parts = Curve.subdivide(v2, 0.5), u = (uMin + uMax) / 2; calls = addCurveIntersections( parts[0], v1, c2, c1, locations, include, !flip, recursion, calls, uMin, u, tMinNew, tMaxNew); calls = addCurveIntersections( parts[1], v1, c2, c1, locations, include, !flip, recursion, calls, u, uMax, tMinNew, tMaxNew); } } else { if (uDiff === 0 || uDiff >= fatLineEpsilon) { calls = addCurveIntersections( v2, v1, c2, c1, locations, include, !flip, recursion, calls, uMin, uMax, tMinNew, tMaxNew); } else { calls = addCurveIntersections( v1, v2, c1, c2, locations, include, flip, recursion, calls, tMinNew, tMaxNew, uMin, uMax); } } } return calls; } function getConvexHull(dq0, dq1, dq2, dq3) { var p0 = [ 0, dq0 ], p1 = [ 1 / 3, dq1 ], p2 = [ 2 / 3, dq2 ], p3 = [ 1, dq3 ], dist1 = dq1 - (2 * dq0 + dq3) / 3, dist2 = dq2 - (dq0 + 2 * dq3) / 3, hull; if (dist1 * dist2 < 0) { hull = [[p0, p1, p3], [p0, p2, p3]]; } else { var distRatio = dist1 / dist2; hull = [ distRatio >= 2 ? [p0, p1, p3] : distRatio <= 0.5 ? [p0, p2, p3] : [p0, p1, p2, p3], [p0, p3] ]; } return (dist1 || dist2) < 0 ? hull.reverse() : hull; } function clipConvexHull(hullTop, hullBottom, dMin, dMax) { if (hullTop[0][1] < dMin) { return clipConvexHullPart(hullTop, true, dMin); } else if (hullBottom[0][1] > dMax) { return clipConvexHullPart(hullBottom, false, dMax); } else { return hullTop[0][0]; } } function clipConvexHullPart(part, top, threshold) { var px = part[0][0], py = part[0][1]; for (var i = 1, l = part.length; i < l; i++) { var qx = part[i][0], qy = part[i][1]; if (top ? qy >= threshold : qy <= threshold) { return qy === threshold ? qx : px + (threshold - py) * (qx - px) / (qy - py); } px = qx; py = qy; } return null; } function getCurveLineIntersections(v, px, py, vx, vy) { var isZero = Numerical.isZero; if (isZero(vx) && isZero(vy)) { var t = Curve.getTimeOf(v, new Point(px, py)); return t === null ? [] : [t]; } var angle = Math.atan2(-vy, vx), sin = Math.sin(angle), cos = Math.cos(angle), rv = [], roots = []; for (var i = 0; i < 8; i += 2) { var x = v[i] - px, y = v[i + 1] - py; rv.push( x * cos - y * sin, x * sin + y * cos); } Curve.solveCubic(rv, 1, 0, roots, 0, 1); return roots; } function addCurveLineIntersections(v1, v2, c1, c2, locations, include, flip) { var x1 = v2[0], y1 = v2[1], x2 = v2[6], y2 = v2[7], roots = getCurveLineIntersections(v1, x1, y1, x2 - x1, y2 - y1); for (var i = 0, l = roots.length; i < l; i++) { var t1 = roots[i], p1 = Curve.getPoint(v1, t1), t2 = Curve.getTimeOf(v2, p1); if (t2 !== null) { addLocation(locations, include, flip ? c2 : c1, flip ? t2 : t1, flip ? c1 : c2, flip ? t1 : t2); } } } function addLineIntersection(v1, v2, c1, c2, locations, include) { var pt = Line.intersect( v1[0], v1[1], v1[6], v1[7], v2[0], v2[1], v2[6], v2[7]); if (pt) { addLocation(locations, include, c1, Curve.getTimeOf(v1, pt), c2, Curve.getTimeOf(v2, pt)); } } function getCurveIntersections(v1, v2, c1, c2, locations, include) { var epsilon = 1e-12, min = Math.min, max = Math.max; if (max(v1[0], v1[2], v1[4], v1[6]) + epsilon > min(v2[0], v2[2], v2[4], v2[6]) && min(v1[0], v1[2], v1[4], v1[6]) - epsilon < max(v2[0], v2[2], v2[4], v2[6]) && max(v1[1], v1[3], v1[5], v1[7]) + epsilon > min(v2[1], v2[3], v2[5], v2[7]) && min(v1[1], v1[3], v1[5], v1[7]) - epsilon < max(v2[1], v2[3], v2[5], v2[7])) { var overlaps = getOverlaps(v1, v2); if (overlaps) { for (var i = 0; i < 2; i++) { var overlap = overlaps[i]; addLocation(locations, include, c1, overlap[0], c2, overlap[1], true); } } else { var straight1 = Curve.isStraight(v1), straight2 = Curve.isStraight(v2), straight = straight1 && straight2, flip = straight1 && !straight2, before = locations.length; (straight ? addLineIntersection : straight1 || straight2 ? addCurveLineIntersections : addCurveIntersections)( flip ? v2 : v1, flip ? v1 : v2, flip ? c2 : c1, flip ? c1 : c2, locations, include, flip, 0, 0, 0, 1, 0, 1); if (!straight || locations.length === before) { for (var i = 0; i < 4; i++) { var t1 = i >> 1, t2 = i & 1, i1 = t1 * 6, i2 = t2 * 6, p1 = new Point(v1[i1], v1[i1 + 1]), p2 = new Point(v2[i2], v2[i2 + 1]); if (p1.isClose(p2, epsilon)) { addLocation(locations, include, c1, t1, c2, t2); } } } } } return locations; } function getSelfIntersection(v1, c1, locations, include) { var info = Curve.classify(v1); if (info.type === 'loop') { var roots = info.roots; addLocation(locations, include, c1, roots[0], c1, roots[1]); } return locations; } function getIntersections(curves1, curves2, include, matrix1, matrix2, _returnFirst) { var epsilon = 1e-7, self = !curves2; if (self) curves2 = curves1; var length1 = curves1.length, length2 = curves2.length, values1 = new Array(length1), values2 = self ? values1 : new Array(length2), locations = []; for (var i = 0; i < length1; i++) { values1[i] = curves1[i].getValues(matrix1); } if (!self) { for (var i = 0; i < length2; i++) { values2[i] = curves2[i].getValues(matrix2); } } var boundsCollisions = CollisionDetection.findCurveBoundsCollisions( values1, values2, epsilon); for (var index1 = 0; index1 < length1; index1++) { var curve1 = curves1[index1], v1 = values1[index1]; if (self) { getSelfIntersection(v1, curve1, locations, include); } var collisions1 = boundsCollisions[index1]; if (collisions1) { for (var j = 0; j < collisions1.length; j++) { if (_returnFirst && locations.length) return locations; var index2 = collisions1[j]; if (!self || index2 > index1) { var curve2 = curves2[index2], v2 = values2[index2]; getCurveIntersections( v1, v2, curve1, curve2, locations, include); } } } } return locations; } function getOverlaps(v1, v2) { function getSquaredLineLength(v) { var x = v[6] - v[0], y = v[7] - v[1]; return x * x + y * y; } var abs = Math.abs, getDistance = Line.getDistance, timeEpsilon = 1e-8, geomEpsilon = 1e-7, straight1 = Curve.isStraight(v1), straight2 = Curve.isStraight(v2), straightBoth = straight1 && straight2, flip = getSquaredLineLength(v1) < getSquaredLineLength(v2), l1 = flip ? v2 : v1, l2 = flip ? v1 : v2, px = l1[0], py = l1[1], vx = l1[6] - px, vy = l1[7] - py; if (getDistance(px, py, vx, vy, l2[0], l2[1], true) < geomEpsilon && getDistance(px, py, vx, vy, l2[6], l2[7], true) < geomEpsilon) { if (!straightBoth && getDistance(px, py, vx, vy, l1[2], l1[3], true) < geomEpsilon && getDistance(px, py, vx, vy, l1[4], l1[5], true) < geomEpsilon && getDistance(px, py, vx, vy, l2[2], l2[3], true) < geomEpsilon && getDistance(px, py, vx, vy, l2[4], l2[5], true) < geomEpsilon) { straight1 = straight2 = straightBoth = true; } } else if (straightBoth) { return null; } if (straight1 ^ straight2) { return null; } var v = [v1, v2], pairs = []; for (var i = 0; i < 4 && pairs.length < 2; i++) { var i1 = i & 1, i2 = i1 ^ 1, t1 = i >> 1, t2 = Curve.getTimeOf(v[i1], new Point( v[i2][t1 ? 6 : 0], v[i2][t1 ? 7 : 1])); if (t2 != null) { var pair = i1 ? [t1, t2] : [t2, t1]; if (!pairs.length || abs(pair[0] - pairs[0][0]) > timeEpsilon && abs(pair[1] - pairs[0][1]) > timeEpsilon) { pairs.push(pair); } } if (i > 2 && !pairs.length) break; } if (pairs.length !== 2) { pairs = null; } else if (!straightBoth) { var o1 = Curve.getPart(v1, pairs[0][0], pairs[1][0]), o2 = Curve.getPart(v2, pairs[0][1], pairs[1][1]); if (abs(o2[2] - o1[2]) > geomEpsilon || abs(o2[3] - o1[3]) > geomEpsilon || abs(o2[4] - o1[4]) > geomEpsilon || abs(o2[5] - o1[5]) > geomEpsilon) pairs = null; } return pairs; } function getTimesWithTangent(v, tangent) { var x0 = v[0], y0 = v[1], x1 = v[2], y1 = v[3], x2 = v[4], y2 = v[5], x3 = v[6], y3 = v[7], normalized = tangent.normalize(), tx = normalized.x, ty = normalized.y, ax = 3 * x3 - 9 * x2 + 9 * x1 - 3 * x0, ay = 3 * y3 - 9 * y2 + 9 * y1 - 3 * y0, bx = 6 * x2 - 12 * x1 + 6 * x0, by = 6 * y2 - 12 * y1 + 6 * y0, cx = 3 * x1 - 3 * x0, cy = 3 * y1 - 3 * y0, den = 2 * ax * ty - 2 * ay * tx, times = []; if (Math.abs(den) < Numerical.CURVETIME_EPSILON) { var num = ax * cy - ay * cx, den = ax * by - ay * bx; if (den != 0) { var t = -num / den; if (t >= 0 && t <= 1) times.push(t); } } else { var delta = (bx * bx - 4 * ax * cx) * ty * ty + (-2 * bx * by + 4 * ay * cx + 4 * ax * cy) * tx * ty + (by * by - 4 * ay * cy) * tx * tx, k = bx * ty - by * tx; if (delta >= 0 && den != 0) { var d = Math.sqrt(delta), t0 = -(k + d) / den, t1 = (-k + d) / den; if (t0 >= 0 && t0 <= 1) times.push(t0); if (t1 >= 0 && t1 <= 1) times.push(t1); } } return times; } return { getIntersections: function(curve) { var v1 = this.getValues(), v2 = curve && curve !== this && curve.getValues(); return v2 ? getCurveIntersections(v1, v2, this, curve, []) : getSelfIntersection(v1, this, []); }, statics: { getOverlaps: getOverlaps, getIntersections: getIntersections, getCurveLineIntersections: getCurveLineIntersections, getTimesWithTangent: getTimesWithTangent } }; }); var CurveLocation = Base.extend({ _class: 'CurveLocation', initialize: function CurveLocation(curve, time, point, _overlap, _distance) { if (time >= 0.99999999) { var next = curve.getNext(); if (next) { time = 0; curve = next; } } this._setCurve(curve); this._time = time; this._point = point || curve.getPointAtTime(time); this._overlap = _overlap; this._distance = _distance; this._intersection = this._next = this._previous = null; }, _setPath: function(path) { this._path = path; this._version = path ? path._version : 0; }, _setCurve: function(curve) { this._setPath(curve._path); this._curve = curve; this._segment = null; this._segment1 = curve._segment1; this._segment2 = curve._segment2; }, _setSegment: function(segment) { var curve = segment.getCurve(); if (curve) { this._setCurve(curve); } else { this._setPath(segment._path); this._segment1 = segment; this._segment2 = null; } this._segment = segment; this._time = segment === this._segment1 ? 0 : 1; this._point = segment._point.clone(); }, getSegment: function() { var segment = this._segment; if (!segment) { var curve = this.getCurve(), time = this.getTime(); if (time === 0) { segment = curve._segment1; } else if (time === 1) { segment = curve._segment2; } else if (time != null) { segment = curve.getPartLength(0, time) < curve.getPartLength(time, 1) ? curve._segment1 : curve._segment2; } this._segment = segment; } return segment; }, getCurve: function() { var path = this._path, that = this; if (path && path._version !== this._version) { this._time = this._offset = this._curveOffset = this._curve = null; } function trySegment(segment) { var curve = segment && segment.getCurve(); if (curve && (that._time = curve.getTimeOf(that._point)) != null) { that._setCurve(curve); return curve; } } return this._curve || trySegment(this._segment) || trySegment(this._segment1) || trySegment(this._segment2.getPrevious()); }, getPath: function() { var curve = this.getCurve(); return curve && curve._path; }, getIndex: function() { var curve = this.getCurve(); return curve && curve.getIndex(); }, getTime: function() { var curve = this.getCurve(), time = this._time; return curve && time == null ? this._time = curve.getTimeOf(this._point) : time; }, getParameter: '#getTime', getPoint: function() { return this._point; }, getOffset: function() { var offset = this._offset; if (offset == null) { offset = 0; var path = this.getPath(), index = this.getIndex(); if (path && index != null) { var curves = path.getCurves(); for (var i = 0; i < index; i++) offset += curves[i].getLength(); } this._offset = offset += this.getCurveOffset(); } return offset; }, getCurveOffset: function() { var offset = this._curveOffset; if (offset == null) { var curve = this.getCurve(), time = this.getTime(); this._curveOffset = offset = time != null && curve && curve.getPartLength(0, time); } return offset; }, getIntersection: function() { return this._intersection; }, getDistance: function() { return this._distance; }, divide: function() { var curve = this.getCurve(), res = curve && curve.divideAtTime(this.getTime()); if (res) { this._setSegment(res._segment1); } return res; }, split: function() { var curve = this.getCurve(), path = curve._path, res = curve && curve.splitAtTime(this.getTime()); if (res) { this._setSegment(path.getLastSegment()); } return res; }, equals: function(loc, _ignoreOther) { var res = this === loc; if (!res && loc instanceof CurveLocation) { var c1 = this.getCurve(), c2 = loc.getCurve(), p1 = c1._path, p2 = c2._path; if (p1 === p2) { var abs = Math.abs, epsilon = 1e-7, diff = abs(this.getOffset() - loc.getOffset()), i1 = !_ignoreOther && this._intersection, i2 = !_ignoreOther && loc._intersection; res = (diff < epsilon || p1 && abs(p1.getLength() - diff) < epsilon) && (!i1 && !i2 || i1 && i2 && i1.equals(i2, true)); } } return res; }, toString: function() { var parts = [], point = this.getPoint(), f = Formatter.instance; if (point) parts.push('point: ' + point); var index = this.getIndex(); if (index != null) parts.push('index: ' + index); var time = this.getTime(); if (time != null) parts.push('time: ' + f.number(time)); if (this._distance != null) parts.push('distance: ' + f.number(this._distance)); return '{ ' + parts.join(', ') + ' }'; }, isTouching: function() { var inter = this._intersection; if (inter && this.getTangent().isCollinear(inter.getTangent())) { var curve1 = this.getCurve(), curve2 = inter.getCurve(); return !(curve1.isStraight() && curve2.isStraight() && curve1.getLine().intersect(curve2.getLine())); } return false; }, isCrossing: function() { var inter = this._intersection; if (!inter) return false; var t1 = this.getTime(), t2 = inter.getTime(), tMin = 1e-8, tMax = 1 - tMin, t1Inside = t1 >= tMin && t1 <= tMax, t2Inside = t2 >= tMin && t2 <= tMax; if (t1Inside && t2Inside) return !this.isTouching(); var c2 = this.getCurve(), c1 = c2 && t1 < tMin ? c2.getPrevious() : c2, c4 = inter.getCurve(), c3 = c4 && t2 < tMin ? c4.getPrevious() : c4; if (t1 > tMax) c2 = c2.getNext(); if (t2 > tMax) c4 = c4.getNext(); if (!c1 || !c2 || !c3 || !c4) return false; var offsets = []; function addOffsets(curve, end) { var v = curve.getValues(), roots = Curve.classify(v).roots || Curve.getPeaks(v), count = roots.length, offset = Curve.getLength(v, end && count ? roots[count - 1] : 0, !end && count ? roots[0] : 1); offsets.push(count ? offset : offset / 32); } function isInRange(angle, min, max) { return min < max ? angle > min && angle < max : angle > min || angle < max; } if (!t1Inside) { addOffsets(c1, true); addOffsets(c2, false); } if (!t2Inside) { addOffsets(c3, true); addOffsets(c4, false); } var pt = this.getPoint(), offset = Math.min.apply(Math, offsets), v2 = t1Inside ? c2.getTangentAtTime(t1) : c2.getPointAt(offset).subtract(pt), v1 = t1Inside ? v2.negate() : c1.getPointAt(-offset).subtract(pt), v4 = t2Inside ? c4.getTangentAtTime(t2) : c4.getPointAt(offset).subtract(pt), v3 = t2Inside ? v4.negate() : c3.getPointAt(-offset).subtract(pt), a1 = v1.getAngle(), a2 = v2.getAngle(), a3 = v3.getAngle(), a4 = v4.getAngle(); return !!(t1Inside ? (isInRange(a1, a3, a4) ^ isInRange(a2, a3, a4)) && (isInRange(a1, a4, a3) ^ isInRange(a2, a4, a3)) : (isInRange(a3, a1, a2) ^ isInRange(a4, a1, a2)) && (isInRange(a3, a2, a1) ^ isInRange(a4, a2, a1))); }, hasOverlap: function() { return !!this._overlap; } }, Base.each(Curve._evaluateMethods, function(name) { var get = name + 'At'; this[name] = function() { var curve = this.getCurve(), time = this.getTime(); return time != null && curve && curve[get](time, true); }; }, { preserve: true }), new function() { function insert(locations, loc, merge) { var length = locations.length, l = 0, r = length - 1; function search(index, dir) { for (var i = index + dir; i >= -1 && i <= length; i += dir) { var loc2 = locations[((i % length) + length) % length]; if (!loc.getPoint().isClose(loc2.getPoint(), 1e-7)) break; if (loc.equals(loc2)) return loc2; } return null; } while (l <= r) { var m = (l + r) >>> 1, loc2 = locations[m], found; if (merge && (found = loc.equals(loc2) ? loc2 : (search(m, -1) || search(m, 1)))) { if (loc._overlap) { found._overlap = found._intersection._overlap = true; } return found; } var path1 = loc.getPath(), path2 = loc2.getPath(), diff = path1 !== path2 ? path1._id - path2._id : (loc.getIndex() + loc.getTime()) - (loc2.getIndex() + loc2.getTime()); if (diff < 0) { r = m - 1; } else { l = m + 1; } } locations.splice(l, 0, loc); return loc; } return { statics: { insert: insert, expand: function(locations) { var expanded = locations.slice(); for (var i = locations.length - 1; i >= 0; i--) { insert(expanded, locations[i]._intersection, false); } return expanded; } }}; }); var PathItem = Item.extend({ _class: 'PathItem', _selectBounds: false, _canScaleStroke: true, beans: true, initialize: function PathItem() { }, statics: { create: function(arg) { var data, segments, compound; if (Base.isPlainObject(arg)) { segments = arg.segments; data = arg.pathData; } else if (Array.isArray(arg)) { segments = arg; } else if (typeof arg === 'string') { data = arg; } if (segments) { var first = segments[0]; compound = first && Array.isArray(first[0]); } else if (data) { compound = (data.match(/m/gi) || []).length > 1 || /z\s*\S+/i.test(data); } var ctor = compound ? CompoundPath : Path; return new ctor(arg); } }, _asPathItem: function() { return this; }, isClockwise: function() { return this.getArea() >= 0; }, setClockwise: function(clockwise) { if (this.isClockwise() != (clockwise = !!clockwise)) this.reverse(); }, setPathData: function(data) { var parts = data && data.match(/[mlhvcsqtaz][^mlhvcsqtaz]*/ig), coords, relative = false, previous, control, current = new Point(), start = new Point(); function getCoord(index, coord) { var val = +coords[index]; if (relative) val += current[coord]; return val; } function getPoint(index) { return new Point( getCoord(index, 'x'), getCoord(index + 1, 'y') ); } this.clear(); for (var i = 0, l = parts && parts.length; i < l; i++) { var part = parts[i], command = part[0], lower = command.toLowerCase(); coords = part.match(/[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g); var length = coords && coords.length; relative = command === lower; if (previous === 'z' && !/[mz]/.test(lower)) this.moveTo(current); switch (lower) { case 'm': case 'l': var move = lower === 'm'; for (var j = 0; j < length; j += 2) { this[move ? 'moveTo' : 'lineTo'](current = getPoint(j)); if (move) { start = current; move = false; } } control = current; break; case 'h': case 'v': var coord = lower === 'h' ? 'x' : 'y'; current = current.clone(); for (var j = 0; j < length; j++) { current[coord] = getCoord(j, coord); this.lineTo(current); } control = current; break; case 'c': for (var j = 0; j < length; j += 6) { this.cubicCurveTo( getPoint(j), control = getPoint(j + 2), current = getPoint(j + 4)); } break; case 's': for (var j = 0; j < length; j += 4) { this.cubicCurveTo( /[cs]/.test(previous) ? current.multiply(2).subtract(control) : current, control = getPoint(j), current = getPoint(j + 2)); previous = lower; } break; case 'q': for (var j = 0; j < length; j += 4) { this.quadraticCurveTo( control = getPoint(j), current = getPoint(j + 2)); } break; case 't': for (var j = 0; j < length; j += 2) { this.quadraticCurveTo( control = (/[qt]/.test(previous) ? current.multiply(2).subtract(control) : current), current = getPoint(j)); previous = lower; } break; case 'a': for (var j = 0; j < length; j += 7) { this.arcTo(current = getPoint(j + 5), new Size(+coords[j], +coords[j + 1]), +coords[j + 2], +coords[j + 4], +coords[j + 3]); } break; case 'z': this.closePath(1e-12); current = start; break; } previous = lower; } }, _canComposite: function() { return !(this.hasFill() && this.hasStroke()); }, _contains: function(point) { var winding = point.isInside( this.getBounds({ internal: true, handle: true })) ? this._getWinding(point) : {}; return winding.onPath || !!(this.getFillRule() === 'evenodd' ? winding.windingL & 1 || winding.windingR & 1 : winding.winding); }, getIntersections: function(path, include, _matrix, _returnFirst) { var self = this === path || !path, matrix1 = this._matrix._orNullIfIdentity(), matrix2 = self ? matrix1 : (_matrix || path._matrix)._orNullIfIdentity(); return self || this.getBounds(matrix1).intersects( path.getBounds(matrix2), 1e-12) ? Curve.getIntersections( this.getCurves(), !self && path.getCurves(), include, matrix1, matrix2, _returnFirst) : []; }, getCrossings: function(path) { return this.getIntersections(path, function(inter) { return inter.isCrossing(); }); }, getNearestLocation: function() { var point = Point.read(arguments), curves = this.getCurves(), minDist = Infinity, minLoc = null; for (var i = 0, l = curves.length; i < l; i++) { var loc = curves[i].getNearestLocation(point); if (loc._distance < minDist) { minDist = loc._distance; minLoc = loc; } } return minLoc; }, getNearestPoint: function() { var loc = this.getNearestLocation.apply(this, arguments); return loc ? loc.getPoint() : loc; }, interpolate: function(from, to, factor) { var isPath = !this._children, name = isPath ? '_segments' : '_children', itemsFrom = from[name], itemsTo = to[name], items = this[name]; if (!itemsFrom || !itemsTo || itemsFrom.length !== itemsTo.length) { throw new Error('Invalid operands in interpolate() call: ' + from + ', ' + to); } var current = items.length, length = itemsTo.length; if (current < length) { var ctor = isPath ? Segment : Path; for (var i = current; i < length; i++) { this.add(new ctor()); } } else if (current > length) { this[isPath ? 'removeSegments' : 'removeChildren'](length, current); } for (var i = 0; i < length; i++) { items[i].interpolate(itemsFrom[i], itemsTo[i], factor); } if (isPath) { this.setClosed(from._closed); this._changed(9); } }, compare: function(path) { var ok = false; if (path) { var paths1 = this._children || [this], paths2 = path._children ? path._children.slice() : [path], length1 = paths1.length, length2 = paths2.length, matched = [], count = 0; ok = true; var boundsOverlaps = CollisionDetection.findItemBoundsCollisions(paths1, paths2, Numerical.GEOMETRIC_EPSILON); for (var i1 = length1 - 1; i1 >= 0 && ok; i1--) { var path1 = paths1[i1]; ok = false; var pathBoundsOverlaps = boundsOverlaps[i1]; if (pathBoundsOverlaps) { for (var i2 = pathBoundsOverlaps.length - 1; i2 >= 0 && !ok; i2--) { if (path1.compare(paths2[pathBoundsOverlaps[i2]])) { if (!matched[pathBoundsOverlaps[i2]]) { matched[pathBoundsOverlaps[i2]] = true; count++; } ok = true; } } } } ok = ok && count === length2; } return ok; }, }); var Path = PathItem.extend({ _class: 'Path', _serializeFields: { segments: [], closed: false }, initialize: function Path(arg) { this._closed = false; this._segments = []; this._version = 0; var args = arguments, segments = Array.isArray(arg) ? typeof arg[0] === 'object' ? arg : args : arg && (arg.size === undefined && (arg.x !== undefined || arg.point !== undefined)) ? args : null; if (segments && segments.length > 0) { this.setSegments(segments); } else { this._curves = undefined; this._segmentSelection = 0; if (!segments && typeof arg === 'string') { this.setPathData(arg); arg = null; } } this._initialize(!segments && arg); }, _equals: function(item) { return this._closed === item._closed && Base.equals(this._segments, item._segments); }, copyContent: function(source) { this.setSegments(source._segments); this._closed = source._closed; }, _changed: function _changed(flags) { _changed.base.call(this, flags); if (flags & 8) { this._length = this._area = undefined; if (flags & 32) { this._version++; } else if (this._curves) { for (var i = 0, l = this._curves.length; i < l; i++) this._curves[i]._changed(); } } else if (flags & 64) { this._bounds = undefined; } }, getStyle: function() { var parent = this._parent; return (parent instanceof CompoundPath ? parent : this)._style; }, getSegments: function() { return this._segments; }, setSegments: function(segments) { var fullySelected = this.isFullySelected(), length = segments && segments.length; this._segments.length = 0; this._segmentSelection = 0; this._curves = undefined; if (length) { var last = segments[length - 1]; if (typeof last === 'boolean') { this.setClosed(last); length--; } this._add(Segment.readList(segments, 0, {}, length)); } if (fullySelected) this.setFullySelected(true); }, getFirstSegment: function() { return this._segments[0]; }, getLastSegment: function() { return this._segments[this._segments.length - 1]; }, getCurves: function() { var curves = this._curves, segments = this._segments; if (!curves) { var length = this._countCurves(); curves = this._curves = new Array(length); for (var i = 0; i < length; i++) curves[i] = new Curve(this, segments[i], segments[i + 1] || segments[0]); } return curves; }, getFirstCurve: function() { return this.getCurves()[0]; }, getLastCurve: function() { var curves = this.getCurves(); return curves[curves.length - 1]; }, isClosed: function() { return this._closed; }, setClosed: function(closed) { if (this._closed != (closed = !!closed)) { this._closed = closed; if (this._curves) { var length = this._curves.length = this._countCurves(); if (closed) this._curves[length - 1] = new Curve(this, this._segments[length - 1], this._segments[0]); } this._changed(41); } } }, { beans: true, getPathData: function(_matrix, _precision) { var segments = this._segments, length = segments.length, f = new Formatter(_precision), coords = new Array(6), first = true, curX, curY, prevX, prevY, inX, inY, outX, outY, parts = []; function addSegment(segment, skipLine) { segment._transformCoordinates(_matrix, coords); curX = coords[0]; curY = coords[1]; if (first) { parts.push('M' + f.pair(curX, curY)); first = false; } else { inX = coords[2]; inY = coords[3]; if (inX === curX && inY === curY && outX === prevX && outY === prevY) { if (!skipLine) { var dx = curX - prevX, dy = curY - prevY; parts.push( dx === 0 ? 'v' + f.number(dy) : dy === 0 ? 'h' + f.number(dx) : 'l' + f.pair(dx, dy)); } } else { parts.push('c' + f.pair(outX - prevX, outY - prevY) + ' ' + f.pair( inX - prevX, inY - prevY) + ' ' + f.pair(curX - prevX, curY - prevY)); } } prevX = curX; prevY = curY; outX = coords[4]; outY = coords[5]; } if (!length) return ''; for (var i = 0; i < length; i++) addSegment(segments[i]); if (this._closed && length > 0) { addSegment(segments[0], true); parts.push('z'); } return parts.join(''); }, isEmpty: function() { return !this._segments.length; }, _transformContent: function(matrix) { var segments = this._segments, coords = new Array(6); for (var i = 0, l = segments.length; i < l; i++) segments[i]._transformCoordinates(matrix, coords, true); return true; }, _add: function(segs, index) { var segments = this._segments, curves = this._curves, amount = segs.length, append = index == null, index = append ? segments.length : index; for (var i = 0; i < amount; i++) { var segment = segs[i]; if (segment._path) segment = segs[i] = segment.clone(); segment._path = this; segment._index = index + i; if (segment._selection) this._updateSelection(segment, 0, segment._selection); } if (append) { Base.push(segments, segs); } else { segments.splice.apply(segments, [index, 0].concat(segs)); for (var i = index + amount, l = segments.length; i < l; i++) segments[i]._index = i; } if (curves) { var total = this._countCurves(), start = index > 0 && index + amount - 1 === total ? index - 1 : index, insert = start, end = Math.min(start + amount, total); if (segs._curves) { curves.splice.apply(curves, [start, 0].concat(segs._curves)); insert += segs._curves.length; } for (var i = insert; i < end; i++) curves.splice(i, 0, new Curve(this, null, null)); this._adjustCurves(start, end); } this._changed(41); return segs; }, _adjustCurves: function(start, end) { var segments = this._segments, curves = this._curves, curve; for (var i = start; i < end; i++) { curve = curves[i]; curve._path = this; curve._segment1 = segments[i]; curve._segment2 = segments[i + 1] || segments[0]; curve._changed(); } if (curve = curves[this._closed && !start ? segments.length - 1 : start - 1]) { curve._segment2 = segments[start] || segments[0]; curve._changed(); } if (curve = curves[end]) { curve._segment1 = segments[end]; curve._changed(); } }, _countCurves: function() { var length = this._segments.length; return !this._closed && length > 0 ? length - 1 : length; }, add: function(segment1 ) { var args = arguments; return args.length > 1 && typeof segment1 !== 'number' ? this._add(Segment.readList(args)) : this._add([ Segment.read(args) ])[0]; }, insert: function(index, segment1 ) { var args = arguments; return args.length > 2 && typeof segment1 !== 'number' ? this._add(Segment.readList(args, 1), index) : this._add([ Segment.read(args, 1) ], index)[0]; }, addSegment: function() { return this._add([ Segment.read(arguments) ])[0]; }, insertSegment: function(index ) { return this._add([ Segment.read(arguments, 1) ], index)[0]; }, addSegments: function(segments) { return this._add(Segment.readList(segments)); }, insertSegments: function(index, segments) { return this._add(Segment.readList(segments), index); }, removeSegment: function(index) { return this.removeSegments(index, index + 1)[0] || null; }, removeSegments: function(start, end, _includeCurves) { start = start || 0; end = Base.pick(end, this._segments.length); var segments = this._segments, curves = this._curves, count = segments.length, removed = segments.splice(start, end - start), amount = removed.length; if (!amount) return removed; for (var i = 0; i < amount; i++) { var segment = removed[i]; if (segment._selection) this._updateSelection(segment, segment._selection, 0); segment._index = segment._path = null; } for (var i = start, l = segments.length; i < l; i++) segments[i]._index = i; if (curves) { var index = start > 0 && end === count + (this._closed ? 1 : 0) ? start - 1 : start, curves = curves.splice(index, amount); for (var i = curves.length - 1; i >= 0; i--) curves[i]._path = null; if (_includeCurves) removed._curves = curves.slice(1); this._adjustCurves(index, index); } this._changed(41); return removed; }, clear: '#removeSegments', hasHandles: function() { var segments = this._segments; for (var i = 0, l = segments.length; i < l; i++) { if (segments[i].hasHandles()) return true; } return false; }, clearHandles: function() { var segments = this._segments; for (var i = 0, l = segments.length; i < l; i++) segments[i].clearHandles(); }, getLength: function() { if (this._length == null) { var curves = this.getCurves(), length = 0; for (var i = 0, l = curves.length; i < l; i++) length += curves[i].getLength(); this._length = length; } return this._length; }, getArea: function() { var area = this._area; if (area == null) { var segments = this._segments, closed = this._closed; area = 0; for (var i = 0, l = segments.length; i < l; i++) { var last = i + 1 === l; area += Curve.getArea(Curve.getValues( segments[i], segments[last ? 0 : i + 1], null, last && !closed)); } this._area = area; } return area; }, isFullySelected: function() { var length = this._segments.length; return this.isSelected() && length > 0 && this._segmentSelection === length * 7; }, setFullySelected: function(selected) { if (selected) this._selectSegments(true); this.setSelected(selected); }, setSelection: function setSelection(selection) { if (!(selection & 1)) this._selectSegments(false); setSelection.base.call(this, selection); }, _selectSegments: function(selected) { var segments = this._segments, length = segments.length, selection = selected ? 7 : 0; this._segmentSelection = selection * length; for (var i = 0; i < length; i++) segments[i]._selection = selection; }, _updateSelection: function(segment, oldSelection, newSelection) { segment._selection = newSelection; var selection = this._segmentSelection += newSelection - oldSelection; if (selection > 0) this.setSelected(true); }, divideAt: function(location) { var loc = this.getLocationAt(location), curve; return loc && (curve = loc.getCurve().divideAt(loc.getCurveOffset())) ? curve._segment1 : null; }, splitAt: function(location) { var loc = this.getLocationAt(location), index = loc && loc.index, time = loc && loc.time, tMin = 1e-8, tMax = 1 - tMin; if (time > tMax) { index++; time = 0; } var curves = this.getCurves(); if (index >= 0 && index < curves.length) { if (time >= tMin) { curves[index++].divideAtTime(time); } var segs = this.removeSegments(index, this._segments.length, true), path; if (this._closed) { this.setClosed(false); path = this; } else { path = new Path(Item.NO_INSERT); path.insertAbove(this); path.copyAttributes(this); } path._add(segs, 0); this.addSegment(segs[0]); return path; } return null; }, split: function(index, time) { var curve, location = time === undefined ? index : (curve = this.getCurves()[index]) && curve.getLocationAtTime(time); return location != null ? this.splitAt(location) : null; }, join: function(path, tolerance) { var epsilon = tolerance || 0; if (path && path !== this) { var segments = path._segments, last1 = this.getLastSegment(), last2 = path.getLastSegment(); if (!last2) return this; if (last1 && last1._point.isClose(last2._point, epsilon)) path.reverse(); var first2 = path.getFirstSegment(); if (last1 && last1._point.isClose(first2._point, epsilon)) { last1.setHandleOut(first2._handleOut); this._add(segments.slice(1)); } else { var first1 = this.getFirstSegment(); if (first1 && first1._point.isClose(first2._point, epsilon)) path.reverse(); last2 = path.getLastSegment(); if (first1 && first1._point.isClose(last2._point, epsilon)) { first1.setHandleIn(last2._handleIn); this._add(segments.slice(0, segments.length - 1), 0); } else { this._add(segments.slice()); } } if (path._closed) this._add([segments[0]]); path.remove(); } var first = this.getFirstSegment(), last = this.getLastSegment(); if (first !== last && first._point.isClose(last._point, epsilon)) { first.setHandleIn(last._handleIn); last.remove(); this.setClosed(true); } return this; }, reduce: function(options) { var curves = this.getCurves(), simplify = options && options.simplify, tolerance = simplify ? 1e-7 : 0; for (var i = curves.length - 1; i >= 0; i--) { var curve = curves[i]; if (!curve.hasHandles() && (!curve.hasLength(tolerance) || simplify && curve.isCollinear(curve.getNext()))) curve.remove(); } return this; }, reverse: function() { this._segments.reverse(); for (var i = 0, l = this._segments.length; i < l; i++) { var segment = this._segments[i]; var handleIn = segment._handleIn; segment._handleIn = segment._handleOut; segment._handleOut = handleIn; segment._index = i; } this._curves = null; this._changed(9); }, flatten: function(flatness) { var flattener = new PathFlattener(this, flatness || 0.25, 256, true), parts = flattener.parts, length = parts.length, segments = []; for (var i = 0; i < length; i++) { segments.push(new Segment(parts[i].curve.slice(0, 2))); } if (!this._closed && length > 0) { segments.push(new Segment(parts[length - 1].curve.slice(6))); } this.setSegments(segments); }, simplify: function(tolerance) { var segments = new PathFitter(this).fit(tolerance || 2.5); if (segments) this.setSegments(segments); return !!segments; }, smooth: function(options) { var that = this, opts = options || {}, type = opts.type || 'asymmetric', segments = this._segments, length = segments.length, closed = this._closed; function getIndex(value, _default) { var index = value && value.index; if (index != null) { var path = value.path; if (path && path !== that) throw new Error(value._class + ' ' + index + ' of ' + path + ' is not part of ' + that); if (_default && value instanceof Curve) index++; } else { index = typeof value === 'number' ? value : _default; } return Math.min(index < 0 && closed ? index % length : index < 0 ? index + length : index, length - 1); } var loop = closed && opts.from === undefined && opts.to === undefined, from = getIndex(opts.from, 0), to = getIndex(opts.to, length - 1); if (from > to) { if (closed) { from -= length; } else { var tmp = from; from = to; to = tmp; } } if (/^(?:asymmetric|continuous)$/.test(type)) { var asymmetric = type === 'asymmetric', min = Math.min, amount = to - from + 1, n = amount - 1, padding = loop ? min(amount, 4) : 1, paddingLeft = padding, paddingRight = padding, knots = []; if (!closed) { paddingLeft = min(1, from); paddingRight = min(1, length - to - 1); } n += paddingLeft + paddingRight; if (n <= 1) return; for (var i = 0, j = from - paddingLeft; i <= n; i++, j++) { knots[i] = segments[(j < 0 ? j + length : j) % length]._point; } var x = knots[0]._x + 2 * knots[1]._x, y = knots[0]._y + 2 * knots[1]._y, f = 2, n_1 = n - 1, rx = [x], ry = [y], rf = [f], px = [], py = []; for (var i = 1; i < n; i++) { var internal = i < n_1, a = internal ? 1 : asymmetric ? 1 : 2, b = internal ? 4 : asymmetric ? 2 : 7, u = internal ? 4 : asymmetric ? 3 : 8, v = internal ? 2 : asymmetric ? 0 : 1, m = a / f; f = rf[i] = b - m; x = rx[i] = u * knots[i]._x + v * knots[i + 1]._x - m * x; y = ry[i] = u * knots[i]._y + v * knots[i + 1]._y - m * y; } px[n_1] = rx[n_1] / rf[n_1]; py[n_1] = ry[n_1] / rf[n_1]; for (var i = n - 2; i >= 0; i--) { px[i] = (rx[i] - px[i + 1]) / rf[i]; py[i] = (ry[i] - py[i + 1]) / rf[i]; } px[n] = (3 * knots[n]._x - px[n_1]) / 2; py[n] = (3 * knots[n]._y - py[n_1]) / 2; for (var i = paddingLeft, max = n - paddingRight, j = from; i <= max; i++, j++) { var segment = segments[j < 0 ? j + length : j], pt = segment._point, hx = px[i] - pt._x, hy = py[i] - pt._y; if (loop || i < max) segment.setHandleOut(hx, hy); if (loop || i > paddingLeft) segment.setHandleIn(-hx, -hy); } } else { for (var i = from; i <= to; i++) { segments[i < 0 ? i + length : i].smooth(opts, !loop && i === from, !loop && i === to); } } }, toShape: function(insert) { if (!this._closed) return null; var segments = this._segments, type, size, radius, topCenter; function isCollinear(i, j) { var seg1 = segments[i], seg2 = seg1.getNext(), seg3 = segments[j], seg4 = seg3.getNext(); return seg1._handleOut.isZero() && seg2._handleIn.isZero() && seg3._handleOut.isZero() && seg4._handleIn.isZero() && seg2._point.subtract(seg1._point).isCollinear( seg4._point.subtract(seg3._point)); } function isOrthogonal(i) { var seg2 = segments[i], seg1 = seg2.getPrevious(), seg3 = seg2.getNext(); return seg1._handleOut.isZero() && seg2._handleIn.isZero() && seg2._handleOut.isZero() && seg3._handleIn.isZero() && seg2._point.subtract(seg1._point).isOrthogonal( seg3._point.subtract(seg2._point)); } function isArc(i) { var seg1 = segments[i], seg2 = seg1.getNext(), handle1 = seg1._handleOut, handle2 = seg2._handleIn, kappa = 0.5522847498307936; if (handle1.isOrthogonal(handle2)) { var pt1 = seg1._point, pt2 = seg2._point, corner = new Line(pt1, handle1, true).intersect( new Line(pt2, handle2, true), true); return corner && Numerical.isZero(handle1.getLength() / corner.subtract(pt1).getLength() - kappa) && Numerical.isZero(handle2.getLength() / corner.subtract(pt2).getLength() - kappa); } return false; } function getDistance(i, j) { return segments[i]._point.getDistance(segments[j]._point); } if (!this.hasHandles() && segments.length === 4 && isCollinear(0, 2) && isCollinear(1, 3) && isOrthogonal(1)) { type = Shape.Rectangle; size = new Size(getDistance(0, 3), getDistance(0, 1)); topCenter = segments[1]._point.add(segments[2]._point).divide(2); } else if (segments.length === 8 && isArc(0) && isArc(2) && isArc(4) && isArc(6) && isCollinear(1, 5) && isCollinear(3, 7)) { type = Shape.Rectangle; size = new Size(getDistance(1, 6), getDistance(0, 3)); radius = size.subtract(new Size(getDistance(0, 7), getDistance(1, 2))).divide(2); topCenter = segments[3]._point.add(segments[4]._point).divide(2); } else if (segments.length === 4 && isArc(0) && isArc(1) && isArc(2) && isArc(3)) { if (Numerical.isZero(getDistance(0, 2) - getDistance(1, 3))) { type = Shape.Circle; radius = getDistance(0, 2) / 2; } else { type = Shape.Ellipse; radius = new Size(getDistance(2, 0) / 2, getDistance(3, 1) / 2); } topCenter = segments[1]._point; } if (type) { var center = this.getPosition(true), shape = new type({ center: center, size: size, radius: radius, insert: false }); shape.copyAttributes(this, true); shape._matrix.prepend(this._matrix); shape.rotate(topCenter.subtract(center).getAngle() + 90); if (insert === undefined || insert) shape.insertAbove(this); return shape; } return null; }, toPath: '#clone', compare: function compare(path) { if (!path || path instanceof CompoundPath) return compare.base.call(this, path); var curves1 = this.getCurves(), curves2 = path.getCurves(), length1 = curves1.length, length2 = curves2.length; if (!length1 || !length2) { return length1 == length2; } var v1 = curves1[0].getValues(), values2 = [], pos1 = 0, pos2, end1 = 0, end2; for (var i = 0; i < length2; i++) { var v2 = curves2[i].getValues(); values2.push(v2); var overlaps = Curve.getOverlaps(v1, v2); if (overlaps) { pos2 = !i && overlaps[0][0] > 0 ? length2 - 1 : i; end2 = overlaps[0][1]; break; } } var abs = Math.abs, epsilon = 1e-8, v2 = values2[pos2], start2; while (v1 && v2) { var overlaps = Curve.getOverlaps(v1, v2); if (overlaps) { var t1 = overlaps[0][0]; if (abs(t1 - end1) < epsilon) { end1 = overlaps[1][0]; if (end1 === 1) { v1 = ++pos1 < length1 ? curves1[pos1].getValues() : null; end1 = 0; } var t2 = overlaps[0][1]; if (abs(t2 - end2) < epsilon) { if (!start2) start2 = [pos2, t2]; end2 = overlaps[1][1]; if (end2 === 1) { if (++pos2 >= length2) pos2 = 0; v2 = values2[pos2] || curves2[pos2].getValues(); end2 = 0; } if (!v1) { return start2[0] === pos2 && start2[1] === end2; } continue; } } } break; } return false; }, _hitTestSelf: function(point, options, viewMatrix, strokeMatrix) { var that = this, style = this.getStyle(), segments = this._segments, numSegments = segments.length, closed = this._closed, tolerancePadding = options._tolerancePadding, strokePadding = tolerancePadding, join, cap, miterLimit, area, loc, res, hitStroke = options.stroke && (style.hasStroke() || options.hitUnstrokedPaths), hitFill = options.fill && (style.hasFill() || options.hitUnfilledPaths), hitCurves = options.curves, strokeRadius = hitStroke ? style.getStrokeWidth() / 2 : hitFill && options.tolerance > 0 || hitCurves ? 0 : null; if (strokeRadius !== null) { if (strokeRadius > 0) { join = style.getStrokeJoin(); cap = style.getStrokeCap(); miterLimit = style.getMiterLimit(); strokePadding = strokePadding.add( Path._getStrokePadding(strokeRadius, strokeMatrix)); } else { join = cap = 'round'; } } function isCloseEnough(pt, padding) { return point.subtract(pt).divide(padding).length <= 1; } function checkSegmentPoint(seg, pt, name) { if (!options.selected || pt.isSelected()) { var anchor = seg._point; if (pt !== anchor) pt = pt.add(anchor); if (isCloseEnough(pt, strokePadding)) { return new HitResult(name, that, { segment: seg, point: pt }); } } } function checkSegmentPoints(seg, ends) { return (ends || options.segments) && checkSegmentPoint(seg, seg._point, 'segment') || (!ends && options.handles) && ( checkSegmentPoint(seg, seg._handleIn, 'handle-in') || checkSegmentPoint(seg, seg._handleOut, 'handle-out')); } function addToArea(point) { area.add(point); } function checkSegmentStroke(segment) { var isJoin = closed || segment._index > 0 && segment._index < numSegments - 1; if ((isJoin ? join : cap) === 'round') { return isCloseEnough(segment._point, strokePadding); } else { area = new Path({ internal: true, closed: true }); if (isJoin) { if (!segment.isSmooth()) { Path._addBevelJoin(segment, join, strokeRadius, miterLimit, null, strokeMatrix, addToArea, true); } } else if (cap === 'square') { Path._addSquareCap(segment, cap, strokeRadius, null, strokeMatrix, addToArea, true); } if (!area.isEmpty()) { var loc; return area.contains(point) || (loc = area.getNearestLocation(point)) && isCloseEnough(loc.getPoint(), tolerancePadding); } } } if (options.ends && !options.segments && !closed) { if (res = checkSegmentPoints(segments[0], true) || checkSegmentPoints(segments[numSegments - 1], true)) return res; } else if (options.segments || options.handles) { for (var i = 0; i < numSegments; i++) if (res = checkSegmentPoints(segments[i])) return res; } if (strokeRadius !== null) { loc = this.getNearestLocation(point); if (loc) { var time = loc.getTime(); if (time === 0 || time === 1 && numSegments > 1) { if (!checkSegmentStroke(loc.getSegment())) loc = null; } else if (!isCloseEnough(loc.getPoint(), strokePadding)) { loc = null; } } if (!loc && join === 'miter' && numSegments > 1) { for (var i = 0; i < numSegments; i++) { var segment = segments[i]; if (point.getDistance(segment._point) <= miterLimit * strokeRadius && checkSegmentStroke(segment)) { loc = segment.getLocation(); break; } } } } return !loc && hitFill && this._contains(point) || loc && !hitStroke && !hitCurves ? new HitResult('fill', this) : loc ? new HitResult(hitStroke ? 'stroke' : 'curve', this, { location: loc, point: loc.getPoint() }) : null; } }, Base.each(Curve._evaluateMethods, function(name) { this[name + 'At'] = function(offset) { var loc = this.getLocationAt(offset); return loc && loc[name](); }; }, { beans: false, getLocationOf: function() { var point = Point.read(arguments), curves = this.getCurves(); for (var i = 0, l = curves.length; i < l; i++) { var loc = curves[i].getLocationOf(point); if (loc) return loc; } return null; }, getOffsetOf: function() { var loc = this.getLocationOf.apply(this, arguments); return loc ? loc.getOffset() : null; }, getLocationAt: function(offset) { if (typeof offset === 'number') { var curves = this.getCurves(), length = 0; for (var i = 0, l = curves.length; i < l; i++) { var start = length, curve = curves[i]; length += curve.getLength(); if (length > offset) { return curve.getLocationAt(offset - start); } } if (curves.length > 0 && offset <= this.getLength()) { return new CurveLocation(curves[curves.length - 1], 1); } } else if (offset && offset.getPath && offset.getPath() === this) { return offset; } return null; }, getOffsetsWithTangent: function() { var tangent = Point.read(arguments); if (tangent.isZero()) { return []; } var offsets = []; var curveStart = 0; var curves = this.getCurves(); for (var i = 0, l = curves.length; i < l; i++) { var curve = curves[i]; var curveTimes = curve.getTimesWithTangent(tangent); for (var j = 0, m = curveTimes.length; j < m; j++) { var offset = curveStart + curve.getOffsetAtTime(curveTimes[j]); if (offsets.indexOf(offset) < 0) { offsets.push(offset); } } curveStart += curve.length; } return offsets; } }), new function() { function drawHandles(ctx, segments, matrix, size, isFullySelected) { if (size <= 0) return; var half = size / 2, coords = new Array(6), pX, pY; function drawHandle(index) { var hX = coords[index], hY = coords[index + 1]; if (pX != hX || pY != hY) { ctx.beginPath(); ctx.moveTo(pX, pY); ctx.lineTo(hX, hY); ctx.moveTo(hX - half, hY); ctx.lineTo(hX, hY + half); ctx.lineTo(hX + half, hY); ctx.lineTo(hX, hY - half); ctx.closePath(); ctx.stroke(); } } for (var i = 0, l = segments.length; i < l; i++) { var segment = segments[i], selection = segment._selection; segment._transformCoordinates(matrix, coords); pX = coords[0]; pY = coords[1]; if (selection & 2 && !isFullySelected) drawHandle(2); if (selection & 4 && !isFullySelected) drawHandle(4); ctx.beginPath(); ctx.arc(pX, pY, half, 0, Math.PI * 2, true); ctx.stroke(); var fillStyle = ctx.fillStyle; if (!(selection & 1)) { ctx.fillStyle = 'rgba(255, 255, 255, 0.5)'; } ctx.fill(); ctx.fillStyle = fillStyle; } } function drawSegments(ctx, path, matrix) { var segments = path._segments, length = segments.length, coords = new Array(6), first = true, curX, curY, prevX, prevY, inX, inY, outX, outY; function drawSegment(segment) { if (matrix) { segment._transformCoordinates(matrix, coords); curX = coords[0]; curY = coords[1]; } else { var point = segment._point; curX = point._x; curY = point._y; } if (first) { ctx.moveTo(curX, curY); first = false; } else { if (matrix) { inX = coords[2]; inY = coords[3]; } else { var handle = segment._handleIn; inX = curX + handle._x; inY = curY + handle._y; } if (inX === curX && inY === curY && outX === prevX && outY === prevY) { ctx.lineTo(curX, curY); } else { ctx.bezierCurveTo(outX, outY, inX, inY, curX, curY); } } prevX = curX; prevY = curY; if (matrix) { outX = coords[4]; outY = coords[5]; } else { var handle = segment._handleOut; outX = prevX + handle._x; outY = prevY + handle._y; } } for (var i = 0; i < length; i++) drawSegment(segments[i]); if (path._closed && length > 0) drawSegment(segments[0]); } return { _draw: function(ctx, param, viewMatrix, strokeMatrix) { var dontStart = param.dontStart, dontPaint = param.dontFinish || param.clip, style = this.getStyle(), hasFill = style.hasFill(), hasStroke = style.hasStroke(), dashArray = style.getDashArray(), dashLength = !paper.support.nativeDash && hasStroke && dashArray && dashArray.length; if (!dontStart) ctx.beginPath(); if (hasFill || hasStroke && !dashLength || dontPaint) { drawSegments(ctx, this, strokeMatrix); if (this._closed) ctx.closePath(); } function getOffset(i) { return dashArray[((i % dashLength) + dashLength) % dashLength]; } if (!dontPaint && (hasFill || hasStroke)) { this._setStyles(ctx, param, viewMatrix, strokeMatrix); if (hasFill) { ctx.fill(style.getFillRule()); ctx.shadowColor = 'rgba(0,0,0,0)'; } if (hasStroke) { if (dashLength) { if (!dontStart) ctx.beginPath(); var flattener = new PathFlattener(this, 0.25, 32, false, strokeMatrix), length = flattener.length, from = -style.getDashOffset(), to, i = 0; from = from % length; while (from > 0) { from -= getOffset(i--) + getOffset(i--); } while (from < length) { to = from + getOffset(i++); if (from > 0 || to > 0) flattener.drawPart(ctx, Math.max(from, 0), Math.max(to, 0)); from = to + getOffset(i++); } } ctx.stroke(); } } }, _drawSelected: function(ctx, matrix) { ctx.beginPath(); drawSegments(ctx, this, matrix); ctx.stroke(); drawHandles(ctx, this._segments, matrix, paper.settings.handleSize, this.isFullySelected()); } }; }, new function() { function getCurrentSegment(that) { var segments = that._segments; if (!segments.length) throw new Error('Use a moveTo() command first'); return segments[segments.length - 1]; } return { moveTo: function() { var segments = this._segments; if (segments.length === 1) this.removeSegment(0); if (!segments.length) this._add([ new Segment(Point.read(arguments)) ]); }, moveBy: function() { throw new Error('moveBy() is unsupported on Path items.'); }, lineTo: function() { this._add([ new Segment(Point.read(arguments)) ]); }, cubicCurveTo: function() { var args = arguments, handle1 = Point.read(args), handle2 = Point.read(args), to = Point.read(args), current = getCurrentSegment(this); current.setHandleOut(handle1.subtract(current._point)); this._add([ new Segment(to, handle2.subtract(to)) ]); }, quadraticCurveTo: function() { var args = arguments, handle = Point.read(args), to = Point.read(args), current = getCurrentSegment(this)._point; this.cubicCurveTo( handle.add(current.subtract(handle).multiply(1 / 3)), handle.add(to.subtract(handle).multiply(1 / 3)), to ); }, curveTo: function() { var args = arguments, through = Point.read(args), to = Point.read(args), t = Base.pick(Base.read(args), 0.5), t1 = 1 - t, current = getCurrentSegment(this)._point, handle = through.subtract(current.multiply(t1 * t1)) .subtract(to.multiply(t * t)).divide(2 * t * t1); if (handle.isNaN()) throw new Error( 'Cannot put a curve through points with parameter = ' + t); this.quadraticCurveTo(handle, to); }, arcTo: function() { var args = arguments, abs = Math.abs, sqrt = Math.sqrt, current = getCurrentSegment(this), from = current._point, to = Point.read(args), through, peek = Base.peek(args), clockwise = Base.pick(peek, true), center, extent, vector, matrix; if (typeof clockwise === 'boolean') { var middle = from.add(to).divide(2), through = middle.add(middle.subtract(from).rotate( clockwise ? -90 : 90)); } else if (Base.remain(args) <= 2) { through = to; to = Point.read(args); } else if (!from.equals(to)) { var radius = Size.read(args), isZero = Numerical.isZero; if (isZero(radius.width) || isZero(radius.height)) return this.lineTo(to); var rotation = Base.read(args), clockwise = !!Base.read(args), large = !!Base.read(args), middle = from.add(to).divide(2), pt = from.subtract(middle).rotate(-rotation), x = pt.x, y = pt.y, rx = abs(radius.width), ry = abs(radius.height), rxSq = rx * rx, rySq = ry * ry, xSq = x * x, ySq = y * y; var factor = sqrt(xSq / rxSq + ySq / rySq); if (factor > 1) { rx *= factor; ry *= factor; rxSq = rx * rx; rySq = ry * ry; } factor = (rxSq * rySq - rxSq * ySq - rySq * xSq) / (rxSq * ySq + rySq * xSq); if (abs(factor) < 1e-12) factor = 0; if (factor < 0) throw new Error( 'Cannot create an arc with the given arguments'); center = new Point(rx * y / ry, -ry * x / rx) .multiply((large === clockwise ? -1 : 1) * sqrt(factor)) .rotate(rotation).add(middle); matrix = new Matrix().translate(center).rotate(rotation) .scale(rx, ry); vector = matrix._inverseTransform(from); extent = vector.getDirectedAngle(matrix._inverseTransform(to)); if (!clockwise && extent > 0) extent -= 360; else if (clockwise && extent < 0) extent += 360; } if (through) { var l1 = new Line(from.add(through).divide(2), through.subtract(from).rotate(90), true), l2 = new Line(through.add(to).divide(2), to.subtract(through).rotate(90), true), line = new Line(from, to), throughSide = line.getSide(through); center = l1.intersect(l2, true); if (!center) { if (!throughSide) return this.lineTo(to); throw new Error( 'Cannot create an arc with the given arguments'); } vector = from.subtract(center); extent = vector.getDirectedAngle(to.subtract(center)); var centerSide = line.getSide(center, true); if (centerSide === 0) { extent = throughSide * abs(extent); } else if (throughSide === centerSide) { extent += extent < 0 ? 360 : -360; } } if (extent) { var epsilon = 1e-7, ext = abs(extent), count = ext >= 360 ? 4 : Math.ceil((ext - epsilon) / 90), inc = extent / count, half = inc * Math.PI / 360, z = 4 / 3 * Math.sin(half) / (1 + Math.cos(half)), segments = []; for (var i = 0; i <= count; i++) { var pt = to, out = null; if (i < count) { out = vector.rotate(90).multiply(z); if (matrix) { pt = matrix._transformPoint(vector); out = matrix._transformPoint(vector.add(out)) .subtract(pt); } else { pt = center.add(vector); } } if (!i) { current.setHandleOut(out); } else { var _in = vector.rotate(-90).multiply(z); if (matrix) { _in = matrix._transformPoint(vector.add(_in)) .subtract(pt); } segments.push(new Segment(pt, _in, out)); } vector = vector.rotate(inc); } this._add(segments); } }, lineBy: function() { var to = Point.read(arguments), current = getCurrentSegment(this)._point; this.lineTo(current.add(to)); }, curveBy: function() { var args = arguments, through = Point.read(args), to = Point.read(args), parameter = Base.read(args), current = getCurrentSegment(this)._point; this.curveTo(current.add(through), current.add(to), parameter); }, cubicCurveBy: function() { var args = arguments, handle1 = Point.read(args), handle2 = Point.read(args), to = Point.read(args), current = getCurrentSegment(this)._point; this.cubicCurveTo(current.add(handle1), current.add(handle2), current.add(to)); }, quadraticCurveBy: function() { var args = arguments, handle = Point.read(args), to = Point.read(args), current = getCurrentSegment(this)._point; this.quadraticCurveTo(current.add(handle), current.add(to)); }, arcBy: function() { var args = arguments, current = getCurrentSegment(this)._point, point = current.add(Point.read(args)), clockwise = Base.pick(Base.peek(args), true); if (typeof clockwise === 'boolean') { this.arcTo(point, clockwise); } else { this.arcTo(point, current.add(Point.read(args))); } }, closePath: function(tolerance) { this.setClosed(true); this.join(this, tolerance); } }; }, { _getBounds: function(matrix, options) { var method = options.handle ? 'getHandleBounds' : options.stroke ? 'getStrokeBounds' : 'getBounds'; return Path[method](this._segments, this._closed, this, matrix, options); }, statics: { getBounds: function(segments, closed, path, matrix, options, strokePadding) { var first = segments[0]; if (!first) return new Rectangle(); var coords = new Array(6), prevCoords = first._transformCoordinates(matrix, new Array(6)), min = prevCoords.slice(0, 2), max = min.slice(), roots = new Array(2); function processSegment(segment) { segment._transformCoordinates(matrix, coords); for (var i = 0; i < 2; i++) { Curve._addBounds( prevCoords[i], prevCoords[i + 4], coords[i + 2], coords[i], i, strokePadding ? strokePadding[i] : 0, min, max, roots); } var tmp = prevCoords; prevCoords = coords; coords = tmp; } for (var i = 1, l = segments.length; i < l; i++) processSegment(segments[i]); if (closed) processSegment(first); return new Rectangle(min[0], min[1], max[0] - min[0], max[1] - min[1]); }, getStrokeBounds: function(segments, closed, path, matrix, options) { var style = path.getStyle(), stroke = style.hasStroke(), strokeWidth = style.getStrokeWidth(), strokeMatrix = stroke && path._getStrokeMatrix(matrix, options), strokePadding = stroke && Path._getStrokePadding(strokeWidth, strokeMatrix), bounds = Path.getBounds(segments, closed, path, matrix, options, strokePadding); if (!stroke) return bounds; var strokeRadius = strokeWidth / 2, join = style.getStrokeJoin(), cap = style.getStrokeCap(), miterLimit = style.getMiterLimit(), joinBounds = new Rectangle(new Size(strokePadding)); function addPoint(point) { bounds = bounds.include(point); } function addRound(segment) { bounds = bounds.unite( joinBounds.setCenter(segment._point.transform(matrix))); } function addJoin(segment, join) { if (join === 'round' || segment.isSmooth()) { addRound(segment); } else { Path._addBevelJoin(segment, join, strokeRadius, miterLimit, matrix, strokeMatrix, addPoint); } } function addCap(segment, cap) { if (cap === 'round') { addRound(segment); } else { Path._addSquareCap(segment, cap, strokeRadius, matrix, strokeMatrix, addPoint); } } var length = segments.length - (closed ? 0 : 1); if (length > 0) { for (var i = 1; i < length; i++) { addJoin(segments[i], join); } if (closed) { addJoin(segments[0], join); } else { addCap(segments[0], cap); addCap(segments[segments.length - 1], cap); } } return bounds; }, _getStrokePadding: function(radius, matrix) { if (!matrix) return [radius, radius]; var hor = new Point(radius, 0).transform(matrix), ver = new Point(0, radius).transform(matrix), phi = hor.getAngleInRadians(), a = hor.getLength(), b = ver.getLength(); var sin = Math.sin(phi), cos = Math.cos(phi), tan = Math.tan(phi), tx = Math.atan2(b * tan, a), ty = Math.atan2(b, tan * a); return [Math.abs(a * Math.cos(tx) * cos + b * Math.sin(tx) * sin), Math.abs(b * Math.sin(ty) * cos + a * Math.cos(ty) * sin)]; }, _addBevelJoin: function(segment, join, radius, miterLimit, matrix, strokeMatrix, addPoint, isArea) { var curve2 = segment.getCurve(), curve1 = curve2.getPrevious(), point = curve2.getPoint1().transform(matrix), normal1 = curve1.getNormalAtTime(1).multiply(radius) .transform(strokeMatrix), normal2 = curve2.getNormalAtTime(0).multiply(radius) .transform(strokeMatrix), angle = normal1.getDirectedAngle(normal2); if (angle < 0 || angle >= 180) { normal1 = normal1.negate(); normal2 = normal2.negate(); } if (isArea) addPoint(point); addPoint(point.add(normal1)); if (join === 'miter') { var corner = new Line(point.add(normal1), new Point(-normal1.y, normal1.x), true ).intersect(new Line(point.add(normal2), new Point(-normal2.y, normal2.x), true ), true); if (corner && point.getDistance(corner) <= miterLimit * radius) { addPoint(corner); } } addPoint(point.add(normal2)); }, _addSquareCap: function(segment, cap, radius, matrix, strokeMatrix, addPoint, isArea) { var point = segment._point.transform(matrix), loc = segment.getLocation(), normal = loc.getNormal() .multiply(loc.getTime() === 0 ? radius : -radius) .transform(strokeMatrix); if (cap === 'square') { if (isArea) { addPoint(point.subtract(normal)); addPoint(point.add(normal)); } point = point.add(normal.rotate(-90)); } addPoint(point.add(normal)); addPoint(point.subtract(normal)); }, getHandleBounds: function(segments, closed, path, matrix, options) { var style = path.getStyle(), stroke = options.stroke && style.hasStroke(), strokePadding, joinPadding; if (stroke) { var strokeMatrix = path._getStrokeMatrix(matrix, options), strokeRadius = style.getStrokeWidth() / 2, joinRadius = strokeRadius; if (style.getStrokeJoin() === 'miter') joinRadius = strokeRadius * style.getMiterLimit(); if (style.getStrokeCap() === 'square') joinRadius = Math.max(joinRadius, strokeRadius * Math.SQRT2); strokePadding = Path._getStrokePadding(strokeRadius, strokeMatrix); joinPadding = Path._getStrokePadding(joinRadius, strokeMatrix); } var coords = new Array(6), x1 = Infinity, x2 = -x1, y1 = x1, y2 = x2; for (var i = 0, l = segments.length; i < l; i++) { var segment = segments[i]; segment._transformCoordinates(matrix, coords); for (var j = 0; j < 6; j += 2) { var padding = !j ? joinPadding : strokePadding, paddingX = padding ? padding[0] : 0, paddingY = padding ? padding[1] : 0, x = coords[j], y = coords[j + 1], xn = x - paddingX, xx = x + paddingX, yn = y - paddingY, yx = y + paddingY; if (xn < x1) x1 = xn; if (xx > x2) x2 = xx; if (yn < y1) y1 = yn; if (yx > y2) y2 = yx; } } return new Rectangle(x1, y1, x2 - x1, y2 - y1); } }}); Path.inject({ statics: new function() { var kappa = 0.5522847498307936, ellipseSegments = [ new Segment([-1, 0], [0, kappa ], [0, -kappa]), new Segment([0, -1], [-kappa, 0], [kappa, 0 ]), new Segment([1, 0], [0, -kappa], [0, kappa ]), new Segment([0, 1], [kappa, 0 ], [-kappa, 0]) ]; function createPath(segments, closed, args) { var props = Base.getNamed(args), path = new Path(props && props.insert == false && Item.NO_INSERT); path._add(segments); path._closed = closed; return path.set(props, { insert: true }); } function createEllipse(center, radius, args) { var segments = new Array(4); for (var i = 0; i < 4; i++) { var segment = ellipseSegments[i]; segments[i] = new Segment( segment._point.multiply(radius).add(center), segment._handleIn.multiply(radius), segment._handleOut.multiply(radius) ); } return createPath(segments, true, args); } return { Line: function() { var args = arguments; return createPath([ new Segment(Point.readNamed(args, 'from')), new Segment(Point.readNamed(args, 'to')) ], false, args); }, Circle: function() { var args = arguments, center = Point.readNamed(args, 'center'), radius = Base.readNamed(args, 'radius'); return createEllipse(center, new Size(radius), args); }, Rectangle: function() { var args = arguments, rect = Rectangle.readNamed(args, 'rectangle'), radius = Size.readNamed(args, 'radius', 0, { readNull: true }), bl = rect.getBottomLeft(true), tl = rect.getTopLeft(true), tr = rect.getTopRight(true), br = rect.getBottomRight(true), segments; if (!radius || radius.isZero()) { segments = [ new Segment(bl), new Segment(tl), new Segment(tr), new Segment(br) ]; } else { radius = Size.min(radius, rect.getSize(true).divide(2)); var rx = radius.width, ry = radius.height, hx = rx * kappa, hy = ry * kappa; segments = [ new Segment(bl.add(rx, 0), null, [-hx, 0]), new Segment(bl.subtract(0, ry), [0, hy]), new Segment(tl.add(0, ry), null, [0, -hy]), new Segment(tl.add(rx, 0), [-hx, 0], null), new Segment(tr.subtract(rx, 0), null, [hx, 0]), new Segment(tr.add(0, ry), [0, -hy], null), new Segment(br.subtract(0, ry), null, [0, hy]), new Segment(br.subtract(rx, 0), [hx, 0]) ]; } return createPath(segments, true, args); }, RoundRectangle: '#Rectangle', Ellipse: function() { var args = arguments, ellipse = Shape._readEllipse(args); return createEllipse(ellipse.center, ellipse.radius, args); }, Oval: '#Ellipse', Arc: function() { var args = arguments, from = Point.readNamed(args, 'from'), through = Point.readNamed(args, 'through'), to = Point.readNamed(args, 'to'), props = Base.getNamed(args), path = new Path(props && props.insert == false && Item.NO_INSERT); path.moveTo(from); path.arcTo(through, to); return path.set(props); }, RegularPolygon: function() { var args = arguments, center = Point.readNamed(args, 'center'), sides = Base.readNamed(args, 'sides'), radius = Base.readNamed(args, 'radius'), step = 360 / sides, three = sides % 3 === 0, vector = new Point(0, three ? -radius : radius), offset = three ? -1 : 0.5, segments = new Array(sides); for (var i = 0; i < sides; i++) segments[i] = new Segment(center.add( vector.rotate((i + offset) * step))); return createPath(segments, true, args); }, Star: function() { var args = arguments, center = Point.readNamed(args, 'center'), points = Base.readNamed(args, 'points') * 2, radius1 = Base.readNamed(args, 'radius1'), radius2 = Base.readNamed(args, 'radius2'), step = 360 / points, vector = new Point(0, -1), segments = new Array(points); for (var i = 0; i < points; i++) segments[i] = new Segment(center.add(vector.rotate(step * i) .multiply(i % 2 ? radius2 : radius1))); return createPath(segments, true, args); } }; }}); var CompoundPath = PathItem.extend({ _class: 'CompoundPath', _serializeFields: { children: [] }, beans: true, initialize: function CompoundPath(arg) { this._children = []; this._namedChildren = {}; if (!this._initialize(arg)) { if (typeof arg === 'string') { this.setPathData(arg); } else { this.addChildren(Array.isArray(arg) ? arg : arguments); } } }, insertChildren: function insertChildren(index, items) { var list = items, first = list[0]; if (first && typeof first[0] === 'number') list = [list]; for (var i = items.length - 1; i >= 0; i--) { var item = list[i]; if (list === items && !(item instanceof Path)) list = Base.slice(list); if (Array.isArray(item)) { list[i] = new Path({ segments: item, insert: false }); } else if (item instanceof CompoundPath) { list.splice.apply(list, [i, 1].concat(item.removeChildren())); item.remove(); } } return insertChildren.base.call(this, index, list); }, reduce: function reduce(options) { var children = this._children; for (var i = children.length - 1; i >= 0; i--) { var path = children[i].reduce(options); if (path.isEmpty()) path.remove(); } if (!children.length) { var path = new Path(Item.NO_INSERT); path.copyAttributes(this); path.insertAbove(this); this.remove(); return path; } return reduce.base.call(this); }, isClosed: function() { var children = this._children; for (var i = 0, l = children.length; i < l; i++) { if (!children[i]._closed) return false; } return true; }, setClosed: function(closed) { var children = this._children; for (var i = 0, l = children.length; i < l; i++) { children[i].setClosed(closed); } }, getFirstSegment: function() { var first = this.getFirstChild(); return first && first.getFirstSegment(); }, getLastSegment: function() { var last = this.getLastChild(); return last && last.getLastSegment(); }, getCurves: function() { var children = this._children, curves = []; for (var i = 0, l = children.length; i < l; i++) { Base.push(curves, children[i].getCurves()); } return curves; }, getFirstCurve: function() { var first = this.getFirstChild(); return first && first.getFirstCurve(); }, getLastCurve: function() { var last = this.getLastChild(); return last && last.getLastCurve(); }, getArea: function() { var children = this._children, area = 0; for (var i = 0, l = children.length; i < l; i++) area += children[i].getArea(); return area; }, getLength: function() { var children = this._children, length = 0; for (var i = 0, l = children.length; i < l; i++) length += children[i].getLength(); return length; }, getPathData: function(_matrix, _precision) { var children = this._children, paths = []; for (var i = 0, l = children.length; i < l; i++) { var child = children[i], mx = child._matrix; paths.push(child.getPathData(_matrix && !mx.isIdentity() ? _matrix.appended(mx) : _matrix, _precision)); } return paths.join(''); }, _hitTestChildren: function _hitTestChildren(point, options, viewMatrix) { return _hitTestChildren.base.call(this, point, options.class === Path || options.type === 'path' || options.hitUnfilledPaths ? options : Base.set({}, options, { fill: false }), viewMatrix); }, _draw: function(ctx, param, viewMatrix, strokeMatrix) { var children = this._children; if (!children.length) return; param = param.extend({ dontStart: true, dontFinish: true }); ctx.beginPath(); for (var i = 0, l = children.length; i < l; i++) children[i].draw(ctx, param, strokeMatrix); if (!param.clip) { this._setStyles(ctx, param, viewMatrix, strokeMatrix); var style = this._style; if (style.hasFill()) { ctx.fill(style.getFillRule()); ctx.shadowColor = 'rgba(0,0,0,0)'; } if (style.hasStroke()) ctx.stroke(); } }, _drawSelected: function(ctx, matrix, selectionItems) { var children = this._children; for (var i = 0, l = children.length; i < l; i++) { var child = children[i], mx = child._matrix; if (!selectionItems[child._id]) { child._drawSelected(ctx, mx.isIdentity() ? matrix : matrix.appended(mx)); } } } }, new function() { function getCurrentPath(that, check) { var children = that._children; if (check && !children.length) throw new Error('Use a moveTo() command first'); return children[children.length - 1]; } return Base.each(['lineTo', 'cubicCurveTo', 'quadraticCurveTo', 'curveTo', 'arcTo', 'lineBy', 'cubicCurveBy', 'quadraticCurveBy', 'curveBy', 'arcBy'], function(key) { this[key] = function() { var path = getCurrentPath(this, true); path[key].apply(path, arguments); }; }, { moveTo: function() { var current = getCurrentPath(this), path = current && current.isEmpty() ? current : new Path(Item.NO_INSERT); if (path !== current) this.addChild(path); path.moveTo.apply(path, arguments); }, moveBy: function() { var current = getCurrentPath(this, true), last = current && current.getLastSegment(), point = Point.read(arguments); this.moveTo(last ? point.add(last._point) : point); }, closePath: function(tolerance) { getCurrentPath(this, true).closePath(tolerance); } } ); }, Base.each(['reverse', 'flatten', 'simplify', 'smooth'], function(key) { this[key] = function(param) { var children = this._children, res; for (var i = 0, l = children.length; i < l; i++) { res = children[i][key](param) || res; } return res; }; }, {})); PathItem.inject(new function() { var min = Math.min, max = Math.max, abs = Math.abs, operators = { unite: { '1': true, '2': true }, intersect: { '2': true }, subtract: { '1': true }, exclude: { '1': true, '-1': true } }; function getPaths(path) { return path._children || [path]; } function preparePath(path, resolve) { var res = path .clone(false) .reduce({ simplify: true }) .transform(null, true, true); if (resolve) { var paths = getPaths(res); for (var i = 0, l = paths.length; i < l; i++) { var path = paths[i]; if (!path._closed && !path.isEmpty()) { path.closePath(1e-12); path.getFirstSegment().setHandleIn(0, 0); path.getLastSegment().setHandleOut(0, 0); } } res = res .resolveCrossings() .reorient(res.getFillRule() === 'nonzero', true); } return res; } function createResult(paths, simplify, path1, path2, options) { var result = new CompoundPath(Item.NO_INSERT); result.addChildren(paths, true); result = result.reduce({ simplify: simplify }); if (!(options && options.insert == false)) { result.insertAbove(path2 && path1.isSibling(path2) && path1.getIndex() < path2.getIndex() ? path2 : path1); } result.copyAttributes(path1, true); return result; } function filterIntersection(inter) { return inter.hasOverlap() || inter.isCrossing(); } function traceBoolean(path1, path2, operation, options) { if (options && (options.trace == false || options.stroke) && /^(subtract|intersect)$/.test(operation)) return splitBoolean(path1, path2, operation); var _path1 = preparePath(path1, true), _path2 = path2 && path1 !== path2 && preparePath(path2, true), operator = operators[operation]; operator[operation] = true; if (_path2 && (operator.subtract || operator.exclude) ^ (_path2.isClockwise() ^ _path1.isClockwise())) _path2.reverse(); var crossings = divideLocations(CurveLocation.expand( _path1.getIntersections(_path2, filterIntersection))), paths1 = getPaths(_path1), paths2 = _path2 && getPaths(_path2), segments = [], curves = [], paths; function collectPaths(paths) { for (var i = 0, l = paths.length; i < l; i++) { var path = paths[i]; Base.push(segments, path._segments); Base.push(curves, path.getCurves()); path._overlapsOnly = true; } } function getCurves(indices) { var list = []; for (var i = 0, l = indices && indices.length; i < l; i++) { list.push(curves[indices[i]]); } return list; } if (crossings.length) { collectPaths(paths1); if (paths2) collectPaths(paths2); var curvesValues = new Array(curves.length); for (var i = 0, l = curves.length; i < l; i++) { curvesValues[i] = curves[i].getValues(); } var curveCollisions = CollisionDetection.findCurveBoundsCollisions( curvesValues, curvesValues, 0, true); var curveCollisionsMap = {}; for (var i = 0; i < curves.length; i++) { var curve = curves[i], id = curve._path._id, map = curveCollisionsMap[id] = curveCollisionsMap[id] || {}; map[curve.getIndex()] = { hor: getCurves(curveCollisions[i].hor), ver: getCurves(curveCollisions[i].ver) }; } for (var i = 0, l = crossings.length; i < l; i++) { propagateWinding(crossings[i]._segment, _path1, _path2, curveCollisionsMap, operator); } for (var i = 0, l = segments.length; i < l; i++) { var segment = segments[i], inter = segment._intersection; if (!segment._winding) { propagateWinding(segment, _path1, _path2, curveCollisionsMap, operator); } if (!(inter && inter._overlap)) segment._path._overlapsOnly = false; } paths = tracePaths(segments, operator); } else { paths = reorientPaths( paths2 ? paths1.concat(paths2) : paths1.slice(), function(w) { return !!operator[w]; }); } return createResult(paths, true, path1, path2, options); } function splitBoolean(path1, path2, operation) { var _path1 = preparePath(path1), _path2 = preparePath(path2), crossings = _path1.getIntersections(_path2, filterIntersection), subtract = operation === 'subtract', divide = operation === 'divide', added = {}, paths = []; function addPath(path) { if (!added[path._id] && (divide || _path2.contains(path.getPointAt(path.getLength() / 2)) ^ subtract)) { paths.unshift(path); return added[path._id] = true; } } for (var i = crossings.length - 1; i >= 0; i--) { var path = crossings[i].split(); if (path) { if (addPath(path)) path.getFirstSegment().setHandleIn(0, 0); _path1.getLastSegment().setHandleOut(0, 0); } } addPath(_path1); return createResult(paths, false, path1, path2); } function linkIntersections(from, to) { var prev = from; while (prev) { if (prev === to) return; prev = prev._previous; } while (from._next && from._next !== to) from = from._next; if (!from._next) { while (to._previous) to = to._previous; from._next = to; to._previous = from; } } function clearCurveHandles(curves) { for (var i = curves.length - 1; i >= 0; i--) curves[i].clearHandles(); } function reorientPaths(paths, isInside, clockwise) { var length = paths && paths.length; if (length) { var lookup = Base.each(paths, function (path, i) { this[path._id] = { container: null, winding: path.isClockwise() ? 1 : -1, index: i }; }, {}), sorted = paths.slice().sort(function (a, b) { return abs(b.getArea()) - abs(a.getArea()); }), first = sorted[0]; var collisions = CollisionDetection.findItemBoundsCollisions(sorted, null, Numerical.GEOMETRIC_EPSILON); if (clockwise == null) clockwise = first.isClockwise(); for (var i = 0; i < length; i++) { var path1 = sorted[i], entry1 = lookup[path1._id], containerWinding = 0, indices = collisions[i]; if (indices) { var point = null; for (var j = indices.length - 1; j >= 0; j--) { if (indices[j] < i) { point = point || path1.getInteriorPoint(); var path2 = sorted[indices[j]]; if (path2.contains(point)) { var entry2 = lookup[path2._id]; containerWinding = entry2.winding; entry1.winding += containerWinding; entry1.container = entry2.exclude ? entry2.container : path2; break; } } } } if (isInside(entry1.winding) === isInside(containerWinding)) { entry1.exclude = true; paths[entry1.index] = null; } else { var container = entry1.container; path1.setClockwise( container ? !container.isClockwise() : clockwise); } } } return paths; } function divideLocations(locations, include, clearLater) { var results = include && [], tMin = 1e-8, tMax = 1 - tMin, clearHandles = false, clearCurves = clearLater || [], clearLookup = clearLater && {}, renormalizeLocs, prevCurve, prevTime; function getId(curve) { return curve._path._id + '.' + curve._segment1._index; } for (var i = (clearLater && clearLater.length) - 1; i >= 0; i--) { var curve = clearLater[i]; if (curve._path) clearLookup[getId(curve)] = true; } for (var i = locations.length - 1; i >= 0; i--) { var loc = locations[i], time = loc._time, origTime = time, exclude = include && !include(loc), curve = loc._curve, segment; if (curve) { if (curve !== prevCurve) { clearHandles = !curve.hasHandles() || clearLookup && clearLookup[getId(curve)]; renormalizeLocs = []; prevTime = null; prevCurve = curve; } else if (prevTime >= tMin) { time /= prevTime; } } if (exclude) { if (renormalizeLocs) renormalizeLocs.push(loc); continue; } else if (include) { results.unshift(loc); } prevTime = origTime; if (time < tMin) { segment = curve._segment1; } else if (time > tMax) { segment = curve._segment2; } else { var newCurve = curve.divideAtTime(time, true); if (clearHandles) clearCurves.push(curve, newCurve); segment = newCurve._segment1; for (var j = renormalizeLocs.length - 1; j >= 0; j--) { var l = renormalizeLocs[j]; l._time = (l._time - time) / (1 - time); } } loc._setSegment(segment); var inter = segment._intersection, dest = loc._intersection; if (inter) { linkIntersections(inter, dest); var other = inter; while (other) { linkIntersections(other._intersection, inter); other = other._next; } } else { segment._intersection = dest; } } if (!clearLater) clearCurveHandles(clearCurves); return results || locations; } function getWinding(point, curves, dir, closed, dontFlip) { var curvesList = Array.isArray(curves) ? curves : curves[dir ? 'hor' : 'ver']; var ia = dir ? 1 : 0, io = ia ^ 1, pv = [point.x, point.y], pa = pv[ia], po = pv[io], windingEpsilon = 1e-9, qualityEpsilon = 1e-6, paL = pa - windingEpsilon, paR = pa + windingEpsilon, windingL = 0, windingR = 0, pathWindingL = 0, pathWindingR = 0, onPath = false, onAnyPath = false, quality = 1, roots = [], vPrev, vClose; function addWinding(v) { var o0 = v[io + 0], o3 = v[io + 6]; if (po < min(o0, o3) || po > max(o0, o3)) { return; } var a0 = v[ia + 0], a1 = v[ia + 2], a2 = v[ia + 4], a3 = v[ia + 6]; if (o0 === o3) { if (a0 < paR && a3 > paL || a3 < paR && a0 > paL) { onPath = true; } return; } var t = po === o0 ? 0 : po === o3 ? 1 : paL > max(a0, a1, a2, a3) || paR < min(a0, a1, a2, a3) ? 1 : Curve.solveCubic(v, io, po, roots, 0, 1) > 0 ? roots[0] : 1, a = t === 0 ? a0 : t === 1 ? a3 : Curve.getPoint(v, t)[dir ? 'y' : 'x'], winding = o0 > o3 ? 1 : -1, windingPrev = vPrev[io] > vPrev[io + 6] ? 1 : -1, a3Prev = vPrev[ia + 6]; if (po !== o0) { if (a < paL) { pathWindingL += winding; } else if (a > paR) { pathWindingR += winding; } else { onPath = true; } if (a > pa - qualityEpsilon && a < pa + qualityEpsilon) quality /= 2; } else { if (winding !== windingPrev) { if (a0 < paL) { pathWindingL += winding; } else if (a0 > paR) { pathWindingR += winding; } } else if (a0 != a3Prev) { if (a3Prev < paR && a > paR) { pathWindingR += winding; onPath = true; } else if (a3Prev > paL && a < paL) { pathWindingL += winding; onPath = true; } } quality /= 4; } vPrev = v; return !dontFlip && a > paL && a < paR && Curve.getTangent(v, t)[dir ? 'x' : 'y'] === 0 && getWinding(point, curves, !dir, closed, true); } function handleCurve(v) { var o0 = v[io + 0], o1 = v[io + 2], o2 = v[io + 4], o3 = v[io + 6]; if (po <= max(o0, o1, o2, o3) && po >= min(o0, o1, o2, o3)) { var a0 = v[ia + 0], a1 = v[ia + 2], a2 = v[ia + 4], a3 = v[ia + 6], monoCurves = paL > max(a0, a1, a2, a3) || paR < min(a0, a1, a2, a3) ? [v] : Curve.getMonoCurves(v, dir), res; for (var i = 0, l = monoCurves.length; i < l; i++) { if (res = addWinding(monoCurves[i])) return res; } } } for (var i = 0, l = curvesList.length; i < l; i++) { var curve = curvesList[i], path = curve._path, v = curve.getValues(), res; if (!i || curvesList[i - 1]._path !== path) { vPrev = null; if (!path._closed) { vClose = Curve.getValues( path.getLastCurve().getSegment2(), curve.getSegment1(), null, !closed); if (vClose[io] !== vClose[io + 6]) { vPrev = vClose; } } if (!vPrev) { vPrev = v; var prev = path.getLastCurve(); while (prev && prev !== curve) { var v2 = prev.getValues(); if (v2[io] !== v2[io + 6]) { vPrev = v2; break; } prev = prev.getPrevious(); } } } if (res = handleCurve(v)) return res; if (i + 1 === l || curvesList[i + 1]._path !== path) { if (vClose && (res = handleCurve(vClose))) return res; if (onPath && !pathWindingL && !pathWindingR) { pathWindingL = pathWindingR = path.isClockwise(closed) ^ dir ? 1 : -1; } windingL += pathWindingL; windingR += pathWindingR; pathWindingL = pathWindingR = 0; if (onPath) { onAnyPath = true; onPath = false; } vClose = null; } } windingL = abs(windingL); windingR = abs(windingR); return { winding: max(windingL, windingR), windingL: windingL, windingR: windingR, quality: quality, onPath: onAnyPath }; } function propagateWinding(segment, path1, path2, curveCollisionsMap, operator) { var chain = [], start = segment, totalLength = 0, winding; do { var curve = segment.getCurve(); if (curve) { var length = curve.getLength(); chain.push({ segment: segment, curve: curve, length: length }); totalLength += length; } segment = segment.getNext(); } while (segment && !segment._intersection && segment !== start); var offsets = [0.5, 0.25, 0.75], winding = { winding: 0, quality: -1 }, tMin = 1e-3, tMax = 1 - tMin; for (var i = 0; i < offsets.length && winding.quality < 0.5; i++) { var length = totalLength * offsets[i]; for (var j = 0, l = chain.length; j < l; j++) { var entry = chain[j], curveLength = entry.length; if (length <= curveLength) { var curve = entry.curve, path = curve._path, parent = path._parent, operand = parent instanceof CompoundPath ? parent : path, t = Numerical.clamp(curve.getTimeAt(length), tMin, tMax), pt = curve.getPointAtTime(t), dir = abs(curve.getTangentAtTime(t).y) < Math.SQRT1_2; var wind = null; if (operator.subtract && path2) { var otherPath = operand === path1 ? path2 : path1, pathWinding = otherPath._getWinding(pt, dir, true); if (operand === path1 && pathWinding.winding || operand === path2 && !pathWinding.winding) { if (pathWinding.quality < 1) { continue; } else { wind = { winding: 0, quality: 1 }; } } } wind = wind || getWinding( pt, curveCollisionsMap[path._id][curve.getIndex()], dir, true); if (wind.quality > winding.quality) winding = wind; break; } length -= curveLength; } } for (var j = chain.length - 1; j >= 0; j--) { chain[j].segment._winding = winding; } } function tracePaths(segments, operator) { var paths = [], starts; function isValid(seg) { var winding; return !!(seg && !seg._visited && (!operator || operator[(winding = seg._winding || {}).winding] && !(operator.unite && winding.winding === 2 && winding.windingL && winding.windingR))); } function isStart(seg) { if (seg) { for (var i = 0, l = starts.length; i < l; i++) { if (seg === starts[i]) return true; } } return false; } function visitPath(path) { var segments = path._segments; for (var i = 0, l = segments.length; i < l; i++) { segments[i]._visited = true; } } function getCrossingSegments(segment, collectStarts) { var inter = segment._intersection, start = inter, crossings = []; if (collectStarts) starts = [segment]; function collect(inter, end) { while (inter && inter !== end) { var other = inter._segment, path = other && other._path; if (path) { var next = other.getNext() || path.getFirstSegment(), nextInter = next._intersection; if (other !== segment && (isStart(other) || isStart(next) || next && (isValid(other) && (isValid(next) || nextInter && isValid(nextInter._segment)))) ) { crossings.push(other); } if (collectStarts) starts.push(other); } inter = inter._next; } } if (inter) { collect(inter); while (inter && inter._previous) inter = inter._previous; collect(inter, start); } return crossings; } segments.sort(function(seg1, seg2) { var inter1 = seg1._intersection, inter2 = seg2._intersection, over1 = !!(inter1 && inter1._overlap), over2 = !!(inter2 && inter2._overlap), path1 = seg1._path, path2 = seg2._path; return over1 ^ over2 ? over1 ? 1 : -1 : !inter1 ^ !inter2 ? inter1 ? 1 : -1 : path1 !== path2 ? path1._id - path2._id : seg1._index - seg2._index; }); for (var i = 0, l = segments.length; i < l; i++) { var seg = segments[i], valid = isValid(seg), path = null, finished = false, closed = true, branches = [], branch, visited, handleIn; if (valid && seg._path._overlapsOnly) { var path1 = seg._path, path2 = seg._intersection._segment._path; if (path1.compare(path2)) { if (path1.getArea()) paths.push(path1.clone(false)); visitPath(path1); visitPath(path2); valid = false; } } while (valid) { var first = !path, crossings = getCrossingSegments(seg, first), other = crossings.shift(), finished = !first && (isStart(seg) || isStart(other)), cross = !finished && other; if (first) { path = new Path(Item.NO_INSERT); branch = null; } if (finished) { if (seg.isFirst() || seg.isLast()) closed = seg._path._closed; seg._visited = true; break; } if (cross && branch) { branches.push(branch); branch = null; } if (!branch) { if (cross) crossings.push(seg); branch = { start: path._segments.length, crossings: crossings, visited: visited = [], handleIn: handleIn }; } if (cross) seg = other; if (!isValid(seg)) { path.removeSegments(branch.start); for (var j = 0, k = visited.length; j < k; j++) { visited[j]._visited = false; } visited.length = 0; do { seg = branch && branch.crossings.shift(); if (!seg || !seg._path) { seg = null; branch = branches.pop(); if (branch) { visited = branch.visited; handleIn = branch.handleIn; } } } while (branch && !isValid(seg)); if (!seg) break; } var next = seg.getNext(); path.add(new Segment(seg._point, handleIn, next && seg._handleOut)); seg._visited = true; visited.push(seg); seg = next || seg._path.getFirstSegment(); handleIn = next && next._handleIn; } if (finished) { if (closed) { path.getFirstSegment().setHandleIn(handleIn); path.setClosed(closed); } if (path.getArea() !== 0) { paths.push(path); } } } return paths; } return { _getWinding: function(point, dir, closed) { return getWinding(point, this.getCurves(), dir, closed); }, unite: function(path, options) { return traceBoolean(this, path, 'unite', options); }, intersect: function(path, options) { return traceBoolean(this, path, 'intersect', options); }, subtract: function(path, options) { return traceBoolean(this, path, 'subtract', options); }, exclude: function(path, options) { return traceBoolean(this, path, 'exclude', options); }, divide: function(path, options) { return options && (options.trace == false || options.stroke) ? splitBoolean(this, path, 'divide') : createResult([ this.subtract(path, options), this.intersect(path, options) ], true, this, path, options); }, resolveCrossings: function() { var children = this._children, paths = children || [this]; function hasOverlap(seg, path) { var inter = seg && seg._intersection; return inter && inter._overlap && inter._path === path; } var hasOverlaps = false, hasCrossings = false, intersections = this.getIntersections(null, function(inter) { return inter.hasOverlap() && (hasOverlaps = true) || inter.isCrossing() && (hasCrossings = true); }), clearCurves = hasOverlaps && hasCrossings && []; intersections = CurveLocation.expand(intersections); if (hasOverlaps) { var overlaps = divideLocations(intersections, function(inter) { return inter.hasOverlap(); }, clearCurves); for (var i = overlaps.length - 1; i >= 0; i--) { var overlap = overlaps[i], path = overlap._path, seg = overlap._segment, prev = seg.getPrevious(), next = seg.getNext(); if (hasOverlap(prev, path) && hasOverlap(next, path)) { seg.remove(); prev._handleOut._set(0, 0); next._handleIn._set(0, 0); if (prev !== seg && !prev.getCurve().hasLength()) { next._handleIn.set(prev._handleIn); prev.remove(); } } } } if (hasCrossings) { divideLocations(intersections, hasOverlaps && function(inter) { var curve1 = inter.getCurve(), seg1 = inter.getSegment(), other = inter._intersection, curve2 = other._curve, seg2 = other._segment; if (curve1 && curve2 && curve1._path && curve2._path) return true; if (seg1) seg1._intersection = null; if (seg2) seg2._intersection = null; }, clearCurves); if (clearCurves) clearCurveHandles(clearCurves); paths = tracePaths(Base.each(paths, function(path) { Base.push(this, path._segments); }, [])); } var length = paths.length, item; if (length > 1 && children) { if (paths !== children) this.setChildren(paths); item = this; } else if (length === 1 && !children) { if (paths[0] !== this) this.setSegments(paths[0].removeSegments()); item = this; } if (!item) { item = new CompoundPath(Item.NO_INSERT); item.addChildren(paths); item = item.reduce(); item.copyAttributes(this); this.replaceWith(item); } return item; }, reorient: function(nonZero, clockwise) { var children = this._children; if (children && children.length) { this.setChildren(reorientPaths(this.removeChildren(), function(w) { return !!(nonZero ? w : w & 1); }, clockwise)); } else if (clockwise !== undefined) { this.setClockwise(clockwise); } return this; }, getInteriorPoint: function() { var bounds = this.getBounds(), point = bounds.getCenter(true); if (!this.contains(point)) { var curves = this.getCurves(), y = point.y, intercepts = [], roots = []; for (var i = 0, l = curves.length; i < l; i++) { var v = curves[i].getValues(), o0 = v[1], o1 = v[3], o2 = v[5], o3 = v[7]; if (y >= min(o0, o1, o2, o3) && y <= max(o0, o1, o2, o3)) { var monoCurves = Curve.getMonoCurves(v); for (var j = 0, m = monoCurves.length; j < m; j++) { var mv = monoCurves[j], mo0 = mv[1], mo3 = mv[7]; if ((mo0 !== mo3) && (y >= mo0 && y <= mo3 || y >= mo3 && y <= mo0)){ var x = y === mo0 ? mv[0] : y === mo3 ? mv[6] : Curve.solveCubic(mv, 1, y, roots, 0, 1) === 1 ? Curve.getPoint(mv, roots[0]).x : (mv[0] + mv[6]) / 2; intercepts.push(x); } } } } if (intercepts.length > 1) { intercepts.sort(function(a, b) { return a - b; }); point.x = (intercepts[0] + intercepts[1]) / 2; } } return point; } }; }); var PathFlattener = Base.extend({ _class: 'PathFlattener', initialize: function(path, flatness, maxRecursion, ignoreStraight, matrix) { var curves = [], parts = [], length = 0, minSpan = 1 / (maxRecursion || 32), segments = path._segments, segment1 = segments[0], segment2; function addCurve(segment1, segment2) { var curve = Curve.getValues(segment1, segment2, matrix); curves.push(curve); computeParts(curve, segment1._index, 0, 1); } function computeParts(curve, index, t1, t2) { if ((t2 - t1) > minSpan && !(ignoreStraight && Curve.isStraight(curve)) && !Curve.isFlatEnough(curve, flatness || 0.25)) { var halves = Curve.subdivide(curve, 0.5), tMid = (t1 + t2) / 2; computeParts(halves[0], index, t1, tMid); computeParts(halves[1], index, tMid, t2); } else { var dx = curve[6] - curve[0], dy = curve[7] - curve[1], dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { length += dist; parts.push({ offset: length, curve: curve, index: index, time: t2, }); } } } for (var i = 1, l = segments.length; i < l; i++) { segment2 = segments[i]; addCurve(segment1, segment2); segment1 = segment2; } if (path._closed) addCurve(segment2 || segment1, segments[0]); this.curves = curves; this.parts = parts; this.length = length; this.index = 0; }, _get: function(offset) { var parts = this.parts, length = parts.length, start, i, j = this.index; for (;;) { i = j; if (!j || parts[--j].offset < offset) break; } for (; i < length; i++) { var part = parts[i]; if (part.offset >= offset) { this.index = i; var prev = parts[i - 1], prevTime = prev && prev.index === part.index ? prev.time : 0, prevOffset = prev ? prev.offset : 0; return { index: part.index, time: prevTime + (part.time - prevTime) * (offset - prevOffset) / (part.offset - prevOffset) }; } } return { index: parts[length - 1].index, time: 1 }; }, drawPart: function(ctx, from, to) { var start = this._get(from), end = this._get(to); for (var i = start.index, l = end.index; i <= l; i++) { var curve = Curve.getPart(this.curves[i], i === start.index ? start.time : 0, i === end.index ? end.time : 1); if (i === start.index) ctx.moveTo(curve[0], curve[1]); ctx.bezierCurveTo.apply(ctx, curve.slice(2)); } } }, Base.each(Curve._evaluateMethods, function(name) { this[name + 'At'] = function(offset) { var param = this._get(offset); return Curve[name](this.curves[param.index], param.time); }; }, {}) ); var PathFitter = Base.extend({ initialize: function(path) { var points = this.points = [], segments = path._segments, closed = path._closed; for (var i = 0, prev, l = segments.length; i < l; i++) { var point = segments[i].point; if (!prev || !prev.equals(point)) { points.push(prev = point.clone()); } } if (closed) { points.unshift(points[points.length - 1]); points.push(points[1]); } this.closed = closed; }, fit: function(error) { var points = this.points, length = points.length, segments = null; if (length > 0) { segments = [new Segment(points[0])]; if (length > 1) { this.fitCubic(segments, error, 0, length - 1, points[1].subtract(points[0]), points[length - 2].subtract(points[length - 1])); if (this.closed) { segments.shift(); segments.pop(); } } } return segments; }, fitCubic: function(segments, error, first, last, tan1, tan2) { var points = this.points; if (last - first === 1) { var pt1 = points[first], pt2 = points[last], dist = pt1.getDistance(pt2) / 3; this.addCurve(segments, [pt1, pt1.add(tan1.normalize(dist)), pt2.add(tan2.normalize(dist)), pt2]); return; } var uPrime = this.chordLengthParameterize(first, last), maxError = Math.max(error, error * error), split, parametersInOrder = true; for (var i = 0; i <= 4; i++) { var curve = this.generateBezier(first, last, uPrime, tan1, tan2); var max = this.findMaxError(first, last, curve, uPrime); if (max.error < error && parametersInOrder) { this.addCurve(segments, curve); return; } split = max.index; if (max.error >= maxError) break; parametersInOrder = this.reparameterize(first, last, uPrime, curve); maxError = max.error; } var tanCenter = points[split - 1].subtract(points[split + 1]); this.fitCubic(segments, error, first, split, tan1, tanCenter); this.fitCubic(segments, error, split, last, tanCenter.negate(), tan2); }, addCurve: function(segments, curve) { var prev = segments[segments.length - 1]; prev.setHandleOut(curve[1].subtract(curve[0])); segments.push(new Segment(curve[3], curve[2].subtract(curve[3]))); }, generateBezier: function(first, last, uPrime, tan1, tan2) { var epsilon = 1e-12, abs = Math.abs, points = this.points, pt1 = points[first], pt2 = points[last], C = [[0, 0], [0, 0]], X = [0, 0]; for (var i = 0, l = last - first + 1; i < l; i++) { var u = uPrime[i], t = 1 - u, b = 3 * u * t, b0 = t * t * t, b1 = b * t, b2 = b * u, b3 = u * u * u, a1 = tan1.normalize(b1), a2 = tan2.normalize(b2), tmp = points[first + i] .subtract(pt1.multiply(b0 + b1)) .subtract(pt2.multiply(b2 + b3)); C[0][0] += a1.dot(a1); C[0][1] += a1.dot(a2); C[1][0] = C[0][1]; C[1][1] += a2.dot(a2); X[0] += a1.dot(tmp); X[1] += a2.dot(tmp); } var detC0C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1], alpha1, alpha2; if (abs(detC0C1) > epsilon) { var detC0X = C[0][0] * X[1] - C[1][0] * X[0], detXC1 = X[0] * C[1][1] - X[1] * C[0][1]; alpha1 = detXC1 / detC0C1; alpha2 = detC0X / detC0C1; } else { var c0 = C[0][0] + C[0][1], c1 = C[1][0] + C[1][1]; alpha1 = alpha2 = abs(c0) > epsilon ? X[0] / c0 : abs(c1) > epsilon ? X[1] / c1 : 0; } var segLength = pt2.getDistance(pt1), eps = epsilon * segLength, handle1, handle2; if (alpha1 < eps || alpha2 < eps) { alpha1 = alpha2 = segLength / 3; } else { var line = pt2.subtract(pt1); handle1 = tan1.normalize(alpha1); handle2 = tan2.normalize(alpha2); if (handle1.dot(line) - handle2.dot(line) > segLength * segLength) { alpha1 = alpha2 = segLength / 3; handle1 = handle2 = null; } } return [pt1, pt1.add(handle1 || tan1.normalize(alpha1)), pt2.add(handle2 || tan2.normalize(alpha2)), pt2]; }, reparameterize: function(first, last, u, curve) { for (var i = first; i <= last; i++) { u[i - first] = this.findRoot(curve, this.points[i], u[i - first]); } for (var i = 1, l = u.length; i < l; i++) { if (u[i] <= u[i - 1]) return false; } return true; }, findRoot: function(curve, point, u) { var curve1 = [], curve2 = []; for (var i = 0; i <= 2; i++) { curve1[i] = curve[i + 1].subtract(curve[i]).multiply(3); } for (var i = 0; i <= 1; i++) { curve2[i] = curve1[i + 1].subtract(curve1[i]).multiply(2); } var pt = this.evaluate(3, curve, u), pt1 = this.evaluate(2, curve1, u), pt2 = this.evaluate(1, curve2, u), diff = pt.subtract(point), df = pt1.dot(pt1) + diff.dot(pt2); return Numerical.isMachineZero(df) ? u : u - diff.dot(pt1) / df; }, evaluate: function(degree, curve, t) { var tmp = curve.slice(); for (var i = 1; i <= degree; i++) { for (var j = 0; j <= degree - i; j++) { tmp[j] = tmp[j].multiply(1 - t).add(tmp[j + 1].multiply(t)); } } return tmp[0]; }, chordLengthParameterize: function(first, last) { var u = [0]; for (var i = first + 1; i <= last; i++) { u[i - first] = u[i - first - 1] + this.points[i].getDistance(this.points[i - 1]); } for (var i = 1, m = last - first; i <= m; i++) { u[i] /= u[m]; } return u; }, findMaxError: function(first, last, curve, u) { var index = Math.floor((last - first + 1) / 2), maxDist = 0; for (var i = first + 1; i < last; i++) { var P = this.evaluate(3, curve, u[i - first]); var v = P.subtract(this.points[i]); var dist = v.x * v.x + v.y * v.y; if (dist >= maxDist) { maxDist = dist; index = i; } } return { error: maxDist, index: index }; } }); var TextItem = Item.extend({ _class: 'TextItem', _applyMatrix: false, _canApplyMatrix: false, _serializeFields: { content: null }, _boundsOptions: { stroke: false, handle: false }, initialize: function TextItem(arg) { this._content = ''; this._lines = []; var hasProps = arg && Base.isPlainObject(arg) && arg.x === undefined && arg.y === undefined; this._initialize(hasProps && arg, !hasProps && Point.read(arguments)); }, _equals: function(item) { return this._content === item._content; }, copyContent: function(source) { this.setContent(source._content); }, getContent: function() { return this._content; }, setContent: function(content) { this._content = '' + content; this._lines = this._content.split(/\r\n|\n|\r/mg); this._changed(521); }, isEmpty: function() { return !this._content; }, getCharacterStyle: '#getStyle', setCharacterStyle: '#setStyle', getParagraphStyle: '#getStyle', setParagraphStyle: '#setStyle' }); var PointText = TextItem.extend({ _class: 'PointText', initialize: function PointText() { TextItem.apply(this, arguments); }, getPoint: function() { var point = this._matrix.getTranslation(); return new LinkedPoint(point.x, point.y, this, 'setPoint'); }, setPoint: function() { var point = Point.read(arguments); this.translate(point.subtract(this._matrix.getTranslation())); }, _draw: function(ctx, param, viewMatrix) { if (!this._content) return; this._setStyles(ctx, param, viewMatrix); var lines = this._lines, style = this._style, hasFill = style.hasFill(), hasStroke = style.hasStroke(), leading = style.getLeading(), shadowColor = ctx.shadowColor; ctx.font = style.getFontStyle(); ctx.textAlign = style.getJustification(); for (var i = 0, l = lines.length; i < l; i++) { ctx.shadowColor = shadowColor; var line = lines[i]; if (hasFill) { ctx.fillText(line, 0, 0); ctx.shadowColor = 'rgba(0,0,0,0)'; } if (hasStroke) ctx.strokeText(line, 0, 0); ctx.translate(0, leading); } }, _getBounds: function(matrix, options) { var rect = options.drawnTextBounds ? this._getDrawnTextSize() : this._getMeasuredTextSize(); return matrix ? matrix._transformBounds(rect, rect) : rect; }, _getMeasuredTextSize: function() { var style = this._style, lines = this._lines, numLines = lines.length, justification = style.getJustification(), leading = style.getLeading(), width = this.getView().getTextWidth(style.getFontStyle(), lines), x = 0; if (justification !== 'left') x -= width / (justification === 'center' ? 2: 1); return new Rectangle(x, numLines ? - 0.75 * leading : 0, width, numLines * leading); }, _getDrawnTextSize: function() { var style = this._style; var lines = this._lines; var numLines = lines.length; var leading = style.getLeading(); var justification = style.getJustification(); var svg = SvgElement.create('svg', { version: '1.1', xmlns: SvgElement.svg }); var node = SvgElement.create('text'); node.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve'); svg.appendChild(node); for (var i = 0; i < numLines; i++) { var tspanNode = SvgElement.create('tspan', { x: '0', dy: i === 0 ? '0' : leading + 'px' }); tspanNode.textContent = this._lines[i]; node.appendChild(tspanNode); } var element = document.createElement('span'); element.style.visibility = ('hidden'); element.style.whiteSpace = 'pre'; element.style.fontSize = this.fontSize + 'px'; element.style.fontFamily = this.font; element.style.lineHeight = this.leading / this.fontSize; var bbox; try { element.appendChild(svg); document.body.appendChild(element); bbox = svg.getBBox(); } finally { document.body.removeChild(element); } var halfStrokeWidth = this.strokeWidth / 2; var width = bbox.width + (halfStrokeWidth * 2); var height = bbox.height + (halfStrokeWidth * 2); var x = bbox.x - halfStrokeWidth; var y = bbox.y - halfStrokeWidth; if (justification !== 'left') { var eltWidth = this.getView().getTextWidth(style.getFontStyle(), lines); x -= eltWidth / (justification === 'center' ? 2: 1); } return new Rectangle(x, y, width + 1, Math.max(height, numLines * leading)); }, _hitTestSelf: function(point, options) { if (options.fill && (this.hasFill() || options.hitUnfilledPaths) && this._contains(point)) return new HitResult('fill', this); } }); var Color = Base.extend(new function() { var types = { gray: ['gray'], rgb: ['red', 'green', 'blue'], hsb: ['hue', 'saturation', 'brightness'], hsl: ['hue', 'saturation', 'lightness'], gradient: ['gradient', 'origin', 'destination', 'highlight'] }; var componentParsers = {}, namedColors = { transparent: [0, 0, 0, 0] }, colorCtx; function fromCSS(string) { var match = string.match( /^#([\da-f]{2})([\da-f]{2})([\da-f]{2})([\da-f]{2})?$/i ) || string.match( /^#([\da-f])([\da-f])([\da-f])([\da-f])?$/i ), type = 'rgb', components; if (match) { var amount = match[4] ? 4 : 3; components = new Array(amount); for (var i = 0; i < amount; i++) { var value = match[i + 1]; components[i] = parseInt(value.length == 1 ? value + value : value, 16) / 255; } } else if (match = string.match(/^(rgb|hsl)a?\((.*)\)$/)) { type = match[1]; components = match[2].trim().split(/[,\s]+/g); var isHSL = type === 'hsl'; for (var i = 0, l = Math.min(components.length, 4); i < l; i++) { var component = components[i]; var value = parseFloat(component); if (isHSL) { if (i === 0) { var unit = component.match(/([a-z]*)$/)[1]; value *= ({ turn: 360, rad: 180 / Math.PI, grad: 0.9 }[unit] || 1); } else if (i < 3) { value /= 100; } } else if (i < 3) { value /= /%$/.test(component) ? 100 : 255; } components[i] = value; } } else { var color = namedColors[string]; if (!color) { if (window) { if (!colorCtx) { colorCtx = CanvasProvider.getContext(1, 1); colorCtx.globalCompositeOperation = 'copy'; } colorCtx.fillStyle = 'rgba(0,0,0,0)'; colorCtx.fillStyle = string; colorCtx.fillRect(0, 0, 1, 1); var data = colorCtx.getImageData(0, 0, 1, 1).data; color = namedColors[string] = [ data[0] / 255, data[1] / 255, data[2] / 255 ]; } else { color = [0, 0, 0]; } } components = color.slice(); } return [type, components]; } var hsbIndices = [ [0, 3, 1], [2, 0, 1], [1, 0, 3], [1, 2, 0], [3, 1, 0], [0, 1, 2] ]; var converters = { 'rgb-hsb': function(r, g, b) { var max = Math.max(r, g, b), min = Math.min(r, g, b), delta = max - min, h = delta === 0 ? 0 : ( max == r ? (g - b) / delta + (g < b ? 6 : 0) : max == g ? (b - r) / delta + 2 : (r - g) / delta + 4) * 60; return [h, max === 0 ? 0 : delta / max, max]; }, 'hsb-rgb': function(h, s, b) { h = (((h / 60) % 6) + 6) % 6; var i = Math.floor(h), f = h - i, i = hsbIndices[i], v = [ b, b * (1 - s), b * (1 - s * f), b * (1 - s * (1 - f)) ]; return [v[i[0]], v[i[1]], v[i[2]]]; }, 'rgb-hsl': function(r, g, b) { var max = Math.max(r, g, b), min = Math.min(r, g, b), delta = max - min, achromatic = delta === 0, h = achromatic ? 0 : ( max == r ? (g - b) / delta + (g < b ? 6 : 0) : max == g ? (b - r) / delta + 2 : (r - g) / delta + 4) * 60, l = (max + min) / 2, s = achromatic ? 0 : l < 0.5 ? delta / (max + min) : delta / (2 - max - min); return [h, s, l]; }, 'hsl-rgb': function(h, s, l) { h = (((h / 360) % 1) + 1) % 1; if (s === 0) return [l, l, l]; var t3s = [ h + 1 / 3, h, h - 1 / 3 ], t2 = l < 0.5 ? l * (1 + s) : l + s - l * s, t1 = 2 * l - t2, c = []; for (var i = 0; i < 3; i++) { var t3 = t3s[i]; if (t3 < 0) t3 += 1; if (t3 > 1) t3 -= 1; c[i] = 6 * t3 < 1 ? t1 + (t2 - t1) * 6 * t3 : 2 * t3 < 1 ? t2 : 3 * t3 < 2 ? t1 + (t2 - t1) * ((2 / 3) - t3) * 6 : t1; } return c; }, 'rgb-gray': function(r, g, b) { return [r * 0.2989 + g * 0.587 + b * 0.114]; }, 'gray-rgb': function(g) { return [g, g, g]; }, 'gray-hsb': function(g) { return [0, 0, g]; }, 'gray-hsl': function(g) { return [0, 0, g]; }, 'gradient-rgb': function() { return []; }, 'rgb-gradient': function() { return []; } }; return Base.each(types, function(properties, type) { componentParsers[type] = []; Base.each(properties, function(name, index) { var part = Base.capitalize(name), hasOverlap = /^(hue|saturation)$/.test(name), parser = componentParsers[type][index] = type === 'gradient' ? name === 'gradient' ? function(value) { var current = this._components[0]; value = Gradient.read( Array.isArray(value) ? value : arguments, 0, { readNull: true } ); if (current !== value) { if (current) current._removeOwner(this); if (value) value._addOwner(this); } return value; } : function() { return Point.read(arguments, 0, { readNull: name === 'highlight', clone: true }); } : function(value) { return value == null || isNaN(value) ? 0 : +value; }; this['get' + part] = function() { return this._type === type || hasOverlap && /^hs[bl]$/.test(this._type) ? this._components[index] : this._convert(type)[index]; }; this['set' + part] = function(value) { if (this._type !== type && !(hasOverlap && /^hs[bl]$/.test(this._type))) { this._components = this._convert(type); this._properties = types[type]; this._type = type; } this._components[index] = parser.call(this, value); this._changed(); }; }, this); }, { _class: 'Color', _readIndex: true, initialize: function Color(arg) { var args = arguments, reading = this.__read, read = 0, type, components, alpha, values; if (Array.isArray(arg)) { args = arg; arg = args[0]; } var argType = arg != null && typeof arg; if (argType === 'string' && arg in types) { type = arg; arg = args[1]; if (Array.isArray(arg)) { components = arg; alpha = args[2]; } else { if (reading) read = 1; args = Base.slice(args, 1); argType = typeof arg; } } if (!components) { values = argType === 'number' ? args : argType === 'object' && arg.length != null ? arg : null; if (values) { if (!type) type = values.length >= 3 ? 'rgb' : 'gray'; var length = types[type].length; alpha = values[length]; if (reading) { read += values === arguments ? length + (alpha != null ? 1 : 0) : 1; } if (values.length > length) values = Base.slice(values, 0, length); } else if (argType === 'string') { var converted = fromCSS(arg); type = converted[0]; components = converted[1]; if (components.length === 4) { alpha = components[3]; components.length--; } } else if (argType === 'object') { if (arg.constructor === Color) { type = arg._type; components = arg._components.slice(); alpha = arg._alpha; if (type === 'gradient') { for (var i = 1, l = components.length; i < l; i++) { var point = components[i]; if (point) components[i] = point.clone(); } } } else if (arg.constructor === Gradient) { type = 'gradient'; values = args; } else { type = 'hue' in arg ? 'lightness' in arg ? 'hsl' : 'hsb' : 'gradient' in arg || 'stops' in arg || 'radial' in arg ? 'gradient' : 'gray' in arg ? 'gray' : 'rgb'; var properties = types[type], parsers = componentParsers[type]; this._components = components = []; for (var i = 0, l = properties.length; i < l; i++) { var value = arg[properties[i]]; if (value == null && !i && type === 'gradient' && 'stops' in arg) { value = { stops: arg.stops, radial: arg.radial }; } value = parsers[i].call(this, value); if (value != null) components[i] = value; } alpha = arg.alpha; } } if (reading && type) read = 1; } this._type = type || 'rgb'; if (!components) { this._components = components = []; var parsers = componentParsers[this._type]; for (var i = 0, l = parsers.length; i < l; i++) { var value = parsers[i].call(this, values && values[i]); if (value != null) components[i] = value; } } this._components = components; this._properties = types[this._type]; this._alpha = alpha; if (reading) this.__read = read; return this; }, set: '#initialize', _serialize: function(options, dictionary) { var components = this.getComponents(); return Base.serialize( /^(gray|rgb)$/.test(this._type) ? components : [this._type].concat(components), options, true, dictionary); }, _changed: function() { this._canvasStyle = null; if (this._owner) { if (this._setter) { this._owner[this._setter](this); } else { this._owner._changed(129); } } }, _convert: function(type) { var converter; return this._type === type ? this._components.slice() : (converter = converters[this._type + '-' + type]) ? converter.apply(this, this._components) : converters['rgb-' + type].apply(this, converters[this._type + '-rgb'].apply(this, this._components)); }, convert: function(type) { return new Color(type, this._convert(type), this._alpha); }, getType: function() { return this._type; }, setType: function(type) { this._components = this._convert(type); this._properties = types[type]; this._type = type; }, getComponents: function() { var components = this._components.slice(); if (this._alpha != null) components.push(this._alpha); return components; }, getAlpha: function() { return this._alpha != null ? this._alpha : 1; }, setAlpha: function(alpha) { this._alpha = alpha == null ? null : Math.min(Math.max(alpha, 0), 1); this._changed(); }, hasAlpha: function() { return this._alpha != null; }, equals: function(color) { var col = Base.isPlainValue(color, true) ? Color.read(arguments) : color; return col === this || col && this._class === col._class && this._type === col._type && this.getAlpha() === col.getAlpha() && Base.equals(this._components, col._components) || false; }, toString: function() { var properties = this._properties, parts = [], isGradient = this._type === 'gradient', f = Formatter.instance; for (var i = 0, l = properties.length; i < l; i++) { var value = this._components[i]; if (value != null) parts.push(properties[i] + ': ' + (isGradient ? value : f.number(value))); } if (this._alpha != null) parts.push('alpha: ' + f.number(this._alpha)); return '{ ' + parts.join(', ') + ' }'; }, toCSS: function(hex) { var components = this._convert('rgb'), alpha = hex || this._alpha == null ? 1 : this._alpha; function convert(val) { return Math.round((val < 0 ? 0 : val > 1 ? 1 : val) * 255); } components = [ convert(components[0]), convert(components[1]), convert(components[2]) ]; if (alpha < 1) components.push(alpha < 0 ? 0 : alpha); return hex ? '#' + ((1 << 24) + (components[0] << 16) + (components[1] << 8) + components[2]).toString(16).slice(1) : (components.length == 4 ? 'rgba(' : 'rgb(') + components.join(',') + ')'; }, toCanvasStyle: function(ctx, matrix, strokeMatrix) { var strokeMayChange = this._type === 'gradient' && strokeMatrix; if (this._canvasStyle && !strokeMayChange) return this._canvasStyle; if (this._type !== 'gradient') return this._canvasStyle = this.toCSS(); var components = this._components, gradient = components[0], stops = gradient._stops, origin = components[1], destination = components[2], highlight = components[3], inverse = matrix && matrix.inverted(), canvasGradient; if (inverse) { origin = inverse._transformPoint(origin); destination = inverse._transformPoint(destination); if (highlight) highlight = inverse._transformPoint(highlight); } if (strokeMatrix) { origin = strokeMatrix._transformPoint(origin); destination = strokeMatrix._transformPoint(destination); if (highlight) highlight = strokeMatrix._transformPoint(highlight); } if (gradient._radial) { var radius = destination.getDistance(origin); if (highlight) { var vector = highlight.subtract(origin); if (vector.getLength() > radius) highlight = origin.add(vector.normalize(radius - 0.1)); } var start = highlight || origin; canvasGradient = ctx.createRadialGradient(start.x, start.y, 0, origin.x, origin.y, radius); } else { canvasGradient = ctx.createLinearGradient(origin.x, origin.y, destination.x, destination.y); } for (var i = 0, l = stops.length; i < l; i++) { var stop = stops[i], offset = stop._offset; canvasGradient.addColorStop( offset == null ? i / (l - 1) : offset, stop._color.toCanvasStyle()); } if (!strokeMayChange) this._canvasStyle = canvasGradient; return canvasGradient; }, transform: function(matrix) { if (this._type === 'gradient') { var components = this._components; for (var i = 1, l = components.length; i < l; i++) { var point = components[i]; matrix._transformPoint(point, point, true); } this._changed(); } }, statics: { _types: types, random: function() { var random = Math.random; return new Color(random(), random(), random()); }, _setOwner: function(color, owner, setter) { if (color) { if (color._owner && owner && color._owner !== owner) { color = color.clone(); } if (!color._owner ^ !owner) { color._owner = owner || null; color._setter = setter || null; } } return color; } } }); }, new function() { var operators = { add: function(a, b) { return a + b; }, subtract: function(a, b) { return a - b; }, multiply: function(a, b) { return a * b; }, divide: function(a, b) { return a / b; } }; return Base.each(operators, function(operator, name) { this[name] = function(color) { color = Color.read(arguments); var type = this._type, components1 = this._components, components2 = color._convert(type); for (var i = 0, l = components1.length; i < l; i++) components2[i] = operator(components1[i], components2[i]); return new Color(type, components2, this._alpha != null ? operator(this._alpha, color.getAlpha()) : null); }; }, { }); }); var Gradient = Base.extend({ _class: 'Gradient', initialize: function Gradient(stops, radial) { this._id = UID.get(); if (stops && Base.isPlainObject(stops)) { this.set(stops); stops = radial = null; } if (this._stops == null) { this.setStops(stops || ['white', 'black']); } if (this._radial == null) { this.setRadial(typeof radial === 'string' && radial === 'radial' || radial || false); } }, _serialize: function(options, dictionary) { return dictionary.add(this, function() { return Base.serialize([this._stops, this._radial], options, true, dictionary); }); }, _changed: function() { for (var i = 0, l = this._owners && this._owners.length; i < l; i++) { this._owners[i]._changed(); } }, _addOwner: function(color) { if (!this._owners) this._owners = []; this._owners.push(color); }, _removeOwner: function(color) { var index = this._owners ? this._owners.indexOf(color) : -1; if (index != -1) { this._owners.splice(index, 1); if (!this._owners.length) this._owners = undefined; } }, clone: function() { var stops = []; for (var i = 0, l = this._stops.length; i < l; i++) { stops[i] = this._stops[i].clone(); } return new Gradient(stops, this._radial); }, getStops: function() { return this._stops; }, setStops: function(stops) { if (stops.length < 2) { throw new Error( 'Gradient stop list needs to contain at least two stops.'); } var _stops = this._stops; if (_stops) { for (var i = 0, l = _stops.length; i < l; i++) _stops[i]._owner = undefined; } _stops = this._stops = GradientStop.readList(stops, 0, { clone: true }); for (var i = 0, l = _stops.length; i < l; i++) _stops[i]._owner = this; this._changed(); }, getRadial: function() { return this._radial; }, setRadial: function(radial) { this._radial = radial; this._changed(); }, equals: function(gradient) { if (gradient === this) return true; if (gradient && this._class === gradient._class) { var stops1 = this._stops, stops2 = gradient._stops, length = stops1.length; if (length === stops2.length) { for (var i = 0; i < length; i++) { if (!stops1[i].equals(stops2[i])) return false; } return true; } } return false; } }); var GradientStop = Base.extend({ _class: 'GradientStop', initialize: function GradientStop(arg0, arg1) { var color = arg0, offset = arg1; if (typeof arg0 === 'object' && arg1 === undefined) { if (Array.isArray(arg0) && typeof arg0[0] !== 'number') { color = arg0[0]; offset = arg0[1]; } else if ('color' in arg0 || 'offset' in arg0 || 'rampPoint' in arg0) { color = arg0.color; offset = arg0.offset || arg0.rampPoint || 0; } } this.setColor(color); this.setOffset(offset); }, clone: function() { return new GradientStop(this._color.clone(), this._offset); }, _serialize: function(options, dictionary) { var color = this._color, offset = this._offset; return Base.serialize(offset == null ? [color] : [color, offset], options, true, dictionary); }, _changed: function() { if (this._owner) this._owner._changed(129); }, getOffset: function() { return this._offset; }, setOffset: function(offset) { this._offset = offset; this._changed(); }, getRampPoint: '#getOffset', setRampPoint: '#setOffset', getColor: function() { return this._color; }, setColor: function() { Color._setOwner(this._color, null); this._color = Color._setOwner(Color.read(arguments, 0), this, 'setColor'); this._changed(); }, equals: function(stop) { return stop === this || stop && this._class === stop._class && this._color.equals(stop._color) && this._offset == stop._offset || false; } }); var Style = Base.extend(new function() { var itemDefaults = { fillColor: null, fillRule: 'nonzero', strokeColor: null, strokeWidth: 1, strokeCap: 'butt', strokeJoin: 'miter', strokeScaling: true, miterLimit: 10, dashOffset: 0, dashArray: [], shadowColor: null, shadowBlur: 0, shadowOffset: new Point(), selectedColor: null }, groupDefaults = Base.set({}, itemDefaults, { fontFamily: 'sans-serif', fontWeight: 'normal', fontSize: 12, leading: null, justification: 'left' }), textDefaults = Base.set({}, groupDefaults, { fillColor: new Color() }), flags = { strokeWidth: 193, strokeCap: 193, strokeJoin: 193, strokeScaling: 201, miterLimit: 193, fontFamily: 9, fontWeight: 9, fontSize: 9, font: 9, leading: 9, justification: 9 }, item = { beans: true }, fields = { _class: 'Style', beans: true, initialize: function Style(style, _owner, _project) { this._values = {}; this._owner = _owner; this._project = _owner && _owner._project || _project || paper.project; this._defaults = !_owner || _owner instanceof Group ? groupDefaults : _owner instanceof TextItem ? textDefaults : itemDefaults; if (style) this.set(style); } }; Base.each(groupDefaults, function(value, key) { var isColor = /Color$/.test(key), isPoint = key === 'shadowOffset', part = Base.capitalize(key), flag = flags[key], set = 'set' + part, get = 'get' + part; fields[set] = function(value) { var owner = this._owner, children = owner && owner._children, applyToChildren = children && children.length > 0 && !(owner instanceof CompoundPath); if (applyToChildren) { for (var i = 0, l = children.length; i < l; i++) children[i]._style[set](value); } if ((key === 'selectedColor' || !applyToChildren) && key in this._defaults) { var old = this._values[key]; if (old !== value) { if (isColor) { if (old) { Color._setOwner(old, null); old._canvasStyle = null; } if (value && value.constructor === Color) { value = Color._setOwner(value, owner, applyToChildren && set); } } this._values[key] = value; if (owner) owner._changed(flag || 129); } } }; fields[get] = function(_dontMerge) { var owner = this._owner, children = owner && owner._children, applyToChildren = children && children.length > 0 && !(owner instanceof CompoundPath), value; if (applyToChildren && !_dontMerge) { for (var i = 0, l = children.length; i < l; i++) { var childValue = children[i]._style[get](); if (!i) { value = childValue; } else if (!Base.equals(value, childValue)) { return undefined; } } } else if (key in this._defaults) { var value = this._values[key]; if (value === undefined) { value = this._defaults[key]; if (value && value.clone) { value = value.clone(); } } else { var ctor = isColor ? Color : isPoint ? Point : null; if (ctor && !(value && value.constructor === ctor)) { this._values[key] = value = ctor.read([value], 0, { readNull: true, clone: true }); } } } if (value && isColor) { value = Color._setOwner(value, owner, applyToChildren && set); } return value; }; item[get] = function(_dontMerge) { return this._style[get](_dontMerge); }; item[set] = function(value) { this._style[set](value); }; }); Base.each({ Font: 'FontFamily', WindingRule: 'FillRule' }, function(value, key) { var get = 'get' + key, set = 'set' + key; fields[get] = item[get] = '#get' + value; fields[set] = item[set] = '#set' + value; }); Item.inject(item); return fields; }, { set: function(style) { var isStyle = style instanceof Style, values = isStyle ? style._values : style; if (values) { for (var key in values) { if (key in this._defaults) { var value = values[key]; this[key] = value && isStyle && value.clone ? value.clone() : value; } } } }, equals: function(style) { function compare(style1, style2, secondary) { var values1 = style1._values, values2 = style2._values, defaults2 = style2._defaults; for (var key in values1) { var value1 = values1[key], value2 = values2[key]; if (!(secondary && key in values2) && !Base.equals(value1, value2 === undefined ? defaults2[key] : value2)) return false; } return true; } return style === this || style && this._class === style._class && compare(this, style) && compare(style, this, true) || false; }, _dispose: function() { var color; color = this.getFillColor(); if (color) color._canvasStyle = null; color = this.getStrokeColor(); if (color) color._canvasStyle = null; color = this.getShadowColor(); if (color) color._canvasStyle = null; }, hasFill: function() { var color = this.getFillColor(); return !!color && color.alpha > 0; }, hasStroke: function() { var color = this.getStrokeColor(); return !!color && color.alpha > 0 && this.getStrokeWidth() > 0; }, hasShadow: function() { var color = this.getShadowColor(); return !!color && color.alpha > 0 && (this.getShadowBlur() > 0 || !this.getShadowOffset().isZero()); }, getView: function() { return this._project._view; }, getFontStyle: function() { var fontSize = this.getFontSize(); return this.getFontWeight() + ' ' + fontSize + (/[a-z]/i.test(fontSize + '') ? ' ' : 'px ') + this.getFontFamily(); }, getFont: '#getFontFamily', setFont: '#setFontFamily', getLeading: function getLeading() { var leading = getLeading.base.call(this), fontSize = this.getFontSize(); if (/pt|em|%|px/.test(fontSize)) fontSize = this.getView().getPixelSize(fontSize); return leading != null ? leading : fontSize * 1.2; } }); var DomElement = new function() { function handlePrefix(el, name, set, value) { var prefixes = ['', 'webkit', 'moz', 'Moz', 'ms', 'o'], suffix = name[0].toUpperCase() + name.substring(1); for (var i = 0; i < 6; i++) { var prefix = prefixes[i], key = prefix ? prefix + suffix : name; if (key in el) { if (set) { el[key] = value; } else { return el[key]; } break; } } } return { getStyles: function(el) { var doc = el && el.nodeType !== 9 ? el.ownerDocument : el, view = doc && doc.defaultView; return view && view.getComputedStyle(el, ''); }, getBounds: function(el, viewport) { var doc = el.ownerDocument, body = doc.body, html = doc.documentElement, rect; try { rect = el.getBoundingClientRect(); } catch (e) { rect = { left: 0, top: 0, width: 0, height: 0 }; } var x = rect.left - (html.clientLeft || body.clientLeft || 0), y = rect.top - (html.clientTop || body.clientTop || 0); if (!viewport) { var view = doc.defaultView; x += view.pageXOffset || html.scrollLeft || body.scrollLeft; y += view.pageYOffset || html.scrollTop || body.scrollTop; } return new Rectangle(x, y, rect.width, rect.height); }, getViewportBounds: function(el) { var doc = el.ownerDocument, view = doc.defaultView, html = doc.documentElement; return new Rectangle(0, 0, view.innerWidth || html.clientWidth, view.innerHeight || html.clientHeight ); }, getOffset: function(el, viewport) { return DomElement.getBounds(el, viewport).getPoint(); }, getSize: function(el) { return DomElement.getBounds(el, true).getSize(); }, isInvisible: function(el) { return DomElement.getSize(el).equals(new Size(0, 0)); }, isInView: function(el) { return !DomElement.isInvisible(el) && DomElement.getViewportBounds(el).intersects( DomElement.getBounds(el, true)); }, isInserted: function(el) { return document.body.contains(el); }, getPrefixed: function(el, name) { return el && handlePrefix(el, name); }, setPrefixed: function(el, name, value) { if (typeof name === 'object') { for (var key in name) handlePrefix(el, key, true, name[key]); } else { handlePrefix(el, name, true, value); } } }; }; var DomEvent = { add: function(el, events) { if (el) { for (var type in events) { var func = events[type], parts = type.split(/[\s,]+/g); for (var i = 0, l = parts.length; i < l; i++) { var name = parts[i]; var options = ( el === document && (name === 'touchstart' || name === 'touchmove') ) ? { passive: false } : false; el.addEventListener(name, func, options); } } } }, remove: function(el, events) { if (el) { for (var type in events) { var func = events[type], parts = type.split(/[\s,]+/g); for (var i = 0, l = parts.length; i < l; i++) el.removeEventListener(parts[i], func, false); } } }, getPoint: function(event) { var pos = event.targetTouches ? event.targetTouches.length ? event.targetTouches[0] : event.changedTouches[0] : event; return new Point( pos.pageX || pos.clientX + document.documentElement.scrollLeft, pos.pageY || pos.clientY + document.documentElement.scrollTop ); }, getTarget: function(event) { return event.target || event.srcElement; }, getRelatedTarget: function(event) { return event.relatedTarget || event.toElement; }, getOffset: function(event, target) { return DomEvent.getPoint(event).subtract(DomElement.getOffset( target || DomEvent.getTarget(event))); } }; DomEvent.requestAnimationFrame = new function() { var nativeRequest = DomElement.getPrefixed(window, 'requestAnimationFrame'), requested = false, callbacks = [], timer; function handleCallbacks() { var functions = callbacks; callbacks = []; for (var i = 0, l = functions.length; i < l; i++) functions[i](); requested = nativeRequest && callbacks.length; if (requested) nativeRequest(handleCallbacks); } return function(callback) { callbacks.push(callback); if (nativeRequest) { if (!requested) { nativeRequest(handleCallbacks); requested = true; } } else if (!timer) { timer = setInterval(handleCallbacks, 1000 / 60); } }; }; var View = Base.extend(Emitter, { _class: 'View', initialize: function View(project, element) { function getSize(name) { return element[name] || parseInt(element.getAttribute(name), 10); } function getCanvasSize() { var size = DomElement.getSize(element); return size.isNaN() || size.isZero() ? new Size(getSize('width'), getSize('height')) : size; } var size; if (window && element) { this._id = element.getAttribute('id'); if (this._id == null) element.setAttribute('id', this._id = 'paper-view-' + View._id++); DomEvent.add(element, this._viewEvents); var none = 'none'; DomElement.setPrefixed(element.style, { userDrag: none, userSelect: none, touchCallout: none, contentZooming: none, tapHighlightColor: 'rgba(0,0,0,0)' }); if (PaperScope.hasAttribute(element, 'resize')) { var that = this; DomEvent.add(window, this._windowEvents = { resize: function() { that.setViewSize(getCanvasSize()); } }); } size = getCanvasSize(); if (PaperScope.hasAttribute(element, 'stats') && typeof Stats !== 'undefined') { this._stats = new Stats(); var stats = this._stats.domElement, style = stats.style, offset = DomElement.getOffset(element); style.position = 'absolute'; style.left = offset.x + 'px'; style.top = offset.y + 'px'; document.body.appendChild(stats); } } else { size = new Size(element); element = null; } this._project = project; this._scope = project._scope; this._element = element; if (!this._pixelRatio) this._pixelRatio = window && window.devicePixelRatio || 1; this._setElementSize(size.width, size.height); this._viewSize = size; View._views.push(this); View._viewsById[this._id] = this; (this._matrix = new Matrix())._owner = this; if (!View._focused) View._focused = this; this._frameItems = {}; this._frameItemCount = 0; this._itemEvents = { native: {}, virtual: {} }; this._autoUpdate = !paper.agent.node; this._needsUpdate = false; }, remove: function() { if (!this._project) return false; if (View._focused === this) View._focused = null; View._views.splice(View._views.indexOf(this), 1); delete View._viewsById[this._id]; var project = this._project; if (project._view === this) project._view = null; DomEvent.remove(this._element, this._viewEvents); DomEvent.remove(window, this._windowEvents); this._element = this._project = null; this.off('frame'); this._animate = false; this._frameItems = {}; return true; }, _events: Base.each( Item._itemHandlers.concat(['onResize', 'onKeyDown', 'onKeyUp']), function(name) { this[name] = {}; }, { onFrame: { install: function() { this.play(); }, uninstall: function() { this.pause(); } } } ), _animate: false, _time: 0, _count: 0, getAutoUpdate: function() { return this._autoUpdate; }, setAutoUpdate: function(autoUpdate) { this._autoUpdate = autoUpdate; if (autoUpdate) this.requestUpdate(); }, update: function() { }, draw: function() { this.update(); }, requestUpdate: function() { if (!this._requested) { var that = this; DomEvent.requestAnimationFrame(function() { that._requested = false; if (that._animate) { that.requestUpdate(); var element = that._element; if ((!DomElement.getPrefixed(document, 'hidden') || PaperScope.getAttribute(element, 'keepalive') === 'true') && DomElement.isInView(element)) { that._handleFrame(); } } if (that._autoUpdate) that.update(); }); this._requested = true; } }, play: function() { this._animate = true; this.requestUpdate(); }, pause: function() { this._animate = false; }, _handleFrame: function() { paper = this._scope; var now = Date.now() / 1000, delta = this._last ? now - this._last : 0; this._last = now; this.emit('frame', new Base({ delta: delta, time: this._time += delta, count: this._count++ })); if (this._stats) this._stats.update(); }, _animateItem: function(item, animate) { var items = this._frameItems; if (animate) { items[item._id] = { item: item, time: 0, count: 0 }; if (++this._frameItemCount === 1) this.on('frame', this._handleFrameItems); } else { delete items[item._id]; if (--this._frameItemCount === 0) { this.off('frame', this._handleFrameItems); } } }, _handleFrameItems: function(event) { for (var i in this._frameItems) { var entry = this._frameItems[i]; entry.item.emit('frame', new Base(event, { time: entry.time += event.delta, count: entry.count++ })); } }, _changed: function() { this._project._changed(4097); this._bounds = this._decomposed = undefined; }, getElement: function() { return this._element; }, getPixelRatio: function() { return this._pixelRatio; }, getResolution: function() { return this._pixelRatio * 72; }, getViewSize: function() { var size = this._viewSize; return new LinkedSize(size.width, size.height, this, 'setViewSize'); }, setViewSize: function() { var size = Size.read(arguments), delta = size.subtract(this._viewSize); if (delta.isZero()) return; this._setElementSize(size.width, size.height); this._viewSize.set(size); this._changed(); this.emit('resize', { size: size, delta: delta }); if (this._autoUpdate) { this.update(); } }, _setElementSize: function(width, height) { var element = this._element; if (element) { if (element.width !== width) element.width = width; if (element.height !== height) element.height = height; } }, getBounds: function() { if (!this._bounds) this._bounds = this._matrix.inverted()._transformBounds( new Rectangle(new Point(), this._viewSize)); return this._bounds; }, getSize: function() { return this.getBounds().getSize(); }, isVisible: function() { return DomElement.isInView(this._element); }, isInserted: function() { return DomElement.isInserted(this._element); }, getPixelSize: function(size) { var element = this._element, pixels; if (element) { var parent = element.parentNode, temp = document.createElement('div'); temp.style.fontSize = size; parent.appendChild(temp); pixels = parseFloat(DomElement.getStyles(temp).fontSize); parent.removeChild(temp); } else { pixels = parseFloat(pixels); } return pixels; }, getTextWidth: function(font, lines) { return 0; } }, Base.each(['rotate', 'scale', 'shear', 'skew'], function(key) { var rotate = key === 'rotate'; this[key] = function() { var args = arguments, value = (rotate ? Base : Point).read(args), center = Point.read(args, 0, { readNull: true }); return this.transform(new Matrix()[key](value, center || this.getCenter(true))); }; }, { _decompose: function() { return this._decomposed || (this._decomposed = this._matrix.decompose()); }, translate: function() { var mx = new Matrix(); return this.transform(mx.translate.apply(mx, arguments)); }, getCenter: function() { return this.getBounds().getCenter(); }, setCenter: function() { var center = Point.read(arguments); this.translate(this.getCenter().subtract(center)); }, getZoom: function() { var scaling = this._decompose().scaling; return (scaling.x + scaling.y) / 2; }, setZoom: function(zoom) { this.transform(new Matrix().scale(zoom / this.getZoom(), this.getCenter())); }, getRotation: function() { return this._decompose().rotation; }, setRotation: function(rotation) { var current = this.getRotation(); if (current != null && rotation != null) { this.rotate(rotation - current); } }, getScaling: function() { var scaling = this._decompose().scaling; return new LinkedPoint(scaling.x, scaling.y, this, 'setScaling'); }, setScaling: function() { var current = this.getScaling(), scaling = Point.read(arguments, 0, { clone: true, readNull: true }); if (current && scaling) { this.scale(scaling.x / current.x, scaling.y / current.y); } }, getMatrix: function() { return this._matrix; }, setMatrix: function() { var matrix = this._matrix; matrix.initialize.apply(matrix, arguments); }, transform: function(matrix) { this._matrix.append(matrix); }, scrollBy: function() { this.translate(Point.read(arguments).negate()); } }), { projectToView: function() { return this._matrix._transformPoint(Point.read(arguments)); }, viewToProject: function() { return this._matrix._inverseTransform(Point.read(arguments)); }, getEventPoint: function(event) { return this.viewToProject(DomEvent.getOffset(event, this._element)); }, }, { statics: { _views: [], _viewsById: {}, _id: 0, create: function(project, element) { if (document && typeof element === 'string') element = document.getElementById(element); var ctor = window ? CanvasView : View; return new ctor(project, element); } } }, new function() { if (!window) return; var prevFocus, tempFocus, dragging = false, mouseDown = false; function getView(event) { var target = DomEvent.getTarget(event); return target.getAttribute && View._viewsById[ target.getAttribute('id')]; } function updateFocus() { var view = View._focused; if (!view || !view.isVisible()) { for (var i = 0, l = View._views.length; i < l; i++) { if ((view = View._views[i]).isVisible()) { View._focused = tempFocus = view; break; } } } } function handleMouseMove(view, event, point) { view._handleMouseEvent('mousemove', event, point); } var navigator = window.navigator, mousedown, mousemove, mouseup; if (navigator.pointerEnabled || navigator.msPointerEnabled) { mousedown = 'pointerdown MSPointerDown'; mousemove = 'pointermove MSPointerMove'; mouseup = 'pointerup pointercancel MSPointerUp MSPointerCancel'; } else { mousedown = 'touchstart'; mousemove = 'touchmove'; mouseup = 'touchend touchcancel'; if (!('ontouchstart' in window && navigator.userAgent.match( /mobile|tablet|ip(ad|hone|od)|android|silk/i))) { mousedown += ' mousedown'; mousemove += ' mousemove'; mouseup += ' mouseup'; } } var viewEvents = {}, docEvents = { mouseout: function(event) { var view = View._focused, target = DomEvent.getRelatedTarget(event); if (view && (!target || target.nodeName === 'HTML')) { var offset = DomEvent.getOffset(event, view._element), x = offset.x, abs = Math.abs, ax = abs(x), max = 1 << 25, diff = ax - max; offset.x = abs(diff) < ax ? diff * (x < 0 ? -1 : 1) : x; handleMouseMove(view, event, view.viewToProject(offset)); } }, scroll: updateFocus }; viewEvents[mousedown] = function(event) { var view = View._focused = getView(event); if (!dragging) { dragging = true; view._handleMouseEvent('mousedown', event); } }; docEvents[mousemove] = function(event) { var view = View._focused; if (!mouseDown) { var target = getView(event); if (target) { if (view !== target) { if (view) handleMouseMove(view, event); if (!prevFocus) prevFocus = view; view = View._focused = tempFocus = target; } } else if (tempFocus && tempFocus === view) { if (prevFocus && !prevFocus.isInserted()) prevFocus = null; view = View._focused = prevFocus; prevFocus = null; updateFocus(); } } if (view) handleMouseMove(view, event); }; docEvents[mousedown] = function() { mouseDown = true; }; docEvents[mouseup] = function(event) { var view = View._focused; if (view && dragging) view._handleMouseEvent('mouseup', event); mouseDown = dragging = false; }; DomEvent.add(document, docEvents); DomEvent.add(window, { load: updateFocus }); var called = false, prevented = false, fallbacks = { doubleclick: 'click', mousedrag: 'mousemove' }, wasInView = false, overView, downPoint, lastPoint, downItem, overItem, dragItem, clickItem, clickTime, dblClick; function emitMouseEvent(obj, target, type, event, point, prevPoint, stopItem) { var stopped = false, mouseEvent; function emit(obj, type) { if (obj.responds(type)) { if (!mouseEvent) { mouseEvent = new MouseEvent(type, event, point, target || obj, prevPoint ? point.subtract(prevPoint) : null); } if (obj.emit(type, mouseEvent)) { called = true; if (mouseEvent.prevented) prevented = true; if (mouseEvent.stopped) return stopped = true; } } else { var fallback = fallbacks[type]; if (fallback) return emit(obj, fallback); } } while (obj && obj !== stopItem) { if (emit(obj, type)) break; obj = obj._parent; } return stopped; } function emitMouseEvents(view, hitItem, type, event, point, prevPoint) { view._project.removeOn(type); prevented = called = false; return (dragItem && emitMouseEvent(dragItem, null, type, event, point, prevPoint) || hitItem && hitItem !== dragItem && !hitItem.isDescendant(dragItem) && emitMouseEvent(hitItem, null, type === 'mousedrag' ? 'mousemove' : type, event, point, prevPoint, dragItem) || emitMouseEvent(view, dragItem || hitItem || view, type, event, point, prevPoint)); } var itemEventsMap = { mousedown: { mousedown: 1, mousedrag: 1, click: 1, doubleclick: 1 }, mouseup: { mouseup: 1, mousedrag: 1, click: 1, doubleclick: 1 }, mousemove: { mousedrag: 1, mousemove: 1, mouseenter: 1, mouseleave: 1 } }; return { _viewEvents: viewEvents, _handleMouseEvent: function(type, event, point) { var itemEvents = this._itemEvents, hitItems = itemEvents.native[type], nativeMove = type === 'mousemove', tool = this._scope.tool, view = this; function responds(type) { return itemEvents.virtual[type] || view.responds(type) || tool && tool.responds(type); } if (nativeMove && dragging && responds('mousedrag')) type = 'mousedrag'; if (!point) point = this.getEventPoint(event); var inView = this.getBounds().contains(point), hit = hitItems && inView && view._project.hitTest(point, { tolerance: 0, fill: true, stroke: true }), hitItem = hit && hit.item || null, handle = false, mouse = {}; mouse[type.substr(5)] = true; if (hitItems && hitItem !== overItem) { if (overItem) { emitMouseEvent(overItem, null, 'mouseleave', event, point); } if (hitItem) { emitMouseEvent(hitItem, null, 'mouseenter', event, point); } overItem = hitItem; } if (wasInView ^ inView) { emitMouseEvent(this, null, inView ? 'mouseenter' : 'mouseleave', event, point); overView = inView ? this : null; handle = true; } if ((inView || mouse.drag) && !point.equals(lastPoint)) { emitMouseEvents(this, hitItem, nativeMove ? type : 'mousemove', event, point, lastPoint); handle = true; } wasInView = inView; if (mouse.down && inView || mouse.up && downPoint) { emitMouseEvents(this, hitItem, type, event, point, downPoint); if (mouse.down) { dblClick = hitItem === clickItem && (Date.now() - clickTime < 300); downItem = clickItem = hitItem; if (!prevented && hitItem) { var item = hitItem; while (item && !item.responds('mousedrag')) item = item._parent; if (item) dragItem = hitItem; } downPoint = point; } else if (mouse.up) { if (!prevented && hitItem === downItem) { clickTime = Date.now(); emitMouseEvents(this, hitItem, dblClick ? 'doubleclick' : 'click', event, point, downPoint); dblClick = false; } downItem = dragItem = null; } wasInView = false; handle = true; } lastPoint = point; if (handle && tool) { called = tool._handleMouseEvent(type, event, point, mouse) || called; } if ( event.cancelable !== false && (called && !mouse.move || mouse.down && responds('mouseup')) ) { event.preventDefault(); } }, _handleKeyEvent: function(type, event, key, character) { var scope = this._scope, tool = scope.tool, keyEvent; function emit(obj) { if (obj.responds(type)) { paper = scope; obj.emit(type, keyEvent = keyEvent || new KeyEvent(type, event, key, character)); } } if (this.isVisible()) { emit(this); if (tool && tool.responds(type)) emit(tool); } }, _countItemEvent: function(type, sign) { var itemEvents = this._itemEvents, native = itemEvents.native, virtual = itemEvents.virtual; for (var key in itemEventsMap) { native[key] = (native[key] || 0) + (itemEventsMap[key][type] || 0) * sign; } virtual[type] = (virtual[type] || 0) + sign; }, statics: { updateFocus: updateFocus, _resetState: function() { dragging = mouseDown = called = wasInView = false; prevFocus = tempFocus = overView = downPoint = lastPoint = downItem = overItem = dragItem = clickItem = clickTime = dblClick = null; } } }; }); var CanvasView = View.extend({ _class: 'CanvasView', initialize: function CanvasView(project, canvas) { if (!(canvas instanceof window.HTMLCanvasElement)) { var size = Size.read(arguments, 1); if (size.isZero()) throw new Error( 'Cannot create CanvasView with the provided argument: ' + Base.slice(arguments, 1)); canvas = CanvasProvider.getCanvas(size); } var ctx = this._context = canvas.getContext('2d'); ctx.save(); this._pixelRatio = 1; if (!/^off|false$/.test(PaperScope.getAttribute(canvas, 'hidpi'))) { var deviceRatio = window.devicePixelRatio || 1, backingStoreRatio = DomElement.getPrefixed(ctx, 'backingStorePixelRatio') || 1; this._pixelRatio = deviceRatio / backingStoreRatio; } View.call(this, project, canvas); this._needsUpdate = true; }, remove: function remove() { this._context.restore(); return remove.base.call(this); }, _setElementSize: function _setElementSize(width, height) { var pixelRatio = this._pixelRatio; _setElementSize.base.call(this, width * pixelRatio, height * pixelRatio); if (pixelRatio !== 1) { var element = this._element, ctx = this._context; if (!PaperScope.hasAttribute(element, 'resize')) { var style = element.style; style.width = width + 'px'; style.height = height + 'px'; } ctx.restore(); ctx.save(); ctx.scale(pixelRatio, pixelRatio); } }, getContext: function() { return this._context; }, getPixelSize: function getPixelSize(size) { var agent = paper.agent, pixels; if (agent && agent.firefox) { pixels = getPixelSize.base.call(this, size); } else { var ctx = this._context, prevFont = ctx.font; ctx.font = size + ' serif'; pixels = parseFloat(ctx.font); ctx.font = prevFont; } return pixels; }, getTextWidth: function(font, lines) { var ctx = this._context, prevFont = ctx.font, width = 0; ctx.font = font; for (var i = 0, l = lines.length; i < l; i++) width = Math.max(width, ctx.measureText(lines[i]).width); ctx.font = prevFont; return width; }, update: function() { if (!this._needsUpdate) return false; var project = this._project, ctx = this._context, size = this._viewSize; ctx.clearRect(0, 0, size.width + 1, size.height + 1); if (project) project.draw(ctx, this._matrix, this._pixelRatio); this._needsUpdate = false; return true; } }); var Event = Base.extend({ _class: 'Event', initialize: function Event(event) { this.event = event; this.type = event && event.type; }, prevented: false, stopped: false, preventDefault: function() { this.prevented = true; this.event.preventDefault(); }, stopPropagation: function() { this.stopped = true; this.event.stopPropagation(); }, stop: function() { this.stopPropagation(); this.preventDefault(); }, getTimeStamp: function() { return this.event.timeStamp; }, getModifiers: function() { return Key.modifiers; } }); var KeyEvent = Event.extend({ _class: 'KeyEvent', initialize: function KeyEvent(type, event, key, character) { this.type = type; this.event = event; this.key = key; this.character = character; }, toString: function() { return "{ type: '" + this.type + "', key: '" + this.key + "', character: '" + this.character + "', modifiers: " + this.getModifiers() + " }"; } }); var Key = new function() { var keyLookup = { '\t': 'tab', ' ': 'space', '\b': 'backspace', '\x7f': 'delete', 'Spacebar': 'space', 'Del': 'delete', 'Win': 'meta', 'Esc': 'escape' }, charLookup = { 'tab': '\t', 'space': ' ', 'enter': '\r' }, keyMap = {}, charMap = {}, metaFixMap, downKey, modifiers = new Base({ shift: false, control: false, alt: false, meta: false, capsLock: false, space: false }).inject({ option: { get: function() { return this.alt; } }, command: { get: function() { var agent = paper && paper.agent; return agent && agent.mac ? this.meta : this.control; } } }); function getKey(event) { var key = event.key || event.keyIdentifier; key = /^U\+/.test(key) ? String.fromCharCode(parseInt(key.substr(2), 16)) : /^Arrow[A-Z]/.test(key) ? key.substr(5) : key === 'Unidentified' || key === undefined ? String.fromCharCode(event.keyCode) : key; return keyLookup[key] || (key.length > 1 ? Base.hyphenate(key) : key.toLowerCase()); } function handleKey(down, key, character, event) { var type = down ? 'keydown' : 'keyup', view = View._focused, name; keyMap[key] = down; if (down) { charMap[key] = character; } else { delete charMap[key]; } if (key.length > 1 && (name = Base.camelize(key)) in modifiers) { modifiers[name] = down; var agent = paper && paper.agent; if (name === 'meta' && agent && agent.mac) { if (down) { metaFixMap = {}; } else { for (var k in metaFixMap) { if (k in charMap) handleKey(false, k, metaFixMap[k], event); } metaFixMap = null; } } } else if (down && metaFixMap) { metaFixMap[key] = character; } if (view) { view._handleKeyEvent(down ? 'keydown' : 'keyup', event, key, character); } } DomEvent.add(document, { keydown: function(event) { var key = getKey(event), agent = paper && paper.agent; if (key.length > 1 || agent && (agent.chrome && (event.altKey || agent.mac && event.metaKey || !agent.mac && event.ctrlKey))) { handleKey(true, key, charLookup[key] || (key.length > 1 ? '' : key), event); } else { downKey = key; } }, keypress: function(event) { if (downKey) { var key = getKey(event), code = event.charCode, character = code >= 32 ? String.fromCharCode(code) : key.length > 1 ? '' : key; if (key !== downKey) { key = character.toLowerCase(); } handleKey(true, key, character, event); downKey = null; } }, keyup: function(event) { var key = getKey(event); if (key in charMap) handleKey(false, key, charMap[key], event); } }); DomEvent.add(window, { blur: function(event) { for (var key in charMap) handleKey(false, key, charMap[key], event); } }); return { modifiers: modifiers, isDown: function(key) { return !!keyMap[key]; } }; }; var MouseEvent = Event.extend({ _class: 'MouseEvent', initialize: function MouseEvent(type, event, point, target, delta) { this.type = type; this.event = event; this.point = point; this.target = target; this.delta = delta; }, toString: function() { return "{ type: '" + this.type + "', point: " + this.point + ', target: ' + this.target + (this.delta ? ', delta: ' + this.delta : '') + ', modifiers: ' + this.getModifiers() + ' }'; } }); var ToolEvent = Event.extend({ _class: 'ToolEvent', _item: null, initialize: function ToolEvent(tool, type, event) { this.tool = tool; this.type = type; this.event = event; }, _choosePoint: function(point, toolPoint) { return point ? point : toolPoint ? toolPoint.clone() : null; }, getPoint: function() { return this._choosePoint(this._point, this.tool._point); }, setPoint: function(point) { this._point = point; }, getLastPoint: function() { return this._choosePoint(this._lastPoint, this.tool._lastPoint); }, setLastPoint: function(lastPoint) { this._lastPoint = lastPoint; }, getDownPoint: function() { return this._choosePoint(this._downPoint, this.tool._downPoint); }, setDownPoint: function(downPoint) { this._downPoint = downPoint; }, getMiddlePoint: function() { if (!this._middlePoint && this.tool._lastPoint) { return this.tool._point.add(this.tool._lastPoint).divide(2); } return this._middlePoint; }, setMiddlePoint: function(middlePoint) { this._middlePoint = middlePoint; }, getDelta: function() { return !this._delta && this.tool._lastPoint ? this.tool._point.subtract(this.tool._lastPoint) : this._delta; }, setDelta: function(delta) { this._delta = delta; }, getCount: function() { return this.tool[/^mouse(down|up)$/.test(this.type) ? '_downCount' : '_moveCount']; }, setCount: function(count) { this.tool[/^mouse(down|up)$/.test(this.type) ? 'downCount' : 'count'] = count; }, getItem: function() { if (!this._item) { var result = this.tool._scope.project.hitTest(this.getPoint()); if (result) { var item = result.item, parent = item._parent; while (/^(Group|CompoundPath)$/.test(parent._class)) { item = parent; parent = parent._parent; } this._item = item; } } return this._item; }, setItem: function(item) { this._item = item; }, toString: function() { return '{ type: ' + this.type + ', point: ' + this.getPoint() + ', count: ' + this.getCount() + ', modifiers: ' + this.getModifiers() + ' }'; } }); var Tool = PaperScopeItem.extend({ _class: 'Tool', _list: 'tools', _reference: 'tool', _events: ['onMouseDown', 'onMouseUp', 'onMouseDrag', 'onMouseMove', 'onActivate', 'onDeactivate', 'onEditOptions', 'onKeyDown', 'onKeyUp'], initialize: function Tool(props) { PaperScopeItem.call(this); this._moveCount = -1; this._downCount = -1; this.set(props); }, getMinDistance: function() { return this._minDistance; }, setMinDistance: function(minDistance) { this._minDistance = minDistance; if (minDistance != null && this._maxDistance != null && minDistance > this._maxDistance) { this._maxDistance = minDistance; } }, getMaxDistance: function() { return this._maxDistance; }, setMaxDistance: function(maxDistance) { this._maxDistance = maxDistance; if (this._minDistance != null && maxDistance != null && maxDistance < this._minDistance) { this._minDistance = maxDistance; } }, getFixedDistance: function() { return this._minDistance == this._maxDistance ? this._minDistance : null; }, setFixedDistance: function(distance) { this._minDistance = this._maxDistance = distance; }, _handleMouseEvent: function(type, event, point, mouse) { paper = this._scope; if (mouse.drag && !this.responds(type)) type = 'mousemove'; var move = mouse.move || mouse.drag, responds = this.responds(type), minDistance = this.minDistance, maxDistance = this.maxDistance, called = false, tool = this; function update(minDistance, maxDistance) { var pt = point, toolPoint = move ? tool._point : (tool._downPoint || pt); if (move) { if (tool._moveCount >= 0 && pt.equals(toolPoint)) { return false; } if (toolPoint && (minDistance != null || maxDistance != null)) { var vector = pt.subtract(toolPoint), distance = vector.getLength(); if (distance < (minDistance || 0)) return false; if (maxDistance) { pt = toolPoint.add(vector.normalize( Math.min(distance, maxDistance))); } } tool._moveCount++; } tool._point = pt; tool._lastPoint = toolPoint || pt; if (mouse.down) { tool._moveCount = -1; tool._downPoint = pt; tool._downCount++; } return true; } function emit() { if (responds) { called = tool.emit(type, new ToolEvent(tool, type, event)) || called; } } if (mouse.down) { update(); emit(); } else if (mouse.up) { update(null, maxDistance); emit(); } else if (responds) { while (update(minDistance, maxDistance)) emit(); } return called; } }); var Tween = Base.extend(Emitter, { _class: 'Tween', statics: { easings: { linear: function(t) { return t; }, easeInQuad: function(t) { return t * t; }, easeOutQuad: function(t) { return t * (2 - t); }, easeInOutQuad: function(t) { return t < 0.5 ? 2 * t * t : -1 + 2 * (2 - t) * t; }, easeInCubic: function(t) { return t * t * t; }, easeOutCubic: function(t) { return --t * t * t + 1; }, easeInOutCubic: function(t) { return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1; }, easeInQuart: function(t) { return t * t * t * t; }, easeOutQuart: function(t) { return 1 - (--t) * t * t * t; }, easeInOutQuart: function(t) { return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t; }, easeInQuint: function(t) { return t * t * t * t * t; }, easeOutQuint: function(t) { return 1 + --t * t * t * t * t; }, easeInOutQuint: function(t) { return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t; } } }, initialize: function Tween(object, from, to, duration, easing, start) { this.object = object; var type = typeof easing; var isFunction = type === 'function'; this.type = isFunction ? type : type === 'string' ? easing : 'linear'; this.easing = isFunction ? easing : Tween.easings[this.type]; this.duration = duration; this.running = false; this._then = null; this._startTime = null; var state = from || to; this._keys = state ? Object.keys(state) : []; this._parsedKeys = this._parseKeys(this._keys); this._from = state && this._getState(from); this._to = state && this._getState(to); if (start !== false) { this.start(); } }, then: function(then) { this._then = then; return this; }, start: function() { this._startTime = null; this.running = true; return this; }, stop: function() { this.running = false; return this; }, update: function(progress) { if (this.running) { if (progress > 1) { progress = 1; this.running = false; } var factor = this.easing(progress), keys = this._keys, getValue = function(value) { return typeof value === 'function' ? value(factor, progress) : value; }; for (var i = 0, l = keys && keys.length; i < l; i++) { var key = keys[i], from = getValue(this._from[key]), to = getValue(this._to[key]), value = (from && to && from.__add && to.__add) ? to.__subtract(from).__multiply(factor).__add(from) : ((to - from) * factor) + from; this._setProperty(this._parsedKeys[key], value); } if (!this.running && this._then) { this._then(this.object); } if (this.responds('update')) { this.emit('update', new Base({ progress: progress, factor: factor })); } } return this; }, _events: { onUpdate: {} }, _handleFrame: function(time) { var startTime = this._startTime, progress = startTime ? (time - startTime) / this.duration : 0; if (!startTime) { this._startTime = time; } this.update(progress); }, _getState: function(state) { var keys = this._keys, result = {}; for (var i = 0, l = keys.length; i < l; i++) { var key = keys[i], path = this._parsedKeys[key], current = this._getProperty(path), value; if (state) { var resolved = this._resolveValue(current, state[key]); this._setProperty(path, resolved); value = this._getProperty(path); value = value && value.clone ? value.clone() : value; this._setProperty(path, current); } else { value = current && current.clone ? current.clone() : current; } result[key] = value; } return result; }, _resolveValue: function(current, value) { if (value) { if (Array.isArray(value) && value.length === 2) { var operator = value[0]; return ( operator && operator.match && operator.match(/^[+\-\*\/]=/) ) ? this._calculate(current, operator[0], value[1]) : value; } else if (typeof value === 'string') { var match = value.match(/^[+\-*/]=(.*)/); if (match) { var parsed = JSON.parse(match[1].replace( /(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2": ' )); return this._calculate(current, value[0], parsed); } } } return value; }, _calculate: function(left, operator, right) { return paper.PaperScript.calculateBinary(left, operator, right); }, _parseKeys: function(keys) { var parsed = {}; for (var i = 0, l = keys.length; i < l; i++) { var key = keys[i], path = key .replace(/\.([^.]*)/g, '/$1') .replace(/\[['"]?([^'"\]]*)['"]?\]/g, '/$1'); parsed[key] = path.split('/'); } return parsed; }, _getProperty: function(path, offset) { var obj = this.object; for (var i = 0, l = path.length - (offset || 0); i < l && obj; i++) { obj = obj[path[i]]; } return obj; }, _setProperty: function(path, value) { var dest = this._getProperty(path, 1); if (dest) { dest[path[path.length - 1]] = value; } } }); var Http = { request: function(options) { var xhr = new self.XMLHttpRequest(); xhr.open((options.method || 'get').toUpperCase(), options.url, Base.pick(options.async, true)); if (options.mimeType) xhr.overrideMimeType(options.mimeType); xhr.onload = function() { var status = xhr.status; if (status === 0 || status === 200) { if (options.onLoad) { options.onLoad.call(xhr, xhr.responseText); } } else { xhr.onerror(); } }; xhr.onerror = function() { var status = xhr.status, message = 'Could not load "' + options.url + '" (Status: ' + status + ')'; if (options.onError) { options.onError(message, status); } else { throw new Error(message); } }; return xhr.send(null); } }; var CanvasProvider = { canvases: [], getCanvas: function(width, height) { if (!window) return null; var canvas, clear = true; if (typeof width === 'object') { height = width.height; width = width.width; } if (this.canvases.length) { canvas = this.canvases.pop(); } else { canvas = document.createElement('canvas'); clear = false; } var ctx = canvas.getContext('2d'); if (!ctx) { throw new Error('Canvas ' + canvas + ' is unable to provide a 2D context.'); } if (canvas.width === width && canvas.height === height) { if (clear) ctx.clearRect(0, 0, width + 1, height + 1); } else { canvas.width = width; canvas.height = height; } ctx.save(); return canvas; }, getContext: function(width, height) { var canvas = this.getCanvas(width, height); return canvas ? canvas.getContext('2d') : null; }, release: function(obj) { var canvas = obj && obj.canvas ? obj.canvas : obj; if (canvas && canvas.getContext) { canvas.getContext('2d').restore(); this.canvases.push(canvas); } } }; var BlendMode = new function() { var min = Math.min, max = Math.max, abs = Math.abs, sr, sg, sb, sa, br, bg, bb, ba, dr, dg, db; function getLum(r, g, b) { return 0.2989 * r + 0.587 * g + 0.114 * b; } function setLum(r, g, b, l) { var d = l - getLum(r, g, b); dr = r + d; dg = g + d; db = b + d; var l = getLum(dr, dg, db), mn = min(dr, dg, db), mx = max(dr, dg, db); if (mn < 0) { var lmn = l - mn; dr = l + (dr - l) * l / lmn; dg = l + (dg - l) * l / lmn; db = l + (db - l) * l / lmn; } if (mx > 255) { var ln = 255 - l, mxl = mx - l; dr = l + (dr - l) * ln / mxl; dg = l + (dg - l) * ln / mxl; db = l + (db - l) * ln / mxl; } } function getSat(r, g, b) { return max(r, g, b) - min(r, g, b); } function setSat(r, g, b, s) { var col = [r, g, b], mx = max(r, g, b), mn = min(r, g, b), md; mn = mn === r ? 0 : mn === g ? 1 : 2; mx = mx === r ? 0 : mx === g ? 1 : 2; md = min(mn, mx) === 0 ? max(mn, mx) === 1 ? 2 : 1 : 0; if (col[mx] > col[mn]) { col[md] = (col[md] - col[mn]) * s / (col[mx] - col[mn]); col[mx] = s; } else { col[md] = col[mx] = 0; } col[mn] = 0; dr = col[0]; dg = col[1]; db = col[2]; } var modes = { multiply: function() { dr = br * sr / 255; dg = bg * sg / 255; db = bb * sb / 255; }, screen: function() { dr = br + sr - (br * sr / 255); dg = bg + sg - (bg * sg / 255); db = bb + sb - (bb * sb / 255); }, overlay: function() { dr = br < 128 ? 2 * br * sr / 255 : 255 - 2 * (255 - br) * (255 - sr) / 255; dg = bg < 128 ? 2 * bg * sg / 255 : 255 - 2 * (255 - bg) * (255 - sg) / 255; db = bb < 128 ? 2 * bb * sb / 255 : 255 - 2 * (255 - bb) * (255 - sb) / 255; }, 'soft-light': function() { var t = sr * br / 255; dr = t + br * (255 - (255 - br) * (255 - sr) / 255 - t) / 255; t = sg * bg / 255; dg = t + bg * (255 - (255 - bg) * (255 - sg) / 255 - t) / 255; t = sb * bb / 255; db = t + bb * (255 - (255 - bb) * (255 - sb) / 255 - t) / 255; }, 'hard-light': function() { dr = sr < 128 ? 2 * sr * br / 255 : 255 - 2 * (255 - sr) * (255 - br) / 255; dg = sg < 128 ? 2 * sg * bg / 255 : 255 - 2 * (255 - sg) * (255 - bg) / 255; db = sb < 128 ? 2 * sb * bb / 255 : 255 - 2 * (255 - sb) * (255 - bb) / 255; }, 'color-dodge': function() { dr = br === 0 ? 0 : sr === 255 ? 255 : min(255, 255 * br / (255 - sr)); dg = bg === 0 ? 0 : sg === 255 ? 255 : min(255, 255 * bg / (255 - sg)); db = bb === 0 ? 0 : sb === 255 ? 255 : min(255, 255 * bb / (255 - sb)); }, 'color-burn': function() { dr = br === 255 ? 255 : sr === 0 ? 0 : max(0, 255 - (255 - br) * 255 / sr); dg = bg === 255 ? 255 : sg === 0 ? 0 : max(0, 255 - (255 - bg) * 255 / sg); db = bb === 255 ? 255 : sb === 0 ? 0 : max(0, 255 - (255 - bb) * 255 / sb); }, darken: function() { dr = br < sr ? br : sr; dg = bg < sg ? bg : sg; db = bb < sb ? bb : sb; }, lighten: function() { dr = br > sr ? br : sr; dg = bg > sg ? bg : sg; db = bb > sb ? bb : sb; }, difference: function() { dr = br - sr; if (dr < 0) dr = -dr; dg = bg - sg; if (dg < 0) dg = -dg; db = bb - sb; if (db < 0) db = -db; }, exclusion: function() { dr = br + sr * (255 - br - br) / 255; dg = bg + sg * (255 - bg - bg) / 255; db = bb + sb * (255 - bb - bb) / 255; }, hue: function() { setSat(sr, sg, sb, getSat(br, bg, bb)); setLum(dr, dg, db, getLum(br, bg, bb)); }, saturation: function() { setSat(br, bg, bb, getSat(sr, sg, sb)); setLum(dr, dg, db, getLum(br, bg, bb)); }, luminosity: function() { setLum(br, bg, bb, getLum(sr, sg, sb)); }, color: function() { setLum(sr, sg, sb, getLum(br, bg, bb)); }, add: function() { dr = min(br + sr, 255); dg = min(bg + sg, 255); db = min(bb + sb, 255); }, subtract: function() { dr = max(br - sr, 0); dg = max(bg - sg, 0); db = max(bb - sb, 0); }, average: function() { dr = (br + sr) / 2; dg = (bg + sg) / 2; db = (bb + sb) / 2; }, negation: function() { dr = 255 - abs(255 - sr - br); dg = 255 - abs(255 - sg - bg); db = 255 - abs(255 - sb - bb); } }; var nativeModes = this.nativeModes = Base.each([ 'source-over', 'source-in', 'source-out', 'source-atop', 'destination-over', 'destination-in', 'destination-out', 'destination-atop', 'lighter', 'darker', 'copy', 'xor' ], function(mode) { this[mode] = true; }, {}); var ctx = CanvasProvider.getContext(1, 1); if (ctx) { Base.each(modes, function(func, mode) { var darken = mode === 'darken', ok = false; ctx.save(); try { ctx.fillStyle = darken ? '#300' : '#a00'; ctx.fillRect(0, 0, 1, 1); ctx.globalCompositeOperation = mode; if (ctx.globalCompositeOperation === mode) { ctx.fillStyle = darken ? '#a00' : '#300'; ctx.fillRect(0, 0, 1, 1); ok = ctx.getImageData(0, 0, 1, 1).data[0] !== darken ? 170 : 51; } } catch (e) {} ctx.restore(); nativeModes[mode] = ok; }); CanvasProvider.release(ctx); } this.process = function(mode, srcContext, dstContext, alpha, offset) { var srcCanvas = srcContext.canvas, normal = mode === 'normal'; if (normal || nativeModes[mode]) { dstContext.save(); dstContext.setTransform(1, 0, 0, 1, 0, 0); dstContext.globalAlpha = alpha; if (!normal) dstContext.globalCompositeOperation = mode; dstContext.drawImage(srcCanvas, offset.x, offset.y); dstContext.restore(); } else { var process = modes[mode]; if (!process) return; var dstData = dstContext.getImageData(offset.x, offset.y, srcCanvas.width, srcCanvas.height), dst = dstData.data, src = srcContext.getImageData(0, 0, srcCanvas.width, srcCanvas.height).data; for (var i = 0, l = dst.length; i < l; i += 4) { sr = src[i]; br = dst[i]; sg = src[i + 1]; bg = dst[i + 1]; sb = src[i + 2]; bb = dst[i + 2]; sa = src[i + 3]; ba = dst[i + 3]; process(); var a1 = sa * alpha / 255, a2 = 1 - a1; dst[i] = a1 * dr + a2 * br; dst[i + 1] = a1 * dg + a2 * bg; dst[i + 2] = a1 * db + a2 * bb; dst[i + 3] = sa * alpha + a2 * ba; } dstContext.putImageData(dstData, offset.x, offset.y); } }; }; var SvgElement = new function() { var svg = 'http://www.w3.org/2000/svg', xmlns = 'http://www.w3.org/2000/xmlns', xlink = 'http://www.w3.org/1999/xlink', attributeNamespace = { href: xlink, xlink: xmlns, xmlns: xmlns + '/', 'xmlns:xlink': xmlns + '/' }; function create(tag, attributes, formatter) { return set(document.createElementNS(svg, tag), attributes, formatter); } function get(node, name) { var namespace = attributeNamespace[name], value = namespace ? node.getAttributeNS(namespace, name) : node.getAttribute(name); return value === 'null' ? null : value; } function set(node, attributes, formatter) { for (var name in attributes) { var value = attributes[name], namespace = attributeNamespace[name]; if (typeof value === 'number' && formatter) value = formatter.number(value); if (namespace) { node.setAttributeNS(namespace, name, value); } else { node.setAttribute(name, value); } } return node; } return { svg: svg, xmlns: xmlns, xlink: xlink, create: create, get: get, set: set }; }; var SvgStyles = Base.each({ fillColor: ['fill', 'color'], fillRule: ['fill-rule', 'string'], strokeColor: ['stroke', 'color'], strokeWidth: ['stroke-width', 'number'], strokeCap: ['stroke-linecap', 'string'], strokeJoin: ['stroke-linejoin', 'string'], strokeScaling: ['vector-effect', 'lookup', { true: 'none', false: 'non-scaling-stroke' }, function(item, value) { return !value && (item instanceof PathItem || item instanceof Shape || item instanceof TextItem); }], miterLimit: ['stroke-miterlimit', 'number'], dashArray: ['stroke-dasharray', 'array'], dashOffset: ['stroke-dashoffset', 'number'], fontFamily: ['font-family', 'string'], fontWeight: ['font-weight', 'string'], fontSize: ['font-size', 'number'], justification: ['text-anchor', 'lookup', { left: 'start', center: 'middle', right: 'end' }], opacity: ['opacity', 'number'], blendMode: ['mix-blend-mode', 'style'] }, function(entry, key) { var part = Base.capitalize(key), lookup = entry[2]; this[key] = { type: entry[1], property: key, attribute: entry[0], toSVG: lookup, fromSVG: lookup && Base.each(lookup, function(value, name) { this[value] = name; }, {}), exportFilter: entry[3], get: 'get' + part, set: 'set' + part }; }, {}); new function() { var formatter; function getTransform(matrix, coordinates, center) { var attrs = new Base(), trans = matrix.getTranslation(); if (coordinates) { var point; if (matrix.isInvertible()) { matrix = matrix._shiftless(); point = matrix._inverseTransform(trans); trans = null; } else { point = new Point(); } attrs[center ? 'cx' : 'x'] = point.x; attrs[center ? 'cy' : 'y'] = point.y; } if (!matrix.isIdentity()) { var decomposed = matrix.decompose(); if (decomposed) { var parts = [], angle = decomposed.rotation, scale = decomposed.scaling, skew = decomposed.skewing; if (trans && !trans.isZero()) parts.push('translate(' + formatter.point(trans) + ')'); if (angle) parts.push('rotate(' + formatter.number(angle) + ')'); if (!Numerical.isZero(scale.x - 1) || !Numerical.isZero(scale.y - 1)) parts.push('scale(' + formatter.point(scale) +')'); if (skew.x) parts.push('skewX(' + formatter.number(skew.x) + ')'); if (skew.y) parts.push('skewY(' + formatter.number(skew.y) + ')'); attrs.transform = parts.join(' '); } else { attrs.transform = 'matrix(' + matrix.getValues().join(',') + ')'; } } return attrs; } function exportGroup(item, options) { var attrs = getTransform(item._matrix), children = item._children; var node = SvgElement.create('g', attrs, formatter); for (var i = 0, l = children.length; i < l; i++) { var child = children[i]; var childNode = exportSVG(child, options); if (childNode) { if (child.isClipMask()) { var clip = SvgElement.create('clipPath'); clip.appendChild(childNode); setDefinition(child, clip, 'clip'); SvgElement.set(node, { 'clip-path': 'url(#' + clip.id + ')' }); } else { node.appendChild(childNode); } } } return node; } function exportRaster(item, options) { var attrs = getTransform(item._matrix, true), size = item.getSize(), image = item.getImage(); attrs.x -= size.width / 2; attrs.y -= size.height / 2; attrs.width = size.width; attrs.height = size.height; attrs.href = options.embedImages == false && image && image.src || item.toDataURL(); return SvgElement.create('image', attrs, formatter); } function exportPath(item, options) { var matchShapes = options.matchShapes; if (matchShapes) { var shape = item.toShape(false); if (shape) return exportShape(shape, options); } var segments = item._segments, length = segments.length, type, attrs = getTransform(item._matrix); if (matchShapes && length >= 2 && !item.hasHandles()) { if (length > 2) { type = item._closed ? 'polygon' : 'polyline'; var parts = []; for (var i = 0; i < length; i++) { parts.push(formatter.point(segments[i]._point)); } attrs.points = parts.join(' '); } else { type = 'line'; var start = segments[0]._point, end = segments[1]._point; attrs.set({ x1: start.x, y1: start.y, x2: end.x, y2: end.y }); } } else { type = 'path'; attrs.d = item.getPathData(null, options.precision); } return SvgElement.create(type, attrs, formatter); } function exportShape(item) { var type = item._type, radius = item._radius, attrs = getTransform(item._matrix, true, type !== 'rectangle'); if (type === 'rectangle') { type = 'rect'; var size = item._size, width = size.width, height = size.height; attrs.x -= width / 2; attrs.y -= height / 2; attrs.width = width; attrs.height = height; if (radius.isZero()) radius = null; } if (radius) { if (type === 'circle') { attrs.r = radius; } else { attrs.rx = radius.width; attrs.ry = radius.height; } } return SvgElement.create(type, attrs, formatter); } function exportCompoundPath(item, options) { var attrs = getTransform(item._matrix); var data = item.getPathData(null, options.precision); if (data) attrs.d = data; return SvgElement.create('path', attrs, formatter); } function exportSymbolItem(item, options) { var attrs = getTransform(item._matrix, true), definition = item._definition, node = getDefinition(definition, 'symbol'), definitionItem = definition._item, bounds = definitionItem.getStrokeBounds(); if (!node) { node = SvgElement.create('symbol', { viewBox: formatter.rectangle(bounds) }); node.appendChild(exportSVG(definitionItem, options)); setDefinition(definition, node, 'symbol'); } attrs.href = '#' + node.id; attrs.x += bounds.x; attrs.y += bounds.y; attrs.width = bounds.width; attrs.height = bounds.height; attrs.overflow = 'visible'; return SvgElement.create('use', attrs, formatter); } function exportGradient(color, item) { var gradientNode = getDefinition(color, 'color'); if (!gradientNode) { var gradient = color.getGradient(), radial = gradient._radial, origin = color.getOrigin(), destination = color.getDestination(), attrs; if (radial) { attrs = { cx: origin.x, cy: origin.y, r: origin.getDistance(destination) }; var highlight = color.getHighlight(); if (highlight) { attrs.fx = highlight.x; attrs.fy = highlight.y; } } else { attrs = { x1: origin.x, y1: origin.y, x2: destination.x, y2: destination.y }; } if (item instanceof paper.PointText) { attrs.gradientTransform = getTransform( item._matrix.clone().invert(), false, formatter).transform; } attrs.gradientUnits = 'userSpaceOnUse'; gradientNode = SvgElement.create((radial ? 'radial' : 'linear') + 'Gradient', attrs, formatter); var stops = gradient._stops; for (var i = 0, l = stops.length; i < l; i++) { var stop = stops[i], stopColor = stop._color, alpha = stopColor.getAlpha(), offset = stop._offset; attrs = { offset: offset == null ? i / (l - 1) : offset }; if (stopColor) attrs['stop-color'] = stopColor.toCSS(true); if (alpha < 1) attrs['stop-opacity'] = alpha; gradientNode.appendChild( SvgElement.create('stop', attrs, formatter)); } setDefinition(color, gradientNode, 'color'); } return 'url(#' + gradientNode.id + ')'; } function exportText(item) { var node = SvgElement.create('text', getTransform(item._matrix, false), formatter); node.setAttribute('font-size', item.fontSize); node.setAttribute('xml:space', 'preserve'); for (var i = 0; i < item._lines.length; i++) { var tspanNode = SvgElement.create('tspan', { x: '0', dy: i === 0 ? '0' : item.getLeading() + 'px' }, formatter); tspanNode.textContent = item._lines[i] ? item._lines[i] : ' '; node.appendChild(tspanNode); } return node; } var exporters = { Group: exportGroup, Layer: exportGroup, Raster: exportRaster, Path: exportPath, Shape: exportShape, CompoundPath: exportCompoundPath, SymbolItem: exportSymbolItem, PointText: exportText }; function applyStyle(item, node, isRoot) { var attrs = {}, parent = !isRoot && item.getParent(), style = []; if (item._name != null) attrs.id = item._name; Base.each(SvgStyles, function(entry) { var get = entry.get, type = entry.type, value = item[get](); if (value === undefined) return; if (entry.exportFilter ? entry.exportFilter(item, value) : !parent || !Base.equals(parent[get](), value) || item instanceof paper.PointText) { if (type === 'color' && value != null) { var alpha = value.getAlpha(); if (alpha < 1) attrs[entry.attribute + '-opacity'] = alpha; } if (type === 'style') { style.push(entry.attribute + ': ' + value); } else { attrs[entry.attribute] = value == null ? 'none' : type === 'color' ? value.gradient ? exportGradient(value, item) : value.toCSS(true) : type === 'array' ? value.join(',') : type === 'lookup' ? entry.toSVG[value] : value; } } }); if (style.length) attrs.style = style.join(';'); if (attrs.opacity === 1) delete attrs.opacity; if (!item._visible) attrs.visibility = 'hidden'; return SvgElement.set(node, attrs, formatter); } var definitions; function getDefinition(item, type) { if (!definitions) definitions = { ids: {}, svgs: {} }; return item && definitions.svgs[type + '-' + (item._id || item.__id || (item.__id = UID.get('svg')))]; } function setDefinition(item, node, type) { if (!definitions) getDefinition(); var typeId = definitions.ids[type] = (definitions.ids[type] || 0) + 1; node.id = type + '-' + typeId; definitions.svgs[type + '-' + (item._id || item.__id)] = node; } function exportDefinitions(node, options) { var svg = node, defs = null; if (definitions) { svg = node.nodeName.toLowerCase() === 'svg' && node; for (var i in definitions.svgs) { if (!defs) { if (!svg) { svg = SvgElement.create('svg'); svg.appendChild(node); } defs = svg.insertBefore(SvgElement.create('defs'), svg.firstChild); } defs.appendChild(definitions.svgs[i]); } definitions = null; } return options.asString ? new self.XMLSerializer().serializeToString(svg) : svg; } function exportSVG(item, options, isRoot) { var exporter = exporters[item._class], node = exporter && exporter(item, options); if (node) { var onExport = options.onExport; if (onExport) node = onExport(item, node, options) || node; var data = JSON.stringify(item._data); if (data && data !== '{}' && data !== 'null') node.setAttribute('data-paper-data', data); } return node && applyStyle(item, node, isRoot); } function setOptions(options) { if (!options) options = {}; formatter = new Formatter(options.precision); return options; } Item.inject({ exportSVG: function(options) { options = setOptions(options); return exportDefinitions(exportSVG(this, options, true), options); } }); Project.inject({ exportSVG: function(options) { options = setOptions(options); var children = this._children, view = this.getView(), bounds = Base.pick(options.bounds, 'view'), mx = options.matrix || bounds === 'view' && view._matrix, matrix = mx && Matrix.read([mx]), rect = bounds === 'view' ? new Rectangle([0, 0], view.getViewSize()) : bounds === 'content' ? Item._getBounds(children, matrix, { stroke: true, drawnTextBounds: true }) .rect : Rectangle.read([bounds], 0, { readNull: true }), attrs = { version: '1.1', xmlns: SvgElement.svg, 'xmlns:xlink': SvgElement.xlink, }; if (rect) { attrs.width = rect.width; attrs.height = rect.height; if (rect.x || rect.x === 0 || rect.y || rect.y === 0) attrs.viewBox = formatter.rectangle(rect); } var node = SvgElement.create('svg', attrs, formatter), parent = node; if (matrix && !matrix.isIdentity()) { parent = node.appendChild(SvgElement.create('g', getTransform(matrix), formatter)); } for (var i = 0, l = children.length; i < l; i++) { parent.appendChild(exportSVG(children[i], options, true)); } return exportDefinitions(node, options); } }); }; new function() { var definitions = {}, rootSize; function getValue(node, name, isString, allowNull, allowPercent, defaultValue) { var value = SvgElement.get(node, name) || defaultValue, res = value == null ? allowNull ? null : isString ? '' : 0 : isString ? value : parseFloat(value); return /%\s*$/.test(value) ? (res / 100) * (allowPercent ? 1 : rootSize[/x|^width/.test(name) ? 'width' : 'height']) : res; } function getPoint(node, x, y, allowNull, allowPercent, defaultX, defaultY) { x = getValue(node, x || 'x', false, allowNull, allowPercent, defaultX); y = getValue(node, y || 'y', false, allowNull, allowPercent, defaultY); return allowNull && (x == null || y == null) ? null : new Point(x, y); } function getSize(node, w, h, allowNull, allowPercent) { w = getValue(node, w || 'width', false, allowNull, allowPercent); h = getValue(node, h || 'height', false, allowNull, allowPercent); return allowNull && (w == null || h == null) ? null : new Size(w, h); } function convertValue(value, type, lookup) { return value === 'none' ? null : type === 'number' ? parseFloat(value) : type === 'array' ? value ? value.split(/[\s,]+/g).map(parseFloat) : [] : type === 'color' ? getDefinition(value) || value : type === 'lookup' ? lookup[value] : value; } function importGroup(node, type, options, isRoot) { var nodes = node.childNodes, isClip = type === 'clippath', isDefs = type === 'defs', item = new Group(), project = item._project, currentStyle = project._currentStyle, children = []; if (!isClip && !isDefs) { item = applyAttributes(item, node, isRoot); project._currentStyle = item._style.clone(); } if (isRoot) { var defs = node.querySelectorAll('defs'); for (var i = 0, l = defs.length; i < l; i++) { importNode(defs[i], options, false); } } for (var i = 0, l = nodes.length; i < l; i++) { var childNode = nodes[i], child; if (childNode.nodeType === 1 && !/^defs$/i.test(childNode.nodeName) && (child = importNode(childNode, options, false)) && !(child instanceof SymbolDefinition)) children.push(child); } item.addChildren(children); if (isClip) item = applyAttributes(item.reduce(), node, isRoot); project._currentStyle = currentStyle; if (isClip || isDefs) { item.remove(); item = null; } return item; } function importPoly(node, type) { var coords = node.getAttribute('points').match( /[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g), points = []; for (var i = 0, l = coords.length; i < l; i += 2) points.push(new Point( parseFloat(coords[i]), parseFloat(coords[i + 1]))); var path = new Path(points); if (type === 'polygon') path.closePath(); return path; } function importPath(node) { return PathItem.create(node.getAttribute('d')); } function importGradient(node, type) { var id = (getValue(node, 'href', true) || '').substring(1), radial = type === 'radialgradient', gradient; if (id) { gradient = definitions[id].getGradient(); if (gradient._radial ^ radial) { gradient = gradient.clone(); gradient._radial = radial; } } else { var nodes = node.childNodes, stops = []; for (var i = 0, l = nodes.length; i < l; i++) { var child = nodes[i]; if (child.nodeType === 1) stops.push(applyAttributes(new GradientStop(), child)); } gradient = new Gradient(stops, radial); } var origin, destination, highlight, scaleToBounds = getValue(node, 'gradientUnits', true) !== 'userSpaceOnUse'; if (radial) { origin = getPoint(node, 'cx', 'cy', false, scaleToBounds, '50%', '50%'); destination = origin.add( getValue(node, 'r', false, false, scaleToBounds, '50%'), 0); highlight = getPoint(node, 'fx', 'fy', true, scaleToBounds); } else { origin = getPoint(node, 'x1', 'y1', false, scaleToBounds, '0%', '0%'); destination = getPoint(node, 'x2', 'y2', false, scaleToBounds, '100%', '0%'); } var color = applyAttributes( new Color(gradient, origin, destination, highlight), node); color._scaleToBounds = scaleToBounds; return null; } var importers = { '#document': function (node, type, options, isRoot) { var nodes = node.childNodes; for (var i = 0, l = nodes.length; i < l; i++) { var child = nodes[i]; if (child.nodeType === 1) return importNode(child, options, isRoot); } }, g: importGroup, svg: importGroup, clippath: importGroup, polygon: importPoly, polyline: importPoly, path: importPath, lineargradient: importGradient, radialgradient: importGradient, image: function (node) { var raster = new Raster(getValue(node, 'href', true)); raster.on('load', function() { var size = getSize(node); this.setSize(size); var center = getPoint(node).add(size.divide(2)); this._matrix.append(new Matrix().translate(center)); }); return raster; }, symbol: function(node, type, options, isRoot) { return new SymbolDefinition( importGroup(node, type, options, isRoot), true); }, defs: importGroup, use: function(node) { var id = (getValue(node, 'href', true) || '').substring(1), definition = definitions[id], point = getPoint(node); return definition ? definition instanceof SymbolDefinition ? definition.place(point) : definition.clone().translate(point) : null; }, circle: function(node) { return new Shape.Circle( getPoint(node, 'cx', 'cy'), getValue(node, 'r')); }, ellipse: function(node) { return new Shape.Ellipse({ center: getPoint(node, 'cx', 'cy'), radius: getSize(node, 'rx', 'ry') }); }, rect: function(node) { return new Shape.Rectangle(new Rectangle( getPoint(node), getSize(node) ), getSize(node, 'rx', 'ry')); }, line: function(node) { return new Path.Line( getPoint(node, 'x1', 'y1'), getPoint(node, 'x2', 'y2')); }, text: function(node) { var fontSize = parseFloat(node.getAttribute("font-size")); var alignmentBaseline = node.getAttribute("alignment-baseline"); if (node.childElementCount === 0) { var text = new PointText(); text.setContent(node.textContent.trim() || ''); text.translate(0, text._style.getLeading()); if (!isNaN(fontSize)) text.setFontSize(fontSize); return text; } else { var lines = []; var spacing = 1.2; for (var i = 0; i < node.childNodes.length; i++) { var child = node.childNodes[i]; if (!child.getAttribute) continue; lines.push(child.textContent); var dyString = child.getAttribute('dy'); if (dyString) { var dy = parseFloat(dyString); if (!isNaN(dy)) { if (dyString.endsWith('em')) { spacing = dy; } else if (dyString.endsWith('px') && !isNaN(fontSize)) { spacing = dy / fontSize; } } } } var text = new PointText(); if (!isNaN(fontSize)) text.setFontSize(fontSize); text.setLeading(text.fontSize * spacing); if (alignmentBaseline === 'text-before-edge') { text.setContent(' '); text.translate(0, text.bounds.height); } text.setContent(lines.join('\n')); return text; } }, switch: importGroup }; function applyTransform(item, value, name, node) { if (item.transform) { var transforms = (node.getAttribute(name) || '').split(/\)\s*/g), matrix = new Matrix(); for (var i = 0, l = transforms.length; i < l; i++) { var transform = transforms[i]; if (!transform) break; var parts = transform.split(/\(\s*/), command = parts[0], v = parts[1].split(/[\s,]+/g); for (var j = 0, m = v.length; j < m; j++) v[j] = parseFloat(v[j]); switch (command) { case 'matrix': matrix.append( new Matrix(v[0], v[1], v[2], v[3], v[4], v[5])); break; case 'rotate': matrix.rotate(v[0], v[1] || 0, v[2] || 0); break; case 'translate': matrix.translate(v[0], v[1] || 0); break; case 'scale': matrix.scale(v); break; case 'skewX': matrix.skew(v[0], 0); break; case 'skewY': matrix.skew(0, v[0]); break; } } item.transform(matrix); } } function applyOpacity(item, value, name) { var key = name === 'fill-opacity' ? 'getFillColor' : 'getStrokeColor', color = item[key] && item[key](); if (color) color.setAlpha(parseFloat(value)); } var attributes = Base.set(Base.each(SvgStyles, function(entry) { this[entry.attribute] = function(item, value) { if (item[entry.set]) { item[entry.set](convertValue(value, entry.type, entry.fromSVG)); if (entry.type === 'color') { var color = item[entry.get](); if (color) { if (color._scaleToBounds) { var bounds = item.getBounds(); color.transform(new Matrix() .translate(bounds.getPoint()) .scale(bounds.getSize())); } } } } }; }, {}), { id: function(item, value) { definitions[value] = item; }, 'clip-path': function(item, value) { var clip = getDefinition(value); if (clip) { clip = clip.clone(); clip.setClipMask(true); if (item instanceof Group) { item.insertChild(0, clip); } else { return new Group(clip, item); } } }, gradientTransform: applyTransform, transform: applyTransform, 'fill-opacity': applyOpacity, 'stroke-opacity': applyOpacity, visibility: function(item, value) { if (item.setVisible) item.setVisible(value === 'visible'); }, display: function(item, value) { if (item.setVisible) item.setVisible(value !== null); }, 'stop-color': function(item, value) { if (item.setColor) item.setColor(value); }, 'stop-opacity': function(item, value) { if (item._color) item._color.setAlpha(parseFloat(value)); }, offset: function(item, value) { if (item.setOffset) { var percent = value.match(/(.*)%$/); item.setOffset(percent ? percent[1] / 100 : parseFloat(value)); } }, viewBox: function(item, value, name, node, styles) { var rect = new Rectangle(convertValue(value, 'array')), size = getSize(node, null, null, true), group, matrix; if (item instanceof Group) { var scale = size ? size.divide(rect.getSize()) : 1, matrix = new Matrix().scale(scale) .translate(rect.getPoint().negate()); group = item; } else if (item instanceof SymbolDefinition) { if (size) rect.setSize(size); group = item._item; } if (group) { if (getAttribute(node, 'overflow', styles) !== 'visible') { var clip = new Shape.Rectangle(rect); clip.setClipMask(true); group.addChild(clip); } if (matrix) group.transform(matrix); } }, 'fill-rule': function(item, value) { if (value === 'evenodd' || value === 'nonzero') item.fillRule = value; } }); function getAttribute(node, name, styles) { var attr = node.attributes[name], value = attr && attr.value; if (!value && node.style) { var style = Base.camelize(name); value = node.style[style]; if (!value && styles.node[style] !== styles.parent[style]) value = styles.node[style]; } return !value ? undefined : value === 'none' ? null : value; } function applyAttributes(item, node, isRoot) { var parent = node.parentNode, styles = { node: DomElement.getStyles(node) || {}, parent: !isRoot && !/^defs$/i.test(parent.tagName) && DomElement.getStyles(parent) || {} }; Base.each(attributes, function(apply, name) { var value = getAttribute(node, name, styles); item = value !== undefined && apply(item, value, name, node, styles) || item; }); return item; } function getDefinition(value) { var match = value && value.match(/\((?:["'#]*)([^"')]+)/), name = match && match[1], res = name && definitions[window ? name.replace(window.location.href.split('#')[0] + '#', '') : name]; if (res && res._scaleToBounds) { res = res.clone(); res._scaleToBounds = true; } return res; } function importNode(node, options, isRoot) { var type = node.nodeName.toLowerCase(), isElement = type !== '#document', body = document.body, container, parent, next; if (isRoot && isElement) { rootSize = paper.getView().getSize(); rootSize = getSize(node, null, null, true) || rootSize; container = SvgElement.create('svg', { style: 'stroke-width: 1px; stroke-miterlimit: 10' }); parent = node.parentNode; next = node.nextSibling; container.appendChild(node); body.appendChild(container); } var settings = paper.settings, applyMatrix = settings.applyMatrix, insertItems = settings.insertItems; settings.applyMatrix = false; settings.insertItems = false; var importer = importers[type], item = importer && importer(node, type, options, isRoot) || null; settings.insertItems = insertItems; settings.applyMatrix = applyMatrix; if (item) { if (isElement && !(item instanceof Group)) item = applyAttributes(item, node, isRoot); var onImport = options.onImport, data = isElement && node.getAttribute('data-paper-data'); if (onImport) item = onImport(node, item, options) || item; if (options.expandShapes && item instanceof Shape) { item.remove(); item = item.toPath(); } if (data) item._data = JSON.parse(data); } if (container) { body.removeChild(container); if (parent) { if (next) { parent.insertBefore(node, next); } else { parent.appendChild(node); } } } if (isRoot) { definitions = {}; if (item && Base.pick(options.applyMatrix, applyMatrix)) item.matrix.apply(true, true); } return item; } function importSVG(source, options, owner) { if (!source) return null; options = typeof options === 'function' ? { onLoad: options } : options || {}; var scope = paper, item = null; function onLoad(svg) { try { var node = typeof svg === 'object' ? svg : new self.DOMParser().parseFromString( svg, 'image/svg+xml' ); if (!node.nodeName) { node = null; throw new Error('Unsupported SVG source: ' + source); } paper = scope; item = importNode(node, options, true); if (!options || options.insert !== false) { owner._insertItem(undefined, item); } var onLoad = options.onLoad; if (onLoad) onLoad(item, svg); } catch (e) { onError(e); } } function onError(message, status) { var onError = options.onError; if (onError) { onError(message, status); } else { throw new Error(message); } } if (typeof source === 'string' && !/^[\s\S]* 3) { cats.sort(function(a, b) {return b.length - a.length;}); f += "switch(str.length){"; for (var i = 0; i < cats.length; ++i) { var cat = cats[i]; f += "case " + cat[0].length + ":"; compareTo(cat); } f += "}"; } else { compareTo(words); } return new Function("str", f); } var isReservedWord3 = makePredicate("abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile"); var isReservedWord5 = makePredicate("class enum extends super const export import"); var isStrictReservedWord = makePredicate("implements interface let package private protected public static yield"); var isStrictBadIdWord = makePredicate("eval arguments"); var isKeyword = makePredicate("break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this"); var nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/; var nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc"; var nonASCIIidentifierChars = "\u0300-\u036f\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u0620-\u0649\u0672-\u06d3\u06e7-\u06e8\u06fb-\u06fc\u0730-\u074a\u0800-\u0814\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0840-\u0857\u08e4-\u08fe\u0900-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962-\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09d7\u09df-\u09e0\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5f-\u0b60\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2-\u0ce3\u0ce6-\u0cef\u0d02\u0d03\u0d46-\u0d48\u0d57\u0d62-\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e34-\u0e3a\u0e40-\u0e45\u0e50-\u0e59\u0eb4-\u0eb9\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f41-\u0f47\u0f71-\u0f84\u0f86-\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1029\u1040-\u1049\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u170e-\u1710\u1720-\u1730\u1740-\u1750\u1772\u1773\u1780-\u17b2\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1920-\u192b\u1930-\u193b\u1951-\u196d\u19b0-\u19c0\u19c8-\u19c9\u19d0-\u19d9\u1a00-\u1a15\u1a20-\u1a53\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1b46-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1bb0-\u1bb9\u1be6-\u1bf3\u1c00-\u1c22\u1c40-\u1c49\u1c5b-\u1c7d\u1cd0-\u1cd2\u1d00-\u1dbe\u1e01-\u1f15\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2d81-\u2d96\u2de0-\u2dff\u3021-\u3028\u3099\u309a\ua640-\ua66d\ua674-\ua67d\ua69f\ua6f0-\ua6f1\ua7f8-\ua800\ua806\ua80b\ua823-\ua827\ua880-\ua881\ua8b4-\ua8c4\ua8d0-\ua8d9\ua8f3-\ua8f7\ua900-\ua909\ua926-\ua92d\ua930-\ua945\ua980-\ua983\ua9b3-\ua9c0\uaa00-\uaa27\uaa40-\uaa41\uaa4c-\uaa4d\uaa50-\uaa59\uaa7b\uaae0-\uaae9\uaaf2-\uaaf3\uabc0-\uabe1\uabec\uabed\uabf0-\uabf9\ufb20-\ufb28\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f"; var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]"); var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]"); var newline = /[\n\r\u2028\u2029]/; var lineBreak = /\r\n|[\n\r\u2028\u2029]/g; var isIdentifierStart = exports.isIdentifierStart = function(code) { if (code < 65) return code === 36; if (code < 91) return true; if (code < 97) return code === 95; if (code < 123)return true; return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code)); }; var isIdentifierChar = exports.isIdentifierChar = function(code) { if (code < 48) return code === 36; if (code < 58) return true; if (code < 65) return false; if (code < 91) return true; if (code < 97) return code === 95; if (code < 123)return true; return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code)); }; function line_loc_t() { this.line = tokCurLine; this.column = tokPos - tokLineStart; } function initTokenState() { tokCurLine = 1; tokPos = tokLineStart = 0; tokRegexpAllowed = true; skipSpace(); } function finishToken(type, val) { tokEnd = tokPos; if (options.locations) tokEndLoc = new line_loc_t; tokType = type; skipSpace(); tokVal = val; tokRegexpAllowed = type.beforeExpr; } function skipBlockComment() { var startLoc = options.onComment && options.locations && new line_loc_t; var start = tokPos, end = input.indexOf("*/", tokPos += 2); if (end === -1) raise(tokPos - 2, "Unterminated comment"); tokPos = end + 2; if (options.locations) { lineBreak.lastIndex = start; var match; while ((match = lineBreak.exec(input)) && match.index < tokPos) { ++tokCurLine; tokLineStart = match.index + match[0].length; } } if (options.onComment) options.onComment(true, input.slice(start + 2, end), start, tokPos, startLoc, options.locations && new line_loc_t); } function skipLineComment() { var start = tokPos; var startLoc = options.onComment && options.locations && new line_loc_t; var ch = input.charCodeAt(tokPos+=2); while (tokPos < inputLen && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8233) { ++tokPos; ch = input.charCodeAt(tokPos); } if (options.onComment) options.onComment(false, input.slice(start + 2, tokPos), start, tokPos, startLoc, options.locations && new line_loc_t); } function skipSpace() { while (tokPos < inputLen) { var ch = input.charCodeAt(tokPos); if (ch === 32) { ++tokPos; } else if (ch === 13) { ++tokPos; var next = input.charCodeAt(tokPos); if (next === 10) { ++tokPos; } if (options.locations) { ++tokCurLine; tokLineStart = tokPos; } } else if (ch === 10 || ch === 8232 || ch === 8233) { ++tokPos; if (options.locations) { ++tokCurLine; tokLineStart = tokPos; } } else if (ch > 8 && ch < 14) { ++tokPos; } else if (ch === 47) { var next = input.charCodeAt(tokPos + 1); if (next === 42) { skipBlockComment(); } else if (next === 47) { skipLineComment(); } else break; } else if (ch === 160) { ++tokPos; } else if (ch >= 5760 && nonASCIIwhitespace.test(String.fromCharCode(ch))) { ++tokPos; } else { break; } } } function readToken_dot() { var next = input.charCodeAt(tokPos + 1); if (next >= 48 && next <= 57) return readNumber(true); ++tokPos; return finishToken(_dot); } function readToken_slash() { var next = input.charCodeAt(tokPos + 1); if (tokRegexpAllowed) {++tokPos; return readRegexp();} if (next === 61) return finishOp(_assign, 2); return finishOp(_slash, 1); } function readToken_mult_modulo() { var next = input.charCodeAt(tokPos + 1); if (next === 61) return finishOp(_assign, 2); return finishOp(_multiplyModulo, 1); } function readToken_pipe_amp(code) { var next = input.charCodeAt(tokPos + 1); if (next === code) return finishOp(code === 124 ? _logicalOR : _logicalAND, 2); if (next === 61) return finishOp(_assign, 2); return finishOp(code === 124 ? _bitwiseOR : _bitwiseAND, 1); } function readToken_caret() { var next = input.charCodeAt(tokPos + 1); if (next === 61) return finishOp(_assign, 2); return finishOp(_bitwiseXOR, 1); } function readToken_plus_min(code) { var next = input.charCodeAt(tokPos + 1); if (next === code) { if (next == 45 && input.charCodeAt(tokPos + 2) == 62 && newline.test(input.slice(lastEnd, tokPos))) { tokPos += 3; skipLineComment(); skipSpace(); return readToken(); } return finishOp(_incDec, 2); } if (next === 61) return finishOp(_assign, 2); return finishOp(_plusMin, 1); } function readToken_lt_gt(code) { var next = input.charCodeAt(tokPos + 1); var size = 1; if (next === code) { size = code === 62 && input.charCodeAt(tokPos + 2) === 62 ? 3 : 2; if (input.charCodeAt(tokPos + size) === 61) return finishOp(_assign, size + 1); return finishOp(_bitShift, size); } if (next == 33 && code == 60 && input.charCodeAt(tokPos + 2) == 45 && input.charCodeAt(tokPos + 3) == 45) { tokPos += 4; skipLineComment(); skipSpace(); return readToken(); } if (next === 61) size = input.charCodeAt(tokPos + 2) === 61 ? 3 : 2; return finishOp(_relational, size); } function readToken_eq_excl(code) { var next = input.charCodeAt(tokPos + 1); if (next === 61) return finishOp(_equality, input.charCodeAt(tokPos + 2) === 61 ? 3 : 2); return finishOp(code === 61 ? _eq : _prefix, 1); } function getTokenFromCode(code) { switch(code) { case 46: return readToken_dot(); case 40: ++tokPos; return finishToken(_parenL); case 41: ++tokPos; return finishToken(_parenR); case 59: ++tokPos; return finishToken(_semi); case 44: ++tokPos; return finishToken(_comma); case 91: ++tokPos; return finishToken(_bracketL); case 93: ++tokPos; return finishToken(_bracketR); case 123: ++tokPos; return finishToken(_braceL); case 125: ++tokPos; return finishToken(_braceR); case 58: ++tokPos; return finishToken(_colon); case 63: ++tokPos; return finishToken(_question); case 48: var next = input.charCodeAt(tokPos + 1); if (next === 120 || next === 88) return readHexNumber(); case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: return readNumber(false); case 34: case 39: return readString(code); case 47: return readToken_slash(code); case 37: case 42: return readToken_mult_modulo(); case 124: case 38: return readToken_pipe_amp(code); case 94: return readToken_caret(); case 43: case 45: return readToken_plus_min(code); case 60: case 62: return readToken_lt_gt(code); case 61: case 33: return readToken_eq_excl(code); case 126: return finishOp(_prefix, 1); } return false; } function readToken(forceRegexp) { if (!forceRegexp) tokStart = tokPos; else tokPos = tokStart + 1; if (options.locations) tokStartLoc = new line_loc_t; if (forceRegexp) return readRegexp(); if (tokPos >= inputLen) return finishToken(_eof); var code = input.charCodeAt(tokPos); if (isIdentifierStart(code) || code === 92 ) return readWord(); var tok = getTokenFromCode(code); if (tok === false) { var ch = String.fromCharCode(code); if (ch === "\\" || nonASCIIidentifierStart.test(ch)) return readWord(); raise(tokPos, "Unexpected character '" + ch + "'"); } return tok; } function finishOp(type, size) { var str = input.slice(tokPos, tokPos + size); tokPos += size; finishToken(type, str); } function readRegexp() { var content = "", escaped, inClass, start = tokPos; for (;;) { if (tokPos >= inputLen) raise(start, "Unterminated regular expression"); var ch = input.charAt(tokPos); if (newline.test(ch)) raise(start, "Unterminated regular expression"); if (!escaped) { if (ch === "[") inClass = true; else if (ch === "]" && inClass) inClass = false; else if (ch === "/" && !inClass) break; escaped = ch === "\\"; } else escaped = false; ++tokPos; } var content = input.slice(start, tokPos); ++tokPos; var mods = readWord1(); if (mods && !/^[gmsiy]*$/.test(mods)) raise(start, "Invalid regexp flag"); try { var value = new RegExp(content, mods); } catch (e) { if (e instanceof SyntaxError) raise(start, e.message); raise(e); } return finishToken(_regexp, value); } function readInt(radix, len) { var start = tokPos, total = 0; for (var i = 0, e = len == null ? Infinity : len; i < e; ++i) { var code = input.charCodeAt(tokPos), val; if (code >= 97) val = code - 97 + 10; else if (code >= 65) val = code - 65 + 10; else if (code >= 48 && code <= 57) val = code - 48; else val = Infinity; if (val >= radix) break; ++tokPos; total = total * radix + val; } if (tokPos === start || len != null && tokPos - start !== len) return null; return total; } function readHexNumber() { tokPos += 2; var val = readInt(16); if (val == null) raise(tokStart + 2, "Expected hexadecimal number"); if (isIdentifierStart(input.charCodeAt(tokPos))) raise(tokPos, "Identifier directly after number"); return finishToken(_num, val); } function readNumber(startsWithDot) { var start = tokPos, isFloat = false, octal = input.charCodeAt(tokPos) === 48; if (!startsWithDot && readInt(10) === null) raise(start, "Invalid number"); if (input.charCodeAt(tokPos) === 46) { ++tokPos; readInt(10); isFloat = true; } var next = input.charCodeAt(tokPos); if (next === 69 || next === 101) { next = input.charCodeAt(++tokPos); if (next === 43 || next === 45) ++tokPos; if (readInt(10) === null) raise(start, "Invalid number"); isFloat = true; } if (isIdentifierStart(input.charCodeAt(tokPos))) raise(tokPos, "Identifier directly after number"); var str = input.slice(start, tokPos), val; if (isFloat) val = parseFloat(str); else if (!octal || str.length === 1) val = parseInt(str, 10); else if (/[89]/.test(str) || strict) raise(start, "Invalid number"); else val = parseInt(str, 8); return finishToken(_num, val); } function readString(quote) { tokPos++; var out = ""; for (;;) { if (tokPos >= inputLen) raise(tokStart, "Unterminated string constant"); var ch = input.charCodeAt(tokPos); if (ch === quote) { ++tokPos; return finishToken(_string, out); } if (ch === 92) { ch = input.charCodeAt(++tokPos); var octal = /^[0-7]+/.exec(input.slice(tokPos, tokPos + 3)); if (octal) octal = octal[0]; while (octal && parseInt(octal, 8) > 255) octal = octal.slice(0, -1); if (octal === "0") octal = null; ++tokPos; if (octal) { if (strict) raise(tokPos - 2, "Octal literal in strict mode"); out += String.fromCharCode(parseInt(octal, 8)); tokPos += octal.length - 1; } else { switch (ch) { case 110: out += "\n"; break; case 114: out += "\r"; break; case 120: out += String.fromCharCode(readHexChar(2)); break; case 117: out += String.fromCharCode(readHexChar(4)); break; case 85: out += String.fromCharCode(readHexChar(8)); break; case 116: out += "\t"; break; case 98: out += "\b"; break; case 118: out += "\u000b"; break; case 102: out += "\f"; break; case 48: out += "\0"; break; case 13: if (input.charCodeAt(tokPos) === 10) ++tokPos; case 10: if (options.locations) { tokLineStart = tokPos; ++tokCurLine; } break; default: out += String.fromCharCode(ch); break; } } } else { if (ch === 13 || ch === 10 || ch === 8232 || ch === 8233) raise(tokStart, "Unterminated string constant"); out += String.fromCharCode(ch); ++tokPos; } } } function readHexChar(len) { var n = readInt(16, len); if (n === null) raise(tokStart, "Bad character escape sequence"); return n; } var containsEsc; function readWord1() { containsEsc = false; var word, first = true, start = tokPos; for (;;) { var ch = input.charCodeAt(tokPos); if (isIdentifierChar(ch)) { if (containsEsc) word += input.charAt(tokPos); ++tokPos; } else if (ch === 92) { if (!containsEsc) word = input.slice(start, tokPos); containsEsc = true; if (input.charCodeAt(++tokPos) != 117) raise(tokPos, "Expecting Unicode escape sequence \\uXXXX"); ++tokPos; var esc = readHexChar(4); var escStr = String.fromCharCode(esc); if (!escStr) raise(tokPos - 1, "Invalid Unicode escape"); if (!(first ? isIdentifierStart(esc) : isIdentifierChar(esc))) raise(tokPos - 4, "Invalid Unicode escape"); word += escStr; } else { break; } first = false; } return containsEsc ? word : input.slice(start, tokPos); } function readWord() { var word = readWord1(); var type = _name; if (!containsEsc && isKeyword(word)) type = keywordTypes[word]; return finishToken(type, word); } function next() { lastStart = tokStart; lastEnd = tokEnd; lastEndLoc = tokEndLoc; readToken(); } function setStrict(strct) { strict = strct; tokPos = tokStart; if (options.locations) { while (tokPos < tokLineStart) { tokLineStart = input.lastIndexOf("\n", tokLineStart - 2) + 1; --tokCurLine; } } skipSpace(); readToken(); } function node_t() { this.type = null; this.start = tokStart; this.end = null; } function node_loc_t() { this.start = tokStartLoc; this.end = null; if (sourceFile !== null) this.source = sourceFile; } function startNode() { var node = new node_t(); if (options.locations) node.loc = new node_loc_t(); if (options.directSourceFile) node.sourceFile = options.directSourceFile; if (options.ranges) node.range = [tokStart, 0]; return node; } function startNodeFrom(other) { var node = new node_t(); node.start = other.start; if (options.locations) { node.loc = new node_loc_t(); node.loc.start = other.loc.start; } if (options.ranges) node.range = [other.range[0], 0]; return node; } function finishNode(node, type) { node.type = type; node.end = lastEnd; if (options.locations) node.loc.end = lastEndLoc; if (options.ranges) node.range[1] = lastEnd; return node; } function isUseStrict(stmt) { return options.ecmaVersion >= 5 && stmt.type === "ExpressionStatement" && stmt.expression.type === "Literal" && stmt.expression.value === "use strict"; } function eat(type) { if (tokType === type) { next(); return true; } } function canInsertSemicolon() { return !options.strictSemicolons && (tokType === _eof || tokType === _braceR || newline.test(input.slice(lastEnd, tokStart))); } function semicolon() { if (!eat(_semi) && !canInsertSemicolon()) unexpected(); } function expect(type) { if (tokType === type) next(); else unexpected(); } function unexpected() { raise(tokStart, "Unexpected token"); } function checkLVal(expr) { if (expr.type !== "Identifier" && expr.type !== "MemberExpression") raise(expr.start, "Assigning to rvalue"); if (strict && expr.type === "Identifier" && isStrictBadIdWord(expr.name)) raise(expr.start, "Assigning to " + expr.name + " in strict mode"); } function parseTopLevel(program) { lastStart = lastEnd = tokPos; if (options.locations) lastEndLoc = new line_loc_t; inFunction = strict = null; labels = []; readToken(); var node = program || startNode(), first = true; if (!program) node.body = []; while (tokType !== _eof) { var stmt = parseStatement(); node.body.push(stmt); if (first && isUseStrict(stmt)) setStrict(true); first = false; } return finishNode(node, "Program"); } var loopLabel = {kind: "loop"}, switchLabel = {kind: "switch"}; function parseStatement() { if (tokType === _slash || tokType === _assign && tokVal == "/=") readToken(true); var starttype = tokType, node = startNode(); switch (starttype) { case _break: case _continue: next(); var isBreak = starttype === _break; if (eat(_semi) || canInsertSemicolon()) node.label = null; else if (tokType !== _name) unexpected(); else { node.label = parseIdent(); semicolon(); } for (var i = 0; i < labels.length; ++i) { var lab = labels[i]; if (node.label == null || lab.name === node.label.name) { if (lab.kind != null && (isBreak || lab.kind === "loop")) break; if (node.label && isBreak) break; } } if (i === labels.length) raise(node.start, "Unsyntactic " + starttype.keyword); return finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement"); case _debugger: next(); semicolon(); return finishNode(node, "DebuggerStatement"); case _do: next(); labels.push(loopLabel); node.body = parseStatement(); labels.pop(); expect(_while); node.test = parseParenExpression(); semicolon(); return finishNode(node, "DoWhileStatement"); case _for: next(); labels.push(loopLabel); expect(_parenL); if (tokType === _semi) return parseFor(node, null); if (tokType === _var) { var init = startNode(); next(); parseVar(init, true); finishNode(init, "VariableDeclaration"); if (init.declarations.length === 1 && eat(_in)) return parseForIn(node, init); return parseFor(node, init); } var init = parseExpression(false, true); if (eat(_in)) {checkLVal(init); return parseForIn(node, init);} return parseFor(node, init); case _function: next(); return parseFunction(node, true); case _if: next(); node.test = parseParenExpression(); node.consequent = parseStatement(); node.alternate = eat(_else) ? parseStatement() : null; return finishNode(node, "IfStatement"); case _return: if (!inFunction && !options.allowReturnOutsideFunction) raise(tokStart, "'return' outside of function"); next(); if (eat(_semi) || canInsertSemicolon()) node.argument = null; else { node.argument = parseExpression(); semicolon(); } return finishNode(node, "ReturnStatement"); case _switch: next(); node.discriminant = parseParenExpression(); node.cases = []; expect(_braceL); labels.push(switchLabel); for (var cur, sawDefault; tokType != _braceR;) { if (tokType === _case || tokType === _default) { var isCase = tokType === _case; if (cur) finishNode(cur, "SwitchCase"); node.cases.push(cur = startNode()); cur.consequent = []; next(); if (isCase) cur.test = parseExpression(); else { if (sawDefault) raise(lastStart, "Multiple default clauses"); sawDefault = true; cur.test = null; } expect(_colon); } else { if (!cur) unexpected(); cur.consequent.push(parseStatement()); } } if (cur) finishNode(cur, "SwitchCase"); next(); labels.pop(); return finishNode(node, "SwitchStatement"); case _throw: next(); if (newline.test(input.slice(lastEnd, tokStart))) raise(lastEnd, "Illegal newline after throw"); node.argument = parseExpression(); semicolon(); return finishNode(node, "ThrowStatement"); case _try: next(); node.block = parseBlock(); node.handler = null; if (tokType === _catch) { var clause = startNode(); next(); expect(_parenL); clause.param = parseIdent(); if (strict && isStrictBadIdWord(clause.param.name)) raise(clause.param.start, "Binding " + clause.param.name + " in strict mode"); expect(_parenR); clause.guard = null; clause.body = parseBlock(); node.handler = finishNode(clause, "CatchClause"); } node.guardedHandlers = empty; node.finalizer = eat(_finally) ? parseBlock() : null; if (!node.handler && !node.finalizer) raise(node.start, "Missing catch or finally clause"); return finishNode(node, "TryStatement"); case _var: next(); parseVar(node); semicolon(); return finishNode(node, "VariableDeclaration"); case _while: next(); node.test = parseParenExpression(); labels.push(loopLabel); node.body = parseStatement(); labels.pop(); return finishNode(node, "WhileStatement"); case _with: if (strict) raise(tokStart, "'with' in strict mode"); next(); node.object = parseParenExpression(); node.body = parseStatement(); return finishNode(node, "WithStatement"); case _braceL: return parseBlock(); case _semi: next(); return finishNode(node, "EmptyStatement"); default: var maybeName = tokVal, expr = parseExpression(); if (starttype === _name && expr.type === "Identifier" && eat(_colon)) { for (var i = 0; i < labels.length; ++i) if (labels[i].name === maybeName) raise(expr.start, "Label '" + maybeName + "' is already declared"); var kind = tokType.isLoop ? "loop" : tokType === _switch ? "switch" : null; labels.push({name: maybeName, kind: kind}); node.body = parseStatement(); labels.pop(); node.label = expr; return finishNode(node, "LabeledStatement"); } else { node.expression = expr; semicolon(); return finishNode(node, "ExpressionStatement"); } } } function parseParenExpression() { expect(_parenL); var val = parseExpression(); expect(_parenR); return val; } function parseBlock(allowStrict) { var node = startNode(), first = true, strict = false, oldStrict; node.body = []; expect(_braceL); while (!eat(_braceR)) { var stmt = parseStatement(); node.body.push(stmt); if (first && allowStrict && isUseStrict(stmt)) { oldStrict = strict; setStrict(strict = true); } first = false; } if (strict && !oldStrict) setStrict(false); return finishNode(node, "BlockStatement"); } function parseFor(node, init) { node.init = init; expect(_semi); node.test = tokType === _semi ? null : parseExpression(); expect(_semi); node.update = tokType === _parenR ? null : parseExpression(); expect(_parenR); node.body = parseStatement(); labels.pop(); return finishNode(node, "ForStatement"); } function parseForIn(node, init) { node.left = init; node.right = parseExpression(); expect(_parenR); node.body = parseStatement(); labels.pop(); return finishNode(node, "ForInStatement"); } function parseVar(node, noIn) { node.declarations = []; node.kind = "var"; for (;;) { var decl = startNode(); decl.id = parseIdent(); if (strict && isStrictBadIdWord(decl.id.name)) raise(decl.id.start, "Binding " + decl.id.name + " in strict mode"); decl.init = eat(_eq) ? parseExpression(true, noIn) : null; node.declarations.push(finishNode(decl, "VariableDeclarator")); if (!eat(_comma)) break; } return node; } function parseExpression(noComma, noIn) { var expr = parseMaybeAssign(noIn); if (!noComma && tokType === _comma) { var node = startNodeFrom(expr); node.expressions = [expr]; while (eat(_comma)) node.expressions.push(parseMaybeAssign(noIn)); return finishNode(node, "SequenceExpression"); } return expr; } function parseMaybeAssign(noIn) { var left = parseMaybeConditional(noIn); if (tokType.isAssign) { var node = startNodeFrom(left); node.operator = tokVal; node.left = left; next(); node.right = parseMaybeAssign(noIn); checkLVal(left); return finishNode(node, "AssignmentExpression"); } return left; } function parseMaybeConditional(noIn) { var expr = parseExprOps(noIn); if (eat(_question)) { var node = startNodeFrom(expr); node.test = expr; node.consequent = parseExpression(true); expect(_colon); node.alternate = parseExpression(true, noIn); return finishNode(node, "ConditionalExpression"); } return expr; } function parseExprOps(noIn) { return parseExprOp(parseMaybeUnary(), -1, noIn); } function parseExprOp(left, minPrec, noIn) { var prec = tokType.binop; if (prec != null && (!noIn || tokType !== _in)) { if (prec > minPrec) { var node = startNodeFrom(left); node.left = left; node.operator = tokVal; var op = tokType; next(); node.right = parseExprOp(parseMaybeUnary(), prec, noIn); var exprNode = finishNode(node, (op === _logicalOR || op === _logicalAND) ? "LogicalExpression" : "BinaryExpression"); return parseExprOp(exprNode, minPrec, noIn); } } return left; } function parseMaybeUnary() { if (tokType.prefix) { var node = startNode(), update = tokType.isUpdate; node.operator = tokVal; node.prefix = true; tokRegexpAllowed = true; next(); node.argument = parseMaybeUnary(); if (update) checkLVal(node.argument); else if (strict && node.operator === "delete" && node.argument.type === "Identifier") raise(node.start, "Deleting local variable in strict mode"); return finishNode(node, update ? "UpdateExpression" : "UnaryExpression"); } var expr = parseExprSubscripts(); while (tokType.postfix && !canInsertSemicolon()) { var node = startNodeFrom(expr); node.operator = tokVal; node.prefix = false; node.argument = expr; checkLVal(expr); next(); expr = finishNode(node, "UpdateExpression"); } return expr; } function parseExprSubscripts() { return parseSubscripts(parseExprAtom()); } function parseSubscripts(base, noCalls) { if (eat(_dot)) { var node = startNodeFrom(base); node.object = base; node.property = parseIdent(true); node.computed = false; return parseSubscripts(finishNode(node, "MemberExpression"), noCalls); } else if (eat(_bracketL)) { var node = startNodeFrom(base); node.object = base; node.property = parseExpression(); node.computed = true; expect(_bracketR); return parseSubscripts(finishNode(node, "MemberExpression"), noCalls); } else if (!noCalls && eat(_parenL)) { var node = startNodeFrom(base); node.callee = base; node.arguments = parseExprList(_parenR, false); return parseSubscripts(finishNode(node, "CallExpression"), noCalls); } else return base; } function parseExprAtom() { switch (tokType) { case _this: var node = startNode(); next(); return finishNode(node, "ThisExpression"); case _name: return parseIdent(); case _num: case _string: case _regexp: var node = startNode(); node.value = tokVal; node.raw = input.slice(tokStart, tokEnd); next(); return finishNode(node, "Literal"); case _null: case _true: case _false: var node = startNode(); node.value = tokType.atomValue; node.raw = tokType.keyword; next(); return finishNode(node, "Literal"); case _parenL: var tokStartLoc1 = tokStartLoc, tokStart1 = tokStart; next(); var val = parseExpression(); val.start = tokStart1; val.end = tokEnd; if (options.locations) { val.loc.start = tokStartLoc1; val.loc.end = tokEndLoc; } if (options.ranges) val.range = [tokStart1, tokEnd]; expect(_parenR); return val; case _bracketL: var node = startNode(); next(); node.elements = parseExprList(_bracketR, true, true); return finishNode(node, "ArrayExpression"); case _braceL: return parseObj(); case _function: var node = startNode(); next(); return parseFunction(node, false); case _new: return parseNew(); default: unexpected(); } } function parseNew() { var node = startNode(); next(); node.callee = parseSubscripts(parseExprAtom(), true); if (eat(_parenL)) node.arguments = parseExprList(_parenR, false); else node.arguments = empty; return finishNode(node, "NewExpression"); } function parseObj() { var node = startNode(), first = true, sawGetSet = false; node.properties = []; next(); while (!eat(_braceR)) { if (!first) { expect(_comma); if (options.allowTrailingCommas && eat(_braceR)) break; } else first = false; var prop = {key: parsePropertyName()}, isGetSet = false, kind; if (eat(_colon)) { prop.value = parseExpression(true); kind = prop.kind = "init"; } else if (options.ecmaVersion >= 5 && prop.key.type === "Identifier" && (prop.key.name === "get" || prop.key.name === "set")) { isGetSet = sawGetSet = true; kind = prop.kind = prop.key.name; prop.key = parsePropertyName(); if (tokType !== _parenL) unexpected(); prop.value = parseFunction(startNode(), false); } else unexpected(); if (prop.key.type === "Identifier" && (strict || sawGetSet)) { for (var i = 0; i < node.properties.length; ++i) { var other = node.properties[i]; if (other.key.name === prop.key.name) { var conflict = kind == other.kind || isGetSet && other.kind === "init" || kind === "init" && (other.kind === "get" || other.kind === "set"); if (conflict && !strict && kind === "init" && other.kind === "init") conflict = false; if (conflict) raise(prop.key.start, "Redefinition of property"); } } } node.properties.push(prop); } return finishNode(node, "ObjectExpression"); } function parsePropertyName() { if (tokType === _num || tokType === _string) return parseExprAtom(); return parseIdent(true); } function parseFunction(node, isStatement) { if (tokType === _name) node.id = parseIdent(); else if (isStatement) unexpected(); else node.id = null; node.params = []; var first = true; expect(_parenL); while (!eat(_parenR)) { if (!first) expect(_comma); else first = false; node.params.push(parseIdent()); } var oldInFunc = inFunction, oldLabels = labels; inFunction = true; labels = []; node.body = parseBlock(true); inFunction = oldInFunc; labels = oldLabels; if (strict || node.body.body.length && isUseStrict(node.body.body[0])) { for (var i = node.id ? -1 : 0; i < node.params.length; ++i) { var id = i < 0 ? node.id : node.params[i]; if (isStrictReservedWord(id.name) || isStrictBadIdWord(id.name)) raise(id.start, "Defining '" + id.name + "' in strict mode"); if (i >= 0) for (var j = 0; j < i; ++j) if (id.name === node.params[j].name) raise(id.start, "Argument name clash in strict mode"); } } return finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression"); } function parseExprList(close, allowTrailingComma, allowEmpty) { var elts = [], first = true; while (!eat(close)) { if (!first) { expect(_comma); if (allowTrailingComma && options.allowTrailingCommas && eat(close)) break; } else first = false; if (allowEmpty && tokType === _comma) elts.push(null); else elts.push(parseExpression(true)); } return elts; } function parseIdent(liberal) { var node = startNode(); if (liberal && options.forbidReserved == "everywhere") liberal = false; if (tokType === _name) { if (!liberal && (options.forbidReserved && (options.ecmaVersion === 3 ? isReservedWord3 : isReservedWord5)(tokVal) || strict && isStrictReservedWord(tokVal)) && input.slice(tokStart, tokEnd).indexOf("\\") == -1) raise(tokStart, "The keyword '" + tokVal + "' is reserved"); node.name = tokVal; } else if (liberal && tokType.keyword) { node.name = tokType.keyword; } else { unexpected(); } tokRegexpAllowed = false; next(); return finishNode(node, "Identifier"); } }); if (!acorn.version) acorn = null; } function parse(code, options) { return (global.acorn || acorn).parse(code, options); } var binaryOperators = { '+': '__add', '-': '__subtract', '*': '__multiply', '/': '__divide', '%': '__modulo', '==': '__equals', '!=': '__equals' }; var unaryOperators = { '-': '__negate', '+': '__self' }; var fields = Base.each( ['add', 'subtract', 'multiply', 'divide', 'modulo', 'equals', 'negate'], function(name) { this['__' + name] = '#' + name; }, { __self: function() { return this; } } ); Point.inject(fields); Size.inject(fields); Color.inject(fields); function __$__(left, operator, right) { var handler = binaryOperators[operator]; if (left && left[handler]) { var res = left[handler](right); return operator === '!=' ? !res : res; } switch (operator) { case '+': return left + right; case '-': return left - right; case '*': return left * right; case '/': return left / right; case '%': return left % right; case '==': return left == right; case '!=': return left != right; } } function $__(operator, value) { var handler = unaryOperators[operator]; if (value && value[handler]) return value[handler](); switch (operator) { case '+': return +value; case '-': return -value; } } function compile(code, options) { if (!code) return ''; options = options || {}; var insertions = []; function getOffset(offset) { for (var i = 0, l = insertions.length; i < l; i++) { var insertion = insertions[i]; if (insertion[0] >= offset) break; offset += insertion[1]; } return offset; } function getCode(node) { return code.substring(getOffset(node.range[0]), getOffset(node.range[1])); } function getBetween(left, right) { return code.substring(getOffset(left.range[1]), getOffset(right.range[0])); } function replaceCode(node, str) { var start = getOffset(node.range[0]), end = getOffset(node.range[1]), insert = 0; for (var i = insertions.length - 1; i >= 0; i--) { if (start > insertions[i][0]) { insert = i + 1; break; } } insertions.splice(insert, 0, [start, str.length - end + start]); code = code.substring(0, start) + str + code.substring(end); } function handleOverloading(node, parent) { switch (node.type) { case 'UnaryExpression': if (node.operator in unaryOperators && node.argument.type !== 'Literal') { var arg = getCode(node.argument); replaceCode(node, '$__("' + node.operator + '", ' + arg + ')'); } break; case 'BinaryExpression': if (node.operator in binaryOperators && node.left.type !== 'Literal') { var left = getCode(node.left), right = getCode(node.right), between = getBetween(node.left, node.right), operator = node.operator; replaceCode(node, '__$__(' + left + ',' + between.replace(new RegExp('\\' + operator), '"' + operator + '"') + ', ' + right + ')'); } break; case 'UpdateExpression': case 'AssignmentExpression': var parentType = parent && parent.type; if (!( parentType === 'ForStatement' || parentType === 'BinaryExpression' && /^[=!<>]/.test(parent.operator) || parentType === 'MemberExpression' && parent.computed )) { if (node.type === 'UpdateExpression') { var arg = getCode(node.argument), exp = '__$__(' + arg + ', "' + node.operator[0] + '", 1)', str = arg + ' = ' + exp; if (node.prefix) { str = '(' + str + ')'; } else if ( parentType === 'AssignmentExpression' || parentType === 'VariableDeclarator' || parentType === 'BinaryExpression' ) { if (getCode(parent.left || parent.id) === arg) str = exp; str = arg + '; ' + str; } replaceCode(node, str); } else { if (/^.=$/.test(node.operator) && node.left.type !== 'Literal') { var left = getCode(node.left), right = getCode(node.right), exp = left + ' = __$__(' + left + ', "' + node.operator[0] + '", ' + right + ')'; replaceCode(node, /^\(.*\)$/.test(getCode(node)) ? '(' + exp + ')' : exp); } } } break; } } function handleExports(node) { switch (node.type) { case 'ExportDefaultDeclaration': replaceCode({ range: [node.start, node.declaration.start] }, 'module.exports = '); break; case 'ExportNamedDeclaration': var declaration = node.declaration; var specifiers = node.specifiers; if (declaration) { var declarations = declaration.declarations; if (declarations) { declarations.forEach(function(dec) { replaceCode(dec, 'module.exports.' + getCode(dec)); }); replaceCode({ range: [ node.start, declaration.start + declaration.kind.length ] }, ''); } } else if (specifiers) { var exports = specifiers.map(function(specifier) { var name = getCode(specifier); return 'module.exports.' + name + ' = ' + name + '; '; }).join(''); if (exports) { replaceCode(node, exports); } } break; } } function walkAST(node, parent, paperFeatures) { if (node) { for (var key in node) { if (key !== 'range' && key !== 'loc') { var value = node[key]; if (Array.isArray(value)) { for (var i = 0, l = value.length; i < l; i++) { walkAST(value[i], node, paperFeatures); } } else if (value && typeof value === 'object') { walkAST(value, node, paperFeatures); } } } if (paperFeatures.operatorOverloading !== false) { handleOverloading(node, parent); } if (paperFeatures.moduleExports !== false) { handleExports(node); } } } function encodeVLQ(value) { var res = '', base64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; value = (Math.abs(value) << 1) + (value < 0 ? 1 : 0); while (value || !res) { var next = value & (32 - 1); value >>= 5; if (value) next |= 32; res += base64[next]; } return res; } var url = options.url || '', sourceMaps = options.sourceMaps, paperFeatures = options.paperFeatures || {}, source = options.source || code, offset = options.offset || 0, agent = paper.agent, version = agent.versionNumber, offsetCode = false, lineBreaks = /\r\n|\n|\r/mg, map; if (sourceMaps && (agent.chrome && version >= 30 || agent.webkit && version >= 537.76 || agent.firefox && version >= 23 || agent.node)) { if (agent.node) { offset -= 2; } else if (window && url && !window.location.href.indexOf(url)) { var html = document.getElementsByTagName('html')[0].innerHTML; offset = html.substr(0, html.indexOf(code) + 1).match( lineBreaks).length + 1; } offsetCode = offset > 0 && !( agent.chrome && version >= 36 || agent.safari && version >= 600 || agent.firefox && version >= 40 || agent.node); var mappings = ['AA' + encodeVLQ(offsetCode ? 0 : offset) + 'A']; mappings.length = (code.match(lineBreaks) || []).length + 1 + (offsetCode ? offset : 0); map = { version: 3, file: url, names:[], mappings: mappings.join(';AACA'), sourceRoot: '', sources: [url], sourcesContent: [source] }; } if ( paperFeatures.operatorOverloading !== false || paperFeatures.moduleExports !== false ) { walkAST(parse(code, { ranges: true, preserveParens: true, sourceType: 'module' }), null, paperFeatures); } if (map) { if (offsetCode) { code = new Array(offset + 1).join('\n') + code; } if (/^(inline|both)$/.test(sourceMaps)) { code += "\n//# sourceMappingURL=data:application/json;base64," + self.btoa(unescape(encodeURIComponent( JSON.stringify(map)))); } code += "\n//# sourceURL=" + (url || 'paperscript'); } return { url: url, source: source, code: code, map: map }; } function execute(code, scope, options) { paper = scope; var view = scope.getView(), tool = /\btool\.\w+|\s+on(?:Key|Mouse)(?:Up|Down|Move|Drag)\b/ .test(code) && !/\bnew\s+Tool\b/.test(code) ? new Tool() : null, toolHandlers = tool ? tool._events : [], handlers = ['onFrame', 'onResize'].concat(toolHandlers), params = [], args = [], func, compiled = typeof code === 'object' ? code : compile(code, options); code = compiled.code; function expose(scope, hidden) { for (var key in scope) { if ((hidden || !/^_/.test(key)) && new RegExp('([\\b\\s\\W]|^)' + key.replace(/\$/g, '\\$') + '\\b').test(code)) { params.push(key); args.push(scope[key]); } } } expose({ __$__: __$__, $__: $__, paper: scope, tool: tool }, true); expose(scope); code = 'var module = { exports: {} }; ' + code; var exports = Base.each(handlers, function(key) { if (new RegExp('\\s+' + key + '\\b').test(code)) { params.push(key); this.push('module.exports.' + key + ' = ' + key + ';'); } }, []).join('\n'); if (exports) { code += '\n' + exports; } code += '\nreturn module.exports;'; var agent = paper.agent; if (document && (agent.chrome || agent.firefox && agent.versionNumber < 40)) { var script = document.createElement('script'), head = document.head || document.getElementsByTagName('head')[0]; if (agent.firefox) code = '\n' + code; script.appendChild(document.createTextNode( 'document.__paperscript__ = function(' + params + ') {' + code + '\n}' )); head.appendChild(script); func = document.__paperscript__; delete document.__paperscript__; head.removeChild(script); } else { func = Function(params, code); } var exports = func && func.apply(scope, args); var obj = exports || {}; Base.each(toolHandlers, function(key) { var value = obj[key]; if (value) tool[key] = value; }); if (view) { if (obj.onResize) view.setOnResize(obj.onResize); view.emit('resize', { size: view.size, delta: new Point() }); if (obj.onFrame) view.setOnFrame(obj.onFrame); view.requestUpdate(); } return exports; } function loadScript(script) { if (/^text\/(?:x-|)paperscript$/.test(script.type) && PaperScope.getAttribute(script, 'ignore') !== 'true') { var canvasId = PaperScope.getAttribute(script, 'canvas'), canvas = document.getElementById(canvasId), src = script.src || script.getAttribute('data-src'), async = PaperScope.hasAttribute(script, 'async'), scopeAttribute = 'data-paper-scope'; if (!canvas) throw new Error('Unable to find canvas with id "' + canvasId + '"'); var scope = PaperScope.get(canvas.getAttribute(scopeAttribute)) || new PaperScope().setup(canvas); canvas.setAttribute(scopeAttribute, scope._id); if (src) { Http.request({ url: src, async: async, mimeType: 'text/plain', onLoad: function(code) { execute(code, scope, src); } }); } else { execute(script.innerHTML, scope, script.baseURI); } script.setAttribute('data-paper-ignore', 'true'); return scope; } } function loadAll() { Base.each(document && document.getElementsByTagName('script'), loadScript); } function load(script) { return script ? loadScript(script) : loadAll(); } if (window) { if (document.readyState === 'complete') { setTimeout(loadAll); } else { DomEvent.add(window, { load: loadAll }); } } return { compile: compile, execute: execute, load: load, parse: parse, calculateBinary: __$__, calculateUnary: $__ }; }.call(this); var paper = new (PaperScope.inject(Base.exports, { Base: Base, Numerical: Numerical, Key: Key, DomEvent: DomEvent, DomElement: DomElement, document: document, window: window, Symbol: SymbolDefinition, PlacedSymbol: SymbolItem }))(); if (paper.agent.node) { __webpack_require__(/*! ./node/extend.js */ 7)(paper); } if (true) { !(__WEBPACK_AMD_DEFINE_FACTORY__ = (paper), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); } else {} return paper; }.call(this, typeof self === 'object' ? self : null); /***/ }), /***/ "./node_modules/@turbowarp/json/src/index.js": /*!***************************************************!*\ !*** ./node_modules/@turbowarp/json/src/index.js ***! \***************************************************/ /*! exports provided: _parse, parse, stringify */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_parse", function() { return _parse; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "parse", function() { return parse; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "stringify", function() { return stringify; }); /** * @param {string} source * @returns {unknown} */ const _parse = (source) => { let index = 0; const lineInfo = () => { let line = 0; let column = 0; for (let i = 0; i < index; i++) { if (source[i] === '\n') { line++; column = 0; } else { column++; } } return { line: line + 1, column: column + 1 }; }; const error = (message) => { const { line, column } = lineInfo(); throw new SyntaxError( `${message} (Line ${line} Column ${column})` ); }; const charAt = (index) => { if (index >= source.length) { error('Unexpected end of input'); } return source[index]; }; const currentChar = () => charAt(index); const next = () => { index++; }; const expect = (char) => { if (currentChar() !== char) { error(`Expected '${char}' but found '${currentChar()}'`); } next(); }; const peek = (length = 1, offset = 1) => { if (index + offset + length > source.length) { return ''; } if (length === 1) { return charAt(index + offset); } let result = ''; for (let i = 0; i < length; i++) { result += charAt(index + offset + i); } return result; }; const skipWhitespaceAndComments = () => { while (true) { if (/\s/.test(currentChar())) { next(); } else if (peek(2, 0) === '//') { next(); // consume / next(); // consume / while (currentChar() !== '\n') { next(); } } else if (peek(2, 0) === '/*') { next(); // consume / next(); // consume * while (peek(2, 0) !== '*/') { next(); } next(); // consume * next(); // consume / } else { break; } } }; const parseValue = () => { skipWhitespaceAndComments(); const char = currentChar(); switch (char) { case '"': return parseString(); case '{': return parseObject(); case '[': return parseList(); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '-': return parseNumber(); default: return parseWord(); } }; const parseWord = () => { if (peek(4, 0) === 'null') { for (let i = 0; i < 4; i++) { next(); } return null; } if (peek(4, 0) === 'true') { for (let i = 0; i < 4; i++) { next(); } return true; } if (peek(5, 0) === 'false') { for (let i = 0; i < 5; i++) { next(); } return false; } // Non-standard extensions if (peek(8, 0) === 'Infinity') { for (let i = 0; i < 8; i++) { next(); } return Infinity; } if (peek(3, 0) === 'NaN') { for (let i = 0; i < 3; i++) { next(); } return NaN; } error(`Unexpected character '${currentChar()}'`); }; const parseNumber = () => { // Non-standard extension if (peek(9, 0) === '-Infinity') { for (let i = 0; i < 9; i++) { next(); } return -Infinity; } let number = ''; while (true) { number += currentChar(); if (/[\d.e+-]/i.test(peek())) { next(); } else { break; } } next(); const value = +number; if (Number.isNaN(value)) { error(`Not a number: ${number}`); } return value; }; const parseString = () => { expect('"'); let result = ''; if (currentChar() === '"') { next(); return ''; } while (true) { const char = currentChar(); if (char === '\\') { next(); switch (currentChar()) { case '"': result += '"'; break; case '/': result += '/'; break; case '\\': result += '\\'; break; case 'b': result += '\b'; break; case 'f': result += '\f'; break; case 'n': result += '\n'; break; case 'r': result += '\r'; break; case 't': result += '\t'; break; case 'u': { let hexString = ''; for (let i = 0; i < 4; i++) { next(); const nextChar = currentChar(); if (!/[0-9a-f]/i.test(nextChar)) { error(`Invalid hex code: ${nextChar}`); } hexString += nextChar; } const hexNumber = Number.parseInt(hexString, 16); const letter = String.fromCharCode(hexNumber); result += letter; break; } default: error(`Invalid escape code: \\${currentChar()}`); } } else { result += char; } if (peek() === '"') { break; } next(); } next(); expect('"'); return result; }; const parseList = () => { expect('['); skipWhitespaceAndComments(); const result = []; while (true) { skipWhitespaceAndComments(); if (currentChar() === ']') { break; } const value = parseValue(); result.push(value); skipWhitespaceAndComments(); if (currentChar() === ',') { next(); } else { break; } } expect(']'); return result; }; const parseObject = () => { expect('{'); skipWhitespaceAndComments(); const result = {}; while (true) { skipWhitespaceAndComments(); if (currentChar() === '}') { break; } const key = parseString(); skipWhitespaceAndComments(); expect(':'); const value = parseValue(); result[key] = value; skipWhitespaceAndComments(); if (currentChar() === ',') { next(); } else { break; } } expect('}'); return result; }; return parseValue(); }; /** * @param {string} source * @returns {unknown} */ const parse = (source) => { try { return JSON.parse(source); } catch (e1) { try { return _parse(source); } catch (e2) { // The error from JSON.parse is probably more useful. throw e1; } } }; /** * @param {unknown} object * @returns {string} */ const stringify = (object) => { if (typeof object === 'string') { return JSON.stringify(object); } if (typeof object === 'number' || typeof object === 'boolean') { // Difference from regular JSON: [-]Infinity and NaN will be sanitized as-is return object.toString(); } if (object === null || typeof object === 'undefined' || typeof object === 'symbol') { return 'null'; } if (Array.isArray(object)) { return `[${object.map((i) => stringify(i)).join(',')}]`; } if (typeof object === 'object') { let result = '{'; let isFirstItem = true; const keys = Object.keys(object); for (let i = 0; i < keys.length; i++) { const key = keys[i]; const value = object[key]; if (typeof value !== 'undefined') { if (!isFirstItem) { result += ','; } result += `${JSON.stringify(key)}:${stringify(value)}`; isFirstItem = false; } } result += '}'; return result; } if (typeof object === 'bigint') { throw new TypeError('Can not stringify bigint'); } throw new TypeError(`Can not stringify: ${object}`); }; /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/locales/editor-msgs.js": /*!*********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/locales/editor-msgs.js ***! \*********************************************************************/ /*! exports provided: default */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); // GENERATED FILE: /* harmony default export */ __webpack_exports__["default"] = (JSON.parse('{"ab":{"gui.alerts.tryAgain":"Даҽазнык игәашәҭ","gui.alerts.download":"Иҭыгатәуп","gui.connection.reconnect":"Даҽазнык аҿакра","gui.backpack.costumeLabel":"акостиум","gui.backpack.soundLabel":"абжьы","gui.backpack.scriptLabel":"апрограмма","gui.backpack.spriteLabel":"анагӡаҩ","gui.backpack.header":"Абӷакыдҵа","gui.backpack.errorBackpack":"Абӷакыдҵа аҭагалараан агха","gui.backpack.loadingBackpack":"Аҭагалара...","gui.backpack.more":"Иҵегь","gui.backpack.emptyBackpack":"Абӷакыдҵа ҭацәуп","gui.unsupportedBrowser.label":"Абраузер аднакылом","gui.cards.all-tutorials":"Ахархәагақәа","gui.cards.shrink":"Еикәарҳәтәуп","gui.cards.expand":"Еиҵыхтәуп","gui.cards.close":"Иарктәуп","gui.cards.more-things-to-try":"Игәашәҭ егьырҭ алшарақәа!","gui.cards.see-more":"Еилкаатәуп еиҳаны","gui.comingSoon.message1":"Шәгәы шәырҭынч, ари ҳара аус адулара ҳаҿуп {emoji}","gui.comingSoon.message2":"Иаарласны...","gui.comingSoon.message3":"Ари, ҳара аус адулара ҳаҿуп {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Аиҿартәырақәа ԥшаам","gui.connection.auto-scanning.prescan":"Аиҿартәыра ааигәа иҟашәҵа, нас шәалага аԥшаара.","gui.connection.auto-scanning.pressbutton":"Аиҿартәыра аҟны шәақәыӷәӷәа акнопка.","gui.connection.auto-scanning.start-search":"Иалагатәуп аԥшаара","gui.connection.connecting-searchbutton":"Аԥшаара...","gui.connection.auto-scanning.try-again":"Игәаҭатәуп иҵегь","gui.connection.connected":"Аимадара шьақәыргылоуп","gui.connection.disconnect":"Аимадара ықәгатәуп","gui.connection.go-to-editor":"Ииастәуп Аредактор ахь","gui.connection.connecting-cancelbutton":"Аимадара...","gui.connection.error.errorMessage":"Уаҳ, аусқәа ишахәҭам ицеит.","gui.connection.error.tryagainbutton":"Игәаҭатәуп иҵегь","gui.connection.error.helpbutton":"Ацхыраара","gui.connection.peripheral-name-label":"Аиҿартәыра ахьӡ","gui.connection.connect":"Аимадара шьақәыргылатәуп","gui.connection.scanning.lookingforperipherals":"Аиҿартәырақәа рыԥшаара цоит","gui.connection.scanning.noPeripheralsFound":"Аиҿартәырақәа ԥшаам","gui.connection.scanning.instructions":"Иалышәх аиҿартәыра хыхьтәи асиа аҟынтәи.","gui.connection.search":"Ирҿыцтәуп","gui.connection.unavailable.installscratchlink":"Агәра жәга, апрограмма Scratch Link шықәыргылои аусура ишаҿуи ","gui.connection.unavailable.enablebluetooth":"Bluetooth шаҿаку гәашәҭ","gui.connection.unavailable.tryagainbutton":"Игәаҭатәуп иҵегь","gui.connection.unavailable.helpbutton":"Ацхыраара","gui.controls.go":"Ԥхьаҟа","gui.controls.stop":"Иаанкылатәуп","gui.crashMessage.label":"Уаҳ! Аусқәа иашамкәа ицеит.","gui.crashMessage.errorNumber":"Шәара шәыгха арегистрациатә код {errorId}","gui.crashMessage.reload":"Аиҭадәықәҵара","gui.customProcedures.myblockModalTitle":"Иаԥҵатәуп аблок","gui.customProcedures.addAnInputNumberText":"Иацҵатәуп аҵакы","gui.customProcedures.numberTextType":"ахыԥхьаӡара ма атекст","gui.customProcedures.addAnInputBoolean":"Иацҵатәуп аҵакы","gui.customProcedures.booleanType":"алогикатә","gui.customProcedures.addALabel":"Иацҵатәуп аҵаҩра","gui.customProcedures.runWithoutScreenRefresh":"Идәықәҵатәуп аекран мырҿыцқәа","gui.customProcedures.cancel":"Иаҟәыхтәуп","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Ахырхарҭа","gui.directionPicker.rotationStyles.allAround":"Иргьежьтәуп","gui.directionPicker.rotationStyles.leftRight":"Армарахь/Арӷьарахь","gui.directionPicker.rotationStyles.dontRotate":"Иргьежьтәӡам","gui.gui.addExtension":"Иацҵатәуп арҭбаара","gui.gui.codeTab":"Акод","gui.gui.backdropsTab":"Аҿаԥшырақәа","gui.gui.costumesTab":"Акостиумқәа","gui.gui.soundsTab":"Абжьқәа","gui.extensionLibrary.comingSoon":"Иаарласны...","gui.extensionLibrary.requires":"Иаҭахуп","gui.extensionLibrary.collaboration":"Аус рыцутәуп","gui.library.filterPlaceholder":"Аԥшаара","gui.library.allTag":"Зегьы","gui.loader.headline":"Апроект аҭагалара","gui.loader.creating":"Иаԥҵатәуп апроект","gui.authorInfo.byUser":"{username}и(л)ҟынтә","gui.menuBar.seeProjectPage":"Иахәаԥштәуп апроект адаҟьа","gui.menuBar.LanguageSelector":"абызшәа алхра","gui.menuBar.tutorialsLibrary":"Ахархәагақәа","gui.menuBar.restoreSprite":"Дырхынҳәтәуп Анагӡаҩ","gui.menuBar.restoreSound":"Ирхынҳәтәуп Абжьы","gui.menuBar.restoreCostume":"Ирхынҳәтәуп Акостиум","gui.menuBar.restore":"Ирхынҳәтәуп","gui.menuBar.saveNow":"Еиқәырхатәуп абыржәы","gui.menuBar.saveAsCopy":"Еиқәырхатәуп акопиа ҳасабла","gui.menuBar.remix":"Аремикс","gui.menuBar.new":"Аҿыц","gui.menuBar.file":"Афаил","gui.menuBar.downloadToComputer":"Еиқәырхатәуп шәкомпиутер аҟны","gui.menuBar.edit":"Аредакциазура","gui.menuBar.turboModeOff":"Иаҿыхтәуп Turbo арежим","gui.menuBar.turboModeOn":"Иаҿактәуп Turbo арежим","gui.gui.projectTitlePlaceholder":"Апроект ахьӡ","gui.menuBar.isShared":"Асаит иҭагалоуп","gui.menuBar.share":"Асаит иҭагалатәуп","gui.modal.help":"Ацхыраара","gui.modal.back":"Шьҭахьҟа","gui.monitor.listMonitor.empty":"(иҭацәуп)","gui.monitor.listMonitor.listLength":"аура {length}","gui.monitor.contextMenu.default":"истандарту аԥшра","gui.monitor.contextMenu.large":"идуу аԥшра","gui.monitor.contextMenu.slider":"аслаидер","gui.monitor.contextMenu.sliderRange":"иԥсахтәуп аслаидер адиапазон","gui.monitor.contextMenu.import":"аимпорт","gui.monitor.contextMenu.export":"аекспорт","gui.monitor.contextMenu.hide":"аҽыҵәахра","gui.playButton.play":"Иарҳәатәуп","gui.playButton.stop":"Иаанкылатәуп","gui.gui.variableScopeOptionAllSprites":"Анагӡаҩцәа зегьы рзы","gui.gui.variableScopeOptionSpriteOnly":"Абри анагӡаҩ мацара изы","gui.gui.cloudVariableOption":"Аԥсҭҳәатә ҽеиҭак (асервер иҭагалоуп)","gui.gui.variablePromptAllSpritesMessage":"Ари аҽеиҭак анагӡаҩцәа зегь ирызкуп.","gui.gui.listPromptAllSpritesMessage":"Ари асиа, анагӡаҩцәа зегьы ирызкуп","gui.prompt.cancel":"Иаҟәыхтәуп","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Иаанкылатәуп","gui.playbackStep.playMsg":"Иарҳәатәуп","gui.playbackStep.loadingMsg":"Аҭагалара...","gui.playbackStep.saveMsg":"Еиқәырхатәуп","gui.playbackStep.reRecordMsg":"Ҿыц иҭаҩтәуп","gui.recordModal.title":"Иҭаҩтәуп Абжьы","gui.recordingStep.beginRecord":"Шәалага аҭаҩра, ҵаҟатәи акнопка ақәыӷәӷәарала","gui.recordingStep.permission":"{arrow} Шәмикрофон ахархәараз, ҳара иҳамазароуп шәара шәзин","gui.recordingStep.stop":"Иаанкылатәуп аҭаҩра","gui.recordingStep.record":"Иҭаҩтәуп","gui.sliderModal.min":"Иминималу аҵакы","gui.sliderModal.max":"Имаксималу аҵакы","gui.sliderModal.title":"Иԥсахтәуп аслаидер адиапазон","gui.sliderPrompt.cancel":"Аҟәыхра","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Абжьы","gui.soundEditor.play":"Иарҳәатәуп","gui.soundEditor.stop":"Иаанкылатәуп","gui.soundEditor.copy":"Акопиа ахыхтәуп","gui.soundEditor.paste":"Иҭаргылатәуп","gui.soundEditor.copyToNew":"Акопиа Абыжь Ҿыц ахь","gui.soundEditor.delete":"Ианыхтәуп","gui.soundEditor.save":"Еиқәырхатәуп","gui.soundEditor.undo":"Иаҟәыхтәуп","gui.soundEditor.redo":"Ирхынҳәтәуп","gui.soundEditor.faster":"Ирласны","gui.soundEditor.slower":"Имырласкәа","gui.soundEditor.echo":"Аныҩбжьы","gui.soundEditor.robot":"Аробот","gui.soundEditor.louder":"Абжьы ардура","gui.soundEditor.softer":"Абжьы армаҷра","gui.soundEditor.reverse":"Еиҵыхтәуп","gui.soundEditor.fadeOut":"Ашьшьыҳәа арԥсыҽра","gui.soundEditor.fadeIn":"Ашьшьыҳәа арӷәӷәара ","gui.soundEditor.mute":"Иқәгатәуп Абжьы","gui.SpriteInfo.spritePlaceholder":"Ахьӡ","gui.SpriteInfo.sprite":"Анагӡаҩ","gui.SpriteInfo.show":"Иаарԥштәуп","gui.SpriteInfo.size":"Ашәагаа","gui.spriteSelectorItem.contextMenuDuplicate":"адубликат","gui.spriteSelectorItem.contextMenuExport":"аекспорт","gui.spriteSelectorItem.contextMenuDelete":"ианыхтәуп","gui.spriteSelector.addSpriteFromLibrary":"Далхтәуп Анагӡаҩ","gui.spriteSelector.addSpriteFromPaint":"Иҭыхтәуп","gui.spriteSelector.addSpriteFromSurprise":"Асиурприз","gui.spriteSelector.addSpriteFromFile":"Дҭагалатәуп Анагӡаҩ","gui.stageHeader.stageSizeLarge":"Асцена ду","gui.stageHeader.stageSizeSmall":"Асцена маҷ","gui.stageHeader.stageSizeFull":"Ииастәуп аекран зегь арежим ахь","gui.stageHeader.stageSizeUnFull":"Иҭыҵтәуп аекран зегь арежим ","gui.stageHeader.fullscreenControl":"Аекран зегь арежим","gui.spriteSelector.addBackdropFromLibrary":"Иалхтәуп Аҿаԥшыра","gui.stageSelector.addBackdropFromPaint":"Иҭыхтәуп","gui.stageSelector.addBackdropFromSurprise":"Асиурприз","gui.stageSelector.addBackdropFromFile":"Иҭагалатәуп аҿаԥшыра","gui.stageSelector.stage":"Асцена","gui.stageSelector.backdrops":"Аҿаԥшырақәа","gui.telemetryOptIn.label":"Scratch аиӷьтәразы идәықәышәҵа астатистика","gui.telemetryOptIn.body1":"Scratch Акоманда азҿлымҳауп аилкаара, адунеи зегь аҟны Scratch ахархәашьа. Ари аус шәацхраарцаз, шәара ишәылшоит Scratch азин ашәҭарц, иара ахархәашьаз аинформациа автоматикала адәықәҵара.","gui.telemetryOptIn.body2":"Ҳара еизаҳго аинформациа азкуп: абызшәа, аблокқәа рхархәашьеи егьырҭ ахҭысқәеи, аиқәырхара, апроект аҭагалара. Ҳара ЕИЗАҲГОМ ихатәу аинформациа. Шәахәаԥш {privacyPolicyLink} иаҳа еиҳаны аилкаараз. ","gui.telemetryOptIn.privacyPolicyLink":"Аконфиденциалтә политика","gui.telemetryOptIn.optInText":" Scratch Team акоманда иазыцҳатәуп ахархәаразы сара исызку аинформациа","gui.telemetryOptIn.optInTooltip":"Ателеметриа аҿактәуп","gui.telemetryOptIn.optOutText":"Scratch Team акоманда иазыцҳатәӡам ахархәаразы сара исызку аинформациа","gui.telemetryOptIn.optOutTooltip":"Ателеметриа аҿыхтәуп","gui.telemetryOptIn.settingWasUpdated":"Шәара шәырхиара рҿыцын.","gui.telemetryOptIn.buttonClose":"Иарктәуп","gui.turboMode.active":"Турбо арежим","gui.webglModal.label":"Шәара шәбраузер иаднакылом WebGL.","gui.webglModal.webgllink":"WebGL аднакылом","gui.costumeLibrary.chooseABackdrop":"Иалхтәуп Аҿаԥшыра","gui.costumeLibrary.chooseACostume":"Иалхтәуп акостиум","gui.costumeTab.addBackdropFromLibrary":"Иалхтәуп Аҿаԥшыра ","gui.costumeTab.addCostumeFromLibrary":"Иалхтәуп акостиум","gui.costumeTab.addBlankCostume":"Иҭыхтәуп","gui.costumeTab.addSurpriseCostume":"Асиурприз","gui.costumeTab.addFileBackdrop":"Иҭагалатәуп Аҿаԥшыра","gui.costumeTab.addFileCostume":"Иҭагалатәуп акостиум","gui.extensionLibrary.chooseAnExtension":"Иалхтәуп ахарҭәаага","gui.extensionLibrary.extensionUrl":"Иҭажәгал арҭбаара а-URL ","gui.monitors.importListColumnPrompt":"Иарбан еиҵаҩу ихархәатәу (1- {numberOfColumns})? ","gui.recordingStep.alertMsg":"Иамуӡеит аҭаҩра алагара","gui.soundLibrary.chooseASound":"Иалхтәуп Абжьы","gui.soundTab.fileUploadSound":"Иҭагалатәуп Абжьы","gui.soundTab.surpriseSound":"Асиурприз","gui.soundTab.recordSound":"Иҭаҩтәуп","gui.soundTab.addSoundFromLibrary":"Иалхтәуп Абжьы","gui.spriteLibrary.chooseASprite":"Далхтәуп Анагӡаҩ","gui.tipsLibrary.tutorials":"Иалхтәуп ахархәага","gui.alerts.createsuccess":"Апроект ҿыц аԥҵоуп.","gui.alerts.createcopysuccess":"Апроект акопиа еиқәырхоуп.","gui.alerts.createremixsuccess":"Апроект аремикс еиқәырхоуп.","gui.alerts.creating":"Аҿыц аԥҵара...","gui.alerts.creatingCopy":"Апроект акопиа ахыхра...","gui.alerts.creatingRemix":"Апроект аремикс аԥҵара...","gui.alerts.creatingError":"Иамуӡеит апроект аԥҵара. Даҽазнык инашәыгӡа аԥҵара!","gui.alerts.savingError":"Апроект аиқәырхара ауам.","gui.alerts.savesuccess":"Апроект еиқәырхоуп.","gui.alerts.saving":"Апроект аиқәырхара...","gui.alerts.cloudInfo":"Ишәхашәмыршҭын, аԥсҭҳәатә ҽеиҭакқәа цифрақәа мацараз ауп, инбанзар ма исимволзар ауам. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Еиҳаны аилкаара.","gui.alerts.importing":"Аимпорт...","gui.defaultProject.variable":"исхатәу аҽеиҭак","gui.extension.music.name":"Амузыка","gui.extension.music.description":"Ихәмартәуп амаругақәеи адаулқәеи рҟны.","gui.extension.pen.name":"Акалам","gui.extension.pen.description":"Иҭышәхла анагӡаҩцәа рыла.","gui.extension.videosensing.name":"Авидео Аиҩдыраара","gui.extension.videosensing.description":"Авидеокамера аҟынтәи аиҭаҵра аиҩдыраара.","gui.extension.text2speech.name":"Атекст Ацәажәарахь","gui.extension.text2speech.description":"Шәпроектқәа аԥсы рхашәҵа бжьыла.","gui.extension.translate.name":"Еиҭагатәуп","gui.extension.translate.description":"Еиҭажәгала атекст егьырҭ абызшәақәа рахь.","gui.extension.makeymakey.description":"Иарбанзаалакь акы иалхтәуп ацаԥха.","gui.extension.microbit.description":"Шәпроектқәа адунеи иашәырдыр.","gui.extension.microbit.connectingMessage":"Аимадара","gui.extension.ev3.description":"Иаԥышәҵала аинтерактивтә роботқәеи егьырҭ аобиектқәеи.","gui.extension.ev3.connectingMessage":"Аҿакра. Агәра жәга, EV3  аҟны pin-код 1234 шықәыргылоу.   ","gui.extension.boost.description":"Аробот аԥсы ахашәҵа","gui.extension.boost.connectingMessage":"Аимадара","gui.extension.wedo2.description":"Иаԥышәҵала амоторқәеи асенсорқәеи рхархәарала.","gui.extension.wedo2.connectingMessage":"Аимадара","gui.extension.gdxfor.description":"Иашәоит агәҭасрақәеи арҳәазареи рымчқәеи, аиҭаҵрақәеи аргьежьрақәеи.","gui.extension.gdxfor.connectingMessage":"Аимадара","gui.libraryTags.all":"Зегьы","gui.libraryTags.animals":"Аԥстәқәа","gui.libraryTags.dance":"Акәашара","gui.libraryTags.effects":"Аеффектқәа","gui.libraryTags.fantasy":"Афантастика","gui.libraryTags.fashion":"Амода","gui.libraryTags.food":"Афатә","gui.libraryTags.indoors":"Ауада аҩныҵҟа","gui.libraryTags.loops":"Ациклқәа","gui.libraryTags.music":"Амузыка","gui.libraryTags.notes":"Азгәаҭақәа","gui.libraryTags.outdoors":"Адәахьы","gui.libraryTags.patterns":"Аузорқәа","gui.libraryTags.people":"Ауаа","gui.libraryTags.percussion":"Аперкуссиа","gui.libraryTags.space":"Акосмос","gui.libraryTags.sports":"Аспорт","gui.libraryTags.underwater":"Аӡаҵаҟатәи адунеи","gui.libraryTags.voice":"Абжьы","gui.libraryTags.wacky":"Ахеилагақәа","gui.libraryTags.animation":"Анимациа","gui.libraryTags.art":"Аҟазара","gui.libraryTags.games":"Ахәмаррақәа","gui.libraryTags.stories":"Аҭоурыхқәа","gui.libraryTags.letters":"Анбанқәа","gui.opcodeLabels.direction":"ахырхарҭа","gui.opcodeLabels.xposition":"x апозициа","gui.opcodeLabels.yposition":"y апозициа","gui.opcodeLabels.size":"ашәагаа","gui.opcodeLabels.costumename":"акостиум ахьӡ","gui.opcodeLabels.costumenumber":"акостиум аномер","gui.opcodeLabels.backdropname":"аҿаԥшыра ахьӡ","gui.opcodeLabels.backdropnumber":"аҿаԥшыра аномер","gui.opcodeLabels.volume":"абжьы адура","gui.opcodeLabels.tempo":"атемп","gui.opcodeLabels.answer":"аҭак","gui.opcodeLabels.loudness":"абжьы адура","gui.opcodeLabels.username":"ахархәаҩ ихьӡ","gui.opcodeLabels.year":"ашықәс","gui.opcodeLabels.month":"амза","gui.opcodeLabels.date":"арыцхә","gui.opcodeLabels.dayofweek":"амчыбжь амш","gui.opcodeLabels.hour":"асааҭ","gui.opcodeLabels.minute":"аминуҭ","gui.opcodeLabels.second":"асекунд","gui.opcodeLabels.timer":"атаимер","gui.sharedMessages.backdrop":"аҿаԥшыра {index}","gui.sharedMessages.costume":"акостиум {index}","gui.sharedMessages.sprite":"Анагӡаҩ {index}","gui.sharedMessages.pop":"апоп","gui.sharedMessages.replaceProjectWarning":"Иалаԥсахтәума абри апроект аҵанакы?","gui.sharedMessages.loadFromComputerTitle":"Иҭагалатәуп акомпиутер аҟынтәи","boost.color.any":"иарбанзаалакь аԥштәы","boost.color.black":"аиқәаҵәа","boost.color.blue":"жәҩангәыԥштәы","boost.color.green":"аиаҵәа","boost.color.red":"аҟаԥшь","boost.color.white":"ашкәакәа","boost.color.yellow":"аҩеижь","boost.getMotorPosition":"амотор [MOTOR_REPORTER_ID] апозициа ","boost.getTiltAngle":"арнаара акәакь [TILT_DIRECTION]","boost.motorDirection.backward":"анахь","boost.motorDirection.forward":"арахь","boost.motorDirection.reverse":"иԥсахтәуп ахырхарҭа","boost.motorOff":" амотор [MOTOR_ID] аҿыхтәуп","boost.motorOn":" амотор [MOTOR_ID] аҿактәуп","boost.motorOnFor":"иаҿактәуп амотор [MOTOR_ID] [DURATION] секундк ","boost.motorOnForRotation":"иаҿактәуп амотор [MOTOR_ID] [ROTATION]-нтә аргьежьра ала ","boost.seeingColor":"иаҳбома ақьырмыт [COLOR]? ","boost.setLightHue":"иқәыргылатәуп арлашага аԥштәы [HUE]","boost.setMotorDirection":"иқәыргылатәуп амотор [MOTOR_ID] ахырхарҭа [MOTOR_DIRECTION] аҟны  ","boost.setMotorPower":"иқәыргылатәуп [MOTOR_ID] аласра [POWER] % аҟны ","boost.tiltDirection.any":"иарбанзаалакь ","boost.tiltDirection.down":"алада","boost.tiltDirection.left":"армарахь","boost.tiltDirection.right":"арӷьарахь","boost.tiltDirection.up":"аҩада","boost.whenColor":"ақьырмыт [COLOR] анаҳбо","boost.whenTilted":"[TILT_DIRECTION_ANY] анырнаау","ev3.beepNote":"анота [NOTE] ихәмартәуп [TIME] сек","ev3.buttonPressed":"акнопка [PORT] иақәыӷәӷәоума?","ev3.getBrightness":"ажжара","ev3.getDistance":"ирыбжьоу","ev3.getMotorPosition":"амотор [PORT] апозициа","ev3.motorSetPower":"амотор [PORT] иқәыргылатәуп амчра [POWER] %","ev3.motorTurnClockwise":"амотор [PORT] ыргьежьтәуп арахь [TIME] сек","ev3.motorTurnCounterClockwise":"амотор [PORT] ыргьежьтәуп анахь [TIME] сек","ev3.whenBrightnessLessThan":"ажжара < [DISTANCE] анакәу","ev3.whenButtonPressed":"акнопка [PORT] ианақәыӷәӷәоу","ev3.whenDistanceLessThan":"ирыбжьоу < [DISTANCE] анакәу","gdxfor.getAcceleration":"аццакра [DIRECTION]","gdxfor.getForce":"амч","gdxfor.getSpin":"аргьежьра аласра [DIRECTION]","gdxfor.getTilt":"анаара акәакь [TILT] ","gdxfor.isFreeFalling":"икаҳауама?","gdxfor.isTilted":"ирнааума [TILT]?","gdxfor.pulled":"еиҵыхуп","gdxfor.pushed":"иақәыӷәӷәоуп","gdxfor.shaken":"ирҵысуп","gdxfor.startedFalling":"акаҳара иалагеит","gdxfor.tiltDirectionMenu.any":"иарбанзаалакь ","gdxfor.tiltDirectionMenu.back":"ашьҭахьҟатәи","gdxfor.tiltDirectionMenu.front":"аԥхьаҟатәи","gdxfor.tiltDirectionMenu.left":"армарахьтәи","gdxfor.tiltDirectionMenu.right":"арӷьарахьтәи","gdxfor.turnedFaceDown":"инарҳәуп хаҿыла алада","gdxfor.turnedFaceUp":"инарҳәуп хаҿыла аҩада","gdxfor.whenForcePushedOrPulled":"амч ҳзырбо асенсор [PUSH_PULL] анакәу","gdxfor.whenGesture":"[GESTURE] анакәу","gdxfor.whenTilted":"[TILT] анырнаау","makeymakey.downArrow":"ахыц алада","makeymakey.downArrowShort":"алада","makeymakey.leftArrow":"ахыц армарахь","makeymakey.leftArrowShort":"армарахь","makeymakey.rightArrow":"ахыц арӷьарахь","makeymakey.rightArrowShort":"арӷьарахь","makeymakey.spaceKey":"абжьажьга","makeymakey.upArrow":"ахыц аҩада","makeymakey.upArrowShort":"аҩада","makeymakey.whenKeyPressed":"аклавиша [KEY] ианақәыӷәӷәоу","makeymakey.whenKeysPressedInOrder":"еишьҭаргыланы [SEQUENCE] ақәыӷәӷәараан","microbit.buttonsMenu.any":"иарбанзаалакь","microbit.clearDisplay":"ирыцқьатәуп аекран","microbit.defaultTextToDisplay":"Салам!","microbit.displaySymbol":"иаарԥштәуп [MATRIX]","microbit.displayText":"иаарԥштәуп атекст [TEXT]","microbit.gesturesMenu.jumped":"иԥеит","microbit.gesturesMenu.moved":"инаскьагоуп","microbit.gesturesMenu.shaken":"идырҵысит","microbit.isButtonPressed":"акнопка [BTN] иақәыӷәӷәоума?","microbit.isTilted":"ирнааума [DIRECTION]?","microbit.pinStateMenu.off":"иаҿыхтәуп","microbit.pinStateMenu.on":"иаҿактәуп","microbit.tiltAngle":"арнаара акәакь [DIRECTION]","microbit.tiltDirectionMenu.any":"иарбанзаалакь","microbit.tiltDirectionMenu.back":"шьҭахьҟа","microbit.tiltDirectionMenu.front":"ԥхьаҟа","microbit.tiltDirectionMenu.left":"армарахь","microbit.tiltDirectionMenu.right":"арӷьарахь","microbit.whenButtonPressed":"акнопка [BTN] ианақәыӷәӷәоу","microbit.whenGesture":"[GESTURE] анакәу","microbit.whenPinConnected":"апин [PIN] анаҿаку","microbit.whenTilted":"[DIRECTION] анырнаау","music.categoryName":"Амузыка","music.changeTempo":"иԥсахтәуп атемп [TEMPO] ала","music.drumBass":"(2) Абасстә даул","music.drumBongo":"(13) Бонго","music.drumCabasa":"(15) Кабаса","music.drumClaves":"(9) Аклаве","music.drumClosedHiHat":"(6) Иарку хаи-хет","music.drumConga":"(14) Аконга","music.drumCowbell":"(11) Аҵәҵәабжьы","music.drumCrashCymbal":"(4) Асаанқәа рысра","music.drumCuica":"(18) Акуика","music.drumGuiro":"(16) Гуиро","music.drumHandClap":"(8) Анапеинҟьабжь","music.drumOpenHiHat":"(5) Иаарту хаи-хет","music.drumSideStick":"(3) Аганахьтәи амаа","music.drumSnare":"(1) Адаул хәыҷы","music.drumTambourine":"(7) Атамбурин","music.drumTriangle":"(12) Ахкәакь","music.drumVibraslap":"(17) Авибрациа ҟазҵо аслеп","music.drumWoodBlock":"(10) Амҿтәы шәындыҟәра хәҷы","music.getTempo":"атемп","music.instrumentBass":"(6) Абасс","music.instrumentBassoon":"(14) Афагот","music.instrumentCello":"(8) Авиолончель","music.instrumentChoir":"(15) Ахор","music.instrumentClarinet":"(10) Акларнет","music.instrumentElectricGuitar":"(5) Аелектрогитара","music.instrumentElectricPiano":"(2) Аелектро пианино","music.instrumentFlute":"(12) Афлеита","music.instrumentGuitar":"(4) Агитара","music.instrumentMarimba":"(19) Маримба","music.instrumentMusicBox":"(17) Амузыкатә шкатулка","music.instrumentOrgan":"(3) Ауарӷан","music.instrumentPiano":"(1) Афортепиано","music.instrumentPizzicato":"(7) Апаццикато","music.instrumentSaxophone":"(11) Асаксафон","music.instrumentSteelDrum":"(18) Аџыртә даул","music.instrumentSynthLead":"(20) Ихадоу асинтезатор","music.instrumentSynthPad":"(21) Асинтезатор Pad","music.instrumentTrombone":"(9) Атрамбон","music.instrumentVibraphone":"(16) Авибрафон","music.instrumentWoodenFlute":"(13) Амҿтәы флеита","music.midiPlayDrumForBeats":"ихәмартәуп адаулқәа [DRUM] рҟны [BEATS] битк","music.midiSetInstrument":"иԥсахтәуп амаруга [INSTRUMENT] ала","music.playDrumForBeats":"ихәмартәуп адаулқәа [DRUM] рҟны [BEATS] битк","music.playNoteForBeats":"анота [NOTE] ихәмартәуп [BEATS] тактк","music.restForBeats":"ааҭгылара аамҭала [BEATS] битк","music.setInstrument":"иқәыргылатәуп амаруга [INSTRUMENT] ","music.setTempo":"иқәыргылатәуп атемп [TEMPO] ","pen.categoryName":"Акалам","pen.changeColorParam":"иԥсахтәуп акалам [COLOR_PARAM][VALUE] ала","pen.changeHue":"иԥсахтәуп акалам аԥштәы [HUE] ала","pen.changeShade":"иԥсахтәуп акалам агага [SHADE] ала","pen.changeSize":"иԥсахтәуп акалам ашәагаа [SIZE] ала","pen.clear":"ианыхтәуп зегьы","pen.colorMenu.brightness":"ажжара","pen.colorMenu.color":"аԥштәы","pen.colorMenu.saturation":"аԥштәылгазаара","pen.colorMenu.transparency":"аҵәцара","pen.penDown":"акалам лашьҭтәуп","pen.penUp":"акалам иҩахатәуп","pen.setColor":"иқәыргылатәуп акалам аԥштәы [COLOR]","pen.setColorParam":"иқәыргылатәуп акалам [COLOR_PARAM] [VALUE] аҟны","pen.setHue":"иқәыргылатәуп акалам аԥштәы [HUE]","pen.setShade":"иқәыргылатәуп акалам агага [SHADE]","pen.setSize":"иқәыргылатәуп акалам ашәагаа [SIZE]","pen.stamp":"аштамп","text2speech.alto":"альт","text2speech.categoryName":"Атекст Арцәажәара","text2speech.defaultTextToSpeak":"салам","text2speech.giant":"агигант","text2speech.kitten":"ацгәы","text2speech.setLanguageBlock":"иқәыргылатәуп абызшәа [LANGUAGE]","text2speech.setVoiceBlock":"иқәыргылатәуп абжьы [VOICE]","text2speech.speakAndWaitBlock":"иҳәатәуп [WORDS]","text2speech.squeak":"аҷыжьбжьы","text2speech.tenor":"атенор","translate.categoryName":"Еиҭагатәуп","translate.defaultTextToTranslate":"салам","translate.translateBlock":"еиҭагатәуп [WORDS] [LANGUAGE] ахь","translate.viewerLanguage":"абызшәа","videoSensing.categoryName":"Авидео Аиҩдыраара","videoSensing.direction":"ахырхарҭа","videoSensing.motion":"аиҭаҵра","videoSensing.off":"иаҿыхтәуп","videoSensing.on":"иаҿактәуп","videoSensing.onFlipped":"иаҿактәуп шьҭахьҟала","videoSensing.setVideoTransparency":"иқәыргылатәуп авидео аҵәцара [TRANSPARENCY]","videoSensing.sprite":"анагӡаҩ","videoSensing.stage":"асцена","videoSensing.videoOn":"авидео [ATTRIBUTE] [SUBJECT] аҟны","videoSensing.videoToggle":"иаҿактәуп авидео [VIDEO_STATE] ","videoSensing.whenMotionGreaterThan":"авидео аласра > [REFERENCE] анакәу","wedo2.getDistance":"ирыбжьоу","wedo2.getTiltAngle":"арнаара акәакь [TILT_DIRECTION]","wedo2.isTilted":"ирнааума [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"анахь","wedo2.motorDirection.forward":"арахь","wedo2.motorDirection.reverse":"иԥсахтәуп ахырхарҭа","wedo2.motorId.a":"амотор A","wedo2.motorId.all":"амоторқәа зегьы","wedo2.motorId.b":"амотор B","wedo2.motorId.default":"амотор","wedo2.motorOff":"иаҿыхтәуп [MOTOR_ID] ","wedo2.motorOn":"иаҿактәуп [MOTOR_ID]","wedo2.motorOnFor":"иаҿактәуп [MOTOR_ID] [DURATION] сек","wedo2.playNoteFor":"анота [NOTE] ихәмартәуп [DURATION] сек","wedo2.setLightHue":"иқәыргылатәуп арлашага аԥштәы [HUE]","wedo2.setMotorDirection":"иқәыргылатәуп [MOTOR_ID] ахырхарҭа [MOTOR_DIRECTION] аҟны","wedo2.startMotorPower":"иқәыргылатәуп [MOTOR_ID] амчра [POWER] аҟны","wedo2.tiltDirection.any":"иарбанзаалакь ","wedo2.tiltDirection.down":"алада","wedo2.tiltDirection.left":"армарахь","wedo2.tiltDirection.right":"арӷьарахь","wedo2.tiltDirection.up":"аҩада","wedo2.whenDistance":"ирыбжьоу [OP] [REFERENCE] анакәу","wedo2.whenTilted":"[TILT_DIRECTION_ANY] анырнаау","paint.paintEditor.hue":"Аԥштәы","paint.paintEditor.saturation":"Аԥштәылгазаара","paint.paintEditor.brightness":"Ажжара","paint.paintEditor.costume":"Акостиум","paint.paintEditor.group":"Иргәыԥтәуп","paint.paintEditor.ungroup":"Аргәыԥра ықәгатәуп","paint.paintEditor.undo":"Иаҟәыхтәуп","paint.paintEditor.redo":"Ирхынҳәтәуп","paint.paintEditor.forward":"Ԥхьаҟа","paint.paintEditor.backward":"Шьҭахьҟа","paint.paintEditor.front":"Аԥхьатәи аплан ахь","paint.paintEditor.back":"Шьҭахьҟа","paint.paintEditor.more":"Иҵегь","paint.modeTools.brushSize":"Ашәагаа","paint.modeTools.eraserSize":"Аныхга аҭбаара","paint.modeTools.copy":"Акопиа ахыхтәуп","paint.modeTools.paste":"Иҭаргылатәуп","paint.modeTools.delete":"Ианыхтәуп","paint.modeTools.curved":"Архәақәа рахь","paint.modeTools.pointed":"Ирҵарқәоу рахь","paint.modeTools.thickness":"Ашәпара","paint.modeTools.flipHorizontal":"Горизонталла ианырԥшртәуп","paint.modeTools.flipVertical":"Вертикалла ианырԥштәуп","paint.modeTools.filled":"Иҭарҭәоу","paint.modeTools.outlined":"Иҿыкәыршоу","paint.paintEditor.bitmap":"Аконвертациа арастртә графика ахь","paint.paintEditor.vector":"Аконвертациа авектортә графика ахь ","paint.paintEditor.fill":"Аҭарҭәара","paint.paintEditor.stroke":"Аконтур","paint.brushMode.brush":"Ашәыга","paint.eraserMode.eraser":"Аныхга","paint.fillMode.fill":"Аҭарҭәара","paint.lineMode.line":"Аҵәаӷәа","paint.ovalMode.oval":"Агьежь","paint.rectMode.rect":"Акәакьҭаиаша","paint.reshapeMode.reshape":"Аформа аԥсахра","paint.roundedRectMode.roundedRect":"Ихаргьежьу акәакьҭаиаша","paint.selectMode.select":"Иалхтәуп","paint.textMode.text":"Атекст","paint.colorPicker.swap":"Иалаԥсахтәуп"},"af":{"gui.alerts.tryAgain":"Probeer Weer","gui.alerts.download":"Laai af","gui.connection.reconnect":"Herverbind","gui.backpack.costumeLabel":"kostuum","gui.backpack.soundLabel":"klank","gui.backpack.scriptLabel":"skrip","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Rugsak","gui.backpack.errorBackpack":"Fout kom voor as rugsak laai","gui.backpack.loadingBackpack":"Besig om te laai...","gui.backpack.more":"Meer","gui.backpack.emptyBackpack":"Rugsak is leeg","gui.unsupportedBrowser.label":"Webblaaier word nie ondersteun nie","gui.cards.all-tutorials":"Handleidings","gui.cards.shrink":"Krimp","gui.cards.expand":"Brei uit","gui.cards.close":"Maak toe","gui.cards.more-things-to-try":"Meer goed om te probeer!","gui.cards.see-more":"Sien meer","gui.comingSoon.message1":"Moet nie bekommer nie, ons is op dit {emoji}","gui.comingSoon.message2":"Kom Binnekort...","gui.comingSoon.message3":"Ons werk daaraan{emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Geen toestelle kon gevind word","gui.connection.auto-scanning.prescan":"Hou jou toestel byderhand, began dan soek.","gui.connection.auto-scanning.pressbutton":"Druk die knoppie op jou toestel.","gui.connection.auto-scanning.start-search":"Begin soek","gui.connection.connecting-searchbutton":"Besig om te soek...","gui.connection.auto-scanning.try-again":"Probeer weer","gui.connection.connected":"Verbind","gui.connection.disconnect":"Ontkoppel","gui.connection.go-to-editor":"Gaan na Redigeerder","gui.connection.connecting-cancelbutton":"Besig om te verbind...","gui.connection.error.errorMessage":"Oeps, dit lyk asof iets skeefgeloop het.","gui.connection.error.tryagainbutton":"Probeer weer","gui.connection.error.helpbutton":"Help","gui.connection.peripheral-name-label":"Toestel naam","gui.connection.connect":"Verbind","gui.connection.scanning.lookingforperipherals":"Soek vir toestelle","gui.connection.scanning.noPeripheralsFound":"Geen toestelle kon gevind word","gui.connection.scanning.instructions":"Kies jou toestel uit die bostaande lys uit.","gui.connection.search":"Verfris","gui.connection.unavailable.installscratchlink":"Maak seker dat Scratch Link geïnstalleer is en dat dit hardloop","gui.connection.unavailable.enablebluetooth":"Maak seker Bluetooth is geaktiveer","gui.connection.unavailable.tryagainbutton":"Probeer weer","gui.connection.unavailable.helpbutton":"Help","gui.controls.go":"Gaan","gui.controls.stop":"Stop","gui.crashMessage.label":"Oeps! Iets het skeefgeloop.","gui.crashMessage.errorNumber":"Jou fout is aangeteken met id {errorId}","gui.crashMessage.reload":"Herlaai","gui.customProcedures.myblockModalTitle":"Skep ’n Blok","gui.customProcedures.addAnInputNumberText":"Voeg \'n invoer by","gui.customProcedures.numberTextType":"nommer of teks","gui.customProcedures.addAnInputBoolean":"Voeg \'n invoer by","gui.customProcedures.booleanType":"boolees","gui.customProcedures.addALabel":"Voeg \'n etiket by","gui.customProcedures.runWithoutScreenRefresh":"Hardloop sonder skermverfrissing","gui.customProcedures.cancel":"Kanselleer","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Rigting","gui.directionPicker.rotationStyles.allAround":"Al in die rondte","gui.directionPicker.rotationStyles.leftRight":"Links/Regs","gui.directionPicker.rotationStyles.dontRotate":"Moet nie roteer nie","gui.gui.addExtension":"Voeg Uitbreiding By","gui.gui.codeTab":"Kode","gui.gui.backdropsTab":"Agtergronde","gui.gui.costumesTab":"Kostuums","gui.gui.soundsTab":"Klanke","gui.extensionLibrary.comingSoon":"Kom Binnekort","gui.extensionLibrary.requires":"Vereis","gui.extensionLibrary.collaboration":"Samewerking met","gui.library.filterPlaceholder":"Soek","gui.library.allTag":"Alles","gui.loader.headline":"Besig om Projek te laai","gui.loader.creating":"Besig om projek te skep","gui.authorInfo.byUser":"deur {username}","gui.menuBar.seeProjectPage":"Sien Projek Blad","gui.menuBar.LanguageSelector":"Taalkeurder","gui.menuBar.tutorialsLibrary":"Handleidings","gui.menuBar.restoreSprite":"Herstel Sprite","gui.menuBar.restoreSound":"Herstel Klank","gui.menuBar.restoreCostume":"Herstel Kostuum","gui.menuBar.restore":"Herstel","gui.menuBar.saveNow":"Stoor nou","gui.menuBar.saveAsCopy":"Stoor as \'n kopie","gui.menuBar.remix":"Hermeng","gui.menuBar.new":"Nuut","gui.menuBar.file":"Lêer","gui.menuBar.downloadToComputer":"Stoor op jou rekenaar","gui.menuBar.edit":"Redigeer","gui.menuBar.turboModeOff":"Skakel Turbo Modus af","gui.menuBar.turboModeOn":"Skakel Turbo Modus aan","gui.gui.projectTitlePlaceholder":"Projek titel hier","gui.menuBar.isShared":"Gedeel","gui.menuBar.share":"Deel","gui.modal.help":"Help","gui.modal.back":"Terug","gui.monitor.listMonitor.empty":"(leeg)","gui.monitor.listMonitor.listLength":"lengte {length}","gui.monitor.contextMenu.default":"normale uitlees","gui.monitor.contextMenu.large":"groot uitlees","gui.monitor.contextMenu.slider":"skuifbalk","gui.monitor.contextMenu.sliderRange":"verander skuifreeks","gui.monitor.contextMenu.import":"voer in","gui.monitor.contextMenu.export":"voer uit","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Speel","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"Vir alle sprites","gui.gui.variableScopeOptionSpriteOnly":"Slegs vir hierdie sprite","gui.gui.cloudVariableOption":"Wolk veranderlike (op bediener gestoor)","gui.gui.variablePromptAllSpritesMessage":"Hierdie veranderlike sal vir alle sprites beskikbaar wees.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Kanselleer","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Stop","gui.playbackStep.playMsg":"Speel","gui.playbackStep.loadingMsg":"Besig om te laai...","gui.playbackStep.saveMsg":"Stoor","gui.playbackStep.reRecordMsg":"Heropneem","gui.recordModal.title":"Neem Klank op","gui.recordingStep.beginRecord":"Kliek op die onderstaande knoppie om te begin opneem. ","gui.recordingStep.permission":"{arrow} Ons het jou toestemming nodig om jou mikrofoon te gebruik","gui.recordingStep.stop":"Hou op opneem","gui.recordingStep.record":"Neem op","gui.sliderModal.min":"Minimum waarde","gui.sliderModal.max":"Maksimum waarde","gui.sliderModal.title":"Verander skuifreeks","gui.sliderPrompt.cancel":"Kanselleer","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Klank","gui.soundEditor.play":"Speel","gui.soundEditor.stop":"Stop","gui.soundEditor.copy":"Kopieer","gui.soundEditor.paste":"Plak","gui.soundEditor.copyToNew":"Kopieer na Nuut","gui.soundEditor.delete":"Skrap","gui.soundEditor.save":"Stoor","gui.soundEditor.undo":"Ontdoen","gui.soundEditor.redo":"Herdoen","gui.soundEditor.faster":"Vinniger","gui.soundEditor.slower":"Stadiger","gui.soundEditor.echo":"Eggo","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Harder","gui.soundEditor.softer":"Sagter","gui.soundEditor.reverse":"Keer om","gui.soundEditor.fadeOut":"Uitdoof","gui.soundEditor.fadeIn":"Indoof","gui.soundEditor.mute":"Demp","gui.SpriteInfo.spritePlaceholder":"Naam","gui.SpriteInfo.sprite":"Sprite","gui.SpriteInfo.show":"Vertoon","gui.SpriteInfo.size":"Grootte","gui.spriteSelectorItem.contextMenuDuplicate":"dupliseer","gui.spriteSelectorItem.contextMenuExport":"voer uit","gui.spriteSelectorItem.contextMenuDelete":"skrap","gui.spriteSelector.addSpriteFromLibrary":"Kies \'n Sprite","gui.spriteSelector.addSpriteFromPaint":"Verf","gui.spriteSelector.addSpriteFromSurprise":"Verrassing","gui.spriteSelector.addSpriteFromFile":"Laai Sprite op","gui.stageHeader.stageSizeLarge":"Ruil na groot verhoog","gui.stageHeader.stageSizeSmall":"Ruil na klein verhoog","gui.stageHeader.stageSizeFull":"Gaan na volskermmodus","gui.stageHeader.stageSizeUnFull":"Verlaat volskermmodus","gui.stageHeader.fullscreenControl":"Volskerm Beheer","gui.spriteSelector.addBackdropFromLibrary":"Kies \'n Agtergrond","gui.stageSelector.addBackdropFromPaint":"Verf","gui.stageSelector.addBackdropFromSurprise":"Verrassing","gui.stageSelector.addBackdropFromFile":"Laai Agtergrond op","gui.stageSelector.stage":"Verhoog","gui.stageSelector.backdrops":"Agtergronde","gui.telemetryOptIn.label":"Rapporteer statistieke om Scratch te verbeter","gui.telemetryOptIn.body1":"Die Scratch Span probeer altyd om beter te verstaan hoe Scratch regoor die wêreld gebruik word. Om hierdie poging te ondersteun, kan jy Scratch toelaat om outomaties gebruiksinligting vir die Scratch Span te stuur.","gui.telemetryOptIn.body2":"Die inligting wat ons versamel sluit taalkeuse, blokgebruik, en gebeurtenisse soos stoor, laai, en oplaai van \'n projek. Ons samel NIE enige persoonlike inligting in NIE. Sien asseblief ons {privacyPolicyLink} vir meer inligting.","gui.telemetryOptIn.privacyPolicyLink":"Privaatheidsbeleid","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Turbo Modus","gui.webglModal.label":"Jou Webblaaier Ondersteun Nie WebGL Nie","gui.webglModal.webgllink":"WebGL word nie ondersteun nie","gui.costumeLibrary.chooseABackdrop":"Kies \'n Agtergrond","gui.costumeLibrary.chooseACostume":"Kies \'n Kostuum","gui.costumeTab.addBackdropFromLibrary":"Kies \'n Agtergrond","gui.costumeTab.addCostumeFromLibrary":"Kies \'n Kostuum","gui.costumeTab.addBlankCostume":"Verf","gui.costumeTab.addSurpriseCostume":"Verrassing","gui.costumeTab.addFileBackdrop":"Laai Agtergrond op","gui.costumeTab.addFileCostume":"Laai Kostuum Op","gui.extensionLibrary.chooseAnExtension":"Kies \'n Uitbreiding","gui.extensionLibrary.extensionUrl":"Tik die URL van die uitbreiding in","gui.monitors.importListColumnPrompt":"Watter kolom moet gebruik word (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Kon nie begin opneem nie","gui.soundLibrary.chooseASound":"Kies \'n Klank","gui.soundTab.fileUploadSound":"Laai Klank Op","gui.soundTab.surpriseSound":"Verrassing","gui.soundTab.recordSound":"Neem op","gui.soundTab.addSoundFromLibrary":"Kies \'n Klank","gui.spriteLibrary.chooseASprite":"Kies \'n Sprite","gui.tipsLibrary.tutorials":"Kies \'n Handleiding","gui.alerts.createsuccess":"Nuwe projek geskep.","gui.alerts.createcopysuccess":"Projek as \'n kopie gestoor.","gui.alerts.createremixsuccess":"Projek as \'n hermengsel gestoor.","gui.alerts.creating":"Skep nuwe...","gui.alerts.creatingCopy":"Kopieer projek...","gui.alerts.creatingRemix":"Hermeng projek","gui.alerts.creatingError":"Kon nie die projek skep nie. Probeer asseblief weer!","gui.alerts.savingError":"Projek kon nie stoor nie.","gui.alerts.savesuccess":"Projek is gestoor.","gui.alerts.saving":"Besig om projek te stoor...","gui.alerts.cloudInfo":"Neem asseblief kennis, wolk veranderlikes ondersteun slegs nommers, nie letters of simbole nie. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Leer meer.","gui.alerts.importing":"Besig om in te voer...","gui.defaultProject.variable":"my veranderlike","gui.extension.music.name":"Musiek","gui.extension.music.description":"Speel instrumente en tromme.","gui.extension.pen.name":"Pen","gui.extension.pen.description":"Teken met jou sprites","gui.extension.videosensing.name":"Video Aanvoeling","gui.extension.videosensing.description":"Voel beweging met die kamera.","gui.extension.text2speech.name":"Teks na Spraak","gui.extension.text2speech.description":"Laat jou projekte praat.","gui.extension.translate.name":"Vertaal","gui.extension.translate.description":"Vertaal teks in baie tale.","gui.extension.makeymakey.description":"Verander enige iets in \'n sleutel in.","gui.extension.microbit.description":"Verbind jou projekte met die wêreld.","gui.extension.microbit.connectingMessage":"Besig om te verbind","gui.extension.ev3.description":"Bou interaktiewe robotte en meer.","gui.extension.ev3.connectingMessage":"Besig om te verbind. Maak seker dat die pin op jou EV3 op 1234 gestel is.","gui.extension.boost.description":"Laat robottiese skeppings lewe kry.","gui.extension.boost.connectingMessage":"Besig om te verbind","gui.extension.wedo2.description":"Bou met motors en sensors.","gui.extension.wedo2.connectingMessage":"Besig om te verbind","gui.extension.gdxfor.description":"Voel druk, trek, beweging en draai aan.","gui.extension.gdxfor.connectingMessage":"Besig om te verbind","gui.libraryTags.all":"Alles","gui.libraryTags.animals":"Diere","gui.libraryTags.dance":"Dans","gui.libraryTags.effects":"Effekte","gui.libraryTags.fantasy":"Fantasie","gui.libraryTags.fashion":"Mode","gui.libraryTags.food":"Kos","gui.libraryTags.indoors":"Binnenshuis","gui.libraryTags.loops":"Lusse","gui.libraryTags.music":"Musiek","gui.libraryTags.notes":"Notas","gui.libraryTags.outdoors":"Buite","gui.libraryTags.patterns":"Patrone","gui.libraryTags.people":"Mense","gui.libraryTags.percussion":"Perkussie","gui.libraryTags.space":"Ruimte","gui.libraryTags.sports":"Sport","gui.libraryTags.underwater":"Onderwater","gui.libraryTags.voice":"Stem","gui.libraryTags.wacky":"Verspot","gui.libraryTags.animation":"Animasie","gui.libraryTags.art":"Kuns","gui.libraryTags.games":"Speletjies","gui.libraryTags.stories":"Stories","gui.libraryTags.letters":"Letters","gui.opcodeLabels.direction":"rigting","gui.opcodeLabels.xposition":"x posisie","gui.opcodeLabels.yposition":"y posisie","gui.opcodeLabels.size":"grootte","gui.opcodeLabels.costumename":"kostuumnaam","gui.opcodeLabels.costumenumber":"kostuumnommer","gui.opcodeLabels.backdropname":"agtergrondnaam","gui.opcodeLabels.backdropnumber":"agtergrondnommer","gui.opcodeLabels.volume":"volume","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"antwoord","gui.opcodeLabels.loudness":"hardheid","gui.opcodeLabels.username":"gebruikersnaam","gui.opcodeLabels.year":"jaar","gui.opcodeLabels.month":"maand","gui.opcodeLabels.date":"datum","gui.opcodeLabels.dayofweek":"dag van die week","gui.opcodeLabels.hour":"uur","gui.opcodeLabels.minute":"minuut","gui.opcodeLabels.second":"sekonde","gui.opcodeLabels.timer":"tydhouer","gui.sharedMessages.backdrop":"agtergrond {index}","gui.sharedMessages.costume":"kostuum {index}","gui.sharedMessages.sprite":"Sprite {index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Vervang inhoud van die huidige projek?","gui.sharedMessages.loadFromComputerTitle":"Laai van jou rekenaar","boost.color.any":"enige kleur","boost.color.black":"swart","boost.color.blue":"blou","boost.color.green":"groen","boost.color.red":"rooi","boost.color.white":"wit","boost.color.yellow":"geel","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] posisie","boost.getTiltAngle":"kantel hoek [TILT_DIRECTION]","boost.motorDirection.backward":"soontoe","boost.motorDirection.forward":"hierdie kant toe","boost.motorDirection.reverse":"agteruit","boost.motorOff":"skakel motor [MOTOR_ID] af","boost.motorOn":"skakel motor [MOTOR_ID] aan","boost.motorOnFor":"skakel motor [MOTOR_ID] aan vir [DURATION] sekondes","boost.motorOnForRotation":"skakel motor [MOTOR_ID] aan vir [ROTATION] rotasies","boost.seeingColor":"sien [COLOR] baksteen?","boost.setLightHue":"stel ligkleur na [HUE]","boost.setMotorDirection":"stel motor [MOTOR_ID] rigting [MOTOR_DIRECTION]","boost.setMotorPower":"stel motor [MOTOR_ID] spoed na [POWER] %","boost.tiltDirection.any":"enige","boost.tiltDirection.down":"af","boost.tiltDirection.left":"links","boost.tiltDirection.right":"regs","boost.tiltDirection.up":"op","boost.whenColor":"wanneer [COLOR] baksteen gesien word","boost.whenTilted":"wanneer gekantel [TILT_DIRECTION_ANY]","ev3.beepNote":"biep noot [NOTE] vir [TIME] sekondes","ev3.buttonPressed":"knoppie [PORT] gedruk?","ev3.getBrightness":"helderheid","ev3.getDistance":"afstand","ev3.getMotorPosition":"motor [PORT] posisie","ev3.motorSetPower":"motor [PORT] stel krag [POWER] %","ev3.motorTurnClockwise":"motor [PORT] draai hierdie kant toe vir [TIME] sekondes","ev3.motorTurnCounterClockwise":"motor [PORT] draai soontoe vir [TIME] sekondes","ev3.whenBrightnessLessThan":"wanneer helderheid < [DISTANCE]","ev3.whenButtonPressed":"wanneer knoppie [PORT] gedruk word","ev3.whenDistanceLessThan":"wanneer afstand < [DISTANCE]","gdxfor.getAcceleration":"versnelling [DIRECTION]","gdxfor.getForce":"krag","gdxfor.getSpin":"draai spoed [DIRECTION]","gdxfor.getTilt":"kantel hoek [TILT]","gdxfor.isFreeFalling":"Besig om te val?","gdxfor.isTilted":"Gekantel [TILT]?","gdxfor.pulled":"getrek","gdxfor.pushed":"gestoot","gdxfor.shaken":"geskud","gdxfor.startedFalling":"het begin val","gdxfor.tiltDirectionMenu.any":"enige","gdxfor.tiltDirectionMenu.back":"agterkant","gdxfor.tiltDirectionMenu.front":"voorkant","gdxfor.tiltDirectionMenu.left":"links","gdxfor.tiltDirectionMenu.right":"regs","gdxfor.turnedFaceDown":"met die gesig na onder gedraai","gdxfor.turnedFaceUp":"met die gesig na bo gedraai","gdxfor.whenForcePushedOrPulled":"wanneer krag sensor [PUSH_PULL]","gdxfor.whenGesture":"wanneer [GESTURE]","gdxfor.whenTilted":"wanneer gekantel [TILT]","makeymakey.downArrow":"afwaartsepyl","makeymakey.downArrowShort":"af","makeymakey.leftArrow":"linkerpyl","makeymakey.leftArrowShort":"links","makeymakey.rightArrow":"regterpyl","makeymakey.rightArrowShort":"regs","makeymakey.spaceKey":"spasie","makeymakey.upArrow":"opwaartsepyl","makeymakey.upArrowShort":"op","makeymakey.whenKeyPressed":"wanneer [KEY] sleutel gedruk word","makeymakey.whenKeysPressedInOrder":"wanneer [SEQUENCE] in volgorde gedruk word","microbit.buttonsMenu.any":"enige","microbit.clearDisplay":"verwyder vertooning","microbit.defaultTextToDisplay":"Hallo!","microbit.displaySymbol":"vertoon [MATRIX]","microbit.displayText":"vertoon teks [TEXT]","microbit.gesturesMenu.jumped":"gespring","microbit.gesturesMenu.moved":"geskuif","microbit.gesturesMenu.shaken":"geskud","microbit.isButtonPressed":"[BTN] knoppie gedruk?","microbit.isTilted":"gekantel [DIRECTION]?","microbit.pinStateMenu.off":"af","microbit.pinStateMenu.on":"aan","microbit.tiltAngle":"kantel hoek [DIRECTION]","microbit.tiltDirectionMenu.any":"enige","microbit.tiltDirectionMenu.back":"agterkant","microbit.tiltDirectionMenu.front":"voorkant","microbit.tiltDirectionMenu.left":"links","microbit.tiltDirectionMenu.right":"regs","microbit.whenButtonPressed":"wanneer [BTN] knoppie gedruk word","microbit.whenGesture":"wanneer [GESTURE]","microbit.whenPinConnected":"wanneer pin [PIN] verbind is","microbit.whenTilted":"wanneer [DIRECTION] gekantel","music.categoryName":"Musiek","music.changeTempo":"verander tempo met [TEMPO]","music.drumBass":"(2) Bastrom","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Houtstokkies","music.drumClosedHiHat":"Geslote Hi-Hat","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Koeiklok","music.drumCrashCymbal":"(4) Snel Simbaal","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Handeklap","music.drumOpenHiHat":"(5) Maak Hi-Hat oop","music.drumSideStick":"(3) Systok","music.drumSnare":"(1) Snaartrom","music.drumTambourine":"(7) Tamboeryn","music.drumTriangle":"(12) Driehoek","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Houtblok","music.getTempo":"tempo","music.instrumentBass":"(6) Bas","music.instrumentBassoon":"(14) Fagot","music.instrumentCello":"(8) Tjello","music.instrumentChoir":"(15) Koor","music.instrumentClarinet":"(10) Klarinet","music.instrumentElectricGuitar":"(5) Elektriese Kitaar","music.instrumentElectricPiano":"(2) Elektriese Klavier","music.instrumentFlute":"(12) Fluit","music.instrumentGuitar":"(4) Kitaar","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Musiek Boks","music.instrumentOrgan":"(3) Orrel","music.instrumentPiano":"(1) Klavier","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxofoon","music.instrumentSteelDrum":"(18) Staaltrom","music.instrumentSynthLead":"(20) Hoof Sintetiseerder","music.instrumentSynthPad":"(21) Agtergrond Sintetiseerder","music.instrumentTrombone":"(9) Tromboon","music.instrumentVibraphone":"(16) Vibrafoon","music.instrumentWoodenFlute":"(13) Houtfluit","music.midiPlayDrumForBeats":"speel trom [DRUM] vir [BEATS] slae ","music.midiSetInstrument":"stel instrument na [INSTRUMENT]","music.playDrumForBeats":"speel drom [DRUM] vir [BEATS] slae","music.playNoteForBeats":"speel noot [NOTE] vir [BEATS] slae ","music.restForBeats":"rus vir [BEATS] slae","music.setInstrument":"stel instrument op [INSTRUMENT]","music.setTempo":"stel tempo op [TEMPO]","pen.categoryName":"Pen","pen.changeColorParam":"verander pen [COLOR_PARAM] met [VALUE]","pen.changeHue":"verander pen kleur met [HUE]","pen.changeShade":"Verander pen skakering met [SHADE]","pen.changeSize":"verander pen grootte met [SIZE]","pen.clear":"vee alles uit","pen.colorMenu.brightness":"helderheid","pen.colorMenu.color":"kleur","pen.colorMenu.saturation":"versadiging","pen.colorMenu.transparency":"deursigtigheid","pen.penDown":"sit pen neer","pen.penUp":"tel pen op","pen.setColor":"stel pen kleur op [COLOR]","pen.setColorParam":"stel pen [COLOR_PARAM] op [VALUE]","pen.setHue":"stel pen kleur op [HUE]","pen.setShade":"stel pen skakering op [SHADE]","pen.setSize":"stel pen grootte op [SIZE]","pen.stamp":"stempel","text2speech.alto":"alto","text2speech.categoryName":"Teks na Spraak","text2speech.defaultTextToSpeak":"hallo","text2speech.giant":"reus","text2speech.kitten":"katjie","text2speech.setLanguageBlock":"stel taal op [LANGUAGE]","text2speech.setVoiceBlock":"stel stem op [VOICE]","text2speech.speakAndWaitBlock":"praat [WORDS]","text2speech.squeak":"piep","text2speech.tenor":"tenoor","translate.categoryName":"Vertaal","translate.defaultTextToTranslate":"hallo","translate.translateBlock":"vertaal [WORDS] na [LANGUAGE]","translate.viewerLanguage":"taal","videoSensing.categoryName":"Video Aanvoeling","videoSensing.direction":"rigting","videoSensing.motion":"beweging","videoSensing.off":"af","videoSensing.on":"aan","videoSensing.onFlipped":"omgekeer","videoSensing.setVideoTransparency":"stel video deursigtigheid op [TRANSPARENCY]","videoSensing.sprite":"sprite","videoSensing.stage":"verhoog","videoSensing.videoOn":"video [ATTRIBUTE] op [SUBJECT]","videoSensing.videoToggle":"skakel video [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"wanneer video beweging > [REFERENCE]","wedo2.getDistance":"afstand","wedo2.getTiltAngle":"kantel hoek [TILT_DIRECTION]","wedo2.isTilted":"gekantel [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"soontoe","wedo2.motorDirection.forward":"hierdie kant toe","wedo2.motorDirection.reverse":"agteruit","wedo2.motorId.a":"motor A","wedo2.motorId.all":"alle motors","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"skakel [MOTOR_ID] af","wedo2.motorOn":"skakel [MOTOR_ID] aan","wedo2.motorOnFor":"skakel [MOTOR_ID] aan vir [DURATION] sekondes ","wedo2.playNoteFor":"speel noot [NOTE] vir [DURATION] sekondes","wedo2.setLightHue":"stel ligkleur op [HUE]","wedo2.setMotorDirection":"stel [MOTOR_ID] rigting op [MOTOR_DIRECTION]","wedo2.startMotorPower":"stel [MOTOR_ID] krag op [POWER]","wedo2.tiltDirection.any":"enige","wedo2.tiltDirection.down":"af","wedo2.tiltDirection.left":"links","wedo2.tiltDirection.right":"regs","wedo2.tiltDirection.up":"op","wedo2.whenDistance":"wanneer afstand [OP] [REFERENCE]","wedo2.whenTilted":"wanneer gekantel [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Kleur","paint.paintEditor.saturation":"Versadiging","paint.paintEditor.brightness":"Helderheid","paint.paintEditor.costume":"Kostuum","paint.paintEditor.group":"Groepeer","paint.paintEditor.ungroup":"Ontgroepeer","paint.paintEditor.undo":"Ontdoen","paint.paintEditor.redo":"Herdoen","paint.paintEditor.forward":"Vorentoe","paint.paintEditor.backward":"Agteruit","paint.paintEditor.front":"Voorkant","paint.paintEditor.back":"Terug","paint.paintEditor.more":"Meer","paint.modeTools.brushSize":"Grootte","paint.modeTools.eraserSize":"Uitveër grootte","paint.modeTools.copy":"Kopie","paint.modeTools.paste":"Plak","paint.modeTools.delete":"Verwyder","paint.modeTools.curved":"Kurwe","paint.modeTools.pointed":"Punt","paint.modeTools.thickness":"Dikte","paint.modeTools.flipHorizontal":"Draai Horisontaal","paint.modeTools.flipVertical":"Draai Vertikaal","paint.modeTools.filled":"Gevul","paint.modeTools.outlined":"Buitelyn ","paint.paintEditor.bitmap":"Omskakel na Bitmap","paint.paintEditor.vector":"Omskakel in Vektor","paint.paintEditor.fill":"Vul","paint.paintEditor.stroke":"Buitelyn","paint.brushMode.brush":"Kwas","paint.eraserMode.eraser":"Uitveër","paint.fillMode.fill":"Vul","paint.lineMode.line":"Lyn","paint.ovalMode.oval":"Sirkel","paint.rectMode.rect":"Reghoek","paint.reshapeMode.reshape":"Hervorm","paint.roundedRectMode.roundedRect":"Geronde Reghoek","paint.selectMode.select":"Kies","paint.textMode.text":"Teks","paint.colorPicker.swap":"Ruil om"},"ar":{"gui.alerts.tryAgain":"حاول ثانيةً","gui.alerts.download":"تنزيل","gui.connection.reconnect":"معاودة الاتصال","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"الحقيبة","gui.backpack.errorBackpack":"خطأ في تحميل الحقيبة","gui.backpack.loadingBackpack":"جارٍ التحميل...","gui.backpack.more":"المزيد","gui.backpack.emptyBackpack":"الحقيبة فارغة","gui.unsupportedBrowser.label":"المتصفح غير مدعوم","gui.cards.all-tutorials":"دروس","gui.cards.shrink":"إخفاء","gui.cards.expand":"عرض","gui.cards.close":"إغلاق","gui.cards.more-things-to-try":"المزيد مما يمكن تجريبه!","gui.cards.see-more":"مشاهدة المزيد","gui.comingSoon.message1":"لا تقلق فنحن نعمل على ذلك {emoji}","gui.comingSoon.message2":"قريبًا...","gui.comingSoon.message3":"نحن نعمل على ذلك {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"لم يُعثر على تجهيزات","gui.connection.auto-scanning.prescan":"اجلب جهازك قريبًا ثم باشر البحث.","gui.connection.auto-scanning.pressbutton":"اضغط الزر الموجود على جهازك.","gui.connection.auto-scanning.start-search":"بدء البحث","gui.connection.connecting-searchbutton":"جارٍ البحث...","gui.connection.auto-scanning.try-again":"حاول ثانيةً","gui.connection.connected":"متصل","gui.connection.disconnect":"قطع الاتصال","gui.connection.go-to-editor":"اذهب إلى المحرر","gui.connection.connecting-cancelbutton":"جارٍ الاتصال...","gui.connection.error.errorMessage":"للأسف، يبدو أن هناك خطأً ما.","gui.connection.error.tryagainbutton":"حاول ثانيةً","gui.connection.error.helpbutton":"مساعدة","gui.connection.peripheral-name-label":"اسم الجهاز","gui.connection.connect":"الاتصال بالجهاز","gui.connection.scanning.lookingforperipherals":"جارٍ البحث عن التجهيزات...","gui.connection.scanning.noPeripheralsFound":"لم يتم العثور على الأجهزة","gui.connection.scanning.instructions":"اختر جهازك من القائمة أعلاه.","gui.connection.search":"تحديث","gui.connection.unavailable.installscratchlink":"تأكد من تثبيت Scratch Link وتشغيله","gui.connection.unavailable.enablebluetooth":"تحقق من تفعيل البلوتوث","gui.connection.unavailable.tryagainbutton":"حاول ثانيةً","gui.connection.unavailable.helpbutton":"المساعدة","gui.controls.go":"انطلق","gui.controls.stop":"توقف","gui.crashMessage.label":"للأسف، هناك خطأ ما.","gui.crashMessage.errorNumber":"تم تسجيل الخطأ مع اسم المستخدم {errorId}","gui.crashMessage.reload":"إعادة تحميل الصفحة","gui.customProcedures.myblockModalTitle":"إنشاء لبنة","gui.customProcedures.addAnInputNumberText":"إضافة حقل","gui.customProcedures.numberTextType":"رقم أو نص","gui.customProcedures.addAnInputBoolean":"إضافة حقل","gui.customProcedures.booleanType":"منطقي","gui.customProcedures.addALabel":"إضافة نص","gui.customProcedures.runWithoutScreenRefresh":"التشغيل دون تحديث الشاشة","gui.customProcedures.cancel":"إلغاء الأمر","gui.customProcedures.ok":"موافق","gui.SpriteInfo.direction":"الاتجاه","gui.directionPicker.rotationStyles.allAround":"جميع الاتجاهات","gui.directionPicker.rotationStyles.leftRight":"يمين/ يسار","gui.directionPicker.rotationStyles.dontRotate":"لا استدارة","gui.gui.addExtension":"إدراج إضافة","gui.gui.codeTab":"المقاطع البرمجية","gui.gui.backdropsTab":"الخلفيات","gui.gui.costumesTab":"المظاهر","gui.gui.soundsTab":"الأصوات","gui.extensionLibrary.comingSoon":"قريبًا","gui.extensionLibrary.requires":"المتطلبات","gui.extensionLibrary.collaboration":"بالتعاون مع","gui.library.filterPlaceholder":"بحث","gui.library.allTag":"الكل","gui.loader.headline":"جارٍ تحميل المشروع","gui.loader.creating":"جارٍ إنشاء المشروع","gui.authorInfo.byUser":"بواسطة {username}","gui.menuBar.seeProjectPage":"شاهد صفحة المشروع ","gui.menuBar.LanguageSelector":"اختيار اللغة","gui.menuBar.tutorialsLibrary":"الدروس","gui.menuBar.restoreSprite":"استعادة الكائن","gui.menuBar.restoreSound":"استعادة الصوت","gui.menuBar.restoreCostume":"استعادة المظهر","gui.menuBar.restore":"استعادة","gui.menuBar.saveNow":"الحفظ الآن","gui.menuBar.saveAsCopy":"حفظ نسخة","gui.menuBar.remix":"مزج","gui.menuBar.new":"جديد","gui.menuBar.file":"ملف","gui.menuBar.downloadToComputer":"الحفظ إلى حاسوبك","gui.menuBar.edit":"تحرير","gui.menuBar.turboModeOff":"إيقاف الوضعية السريعة","gui.menuBar.turboModeOn":"تشغيل الوضعية السريعة","gui.gui.projectTitlePlaceholder":"اسم المشروع هنا","gui.menuBar.isShared":"مشارَك","gui.menuBar.share":"مشاركة","gui.modal.help":"مساعدة","gui.modal.back":"عودة إلى السابق","gui.monitor.listMonitor.empty":"(فارغة)","gui.monitor.listMonitor.listLength":"طول {length}","gui.monitor.contextMenu.default":"عرض عادي","gui.monitor.contextMenu.large":"عرض كبير","gui.monitor.contextMenu.slider":"المنزلقة","gui.monitor.contextMenu.sliderRange":"تغيير مجال المنزلقة","gui.monitor.contextMenu.import":"استيراد","gui.monitor.contextMenu.export":"تصدير","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"تشغيل","gui.playButton.stop":"إيقاف","gui.gui.variableScopeOptionAllSprites":"لجميع الكائنات","gui.gui.variableScopeOptionSpriteOnly":"لهذا الكائن فقط","gui.gui.cloudVariableOption":"متغير سحابي (مخزَّن على المخدّم)","gui.gui.variablePromptAllSpritesMessage":"سيكون هذا المتغير متاحًا لجميع الكائنات.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"إلغاء الأمر","gui.prompt.ok":"موافق","gui.playbackStep.stopMsg":"توقف","gui.playbackStep.playMsg":"تشغيل","gui.playbackStep.loadingMsg":"جارٍ التحميل...","gui.playbackStep.saveMsg":"حفظ","gui.playbackStep.reRecordMsg":"إعادة تسجيل","gui.recordModal.title":"تسجيل صوت","gui.recordingStep.beginRecord":"إضغط على الزر في الأسفل لتبدأ التسجيل","gui.recordingStep.permission":"{arrow} نحتاج إذنك لاستخدام الميكروفون","gui.recordingStep.stop":"إيقاف التسجيل","gui.recordingStep.record":"تسجيل","gui.sliderModal.min":"القيمة الدنيا","gui.sliderModal.max":"القيمة العظمى","gui.sliderModal.title":"تغيير مجال المنزلقة","gui.sliderPrompt.cancel":"إلغاء الأمر","gui.sliderPrompt.ok":"موافق","gui.soundEditor.sound":"الصوت","gui.soundEditor.play":"تشغيل","gui.soundEditor.stop":"إيقاف","gui.soundEditor.copy":"نسخ","gui.soundEditor.paste":"لصق","gui.soundEditor.copyToNew":"نسخ إلى صوت جديد","gui.soundEditor.delete":"حذف","gui.soundEditor.save":"حفظ","gui.soundEditor.undo":"تراجع","gui.soundEditor.redo":"إعادة","gui.soundEditor.faster":"تسريع","gui.soundEditor.slower":"إبطاء","gui.soundEditor.echo":"صدى","gui.soundEditor.robot":"روبوت ","gui.soundEditor.louder":"أعلى","gui.soundEditor.softer":"أخفض","gui.soundEditor.reverse":"عكس ","gui.soundEditor.fadeOut":"تلاشي","gui.soundEditor.fadeIn":"تصاعد","gui.soundEditor.mute":"كتم","gui.SpriteInfo.spritePlaceholder":"اسم","gui.SpriteInfo.sprite":"الكائن","gui.SpriteInfo.show":"إظهار","gui.SpriteInfo.size":"الحجم","gui.spriteSelectorItem.contextMenuDuplicate":"مضاعفة","gui.spriteSelectorItem.contextMenuExport":"تصدير","gui.spriteSelectorItem.contextMenuDelete":"حذف","gui.spriteSelector.addSpriteFromLibrary":"اختيار كائن","gui.spriteSelector.addSpriteFromPaint":"رسم","gui.spriteSelector.addSpriteFromSurprise":"كائن عشوائي","gui.spriteSelector.addSpriteFromFile":"تحميل كائن","gui.stageHeader.stageSizeLarge":"التبديل إلى منصة كبيرة","gui.stageHeader.stageSizeSmall":"التبديل إلى منصة صغيرة","gui.stageHeader.stageSizeFull":"الدخول في وضعية ملء الشاشة","gui.stageHeader.stageSizeUnFull":"الخروج من وضعية ملء الشاشة","gui.stageHeader.fullscreenControl":"التحكم في وضعية ملء الشاشة","gui.spriteSelector.addBackdropFromLibrary":"اختيار خلفية","gui.stageSelector.addBackdropFromPaint":"رسام","gui.stageSelector.addBackdropFromSurprise":"خلفية عشوائية","gui.stageSelector.addBackdropFromFile":"تحميل خلفية","gui.stageSelector.stage":"المنصة","gui.stageSelector.backdrops":"الخلفيات","gui.telemetryOptIn.label":"إرسال إحصائيات لتحسين سكراتش","gui.telemetryOptIn.body1":"يتطلع فريق سكراتش دومًا إلى فهم أفضل للكيفية التي تستخدم بها سكراتش في أنحاء العالم. للمساعدة في دعم هذا المجهود يمكنك السماح لسكراتش بإرسال معلومات الاستخدام إلى فريق سكراتش تلقائيًا.","gui.telemetryOptIn.body2":"المعلومات التي نجمعها تتضمن اختيار اللغة واستخدام اللبنات وبعض الأحداث مثل الحفظ والتحميل ورفع مشروع. نحن لا نجمع أي معلومات شخصية. فضلًا راجع {privacyPolicyLink} لمزيد من المعلومات.","gui.telemetryOptIn.privacyPolicyLink":"سياسة الخصوصية","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"الوضعية السريعة","gui.webglModal.label":"متصفحك لا يدعم WebGL","gui.webglModal.webgllink":"لا يدعم WebGL","gui.costumeLibrary.chooseABackdrop":"اختيار خلفية","gui.costumeLibrary.chooseACostume":"اختيار مظهر","gui.costumeTab.addBackdropFromLibrary":"اختيار خلفية","gui.costumeTab.addCostumeFromLibrary":"اختيار مظهر","gui.costumeTab.addBlankCostume":"رسم","gui.costumeTab.addSurpriseCostume":"مظهر عشوائي","gui.costumeTab.addFileBackdrop":"تحميل الخلفية","gui.costumeTab.addFileCostume":"تحميل مظهر","gui.extensionLibrary.chooseAnExtension":"اختر الاضافات","gui.extensionLibrary.extensionUrl":"أدخل الرابط الخاص بالإضافة","gui.monitors.importListColumnPrompt":"أي عمود يجب استخدامه (1-{numberOfColumns})؟","gui.recordingStep.alertMsg":"لا يمكن بدء تسجيل","gui.soundLibrary.chooseASound":"اختيار صوت","gui.soundTab.fileUploadSound":"تحميل صوت","gui.soundTab.surpriseSound":"صوت عشوائي","gui.soundTab.recordSound":"تسجيل","gui.soundTab.addSoundFromLibrary":"اختيار صوت","gui.spriteLibrary.chooseASprite":"اختيار كائن","gui.tipsLibrary.tutorials":"اختيار درس","gui.alerts.createsuccess":"تم إنشاء مشروع جديد. ","gui.alerts.createcopysuccess":"حُفظ المشروع كنسخة.","gui.alerts.createremixsuccess":"حُفظ المشروع كمزج.","gui.alerts.creating":"جارٍ إنشاء مشروع جديد... ","gui.alerts.creatingCopy":"جارٍ نسخ المشروع...","gui.alerts.creatingRemix":"جارٍ مزج المشروع...","gui.alerts.creatingError":"لم يكن بالإمكان إنشاء المشروع. حاول ثانيةً!","gui.alerts.savingError":"لم يمكن حفظ المشروع.","gui.alerts.savesuccess":"حُفظ المشروع.","gui.alerts.saving":"جارٍ حفظ المشروع...","gui.alerts.cloudInfo":"يرجى ملاحظة أن المتغيرات السحابية تدعم الأرقام فقط، ولا تدعم الحروف أو الرموز. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"اعرف المزيد.","gui.alerts.importing":"جارٍ الاستيراد...","gui.defaultProject.variable":"متغيري","gui.extension.music.name":"الموسيقى","gui.extension.music.description":"لعزف الآلات الموسيقية والطبول.","gui.extension.pen.name":"القلم","gui.extension.pen.description":"للرسم بواسطة كائناتك.","gui.extension.videosensing.name":"استشعار الفيديو","gui.extension.videosensing.description":"لاستشعار الحركة بواسطة الكاميرا.","gui.extension.text2speech.name":"نص إلى كلام","gui.extension.text2speech.description":"لجعل مشاريعك تتحدث.","gui.extension.translate.name":"الترجمة","gui.extension.translate.description":"لترجمة نص إلى العديد من اللغات.","gui.extension.makeymakey.description":"لتحويل أي شيء إلى مفتاح.","gui.extension.microbit.description":"لربط مشاريعك بالعالم.","gui.extension.microbit.connectingMessage":"جارٍ التوصيل","gui.extension.ev3.description":"لبناء روبوتات تفاعلية وغيرها.","gui.extension.ev3.connectingMessage":"جارٍ التوصيل. تأكد من أن الرقم السري على جهاز EV3 الخاص بك مضبوط على القيمة 1234.","gui.extension.boost.description":"لبث الروح في كائناتك الروبوتية.","gui.extension.boost.connectingMessage":"جارٍ التوصيل","gui.extension.wedo2.description":"للبناء مستخدمًا المحركات والحساسات.","gui.extension.wedo2.connectingMessage":"جارٍ التوصيل","gui.extension.gdxfor.description":"لاستشعار الدفع والسحب والحركة والدوران.","gui.extension.gdxfor.connectingMessage":"جارٍ التوصيل","gui.libraryTags.all":"الكل","gui.libraryTags.animals":"حيوانات","gui.libraryTags.dance":"رقص","gui.libraryTags.effects":"المؤثرات","gui.libraryTags.fantasy":"عالم الخيال","gui.libraryTags.fashion":"أزياء ","gui.libraryTags.food":"طعام","gui.libraryTags.indoors":"داخلي","gui.libraryTags.loops":"حلقات","gui.libraryTags.music":"موسيقى","gui.libraryTags.notes":"نغمات","gui.libraryTags.outdoors":"خارجي","gui.libraryTags.patterns":"أنماط","gui.libraryTags.people":"بشر","gui.libraryTags.percussion":"إيقاع","gui.libraryTags.space":"فضاء","gui.libraryTags.sports":"رياضة","gui.libraryTags.underwater":"تحت الماء","gui.libraryTags.voice":"صوت","gui.libraryTags.wacky":"لعوب","gui.libraryTags.animation":"رسوم متحركة","gui.libraryTags.art":"فنون","gui.libraryTags.games":"ألعاب","gui.libraryTags.stories":"قصص","gui.libraryTags.letters":"حروف","gui.opcodeLabels.direction":"الاتجاه","gui.opcodeLabels.xposition":"الموضع س","gui.opcodeLabels.yposition":"الموضع ص","gui.opcodeLabels.size":"الحجم","gui.opcodeLabels.costumename":"اسم المظهر","gui.opcodeLabels.costumenumber":"رقم المظهر","gui.opcodeLabels.backdropname":"اسم الخلفية","gui.opcodeLabels.backdropnumber":"رقم الخلفية","gui.opcodeLabels.volume":"شدة الصوت","gui.opcodeLabels.tempo":"سرعة الإيقاع","gui.opcodeLabels.answer":"الإجابة","gui.opcodeLabels.loudness":"الضجيج","gui.opcodeLabels.username":"اسم المستخدم","gui.opcodeLabels.year":"العام","gui.opcodeLabels.month":"الشهر","gui.opcodeLabels.date":"التاريخ","gui.opcodeLabels.dayofweek":"يوم الأسبوع","gui.opcodeLabels.hour":"الساعة","gui.opcodeLabels.minute":"الدقيقة","gui.opcodeLabels.second":"الثانية","gui.opcodeLabels.timer":"المؤقت","gui.sharedMessages.backdrop":"الخلفية {index}","gui.sharedMessages.costume":"المظهر {index}","gui.sharedMessages.sprite":"الكائن {index}","gui.sharedMessages.pop":"بُب","gui.sharedMessages.replaceProjectWarning":"هل تريد الاستغناء عن محتويات المشروع الحالي؟","gui.sharedMessages.loadFromComputerTitle":"التحميل من حاسوبك","boost.color.any":"أي لون","boost.color.black":"الأسود","boost.color.blue":"الأزرق","boost.color.green":"الأخضر","boost.color.red":"الأحمر","boost.color.white":"الأبيض","boost.color.yellow":"الأصفر","boost.getMotorPosition":"موضع المحرك [MOTOR_REPORTER_ID]","boost.getTiltAngle":"زاوية الميلان [TILT_DIRECTION]","boost.motorDirection.backward":"ذاك الاتجاه","boost.motorDirection.forward":"هذا الاتجاه","boost.motorDirection.reverse":"عكس الاتجاه","boost.motorOff":"أوقف المحرك [MOTOR_ID]","boost.motorOn":"شغِّل المحرك [MOTOR_ID]","boost.motorOnFor":"شغِّل المحرك [MOTOR_ID] مدة [DURATION] ثانية","boost.motorOnForRotation":"شغِّل المحرك [MOTOR_ID] لـ[ROTATION] دورات","boost.seeingColor":"ترى اللبنة ذات اللون [COLOR]؟","boost.setLightHue":"اجعل لون المصباح مساويًا [HUE]","boost.setMotorDirection":"اجعل اتجاه المحرك [MOTOR_ID] مساويًا [MOTOR_DIRECTION]","boost.setMotorPower":"اجعل سرعة المحرك [MOTOR_ID] مساويةً [POWER] ٪","boost.tiltDirection.any":"أي اتجاه","boost.tiltDirection.down":"الأسفل","boost.tiltDirection.left":"اليسار ","boost.tiltDirection.right":"اليمين","boost.tiltDirection.up":"الأعلى","boost.whenColor":"عندما ترى اللبنة ذات اللون [COLOR]","boost.whenTilted":"عند الإمالة نحو [TILT_DIRECTION_ANY]","ev3.beepNote":"شغل النغمة [NOTE] مدة [TIME] ثوانٍ","ev3.buttonPressed":"الزر [PORT] مضغوط؟","ev3.getBrightness":"شدة الإضاءة","ev3.getDistance":"المسافة","ev3.getMotorPosition":"موضع المحرك [PORT]","ev3.motorSetPower":"اجعل طاقة المحرك [PORT] مساويةً [POWER] ٪","ev3.motorTurnClockwise":"شغل المحرك [PORT] في هذا الاتجاه مدة [TIME] ثوانٍ","ev3.motorTurnCounterClockwise":"شغل المحرك [PORT] في ذاك الاتجاه مدة [TIME] ثوانٍ","ev3.whenBrightnessLessThan":"عندما الإضاءة < [DISTANCE]","ev3.whenButtonPressed":"عند ضغط زر [PORT]","ev3.whenDistanceLessThan":"عندما المسافة < [DISTANCE]","gdxfor.getAcceleration":"التسارع [DIRECTION]","gdxfor.getForce":"القوة","gdxfor.getSpin":"سرعة الدوران [DIRECTION]","gdxfor.getTilt":"زاوية الميلان [TILT]","gdxfor.isFreeFalling":"في حالة سقوط؟","gdxfor.isTilted":"مائل [TILT]؟","gdxfor.pulled":"مسحوب","gdxfor.pushed":"مدفوع","gdxfor.shaken":"مهزوز","gdxfor.startedFalling":"يبدأ السقوط","gdxfor.tiltDirectionMenu.any":"أي اتجاه","gdxfor.tiltDirectionMenu.back":"الخلف","gdxfor.tiltDirectionMenu.front":"الأمام","gdxfor.tiltDirectionMenu.left":"اليسار ","gdxfor.tiltDirectionMenu.right":"اليمين","gdxfor.turnedFaceDown":"يصبح وجهه للأسفل","gdxfor.turnedFaceUp":"يصبح وجهه للأعلى","gdxfor.whenForcePushedOrPulled":"عندما حساس القوة [PUSH_PULL]","gdxfor.whenGesture":"عندما [GESTURE]","gdxfor.whenTilted":"عندما يميل [TILT]","makeymakey.downArrow":"السهم السفلي","makeymakey.downArrowShort":"الأسفل","makeymakey.leftArrow":"السهم الأيسر","makeymakey.leftArrowShort":"يسار","makeymakey.rightArrow":"السهم الأيمن","makeymakey.rightArrowShort":"اليمين","makeymakey.spaceKey":"المسافة","makeymakey.upArrow":"السهم العلوي","makeymakey.upArrowShort":"الأعلى","makeymakey.whenKeyPressed":"عند ضغط مفتاح [KEY]","makeymakey.whenKeysPressedInOrder":"عند ضغط [SEQUENCE] بالترتيب","microbit.buttonsMenu.any":"أي زر","microbit.clearDisplay":"امسح الشاشة","microbit.defaultTextToDisplay":"Ya Hala!","microbit.displaySymbol":"اعرض [MATRIX]","microbit.displayText":"اعرض النص [TEXT]","microbit.gesturesMenu.jumped":"القفز","microbit.gesturesMenu.moved":"الحركة","microbit.gesturesMenu.shaken":"الهز","microbit.isButtonPressed":"الزر [BTN] مضغوط؟","microbit.isTilted":"مائل نحو [DIRECTION]؟","microbit.pinStateMenu.off":"يتوقف","microbit.pinStateMenu.on":"يعمل","microbit.tiltAngle":"زاوية الميل نحو [DIRECTION]","microbit.tiltDirectionMenu.any":"أي اتجاه","microbit.tiltDirectionMenu.back":"الخلف","microbit.tiltDirectionMenu.front":"الأمام","microbit.tiltDirectionMenu.left":"اليسار","microbit.tiltDirectionMenu.right":"اليمين","microbit.whenButtonPressed":"عند ضغط الزر [BTN]","microbit.whenGesture":"عند [GESTURE]","microbit.whenPinConnected":"عند توصيل الرجل [PIN]","microbit.whenTilted":"عند الميل نحو [DIRECTION]","music.categoryName":"الموسيقى","music.changeTempo":"غيِّر سرعة الأداء بمقدار [TEMPO]","music.drumBass":"(2) طبل كبير","music.drumBongo":"(13) بونغو","music.drumCabasa":"(15) كاباسا","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) هاي هات مغلق","music.drumConga":"(14) كونغا","music.drumCowbell":"(11) جرس","music.drumCrashCymbal":"(4) صنج","music.drumCuica":"(18) كويكا","music.drumGuiro":"(16) غويرو","music.drumHandClap":"(8) صفقة","music.drumOpenHiHat":"(5) هاي هات مفتوح","music.drumSideStick":"(3) عصا جانبية","music.drumSnare":"(1) طبل جانبي","music.drumTambourine":"(7) دف","music.drumTriangle":"(12) مثلث","music.drumVibraslap":"(17) فيبراسلاب","music.drumWoodBlock":"(10) قطعة خشبية","music.getTempo":"سرعة الأداء","music.instrumentBass":"(6) باس","music.instrumentBassoon":"(14) باسون","music.instrumentCello":"(8) تشيلو","music.instrumentChoir":"(15) جوقة","music.instrumentClarinet":"(10) كلارينيت","music.instrumentElectricGuitar":"(5) غيتار كهربائي","music.instrumentElectricPiano":"(2) بيانو كهربائي","music.instrumentFlute":"(12) ناي","music.instrumentGuitar":"(4) غيتار","music.instrumentMarimba":"(19) ماريمبا","music.instrumentMusicBox":"(17) صندوق موسيقى","music.instrumentOrgan":"(3) أورغن","music.instrumentPiano":"(1) بيانو","music.instrumentPizzicato":"(7) بتسيكاتو","music.instrumentSaxophone":"(11) ساكسفون","music.instrumentSteelDrum":"(18) طبل معدني","music.instrumentSynthLead":"(20) Synth Lead","music.instrumentSynthPad":"(21) Synth Pad","music.instrumentTrombone":"(9) ترومبون","music.instrumentVibraphone":"(16) فيبرافون","music.instrumentWoodenFlute":"(13) ناي خشبي","music.midiPlayDrumForBeats":"اقرع [DRUM] مدة [BEATS] وحدة إيقاع","music.midiSetInstrument":"اجعل الآلة [INSTRUMENT]","music.playDrumForBeats":"اقرع [DRUM] مدة [BEATS] وحدة إيقاع","music.playNoteForBeats":"اعزف النغمة [NOTE] مدة [BEATS] وحدة إيقاع","music.restForBeats":"استرح مدة [BEATS] وحدة إيقاع","music.setInstrument":"اجعل الآلة [INSTRUMENT]","music.setTempo":"اجعل سرعة الأداء مساويةً [TEMPO] وحدة إيقاع في الدقيقة","pen.categoryName":"القلم","pen.changeColorParam":"غيِّر [COLOR_PARAM] القلم بمقدار [VALUE]","pen.changeHue":"غيِّر لون القلم بمقدار [HUE]","pen.changeShade":"غيِّر تظليل القلم بمقدار [SHADE]","pen.changeSize":"غيِّر حجم القلم بمقدار [SIZE]","pen.clear":"مسح الكل","pen.colorMenu.brightness":"سطوع لون","pen.colorMenu.color":"لون","pen.colorMenu.saturation":"إشباع لون","pen.colorMenu.transparency":"شفافية","pen.penDown":"أنزل القلم","pen.penUp":"ارفع القلم","pen.setColor":"اجعل لون القلم مساويًا [COLOR]","pen.setColorParam":"اجعل [COLOR_PARAM] القلم مساويًا [VALUE]","pen.setHue":"اجعل لون القلم مساويًا [HUE]","pen.setShade":"اجعل تظليل القلم مساويًا [SHADE]","pen.setSize":"اجعل حجم القلم مساويًا [SIZE]","pen.stamp":"اطبع","text2speech.alto":"صوت امرأة","text2speech.categoryName":"نص إلى كلام","text2speech.defaultTextToSpeak":"السلام عليكم","text2speech.giant":"عميقًا","text2speech.kitten":"صوت قطقوطة","text2speech.setLanguageBlock":"اجعل اللغة هي [LANGUAGE]","text2speech.setVoiceBlock":"اجعل الصوت [VOICE]","text2speech.speakAndWaitBlock":"تكلم [WORDS]","text2speech.squeak":"رفيعًا","text2speech.tenor":"صوت رجل","translate.categoryName":"ترجم","translate.defaultTextToTranslate":"مرحبًا ","translate.translateBlock":"ترجم [WORDS] إلى [LANGUAGE]","translate.viewerLanguage":"لغتي","videoSensing.categoryName":"استشعار الفيديو","videoSensing.direction":"اتجاه","videoSensing.motion":"حركة","videoSensing.off":"يتوقف","videoSensing.on":"يعمل","videoSensing.onFlipped":"يعمل مقلوبًا","videoSensing.setVideoTransparency":"اجعل شفافية الفيديو مساويةً [TRANSPARENCY]","videoSensing.sprite":"الكائن","videoSensing.stage":"المنصة","videoSensing.videoOn":"[ATTRIBUTE] الفيديو على [SUBJECT]","videoSensing.videoToggle":"اجعل الفيديو [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"عندما حركة الفيديو > [REFERENCE]","wedo2.getDistance":"المسافة","wedo2.getTiltAngle":"زاوية الميل نحو [TILT_DIRECTION]","wedo2.isTilted":"مائل نحو [TILT_DIRECTION_ANY]؟","wedo2.motorDirection.backward":"ذاك الاتجاه","wedo2.motorDirection.forward":"هذا الاتجاه","wedo2.motorDirection.reverse":"المعاكس","wedo2.motorId.a":"المحرك A","wedo2.motorId.all":"جميع المحركات","wedo2.motorId.b":"المحرك B","wedo2.motorId.default":"المحرك","wedo2.motorOff":"أوقف [MOTOR_ID]","wedo2.motorOn":"شغِّل [MOTOR_ID]","wedo2.motorOnFor":"شغّل [MOTOR_ID] مدة [DURATION] ثوانٍ","wedo2.playNoteFor":"اعزف النغمة [NOTE] مدة [DURATION] ثوانٍ","wedo2.setLightHue":"اجعل لون المصباح مساويًا [HUE]","wedo2.setMotorDirection":"اجعل دوران [MOTOR_ID] في [MOTOR_DIRECTION]","wedo2.startMotorPower":"اجعل قوة [MOTOR_ID] مساويةً [POWER]","wedo2.tiltDirection.any":"أي اتجاه","wedo2.tiltDirection.down":"الأسفل","wedo2.tiltDirection.left":"اليسار ","wedo2.tiltDirection.right":"اليمين","wedo2.tiltDirection.up":"الأعلى ","wedo2.whenDistance":"عندما المسافة [OP] [REFERENCE]","wedo2.whenTilted":"عند الإمالة نحو [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"اللون","paint.paintEditor.saturation":"تشبع اللون","paint.paintEditor.brightness":"السطوع","paint.paintEditor.costume":"المظهر","paint.paintEditor.group":"تجميع","paint.paintEditor.ungroup":"فك تجميع","paint.paintEditor.undo":"تراجع","paint.paintEditor.redo":"إعادة","paint.paintEditor.forward":"طبقة إلى الأمام","paint.paintEditor.backward":"طبقة إلى الخلف","paint.paintEditor.front":"وضع في الطبقة الأولى","paint.paintEditor.back":"وضع في الطبقة الأخيرة","paint.paintEditor.more":"المزيد","paint.modeTools.brushSize":"الحجم","paint.modeTools.eraserSize":"حجم الممحاة","paint.modeTools.copy":"نسخ","paint.modeTools.paste":"لصق","paint.modeTools.delete":"حذف","paint.modeTools.curved":"مقوَّس","paint.modeTools.pointed":"مدبب","paint.modeTools.thickness":"الثخانة","paint.modeTools.flipHorizontal":"اعكس أفقيًا","paint.modeTools.flipVertical":"اعكس شاقوليًا","paint.modeTools.filled":"مملوء","paint.modeTools.outlined":"مؤطَّر","paint.paintEditor.bitmap":"تحويل إلى رسم نقطي","paint.paintEditor.vector":"تحويل إلى رسم متجه","paint.paintEditor.fill":"ملء","paint.paintEditor.stroke":"الإطار","paint.brushMode.brush":"فرشاة","paint.eraserMode.eraser":"ممحاة","paint.fillMode.fill":"الملء","paint.lineMode.line":"خط ","paint.ovalMode.oval":"دائرة","paint.rectMode.rect":"مستطيل","paint.reshapeMode.reshape":"إعادة تشكيل","paint.roundedRectMode.roundedRect":"مستطيل مستدير الزوايا","paint.selectMode.select":"تحديد","paint.textMode.text":"نص","paint.colorPicker.swap":"تبديل","tw.code":"مصدر الرمز","tw.feedbackButton":"ردود الفعل توربوارب","tw.footer.credits":"الاعتمادات","tw.footer.embed":"التضمين","tw.loader.generic":"مشروع جار التحميل ...","tw.menuBar.compileError":"{sprite}:{error}","tw.paint.alpha":"العتامة","tw.privacy":"سياسة خاصة","tw.usernameModal.reset":"إعادة تعيين"},"am":{"gui.alerts.tryAgain":"Try Again","gui.alerts.download":"Download","gui.connection.reconnect":"Reconnect","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"ቦርሳ","gui.backpack.errorBackpack":"ስሕተት በየቦርሳውን ጭነት","gui.backpack.loadingBackpack":"በመጫን ላይ...","gui.backpack.more":"More","gui.backpack.emptyBackpack":"ቦርሳው ባዶ ነው","gui.unsupportedBrowser.label":"አሳሽው አልተደገፈም ","gui.cards.all-tutorials":"መማሪያዎች","gui.cards.shrink":"Shrink","gui.cards.expand":"Expand","gui.cards.close":"Close","gui.cards.more-things-to-try":"ተጨማሪ ነገሮች ለመሞከር!","gui.cards.see-more":"ተጨማሪ እዩ ","gui.comingSoon.message1":"አትጨነቁ፣ የሰራንበት ነው {emoji}","gui.comingSoon.message2":"በቅርቡ ይደርሳል...","gui.comingSoon.message3":"የሰራንበት ነው {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"No devices found","gui.connection.auto-scanning.prescan":"መሳርያዎን ጠጋ አድርጉ፣ ከዛ ፍለጋውን ይጀምሩ።","gui.connection.auto-scanning.pressbutton":"መሳርያዎቻቹን ላይ ያለውን ቁልፍ ጫን አድርጉ።","gui.connection.auto-scanning.start-search":"ፍለጋ ጀምር","gui.connection.connecting-searchbutton":"በፍለጋ ላይ...","gui.connection.auto-scanning.try-again":"እንደገና ይሞክሩ ","gui.connection.connected":"ተገናኝቷል","gui.connection.disconnect":"አቋርጥ","gui.connection.go-to-editor":"ወደ አርታዒ ሂድ","gui.connection.connecting-cancelbutton":"በመገናኘት ላይ...","gui.connection.error.errorMessage":"ዌይ፣ አንድ ስሕተት ተጋጠመ።","gui.connection.error.tryagainbutton":"እንደገና ይሞክሩ ","gui.connection.error.helpbutton":"እርዳታ","gui.connection.peripheral-name-label":"Device name","gui.connection.connect":"አገናኝ","gui.connection.scanning.lookingforperipherals":"Looking for devices","gui.connection.scanning.noPeripheralsFound":"No devices found","gui.connection.scanning.instructions":"መሳሪያዎን በላይ ያለውን ዝርዝር ይምረጡ።","gui.connection.search":"አድስ","gui.connection.unavailable.installscratchlink":"Scratch Linkን እንደጫኑና እንደሚሰራ አረጋግጡ","gui.connection.unavailable.enablebluetooth":"Bluetooth እንደበራ አረጋግጡ","gui.connection.unavailable.tryagainbutton":"እንደገና ይሞክሩ ","gui.connection.unavailable.helpbutton":"እርዳታ","gui.controls.go":"ሂድ","gui.controls.stop":"አቁም","gui.crashMessage.label":"Oops! Something went wrong.","gui.crashMessage.errorNumber":"Your error was logged with id {errorId}","gui.crashMessage.reload":"Reload","gui.customProcedures.myblockModalTitle":"ጡብ ፍጠር","gui.customProcedures.addAnInputNumberText":"ግቤት ጨምር","gui.customProcedures.numberTextType":"ቁጥር ዌይስ ጽሁፍ","gui.customProcedures.addAnInputBoolean":"ግቤት ጨምር","gui.customProcedures.booleanType":"ቡልያዊ","gui.customProcedures.addALabel":"መሰየሚያ ለጥፍ","gui.customProcedures.runWithoutScreenRefresh":"ፕሮግራሙን ያለ ስክሪኑ ማደስ ክፈት","gui.customProcedures.cancel":"ይቁም","gui.customProcedures.ok":"እሺ","gui.SpriteInfo.direction":"አቅጣጫ","gui.directionPicker.rotationStyles.allAround":"ዙሪያውን","gui.directionPicker.rotationStyles.leftRight":"ግራ/ቀኝ","gui.directionPicker.rotationStyles.dontRotate":"አትዞር","gui.gui.addExtension":"ቅጥያ ጨምር","gui.gui.codeTab":"ኮድ","gui.gui.backdropsTab":"የጀርባ ምስሎች","gui.gui.costumesTab":"አልባሳት","gui.gui.soundsTab":"ድምጾች","gui.extensionLibrary.comingSoon":"በቅርቡ ይመጣል","gui.extensionLibrary.requires":"Requires","gui.extensionLibrary.collaboration":"Collaboration with","gui.library.filterPlaceholder":"ፈልጉ","gui.library.allTag":"All","gui.loader.headline":"ፕሮጀክት በመጫን ላይ","gui.loader.creating":"Creating Project","gui.authorInfo.byUser":"by {username}","gui.menuBar.seeProjectPage":"See Project Page","gui.menuBar.LanguageSelector":"የቋንቋ መምረጫ","gui.menuBar.tutorialsLibrary":"መማሪያዎች","gui.menuBar.restoreSprite":"ስፕራይቱን መልስ","gui.menuBar.restoreSound":"ድምጹን መልስ","gui.menuBar.restoreCostume":"ልብሱን መልስ","gui.menuBar.restore":"መልስ","gui.menuBar.saveNow":"አሁን አስቀምጥ","gui.menuBar.saveAsCopy":"እንደ ቅጂ አስቀምጥ","gui.menuBar.remix":"Remix","gui.menuBar.new":"አዲስ","gui.menuBar.file":"ፋይል","gui.menuBar.downloadToComputer":"ወደ ኮምፒዩተርዎ ይቀመጥ","gui.menuBar.edit":"ቀይር","gui.menuBar.turboModeOff":"ቱርቦ ሞድ አጥፋ","gui.menuBar.turboModeOn":"ቱርቦ ሞድ አብራ","gui.gui.projectTitlePlaceholder":"Project title here","gui.menuBar.isShared":"Shared","gui.menuBar.share":"አጋራ","gui.modal.help":"እርዳታ","gui.modal.back":"ኋላ","gui.monitor.listMonitor.empty":"(empty)","gui.monitor.listMonitor.listLength":"length {length}","gui.monitor.contextMenu.default":"መደበኛ የሚነበብ ነገር","gui.monitor.contextMenu.large":"ትልቅ የሚነበብ ነገር","gui.monitor.contextMenu.slider":"ማንሸራተቻ","gui.monitor.contextMenu.sliderRange":"change slider range","gui.monitor.contextMenu.import":"import","gui.monitor.contextMenu.export":"export","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Play","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"ለሁሉም ስፕራይቶች","gui.gui.variableScopeOptionSpriteOnly":"ለዚህ ስፕራይት ብቻ","gui.gui.cloudVariableOption":"Cloud variable (stored on server)","gui.gui.variablePromptAllSpritesMessage":"ይህ ተለዋዋጭ ለሁሉም ስፕራይቶች ጠቀቃሚ ይሆናል።","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"ይቁም","gui.prompt.ok":"እሺ","gui.playbackStep.stopMsg":"አቁም","gui.playbackStep.playMsg":"ይጫወታሉ","gui.playbackStep.loadingMsg":"በመጫን ላይ...","gui.playbackStep.saveMsg":"አስቀምጥ","gui.playbackStep.reRecordMsg":"በድጋሜ ቅዳ","gui.recordModal.title":"ድምጹ ቅዳ","gui.recordingStep.beginRecord":"Begin recording by clicking the button below","gui.recordingStep.permission":"{arrow}We need your permission to use your microphone","gui.recordingStep.stop":"Stop recording","gui.recordingStep.record":"Record","gui.sliderModal.min":"Minimum value","gui.sliderModal.max":"Maximum value","gui.sliderModal.title":"Change slider range","gui.sliderPrompt.cancel":"Cancel","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"ድምጽ","gui.soundEditor.play":"ይጫወታሉ","gui.soundEditor.stop":"አቁም","gui.soundEditor.copy":"Copy","gui.soundEditor.paste":"Paste","gui.soundEditor.copyToNew":"Copy to New","gui.soundEditor.delete":"Delete","gui.soundEditor.save":"አስቀምጥ","gui.soundEditor.undo":"መልስ","gui.soundEditor.redo":"ድጋሜ አድርግ","gui.soundEditor.faster":"በፍጥነት","gui.soundEditor.slower":"በዝግታ","gui.soundEditor.echo":"ማስተጋባት","gui.soundEditor.robot":"ሮቦት","gui.soundEditor.louder":"ከፍ በል","gui.soundEditor.softer":"ቀስ በል","gui.soundEditor.reverse":"ቀልብስ","gui.soundEditor.fadeOut":"Fade out","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Mute","gui.SpriteInfo.spritePlaceholder":"ስም","gui.SpriteInfo.sprite":"ገፀ-ባህርይ","gui.SpriteInfo.show":"አሳይ","gui.SpriteInfo.size":"ልክ","gui.spriteSelectorItem.contextMenuDuplicate":"አባዛ","gui.spriteSelectorItem.contextMenuExport":"ማስወጣት","gui.spriteSelectorItem.contextMenuDelete":"ደምስስ","gui.spriteSelector.addSpriteFromLibrary":"ስፕራይትን ምረጥ","gui.spriteSelector.addSpriteFromPaint":"ቀለም ቅባ","gui.spriteSelector.addSpriteFromSurprise":"አድናቆት","gui.spriteSelector.addSpriteFromFile":"ስፕራይቱን ስቀል","gui.stageHeader.stageSizeLarge":"ወደ የተለቀ መድረክ ለውጥ","gui.stageHeader.stageSizeSmall":"ወደ ያነሰ መድረክ ለውጥ","gui.stageHeader.stageSizeFull":"ሙሉ ማሳያ ሞድ ውስጥ ግባ","gui.stageHeader.stageSizeUnFull":"ከሙሉ ማሳያ ሞድ ውስጥ ውጣ","gui.stageHeader.fullscreenControl":"ሙሉ ማሳይ አመራር","gui.spriteSelector.addBackdropFromLibrary":"የጀርባ ምስል ይምረጡ","gui.stageSelector.addBackdropFromPaint":"ቀለም ቅባ","gui.stageSelector.addBackdropFromSurprise":"አድናቆት","gui.stageSelector.addBackdropFromFile":"የጀርባ ምስሉን ስቀል","gui.stageSelector.stage":"መድረክ","gui.stageSelector.backdrops":"የጀርባ ምስሎች","gui.telemetryOptIn.label":"Report statistics to improve Scratch","gui.telemetryOptIn.body1":"The Scratch Team is always looking to better understand how Scratch is used around the world. To help support this effort, you can allow Scratch to automatically send usage information to the Scratch Team.","gui.telemetryOptIn.body2":"The information we collect includes language selection, blocks usage, and some events like saving, loading, and uploading a project. We DO NOT collect any personal information. Please see our {privacyPolicyLink} for more information.","gui.telemetryOptIn.privacyPolicyLink":"Privacy Policy","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"ተርቦ ሞድ","gui.webglModal.label":"የእርስዎ አሳሽ WebGL አይደግፍም","gui.webglModal.webgllink":"WebGLን አይደግፍም","gui.costumeLibrary.chooseABackdrop":"የጀርባ ምስል ይምረጡ","gui.costumeLibrary.chooseACostume":"ልብስ ይምረጡ","gui.costumeTab.addBackdropFromLibrary":"የጀርባ ምስል ይምረጡ","gui.costumeTab.addCostumeFromLibrary":"ልብስ ይምረጡ","gui.costumeTab.addBlankCostume":"ቀለም ቅባ","gui.costumeTab.addSurpriseCostume":"አድናቆት","gui.costumeTab.addFileBackdrop":"የጀርባ ምስሉን ስቀል","gui.costumeTab.addFileCostume":"ልብሱን ስቀል","gui.extensionLibrary.chooseAnExtension":"ቅጥያ ይምረጡ","gui.extensionLibrary.extensionUrl":"የቅጥያው ገፅ አድራሻ ያስገቡ","gui.monitors.importListColumnPrompt":"Which column should be used (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"መቅዳት መጀመር አልተቻለም","gui.soundLibrary.chooseASound":"ድምጽ ይምረጡ","gui.soundTab.fileUploadSound":"ድምጹን ስቀል","gui.soundTab.surpriseSound":"አድናቆት","gui.soundTab.recordSound":"ቅዳ","gui.soundTab.addSoundFromLibrary":"ድምጽ ይምረጡ","gui.spriteLibrary.chooseASprite":"ስፕራይትን ምረጥ","gui.tipsLibrary.tutorials":"አጋዥ ስልጠና ይምረጡ","gui.alerts.createsuccess":"New project created.","gui.alerts.createcopysuccess":"Project saved as a copy.","gui.alerts.createremixsuccess":"Project saved as a remix.","gui.alerts.creating":"Creating new…","gui.alerts.creatingCopy":"Copying project…","gui.alerts.creatingRemix":"Remixing project…","gui.alerts.creatingError":"Could not create the project. Please try again!","gui.alerts.savingError":"Project could not save.","gui.alerts.savesuccess":"Project saved.","gui.alerts.saving":"Saving project…","gui.alerts.cloudInfo":"Please note, cloud variables only support numbers, not letters or symbols. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Learn more.","gui.alerts.importing":"Importing…","gui.defaultProject.variable":"my variable","gui.extension.music.name":"ሙዚቃ","gui.extension.music.description":"መሳሪያዎችና ታምቡሮች ተጫወት","gui.extension.pen.name":"ብዕር","gui.extension.pen.description":"ከየእርስዎ ስፕራይቶች ይሳሉ","gui.extension.videosensing.name":"የቪድዮ ህዋስ","gui.extension.videosensing.description":"እንቅስቃሴ ስማ ከካሜራው","gui.extension.text2speech.name":"Text to Speech","gui.extension.text2speech.description":"Make your projects talk.","gui.extension.translate.name":"Translate","gui.extension.translate.description":"Translate text into many languages.","gui.extension.makeymakey.description":"Make anything into a key.","gui.extension.microbit.description":"የእርስዎ ፕሮጀክቶች ያገናኙ ከዓለሙ ጋር","gui.extension.microbit.connectingMessage":"በመገናኘት ላይ ነው","gui.extension.ev3.description":"በይነግንኙነት ሮቦቶችና ተጨማሪ ነገሮች ይገንቡ","gui.extension.ev3.connectingMessage":"በመገናኘት ላይ ነው። EV3 ላይ ያለው ዕስፒልዎ ወደ 1234 እንደተቀየረ ያረጋግጡ።","gui.extension.boost.description":"Bring robotic creations to life.","gui.extension.boost.connectingMessage":"Connecting","gui.extension.wedo2.description":"ከሞተሮችና ቃኚዎች ይገንቡ።","gui.extension.wedo2.connectingMessage":"በመገናኘት ላይ ነው","gui.extension.gdxfor.description":"Sense push, pull, motion, and spin.","gui.extension.gdxfor.connectingMessage":"Connecting","gui.libraryTags.all":"All","gui.libraryTags.animals":"Animals","gui.libraryTags.dance":"Dance","gui.libraryTags.effects":"Effects","gui.libraryTags.fantasy":"Fantasy","gui.libraryTags.fashion":"Fashion","gui.libraryTags.food":"Food","gui.libraryTags.indoors":"Indoors","gui.libraryTags.loops":"Loops","gui.libraryTags.music":"Music","gui.libraryTags.notes":"Notes","gui.libraryTags.outdoors":"Outdoors","gui.libraryTags.patterns":"Patterns","gui.libraryTags.people":"People","gui.libraryTags.percussion":"Percussion","gui.libraryTags.space":"Space","gui.libraryTags.sports":"Sports","gui.libraryTags.underwater":"Underwater","gui.libraryTags.voice":"Voice","gui.libraryTags.wacky":"Wacky","gui.libraryTags.animation":"Animation","gui.libraryTags.art":"Art","gui.libraryTags.games":"Games","gui.libraryTags.stories":"Stories","gui.libraryTags.letters":"Letters","gui.opcodeLabels.direction":"direction","gui.opcodeLabels.xposition":"x position","gui.opcodeLabels.yposition":"y position","gui.opcodeLabels.size":"size","gui.opcodeLabels.costumename":"costume name","gui.opcodeLabels.costumenumber":"costume number","gui.opcodeLabels.backdropname":"backdrop name","gui.opcodeLabels.backdropnumber":"backdrop number","gui.opcodeLabels.volume":"volume","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"answer","gui.opcodeLabels.loudness":"loudness","gui.opcodeLabels.username":"username","gui.opcodeLabels.year":"year","gui.opcodeLabels.month":"month","gui.opcodeLabels.date":"date","gui.opcodeLabels.dayofweek":"day of week","gui.opcodeLabels.hour":"hour","gui.opcodeLabels.minute":"minute","gui.opcodeLabels.second":"second","gui.opcodeLabels.timer":"timer","gui.sharedMessages.backdrop":"backdrop{index}","gui.sharedMessages.costume":"costume{index}","gui.sharedMessages.sprite":"Sprite{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Replace contents of the current project?","gui.sharedMessages.loadFromComputerTitle":"Load from your computer","boost.color.any":"any color","boost.color.black":"black","boost.color.blue":"blue","boost.color.green":"green","boost.color.red":"red","boost.color.white":"white","boost.color.yellow":"yellow","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] position","boost.getTiltAngle":"tilt angle [TILT_DIRECTION]","boost.motorDirection.backward":"that way","boost.motorDirection.forward":"this way","boost.motorDirection.reverse":"reverse","boost.motorOff":"turn motor [MOTOR_ID] off","boost.motorOn":"turn motor [MOTOR_ID] on","boost.motorOnFor":"turn motor [MOTOR_ID] for [DURATION] seconds","boost.motorOnForRotation":"turn motor [MOTOR_ID] for [ROTATION] rotations","boost.seeingColor":"seeing [COLOR] brick?","boost.setLightHue":"set light color to [HUE]","boost.setMotorDirection":"set motor [MOTOR_ID] direction [MOTOR_DIRECTION]","boost.setMotorPower":"set motor [MOTOR_ID] speed to [POWER] %","boost.tiltDirection.any":"any","boost.tiltDirection.down":"down","boost.tiltDirection.left":"left","boost.tiltDirection.right":"right","boost.tiltDirection.up":"up","boost.whenColor":"when [COLOR] brick seen","boost.whenTilted":"when tilted [TILT_DIRECTION_ANY]","ev3.beepNote":"በ[NOTE] ኖታ ጲጵ በል ለ[TIME] ሰከንድ","ev3.buttonPressed":"[PORT]ን ቁልፍ ተጭኗል?","ev3.getBrightness":"የብርሀን መጠን","ev3.getDistance":"ርቀት","ev3.getMotorPosition":"[PORT]ን ሞተር አኳኋን","ev3.motorSetPower":"የ [PORT]ን ሞተር ሃይል ወደ [POWER]% ለውጥ","ev3.motorTurnClockwise":"የ[PORT] ሞተር በዚህ አቅጣጫ አዙር ለ[TIME] ሰከንድ","ev3.motorTurnCounterClockwise":"የ[PORT] ሞተር በዚያ አቅጣጫ አዙር ለ[TIME] ሰከንድ","ev3.whenBrightnessLessThan":"ብሩህነት < [DISTANCE] ሲሆን","ev3.whenButtonPressed":"[PORT]ን ቁልፍ ሲጫን","ev3.whenDistanceLessThan":"ርቀት < [DISTANCE] ሲሆን","gdxfor.getAcceleration":"acceleration [DIRECTION]","gdxfor.getForce":"force","gdxfor.getSpin":"spin speed [DIRECTION]","gdxfor.getTilt":"tilt angle [TILT]","gdxfor.isFreeFalling":"falling?","gdxfor.isTilted":"tilted [TILT]?","gdxfor.pulled":"pulled","gdxfor.pushed":"pushed","gdxfor.shaken":"shaken","gdxfor.startedFalling":"started falling","gdxfor.tiltDirectionMenu.any":"any","gdxfor.tiltDirectionMenu.back":"back","gdxfor.tiltDirectionMenu.front":"front","gdxfor.tiltDirectionMenu.left":"left","gdxfor.tiltDirectionMenu.right":"right","gdxfor.turnedFaceDown":"turned face down","gdxfor.turnedFaceUp":"turned face up","gdxfor.whenForcePushedOrPulled":"when force sensor [PUSH_PULL]","gdxfor.whenGesture":"when [GESTURE]","gdxfor.whenTilted":"when tilted [TILT]","makeymakey.downArrow":"down arrow","makeymakey.downArrowShort":"down","makeymakey.leftArrow":"left arrow","makeymakey.leftArrowShort":"left","makeymakey.rightArrow":"right arrow","makeymakey.rightArrowShort":"right","makeymakey.spaceKey":"space","makeymakey.upArrow":"up arrow","makeymakey.upArrowShort":"up","makeymakey.whenKeyPressed":"when [KEY] key pressed","makeymakey.whenKeysPressedInOrder":"when [SEQUENCE] pressed in order","microbit.buttonsMenu.any":"የቱም","microbit.clearDisplay":"ማሳያ አጽዳ","microbit.defaultTextToDisplay":"ሰላም!","microbit.displaySymbol":"[MATRIX]ን አሳይ","microbit.displayText":"display text [TEXT]","microbit.gesturesMenu.jumped":"ዘልሏል","microbit.gesturesMenu.moved":"ተንቀሳቅሷል","microbit.gesturesMenu.shaken":"አራድቷል","microbit.isButtonPressed":"[BTN]ን ቁልፍ ተጭኗል?","microbit.isTilted":"በ[DIRECTION] አቅጣጫ ተዘነብሏል?","microbit.pinStateMenu.off":"የጠፋ","microbit.pinStateMenu.on":"እየሰራ ያለ","microbit.tiltAngle":"ማዕዘን በ[DIRECTION] አቅጣጫ አዘንብል","microbit.tiltDirectionMenu.any":"የቱም","microbit.tiltDirectionMenu.back":"ኋላ","microbit.tiltDirectionMenu.front":"ፊት","microbit.tiltDirectionMenu.left":"ግራ","microbit.tiltDirectionMenu.right":"ቀኝ","microbit.whenButtonPressed":"[BTN]ን ቁልፍ ሲጫን","microbit.whenGesture":"[GESTURE]ን ሲሰጥ","microbit.whenPinConnected":"when pin [PIN] connected","microbit.whenTilted":"በ[DIRECTION] አቅጣጫ ሲዘነብል","music.categoryName":"ሙዚቃ","music.changeTempo":"ሰልት ቀይር በ[TEMPO]","music.drumBass":"(2) ትልቅ ታምቡር","music.drumBongo":"(13) ቦንጎ","music.drumCabasa":"(13) ካባሳ","music.drumClaves":"(9) ክላቭ","music.drumClosedHiHat":"(6) የተዘጋ ድምፀ ብረት","music.drumConga":"(14) ኮንጋ","music.drumCowbell":"(11) የላም ቃጭል","music.drumCrashCymbal":"(4) ጸናጽል","music.drumCuica":"(18) ኲካ","music.drumGuiro":"(16) ጒሮ","music.drumHandClap":"(8) ጭብጨባ","music.drumOpenHiHat":"(5) የተከፈተ ድምፀ ብረት","music.drumSideStick":"(3) የጎን በትር","music.drumSnare":"(1) ነዛሪ ታምቡር","music.drumTambourine":"(7) ታምቡሪን","music.drumTriangle":"(12) ትራያንግል","music.drumVibraslap":"(17) ቫይብራስላፕ","music.drumWoodBlock":"(10) የእንጨት ብሎኬት","music.getTempo":"ምት","music.instrumentBass":"(6) ባስ","music.instrumentBassoon":"(14) ባዙን","music.instrumentCello":"(8) ቼሎ","music.instrumentChoir":"(15) ሕብረ-ዝማሬ","music.instrumentClarinet":"(10) ክላርኔት","music.instrumentElectricGuitar":"(5) ኤሌክትሪክ ጊታር","music.instrumentElectricPiano":"(2) ኤሌክትሪክ ፒያኖ","music.instrumentFlute":"(12) ፍሉት","music.instrumentGuitar":"(4) ጊታር","music.instrumentMarimba":"(19) ማሪምባ","music.instrumentMusicBox":"(17) የሙዚቃ ሳጥን","music.instrumentOrgan":"(3) ኦርጋን","music.instrumentPiano":"(1) ፒያኖ","music.instrumentPizzicato":"(7) ፒዚካቶ","music.instrumentSaxophone":"(11) ሳክስፎን","music.instrumentSteelDrum":"(18) ብረት ታምቡር","music.instrumentSynthLead":"(20) የመራሄ ድምፅ መምሪያ","music.instrumentSynthPad":"(21) የመራሄ ድምፅ ደረብ","music.instrumentTrombone":"(9) ትሮምቦን","music.instrumentVibraphone":"(16) ቫይብራፎን","music.instrumentWoodenFlute":"(13) የእንጨት ፍሉት","music.midiPlayDrumForBeats":"play drum [DRUM] for [BEATS] beats","music.midiSetInstrument":"set instrument to [INSTRUMENT]","music.playDrumForBeats":"[DRUM]ን ታምቡር ለ[BEATS] ምት ተጫውት","music.playNoteForBeats":"[NOTE]ን ኖታ ለ[BEATS] ምት ተጫውት","music.restForBeats":"እረፍ ለ[BEATS] ምት","music.setInstrument":"መሳሪያ ለውጥ ወደ [INSTRUMENT]","music.setTempo":"ስልት ለውጥ ወደ [TEMPO]","pen.categoryName":"ብዕር","pen.changeColorParam":"የእስክሪብቶን [COLOR_PARAM] ቀይር በ[VALUE]","pen.changeHue":"የእስክሪብቶን ቀልም ቀይር በ[HUE]","pen.changeShade":"የእስክሪብቶን ጥቁረት ቀይር በ[SHADE]","pen.changeSize":"የእስክሪብቶን ልክ ቀይር በ[SIZE]","pen.clear":"ሁሉንም አስወግድ","pen.colorMenu.brightness":"የብርሀን መጠን","pen.colorMenu.color":"ቀለም","pen.colorMenu.saturation":"ርኬት","pen.colorMenu.transparency":"አሳይነት","pen.penDown":"ብእር አሳርፍ","pen.penUp":"ብእር አንሳ","pen.setColor":"የእስክሪብቶን ቀልም ወደ [COLOR] ለውጥ","pen.setColorParam":"የእስክሪብቶን [COLOR_PARAM] ወደ [VALUE] ለውጥ","pen.setHue":"የእስክሪብቶን ቀለም ወደ [HUE] ለውጥ","pen.setShade":"የእስክሪብቶን ጥቁረት ወደ [SHADE] ለውጥ","pen.setSize":"የእስክሪብቶን ልክ ወደ [SIZE] ለውጥ","pen.stamp":"ምልክት","text2speech.alto":"alto","text2speech.categoryName":"Text to Speech","text2speech.defaultTextToSpeak":"hello","text2speech.giant":"giant","text2speech.kitten":"የድመት ግልገል","text2speech.setLanguageBlock":"set language to [LANGUAGE]","text2speech.setVoiceBlock":"ድምጽ ወደ [VOICE] ለውጥ","text2speech.speakAndWaitBlock":"[WORDS]ን ተናገር","text2speech.squeak":"ሲጢት ማለት","text2speech.tenor":"tenor","translate.categoryName":"Translate","translate.defaultTextToTranslate":"ሰላም","translate.translateBlock":"[WORDS]ን ተርጉም ወደ [LANGUAGE]","translate.viewerLanguage":"ቋንቋ","videoSensing.categoryName":"የቪድዮ ህዋስ","videoSensing.direction":"አቅጣጫ","videoSensing.motion":"እንቅስቃሴ","videoSensing.off":"የጠፋ","videoSensing.on":"እየሰራ ያለ","videoSensing.onFlipped":"ሲገለብጥ","videoSensing.setVideoTransparency":"የቪድዮ አሳይነት ወደ [TRANSPARENCY] ለውጥ","videoSensing.sprite":"ስፕራይት","videoSensing.stage":"መድረክ","videoSensing.videoOn":"ቪድዮ [ATTRIBUTE] ስለ [SUBJECT]","videoSensing.videoToggle":"ቪድዮ ወደ [VIDEO_STATE] ቀይር","videoSensing.whenMotionGreaterThan":"የቪድዮ እንቅስቃሴ > [REFERENCE] ሲሆን","wedo2.getDistance":"ርቀት","wedo2.getTiltAngle":"የዝንባሌ ማዕዘን [TILT_DIRECTION]","wedo2.isTilted":"[TILT_DIRECTION_ANY]ተዘነብሏል? ","wedo2.motorDirection.backward":"that way","wedo2.motorDirection.forward":"this way","wedo2.motorDirection.reverse":"reverse","wedo2.motorId.a":"motor A","wedo2.motorId.all":"all motors","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"[MOTOR_ID]ን ሞተር አጥፋ","wedo2.motorOn":"[MOTOR_ID]ን ሞተር አብራ","wedo2.motorOnFor":"[MOTOR_ID]ን ሞተር አብራ ለ[DURATION] ሰከንድ ","wedo2.playNoteFor":"[NOTE]ን ኖታ ለ[DURATION] ተጫወት","wedo2.setLightHue":"የመብራት ቀለም ወደ [HUE] ለውጥ","wedo2.setMotorDirection":"የ[MOTOR_ID]ን ሞተር አቅጣጫ ወደ [MOTOR_DIRECTION] ለውጥ","wedo2.startMotorPower":"የ[MOTOR_ID]ን ሞተር ኃይል ወደ [POWER] ለውጥ","wedo2.tiltDirection.any":"any","wedo2.tiltDirection.down":"down","wedo2.tiltDirection.left":"left","wedo2.tiltDirection.right":"right","wedo2.tiltDirection.up":"up","wedo2.whenDistance":"ርቀት [OP] [REFERENCE] ሲሆን","wedo2.whenTilted":"በ[TILT_DIRECTION_ANY] ሲዘነብል","paint.paintEditor.hue":"ቀለም","paint.paintEditor.saturation":"ርኬት","paint.paintEditor.brightness":"ብሩህነት","paint.paintEditor.costume":"ልብስ","paint.paintEditor.group":"ቡድን","paint.paintEditor.ungroup":"በቡድን የተመደበውን በተን","paint.paintEditor.undo":"መልስ","paint.paintEditor.redo":"ድጋሜ አድርግ","paint.paintEditor.forward":"ወደፊት","paint.paintEditor.backward":"ወደኋላ","paint.paintEditor.front":"ፊት","paint.paintEditor.back":"ኋላ","paint.paintEditor.more":"ተጨማሪ","paint.modeTools.brushSize":"ልክ","paint.modeTools.eraserSize":"የላጲስ ልክ","paint.modeTools.copy":"ቅዳ","paint.modeTools.paste":"ለጥፍ","paint.modeTools.delete":"አጥፋ","paint.modeTools.curved":"የታጠፈ","paint.modeTools.pointed":"ሾለ","paint.modeTools.thickness":"ውፍረት","paint.modeTools.flipHorizontal":"በግድምታ አሽከርክር","paint.modeTools.flipVertical":"በሽቅብዮሽ አሽከርክር","paint.modeTools.filled":"የተሟላ","paint.modeTools.outlined":"የተቀረፀ","paint.paintEditor.bitmap":"ወደ ንድፈ ቅንጣት ለውጥ","paint.paintEditor.vector":"ወደ ቬክተር ለውጥ","paint.paintEditor.fill":"ምላት","paint.paintEditor.stroke":"ቅረፅ","paint.brushMode.brush":"ብሩሽ","paint.eraserMode.eraser":"ላጲስ","paint.fillMode.fill":"ምላት","paint.lineMode.line":"መስመር","paint.ovalMode.oval":"ክብ","paint.rectMode.rect":"አራት ማዕዘን","paint.reshapeMode.reshape":"እንደገና ቅረጽ","paint.roundedRectMode.roundedRect":"የተድበለበለ አራት ማዕዘን","paint.selectMode.select":"ምረጥ","paint.textMode.text":"ጽሀፍ","paint.colorPicker.swap":"ለዋውጥ"},"an":{"gui.alerts.tryAgain":"Torna a prebar-lo","gui.alerts.download":"Descargar","gui.connection.reconnect":"Reconnectar","gui.backpack.costumeLabel":"vestiu","gui.backpack.soundLabel":"son","gui.backpack.scriptLabel":"programa","gui.backpack.spriteLabel":"obchecto","gui.backpack.header":"Muchila","gui.backpack.errorBackpack":"Error en cargar la muchila","gui.backpack.loadingBackpack":"Cargando...","gui.backpack.more":"Mas","gui.backpack.emptyBackpack":"La muchila ye vueda","gui.unsupportedBrowser.label":"Lo navegador no ye compatible","gui.cards.all-tutorials":"Tutorials","gui.cards.shrink":"Achiquir","gui.cards.expand":"Expandir","gui.cards.close":"Zarrar","gui.cards.more-things-to-try":"Mas cosetas pa prebar!","gui.cards.see-more":"Veyer mas","gui.comingSoon.message1":"No te\'n fagas, somos en ixo {emoji}","gui.comingSoon.message2":"Proximament...","gui.comingSoon.message3":"Somos treballando en ixo {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"No s\'han trobau dispositivos","gui.connection.auto-scanning.prescan":"Tiene lo tuyo dispositivo cerca, y alavez empecipia a buscar.","gui.connection.auto-scanning.pressbutton":"Preta lo botón d\'o tuyo dispositivo.","gui.connection.auto-scanning.start-search":"Empecipiar a buscar","gui.connection.connecting-searchbutton":"Buscando...","gui.connection.auto-scanning.try-again":"Prebar de nuevo","gui.connection.connected":"Connectau","gui.connection.disconnect":"Desconnectar","gui.connection.go-to-editor":"Ir ta lo editor","gui.connection.connecting-cancelbutton":"Connectando...","gui.connection.error.errorMessage":"Ups, pareixe que bella cosa ha fallau.","gui.connection.error.tryagainbutton":"Prebar de nuevo","gui.connection.error.helpbutton":"Aduya","gui.connection.peripheral-name-label":"Nombre d\'o dispositivo","gui.connection.connect":"Connectar","gui.connection.scanning.lookingforperipherals":"Buscando dispositivos","gui.connection.scanning.noPeripheralsFound":"No s\'ha trobau dispositivos","gui.connection.scanning.instructions":"Tría lo tuyo dispositivo d\'a lista.","gui.connection.search":"Actualizar","gui.connection.unavailable.installscratchlink":"Asegura-te que tiens Scratch Link instalau y ubierto","gui.connection.unavailable.enablebluetooth":"Compreba que Bluetooth sía habilitau","gui.connection.unavailable.tryagainbutton":"Prebar de nuevo","gui.connection.unavailable.helpbutton":"Aduya","gui.controls.go":"Ir","gui.controls.stop":"Aturar","gui.crashMessage.label":"Ups! Bella cosa ha fallau.","gui.crashMessage.errorNumber":"La suya error ha estau rechistrada con ID {errorId}","gui.crashMessage.reload":"Tornar a cargar","gui.customProcedures.myblockModalTitle":"Creyar un bloque","gui.customProcedures.addAnInputNumberText":"Anyadir una dentrada","gui.customProcedures.numberTextType":"numero u texto","gui.customProcedures.addAnInputBoolean":"Anyadir una dentrada","gui.customProcedures.booleanType":"lochica","gui.customProcedures.addALabel":"Anyadir una etiqueta","gui.customProcedures.runWithoutScreenRefresh":"Executar a l\'inte","gui.customProcedures.cancel":"Cancelar","gui.customProcedures.ok":"Acceptar","gui.SpriteInfo.direction":"Dirección","gui.directionPicker.rotationStyles.allAround":"Tot alredor","gui.directionPicker.rotationStyles.leftRight":"Zurda/Dreita","gui.directionPicker.rotationStyles.dontRotate":"No rotar","gui.gui.addExtension":"Anyadir extensión","gui.gui.codeTab":"Codigo","gui.gui.backdropsTab":"Fondos","gui.gui.costumesTab":"Vestius","gui.gui.soundsTab":"Sons","gui.extensionLibrary.comingSoon":"Proximament...","gui.extensionLibrary.requires":"Requiere","gui.extensionLibrary.collaboration":"En colaboración con","gui.library.filterPlaceholder":"Busca","gui.library.allTag":"Totz","gui.loader.headline":"Cargando prochecto","gui.loader.creating":"Creyando lo prochecto","gui.authorInfo.byUser":"per {username}","gui.menuBar.seeProjectPage":"Veyer pachina d\'o prochecto","gui.menuBar.LanguageSelector":"selector d\'idioma","gui.menuBar.tutorialsLibrary":"Tutorials","gui.menuBar.restoreSprite":"Restaurar obchecto","gui.menuBar.restoreSound":"Restaurar son","gui.menuBar.restoreCostume":"Restaurar disfraz","gui.menuBar.restore":"Restaurar","gui.menuBar.saveNow":"Alzar agora","gui.menuBar.saveAsCopy":"Alzar una copia","gui.menuBar.remix":"Remesclar","gui.menuBar.new":"Nuevo","gui.menuBar.file":"Fichero","gui.menuBar.downloadToComputer":"Alzar en o tuyo ordinador","gui.menuBar.edit":"Editar","gui.menuBar.turboModeOff":"Desactivar lo modo Turbo","gui.menuBar.turboModeOn":"Activar lo modo Turbo","gui.gui.projectTitlePlaceholder":"Nombre d\'o prochecto aquí","gui.menuBar.isShared":"Compartius","gui.menuBar.share":"Compartir","gui.modal.help":"Aduya","gui.modal.back":"Dezaga","gui.monitor.listMonitor.empty":"(vueda)","gui.monitor.listMonitor.listLength":"longaria {length}","gui.monitor.contextMenu.default":"grandaria normal","gui.monitor.contextMenu.large":"grandaria gran","gui.monitor.contextMenu.slider":"eslizador","gui.monitor.contextMenu.sliderRange":"cambiar rango d\'o eslizador","gui.monitor.contextMenu.import":"importar","gui.monitor.contextMenu.export":"exportar","gui.monitor.contextMenu.hide":"amagar","gui.playButton.play":"Reproducir","gui.playButton.stop":"Aturar","gui.gui.variableScopeOptionAllSprites":"Pa totz los obchectos","gui.gui.variableScopeOptionSpriteOnly":"Nomás pa este obchecto","gui.gui.cloudVariableOption":"Variable en a boira (alzada en o servidor)","gui.gui.variablePromptAllSpritesMessage":"Esta variable será disponible en totz los obchectos.","gui.gui.listPromptAllSpritesMessage":"Esta lista será disponible pa totz los obchectos.","gui.prompt.cancel":"Cancelar","gui.prompt.ok":"Acceptar","gui.playbackStep.stopMsg":"Aturar","gui.playbackStep.playMsg":"Reproducir","gui.playbackStep.loadingMsg":"Cargando...","gui.playbackStep.saveMsg":"Alzar","gui.playbackStep.reRecordMsg":"Tornar a gravar","gui.recordModal.title":"Gravar son","gui.recordingStep.beginRecord":"Prencipia a gravar fendo clic en o siguient botón","gui.recordingStep.permission":"{arrow}Nos cal lo tuyo permiso pa usar lo microfono","gui.recordingStep.stop":"Deixar de gravar","gui.recordingStep.record":"Gravar","gui.sliderModal.min":"Valor minima","gui.sliderModal.max":"Valor maxima","gui.sliderModal.title":"Cambiar rango d\'o eslizador","gui.sliderPrompt.cancel":"Cancelar","gui.sliderPrompt.ok":"Acceptar","gui.soundEditor.sound":"Son","gui.soundEditor.play":"Reproducir","gui.soundEditor.stop":"Aturar","gui.soundEditor.copy":"Copiar","gui.soundEditor.paste":"Apegar","gui.soundEditor.copyToNew":"Copiar en nuevo","gui.soundEditor.delete":"Eliminar","gui.soundEditor.save":"Alzar","gui.soundEditor.undo":"Desfer","gui.soundEditor.redo":"Refer","gui.soundEditor.faster":"Mas rapido","gui.soundEditor.slower":"Mas lento","gui.soundEditor.echo":"Eco","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Mas fuerte","gui.soundEditor.softer":"Mas suau","gui.soundEditor.reverse":"Invertir","gui.soundEditor.fadeOut":"Desapareixer","gui.soundEditor.fadeIn":"Amaneixer","gui.soundEditor.mute":"Silenciar","gui.SpriteInfo.spritePlaceholder":"Nombre","gui.SpriteInfo.sprite":"Obchecto","gui.SpriteInfo.show":"Amostrar","gui.SpriteInfo.size":"Grandaria","gui.spriteSelectorItem.contextMenuDuplicate":"duplicar","gui.spriteSelectorItem.contextMenuExport":"exportar","gui.spriteSelectorItem.contextMenuDelete":"borrar","gui.spriteSelector.addSpriteFromLibrary":"Tría un obchecto","gui.spriteSelector.addSpriteFromPaint":"Pinta","gui.spriteSelector.addSpriteFromSurprise":"Sorpresa","gui.spriteSelector.addSpriteFromFile":"Puyar obchecto","gui.stageHeader.stageSizeLarge":"Cambiar a escenario gran","gui.stageHeader.stageSizeSmall":"Cambiar a escenario chicot","gui.stageHeader.stageSizeFull":"Ir a modo pantalla completa","gui.stageHeader.stageSizeUnFull":"Salir d\'o modo de pantalla completa","gui.stageHeader.fullscreenControl":"Control a pantalla completa","gui.spriteSelector.addBackdropFromLibrary":"Tría un fondo","gui.stageSelector.addBackdropFromPaint":"Pinta","gui.stageSelector.addBackdropFromSurprise":"Sorpresa","gui.stageSelector.addBackdropFromFile":"Carga un fondo","gui.stageSelector.stage":"Escenario","gui.stageSelector.backdrops":"Fondos","gui.telemetryOptIn.label":"Reportar las estatisticas pa amillorar Scratch","gui.telemetryOptIn.body1":"L\'Equipo de Scratch busca comprender d\'a millor forma cómo s\'utiliza Scratch arredol d\'o mundo. Pa emparar istos esfuerzos, puede permitir que Scratch ninvie información d\'uso de forma automatica a l\'Equipo de Scratch.","gui.telemetryOptIn.body2":"La información que recopilamos incluye selección d\'idioma, uso de bloques y qualques eventos como alzar, cargar y puyar un prochecto. NO replegamos garra información personal. Per favor, consulta nuestra {privacyPolicyLink} pa mas información.","gui.telemetryOptIn.privacyPolicyLink":"Politica de privacidat","gui.telemetryOptIn.optInText":"Compartir os míos datos d\'uso con l\'equipo de Scratch","gui.telemetryOptIn.optInTooltip":"Habilitar telemetría","gui.telemetryOptIn.optOutText":"No compartir os míos datos d\'uso con l\'equipo de Scratch","gui.telemetryOptIn.optOutTooltip":"Desactivar la telemetria","gui.telemetryOptIn.settingWasUpdated":"A tuya configuración estió actualizada.","gui.telemetryOptIn.buttonClose":"Zarrar","gui.turboMode.active":"Modo Turbo","gui.webglModal.label":"Lo tuyo navegador no suporta WebGL","gui.webglModal.webgllink":"no suporta WebGL","gui.costumeLibrary.chooseABackdrop":"Tría un fondo","gui.costumeLibrary.chooseACostume":"Tría un disfraz","gui.costumeTab.addBackdropFromLibrary":"Tría un fondo","gui.costumeTab.addCostumeFromLibrary":"Tría un disfraz","gui.costumeTab.addBlankCostume":"Pinta","gui.costumeTab.addSurpriseCostume":"Sorpresa","gui.costumeTab.addFileBackdrop":"Carga un fondo","gui.costumeTab.addFileCostume":"Carga un vestiu","gui.extensionLibrary.chooseAnExtension":"Tría una extensión","gui.extensionLibrary.extensionUrl":"Introduz la URL d\'a extensión","gui.monitors.importListColumnPrompt":"Qué columna ha d\'usar-se (1- {numberOfColumns})?","gui.recordingStep.alertMsg":"No s\'ha puesto empecipiar a gravar","gui.soundLibrary.chooseASound":"Tría un son","gui.soundTab.fileUploadSound":"Carga un son","gui.soundTab.surpriseSound":"Sorpresa","gui.soundTab.recordSound":"Gravar","gui.soundTab.addSoundFromLibrary":"Tría un son","gui.spriteLibrary.chooseASprite":"Tría un obchecto","gui.tipsLibrary.tutorials":"Tría un tutorial","gui.alerts.createsuccess":"Nuevo prochecto creyau.","gui.alerts.createcopysuccess":"Prochecto alzau como copia.","gui.alerts.createremixsuccess":"Prochecto alzau como remescla.","gui.alerts.creating":"Creyando nuevo...","gui.alerts.creatingCopy":"Copiando prochecto...","gui.alerts.creatingRemix":"Remesclando prochecto...","gui.alerts.creatingError":"No s\'ha puesto creyar lo prochecto. Per favor, preba-lo de nuevo!","gui.alerts.savingError":"No s\'ha puesto alzar lo prochecto.","gui.alerts.savesuccess":"Prochecto alzau.","gui.alerts.saving":"Alzando prochecto...","gui.alerts.cloudInfo":"Faga-se cuenta que las variables en a boira nomás admiten numeros, no letras ni simbolos. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Mas información.","gui.alerts.importing":"Importando…","gui.defaultProject.variable":"lo mío variable","gui.extension.music.name":"Mosica","gui.extension.music.description":"Toca trastes y percusión.","gui.extension.pen.name":"Lapiz","gui.extension.pen.description":"Dibuixa con os tuyos obchectos.","gui.extension.videosensing.name":"Sensor de vídeo","gui.extension.videosensing.description":"Detecta movimientos con a camera.","gui.extension.text2speech.name":"Texto a voz","gui.extension.text2speech.description":"Fe que los tuyos prochectos charren.","gui.extension.translate.name":"Traducir","gui.extension.translate.description":"Traduz texto a muitos idiomas.","gui.extension.makeymakey.description":"Convierte qualsequier coseta en una tecla.","gui.extension.microbit.description":"Connecta los tuyos prochectos con o mundo.","gui.extension.microbit.connectingMessage":"Connectando","gui.extension.ev3.description":"Construye robots interactivos y muito mas.","gui.extension.ev3.connectingMessage":"Connectando. Asegura-te que lo PIN d\'a tuya EV3 ye 1234.","gui.extension.boost.description":"Da-le vida a las tuyas creacions roboticas.","gui.extension.boost.connectingMessage":"Connectando","gui.extension.wedo2.description":"Construye con motors y sensors.","gui.extension.wedo2.connectingMessage":"Connectando","gui.extension.gdxfor.description":"Detecta empuixe, tirón, movimiento u chiro.","gui.extension.gdxfor.connectingMessage":"Connectando","gui.libraryTags.all":"Totz","gui.libraryTags.animals":"Animals","gui.libraryTags.dance":"Bailar","gui.libraryTags.effects":"Efectos","gui.libraryTags.fantasy":"Fantesía","gui.libraryTags.fashion":"Moda","gui.libraryTags.food":"Minchada","gui.libraryTags.indoors":"Interiors","gui.libraryTags.loops":"Bucles","gui.libraryTags.music":"Mosica","gui.libraryTags.notes":"Notas","gui.libraryTags.outdoors":"Exteriors","gui.libraryTags.patterns":"Patrons","gui.libraryTags.people":"Chent","gui.libraryTags.percussion":"Percusión","gui.libraryTags.space":"Espacio","gui.libraryTags.sports":"Esportes","gui.libraryTags.underwater":"Baixo lo #mar","gui.libraryTags.voice":"Voz","gui.libraryTags.wacky":"Locuras","gui.libraryTags.animation":"Animación","gui.libraryTags.art":"Arte","gui.libraryTags.games":"Chuegos","gui.libraryTags.stories":"Historias","gui.libraryTags.letters":"Letras","gui.opcodeLabels.direction":"dirección","gui.opcodeLabels.xposition":"posición en x","gui.opcodeLabels.yposition":"posición en y","gui.opcodeLabels.size":"grandaria","gui.opcodeLabels.costumename":"nombre de vestiu","gui.opcodeLabels.costumenumber":"numero de vestiu","gui.opcodeLabels.backdropname":"nombre de fondo","gui.opcodeLabels.backdropnumber":"numero de fondo","gui.opcodeLabels.volume":"volumen","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"respuesta","gui.opcodeLabels.loudness":"volumen d\'o son","gui.opcodeLabels.username":"nombre d\'usuario","gui.opcodeLabels.year":"anyo","gui.opcodeLabels.month":"mes","gui.opcodeLabels.date":"data","gui.opcodeLabels.dayofweek":"día d\'a semana","gui.opcodeLabels.hour":"hora","gui.opcodeLabels.minute":"menuto","gui.opcodeLabels.second":"segundo","gui.opcodeLabels.timer":"cronometro","gui.sharedMessages.backdrop":"fondo{index}","gui.sharedMessages.costume":"vestiu{index}","gui.sharedMessages.sprite":"Obchecto{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Reemplazar lo conteniu d\'o prochecto actual?","gui.sharedMessages.loadFromComputerTitle":"Cargar dende lo tuyo ordinador","boost.color.any":"de qualsiquier color","boost.color.black":"negro","boost.color.blue":"azul","boost.color.green":"verde","boost.color.red":"royo","boost.color.white":"blanco","boost.color.yellow":"amariello","boost.getMotorPosition":"posición d\'o motor [MOTOR_REPORTER_ID]","boost.getTiltAngle":"anglo d\'inclinación enta [TILT_DIRECTION]","boost.motorDirection.backward":"ta un costau","boost.motorDirection.forward":"ta l\'atro costau","boost.motorDirection.reverse":"a la inversa","boost.motorOff":"amortar motor [MOTOR_ID]","boost.motorOn":"enchegar motor [MOTOR_ID]","boost.motorOnFor":"chirar motor [MOTOR_ID] [DURATION] segundos","boost.motorOnForRotation":"chirar motor [MOTOR_ID] [ROTATION] vueltas","boost.seeingColor":"detecta lo bloque [COLOR]?","boost.setLightHue":"fixar color d\'a luz a [HUE]","boost.setMotorDirection":"fixar adreza d\'o motor [MOTOR_ID] [MOTOR_DIRECTION]","boost.setMotorPower":"fixar velocidat d\'o motor [MOTOR_ID] a o [POWER] %","boost.tiltDirection.any":"qualsequiera","boost.tiltDirection.down":"abaixo","boost.tiltDirection.left":"zurda","boost.tiltDirection.right":"dreita","boost.tiltDirection.up":"alto","boost.whenColor":"en detectar lo bloque [COLOR]","boost.whenTilted":"en abocar-se enta [TILT_DIRECTION_ANY]","ev3.beepNote":"tanyer nota [NOTE] [TIME] segundos","ev3.buttonPressed":"botón [PORT] pretau?","ev3.getBrightness":"brilo","ev3.getDistance":"distancia","ev3.getMotorPosition":"posición d\'o motor [PORT]","ev3.motorSetPower":"motor [PORT] fixar potencia a [POWER] %","ev3.motorTurnClockwise":"motor [PORT] chirar ta un costau [TIME] segundos","ev3.motorTurnCounterClockwise":"motor [PORT] chirar a l\'atro costau [TIME] segundos","ev3.whenBrightnessLessThan":"quan brilo < [DISTANCE]","ev3.whenButtonPressed":"en pretar botón [PORT]","ev3.whenDistanceLessThan":"quan distancia < [DISTANCE]","gdxfor.getAcceleration":"acceleración [DIRECTION]","gdxfor.getForce":"fuerza","gdxfor.getSpin":"velocidat de chiro [DIRECTION]","gdxfor.getTilt":"anglo d\'inclinación [TILT]","gdxfor.isFreeFalling":"cayendo?","gdxfor.isTilted":"abocau [TILT]?","gdxfor.pulled":"estirau enta difuera","gdxfor.pushed":"empuixau enta dintro","gdxfor.shaken":"sobatiu","gdxfor.startedFalling":"prencipiau a cayer","gdxfor.tiltDirectionMenu.any":"en qualsiquier dirección","gdxfor.tiltDirectionMenu.back":"dezaga","gdxfor.tiltDirectionMenu.front":"debant","gdxfor.tiltDirectionMenu.left":"zurda","gdxfor.tiltDirectionMenu.right":"dreita","gdxfor.turnedFaceDown":"cara enta abaixo","gdxfor.turnedFaceUp":"cara enta alto","gdxfor.whenForcePushedOrPulled":"quan o sensor de fuerza [PUSH_PULL]","gdxfor.whenGesture":"quan [GESTURE]","gdxfor.whenTilted":"en abocar-se [TILT]","makeymakey.downArrow":"flecha enta abaixo","makeymakey.downArrowShort":"abaixo","makeymakey.leftArrow":"flecha enta la zurda","makeymakey.leftArrowShort":"zurda","makeymakey.rightArrow":"flecha enta la dreita","makeymakey.rightArrowShort":"dreita","makeymakey.spaceKey":"espacio","makeymakey.upArrow":"flecha enta alto","makeymakey.upArrowShort":"alto","makeymakey.whenKeyPressed":"en presionar tecla [KEY]","makeymakey.whenKeysPressedInOrder":"en presionar [SEQUENCE] en orden","microbit.buttonsMenu.any":"qualsiquiera","microbit.clearDisplay":"limpiar pantalla","microbit.defaultTextToDisplay":"Ola!","microbit.displaySymbol":"amostrar [MATRIX]","microbit.displayText":"amostrar texto [TEXT]","microbit.gesturesMenu.jumped":"blincau","microbit.gesturesMenu.moved":"moviu","microbit.gesturesMenu.shaken":"sobatiu","microbit.isButtonPressed":"botón [BTN] presionau?","microbit.isTilted":"abocau enta [DIRECTION]?","microbit.pinStateMenu.off":"amortar","microbit.pinStateMenu.on":"enchegar","microbit.tiltAngle":"anglo d\'inclinación enta [DIRECTION]","microbit.tiltDirectionMenu.any":"qualsequiera","microbit.tiltDirectionMenu.back":"dezaga","microbit.tiltDirectionMenu.front":"debant","microbit.tiltDirectionMenu.left":"zurda","microbit.tiltDirectionMenu.right":"dreita","microbit.whenButtonPressed":"en pretar botón [BTN]","microbit.whenGesture":"quan [GESTURE]","microbit.whenPinConnected":"en connectar pin [PIN]","microbit.whenTilted":"en abocar-se enta [DIRECTION]","music.categoryName":"Mosica","music.changeTempo":"cambiar tempo por [TEMPO]","music.drumBass":"(2) Bombo","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Claus","music.drumClosedHiHat":"(6) Charleston zarrau","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Esquilla","music.drumCrashCymbal":"(4) Plated crash","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Güiro","music.drumHandClap":"(8) Palmada","music.drumOpenHiHat":"(5) Charleston ubierto","music.drumSideStick":"(3) Truco lateral","music.drumSnare":"(1) Caixa","music.drumTambourine":"(7) Pandereta","music.drumTriangle":"(12) Trianglo","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Caixa chinesa","music.getTempo":"tempo","music.instrumentBass":"(6) Baixo","music.instrumentBassoon":"(14) Fagot","music.instrumentCello":"(8) Violonchelo","music.instrumentChoir":"(15) Coro","music.instrumentClarinet":"(10) Clarinet","music.instrumentElectricGuitar":"(5) Guitarra electrica","music.instrumentElectricPiano":"(2) Piano electrico","music.instrumentFlute":"(12) Chiflo","music.instrumentGuitar":"(4) Guitarra","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Caixa de mosica","music.instrumentOrgan":"(3) Organo","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxofón","music.instrumentSteelDrum":"(18) Tambor metalico","music.instrumentSynthLead":"(20) Sintetizador melodico","music.instrumentSynthPad":"(21) Sintetizador de fondo","music.instrumentTrombone":"(9) Trompón","music.instrumentVibraphone":"(16) Vibrafono","music.instrumentWoodenFlute":"(13) Chiflo de fusta","music.midiPlayDrumForBeats":"tanyer tambor [DRUM] por [BEATS] tiempos","music.midiSetInstrument":"fixar instrumento a [INSTRUMENT]","music.playDrumForBeats":"tanyer tambor [DRUM] por [BEATS] tiempos","music.playNoteForBeats":"tanyer nota [NOTE] por [BEATS] tiempos","music.restForBeats":"silencio de [BEATS] tiempos","music.setInstrument":"fixar instrumento a [INSTRUMENT]","music.setTempo":"dar a tempo a valor [TEMPO]","pen.categoryName":"Lapicero","pen.changeColorParam":"cambiar [COLOR_PARAM] de lapicero por [VALUE]","pen.changeHue":"cambiar color de lapicero por [HUE]","pen.changeShade":"cambiar uembra de lapicero por [SHADE]","pen.changeSize":"cambiar grandaria de lapicero por [SIZE]","pen.clear":"borrar tot","pen.colorMenu.brightness":"brilo","pen.colorMenu.color":"color","pen.colorMenu.saturation":"saturación","pen.colorMenu.transparency":"transparencia","pen.penDown":"baixar lapicero","pen.penUp":"puyar lapicero","pen.setColor":"fixar color de lapicero a [COLOR]","pen.setColorParam":"fixar [COLOR_PARAM] de lapicero a [VALUE]","pen.setHue":"fixar color de lapicero a [HUE]","pen.setShade":"fixar uembra de lapicero a [SHADE]","pen.setSize":"fixar grandaria de lapicero a [SIZE]","pen.stamp":"sellar","text2speech.alto":"contralto","text2speech.categoryName":"Texto a voz","text2speech.defaultTextToSpeak":"ola","text2speech.giant":"chigant","text2speech.kitten":"gatolín","text2speech.setLanguageBlock":"fixar idioma a [LANGUAGE]","text2speech.setVoiceBlock":"fixar voz a [VOICE]","text2speech.speakAndWaitBlock":"decir [WORDS]","text2speech.squeak":"chilo","text2speech.tenor":"tenor","translate.categoryName":"Traducción","translate.defaultTextToTranslate":"ola","translate.translateBlock":"traducir [WORDS] enta lo [LANGUAGE]","translate.viewerLanguage":"idioma","videoSensing.categoryName":"Sensor de video","videoSensing.direction":"dirección","videoSensing.motion":"movimiento","videoSensing.off":"amortar","videoSensing.on":"enchegar","videoSensing.onFlipped":"contornar","videoSensing.setVideoTransparency":"fixar transparencia de video a [TRANSPARENCY]","videoSensing.sprite":"obchecto","videoSensing.stage":"scenario","videoSensing.videoOn":"[ATTRIBUTE] de video en [SUBJECT]","videoSensing.videoToggle":"[VIDEO_STATE] video","videoSensing.whenMotionGreaterThan":"quan movimiento de video > [REFERENCE]","wedo2.getDistance":"distancia","wedo2.getTiltAngle":"anglo d\'inclinación enta [TILT_DIRECTION]","wedo2.isTilted":"abocau enta [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"per astí","wedo2.motorDirection.forward":"per aquí","wedo2.motorDirection.reverse":"inversa","wedo2.motorId.a":"motor A","wedo2.motorId.all":"totz los motors","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"amortar [MOTOR_ID]","wedo2.motorOn":"enchegar [MOTOR_ID]","wedo2.motorOnFor":"enchegar [MOTOR_ID] por [DURATION] segundos","wedo2.playNoteFor":"tanyer nota [NOTE] por [DURATION] segundos","wedo2.setLightHue":"fixar color d\'a luz a [HUE]","wedo2.setMotorDirection":"fixar dirección de [MOTOR_ID] a [MOTOR_DIRECTION]","wedo2.startMotorPower":"fixar potencia de [MOTOR_ID] a [POWER]","wedo2.tiltDirection.any":"qualsequier","wedo2.tiltDirection.down":"abaixo","wedo2.tiltDirection.left":"zurda","wedo2.tiltDirection.right":"dreita","wedo2.tiltDirection.up":"alto","wedo2.whenDistance":"quan distancia [OP] [REFERENCE]","wedo2.whenTilted":"en abocar-se enta [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Color","paint.paintEditor.saturation":"Saturación","paint.paintEditor.brightness":"Brilo","paint.paintEditor.costume":"Vestiu","paint.paintEditor.group":"Grupo","paint.paintEditor.ungroup":"Desagrupar","paint.paintEditor.undo":"Desfer","paint.paintEditor.redo":"Refer","paint.paintEditor.forward":"Enta debant","paint.paintEditor.backward":"Enta zaga","paint.paintEditor.front":"Debant","paint.paintEditor.back":"Dezaga","paint.paintEditor.more":"Mas","paint.modeTools.brushSize":"Grandaria","paint.modeTools.eraserSize":"Grandaria d\'o borrador","paint.modeTools.copy":"Copiar","paint.modeTools.paste":"Apegar","paint.modeTools.delete":"Borrar","paint.modeTools.curved":"Curva","paint.modeTools.pointed":"Puncha","paint.modeTools.thickness":"Gordaria","paint.modeTools.flipHorizontal":"Chirar en horizontal","paint.modeTools.flipVertical":"Chirar en vertical","paint.modeTools.filled":"Repleno","paint.modeTools.outlined":"Deliniau","paint.paintEditor.bitmap":"Tornar en mapa de bits","paint.paintEditor.vector":"Tornar en vectorial","paint.paintEditor.fill":"Replenar","paint.paintEditor.stroke":"Linia","paint.brushMode.brush":"Pincel","paint.eraserMode.eraser":"Borrador","paint.fillMode.fill":"Replenar","paint.lineMode.line":"Linia","paint.ovalMode.oval":"Cerclo","paint.rectMode.rect":"Rectanglo","paint.reshapeMode.reshape":"Cambiar forma","paint.roundedRectMode.roundedRect":"Rectanglo redondiau","paint.selectMode.select":"Seleccionar","paint.textMode.text":"Texto","paint.colorPicker.swap":"Cambiar"},"ast":{"gui.alerts.tryAgain":"Intentar otra vuelta","gui.alerts.download":"Descargar","gui.connection.reconnect":"Reconeutar","gui.backpack.costumeLabel":"disfraz","gui.backpack.soundLabel":"soníu","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"personaxe","gui.backpack.header":"Maletu","gui.backpack.errorBackpack":"Error cargando\'l maletu","gui.backpack.loadingBackpack":"Cargando...","gui.backpack.more":"Más","gui.backpack.emptyBackpack":"Maletu vacíu","gui.unsupportedBrowser.label":"Restolador non soportáu","gui.cards.all-tutorials":"Tutoriales","gui.cards.shrink":"Encoyer","gui.cards.expand":"Espurrir","gui.cards.close":"Zarrar","gui.cards.more-things-to-try":"¡Más coses a intentar!","gui.cards.see-more":"Ver más","gui.comingSoon.message1":"Nun t\'esmolezas, tamos nello {emoji}","gui.comingSoon.message2":"Aportando en Breve...","gui.comingSoon.message3":"Tamos trabayando nello {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Nun s\'atoparon preseos","gui.connection.auto-scanning.prescan":"Ten el preséu cerca y entama la gueta.","gui.connection.auto-scanning.pressbutton":"Calca\'l botón nel preséu.","gui.connection.auto-scanning.start-search":"Entamar Gueta","gui.connection.connecting-searchbutton":"Guetando...","gui.connection.auto-scanning.try-again":"Intentar otra vuelta","gui.connection.connected":"Coneutáu","gui.connection.disconnect":"Desconeutáu","gui.connection.go-to-editor":"Dir al editor","gui.connection.connecting-cancelbutton":"Coneutando...","gui.connection.error.errorMessage":"Ups, daqué salió mal.","gui.connection.error.tryagainbutton":"Intentar otra vuelta","gui.connection.error.helpbutton":"Ayuda","gui.connection.peripheral-name-label":"Nome del preséu","gui.connection.connect":"Coneutar","gui.connection.scanning.lookingforperipherals":"Guetando preseos","gui.connection.scanning.noPeripheralsFound":"Nun s\'atoparon preseos","gui.connection.scanning.instructions":"Esbiya\'l preséu na llista d\'arriba.","gui.connection.search":"Recargar","gui.connection.unavailable.installscratchlink":"Asegúrate que Scratch Link ta instaláu y furrulando","gui.connection.unavailable.enablebluetooth":"Comprueba que ta actváu\'l Bluetooth","gui.connection.unavailable.tryagainbutton":"Intentar otra vuelta","gui.connection.unavailable.helpbutton":"Ayuda","gui.controls.go":"Dir","gui.controls.stop":"Parar","gui.crashMessage.label":"¡Ups! Daqué salió mal.","gui.crashMessage.errorNumber":"L\'error foi grabáu col id {errorId}","gui.crashMessage.reload":"Recargar","gui.customProcedures.myblockModalTitle":"Crear un Bloque","gui.customProcedures.addAnInputNumberText":"Amestar una entrada","gui.customProcedures.numberTextType":"númberu o testu","gui.customProcedures.addAnInputBoolean":"Amestar una entrada","gui.customProcedures.booleanType":"boleana","gui.customProcedures.addALabel":"Amestar una etiqueta","gui.customProcedures.runWithoutScreenRefresh":"Executar ensin refrescu de pantalla","gui.customProcedures.cancel":"Encaboxar","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Direición","gui.directionPicker.rotationStyles.allAround":"Too alredor","gui.directionPicker.rotationStyles.leftRight":"Izquierda/Drecha","gui.directionPicker.rotationStyles.dontRotate":"Nun xirar","gui.gui.addExtension":"Amestar Extensión","gui.gui.codeTab":"Códigu","gui.gui.backdropsTab":"Fondos","gui.gui.costumesTab":"Disfraces","gui.gui.soundsTab":"Soníos","gui.extensionLibrary.comingSoon":"Aportando en Breve","gui.extensionLibrary.requires":"Requisitos","gui.extensionLibrary.collaboration":"Colaboración con","gui.library.filterPlaceholder":"Guetar","gui.library.allTag":"Too","gui.loader.headline":"Cargando proyeutu","gui.loader.creating":"Creando proyeutu","gui.authorInfo.byUser":"por {username}","gui.menuBar.seeProjectPage":"Ver la Páxina del Proyeutu","gui.menuBar.LanguageSelector":"seleutor de llingua","gui.menuBar.tutorialsLibrary":"Tutoriales","gui.menuBar.restoreSprite":"Restaurar Personaxe","gui.menuBar.restoreSound":"Restaurar Soníu","gui.menuBar.restoreCostume":"Restaurar Disfraz","gui.menuBar.restore":"Restaurar","gui.menuBar.saveNow":"Guardar agora","gui.menuBar.saveAsCopy":"Guardar como una copia","gui.menuBar.remix":"Remecer","gui.menuBar.new":"Nuevu","gui.menuBar.file":"Ficheru","gui.menuBar.downloadToComputer":"Guardar nel ordenador","gui.menuBar.edit":"Editar","gui.menuBar.turboModeOff":"Desactivar Mou Turbu","gui.menuBar.turboModeOn":"Prender Mou Turbu","gui.gui.projectTitlePlaceholder":"Títulu del Proyeutu","gui.menuBar.isShared":"Compartíu","gui.menuBar.share":"Compartir","gui.modal.help":"Ayuda","gui.modal.back":"Atrás","gui.monitor.listMonitor.empty":"(ermu)","gui.monitor.listMonitor.listLength":"llargura {length}","gui.monitor.contextMenu.default":"llectura de salida normal","gui.monitor.contextMenu.large":"llectura de salida llarga","gui.monitor.contextMenu.slider":"eslizador","gui.monitor.contextMenu.sliderRange":"cambiar el rangu del eslizador","gui.monitor.contextMenu.import":"importar","gui.monitor.contextMenu.export":"esportar","gui.monitor.contextMenu.hide":"anubrir","gui.playButton.play":"Tocar","gui.playButton.stop":"Parar","gui.gui.variableScopeOptionAllSprites":"Pa tolos personaxes","gui.gui.variableScopeOptionSpriteOnly":"Pa esti personaxe namás","gui.gui.cloudVariableOption":"Variables na Ñube (agospiaes nel sirvidor)","gui.gui.variablePromptAllSpritesMessage":"Esta variable va tar disponible pa tolos personaxes.","gui.gui.listPromptAllSpritesMessage":"Esta llista va tar disponibles pa tolos personaxes.","gui.prompt.cancel":"Encaboxar","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Parar","gui.playbackStep.playMsg":"Tocar","gui.playbackStep.loadingMsg":"Cargando...","gui.playbackStep.saveMsg":"Guardar","gui.playbackStep.reRecordMsg":"Re-grabar","gui.recordModal.title":"Grabar soníu","gui.recordingStep.beginRecord":"Entamar grabación calcando nel botón d\'abaxo","gui.recordingStep.permission":"{arrow}Necesitamos el to permisu pa usar el micrófonu","gui.recordingStep.stop":"Parar grabación","gui.recordingStep.record":"Grabar","gui.sliderModal.min":"Valor mínimu","gui.sliderModal.max":"Valor máximu","gui.sliderModal.title":"Cambiar el rangu del eslizador","gui.sliderPrompt.cancel":"Encaboxar","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Soníu","gui.soundEditor.play":"Tocar","gui.soundEditor.stop":"Parar","gui.soundEditor.copy":"Copiar","gui.soundEditor.paste":"Apegar","gui.soundEditor.copyToNew":"Copiar a Nuevu","gui.soundEditor.delete":"Esborrar","gui.soundEditor.save":"Guardar","gui.soundEditor.undo":"Desfacer","gui.soundEditor.redo":"Refacer","gui.soundEditor.faster":"Más rápido","gui.soundEditor.slower":"Más lento","gui.soundEditor.echo":"Ecu","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Más alto","gui.soundEditor.softer":"Más baxo","gui.soundEditor.reverse":"Inversu","gui.soundEditor.fadeOut":"Fade out","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Silenciar","gui.SpriteInfo.spritePlaceholder":"Nome","gui.SpriteInfo.sprite":"Personaxe","gui.SpriteInfo.show":"Amosar","gui.SpriteInfo.size":"Tamañu","gui.spriteSelectorItem.contextMenuDuplicate":"duplicar","gui.spriteSelectorItem.contextMenuExport":"esportar","gui.spriteSelectorItem.contextMenuDelete":"esborrar","gui.spriteSelector.addSpriteFromLibrary":"Escoyer un Personaxe","gui.spriteSelector.addSpriteFromPaint":"Pintar","gui.spriteSelector.addSpriteFromSurprise":"Sorpresa","gui.spriteSelector.addSpriteFromFile":"Subir Personaxe","gui.stageHeader.stageSizeLarge":"Cambiar a escenariu grande","gui.stageHeader.stageSizeSmall":"Cambiar a escenariu pequeñu","gui.stageHeader.stageSizeFull":"Pasar a mou de pantala completa","gui.stageHeader.stageSizeUnFull":"Salir del mou de pantalla completa","gui.stageHeader.fullscreenControl":"Control Pantalla Completa","gui.spriteSelector.addBackdropFromLibrary":"Escueyi un Fondu","gui.stageSelector.addBackdropFromPaint":"Pintar","gui.stageSelector.addBackdropFromSurprise":"Sorpresa","gui.stageSelector.addBackdropFromFile":"Subir un Fondu","gui.stageSelector.stage":"Escenariu","gui.stageSelector.backdrops":"Fondos","gui.telemetryOptIn.label":"Unviar estadístiques p\'ameyorar Scratch","gui.telemetryOptIn.body1":"El Equipu de Scratch intenta siempres entender meyor cómo s\'usa Scratch a lo llargo\'l mundu. P\'ayudar nesti esfuerzu puedes permitir a Scratch unviar automáticamente información sobre l\'usu al Equipu Scratch.","gui.telemetryOptIn.body2":"Recoyemos información qu\'inclúi llingua seleicionada, bloques usaos y dalgunos eventos como guardar, cargar y subir proyectos. NUN recoyemos nenguna información personal. Mira la nuesa {privacyPolicyLink} pa más información.","gui.telemetryOptIn.privacyPolicyLink":"Política de Privacidá","gui.telemetryOptIn.optInText":"Compartir los datos d\'usu col Equipu de Scratch","gui.telemetryOptIn.optInTooltip":"Activar telemetría","gui.telemetryOptIn.optOutText":"Nun compartir los mios datos d\'usu col Equipu Scratch","gui.telemetryOptIn.optOutTooltip":"Desactivar telemetría","gui.telemetryOptIn.settingWasUpdated":"Configuración anovada.","gui.telemetryOptIn.buttonClose":"Zarrar","gui.turboMode.active":"Mou Turbu","gui.webglModal.label":"El Restolador Nun Soporta WebGL","gui.webglModal.webgllink":"nun soporta WebGL","gui.costumeLibrary.chooseABackdrop":"Escueyi un Fondu","gui.costumeLibrary.chooseACostume":"Escueyi un Disfraz","gui.costumeTab.addBackdropFromLibrary":"Escueyi un Fondu","gui.costumeTab.addCostumeFromLibrary":"Escueyi un Disfraz","gui.costumeTab.addBlankCostume":"Pintar","gui.costumeTab.addSurpriseCostume":"Sorpresa","gui.costumeTab.addFileBackdrop":"Subir un Fondu","gui.costumeTab.addFileCostume":"Subir Disfraz","gui.extensionLibrary.chooseAnExtension":"Escueyi una Extensión","gui.extensionLibrary.extensionUrl":"Introduz la URL de la extensión","gui.monitors.importListColumnPrompt":"¿Cuáles columnes deberíen ser usaes (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Nun se pudo entamar a grabar","gui.soundLibrary.chooseASound":"Escoyer un Soníu","gui.soundTab.fileUploadSound":"Subir Soníu","gui.soundTab.surpriseSound":"Sorpresa","gui.soundTab.recordSound":"Grabar","gui.soundTab.addSoundFromLibrary":"Escoyer un Soníu","gui.spriteLibrary.chooseASprite":"Escoyer un Personaxe","gui.tipsLibrary.tutorials":"Escoyer un Tutorial","gui.alerts.createsuccess":"Creáu nuevu proyectu","gui.alerts.createcopysuccess":"Proyectu guardáu como una copia.","gui.alerts.createremixsuccess":"Proyectu guardáu como un remix.","gui.alerts.creating":"Creando nuevu...","gui.alerts.creatingCopy":"Copiand proyectu...","gui.alerts.creatingRemix":"Remeciendo proyectu...","gui.alerts.creatingError":"Nun se pudo crear el proyectu. ¡Intétalo otra vuelta!","gui.alerts.savingError":"El proyectu nun se puedo guardar.","gui.alerts.savesuccess":"Proyectu guardáu.","gui.alerts.saving":"Guardando proyectu...","gui.alerts.cloudInfo":"Atención, les variables na ñube namás soporten númberos, nin lletres nin símbolos. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Aprendi más.","gui.alerts.importing":"Importando...","gui.defaultProject.variable":"la mio variable","gui.extension.music.name":"Música","gui.extension.music.description":"Tocar instrumentos y tambores.","gui.extension.pen.name":"Llápiz","gui.extension.pen.description":"Dibuxar colos tos personaxes.","gui.extension.videosensing.name":"Deteición de videu","gui.extension.videosensing.description":"Sensor de movimientu cola cámara","gui.extension.text2speech.name":"Testu pa dicir","gui.extension.text2speech.description":"Fai que los tos proyeutos falen.","gui.extension.translate.name":"Traducir","gui.extension.translate.description":"Traducir el testu en delles llingües.","gui.extension.makeymakey.description":"Convierte cualquier cosa nuna llave.","gui.extension.microbit.description":"Coneuta los tos proyeutos col mundu","gui.extension.microbit.connectingMessage":"Coneutando","gui.extension.ev3.description":"Construyir robots interautivos y más coses","gui.extension.ev3.connectingMessage":"Coneutando. Asegúrate de que\'l pin del to EV3 ye 1234","gui.extension.boost.description":"Da vida a les creaciones robótiques","gui.extension.boost.connectingMessage":"Coneutando","gui.extension.wedo2.description":"Construyir con motores y sensores.","gui.extension.wedo2.connectingMessage":"Coneutando","gui.extension.gdxfor.description":"Sensor d\'emburrie, tiru, movimientu y xiru.","gui.extension.gdxfor.connectingMessage":"Coneutando","gui.libraryTags.all":"Too","gui.libraryTags.animals":"Animales","gui.libraryTags.dance":"Baillar","gui.libraryTags.effects":"Efeutos","gui.libraryTags.fantasy":"Fantasía","gui.libraryTags.fashion":"Moda","gui.libraryTags.food":"Comida","gui.libraryTags.indoors":"Interiores","gui.libraryTags.loops":"Llazos","gui.libraryTags.music":"Música","gui.libraryTags.notes":"Notes","gui.libraryTags.outdoors":"Esteriores","gui.libraryTags.patterns":"Patrones","gui.libraryTags.people":"Xente","gui.libraryTags.percussion":"Percusión","gui.libraryTags.space":"Espaciu","gui.libraryTags.sports":"Deportes","gui.libraryTags.underwater":"Somarín","gui.libraryTags.voice":"Voz","gui.libraryTags.wacky":"Fatu","gui.libraryTags.animation":"Animación","gui.libraryTags.art":"Arte","gui.libraryTags.games":"Xuegos","gui.libraryTags.stories":"Histories","gui.libraryTags.letters":"Lletres","gui.opcodeLabels.direction":"direición","gui.opcodeLabels.xposition":"posición x","gui.opcodeLabels.yposition":"posición y","gui.opcodeLabels.size":"tamañu","gui.opcodeLabels.costumename":"nome del disfraz","gui.opcodeLabels.costumenumber":"númberu de disfraz","gui.opcodeLabels.backdropname":"nombre de fondu","gui.opcodeLabels.backdropnumber":"númberu de fondu","gui.opcodeLabels.volume":"volume","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"respuesta","gui.opcodeLabels.loudness":"volume del soníu","gui.opcodeLabels.username":"nome d\'usuariu","gui.opcodeLabels.year":"añu","gui.opcodeLabels.month":"mes","gui.opcodeLabels.date":"data","gui.opcodeLabels.dayofweek":"día de la selman","gui.opcodeLabels.hour":"hora","gui.opcodeLabels.minute":"minutu","gui.opcodeLabels.second":"segundu","gui.opcodeLabels.timer":"cronómetru","gui.sharedMessages.backdrop":"fondu {index}","gui.sharedMessages.costume":"disfraz {index}","gui.sharedMessages.sprite":"Personax {index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"¿Reemplazar conteníos del proyeutu actual?","gui.sharedMessages.loadFromComputerTitle":"Cargar del to ordenador","boost.color.any":"cualquier color","boost.color.black":"negru","boost.color.blue":"azul","boost.color.green":"verde","boost.color.red":"coloráu","boost.color.white":"blancu","boost.color.yellow":"mariellu","boost.getMotorPosition":"posición [MOTOR_REPORTER_ID] motor","boost.getTiltAngle":"ángulu d\'enclín [TILT_DIRECTION]","boost.motorDirection.backward":"per ehí","boost.motorDirection.forward":"per equí","boost.motorDirection.reverse":"inversu","boost.motorOff":"apagar motor [MOTOR_ID]","boost.motorOn":"prender motor [MOTOR_ID]","boost.motorOnFor":"prender motor [MOTOR_ID] pa [DURATION] segundos","boost.motorOnForRotation":"prender motor [MOTOR_ID] pa [ROTATION] rotaciones","boost.seeingColor":"¿viendo [COLOR] lladriyu?","boost.setLightHue":"afitar color de lluz pa [HUE]","boost.setMotorDirection":"afitar direición del [MOTOR_ID] motor [MOTOR_DIRECTION]","boost.setMotorPower":"afitar velocidá del [MOTOR_ID] motor pa [POWER] %","boost.tiltDirection.any":"cualisquier","boost.tiltDirection.down":"abaxo","boost.tiltDirection.left":"izquierda","boost.tiltDirection.right":"drecha","boost.tiltDirection.up":"arriba","boost.whenColor":"cuando [COLOR] lladriyu asemeya","boost.whenTilted":"cuando l\'enclín [TILT_DIRECTION_ANY]","ev3.beepNote":"pitíu [NOTE] pa [TIME] segundos","ev3.buttonPressed":"¿botón [PORT] calcáu?","ev3.getBrightness":"brillu","ev3.getDistance":"distancia","ev3.getMotorPosition":"posición del [PORT] motor","ev3.motorSetPower":"motor [PORT] afitar potencia [POWER] %","ev3.motorTurnClockwise":"motor [PORT] torcer nesti sentíu pa [TIME] segundos","ev3.motorTurnCounterClockwise":"motor [PORT] torcer nesi sentíu pa [TIME] segundos","ev3.whenBrightnessLessThan":"cuando\'l brillu < [DISTANCE]","ev3.whenButtonPressed":"col botón [PORT] calcáu","ev3.whenDistanceLessThan":"cuando la distancia < [DISTANCE]","gdxfor.getAcceleration":"aceleración [DIRECTION]","gdxfor.getForce":"fuerza","gdxfor.getSpin":"velocidá de xiru [DIRECTION]","gdxfor.getTilt":"ángulu d\'enclín [TILT]","gdxfor.isFreeFalling":"¿cayendo?","gdxfor.isTilted":"¿enclináu [TILT]?","gdxfor.pulled":"tirao","gdxfor.pushed":"emburriao","gdxfor.shaken":"batulláu","gdxfor.startedFalling":"entamó a cayer","gdxfor.tiltDirectionMenu.any":"cualisquier","gdxfor.tiltDirectionMenu.back":"atrás","gdxfor.tiltDirectionMenu.front":"frente","gdxfor.tiltDirectionMenu.left":"izquierda","gdxfor.tiltDirectionMenu.right":"drecha","gdxfor.turnedFaceDown":"pámpana abaxo","gdxfor.turnedFaceUp":"pámpana arriba","gdxfor.whenForcePushedOrPulled":"cuando\'l sensor de fuerza [PUSH_PULL]","gdxfor.whenGesture":"cuando [GESTURE]","gdxfor.whenTilted":"cuando l\'enclín [TILT]","makeymakey.downArrow":"flecha abaxo","makeymakey.downArrowShort":"abaxo","makeymakey.leftArrow":"flecha izquierda","makeymakey.leftArrowShort":"izquierda","makeymakey.rightArrow":"flecha drecha","makeymakey.rightArrowShort":"drecha","makeymakey.spaceKey":"espaciu","makeymakey.upArrow":"flecha arriba","makeymakey.upArrowShort":"arriba","makeymakey.whenKeyPressed":"cuando [KEY] la tecla tea calcada","makeymakey.whenKeysPressedInOrder":"cuando [SEQUENCE] tea calcáu n\'orde","microbit.buttonsMenu.any":"cualisquier","microbit.clearDisplay":"llimpiar pantalla","microbit.defaultTextToDisplay":"¡Hola!","microbit.displaySymbol":"pantalla [MATRIX]","microbit.displayText":"amosar testu [TEXT]","microbit.gesturesMenu.jumped":"saltó","microbit.gesturesMenu.moved":"movió","microbit.gesturesMenu.shaken":"batulláu","microbit.isButtonPressed":"¿ [BTN] botón calcáu","microbit.isTilted":"¿enclín [DIRECTION]?","microbit.pinStateMenu.off":"apagáu","microbit.pinStateMenu.on":"encesu","microbit.tiltAngle":"ángulu d\'enclín [DIRECTION]","microbit.tiltDirectionMenu.any":"cualisquier","microbit.tiltDirectionMenu.back":"atrás","microbit.tiltDirectionMenu.front":"frente","microbit.tiltDirectionMenu.left":"izquierda","microbit.tiltDirectionMenu.right":"drecha","microbit.whenButtonPressed":"col [BTN] botón calcáu","microbit.whenGesture":"cuando [GESTURE]","microbit.whenPinConnected":"col pin [PIN] conectáu","microbit.whenTilted":"cuando l\'enclín [DIRECTION]","music.categoryName":"Música","music.changeTempo":"camudar el tempo por [TEMPO]","music.drumBass":"(2) Bombu","music.drumBongo":"(13) Bongu","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) Charles zarráu","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Lloqueru","music.drumCrashCymbal":"(4) Platiyos","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Aplausu","music.drumOpenHiHat":"(5) Charles abiertu","music.drumSideStick":"(3) Side Stick","music.drumSnare":"(1) Tambor","music.drumTambourine":"(7) Pandereta","music.drumTriangle":"(12) Triángulu","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Clave","music.getTempo":"tempo","music.instrumentBass":"(6) Baxu","music.instrumentBassoon":"(14) Fagot","music.instrumentCello":"(8) Chelu","music.instrumentChoir":"(15) Coru","music.instrumentClarinet":"(10) Clarinete","music.instrumentElectricGuitar":"(5) Guitarra llétrica","music.instrumentElectricPiano":"(2) Pianu llétricu","music.instrumentFlute":"(12) Flauta","music.instrumentGuitar":"(4) Guitarra","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Caxa de música","music.instrumentOrgan":"(3) Órganu","music.instrumentPiano":"(1) Pianu","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxofón","music.instrumentSteelDrum":"(18) Caxa","music.instrumentSynthLead":"(20) Sintetizador lead","music.instrumentSynthPad":"(21) Sintetizador Pad","music.instrumentTrombone":"(9) Trombón","music.instrumentVibraphone":"(16) Vibrafonu","music.instrumentWoodenFlute":"(13) Faluta de madera","music.midiPlayDrumForBeats":"tocar el tambor [DRUM] pa [BEATS] pulsos","music.midiSetInstrument":"afitar instrumentu pa [INSTRUMENT]","music.playDrumForBeats":"tocar el tambor [DRUM] pa [BEATS] pulsos","music.playNoteForBeats":"tocar una nota [NOTE] pa [BEATS] pulsos","music.restForBeats":"silenciu pa [BEATS] pulsos","music.setInstrument":"afitar instrumentu pa [INSTRUMENT]","music.setTempo":"afitar el tempu en [TEMPO]","pen.categoryName":"Llápiz","pen.changeColorParam":"camudar el llápiz [COLOR_PARAM] por [VALUE]","pen.changeHue":"camudar el llápiz por [HUE]","pen.changeShade":"camudar la intensidá del llápiz por [SHADE]","pen.changeSize":"camudar el tamañu del llápiz por [SIZE]","pen.clear":"esborriar too","pen.colorMenu.brightness":"brillu","pen.colorMenu.color":"color","pen.colorMenu.saturation":"saturación","pen.colorMenu.transparency":"tresparencia","pen.penDown":"baxar llápiz","pen.penUp":"xubir llápiz","pen.setColor":"afitar el color del llápiz en [COLOR]","pen.setColorParam":"afitar el llápiz [COLOR_PARAM] como [VALUE]","pen.setHue":"afitar el llápiz como [HUE]","pen.setShade":"afitar el llápiz como [SHADE]","pen.setSize":"apitar el tamañu del llápiz como [SIZE]","pen.stamp":"sellu","text2speech.alto":"altu","text2speech.categoryName":"Testu pa dicir","text2speech.defaultTextToSpeak":"hola","text2speech.giant":"xigante","text2speech.kitten":"gatín","text2speech.setLanguageBlock":"afitar llingua como [LANGUAGE]","text2speech.setVoiceBlock":"afitar voz como [VOICE]","text2speech.speakAndWaitBlock":"falar [WORDS]","text2speech.squeak":"chirríu","text2speech.tenor":"tenor","translate.categoryName":"Traducir","translate.defaultTextToTranslate":"hola","translate.translateBlock":"traducir [WORDS] al [LANGUAGE]","translate.viewerLanguage":"llingua","videoSensing.categoryName":"Deteición de videu","videoSensing.direction":"direición","videoSensing.motion":"movimientu","videoSensing.off":"encesu","videoSensing.on":"encesu","videoSensing.onFlipped":"nel xiru","videoSensing.setVideoTransparency":"afitar tresparencia del videu como [TRANSPARENCY]","videoSensing.sprite":"personaxe","videoSensing.stage":"escenariu","videoSensing.videoOn":"videu [ATTRIBUTE] en [SUBJECT]","videoSensing.videoToggle":"videu [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"cuando\'l movimientu del videu > [REFERENCE]","wedo2.getDistance":"distancia","wedo2.getTiltAngle":"ángulu d\'enclín [TILT_DIRECTION]","wedo2.isTilted":"¿ enclín [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"per ehí","wedo2.motorDirection.forward":"per equí","wedo2.motorDirection.reverse":"inversu","wedo2.motorId.a":"motor A","wedo2.motorId.all":"tolos motores","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"apagar [MOTOR_ID]","wedo2.motorOn":"prender [MOTOR_ID]","wedo2.motorOnFor":"prender [MOTOR_ID] pa [DURATION] segundos","wedo2.playNoteFor":"tocar una nota [NOTE] por [DURATION] segundos","wedo2.setLightHue":"afitar color de lluz pa [HUE]","wedo2.setMotorDirection":"afitar [MOTOR_ID] direición como [MOTOR_DIRECTION]","wedo2.startMotorPower":"afitar [MOTOR_ID] potencia como [POWER]","wedo2.tiltDirection.any":"cualisquier","wedo2.tiltDirection.down":"abaxo","wedo2.tiltDirection.left":"izquierda","wedo2.tiltDirection.right":"drecha","wedo2.tiltDirection.up":"arriba","wedo2.whenDistance":"cuando la distancia [OP] [REFERENCE]","wedo2.whenTilted":"cuando l\'enclín [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Color","paint.paintEditor.saturation":"Saturación","paint.paintEditor.brightness":"Brillu","paint.paintEditor.costume":"Disfraz","paint.paintEditor.group":"Grupu","paint.paintEditor.ungroup":"Desagrupar","paint.paintEditor.undo":"Desfacer","paint.paintEditor.redo":"Refacer","paint.paintEditor.forward":"P\'alantre","paint.paintEditor.backward":"P\'atrás","paint.paintEditor.front":"Frente","paint.paintEditor.back":"Atrás","paint.paintEditor.more":"Más","paint.modeTools.brushSize":"Tamañu","paint.modeTools.eraserSize":"Tamañu del borrador","paint.modeTools.copy":"Copiar","paint.modeTools.paste":"Apegar","paint.modeTools.delete":"Esborrar","paint.modeTools.curved":"En curva","paint.modeTools.pointed":"Afiláu","paint.modeTools.thickness":"Espesor","paint.modeTools.flipHorizontal":"Xirar horizontalmente","paint.modeTools.flipVertical":"Xirar verticalmente","paint.modeTools.filled":"Rellenu","paint.modeTools.outlined":"Contorniáu","paint.paintEditor.bitmap":"Convertir a Bitmap","paint.paintEditor.vector":"Convertir a vector","paint.paintEditor.fill":"Rellenar","paint.paintEditor.stroke":"Contornu","paint.brushMode.brush":"Pincel","paint.eraserMode.eraser":"Borrador","paint.fillMode.fill":"Rellenar","paint.lineMode.line":"Llinia","paint.ovalMode.oval":"Círculu","paint.rectMode.rect":"Rectángulu","paint.reshapeMode.reshape":"Remodelar","paint.roundedRectMode.roundedRect":"Rectángulu arrondiáu","paint.selectMode.select":"Escoyer","paint.textMode.text":"Testu","paint.colorPicker.swap":"Intercambiar"},"az":{"gui.alerts.tryAgain":"Try Again","gui.alerts.download":"Download","gui.connection.reconnect":"Reconnect","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Bel çantası","gui.backpack.errorBackpack":"Bel çantasının yüklənməsində yanlışlıq","gui.backpack.loadingBackpack":"Yüklənir ...","gui.backpack.more":"More","gui.backpack.emptyBackpack":"Bel çantası boşdur","gui.unsupportedBrowser.label":"Brauzer dəstəklənmir","gui.cards.all-tutorials":"Təlimatlar","gui.cards.shrink":"Shrink","gui.cards.expand":"Expand","gui.cards.close":"Close","gui.cards.more-things-to-try":"Yoxlamağa daha çox imkan!","gui.cards.see-more":"Daha çox","gui.comingSoon.message1":"Narahat olmayın, biz bunun üzərində çalışırıq {emoji}","gui.comingSoon.message2":"Tezliklə ...","gui.comingSoon.message3":"Biz bunun üzərində çalışırıq {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"No devices found","gui.connection.auto-scanning.prescan":"Axtarışı başlatmaq üçün cihazınızı yaxınlıqda yerləşdirin.","gui.connection.auto-scanning.pressbutton":"Cihazınızdakı düyməyə basın.","gui.connection.auto-scanning.start-search":"Axtarışa başlayın","gui.connection.connecting-searchbutton":"Axtarılır...","gui.connection.auto-scanning.try-again":"Yenidən cəhd edin","gui.connection.connected":"Qoşuludur","gui.connection.disconnect":"Qoşulma","gui.connection.go-to-editor":"Redaktora keçin","gui.connection.connecting-cancelbutton":"Qoşulur ...","gui.connection.error.errorMessage":"Ups! Görünür ki, nə isə səhv getdi.","gui.connection.error.tryagainbutton":"Yenidən cəhd et","gui.connection.error.helpbutton":"Yardım","gui.connection.peripheral-name-label":"Device name","gui.connection.connect":"Qoşul","gui.connection.scanning.lookingforperipherals":"Looking for devices","gui.connection.scanning.noPeripheralsFound":"No devices found","gui.connection.scanning.instructions":"Yuxarıdakı siyahıdan öz cihazınızı seçin.","gui.connection.search":"Yenilə","gui.connection.unavailable.installscratchlink":"Skreç linkinin yüklənməyində və işləməyindən əmin olun","gui.connection.unavailable.enablebluetooth":"Bluetoothun aktiv olduğunu yoxlayın","gui.connection.unavailable.tryagainbutton":"Yenidən cəhd et","gui.connection.unavailable.helpbutton":"Yardım","gui.controls.go":"Başlat","gui.controls.stop":"Dayandır","gui.crashMessage.label":"Oops! Something went wrong.","gui.crashMessage.errorNumber":"Your error was logged with id {errorId}","gui.crashMessage.reload":"Reload","gui.customProcedures.myblockModalTitle":"Blok yarat","gui.customProcedures.addAnInputNumberText":"Dəyişən əlavə et","gui.customProcedures.numberTextType":"rəqəm və ya mətn","gui.customProcedures.addAnInputBoolean":"Dəyişən əlavə et","gui.customProcedures.booleanType":"məntiqi","gui.customProcedures.addALabel":"Yarlıq əlavə et","gui.customProcedures.runWithoutScreenRefresh":"Ekranı yeniləmədən işə sal","gui.customProcedures.cancel":"Ləğv et","gui.customProcedures.ok":"Oldu","gui.SpriteInfo.direction":"İstiqamət","gui.directionPicker.rotationStyles.allAround":"Ətrafında","gui.directionPicker.rotationStyles.leftRight":"Sol/Sağ","gui.directionPicker.rotationStyles.dontRotate":"Döndərmə","gui.gui.addExtension":"Genişlənmə əlavə et","gui.gui.codeTab":"Kod","gui.gui.backdropsTab":"Fonlar","gui.gui.costumesTab":"Libaslar","gui.gui.soundsTab":"Səslər","gui.extensionLibrary.comingSoon":"Tezliklə ...","gui.extensionLibrary.requires":"Requires","gui.extensionLibrary.collaboration":"Collaboration with","gui.library.filterPlaceholder":"Axtarış","gui.library.allTag":"All","gui.loader.headline":"Layihə yüklənir","gui.loader.creating":"Creating Project","gui.authorInfo.byUser":"by {username}","gui.menuBar.seeProjectPage":"See Project Page","gui.menuBar.LanguageSelector":"dil seçimi","gui.menuBar.tutorialsLibrary":"Təlimatlar","gui.menuBar.restoreSprite":"Spraytı bərpa edin","gui.menuBar.restoreSound":"Restore Sound","gui.menuBar.restoreCostume":"Restore Costume","gui.menuBar.restore":"Restore","gui.menuBar.saveNow":"İndi saxla","gui.menuBar.saveAsCopy":"Save as a copy","gui.menuBar.remix":"Remix","gui.menuBar.new":"Yeni","gui.menuBar.file":"Fayl","gui.menuBar.downloadToComputer":"Kompüterə yüklə","gui.menuBar.edit":"Düzəliş et","gui.menuBar.turboModeOff":"Turn off Turbo Mode","gui.menuBar.turboModeOn":"Turn on Turbo Mode","gui.gui.projectTitlePlaceholder":"Project title here","gui.menuBar.isShared":"Shared","gui.menuBar.share":"Paylaş","gui.modal.help":"Yardım","gui.modal.back":"Geri","gui.monitor.listMonitor.empty":"(empty)","gui.monitor.listMonitor.listLength":"length {length}","gui.monitor.contextMenu.default":"normal readout","gui.monitor.contextMenu.large":"large readout","gui.monitor.contextMenu.slider":"sürüşkən","gui.monitor.contextMenu.sliderRange":"change slider range","gui.monitor.contextMenu.import":"import","gui.monitor.contextMenu.export":"export","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Play","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"Bütün spraytlar üçün","gui.gui.variableScopeOptionSpriteOnly":"Yalnız bu sprayt üçün","gui.gui.cloudVariableOption":"Cloud variable (stored on server)","gui.gui.variablePromptAllSpritesMessage":"Bu dəyişən bütün spraytlar üçün mövcud olacaq.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Ləğv et","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Dayandır","gui.playbackStep.playMsg":"Oynat","gui.playbackStep.loadingMsg":"Yüklənir ...","gui.playbackStep.saveMsg":"Saxla","gui.playbackStep.reRecordMsg":"Səsi yenidən yaz","gui.recordModal.title":"Səs yaz","gui.recordingStep.beginRecord":"Begin recording by clicking the button below","gui.recordingStep.permission":"{arrow}We need your permission to use your microphone","gui.recordingStep.stop":"Stop recording","gui.recordingStep.record":"Record","gui.sliderModal.min":"Minimum value","gui.sliderModal.max":"Maximum value","gui.sliderModal.title":"Change slider range","gui.sliderPrompt.cancel":"Cancel","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Səs","gui.soundEditor.play":"Çal","gui.soundEditor.stop":"dayandır","gui.soundEditor.copy":"Copy","gui.soundEditor.paste":"Paste","gui.soundEditor.copyToNew":"Copy to New","gui.soundEditor.delete":"Delete","gui.soundEditor.save":"Saxla","gui.soundEditor.undo":"Ləğv et","gui.soundEditor.redo":"Redo","gui.soundEditor.faster":"Cəld","gui.soundEditor.slower":"Yavaş","gui.soundEditor.echo":"Əks-səda","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Uca","gui.soundEditor.softer":"Softer","gui.soundEditor.reverse":"Tərsinə çevirmək","gui.soundEditor.fadeOut":"Fade out","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Mute","gui.SpriteInfo.spritePlaceholder":"Ad","gui.SpriteInfo.sprite":"Sprayt","gui.SpriteInfo.show":"Göstər","gui.SpriteInfo.size":"Ölçü","gui.spriteSelectorItem.contextMenuDuplicate":"Dublikat yarat","gui.spriteSelectorItem.contextMenuExport":"ixrac et","gui.spriteSelectorItem.contextMenuDelete":"sil","gui.spriteSelector.addSpriteFromLibrary":"Sprayt seç","gui.spriteSelector.addSpriteFromPaint":"Çək","gui.spriteSelector.addSpriteFromSurprise":"Sürpriz","gui.spriteSelector.addSpriteFromFile":"Upload Sprite","gui.stageHeader.stageSizeLarge":"Böyük səhnəyə keçid","gui.stageHeader.stageSizeSmall":"Kiçik səhnəyə keç","gui.stageHeader.stageSizeFull":"Tam ekran rejiminə daxil ol","gui.stageHeader.stageSizeUnFull":"Tam ekran rejimindən çıx","gui.stageHeader.fullscreenControl":"Tam ekran idarəedicisi","gui.spriteSelector.addBackdropFromLibrary":"Fon seç","gui.stageSelector.addBackdropFromPaint":"Paint","gui.stageSelector.addBackdropFromSurprise":"Sürpriz","gui.stageSelector.addBackdropFromFile":"Fon yüklə","gui.stageSelector.stage":"Səhnə","gui.stageSelector.backdrops":"Fonlar","gui.telemetryOptIn.label":"Report statistics to improve Scratch","gui.telemetryOptIn.body1":"The Scratch Team is always looking to better understand how Scratch is used around the world. To help support this effort, you can allow Scratch to automatically send usage information to the Scratch Team.","gui.telemetryOptIn.body2":"The information we collect includes language selection, blocks usage, and some events like saving, loading, and uploading a project. We DO NOT collect any personal information. Please see our {privacyPolicyLink} for more information.","gui.telemetryOptIn.privacyPolicyLink":"Privacy Policy","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Turbo rejim","gui.webglModal.label":"Sənin Brauzerin WebGL-i dəstəkləmir","gui.webglModal.webgllink":"WebGL-i dəstəkləmir","gui.costumeLibrary.chooseABackdrop":"Fon seç","gui.costumeLibrary.chooseACostume":"Libas seç","gui.costumeTab.addBackdropFromLibrary":"Fon seç","gui.costumeTab.addCostumeFromLibrary":"Libas seç","gui.costumeTab.addBlankCostume":"Paint","gui.costumeTab.addSurpriseCostume":"Sürpriz","gui.costumeTab.addFileBackdrop":"Fon yüklə","gui.costumeTab.addFileCostume":"Libas yüklə","gui.extensionLibrary.chooseAnExtension":"Genişlənmə seç","gui.extensionLibrary.extensionUrl":"Genişlənmənin URL-ini daxil edin","gui.monitors.importListColumnPrompt":"Which column should be used (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Yazmağa başlaya bilmədi","gui.soundLibrary.chooseASound":"Səs seç","gui.soundTab.fileUploadSound":"Səs yüklə","gui.soundTab.surpriseSound":"Sürpriz","gui.soundTab.recordSound":"Record","gui.soundTab.addSoundFromLibrary":"Səs seç","gui.spriteLibrary.chooseASprite":"Sprayt seç","gui.tipsLibrary.tutorials":"Təlimat seçin","gui.alerts.createsuccess":"New project created.","gui.alerts.createcopysuccess":"Project saved as a copy.","gui.alerts.createremixsuccess":"Project saved as a remix.","gui.alerts.creating":"Creating new…","gui.alerts.creatingCopy":"Copying project…","gui.alerts.creatingRemix":"Remixing project…","gui.alerts.creatingError":"Could not create the project. Please try again!","gui.alerts.savingError":"Project could not save.","gui.alerts.savesuccess":"Project saved.","gui.alerts.saving":"Saving project…","gui.alerts.cloudInfo":"Please note, cloud variables only support numbers, not letters or symbols. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Learn more.","gui.alerts.importing":"Importing…","gui.defaultProject.variable":"my variable","gui.extension.music.name":"Musiqi","gui.extension.music.description":"Alətlər və barabanlar çal.","gui.extension.pen.name":"Qələm","gui.extension.pen.description":"Spraytlarınla çək.","gui.extension.videosensing.name":"Video Sensoru","gui.extension.videosensing.description":"Kamera ilə hissi hərəkət","gui.extension.text2speech.name":"Text to Speech","gui.extension.text2speech.description":"Make your projects talk.","gui.extension.translate.name":"Translate","gui.extension.translate.description":"Translate text into many languages.","gui.extension.makeymakey.description":"Make anything into a key.","gui.extension.microbit.description":"Layihələrinizi dünyayla paylaşın.","gui.extension.microbit.connectingMessage":"Qoşulur","gui.extension.ev3.description":"İnteraktiv robotlar və daha çoxunu qurun.","gui.extension.ev3.connectingMessage":"Qoşulur. EV3-dəki pin kodun 1234 təyin olunduğundan əmin olun.","gui.extension.boost.description":"Bring robotic creations to life.","gui.extension.boost.connectingMessage":"Connecting","gui.extension.wedo2.description":"Mühərriklər və sensorlar ilə qurun.","gui.extension.wedo2.connectingMessage":"Connecting","gui.extension.gdxfor.description":"Sense push, pull, motion, and spin.","gui.extension.gdxfor.connectingMessage":"Connecting","gui.libraryTags.all":"All","gui.libraryTags.animals":"Animals","gui.libraryTags.dance":"Dance","gui.libraryTags.effects":"Effects","gui.libraryTags.fantasy":"Fantasy","gui.libraryTags.fashion":"Fashion","gui.libraryTags.food":"Food","gui.libraryTags.indoors":"Indoors","gui.libraryTags.loops":"Loops","gui.libraryTags.music":"Music","gui.libraryTags.notes":"Notes","gui.libraryTags.outdoors":"Outdoors","gui.libraryTags.patterns":"Patterns","gui.libraryTags.people":"People","gui.libraryTags.percussion":"Percussion","gui.libraryTags.space":"Space","gui.libraryTags.sports":"Sports","gui.libraryTags.underwater":"Underwater","gui.libraryTags.voice":"Voice","gui.libraryTags.wacky":"Wacky","gui.libraryTags.animation":"Animation","gui.libraryTags.art":"Art","gui.libraryTags.games":"Games","gui.libraryTags.stories":"Stories","gui.libraryTags.letters":"Letters","gui.opcodeLabels.direction":"direction","gui.opcodeLabels.xposition":"x position","gui.opcodeLabels.yposition":"y position","gui.opcodeLabels.size":"size","gui.opcodeLabels.costumename":"costume name","gui.opcodeLabels.costumenumber":"costume number","gui.opcodeLabels.backdropname":"backdrop name","gui.opcodeLabels.backdropnumber":"backdrop number","gui.opcodeLabels.volume":"volume","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"answer","gui.opcodeLabels.loudness":"loudness","gui.opcodeLabels.username":"username","gui.opcodeLabels.year":"year","gui.opcodeLabels.month":"month","gui.opcodeLabels.date":"date","gui.opcodeLabels.dayofweek":"day of week","gui.opcodeLabels.hour":"hour","gui.opcodeLabels.minute":"minute","gui.opcodeLabels.second":"second","gui.opcodeLabels.timer":"timer","gui.sharedMessages.backdrop":"backdrop{index}","gui.sharedMessages.costume":"costume{index}","gui.sharedMessages.sprite":"Sprite{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Replace contents of the current project?","gui.sharedMessages.loadFromComputerTitle":"Load from your computer","boost.color.any":"any color","boost.color.black":"black","boost.color.blue":"blue","boost.color.green":"green","boost.color.red":"red","boost.color.white":"white","boost.color.yellow":"yellow","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] position","boost.getTiltAngle":"tilt angle [TILT_DIRECTION]","boost.motorDirection.backward":"that way","boost.motorDirection.forward":"this way","boost.motorDirection.reverse":"reverse","boost.motorOff":"turn motor [MOTOR_ID] off","boost.motorOn":"turn motor [MOTOR_ID] on","boost.motorOnFor":"turn motor [MOTOR_ID] for [DURATION] seconds","boost.motorOnForRotation":"turn motor [MOTOR_ID] for [ROTATION] rotations","boost.seeingColor":"seeing [COLOR] brick?","boost.setLightHue":"set light color to [HUE]","boost.setMotorDirection":"set motor [MOTOR_ID] direction [MOTOR_DIRECTION]","boost.setMotorPower":"set motor [MOTOR_ID] speed to [POWER] %","boost.tiltDirection.any":"any","boost.tiltDirection.down":"down","boost.tiltDirection.left":"left","boost.tiltDirection.right":"right","boost.tiltDirection.up":"up","boost.whenColor":"when [COLOR] brick seen","boost.whenTilted":"when tilted [TILT_DIRECTION_ANY]","ev3.beepNote":"[NOTE] notunu [TIME] saniyə səsləndir","ev3.buttonPressed":"[PORT] düyməsi basılıb?","ev3.getBrightness":"parlaqlıq","ev3.getDistance":"məsafə","ev3.getMotorPosition":"[PORT] mühərrikinin mövqeyi","ev3.motorSetPower":"motor [PORT] set power [POWER] %","ev3.motorTurnClockwise":"motor [PORT] turn this way for [TIME] seconds","ev3.motorTurnCounterClockwise":"motor [PORT] turn that way for [TIME] seconds","ev3.whenBrightnessLessThan":"when brightness < [DISTANCE]","ev3.whenButtonPressed":"when button [PORT] pressed","ev3.whenDistanceLessThan":"when distance < [DISTANCE]","gdxfor.getAcceleration":"acceleration [DIRECTION]","gdxfor.getForce":"force","gdxfor.getSpin":"spin speed [DIRECTION]","gdxfor.getTilt":"tilt angle [TILT]","gdxfor.isFreeFalling":"falling?","gdxfor.isTilted":"tilted [TILT]?","gdxfor.pulled":"pulled","gdxfor.pushed":"pushed","gdxfor.shaken":"shaken","gdxfor.startedFalling":"started falling","gdxfor.tiltDirectionMenu.any":"any","gdxfor.tiltDirectionMenu.back":"back","gdxfor.tiltDirectionMenu.front":"front","gdxfor.tiltDirectionMenu.left":"left","gdxfor.tiltDirectionMenu.right":"right","gdxfor.turnedFaceDown":"turned face down","gdxfor.turnedFaceUp":"turned face up","gdxfor.whenForcePushedOrPulled":"when force sensor [PUSH_PULL]","gdxfor.whenGesture":"when [GESTURE]","gdxfor.whenTilted":"when tilted [TILT]","makeymakey.downArrow":"down arrow","makeymakey.downArrowShort":"down","makeymakey.leftArrow":"left arrow","makeymakey.leftArrowShort":"left","makeymakey.rightArrow":"right arrow","makeymakey.rightArrowShort":"right","makeymakey.spaceKey":"space","makeymakey.upArrow":"up arrow","makeymakey.upArrowShort":"up","makeymakey.whenKeyPressed":"when [KEY] key pressed","makeymakey.whenKeysPressedInOrder":"when [SEQUENCE] pressed in order","microbit.buttonsMenu.any":"any","microbit.clearDisplay":"clear display","microbit.defaultTextToDisplay":"Hello!","microbit.displaySymbol":"display [MATRIX]","microbit.displayText":"display text [TEXT]","microbit.gesturesMenu.jumped":"jumped","microbit.gesturesMenu.moved":"moved","microbit.gesturesMenu.shaken":"shaken","microbit.isButtonPressed":"[BTN] button pressed?","microbit.isTilted":"tilted [DIRECTION]?","microbit.pinStateMenu.off":"off","microbit.pinStateMenu.on":"on","microbit.tiltAngle":"tilt angle [DIRECTION]","microbit.tiltDirectionMenu.any":"any","microbit.tiltDirectionMenu.back":"back","microbit.tiltDirectionMenu.front":"front","microbit.tiltDirectionMenu.left":"left","microbit.tiltDirectionMenu.right":"right","microbit.whenButtonPressed":"when [BTN] button pressed","microbit.whenGesture":"when [GESTURE]","microbit.whenPinConnected":"when pin [PIN] connected","microbit.whenTilted":"when tilted [DIRECTION]","music.categoryName":"Musiqi","music.changeTempo":"tempi [TEMPO] qədər dəyiş","music.drumBass":"(2) Bas barabanı","music.drumBongo":"(13) Bonqo","music.drumCabasa":"(15) Kabasa","music.drumClaves":"(9) Klavesin","music.drumClosedHiHat":"(6) Bağlı Hi-Hat","music.drumConga":"(14) Konqa","music.drumCowbell":"(11) Zınqırov","music.drumCrashCymbal":"(4) Zərb aləti","music.drumCuica":"(18) Kuika","music.drumGuiro":"(16) Quiro","music.drumHandClap":"(8) Əl çalmaq","music.drumOpenHiHat":"(5) Açıq Hi-Hat","music.drumSideStick":"(3) Çubuqlu nağara","music.drumSnare":"(1) Kiçik baraban","music.drumTambourine":"(7) Tamburin","music.drumTriangle":"(12) Üçbucaq","music.drumVibraslap":"(17) Vibrasiya edən sləp","music.drumWoodBlock":"(10) Taxta qutu","music.getTempo":"temp","music.instrumentBass":"(6) Bas","music.instrumentBassoon":"(14) Faqot","music.instrumentCello":"(8) Violonçel","music.instrumentChoir":"(15) Xor","music.instrumentClarinet":"(10) Klarnet","music.instrumentElectricGuitar":"(5) Elektro gitara","music.instrumentElectricPiano":"(2) Elektro pianino","music.instrumentFlute":"(12) Fleyta","music.instrumentGuitar":"(4) Gitara","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Musiqi qutusu","music.instrumentOrgan":"(3) Orqan","music.instrumentPiano":"(1) Pianino","music.instrumentPizzicato":"(7) Pizzikato","music.instrumentSaxophone":"(11) Saksafon","music.instrumentSteelDrum":"(18) Polad baraban","music.instrumentSynthLead":"(20) Aparıcı Sintezator","music.instrumentSynthPad":"(21) Sintezator Pad","music.instrumentTrombone":"(9) Trambon","music.instrumentVibraphone":"(16) Vibrafon","music.instrumentWoodenFlute":"(13) Taxta fleyta","music.midiPlayDrumForBeats":"play drum [DRUM] for [BEATS] beats","music.midiSetInstrument":"set instrument to [INSTRUMENT]","music.playDrumForBeats":"[DRUM] barabanını [BEATS] takt çal","music.playNoteForBeats":"[NOTE] notunu [BEATS] takt çal","music.restForBeats":"[BEATS] takt çalma","music.setInstrument":"aləti [INSTRUMENT] təyin et","music.setTempo":"tempi [TEMPO] təyin et","pen.categoryName":"Qələm","pen.changeColorParam":"qələmin [COLOR_PARAM] rəngini [VALUE] qədər dəyiş","pen.changeHue":"qələmin rəngini [HUE] qədər dəyiş","pen.changeShade":"qələmin çalarını [SHADE] qədər dəyiş","pen.changeSize":"qələmin ölçüsünü [SIZE] qədər dəyiş","pen.clear":"hamısını sil","pen.colorMenu.brightness":"parlaqlıq","pen.colorMenu.color":"rəng","pen.colorMenu.saturation":"dolğunluq","pen.colorMenu.transparency":"şəffaflıq","pen.penDown":"qələmi endir","pen.penUp":"qələmi qaldır","pen.setColor":"qələmin rəngini [COLOR] təyin et","pen.setColorParam":"qələmin [COLOR_PARAM] rəngini [VALUE] təyin et","pen.setHue":"qələmin rəngini [HUE] təyin et","pen.setShade":"qələmin çalarını [SHADE] təyin et","pen.setSize":"qələmin ölçüsünü [SIZE] təyin et","pen.stamp":"möhürlə","text2speech.alto":"alto","text2speech.categoryName":"Text to Speech","text2speech.defaultTextToSpeak":"hello","text2speech.giant":"giant","text2speech.kitten":"kitten","text2speech.setLanguageBlock":"set language to [LANGUAGE]","text2speech.setVoiceBlock":"set voice to [VOICE]","text2speech.speakAndWaitBlock":"speak [WORDS]","text2speech.squeak":"squeak","text2speech.tenor":"tenor","translate.categoryName":"Translate","translate.defaultTextToTranslate":"salam","translate.translateBlock":"[WORDS] ifadəsini [LANGUAGE] dilinə tərcümə et","translate.viewerLanguage":"dil","videoSensing.categoryName":"Video Sensoru","videoSensing.direction":"istiqamət","videoSensing.motion":"hərəkət","videoSensing.off":"söndür","videoSensing.on":"on","videoSensing.onFlipped":"çevrilmiş","videoSensing.setVideoTransparency":"videonun şəffaflığını [TRANSPARENCY] təyin et","videoSensing.sprite":"sprayt","videoSensing.stage":"səhnə","videoSensing.videoOn":"videonun [ATTRIBUTE] atributları [SUBJECT] aid","videoSensing.videoToggle":"videonu [VIDEO_STATE] çevir","videoSensing.whenMotionGreaterThan":"videonun hərəkəti > [REFERENCE] olduqda","wedo2.getDistance":"distance","wedo2.getTiltAngle":"tilt angle [TILT_DIRECTION]","wedo2.isTilted":"tilted [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"that way","wedo2.motorDirection.forward":"this way","wedo2.motorDirection.reverse":"reverse","wedo2.motorId.a":"motor A","wedo2.motorId.all":"all motors","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"turn [MOTOR_ID] off","wedo2.motorOn":"turn [MOTOR_ID] on","wedo2.motorOnFor":"turn [MOTOR_ID] on for [DURATION] seconds","wedo2.playNoteFor":"play note [NOTE] for [DURATION] seconds","wedo2.setLightHue":"set light color to [HUE]","wedo2.setMotorDirection":"set [MOTOR_ID] direction to [MOTOR_DIRECTION]","wedo2.startMotorPower":"set [MOTOR_ID] power to [POWER]","wedo2.tiltDirection.any":"any","wedo2.tiltDirection.down":"down","wedo2.tiltDirection.left":"left","wedo2.tiltDirection.right":"right","wedo2.tiltDirection.up":"up","wedo2.whenDistance":"when distance [OP] [REFERENCE]","wedo2.whenTilted":"when tilted [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Rəng","paint.paintEditor.saturation":"Dolğunluq","paint.paintEditor.brightness":"Parlaqlıq","paint.paintEditor.costume":"Libas","paint.paintEditor.group":"Qrup","paint.paintEditor.ungroup":"Qrupu ləğv et","paint.paintEditor.undo":"Ləğv et","paint.paintEditor.redo":"Redo","paint.paintEditor.forward":"İrəli","paint.paintEditor.backward":"Geri","paint.paintEditor.front":"Ön","paint.paintEditor.back":"Geri","paint.paintEditor.more":"Daha çox","paint.modeTools.brushSize":"Ölçü","paint.modeTools.eraserSize":"Pozanın ölçüsü","paint.modeTools.copy":"Kopyala","paint.modeTools.paste":"Yerləşdir","paint.modeTools.delete":"Sil","paint.modeTools.curved":"Əyri","paint.modeTools.pointed":"İşarələnmiş","paint.modeTools.thickness":"Qalınlıq","paint.modeTools.flipHorizontal":"Üfiqi çevir","paint.modeTools.flipVertical":"Şaquli çevir","paint.modeTools.filled":"Dolu","paint.modeTools.outlined":"Konturlanmış","paint.paintEditor.bitmap":"Rastr qrafikasına çevir","paint.paintEditor.vector":"Vektor qrafikasına çevir","paint.paintEditor.fill":"Rənglə doldur","paint.paintEditor.stroke":"Kontur","paint.brushMode.brush":"Brush","paint.eraserMode.eraser":"Eraser","paint.fillMode.fill":"Fill","paint.lineMode.line":"Line","paint.ovalMode.oval":"Circle","paint.rectMode.rect":"Rectangle","paint.reshapeMode.reshape":"Reshape","paint.roundedRectMode.roundedRect":"Rounded Rectangle","paint.selectMode.select":"Select","paint.textMode.text":"Text","paint.colorPicker.swap":"Dəyişdir"},"id":{"gui.alerts.tryAgain":"Coba Lagi","gui.alerts.download":"Unduh","gui.connection.reconnect":"Hubungkan Ulang","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Ransel","gui.backpack.errorBackpack":"Gagal memuat ransel","gui.backpack.loadingBackpack":"Memuat...","gui.backpack.more":"Lebih","gui.backpack.emptyBackpack":"Ransel kosong","gui.unsupportedBrowser.label":"Peramban tidak didukung","gui.cards.all-tutorials":"Tutorial","gui.cards.shrink":"Kecilkan","gui.cards.expand":"Perluas","gui.cards.close":"Tutup","gui.cards.more-things-to-try":"Lebih banyak hal untuk dicoba!","gui.cards.see-more":"Lihat lebih banyak","gui.comingSoon.message1":"Jangan khawatir, kami sedang mengerjakannya {emoji}","gui.comingSoon.message2":"Akan Segera Datang","gui.comingSoon.message3":"Kami sedang mengerjakannya {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Tidak ada gawai yang ditemukan.","gui.connection.auto-scanning.prescan":"Letakkan gawaimu di dekat, lalu mulai pencarian.","gui.connection.auto-scanning.pressbutton":"Tekan tombol di gawaimu.","gui.connection.auto-scanning.start-search":"Mulai Mencari","gui.connection.connecting-searchbutton":"Mencari...","gui.connection.auto-scanning.try-again":"Coba lagi","gui.connection.connected":"Terhubung","gui.connection.disconnect":"Putus hubungan","gui.connection.go-to-editor":"Pergi ke Editor","gui.connection.connecting-cancelbutton":"Menyambung...","gui.connection.error.errorMessage":"Ups, terjadi suatu kesalahan.","gui.connection.error.tryagainbutton":"Coba lagi","gui.connection.error.helpbutton":"Bantuan","gui.connection.peripheral-name-label":"Nama gawai","gui.connection.connect":"Sambung","gui.connection.scanning.lookingforperipherals":"Mencari gawai-gawai","gui.connection.scanning.noPeripheralsFound":"Tidak ada gawai yang ditemukan.","gui.connection.scanning.instructions":"Pilih gawaimu dari daftar di atas.","gui.connection.search":"Perbarui","gui.connection.unavailable.installscratchlink":"Pastikan bahwa Scratch Link telah dipasang dan sedang berjalan","gui.connection.unavailable.enablebluetooth":"Pastikan Bluetooth menyala","gui.connection.unavailable.tryagainbutton":"Coba lagi","gui.connection.unavailable.helpbutton":"Bantuan","gui.controls.go":"Jalankan","gui.controls.stop":"Hentikan","gui.crashMessage.label":"Ups! Suatu kesalahan terjadi","gui.crashMessage.errorNumber":"Kesalahan yang terjadi tercatat dengan id {errorId}","gui.crashMessage.reload":"Muat ulang","gui.customProcedures.myblockModalTitle":"Buat sebuah Balok","gui.customProcedures.addAnInputNumberText":"Tambahkan input","gui.customProcedures.numberTextType":"angka atau teks","gui.customProcedures.addAnInputBoolean":"Tambahkan input","gui.customProcedures.booleanType":"boolean","gui.customProcedures.addALabel":"Tambahkan label","gui.customProcedures.runWithoutScreenRefresh":"Bekerja secara instan","gui.customProcedures.cancel":"Batal","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Arah","gui.directionPicker.rotationStyles.allAround":"Semua arah","gui.directionPicker.rotationStyles.leftRight":"Kiri/Kanan","gui.directionPicker.rotationStyles.dontRotate":"Jangan berputar","gui.gui.addExtension":"Tambahkan Ekstensi","gui.gui.codeTab":"Kode","gui.gui.backdropsTab":"Latar","gui.gui.costumesTab":"Kostum","gui.gui.soundsTab":"Suara","gui.extensionLibrary.comingSoon":"Akan Segera Datang","gui.extensionLibrary.requires":"Memerlukan","gui.extensionLibrary.collaboration":"Kolaborasi dengan","gui.library.filterPlaceholder":"Cari","gui.library.allTag":"Semua","gui.loader.headline":"Memuat Karya","gui.loader.creating":"Membuat Karya","gui.authorInfo.byUser":"oleh {username}","gui.menuBar.seeProjectPage":"Lihat Halaman Karya","gui.menuBar.LanguageSelector":"pemilih bahasa","gui.menuBar.tutorialsLibrary":"Tutorial","gui.menuBar.restoreSprite":"Kembalikan Sprite","gui.menuBar.restoreSound":"Kembalikan Suara","gui.menuBar.restoreCostume":"Kembalikan Kostum","gui.menuBar.restore":"Kembalikan","gui.menuBar.saveNow":"Simpan sekarang","gui.menuBar.saveAsCopy":"Simpan sebagai salinan","gui.menuBar.remix":"Remix","gui.menuBar.new":"Baru","gui.menuBar.file":"Berkas","gui.menuBar.downloadToComputer":"Simpan ke komputermu","gui.menuBar.edit":"Sunting","gui.menuBar.turboModeOff":"Matikan Mode Turbo","gui.menuBar.turboModeOn":"Nyalakan Mode Turbo","gui.gui.projectTitlePlaceholder":"Judul karya di sini","gui.menuBar.isShared":"Terbagikan","gui.menuBar.share":"Bagikan","gui.modal.help":"Bantuan","gui.modal.back":"Kembali","gui.monitor.listMonitor.empty":"(kosong)","gui.monitor.listMonitor.listLength":"panjang {length}","gui.monitor.contextMenu.default":"tampilan normal","gui.monitor.contextMenu.large":"tampilan besar","gui.monitor.contextMenu.slider":"slider","gui.monitor.contextMenu.sliderRange":"ubah rentang slider","gui.monitor.contextMenu.import":"impor","gui.monitor.contextMenu.export":"ekspor","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Putar","gui.playButton.stop":"Berhenti","gui.gui.variableScopeOptionAllSprites":"Untuk semua sprite","gui.gui.variableScopeOptionSpriteOnly":"Hanya untuk sprite ini","gui.gui.cloudVariableOption":"Variabel Cloud (disimpan di server)","gui.gui.variablePromptAllSpritesMessage":"Variabel ini bakal tersedia untuk semua sprite.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Batal","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Hentikan","gui.playbackStep.playMsg":"Putar","gui.playbackStep.loadingMsg":"Memuat...","gui.playbackStep.saveMsg":"Simpan","gui.playbackStep.reRecordMsg":"Rekam ulang","gui.recordModal.title":"Rekam Suara","gui.recordingStep.beginRecord":"Mulai merekam dengan mengklik tombol di bawah","gui.recordingStep.permission":"{arrow}Kami memerlukan izinmu untuk menggunakan mikrofonmu","gui.recordingStep.stop":"Berhenti merekam","gui.recordingStep.record":"Rekam","gui.sliderModal.min":"Nilai minimum","gui.sliderModal.max":"Nilai maksimum","gui.sliderModal.title":"Ubah rentang slider","gui.sliderPrompt.cancel":"Batalkan","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Suara","gui.soundEditor.play":"Putar","gui.soundEditor.stop":"Berhenti","gui.soundEditor.copy":"Salin","gui.soundEditor.paste":"Tempel","gui.soundEditor.copyToNew":"Salin ke Baru","gui.soundEditor.delete":"Hapus","gui.soundEditor.save":"Simpan","gui.soundEditor.undo":"Batalkan","gui.soundEditor.redo":"Ulangi","gui.soundEditor.faster":"Lebih cepat","gui.soundEditor.slower":"Lebih lambat","gui.soundEditor.echo":"Gema","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Lebih nyaring","gui.soundEditor.softer":"Lebih lembut","gui.soundEditor.reverse":"Balikkan arah","gui.soundEditor.fadeOut":"Pudar akhir","gui.soundEditor.fadeIn":"Pudar awal","gui.soundEditor.mute":"Bisukan","gui.SpriteInfo.spritePlaceholder":"Judul","gui.SpriteInfo.sprite":"Sprite","gui.SpriteInfo.show":"Tampilkan","gui.SpriteInfo.size":"Ukuran","gui.spriteSelectorItem.contextMenuDuplicate":"gandakan","gui.spriteSelectorItem.contextMenuExport":"ekspor","gui.spriteSelectorItem.contextMenuDelete":"hapus","gui.spriteSelector.addSpriteFromLibrary":"Pilih Sprite","gui.spriteSelector.addSpriteFromPaint":"Lukis","gui.spriteSelector.addSpriteFromSurprise":"Kejutan","gui.spriteSelector.addSpriteFromFile":"Unggah Sprite","gui.stageHeader.stageSizeLarge":"Ganti ke panggung besar","gui.stageHeader.stageSizeSmall":"Ganti ke panggung kecil","gui.stageHeader.stageSizeFull":"Masuk mode layar penuh","gui.stageHeader.stageSizeUnFull":"Keluar dari mode seluruh layar","gui.stageHeader.fullscreenControl":"Kendali Layar Penuh","gui.spriteSelector.addBackdropFromLibrary":"Pilih Latar","gui.stageSelector.addBackdropFromPaint":"Lukis","gui.stageSelector.addBackdropFromSurprise":"Kejutan","gui.stageSelector.addBackdropFromFile":"Unggah Latar","gui.stageSelector.stage":"Panggung","gui.stageSelector.backdrops":"Latar","gui.telemetryOptIn.label":"Laporkan statistik untuk memperbaiki Scratch","gui.telemetryOptIn.body1":"Scratch Team selalu mencari cara untuk mengerti dengan lebih baik bagaimana Scratch digunakan di segala penjuru dunia. Untuk mendukung usaha ini, kamu bisa memperbolehkan Scratch untuk otomatis mengirim informasi penggunaan ke Scratch Team.","gui.telemetryOptIn.body2":"Informasi yang kami kumpulkan termasuk pemilihan bahasa, penggunaan balok, dan sebagian kejadian seperti penyimpanan, pemuatan, dan pengunggahan karya. Kami TIDAK mengumpulkan informasi pribadi. Mohon lihat {privacyPolicyLink}kami untuk informasi lebih jauh.","gui.telemetryOptIn.privacyPolicyLink":"Kebijakan Privasi","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Mode Turbo","gui.webglModal.label":"Perambanmu Tidak Mendukung WebGL","gui.webglModal.webgllink":"tidak mendukung WebGL","gui.costumeLibrary.chooseABackdrop":"Pilih Latar","gui.costumeLibrary.chooseACostume":"Pilih Kostum","gui.costumeTab.addBackdropFromLibrary":"Pilih Latar","gui.costumeTab.addCostumeFromLibrary":"Pilih Kostum","gui.costumeTab.addBlankCostume":"Lukis","gui.costumeTab.addSurpriseCostume":"Kejutan","gui.costumeTab.addFileBackdrop":"Unggah Latar","gui.costumeTab.addFileCostume":"Unggah Kostum","gui.extensionLibrary.chooseAnExtension":"Pilih Ekstensi","gui.extensionLibrary.extensionUrl":"Masukkan URL ekstensi","gui.monitors.importListColumnPrompt":"Kolom mana yang mesti digunakan (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Tidak dapat mulai merekam","gui.soundLibrary.chooseASound":"Pilih Suara","gui.soundTab.fileUploadSound":"Unggah Suara","gui.soundTab.surpriseSound":"Kejutan","gui.soundTab.recordSound":"Rekam","gui.soundTab.addSoundFromLibrary":"Pilih Suara","gui.spriteLibrary.chooseASprite":"Pilih Sprite","gui.tipsLibrary.tutorials":"Pilih sebuah Tutorial","gui.alerts.createsuccess":"Karya baru terbuat.","gui.alerts.createcopysuccess":"Karya disimpan sebagai salinan.","gui.alerts.createremixsuccess":"Karya disimpan sebagai sebuah remix.","gui.alerts.creating":"Buat baru...","gui.alerts.creatingCopy":"Menyalin karya...","gui.alerts.creatingRemix":"Meremix karya...","gui.alerts.creatingError":"Tidak bisa membuat karya. Tolong coba lagi!","gui.alerts.savingError":"Karya tidak bisa disimpan.","gui.alerts.savesuccess":"Karya tersimpan.","gui.alerts.saving":"Menyimpan karya...","gui.alerts.cloudInfo":"Tolong ingat, bahwa variabel cloud hanya mendukung angka-angka, tidak huruf atau simbol. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Pelajari lebih lanjut.","gui.alerts.importing":"Mengimpor ...","gui.defaultProject.variable":"variabel saya","gui.extension.music.name":"Musik","gui.extension.music.description":"Mainkan instrumen dan drum.","gui.extension.pen.name":"Pena","gui.extension.pen.description":"Menggambar dengan sprite-spritemu.","gui.extension.videosensing.name":"Sensor Video","gui.extension.videosensing.description":"Mendeteksi gerakan dengan kamera.","gui.extension.text2speech.name":"Teks ke Ucapan.","gui.extension.text2speech.description":"Buat karya-karyamu berbicara.","gui.extension.translate.name":"Terjemahkan","gui.extension.translate.description":"Terjemahkan teks menjadi berbagai bahasa.","gui.extension.makeymakey.description":"Buat apapun menjadi sebuah tombol.","gui.extension.microbit.description":"Hubungkan karya-karyamu ke dunia.","gui.extension.microbit.connectingMessage":"Menyambung","gui.extension.ev3.description":"Buat robot-robot interaktif dan lebih banyak lagi.","gui.extension.ev3.connectingMessage":"Menyambung. Pastikan pin di EV3 kamu diatur ke 1234.","gui.extension.boost.description":"Hidupkan kreasi-kreasi robotik.","gui.extension.boost.connectingMessage":"Menghubungkan","gui.extension.wedo2.description":"Berkreasi dengan motor dan sensor.","gui.extension.wedo2.connectingMessage":"Menyambung","gui.extension.gdxfor.description":"Mendeteksi dorongan, tarikan, gerakan, dan putaran.","gui.extension.gdxfor.connectingMessage":"Menghubungkan","gui.libraryTags.all":"Semua","gui.libraryTags.animals":"Hewan","gui.libraryTags.dance":"Menari","gui.libraryTags.effects":"Efek","gui.libraryTags.fantasy":"Fantasi","gui.libraryTags.fashion":"Fesyen","gui.libraryTags.food":"Makanan","gui.libraryTags.indoors":"Dalam ruangan","gui.libraryTags.loops":"Perulangan","gui.libraryTags.music":"Musik","gui.libraryTags.notes":"Catatan","gui.libraryTags.outdoors":"Luar Ruangan","gui.libraryTags.patterns":"Pola","gui.libraryTags.people":"Orang","gui.libraryTags.percussion":"Perkusi","gui.libraryTags.space":"Luar angkasa","gui.libraryTags.sports":"Olahraga","gui.libraryTags.underwater":"Di bawah laut","gui.libraryTags.voice":"Suara","gui.libraryTags.wacky":"Aneh","gui.libraryTags.animation":"Animasi","gui.libraryTags.art":"Kesenian","gui.libraryTags.games":"Permainan","gui.libraryTags.stories":"Cerita","gui.libraryTags.letters":"Huruf","gui.opcodeLabels.direction":"arah","gui.opcodeLabels.xposition":"posisi x","gui.opcodeLabels.yposition":"posisi y","gui.opcodeLabels.size":"ukuran","gui.opcodeLabels.costumename":"nama kostum","gui.opcodeLabels.costumenumber":"nomor kostum","gui.opcodeLabels.backdropname":"nama latar","gui.opcodeLabels.backdropnumber":"nomor latar","gui.opcodeLabels.volume":"volume","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"jawaban","gui.opcodeLabels.loudness":"kenyaringan","gui.opcodeLabels.username":"nama pengguna","gui.opcodeLabels.year":"tahun","gui.opcodeLabels.month":"bulan","gui.opcodeLabels.date":"tanggal","gui.opcodeLabels.dayofweek":"nama hari","gui.opcodeLabels.hour":"jam","gui.opcodeLabels.minute":"menit","gui.opcodeLabels.second":"detik","gui.opcodeLabels.timer":"pengatur waktu","gui.sharedMessages.backdrop":"latar {index}","gui.sharedMessages.costume":"kostum {index}","gui.sharedMessages.sprite":"Sprite {index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Ganti isi dari karya sekarang?","gui.sharedMessages.loadFromComputerTitle":"Muat dari komputermu","boost.color.any":"warna apapun","boost.color.black":"hitam","boost.color.blue":"biru","boost.color.green":"hijau","boost.color.red":"merah","boost.color.white":"putih","boost.color.yellow":"kuning","boost.getMotorPosition":"posisi motor [MOTOR_REPORTER_ID]","boost.getTiltAngle":"sudut kemiringan [TILT_DIRECTION]","boost.motorDirection.backward":"ke arah sana","boost.motorDirection.forward":"ke arah sini","boost.motorDirection.reverse":"reverse","boost.motorOff":"matikan motor [MOTOR_ID]","boost.motorOn":"nyalakan motor [MOTOR_ID]","boost.motorOnFor":"nyalakan motor [MOTOR_ID] selama [DURATION] detik","boost.motorOnForRotation":"nyalakan motor [MOTOR_ID] selama [ROTATION] rotasi","boost.seeingColor":"melihat bata [COLOR]?","boost.setLightHue":"atur warna lampu ke [HUE]","boost.setMotorDirection":"atur arah motor [MOTOR_ID] [MOTOR_DIRECTION]","boost.setMotorPower":"atur kecepatan motor [MOTOR_ID] ke [POWER] %","boost.tiltDirection.any":"any","boost.tiltDirection.down":"bawah","boost.tiltDirection.left":"kiri","boost.tiltDirection.right":"kanan","boost.tiltDirection.up":"atas","boost.whenColor":"ketika bata [COLOR] dilihat","boost.whenTilted":"ketika dimiringkan [TILT_DIRECTION_ANY]","ev3.beepNote":"bunyikan nada [NOTE] selama [TIME] detik","ev3.buttonPressed":"tombol [PORT] ditekan?","ev3.getBrightness":"kecerahan","ev3.getDistance":"jarak","ev3.getMotorPosition":"posisi motor [PORT]","ev3.motorSetPower":"motor [PORT] atur kekuatan [POWER] %","ev3.motorTurnClockwise":"motor [PORT] belok ke arah ini selama [TIME] detik","ev3.motorTurnCounterClockwise":"motor [PORT] belok ke arah itu selama [TIME] detik","ev3.whenBrightnessLessThan":"ketika kecerahan < [DISTANCE]","ev3.whenButtonPressed":"ketika tombol [PORT] ditekan","ev3.whenDistanceLessThan":"ketika jarak < [DISTANCE]","gdxfor.getAcceleration":"akselerasi [DIRECTION]","gdxfor.getForce":"gaya","gdxfor.getSpin":"kecepatan berputar [DIRECTION]","gdxfor.getTilt":"sudut kemiringan [TILT]","gdxfor.isFreeFalling":"sedang jatuh bebas?","gdxfor.isTilted":"dimiringkan [TILT]?","gdxfor.pulled":"ditarik","gdxfor.pushed":"didorong","gdxfor.shaken":"digoyang","gdxfor.startedFalling":"mulai jatuh bebas","gdxfor.tiltDirectionMenu.any":"any","gdxfor.tiltDirectionMenu.back":"belakang","gdxfor.tiltDirectionMenu.front":"depan","gdxfor.tiltDirectionMenu.left":"kiri","gdxfor.tiltDirectionMenu.right":"kanan","gdxfor.turnedFaceDown":"tengkurap","gdxfor.turnedFaceUp":"telentang","gdxfor.whenForcePushedOrPulled":"ketika sensor gaya [PUSH_PULL]","gdxfor.whenGesture":"ketika [GESTURE]","gdxfor.whenTilted":"ketika dimiringkan [TILT]","makeymakey.downArrow":"panah bawah","makeymakey.downArrowShort":"bawah","makeymakey.leftArrow":"panah kiri","makeymakey.leftArrowShort":"kiri","makeymakey.rightArrow":"panah kanan","makeymakey.rightArrowShort":"kanan","makeymakey.spaceKey":"spasi","makeymakey.upArrow":"panah atas","makeymakey.upArrowShort":"atas","makeymakey.whenKeyPressed":"ketika tombol [KEY] ditekan","makeymakey.whenKeysPressedInOrder":"ketika [SEQUENCE] ditekan dalam urutan tersebut","microbit.buttonsMenu.any":"manapun","microbit.clearDisplay":"bersihkan tampilan","microbit.defaultTextToDisplay":"Halo!","microbit.displaySymbol":"tampilkan [MATRIX]","microbit.displayText":"tampilkan teks [TEXT]","microbit.gesturesMenu.jumped":"melompat","microbit.gesturesMenu.moved":"bergerak","microbit.gesturesMenu.shaken":"tergoyang","microbit.isButtonPressed":"tombol [BTN] ditekan?","microbit.isTilted":"miring [DIRECTION]?","microbit.pinStateMenu.off":"mati","microbit.pinStateMenu.on":"hidup","microbit.tiltAngle":"sudut miring [DIRECTION]","microbit.tiltDirectionMenu.any":"manapun","microbit.tiltDirectionMenu.back":"belakang","microbit.tiltDirectionMenu.front":"depan","microbit.tiltDirectionMenu.left":"kiri","microbit.tiltDirectionMenu.right":"kanan","microbit.whenButtonPressed":"ketika tombol [BTN] ditekan","microbit.whenGesture":"ketika [GESTURE]","microbit.whenPinConnected":"ketika pin [PIN] disambung","microbit.whenTilted":"ketika dimiringkan [DIRECTION]","music.categoryName":"Musik","music.changeTempo":"ubah tempo sebesar [TEMPO]","music.drumBass":"(2) Drum Bass","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) Hi-Hat Tertutup","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Lonceng Sapi","music.drumCrashCymbal":"(4) Simbal","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Tepukan Tangan","music.drumOpenHiHat":"(5) Hi-Hat Terbuka","music.drumSideStick":"(3) Tongkat Samping","music.drumSnare":"(1) Drum Senar","music.drumTambourine":"(7) Tamborin","music.drumTriangle":"(12) Triangle","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Balok Kayu","music.getTempo":"tempo","music.instrumentBass":"(6) Bass","music.instrumentBassoon":"(14) Fagot","music.instrumentCello":"(8) Cello","music.instrumentChoir":"(15) Paduan Suara","music.instrumentClarinet":"(10) Klarinet","music.instrumentElectricGuitar":"(5) Gitar Listrik","music.instrumentElectricPiano":"(2) Piano Listrik","music.instrumentFlute":"(12) Seruling","music.instrumentGuitar":"(4) Gitar","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Kotak Musik","music.instrumentOrgan":"(3) Organ","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saksofon","music.instrumentSteelDrum":"(18) Drum Baja","music.instrumentSynthLead":"(20) Sintesis Pimpinan","music.instrumentSynthPad":"(21) Pad Sintesis","music.instrumentTrombone":"(9) Trombon","music.instrumentVibraphone":"(16) Vibrafon","music.instrumentWoodenFlute":"(13) Seruling Kayu","music.midiPlayDrumForBeats":"mainkan drum [DRUM] selama [BEATS] ketukan","music.midiSetInstrument":"atur instrumen ke [INSTRUMENT]","music.playDrumForBeats":"mainkan drum [DRUM] selama [BEATS] ketukan","music.playNoteForBeats":"mainkan nada [NOTE] selama [BEATS] ketukan","music.restForBeats":"diam selama [BEATS] ketukan","music.setInstrument":"atur instrumen ke [INSTRUMENT]","music.setTempo":"atur tempo ke [TEMPO]","pen.categoryName":"Pena","pen.changeColorParam":"ubah [COLOR_PARAM] pena sebesar [VALUE]","pen.changeHue":"ubah warna pena sebesar [HUE]","pen.changeShade":"ubah kegelapan pena sebesar [SHADE]","pen.changeSize":"ubah ukuran pena sebesar [SIZE]","pen.clear":"hapus semua","pen.colorMenu.brightness":"kecerahan","pen.colorMenu.color":"warna","pen.colorMenu.saturation":"saturasi","pen.colorMenu.transparency":"transparansi","pen.penDown":"tekan pena","pen.penUp":"angkat pena","pen.setColor":"atur warna pena ke [COLOR]","pen.setColorParam":"atur [COLOR_PARAM] pena ke [VALUE]","pen.setHue":"atur warna pena ke [HUE]","pen.setShade":"atur kegelapan pena sebesar [SHADE]","pen.setSize":"atur ukuran pena ke [SIZE]","pen.stamp":"cap","text2speech.alto":"alto","text2speech.categoryName":"Teks ke Ucapan.","text2speech.defaultTextToSpeak":"halo","text2speech.giant":"raksasa","text2speech.kitten":"anak kucing","text2speech.setLanguageBlock":"atur bahasa ke [LANGUAGE]","text2speech.setVoiceBlock":"atur suara ke [VOICE]","text2speech.speakAndWaitBlock":"ujarkan [WORDS]","text2speech.squeak":"mencicit","text2speech.tenor":"tenor","translate.categoryName":"Terjemahkan","translate.defaultTextToTranslate":"halo","translate.translateBlock":"terjemahkan [WORDS] ke [LANGUAGE]","translate.viewerLanguage":"bahasa","videoSensing.categoryName":"Sensor Video","videoSensing.direction":"arah","videoSensing.motion":"gerakan","videoSensing.off":"mati","videoSensing.on":"hidup","videoSensing.onFlipped":"nyala dibalik","videoSensing.setVideoTransparency":"atur transparansi video ke [TRANSPARENCY]","videoSensing.sprite":"sprite","videoSensing.stage":"panggung","videoSensing.videoOn":"video [ATTRIBUTE] di [SUBJECT]","videoSensing.videoToggle":"nyalakan video [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"ketika gerakan video > [REFERENCE]","wedo2.getDistance":"jarak","wedo2.getTiltAngle":"sudut kemiringan [TILT_DIRECTION]","wedo2.isTilted":"dimiringkan [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"ke arah sana","wedo2.motorDirection.forward":"ke arah sini","wedo2.motorDirection.reverse":"balikkan arah","wedo2.motorId.a":"motor A","wedo2.motorId.all":"semua motor","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"matikan [MOTOR_ID]","wedo2.motorOn":"nyalakan [MOTOR_ID]","wedo2.motorOnFor":"nyalakan [MOTOR_ID] selama [DURATION] detik","wedo2.playNoteFor":"mainkan nada [NOTE] selama [DURATION] detik","wedo2.setLightHue":"atur warna lampu ke [HUE]","wedo2.setMotorDirection":"atur arah [MOTOR_ID] ke [MOTOR_DIRECTION]","wedo2.startMotorPower":"atur kekuatan [MOTOR_ID] ke [POWER]","wedo2.tiltDirection.any":"manapun","wedo2.tiltDirection.down":"bawah","wedo2.tiltDirection.left":"kiri","wedo2.tiltDirection.right":"kanan","wedo2.tiltDirection.up":"atas","wedo2.whenDistance":"ketika jarak [OP] [REFERENCE]","wedo2.whenTilted":"ketika dimiringkan [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Warna","paint.paintEditor.saturation":"Saturasi","paint.paintEditor.brightness":"Keterangan","paint.paintEditor.costume":"Kostum","paint.paintEditor.group":"Kelompokkan","paint.paintEditor.ungroup":"Pisahkan","paint.paintEditor.undo":"Undo","paint.paintEditor.redo":"Ulangi","paint.paintEditor.forward":"Maju","paint.paintEditor.backward":"Mundur","paint.paintEditor.front":"Depan","paint.paintEditor.back":"Back","paint.paintEditor.more":"Lebih","paint.modeTools.brushSize":"Ukuran","paint.modeTools.eraserSize":"Ukuran penghapus","paint.modeTools.copy":"Salin","paint.modeTools.paste":"Tempel","paint.modeTools.delete":"Hapus","paint.modeTools.curved":"Bundar","paint.modeTools.pointed":"Tajam","paint.modeTools.thickness":"Ketebalan","paint.modeTools.flipHorizontal":"Balikkan Secara Horisontal","paint.modeTools.flipVertical":"Balikkan Secara Vertikal","paint.modeTools.filled":"Terisi","paint.modeTools.outlined":"Garis besar","paint.paintEditor.bitmap":"Sesuaikan ke Bitmap","paint.paintEditor.vector":"Sesuaikan ke Vektor","paint.paintEditor.fill":"Isi","paint.paintEditor.stroke":"Garis besar","paint.brushMode.brush":"Kuas","paint.eraserMode.eraser":"Penghapus","paint.fillMode.fill":"Isi","paint.lineMode.line":"Garis","paint.ovalMode.oval":"Lingkaran","paint.rectMode.rect":"Persegi panjang","paint.reshapeMode.reshape":"Bentuk ulang","paint.roundedRectMode.roundedRect":"Persegi Bulat","paint.selectMode.select":"Pilih","paint.textMode.text":"Teks","paint.colorPicker.swap":"Tukar","tw.alerts.savedToDisk":"Telah disimpan di komputer","tw.footer.donate":"Donasi","tw.footer.translate":"Bantu Translate TurboWarp","tw.gui.crashMessage.description":"Kami minta maaf, sepertinya halaman anda crash.Tolong untuk coba ulang lagi dan memperbarui halaman anda.","tw.gui.defaultProjectTitle":"Proyek","tw.home.credit":"Catatan dan Kredit","tw.home.instructions":"Instruksi","tw.loader.data":"Mendownload Data Proyek","tw.loader.generic":"Memuat Proyek","tw.menuBar.60off":"Matikan Mode FPS 60","tw.menuBar.changeUsername":"Ganti Username","tw.menuBar.reportError2":"Ini adalah Bug.Tolong Laporkan Ini","tw.menuBar.saveAs":"Simpan Sebagai {file}","tw.menuBar.seeInside":"Lihat Didalam","tw.oldDownload":"Simpan di fIle pisahan ","tw.saveAs":"Simpan Sebagai","tw.saveTo":"Simpan Ke {file}","tw.spriteSelectorItem.rename":"ganti nama","tw.studioview.authorAttribution":"dari {author}","tw.usernameModal.reset":"Mengatur Ulang ","tw.usernameModal.title":"Ganti Username"},"bn":{"gui.alerts.tryAgain":"আবার চেষ্টা কর","gui.alerts.download":"ডাউনলোড","gui.connection.reconnect":"পুনঃসংযোগ","gui.backpack.costumeLabel":"পোশাক","gui.backpack.soundLabel":"শব্দ","gui.backpack.scriptLabel":"স্ক্রিপ্ট","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"ব্যাকপ্যাক","gui.backpack.errorBackpack":"ব্যাকপ্যাক লোড করার সময় ত্রুটি","gui.backpack.loadingBackpack":"লোড হচ্ছে...","gui.backpack.more":"আরও","gui.backpack.emptyBackpack":"ব্যাকপ্যাক খালি","gui.unsupportedBrowser.label":"ব্রাউজার সমর্থিত নয়","gui.cards.all-tutorials":"টিউটোরিয়াল","gui.cards.shrink":"সংকোচন","gui.cards.expand":"বৃদ্ধি","gui.cards.close":"বন্ধ কর","gui.cards.more-things-to-try":"আরো জিনিস চেষ্টা কর!","gui.cards.see-more":"আরও দেখ","gui.comingSoon.message1":"চিন্তা কর না, আমরা এটা করছি{emoji}","gui.comingSoon.message2":"শীঘ্রই আসছে...","gui.comingSoon.message3":"আমরা এটা নিয়ে কাজ করছি {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"কোন ডিভাইস খুঁজে পাওয়া যায়নি","gui.connection.auto-scanning.prescan":"তোমার ডিভাইসটি কি কাছাকাছি, তাহলে খোঁজা শুরু কর।","gui.connection.auto-scanning.pressbutton":"তোমার ডিভাইসের বাটনটিতে চাপ দাও।","gui.connection.auto-scanning.start-search":"খোঁজা শুরু কর","gui.connection.connecting-searchbutton":"খোঁজা হচ্ছে...","gui.connection.auto-scanning.try-again":"আবার চেষ্টা কর","gui.connection.connected":"সংযুক্ত","gui.connection.disconnect":"সংযোগ বিচ্ছিন্ন কর","gui.connection.go-to-editor":"এডিটরে যাও","gui.connection.connecting-cancelbutton":"সংযুক্ত হচ্ছে... ","gui.connection.error.errorMessage":"উফ, মনে হচ্ছে কিছু ভুল হয়েছে।","gui.connection.error.tryagainbutton":"আবার চেষ্টা কর ","gui.connection.error.helpbutton":"সাহায্য","gui.connection.peripheral-name-label":"ডিভাইসের নাম","gui.connection.connect":"সংযুক্ত","gui.connection.scanning.lookingforperipherals":"ডিভাইস খুঁজা হচ্ছে","gui.connection.scanning.noPeripheralsFound":"কোন ডিভাইস খুঁজে পাওয়া যায়নি","gui.connection.scanning.instructions":"উপরের তালিকা থেকে তোমার ডিভাইস নির্বাচন কর।","gui.connection.search":"রিফ্রেশ","gui.connection.unavailable.installscratchlink":"নিশ্চিত কর তোমার Scratch লিংকটি ইন্সটল করা এবং চলমান আছে","gui.connection.unavailable.enablebluetooth":"ব্লুটুথ চালু আছে কিনা যাচাই কর","gui.connection.unavailable.tryagainbutton":"আবার চেষ্টা কর ","gui.connection.unavailable.helpbutton":"সাহায্য","gui.controls.go":"যাও ","gui.controls.stop":"থামাও ","gui.crashMessage.label":"উফ! কিছু একটা সমস্যা হয়েছে।","gui.crashMessage.errorNumber":"তোমার ইররটি {errorId} আইডি থেকে লগ করা","gui.crashMessage.reload":"রিলোড","gui.customProcedures.myblockModalTitle":"একটি ব্লক তৈরি কর","gui.customProcedures.addAnInputNumberText":"একটি ইনপুট যোগ কর","gui.customProcedures.numberTextType":"সংখ্যা অথবা টেক্সট","gui.customProcedures.addAnInputBoolean":"একটি ইনপুট যোগ কর ","gui.customProcedures.booleanType":"boolean","gui.customProcedures.addALabel":"একটি লেবেল যোগ কর","gui.customProcedures.runWithoutScreenRefresh":" স্ক্রিন রিফ্রেশ না করে চালাও","gui.customProcedures.cancel":"বাতিল কর","gui.customProcedures.ok":"ঠিক আছে","gui.SpriteInfo.direction":"দিক","gui.directionPicker.rotationStyles.allAround":"চারপাশে ","gui.directionPicker.rotationStyles.leftRight":"বাম/ডান","gui.directionPicker.rotationStyles.dontRotate":"ঘুরাইয়ো না","gui.gui.addExtension":"এক্সটেনশন যোগ কর","gui.gui.codeTab":"কোড ","gui.gui.backdropsTab":"ব্যাকড্রপগুলো ","gui.gui.costumesTab":"পোশাক ","gui.gui.soundsTab":"শব্দগুলো","gui.extensionLibrary.comingSoon":"শীঘ্রই আসছে","gui.extensionLibrary.requires":"প্রয়োজনীয়","gui.extensionLibrary.collaboration":"এর সাথে সহযোগিতা","gui.library.filterPlaceholder":"অনুসন্ধান","gui.library.allTag":"সব","gui.loader.headline":"প্রজেক্ট লোড হচ্ছে","gui.loader.creating":"প্রজেক্ট তৈরি হচ্ছে","gui.authorInfo.byUser":"{username} দ্বারা","gui.menuBar.seeProjectPage":"প্রজেক্ট পেইজ দেখ","gui.menuBar.LanguageSelector":"ভাষা নির্ধারক","gui.menuBar.tutorialsLibrary":"টিউটোরিয়াল","gui.menuBar.restoreSprite":"স্প্রাইট পুনরুদ্ধার কর","gui.menuBar.restoreSound":"শব্দ পুনরুদ্ধার কর","gui.menuBar.restoreCostume":"পোশাক পুনরুদ্ধার কর","gui.menuBar.restore":"পুনরুদ্ধার","gui.menuBar.saveNow":"এখনই সংরক্ষন কর","gui.menuBar.saveAsCopy":"একটি কপি হিসেবে সংরক্ষন কর","gui.menuBar.remix":"রিমিক্স","gui.menuBar.new":"নতুন","gui.menuBar.file":"ফাইল","gui.menuBar.downloadToComputer":"তোমার কম্পিউটারে সংরক্ষন কর","gui.menuBar.edit":"সম্পাদনা","gui.menuBar.turboModeOff":"টার্বো মোড বন্ধ কর","gui.menuBar.turboModeOn":"টার্বো মোড চালু কর ","gui.gui.projectTitlePlaceholder":"প্রজেক্ট এর নাম এখানে","gui.menuBar.isShared":"শেয়ার করেছিল","gui.menuBar.share":"শেয়ার","gui.modal.help":"সাহায্য","gui.modal.back":"পিছনে","gui.monitor.listMonitor.empty":"(empty)","gui.monitor.listMonitor.listLength":"লম্বা {length} ","gui.monitor.contextMenu.default":"সাধারণ রিডআউট","gui.monitor.contextMenu.large":"বড় করে পড় ","gui.monitor.contextMenu.slider":"স্লাইডার","gui.monitor.contextMenu.sliderRange":"স্লাইডার ব্যাপ্তি পরিবর্তন কর","gui.monitor.contextMenu.import":"ইম্পোর্ট","gui.monitor.contextMenu.export":"এক্সপোর্ট","gui.monitor.contextMenu.hide":"লুকাও","gui.playButton.play":"শুরু কর ","gui.playButton.stop":"থামাও ","gui.gui.variableScopeOptionAllSprites":"সব স্প্রাইটের জন্য","gui.gui.variableScopeOptionSpriteOnly":"শুধু এই স্প্রাইটের জন্য","gui.gui.cloudVariableOption":"ক্লাউড ভেরিয়েবল (সার্ভারে সংরক্ষিত হয়েছে)","gui.gui.variablePromptAllSpritesMessage":"এই ভ্যারিয়েবল সব স্প্রাইটের জন্য পাওয়া যাবে।","gui.gui.listPromptAllSpritesMessage":"এই তালিকাটি সব স্প্রাইটের জন্য পাওয়া যাবে।","gui.prompt.cancel":"বাতিল","gui.prompt.ok":"ঠিক আছে","gui.playbackStep.stopMsg":"থামাও","gui.playbackStep.playMsg":"বাজাও","gui.playbackStep.loadingMsg":"লোড হচ্ছে...","gui.playbackStep.saveMsg":"সংরক্ষন","gui.playbackStep.reRecordMsg":"পুনরায় রেকর্ড কর","gui.recordModal.title":"শব্দ রেকর্ড কর","gui.recordingStep.beginRecord":"নিচের বোতাম ক্লিক করে রেকর্ড করা শুরু কর","gui.recordingStep.permission":"{arrow} তোমার মাইক্রোফোনটি ব্যবহার করার জন্য আমাদের তোমার অনুমতি দরকার","gui.recordingStep.stop":"রেকর্ড করা বন্ধ কর","gui.recordingStep.record":"রেকর্ড","gui.sliderModal.min":"সর্বনিন্ম মান ","gui.sliderModal.max":"সর্বোচ্চ মান ","gui.sliderModal.title":"স্লাইডার ব্যাপ্তি পরিবর্তন কর","gui.sliderPrompt.cancel":"বাতিল কর","gui.sliderPrompt.ok":"ঠিক আছে","gui.soundEditor.sound":"শব্দ","gui.soundEditor.play":"বাজাও","gui.soundEditor.stop":"থামাও ","gui.soundEditor.copy":"কপি","gui.soundEditor.paste":"পেস্ট","gui.soundEditor.copyToNew":"নতুন একটি কপি কর","gui.soundEditor.delete":"অপসারণ","gui.soundEditor.save":"সংরক্ষন","gui.soundEditor.undo":"পূর্বাবস্থায় ফেরত","gui.soundEditor.redo":"পুনরায় কর","gui.soundEditor.faster":"দ্রুত গতি","gui.soundEditor.slower":"ধীর গতি","gui.soundEditor.echo":"প্রতিধ্বনি","gui.soundEditor.robot":"রোবট","gui.soundEditor.louder":"উচ্চ স্বর","gui.soundEditor.softer":"কোমল","gui.soundEditor.reverse":"বিপরীত","gui.soundEditor.fadeOut":"উজ্জ্বল","gui.soundEditor.fadeIn":"ফ্যাকাসে","gui.soundEditor.mute":"মিউট","gui.SpriteInfo.spritePlaceholder":"নাম","gui.SpriteInfo.sprite":"স্প্রাইট","gui.SpriteInfo.show":"দেখাও ","gui.SpriteInfo.size":"আকার","gui.spriteSelectorItem.contextMenuDuplicate":"অনুরূপ","gui.spriteSelectorItem.contextMenuExport":"এক্সপোর্ট","gui.spriteSelectorItem.contextMenuDelete":"অপসারণ","gui.spriteSelector.addSpriteFromLibrary":"একটি স্প্রাইট বাছাই কর","gui.spriteSelector.addSpriteFromPaint":"আঁক ","gui.spriteSelector.addSpriteFromSurprise":"চমক","gui.spriteSelector.addSpriteFromFile":" স্প্রাইট আপলোড কর","gui.stageHeader.stageSizeLarge":"বড় মঞ্চে পরিবর্তন কর","gui.stageHeader.stageSizeSmall":"ছোট মঞ্চে পরিবর্তন কর","gui.stageHeader.stageSizeFull":"ফুলস্ক্রিন মুডে প্রবেশ কর","gui.stageHeader.stageSizeUnFull":"ফুলস্ক্রিন মুড থেকে বাহির হও","gui.stageHeader.fullscreenControl":"ফুলস্ক্রিন নিয়ন্ত্রণ","gui.spriteSelector.addBackdropFromLibrary":"একটি ব্যাকড্রপ বাছাই কর","gui.stageSelector.addBackdropFromPaint":"আঁক","gui.stageSelector.addBackdropFromSurprise":"চমক","gui.stageSelector.addBackdropFromFile":" ব্যাকড্রপ আপলোড কর","gui.stageSelector.stage":"মঞ্চ","gui.stageSelector.backdrops":"ব্যাকড্রপগুলো","gui.telemetryOptIn.label":"Scratch আরও উন্নত করতে পরিসংখ্যানটি রিপোর্ট কর","gui.telemetryOptIn.body1":"Scratch টিম সর্বদা বিশ্বজুড়ে Scratch কিভাবে ব্যবহৃত হয় তা আরও ভালোভাবে জানার চেষ্টা করছে। এই প্রচেষ্টাকে সমর্থন করার জন্য, তুমি Scratch এর ব্যবহারের তথ্য Scratch টিমের কাছে স্বয়ংক্রিয়ভাবে প্রেরণের অনুমতি দিতে পার।","gui.telemetryOptIn.body2":"আমরা যে তথ্য সংগ্রহ করি সেগুলোর মধ্যে ভাষা নির্বাচন, ব্লকসমূহ ব্যবহার এবং কিছু ইভেন্টস যেমন সেভ করা, লোডিং এবং প্রজেক্ট আপলোডিং অন্তর্ভুক্ত। আমরা কোন ব্যক্তিগত তথ্য সংগ্রহ করি না। অনুগ্রহ করে আরও তথ্যের জন্য আমাদের {privacyPolicyLink} দেখ।","gui.telemetryOptIn.privacyPolicyLink":"গোপনীয়তা নীতি","gui.telemetryOptIn.optInText":"Scratch টিমের সাথে আমার ব্যবহৃত ডাটা শেয়ার কর","gui.telemetryOptIn.optInTooltip":" telemetry সচল কর","gui.telemetryOptIn.optOutText":"আমার ব্যবহৃত ডাটা Scratch টিমের সাথে শেয়ার কর না। ","gui.telemetryOptIn.optOutTooltip":"telemetry অচল কর","gui.telemetryOptIn.settingWasUpdated":"তোমার সেটিংস আপডেট করা হয়েছে।","gui.telemetryOptIn.buttonClose":"বন্ধ কর","gui.turboMode.active":"টার্বো মোড","gui.webglModal.label":"তোমার ব্রাউজার WebGL সমর্থন করে না","gui.webglModal.webgllink":"WebGL সমর্থন করে না","gui.costumeLibrary.chooseABackdrop":"একটি ব্যাকড্রপ বাছাই কর","gui.costumeLibrary.chooseACostume":"একটি পোশাক বাছাই কর","gui.costumeTab.addBackdropFromLibrary":"একটি ব্যাকড্রপ বাছাই কর","gui.costumeTab.addCostumeFromLibrary":"একটি পোশাক বাছাই কর","gui.costumeTab.addBlankCostume":"আঁক","gui.costumeTab.addSurpriseCostume":"চমক","gui.costumeTab.addFileBackdrop":"ব্যাকড্রপ আপলোড কর","gui.costumeTab.addFileCostume":"পোশাক আপলোড কর","gui.extensionLibrary.chooseAnExtension":"এক্সটেনশন বাছাই কর","gui.extensionLibrary.extensionUrl":"এক্সটেনশনের URL প্রবেশ করাও","gui.monitors.importListColumnPrompt":"কোন কলামটি ব্যবহার করা উচিত (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"রেকর্ডিং শুরু করা যাচ্ছে না","gui.soundLibrary.chooseASound":"একটি শব্দ বাছাই কর","gui.soundTab.fileUploadSound":" শব্দ আপলোড কর","gui.soundTab.surpriseSound":"চমক","gui.soundTab.recordSound":"রেকর্ড","gui.soundTab.addSoundFromLibrary":"একটি শব্দ বাছাই কর","gui.spriteLibrary.chooseASprite":"একটি স্প্রাইট বাছাই কর","gui.tipsLibrary.tutorials":"টিউটোরিয়াল বাছাই কর","gui.alerts.createsuccess":"নতুন প্রজেক্ট তৈরি হয়েছে।","gui.alerts.createcopysuccess":"প্রজেক্ট কপি হিসেবে সেভ হয়েছে।","gui.alerts.createremixsuccess":"প্রজেক্ট রিমিক্স হয়ে সেভ হয়েছে","gui.alerts.creating":"নতুন তৈরি হচ্ছে...","gui.alerts.creatingCopy":"প্রজেক্টে কপি হচ্ছে...","gui.alerts.creatingRemix":"প্রজেক্ট রিমিক্সি হচ্ছে...","gui.alerts.creatingError":"প্রজেক্ট তৈরি করা যায় নি। অনুগ্রহ করে আবার চেষ্টা কর!","gui.alerts.savingError":"প্রজেক্ট সংরক্ষিত হচ্ছে না।","gui.alerts.savesuccess":"প্রজেক্ট সংরক্ষিত।","gui.alerts.saving":"প্রজেক্টে সংরক্ষিত হচ্ছে...","gui.alerts.cloudInfo":"নোট, ক্লাউড ভেরিয়েবল কেবলমাত্র সংখ্যাগুলো সমর্থন করে, অক্ষর বা চিহ্ন নয়। {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"আরও জানো।","gui.alerts.importing":"ইম্পোর্ট হচ্ছে…","gui.defaultProject.variable":"আমার ভ্যারিয়েবল","gui.extension.music.name":"সঙ্গীত","gui.extension.music.description":"ঢোল এবং ইন্সটুমেন্টগুলো বাজাও।","gui.extension.pen.name":"কলম","gui.extension.pen.description":" তোমার স্প্রাইটের সাহায্যে আঁক","gui.extension.videosensing.name":"ভিডিও অনুমান ","gui.extension.videosensing.description":"ক্যামারার সাহায্যে গতি অনুভব কর। ","gui.extension.text2speech.name":"টেক্সট টু স্পিচ","gui.extension.text2speech.description":"তোমার প্রজেক্টটিকে কথা বলাও। ","gui.extension.translate.name":"অনুবাদ","gui.extension.translate.description":" অনেক ভাষায় টেক্সট অনুবাদ কর","gui.extension.makeymakey.description":"যেকোন কিছুকে কী তে পরিণত কর","gui.extension.microbit.description":" পৃথিবীর সাথে তোমার প্রজেক্ট যুক্ত কর।","gui.extension.microbit.connectingMessage":"সংযুক্ত হচ্ছে","gui.extension.ev3.description":" ইন্টারেক্টিভ রোবট বানাও এবং অন্যান্য।","gui.extension.ev3.connectingMessage":"সংযুক্ত হচ্ছে। নিশ্চিত কর তোমার EV3 পিনটি 1234 নির্ধারণ করা আছে","gui.extension.boost.description":"রোবোটিক সৃষ্টিগুলোকে প্রাণবন্ত কর।","gui.extension.boost.connectingMessage":"সংযোগ হচ্ছে","gui.extension.wedo2.description":"মোটর এবং সেন্সরের সাহায্যে তৈরি কর।","gui.extension.wedo2.connectingMessage":"সংযুক্ত হচ্ছে","gui.extension.gdxfor.description":"ধাক্কা, টান, গতি ও ঘুর্নণ অনুভব কর। ","gui.extension.gdxfor.connectingMessage":"সংযোগ হচ্ছে","gui.libraryTags.all":"সব","gui.libraryTags.animals":"পশুপাখি","gui.libraryTags.dance":"নাচ","gui.libraryTags.effects":" ইফেক্ট সমূহ","gui.libraryTags.fantasy":" কল্পনা","gui.libraryTags.fashion":"ফ্যাশন","gui.libraryTags.food":"খাবার","gui.libraryTags.indoors":"ইনডোর","gui.libraryTags.loops":"লুপ","gui.libraryTags.music":"সঙ্গীত","gui.libraryTags.notes":"নোট","gui.libraryTags.outdoors":"বাড়ির বাইরে","gui.libraryTags.patterns":"প্যাটার্নস","gui.libraryTags.people":"মানুষ","gui.libraryTags.percussion":"Percussion","gui.libraryTags.space":"Space","gui.libraryTags.sports":"খেলাধুলা","gui.libraryTags.underwater":"পানির নিচে","gui.libraryTags.voice":"শব্দ","gui.libraryTags.wacky":"Wacky","gui.libraryTags.animation":"অ্যানিমেশন","gui.libraryTags.art":"আর্ট ","gui.libraryTags.games":"খেলা","gui.libraryTags.stories":"গল্পগুলো","gui.libraryTags.letters":"অক্ষর","gui.opcodeLabels.direction":"দিক","gui.opcodeLabels.xposition":"x এর অবস্থান","gui.opcodeLabels.yposition":"y এর অবস্থান","gui.opcodeLabels.size":"আকার","gui.opcodeLabels.costumename":"পোশাক এর নাম","gui.opcodeLabels.costumenumber":"পোশাক নম্বর","gui.opcodeLabels.backdropname":"ব্যাকড্রপ এর নাম","gui.opcodeLabels.backdropnumber":"ব্যাকড্রপ নম্বর","gui.opcodeLabels.volume":"শব্দের মাত্রা","gui.opcodeLabels.tempo":"তাল","gui.opcodeLabels.answer":"উত্তর","gui.opcodeLabels.loudness":"শব্দের মাত্রা","gui.opcodeLabels.username":"ইউজারনেম","gui.opcodeLabels.year":"বছর","gui.opcodeLabels.month":"মাস","gui.opcodeLabels.date":"তারিখ","gui.opcodeLabels.dayofweek":"সপ্তাহের দিন","gui.opcodeLabels.hour":"ঘন্টা","gui.opcodeLabels.minute":"মিনিট","gui.opcodeLabels.second":"সেকেন্ড","gui.opcodeLabels.timer":"সময়","gui.sharedMessages.backdrop":"ব্যাকড্রপ{index}","gui.sharedMessages.costume":"পোশাক{index}","gui.sharedMessages.sprite":"স্প্রাইট{index} ","gui.sharedMessages.pop":"পপ","gui.sharedMessages.replaceProjectWarning":"বর্তমান প্রজেক্ট এর কনটেন্ট প্রতিস্থাপন করবে? ","gui.sharedMessages.loadFromComputerTitle":" তোমার কম্পিউটার থেকে লোড কর","boost.color.any":"যেকোন রঙে","boost.color.black":"কালো","boost.color.blue":"নীল","boost.color.green":"সবুজ","boost.color.red":"লাল","boost.color.white":"সাদা","boost.color.yellow":"হলুদ","boost.getMotorPosition":"[MOTOR_REPORTER_ID] মোটরের অবস্থান","boost.getTiltAngle":"টিল্ট কোণ [TILT_DIRECTION]","boost.motorDirection.backward":"ঐ দিকে","boost.motorDirection.forward":"এই দিকে","boost.motorDirection.reverse":"উল্টো দিকে","boost.motorOff":"[MOTOR_ID] মোটরটি বন্ধ কর","boost.motorOn":"[MOTOR_ID] মোটরটি চালু কর","boost.motorOnFor":"[MOTOR_ID] মটরটি [DURATION] সেকেন্ডের জন্যে ঘোরাও","boost.motorOnForRotation":"[MOTOR_ID] মটরটি [ROTATION] বারের জন্যে ঘোরাও ","boost.seeingColor":"[COLOR] রঙের ইট দেখা যাচ্ছে?","boost.setLightHue":"লাইটের রঙ [HUE] কর","boost.setMotorDirection":"[MOTOR_ID] মোটরটি [MOTOR_DIRECTION] দিকে নির্ধারণ কর","boost.setMotorPower":"মোটর [MOTOR_ID] এর গতি [POWER] % নির্ধারণ কর","boost.tiltDirection.any":"যেকোন","boost.tiltDirection.down":"নিচে","boost.tiltDirection.left":"বামে","boost.tiltDirection.right":"ডানে ","boost.tiltDirection.up":"উপরে ","boost.whenColor":"[COLOR] ইট দেখা গেলে","boost.whenTilted":"[TILT_DIRECTION_ANY] কাত হয়ে গেলে","ev3.beepNote":"[TIME] সেকেন্ডের জন্য বীপ নোট [NOTE]","ev3.buttonPressed":"[PORT] বোতামটি চাপ দেয়া? ","ev3.getBrightness":"উজ্জ্বলতা","ev3.getDistance":"দুরত্ব","ev3.getMotorPosition":"মোটর [PORT] এর স্থান","ev3.motorSetPower":"মোটর [PORT] এ শক্তি নির্ধারণ কর [POWER] %","ev3.motorTurnClockwise":"মোটর [PORT] [TIME] সেকেন্ডের জন্য এই পথে ঘুরিয়ে দাও","ev3.motorTurnCounterClockwise":"মোটর [PORT] [TIME] সেকেন্ডের জন্য সে পথে ঘুরিয়ে দাও","ev3.whenBrightnessLessThan":"যখন উজ্জ্বলতা < [DISTANCE]","ev3.whenButtonPressed":"যখন [PORT] বোতামটি চাপা হবে","ev3.whenDistanceLessThan":"যখন দূরত্ব < [DISTANCE]","gdxfor.getAcceleration":"[DIRECTION] গতিবেগ বৃদ্ধি","gdxfor.getForce":"বল","gdxfor.getSpin":"ঘুর্নণ গতি [DIRECTION]","gdxfor.getTilt":"tilt angle [TILT]","gdxfor.isFreeFalling":"পরে যাচ্ছে?","gdxfor.isTilted":"tilted [TILT]?","gdxfor.pulled":"টেনেছে ","gdxfor.pushed":"ধাক্কা দিয়েছে ","gdxfor.shaken":"ঝাঁকান হয়েছে","gdxfor.startedFalling":"পরতে শুরু করেছে","gdxfor.tiltDirectionMenu.any":"যেকোন","gdxfor.tiltDirectionMenu.back":"পিছনে","gdxfor.tiltDirectionMenu.front":"সামনে","gdxfor.tiltDirectionMenu.left":"বামে","gdxfor.tiltDirectionMenu.right":"ডানে ","gdxfor.turnedFaceDown":"নিচের দিকে মুখ কর","gdxfor.turnedFaceUp":" উপরের দিকে মুখ কর","gdxfor.whenForcePushedOrPulled":"যখন ফোর্স সেন্সর [PUSH_PULL]","gdxfor.whenGesture":"যখন [GESTURE]","gdxfor.whenTilted":"when tilted [TILT]","makeymakey.downArrow":"নিম্নমুখী অ্যারো","makeymakey.downArrowShort":"নিচে","makeymakey.leftArrow":"বামমুখী তীরচিহ্ন","makeymakey.leftArrowShort":"বাম","makeymakey.rightArrow":"ডানমুখী অ্যারো","makeymakey.rightArrowShort":"ডানে ","makeymakey.spaceKey":"স্পেস","makeymakey.upArrow":"ঊর্ধ্বমুখী অ্যারো","makeymakey.upArrowShort":"উপরে ","makeymakey.whenKeyPressed":"যখন [KEY] কী চাপা হবে ","makeymakey.whenKeysPressedInOrder":"যখন [SEQUENCE] ক্রমে চাপ দেওয়া হবে","microbit.buttonsMenu.any":"যেকোন","microbit.clearDisplay":"পর্দার সব পরিষ্কার কর","microbit.defaultTextToDisplay":"হ্যালো!","microbit.displaySymbol":"[MATRIX] প্রদর্শন","microbit.displayText":"[TEXT] টেক্সট প্রদর্শন কর","microbit.gesturesMenu.jumped":"লাফ দিয়েছিল","microbit.gesturesMenu.moved":"সরানো হয়েছে","microbit.gesturesMenu.shaken":"ঝাঁকাও","microbit.isButtonPressed":"[BTN] বোতামটি চাপা হয়েছে?","microbit.isTilted":"tilted [DIRECTION]?","microbit.pinStateMenu.off":"বন্ধ","microbit.pinStateMenu.on":"চালু","microbit.tiltAngle":"tilt angle [DIRECTION]","microbit.tiltDirectionMenu.any":"যেকোনো","microbit.tiltDirectionMenu.back":"পিছনে","microbit.tiltDirectionMenu.front":"সামনে","microbit.tiltDirectionMenu.left":"বাম","microbit.tiltDirectionMenu.right":"ডান ","microbit.whenButtonPressed":"যখন [BTN] বোতামটি চাপ দেওয়া থাকবে","microbit.whenGesture":"যখন [GESTURE]","microbit.whenPinConnected":"যখন [PIN] পিনটি সংযুক্ত করা হবে","microbit.whenTilted":"when tilted [DIRECTION]","music.categoryName":"সঙ্গীত","music.changeTempo":"[TEMPO] ব্যবহার করে টেম্পো পরিবর্তন কর","music.drumBass":"(2) বেজ ড্রাম","music.drumBongo":"(13) বংগো","music.drumCabasa":"(15) কাবসা","music.drumClaves":"(9) ক্লেভস ","music.drumClosedHiHat":"(6) হাই-হ্যাট বন্ধ","music.drumConga":"(14) কঙ্গা","music.drumCowbell":"(11) গরুর গলার ঘণ্টা","music.drumCrashCymbal":" (4) ক্র্যাশ সিম্বল","music.drumCuica":"(18) কুইকা","music.drumGuiro":"(16) গাইরো","music.drumHandClap":"(8) হাত তালি","music.drumOpenHiHat":"(5) হাই-হ্যাট খোল","music.drumSideStick":"(3) সাইড স্টিক","music.drumSnare":"(1) স্নেয়ার ড্রাম","music.drumTambourine":"(7) ট্যামবোরিন","music.drumTriangle":"(12) ত্রিভুজ","music.drumVibraslap":"(17) ভাইরাসল্যাপ","music.drumWoodBlock":"(10) কাঠের ব্লক","music.getTempo":"তাল","music.instrumentBass":"(6) বেজ ","music.instrumentBassoon":"(14) ব্যাসোন","music.instrumentCello":"(8) সেলো","music.instrumentChoir":"(15) গায়কদল","music.instrumentClarinet":"(10) ক্লারিনেট","music.instrumentElectricGuitar":"(5) বৈদ্যুতিক গিটার","music.instrumentElectricPiano":"(2) বৈদ্যুতিক পিয়ানো","music.instrumentFlute":"(12) বাঁশি","music.instrumentGuitar":"(4) গিটার","music.instrumentMarimba":"(19) ম্যারিম্বা","music.instrumentMusicBox":"(17) সঙ্গীত বাক্স","music.instrumentOrgan":"(3) অর্গ্যান","music.instrumentPiano":"(1) পিয়ানো ","music.instrumentPizzicato":"(7) পিজ্জাটো","music.instrumentSaxophone":"(11) স্যাক্সোফোন","music.instrumentSteelDrum":"(18) ইস্পাতের ড্রাম","music.instrumentSynthLead":"(20) সিন্থ লিড","music.instrumentSynthPad":"(21) সিন্থ প্যাড","music.instrumentTrombone":"(9) ট্রমবন","music.instrumentVibraphone":"(16) ভাইব্রাফোন","music.instrumentWoodenFlute":"(13) কাঠের বাঁশি","music.midiPlayDrumForBeats":"[BEATS] বিটের জন্য ড্রাম [DRUM] বাজাও","music.midiSetInstrument":"[INSTRUMENT] বাদ্যযন্ত্রটি নির্ধারণ কর।","music.playDrumForBeats":"[BEATS] বিটে [DRUM] ড্রাম বাজাও ","music.playNoteForBeats":"[BEATS] বিটের জন্য [NOTE] নোট চালু কর","music.restForBeats":"[BEATS] বিটের জন্য অপেক্ষা","music.setInstrument":"[INSTRUMENT] বাদ্যযন্ত্রটি নির্ধারণ কর","music.setTempo":"টেম্পো [TEMPO] নির্ধারণ কর","pen.categoryName":"কলম","pen.changeColorParam":"কলমের [COLOR_PARAM] [VALUE] দ্বারা পরিবর্তন কর","pen.changeHue":"কলমের রঙ [HUE] দ্বারা পরিবর্তন","pen.changeShade":" কলমের ছায়া [SHADE] দ্বারা পরিবর্তন কর","pen.changeSize":"কলমের আকার [SIZE] তে পরিবর্তন কর","pen.clear":"সব মুছে ফেল","pen.colorMenu.brightness":"উজ্জ্বলতা","pen.colorMenu.color":"রঙ","pen.colorMenu.saturation":"saturation","pen.colorMenu.transparency":"স্বচ্ছতা","pen.penDown":"কলম নিচে নামাও","pen.penUp":"কলম উপরে উঠাও","pen.setColor":"কলমের রঙ [COLOR] নির্ধারণ কর","pen.setColorParam":"কলমের [COLOR_PARAM] [VALUE] এ নির্ধারণ কর","pen.setHue":"কলমের রঙ [HUE] এ নির্ধারণ কর","pen.setShade":"কলমের ছায়া [SHADE] নির্ধারণ কর","pen.setSize":"কলমের আকার [SIZE] নির্ধারণ কর","pen.stamp":"স্ট্যাম্প","text2speech.alto":"alto","text2speech.categoryName":"টেক্সট টু স্পিচ","text2speech.defaultTextToSpeak":"hello","text2speech.giant":"দানব","text2speech.kitten":"বিড়ালছানা","text2speech.setLanguageBlock":" [LANGUAGE] এ ভাষা নির্ধারণ কর","text2speech.setVoiceBlock":"[VOICE] ভয়েস নির্ধারণ কর","text2speech.speakAndWaitBlock":"বল [WORDS]","text2speech.squeak":"চিৎকার","text2speech.tenor":"tenor","translate.categoryName":"অনুবাদ","translate.defaultTextToTranslate":"hello","translate.translateBlock":"[WORDS] [LANGUAGE] ভাষায় অনুবাদ কর ","translate.viewerLanguage":"ভাষা","videoSensing.categoryName":"ভিডিও অনুমান","videoSensing.direction":"দিক","videoSensing.motion":"গতি","videoSensing.off":"বন্ধ","videoSensing.on":"চালু","videoSensing.onFlipped":"উল্টানো থাকলে ","videoSensing.setVideoTransparency":"ভিডিওর স্বচ্ছতা [TRANSPARENCY] নির্ধারণ কর","videoSensing.sprite":"স্প্রাইট","videoSensing.stage":"মঞ্চ","videoSensing.videoOn":"[SUBJECT] এর উপর ভিডিও [ATTRIBUTE]","videoSensing.videoToggle":"ভিডিও [VIDEO_STATE] ঘুরাও","videoSensing.whenMotionGreaterThan":"যখন ভিডিওর গতি > [REFERENCE]","wedo2.getDistance":"দুরত্ব","wedo2.getTiltAngle":"tilt angle [TILT_DIRECTION]","wedo2.isTilted":"tilted [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"ঐ দিকে","wedo2.motorDirection.forward":"এই পথে","wedo2.motorDirection.reverse":"বিপরীত","wedo2.motorId.a":"মোটর A","wedo2.motorId.all":"সব মোটরগুলো","wedo2.motorId.b":"মোটর B","wedo2.motorId.default":"মোটর ","wedo2.motorOff":"[MOTOR_ID] বন্ধ কর","wedo2.motorOn":"[MOTOR_ID] চালু কর","wedo2.motorOnFor":"[DURATION] সেকেন্ডের জন্য [MOTOR_ID] চালু কর","wedo2.playNoteFor":"[DURATION] সেকেন্ডের জন্য নোটটি [NOTE] বাজাও","wedo2.setLightHue":"লাইটের রঙ [HUE] নির্ধারণ কর","wedo2.setMotorDirection":"[MOTOR_DIRECTION] এ [MOTOR_ID] এর দিক নির্ধারণ কর","wedo2.startMotorPower":"[MOTOR_ID] শক্তি [POWER] নির্ধারণ কর","wedo2.tiltDirection.any":"যেকোন","wedo2.tiltDirection.down":"নিচে","wedo2.tiltDirection.left":"বাম","wedo2.tiltDirection.right":"ডানে ","wedo2.tiltDirection.up":"উপরে ","wedo2.whenDistance":"যখন দূরুত্ব [OP] [REFERENCE]","wedo2.whenTilted":"when tilted [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"রঙ","paint.paintEditor.saturation":"সম্পৃক্ত","paint.paintEditor.brightness":"উজ্জ্বলতা","paint.paintEditor.costume":"পোশাক","paint.paintEditor.group":"দল","paint.paintEditor.ungroup":"দলমুক্ত","paint.paintEditor.undo":"পূর্বাবস্থায় ফেরত","paint.paintEditor.redo":"পুনরায় কর","paint.paintEditor.forward":"সামনে","paint.paintEditor.backward":"পিছনে","paint.paintEditor.front":"সামনে","paint.paintEditor.back":"পিছনে","paint.paintEditor.more":"আরও","paint.modeTools.brushSize":"আকার","paint.modeTools.eraserSize":"রবারের আকার","paint.modeTools.copy":"কপি","paint.modeTools.paste":"পেস্ট","paint.modeTools.delete":"অপসারণ","paint.modeTools.curved":"বাঁকা","paint.modeTools.pointed":"তীক্ষ্ন","paint.modeTools.thickness":"পুরুত্ব","paint.modeTools.flipHorizontal":"হরিজেন্টালি উল্টাও ","paint.modeTools.flipVertical":"ভার্টিক্যালি উল্টাও","paint.modeTools.filled":"ভরাট করা","paint.modeTools.outlined":"আউটলাইন","paint.paintEditor.bitmap":"বিটম্যাপে রূপান্তর কর","paint.paintEditor.vector":"ভেক্টরে রূপান্তর কর ","paint.paintEditor.fill":"পূরণ","paint.paintEditor.stroke":"আউটলাইন","paint.brushMode.brush":"তুলি","paint.eraserMode.eraser":"রবার","paint.fillMode.fill":"ভরাট","paint.lineMode.line":"রেখা","paint.ovalMode.oval":"বৃত্তাকার","paint.rectMode.rect":"আয়তক্ষেত্র","paint.reshapeMode.reshape":"পুনর্গঠন","paint.roundedRectMode.roundedRect":"গোলাকার আয়তক্ষেত্র","paint.selectMode.select":"নির্বাচন কর","paint.textMode.text":"পাঠ","paint.colorPicker.swap":"বিনিময়"},"be":{"gui.alerts.tryAgain":"Паспрабуйце яшчэ","gui.alerts.download":"Спампаваць","gui.connection.reconnect":"Перападлучыцца","gui.backpack.costumeLabel":"касцюм","gui.backpack.soundLabel":"гук","gui.backpack.scriptLabel":"скрыпт","gui.backpack.spriteLabel":"спрайт","gui.backpack.header":"Заплечнік","gui.backpack.errorBackpack":"Памылка пры загрузцы заплечніка","gui.backpack.loadingBackpack":"Загрузка...","gui.backpack.more":"Яшчэ","gui.backpack.emptyBackpack":"Заплечнік пусты","gui.unsupportedBrowser.label":"Браўзер не падтрымліваецца","gui.cards.all-tutorials":"Падручнікі","gui.cards.shrink":"Сціснуць","gui.cards.expand":"Разгарнуць","gui.cards.close":"Закрыць","gui.cards.more-things-to-try":"Дадатковыя магчымасці!","gui.cards.see-more":"Даведацца больш","gui.comingSoon.message1":"Не хвалюйцеся, мы працуем над гэтым {emoji}","gui.comingSoon.message2":"У бліжэйшы час...","gui.comingSoon.message3":"Мы працуем над гэтым {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Прылады не знойдзены","gui.connection.auto-scanning.prescan":"Размясціце вашу прыладу паблізу і пачніце пошук.","gui.connection.auto-scanning.pressbutton":"Націсніце кнопку на вашай прыладзе.","gui.connection.auto-scanning.start-search":"Пачаць пошук","gui.connection.connecting-searchbutton":"Пошук...","gui.connection.auto-scanning.try-again":"Паспрабуйце яшчэ","gui.connection.connected":"Злучана","gui.connection.disconnect":"Адлучыць","gui.connection.go-to-editor":"Перайсці да рэдактара","gui.connection.connecting-cancelbutton":"Злучэнне...","gui.connection.error.errorMessage":"Ой! Здаецца, штосьці пайшло не так.","gui.connection.error.tryagainbutton":"Паспрабуйце яшчэ","gui.connection.error.helpbutton":"Даведка","gui.connection.peripheral-name-label":"Назва прылады","gui.connection.connect":"Злучыць","gui.connection.scanning.lookingforperipherals":"Ідзе пошук прылад","gui.connection.scanning.noPeripheralsFound":"Прылады не знойдзены","gui.connection.scanning.instructions":"Выберыце сваю прыладу са спіса","gui.connection.search":"Абнавіць","gui.connection.unavailable.installscratchlink":"Пераканайцеся ў тым, што вы ўсталявалі і запусцілі Scratсh Link","gui.connection.unavailable.enablebluetooth":"Праверце, ці ўключаны Bluetooth","gui.connection.unavailable.tryagainbutton":"Паспрабуйце яшчэ","gui.connection.unavailable.helpbutton":"Даведка","gui.controls.go":"Выканаць","gui.controls.stop":"Спыніць","gui.crashMessage.label":"Ой! Штосьці пайшло не так.","gui.crashMessage.errorNumber":"Ваша памылка зарэгістраваная з ідэнтыфікатарам {errorId}","gui.crashMessage.reload":"Перазагрузіць","gui.customProcedures.myblockModalTitle":"Стварыць блок","gui.customProcedures.addAnInputNumberText":"Дадаць значэнне","gui.customProcedures.numberTextType":"лічба або тэкст","gui.customProcedures.addAnInputBoolean":"Дадаць значэнне","gui.customProcedures.booleanType":"лагічны","gui.customProcedures.addALabel":"Дадаць подпіс","gui.customProcedures.runWithoutScreenRefresh":"Выканаць без аднаўлення экрану","gui.customProcedures.cancel":"Скасаваць","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Кірунак","gui.directionPicker.rotationStyles.allAround":"Кругом","gui.directionPicker.rotationStyles.leftRight":"Налева/Направа","gui.directionPicker.rotationStyles.dontRotate":"Не круціць","gui.gui.addExtension":"Дадаць пашырэнне","gui.gui.codeTab":"Код","gui.gui.backdropsTab":"Фоны","gui.gui.costumesTab":"Касцюмы","gui.gui.soundsTab":"Гукі","gui.extensionLibrary.comingSoon":"У бліжэйшы час...","gui.extensionLibrary.requires":"Патрабуюцца","gui.extensionLibrary.collaboration":"У супрацоўніцтве","gui.library.filterPlaceholder":"Шукаць","gui.library.allTag":"Усе","gui.loader.headline":"Загрузка праекта","gui.loader.creating":"Стварыць праект","gui.authorInfo.byUser":"ад {username}","gui.menuBar.seeProjectPage":"Старонка праекта","gui.menuBar.LanguageSelector":"выбар мовы","gui.menuBar.tutorialsLibrary":"Падручнікі","gui.menuBar.restoreSprite":"Аднавіць спрайт","gui.menuBar.restoreSound":"Аднавіць гук","gui.menuBar.restoreCostume":"Аднавіць касцюм","gui.menuBar.restore":"Аднавіць","gui.menuBar.saveNow":"Захаваць","gui.menuBar.saveAsCopy":"Захаваць як копію","gui.menuBar.remix":"Рэмікс","gui.menuBar.new":"Новы","gui.menuBar.file":"Файл","gui.menuBar.downloadToComputer":"Захаваць на свой камп\'ютар","gui.menuBar.edit":"Змяніць","gui.menuBar.turboModeOff":"Выключыць Турба рэжым","gui.menuBar.turboModeOn":"Уключыць Турба рэжым","gui.gui.projectTitlePlaceholder":"Назва праекта","gui.menuBar.isShared":"Апублікаваны","gui.menuBar.share":"Апублікаваць","gui.modal.help":"Даведка","gui.modal.back":"Назад","gui.monitor.listMonitor.empty":"(пусты)","gui.monitor.listMonitor.listLength":"даўжыня {length}","gui.monitor.contextMenu.default":"звычайны выгляд","gui.monitor.contextMenu.large":"павялічаны выгляд","gui.monitor.contextMenu.slider":"паўзунок","gui.monitor.contextMenu.sliderRange":"змяніць дыяпазон паўзунка","gui.monitor.contextMenu.import":"імпарт","gui.monitor.contextMenu.export":"экспарт","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Іграць","gui.playButton.stop":"Спыніць","gui.gui.variableScopeOptionAllSprites":"Для ўсіх спрайтаў","gui.gui.variableScopeOptionSpriteOnly":"Толькі для гэтага спрайта","gui.gui.cloudVariableOption":"Воблачная зменная (захоўваецца на серверы)","gui.gui.variablePromptAllSpritesMessage":"Гэтая зменная будзе даступна для ўсіх спрайтаў.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Скасаваць","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Спыніць","gui.playbackStep.playMsg":"Іграць","gui.playbackStep.loadingMsg":"Загрузка...","gui.playbackStep.saveMsg":"Захаваць","gui.playbackStep.reRecordMsg":"Перазапісаць","gui.recordModal.title":"Запісаць гук","gui.recordingStep.beginRecord":"Пачаць запіс, націснуўшы кнопку ніжэй","gui.recordingStep.permission":"{arrow}Нам патрэбен ваш дазвол для доступу да мікрафона","gui.recordingStep.stop":"Спыніць запіс","gui.recordingStep.record":"Запісаць","gui.sliderModal.min":"Мінімальнае значэнне","gui.sliderModal.max":"Максімальнае значэнне","gui.sliderModal.title":"Змяніць дыяпазон паўзунка","gui.sliderPrompt.cancel":"Скасаваць","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Гук","gui.soundEditor.play":"Іграць","gui.soundEditor.stop":"Спыніць","gui.soundEditor.copy":"Капіраваць","gui.soundEditor.paste":"Уставіць","gui.soundEditor.copyToNew":"Капіраваць у новы","gui.soundEditor.delete":"Выдаліць","gui.soundEditor.save":"Захаваць","gui.soundEditor.undo":"Адмяніць","gui.soundEditor.redo":"Вярнуць","gui.soundEditor.faster":"Хутчэй","gui.soundEditor.slower":"Павольней","gui.soundEditor.echo":"Рэха","gui.soundEditor.robot":"Робат","gui.soundEditor.louder":"Гучней","gui.soundEditor.softer":"Цішэй","gui.soundEditor.reverse":"У адваротным парадку","gui.soundEditor.fadeOut":"Паступовае знікненне","gui.soundEditor.fadeIn":"Паступовае ўзмацненне","gui.soundEditor.mute":"Выкл гук","gui.SpriteInfo.spritePlaceholder":"Імя","gui.SpriteInfo.sprite":"Спрайт","gui.SpriteInfo.show":"Паказаць","gui.SpriteInfo.size":"Памер","gui.spriteSelectorItem.contextMenuDuplicate":"падвоіць","gui.spriteSelectorItem.contextMenuExport":"экспарт","gui.spriteSelectorItem.contextMenuDelete":"выдаліць","gui.spriteSelector.addSpriteFromLibrary":"Выбраць спрайт","gui.spriteSelector.addSpriteFromPaint":"Намаляваць","gui.spriteSelector.addSpriteFromSurprise":"Сюрпрыз","gui.spriteSelector.addSpriteFromFile":"Загрузіць спрайт","gui.stageHeader.stageSizeLarge":"Пераключыцца на вялікую сцэну","gui.stageHeader.stageSizeSmall":"Пераключыцца на маленькую сцэну","gui.stageHeader.stageSizeFull":"Поўнаэкранны рэжым","gui.stageHeader.stageSizeUnFull":"Выхад з поўнаэкраннага рэжыму","gui.stageHeader.fullscreenControl":"Поўнаэкранны рэжым","gui.spriteSelector.addBackdropFromLibrary":"Выбраць фон","gui.stageSelector.addBackdropFromPaint":"Намаляваць","gui.stageSelector.addBackdropFromSurprise":"Сюрпрыз","gui.stageSelector.addBackdropFromFile":"Загрузіць фон","gui.stageSelector.stage":"Сцэна","gui.stageSelector.backdrops":"Фоны","gui.telemetryOptIn.label":"Адправіць статыстыку, каб палепшыць Scratch","gui.telemetryOptIn.body1":"Каманда Scratch заўсёды імкнецца вывучаць, як Scratch выкарыстоўваецца ва ўсім сьвеце. Каб дапамагчы нам, калі ласка, дазвольце Scratch аўтаматычна дасылаць нам інфармацыю аб яго выкарыстанні","gui.telemetryOptIn.body2":"Інфармацыя, якую мы збіраем, датычыцца моўнага выбару, выкарыстання блокаў, а таксама захавання, пампавання і загрузкі праектаў. Мы НЕ збіраем асабістую інфармацыю. Каб даведацца больш, калі ласка, звяртайцеся да нашае {privacyPolicyLink}.","gui.telemetryOptIn.privacyPolicyLink":"Палітыка канфідэнцыяльнасці","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Рэжым турба","gui.webglModal.label":"Ваш браўзер не падтрымлівае WebGL","gui.webglModal.webgllink":"не падтрымлівае WebGL","gui.costumeLibrary.chooseABackdrop":"Выбраць фон","gui.costumeLibrary.chooseACostume":"Выбраць касцюм","gui.costumeTab.addBackdropFromLibrary":"Выбраць фон","gui.costumeTab.addCostumeFromLibrary":"Выбраць касцюм","gui.costumeTab.addBlankCostume":"Намаляваць","gui.costumeTab.addSurpriseCostume":"Сюрпрыз","gui.costumeTab.addFileBackdrop":"Загрузіць фон","gui.costumeTab.addFileCostume":"Загрузіць касцюм","gui.extensionLibrary.chooseAnExtension":"Выбраць пашырэнне","gui.extensionLibrary.extensionUrl":"Увядзіце URL пашырэння","gui.monitors.importListColumnPrompt":"Якая калонка павінна быць выкарыстана (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Немагчыма пачаць запіс","gui.soundLibrary.chooseASound":"Выбраць гук","gui.soundTab.fileUploadSound":"Загрузіць гук","gui.soundTab.surpriseSound":"Сюрпрыз","gui.soundTab.recordSound":"Запісаць","gui.soundTab.addSoundFromLibrary":"Выбраць гук","gui.spriteLibrary.chooseASprite":"Выбраць спрайт","gui.tipsLibrary.tutorials":"Выбраць падручнік","gui.alerts.createsuccess":"Новы праект створаны.","gui.alerts.createcopysuccess":"Праект захаваны як копія.","gui.alerts.createremixsuccess":"Праект захаваны як рэмікс.","gui.alerts.creating":"Стварэнне новага...","gui.alerts.creatingCopy":"Капіраванне праекта...","gui.alerts.creatingRemix":"Рэмікс праекта...","gui.alerts.creatingError":"Немагчыма стварыць праект. Паспрабуйце яшчэ раз!","gui.alerts.savingError":"Праект не можа быць захаваны.","gui.alerts.savesuccess":"Праект захаваны.","gui.alerts.saving":"Захаванне праекта...","gui.alerts.cloudInfo":"Воблачныя зменныя могуць быць толькі лічбамі, а не літарамі ці знакамі. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Даведацца больш.","gui.alerts.importing":"Імпарт...","gui.defaultProject.variable":"мая зменная","gui.extension.music.name":"Музыка","gui.extension.music.description":"Граць на музычных інструментах і барабанах","gui.extension.pen.name":"Аловак","gui.extension.pen.description":"Draw with your sprites.","gui.extension.videosensing.name":"Відэадатчыкі","gui.extension.videosensing.description":"Заўважыць рух з дапамогай камеры","gui.extension.text2speech.name":"пераўтварыць Тэкст у Маўленне","gui.extension.text2speech.description":"Навучыць вашыя праекты размаўляць","gui.extension.translate.name":"Перакладчык","gui.extension.translate.description":"Перакладаць тэксты на іншыя мовы.","gui.extension.makeymakey.description":"Make anything into a key.","gui.extension.microbit.description":"Злучыць вашыя праекты з усім светам","gui.extension.microbit.connectingMessage":"Злучыць","gui.extension.ev3.description":"Build interactive robots and more.","gui.extension.ev3.connectingMessage":"Злучэнне. Праверце, каб pin нумар на вашым EV3 быў усталяваны на 1234.","gui.extension.boost.description":"Ажывіце робататэхнічныя мадэлі.","gui.extension.boost.connectingMessage":"Злучыць","gui.extension.wedo2.description":"Працаваць з рухавікамі і датчыкамі.","gui.extension.wedo2.connectingMessage":"Connecting","gui.extension.gdxfor.description":"Sense push, pull, motion, and spin.","gui.extension.gdxfor.connectingMessage":"Злучыць","gui.libraryTags.all":"Усе","gui.libraryTags.animals":"Жывёлы","gui.libraryTags.dance":"Танцы","gui.libraryTags.effects":"Эфекты","gui.libraryTags.fantasy":"Фэнтэзі","gui.libraryTags.fashion":"Мода","gui.libraryTags.food":"Ежа","gui.libraryTags.indoors":"У памяшканні","gui.libraryTags.loops":"Цыклы","gui.libraryTags.music":"Музыка","gui.libraryTags.notes":"Музычныя ноты","gui.libraryTags.outdoors":"На вольным паветры","gui.libraryTags.patterns":"Узоры","gui.libraryTags.people":"Людзі","gui.libraryTags.percussion":"Перкусія","gui.libraryTags.space":"Космас","gui.libraryTags.sports":"Спорт","gui.libraryTags.underwater":"Падводны свет","gui.libraryTags.voice":"Голас","gui.libraryTags.wacky":"Дурнаваты","gui.libraryTags.animation":"Анімацыя","gui.libraryTags.art":"Мастацтва","gui.libraryTags.games":"Гульні","gui.libraryTags.stories":"Гісторыі","gui.libraryTags.letters":"Літары","gui.opcodeLabels.direction":"кірунак","gui.opcodeLabels.xposition":"пазіцыя X","gui.opcodeLabels.yposition":"пазіцыя Y","gui.opcodeLabels.size":"памер","gui.opcodeLabels.costumename":"імя касцюма","gui.opcodeLabels.costumenumber":"нумар касцюма","gui.opcodeLabels.backdropname":"імя фону","gui.opcodeLabels.backdropnumber":"нумар фону","gui.opcodeLabels.volume":"гучнасць","gui.opcodeLabels.tempo":"тэмп","gui.opcodeLabels.answer":"адказ","gui.opcodeLabels.loudness":"гучнасць","gui.opcodeLabels.username":"імя карыстальніка","gui.opcodeLabels.year":"год","gui.opcodeLabels.month":"месяц","gui.opcodeLabels.date":"дата","gui.opcodeLabels.dayofweek":"дзень тыдня","gui.opcodeLabels.hour":"гадзіна","gui.opcodeLabels.minute":"хвіліна","gui.opcodeLabels.second":"секунда","gui.opcodeLabels.timer":"таймер","gui.sharedMessages.backdrop":"фон {index}","gui.sharedMessages.costume":"касцюм {index}","gui.sharedMessages.sprite":"Спрайт {index}","gui.sharedMessages.pop":"поп","gui.sharedMessages.replaceProjectWarning":"Замяніць змесціва гэтага праекта?","gui.sharedMessages.loadFromComputerTitle":"Загрузіць з камп\'ютара","boost.color.any":"любы колер","boost.color.black":"чорны","boost.color.blue":"сіні","boost.color.green":"зялёны","boost.color.red":"чырвоны","boost.color.white":"белы","boost.color.yellow":"жоўты","boost.getMotorPosition":"пазіцыя рухавіка [MOTOR_REPORTER_ID]","boost.getTiltAngle":"вугал нахілу [TILT_DIRECTION]","boost.motorDirection.backward":"супраць гадзіннікавай стэлкі","boost.motorDirection.forward":"па гадзіннікавай стрэлцы","boost.motorDirection.reverse":"у адваротны бок","boost.motorOff":"выключыць рухавік [MOTOR_ID]","boost.motorOn":"уключыць рухавік [MOTOR_ID]","boost.motorOnFor":"уключыць рухавік [MOTOR_ID] на [DURATION] секунд","boost.motorOnForRotation":"уключыць рухавік [MOTOR_ID] на [ROTATION] абаротаў","boost.seeingColor":"seeing [COLOR] brick?","boost.setLightHue":"устанавіць колер святла [HUE]","boost.setMotorDirection":"устанавіць напрамак [MOTOR_DIRECTION] для рухавіка [MOTOR_ID]","boost.setMotorPower":"устанавіць рухавіку [MOTOR_ID] хуткасць [POWER] %","boost.tiltDirection.any":"як-небудзь","boost.tiltDirection.down":"уніз","boost.tiltDirection.left":"налева","boost.tiltDirection.right":"направа","boost.tiltDirection.up":"уверх","boost.whenColor":"when [COLOR] brick seen","boost.whenTilted":"калі нахілены [TILT_DIRECTION_ANY]","ev3.beepNote":"іграць ноту [NOTE]на працягу [TIME] секунд","ev3.buttonPressed":"кнопка [PORT] націснутая?","ev3.getBrightness":"яркасць","ev3.getDistance":"адлегласць","ev3.getMotorPosition":"пазіцыя рухавіка [PORT]","ev3.motorSetPower":"рухавіку [PORT] устанавіць магутнасць [POWER] % ","ev3.motorTurnClockwise":"рухавік [PORT]павярнуць па гадзіннікавай стрэлцы на [TIME] секундаў ","ev3.motorTurnCounterClockwise":"рухавік [PORT] павярнуць супраць гадзіннікавай стрэлкі на [TIME] секундаў ","ev3.whenBrightnessLessThan":"калі яркасць < [DISTANCE]","ev3.whenButtonPressed":"калі кнопка [PORT] націснутая","ev3.whenDistanceLessThan":"калі адлегласць < [DISTANCE]","gdxfor.getAcceleration":"паскарэнне [DIRECTION]","gdxfor.getForce":"сіла","gdxfor.getSpin":"хуткасць кручэння[DIRECTION]","gdxfor.getTilt":"вугал нахілу [TILT]","gdxfor.isFreeFalling":"падае?","gdxfor.isTilted":"нахілены [TILT]?","gdxfor.pulled":"пацягнуць","gdxfor.pushed":"націснуць","gdxfor.shaken":"патрэсці","gdxfor.startedFalling":"пачаў падаць","gdxfor.tiltDirectionMenu.any":"любы","gdxfor.tiltDirectionMenu.back":"назад","gdxfor.tiltDirectionMenu.front":"наперад","gdxfor.tiltDirectionMenu.left":"налева","gdxfor.tiltDirectionMenu.right":"направа","gdxfor.turnedFaceDown":"павярнуўся тварам уніз","gdxfor.turnedFaceUp":"павярнуўся тварам уверх","gdxfor.whenForcePushedOrPulled":"калі сэнсар сілы [PUSH_PULL]","gdxfor.whenGesture":"калі [GESTURE]","gdxfor.whenTilted":"калі нахілены [TILT]","makeymakey.downArrow":"стрэлка ўніз","makeymakey.downArrowShort":"уніз","makeymakey.leftArrow":"стрэлка налева","makeymakey.leftArrowShort":"налева","makeymakey.rightArrow":"стрэлка направа","makeymakey.rightArrowShort":"направа","makeymakey.spaceKey":"прабел","makeymakey.upArrow":"стрэлка ўверх","makeymakey.upArrowShort":"уверх","makeymakey.whenKeyPressed":"калі клавіша [KEY] націснутая","makeymakey.whenKeysPressedInOrder":"калі націснутыя [SEQUENCE] па парадку","microbit.buttonsMenu.any":"любы","microbit.clearDisplay":"ачысціць дісплэй","microbit.defaultTextToDisplay":"Вітаю!","microbit.displaySymbol":"паказаць [MATRIX]","microbit.displayText":"паказаць тэкст [TEXT]","microbit.gesturesMenu.jumped":"падкінуць","microbit.gesturesMenu.moved":"зрушыць","microbit.gesturesMenu.shaken":"патрэсці","microbit.isButtonPressed":"[BTN]кнопка націснутая? ","microbit.isTilted":"нахілены [DIRECTION]?","microbit.pinStateMenu.off":"выкл","microbit.pinStateMenu.on":"укл","microbit.tiltAngle":"вугал нахілу [DIRECTION]","microbit.tiltDirectionMenu.any":"любы","microbit.tiltDirectionMenu.back":"назад","microbit.tiltDirectionMenu.front":"наперад","microbit.tiltDirectionMenu.left":"налева","microbit.tiltDirectionMenu.right":"направа","microbit.whenButtonPressed":"калі [BTN] кнопка націснутая","microbit.whenGesture":"калі [GESTURE]","microbit.whenPinConnected":"калі падлучаны pin [PIN]","microbit.whenTilted":"калі нахілены [DIRECTION]","music.categoryName":"Музыка","music.changeTempo":"змяніць тэмп на [TEMPO]","music.drumBass":"(2) Турэцкі барабан","music.drumBongo":"(13) Бонга","music.drumCabasa":"(15) Кабаса","music.drumClaves":"(9) Клавесін","music.drumClosedHiHat":"(6) Закрытыя талеркі","music.drumConga":"(14) Конга","music.drumCowbell":"(11) Званочак","music.drumCrashCymbal":"(4) Крэш-талерка","music.drumCuica":"(18) Куіка","music.drumGuiro":"(16) Гуіра","music.drumHandClap":"(8) Пляскат далоняў","music.drumOpenHiHat":"(5) Адкрытыя талеркі","music.drumSideStick":"(3) Удар па барабану збоку","music.drumSnare":"(1) Малы барабан","music.drumTambourine":"(7) Тамбурын","music.drumTriangle":"(12) Трохвугольнік","music.drumVibraslap":"(17) Вібраслэп","music.drumWoodBlock":"(10) Драўляная скрыначка","music.getTempo":"тэмп","music.instrumentBass":"(6) Бас","music.instrumentBassoon":"(14) Фагот","music.instrumentCello":"(8) Віяланчэль","music.instrumentChoir":"(15) Хор","music.instrumentClarinet":"(10) Кларнет","music.instrumentElectricGuitar":"(5) Электрагітара","music.instrumentElectricPiano":"(2) Лічбавае піяніна","music.instrumentFlute":"(12) Флейта","music.instrumentGuitar":"(4) Гітара","music.instrumentMarimba":"(19) Марымба","music.instrumentMusicBox":"(17) Музычная скрынка","music.instrumentOrgan":"(3) Арган","music.instrumentPiano":"(1) Піяніна","music.instrumentPizzicato":"(7) Піцыката","music.instrumentSaxophone":"(11) Саксафон","music.instrumentSteelDrum":"(18) Стальны барабан","music.instrumentSynthLead":"(20) Вядучы сінтэзатар","music.instrumentSynthPad":"(21) Сінтэзатар Pad","music.instrumentTrombone":"(9) Трамбон","music.instrumentVibraphone":"(16) Вібрафон","music.instrumentWoodenFlute":"(13) Драўляная флейта","music.midiPlayDrumForBeats":"барабану [DRUM]іграць [BEATS] тактаў","music.midiSetInstrument":"выбраць інструмент [INSTRUMENT]","music.playDrumForBeats":"барабану [DRUM]іграць [BEATS] тактаў","music.playNoteForBeats":"іграць ноту [NOTE] [BEATS] тактаў","music.restForBeats":"пачакаць [BEATS] тактаў","music.setInstrument":"выбраць інструмент [INSTRUMENT]","music.setTempo":"устанавіць тэмп [TEMPO]","pen.categoryName":"Аловак","pen.changeColorParam":"змяніць [COLOR_PARAM] алоўка на [VALUE]","pen.changeHue":"змяніць колер алоўка на [HUE]","pen.changeShade":"змяніць цень алоўка на [SHADE]","pen.changeSize":"змяніць памер алоўка на [SIZE]","pen.clear":"сцерці ўсё","pen.colorMenu.brightness":"яркасць","pen.colorMenu.color":"колер","pen.colorMenu.saturation":"насычанасць","pen.colorMenu.transparency":"празрыстасць","pen.penDown":"апусціць аловак","pen.penUp":"падняць аловак","pen.setColor":"устанавіць колер алоўка [COLOR]","pen.setColorParam":"устанавіць [COLOR_PARAM] алоўка [VALUE]","pen.setHue":"устанавіць колер алоўка [HUE]","pen.setShade":"устанавіць цень алоўка [SHADE]","pen.setSize":"устанавіць памер алоўка [SIZE]","pen.stamp":"штамп","text2speech.alto":"альт","text2speech.categoryName":"пераўтварыць Тэкст у Маўленне","text2speech.defaultTextToSpeak":"вітаю","text2speech.giant":"гігант","text2speech.kitten":"кацяня","text2speech.setLanguageBlock":"устанавіць мову [LANGUAGE]","text2speech.setVoiceBlock":"устанавіць голас [VOICE]","text2speech.speakAndWaitBlock":"сказаць [WORDS]","text2speech.squeak":"піск","text2speech.tenor":"тэнар","translate.categoryName":"Перакладчык","translate.defaultTextToTranslate":"вітаю","translate.translateBlock":"перакласці [WORDS] на [LANGUAGE]","translate.viewerLanguage":"мова","videoSensing.categoryName":"Відэадатчыкі","videoSensing.direction":"кірунак","videoSensing.motion":"рух","videoSensing.off":"выключыць","videoSensing.on":"уключыць","videoSensing.onFlipped":"у адваротны бок","videoSensing.setVideoTransparency":"устанавіць празрыстасць відэа [TRANSPARENCY]","videoSensing.sprite":"спрайт","videoSensing.stage":"сцэна","videoSensing.videoOn":"відэа [ATTRIBUTE] на [SUBJECT]","videoSensing.videoToggle":"запіс відэа [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"калі рухаў відэа > [REFERENCE]","wedo2.getDistance":"адлегласць","wedo2.getTiltAngle":"вугал нахілу [TILT_DIRECTION]","wedo2.isTilted":"нахілены [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"супраць гадзіннікавай стэлкі","wedo2.motorDirection.forward":"па гадзіннікавай стрэлцы","wedo2.motorDirection.reverse":"у адваротны бок","wedo2.motorId.a":"рухавік А","wedo2.motorId.all":"усе рухавікі","wedo2.motorId.b":"рукавік В","wedo2.motorId.default":"рухавік","wedo2.motorOff":"выключыць [MOTOR_ID]","wedo2.motorOn":"уключыць [MOTOR_ID]","wedo2.motorOnFor":"уключыць [MOTOR_ID] на [DURATION] секунд","wedo2.playNoteFor":"іграць ноту [NOTE] на працягу [DURATION] секунд","wedo2.setLightHue":"устанавіць колер святла [HUE]","wedo2.setMotorDirection":"устанавіць напрамак [MOTOR_ID] як [MOTOR_DIRECTION]","wedo2.startMotorPower":"устанавіць магутнасць рухавіку [MOTOR_ID] як [POWER]","wedo2.tiltDirection.any":"любы","wedo2.tiltDirection.down":"уніз","wedo2.tiltDirection.left":"налева","wedo2.tiltDirection.right":"направа","wedo2.tiltDirection.up":"уверх","wedo2.whenDistance":"калі адлегласць [OP] [REFERENCE]","wedo2.whenTilted":"калі нахілены [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Колер","paint.paintEditor.saturation":"Насычанасць","paint.paintEditor.brightness":"Яркасць","paint.paintEditor.costume":"Касцюм","paint.paintEditor.group":"Згрупаваць","paint.paintEditor.ungroup":"Разгрупаваць","paint.paintEditor.undo":"Адмяніць","paint.paintEditor.redo":"Вярнуць","paint.paintEditor.forward":"Наперад","paint.paintEditor.backward":"Назад","paint.paintEditor.front":"На пярэдні план","paint.paintEditor.back":"Назад","paint.paintEditor.more":"Яшчэ","paint.modeTools.brushSize":"Памер","paint.modeTools.eraserSize":"Памер гумкі","paint.modeTools.copy":"Капіраваць","paint.modeTools.paste":"Уставіць","paint.modeTools.delete":"Выдаліць","paint.modeTools.curved":"Выгнутыя","paint.modeTools.pointed":"Завостраныя","paint.modeTools.thickness":"Таўшчыня","paint.modeTools.flipHorizontal":"Адлюстраваць па гарызанталі","paint.modeTools.flipVertical":"Адлюстраваць па вертыкалі","paint.modeTools.filled":"Заліты","paint.modeTools.outlined":"Абведзены","paint.paintEditor.bitmap":"Канвертаваць у растравую графіку","paint.paintEditor.vector":"Канвертаваць у вектарную графіку","paint.paintEditor.fill":"Заліўка","paint.paintEditor.stroke":"Контур","paint.brushMode.brush":"Пэндзлік","paint.eraserMode.eraser":"Гумка","paint.fillMode.fill":"Заліўка","paint.lineMode.line":"Рыса","paint.ovalMode.oval":"Кола","paint.rectMode.rect":"Прамавугольнік","paint.reshapeMode.reshape":"Змяніць форму","paint.roundedRectMode.roundedRect":"Скруглёны прамавугольнік","paint.selectMode.select":"Выбраць","paint.textMode.text":"Тэкст","paint.colorPicker.swap":"Замяніць"},"bg":{"gui.alerts.tryAgain":"Опитай пак","gui.alerts.download":"Сваляне","gui.connection.reconnect":"Повторно свързване","gui.backpack.costumeLabel":"костюм","gui.backpack.soundLabel":"звук","gui.backpack.scriptLabel":"скрипт","gui.backpack.spriteLabel":"спрайт","gui.backpack.header":"Раница","gui.backpack.errorBackpack":"Грешка при зареждането на раница","gui.backpack.loadingBackpack":"Зареждане…","gui.backpack.more":"Още","gui.backpack.emptyBackpack":"Раницата е празна","gui.unsupportedBrowser.label":"Браузърът не се поддържа","gui.cards.all-tutorials":"Обучения","gui.cards.shrink":"Смаляване","gui.cards.expand":"Разширяване","gui.cards.close":"Затвори","gui.cards.more-things-to-try":"Още неща, които да опиташ!","gui.cards.see-more":"Виж още","gui.comingSoon.message1":"Не се притеснявайте, заели сме се с това{emoji}","gui.comingSoon.message2":"Очаквайте скоро…","gui.comingSoon.message3":"Работим по това {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Не са открити устройства","gui.connection.auto-scanning.prescan":"Приближи устройствата и започни търсенето.","gui.connection.auto-scanning.pressbutton":"Натисни бутона на устройството си.","gui.connection.auto-scanning.start-search":"Започни търсене","gui.connection.connecting-searchbutton":"Търсене...","gui.connection.auto-scanning.try-again":"Опитай пак","gui.connection.connected":"Свързан","gui.connection.disconnect":"Прекрати връзка","gui.connection.go-to-editor":"Отиди в Редактора","gui.connection.connecting-cancelbutton":"Свързване...","gui.connection.error.errorMessage":"Опа, изглежда нещо се обърка","gui.connection.error.tryagainbutton":"Опитай пак","gui.connection.error.helpbutton":"Помощ","gui.connection.peripheral-name-label":"Име на устройството","gui.connection.connect":"Свързвам","gui.connection.scanning.lookingforperipherals":"Търсене на устройства","gui.connection.scanning.noPeripheralsFound":"Не са открити устройства","gui.connection.scanning.instructions":"Избери устройство от списъка по-горе.","gui.connection.search":"Обнови","gui.connection.unavailable.installscratchlink":"Проверете дали имате инсталиран Scratch Link и дали работи","gui.connection.unavailable.enablebluetooth":"Проверете дали Bluetooth е включен","gui.connection.unavailable.tryagainbutton":"Опитай пак","gui.connection.unavailable.helpbutton":"Помощ","gui.controls.go":"Старт","gui.controls.stop":"Спиране","gui.crashMessage.label":"Опа! Нещо се обърка","gui.crashMessage.errorNumber":"Грешката ви беше записана с id {errorId}","gui.crashMessage.reload":"Презареди","gui.customProcedures.myblockModalTitle":"Създаване на блок","gui.customProcedures.addAnInputNumberText":"Добави поле за въвеждане","gui.customProcedures.numberTextType":"число или текст","gui.customProcedures.addAnInputBoolean":"Добави поле за въвеждане","gui.customProcedures.booleanType":"да-не въвеждане","gui.customProcedures.addALabel":"Добавяне на етикет","gui.customProcedures.runWithoutScreenRefresh":"Стартиране без обновяване на екрана","gui.customProcedures.cancel":"Отказ","gui.customProcedures.ok":"Добре","gui.SpriteInfo.direction":"Посока","gui.directionPicker.rotationStyles.allAround":"Пълно завъртане","gui.directionPicker.rotationStyles.leftRight":"Ляво/Дясно","gui.directionPicker.rotationStyles.dontRotate":"Без въртене","gui.gui.addExtension":"Добавяне на разширение","gui.gui.codeTab":"Код","gui.gui.backdropsTab":"Фонове","gui.gui.costumesTab":"Костюми","gui.gui.soundsTab":"Звуци","gui.extensionLibrary.comingSoon":"Очаквайте скоро","gui.extensionLibrary.requires":"Изисква","gui.extensionLibrary.collaboration":"В партньорство с ","gui.library.filterPlaceholder":"Търсене","gui.library.allTag":"Всички","gui.loader.headline":"Зареждане на проекта","gui.loader.creating":"Създай Проект","gui.authorInfo.byUser":"от {username}","gui.menuBar.seeProjectPage":"Виж Страницата на Проекта","gui.menuBar.LanguageSelector":"избор на език","gui.menuBar.tutorialsLibrary":"Обучения","gui.menuBar.restoreSprite":"Възстанови Спрайта","gui.menuBar.restoreSound":"Възстанови звука","gui.menuBar.restoreCostume":"Възстанови костюма","gui.menuBar.restore":"Възстанови","gui.menuBar.saveNow":"Записване сега","gui.menuBar.saveAsCopy":"Записване като копие","gui.menuBar.remix":"Ремиксиране","gui.menuBar.new":"Нов","gui.menuBar.file":"Файл","gui.menuBar.downloadToComputer":"Запиши на вашия компютър","gui.menuBar.edit":"Редактиране","gui.menuBar.turboModeOff":"Изключи Turbo mode","gui.menuBar.turboModeOn":"Включи Turbo mode","gui.gui.projectTitlePlaceholder":"Заглавие на проекта тук","gui.menuBar.isShared":"Споделено","gui.menuBar.share":"Споделяне","gui.modal.help":"Помощ","gui.modal.back":"Назад","gui.monitor.listMonitor.empty":"(празен)","gui.monitor.listMonitor.listLength":"дължина {length}","gui.monitor.contextMenu.default":"нормално изписване","gui.monitor.contextMenu.large":"уголемено изписване","gui.monitor.contextMenu.slider":"плъзгач","gui.monitor.contextMenu.sliderRange":"промяна на обхвата на плъзгача","gui.monitor.contextMenu.import":"импорт","gui.monitor.contextMenu.export":"експорт","gui.monitor.contextMenu.hide":"скрий се","gui.playButton.play":"Пускане","gui.playButton.stop":"Спиране","gui.gui.variableScopeOptionAllSprites":"За всички спрайтове","gui.gui.variableScopeOptionSpriteOnly":"Само за този спрайт","gui.gui.cloudVariableOption":"Облачна променлива (съхранявана на сървър)","gui.gui.variablePromptAllSpritesMessage":"Тази променлива ще бъде достъпна за всички спрайтове.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Отказ","gui.prompt.ok":"Добре","gui.playbackStep.stopMsg":"Спиране","gui.playbackStep.playMsg":"Пускане","gui.playbackStep.loadingMsg":"Зареждане…","gui.playbackStep.saveMsg":"Запазване","gui.playbackStep.reRecordMsg":"Презапис","gui.recordModal.title":"Запиши звук","gui.recordingStep.beginRecord":"Започни запис, като натиснеш бутона по-долу.","gui.recordingStep.permission":"{arrow}Трябва ни Вашето разрешение, за да използваме микрофона Ви","gui.recordingStep.stop":"Спри записа","gui.recordingStep.record":"Запис","gui.sliderModal.min":"Минимална стойност","gui.sliderModal.max":"Максимална стойност","gui.sliderModal.title":"Промяна на обхвата на плъзгача","gui.sliderPrompt.cancel":"Отказ","gui.sliderPrompt.ok":"Добре","gui.soundEditor.sound":"Звук","gui.soundEditor.play":"Пускане","gui.soundEditor.stop":"Спиране","gui.soundEditor.copy":"Копиране","gui.soundEditor.paste":"Поставяне","gui.soundEditor.copyToNew":"Копиране в Нов","gui.soundEditor.delete":"Изтриване","gui.soundEditor.save":"Запазване","gui.soundEditor.undo":"Отмяна","gui.soundEditor.redo":"Повтаряне","gui.soundEditor.faster":"По-бързо","gui.soundEditor.slower":"По-бавно","gui.soundEditor.echo":"Ехо","gui.soundEditor.robot":"Робот","gui.soundEditor.louder":"По-силно","gui.soundEditor.softer":"По-меко","gui.soundEditor.reverse":"Размени","gui.soundEditor.fadeOut":"Затихване","gui.soundEditor.fadeIn":"Засилване","gui.soundEditor.mute":"Без звук","gui.SpriteInfo.spritePlaceholder":"Име","gui.SpriteInfo.sprite":"Спрайт","gui.SpriteInfo.show":"Показване","gui.SpriteInfo.size":"Размер","gui.spriteSelectorItem.contextMenuDuplicate":"копиране","gui.spriteSelectorItem.contextMenuExport":"експорт","gui.spriteSelectorItem.contextMenuDelete":"изтриване","gui.spriteSelector.addSpriteFromLibrary":"Избор на спрайт","gui.spriteSelector.addSpriteFromPaint":"Нарисувай","gui.spriteSelector.addSpriteFromSurprise":"Изненада","gui.spriteSelector.addSpriteFromFile":"Качи Спрайт","gui.stageHeader.stageSizeLarge":"Превключване към голяма сцена","gui.stageHeader.stageSizeSmall":"Превключване към малка сцена","gui.stageHeader.stageSizeFull":"Влизане в режим \\"Full screen\\"","gui.stageHeader.stageSizeUnFull":"Излизане от режим \\"Full screen\\"","gui.stageHeader.fullscreenControl":"Цял Екран","gui.spriteSelector.addBackdropFromLibrary":"Избор на фон","gui.stageSelector.addBackdropFromPaint":"Нарисувай","gui.stageSelector.addBackdropFromSurprise":"Изненада","gui.stageSelector.addBackdropFromFile":"Качи Декор","gui.stageSelector.stage":"Сцена","gui.stageSelector.backdrops":"Фонове","gui.telemetryOptIn.label":"Пращайте статистики, за да подобряваме Scratch","gui.telemetryOptIn.body1":"Екипът на Scratch винаги се опитва да да разбере как Scratch се използва навсякъде по света. За да помогнете за това, можете да разрешите на Scratch автоматично да изпраща информация относно използването му към екипът на Scratch.","gui.telemetryOptIn.body2":"Информацията, която събираме съдържа избор на език, използване на блокове и неща като запазване, зареждане и качване на проект. НЕ събираме никаква лична информация. Моля вижте нашата {privacyPolicyLink} за повече информация.","gui.telemetryOptIn.privacyPolicyLink":"Декларация за поверителност","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Активиране на телеметрията","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Деактивиране на телеметрията","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Затвори","gui.turboMode.active":"Режим Турбо","gui.webglModal.label":"Браузърът не поддържа WebGL","gui.webglModal.webgllink":"не поддържа WebGL","gui.costumeLibrary.chooseABackdrop":"Избор на фон","gui.costumeLibrary.chooseACostume":"Избор на костюм","gui.costumeTab.addBackdropFromLibrary":"Избор на фон","gui.costumeTab.addCostumeFromLibrary":"Избор на костюм","gui.costumeTab.addBlankCostume":"Нарисувай","gui.costumeTab.addSurpriseCostume":"Изненада","gui.costumeTab.addFileBackdrop":"Качи Декор","gui.costumeTab.addFileCostume":"Качи Костюм","gui.extensionLibrary.chooseAnExtension":"Избери разширение","gui.extensionLibrary.extensionUrl":"Въведете URL адреса на разширението","gui.monitors.importListColumnPrompt":"Коя колона трябва да бъде използвана (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Записването не можа да започне","gui.soundLibrary.chooseASound":"Избор на звук","gui.soundTab.fileUploadSound":"Качване на звук","gui.soundTab.surpriseSound":"Изненада","gui.soundTab.recordSound":"Запис","gui.soundTab.addSoundFromLibrary":"Избор на звук","gui.spriteLibrary.chooseASprite":"Избор на картинка","gui.tipsLibrary.tutorials":"Избери Урок","gui.alerts.createsuccess":"Създаден е нов проект.","gui.alerts.createcopysuccess":"Проектът бе запазен като копие.","gui.alerts.createremixsuccess":"Проектът бе запазен като ремикс.","gui.alerts.creating":"Създаване на нов...","gui.alerts.creatingCopy":"Проектът се копира...","gui.alerts.creatingRemix":"Проектът се ремиксира...","gui.alerts.creatingError":"Проектът не можа да се създаде. Моля опитайте пак!","gui.alerts.savingError":"Проектът не можа да се запази.","gui.alerts.savesuccess":"Проектът е записан.","gui.alerts.saving":"Запис проект...","gui.alerts.cloudInfo":"Моля помнете, че клауд променливите могат да съдържат само числа, без букви и символи.{learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Научи повече","gui.alerts.importing":"Импортиране...","gui.defaultProject.variable":"моята променлива","gui.extension.music.name":"Музика","gui.extension.music.description":"Изсвирете с инструменти и барабани.","gui.extension.pen.name":"Молив","gui.extension.pen.description":"Рисувайте с вашите спрайтове.","gui.extension.videosensing.name":"Видео Усет","gui.extension.videosensing.description":"Доловете движение с камерата.","gui.extension.text2speech.name":"Текст за Произнасяне","gui.extension.text2speech.description":"Накарай проектите си да говорят.","gui.extension.translate.name":"Преведи","gui.extension.translate.description":"Превеждай текст на много езици.","gui.extension.makeymakey.description":"Направи всичко на клавиш.","gui.extension.microbit.description":"Свържи проектите си със света.","gui.extension.microbit.connectingMessage":"Свързване","gui.extension.ev3.description":"Построй интерактивни роботи и други неща.","gui.extension.ev3.connectingMessage":"Свързване. Уверете се, че кода на Вашия EV3 е настроен на 1234.","gui.extension.boost.description":"Вдъхни живот на роботите.","gui.extension.boost.connectingMessage":"Свързване","gui.extension.wedo2.description":"Направи ги с мотори и сензори.","gui.extension.wedo2.connectingMessage":"Свързване","gui.extension.gdxfor.description":"Сензор за натиск, опън, движете, и въртете.","gui.extension.gdxfor.connectingMessage":"Свързване","gui.libraryTags.all":"Всички","gui.libraryTags.animals":"Животни","gui.libraryTags.dance":"Танци","gui.libraryTags.effects":"Ефекти","gui.libraryTags.fantasy":"Фантастика","gui.libraryTags.fashion":"Мода","gui.libraryTags.food":"Храни","gui.libraryTags.indoors":"На закрито","gui.libraryTags.loops":"Цикли","gui.libraryTags.music":"Музика","gui.libraryTags.notes":"Бележки","gui.libraryTags.outdoors":"На открито","gui.libraryTags.patterns":"Шаблони","gui.libraryTags.people":"Хора","gui.libraryTags.percussion":"Перкусионни","gui.libraryTags.space":"Космос","gui.libraryTags.sports":"Спорт","gui.libraryTags.underwater":"Подводни","gui.libraryTags.voice":"Гласове","gui.libraryTags.wacky":"Шантави","gui.libraryTags.animation":"Анимации","gui.libraryTags.art":"Изкуство","gui.libraryTags.games":"Игри","gui.libraryTags.stories":"Истории","gui.libraryTags.letters":"Букви","gui.opcodeLabels.direction":"посока","gui.opcodeLabels.xposition":"x позиция","gui.opcodeLabels.yposition":"y позиция","gui.opcodeLabels.size":"размер","gui.opcodeLabels.costumename":"име на костюм","gui.opcodeLabels.costumenumber":"номер на костюм","gui.opcodeLabels.backdropname":"име на декор","gui.opcodeLabels.backdropnumber":"декор номер","gui.opcodeLabels.volume":"сила на звука","gui.opcodeLabels.tempo":"темпо","gui.opcodeLabels.answer":"отговор","gui.opcodeLabels.loudness":"шумно","gui.opcodeLabels.username":"потребителско име","gui.opcodeLabels.year":"година","gui.opcodeLabels.month":"месец","gui.opcodeLabels.date":"дата","gui.opcodeLabels.dayofweek":"ден от седмицата","gui.opcodeLabels.hour":"час","gui.opcodeLabels.minute":"минута","gui.opcodeLabels.second":"секунда","gui.opcodeLabels.timer":"таймер","gui.sharedMessages.backdrop":"декор {index}","gui.sharedMessages.costume":"костюм {index}","gui.sharedMessages.sprite":"Спрайт {index}","gui.sharedMessages.pop":"пук","gui.sharedMessages.replaceProjectWarning":"Да се замени ли съдържанието от текущия проект?","gui.sharedMessages.loadFromComputerTitle":"Зареди от своя компютър","boost.color.any":"който и да е цвят","boost.color.black":"черно","boost.color.blue":"синьо","boost.color.green":"зелено","boost.color.red":"червено","boost.color.white":"бяло","boost.color.yellow":"жълто","boost.getMotorPosition":"мотор [MOTOR_REPORTER_ID] на позиция ","boost.getTiltAngle":"наклон на ъгъла [TILT_DIRECTION]","boost.motorDirection.backward":"назад","boost.motorDirection.forward":"напред","boost.motorDirection.reverse":"обръщане","boost.motorOff":"изключи мотор [MOTOR_ID] ","boost.motorOn":"включи мотор [MOTOR_ID]","boost.motorOnFor":"включи мотор [MOTOR_ID] за [DURATION] секунди","boost.motorOnForRotation":"включи мотор [MOTOR_ID] за [ROTATION] оборота","boost.seeingColor":"виждам [COLOR] тухла?","boost.setLightHue":"направи светлината на цвета на [HUE]","boost.setMotorDirection":"задай на мотор [MOTOR_ID] посока [MOTOR_DIRECTION]","boost.setMotorPower":"задай скоростта на мотор [MOTOR_ID] на [POWER] %","boost.tiltDirection.any":"който и да е","boost.tiltDirection.down":"надолу","boost.tiltDirection.left":"наляво","boost.tiltDirection.right":"надясно","boost.tiltDirection.up":"нагоре","boost.whenColor":"когато се вижда тухла с цвят [COLOR] ","boost.whenTilted":"при наклон [TILT_DIRECTION_ANY]","ev3.beepNote":"изсвири тон [NOTE] за [TIME] секунди","ev3.buttonPressed":"бутон [PORT] натиснат ли е?","ev3.getBrightness":"яркост","ev3.getDistance":"разстояние","ev3.getMotorPosition":"позиция на мотор [PORT]","ev3.motorSetPower":"мотор [PORT] направи мощност на [POWER] %","ev3.motorTurnClockwise":"моторът [PORT] се върти по часовника за [TIME] секунди","ev3.motorTurnCounterClockwise":"моторът [PORT] се върти обратно на часовника за [TIME] секунди","ev3.whenBrightnessLessThan":"когато яркост < [DISTANCE]","ev3.whenButtonPressed":"когато бутон [PORT] е натиснат","ev3.whenDistanceLessThan":"когато дистанция < [DISTANCE]","gdxfor.getAcceleration":"ускорение [DIRECTION]","gdxfor.getForce":"сила","gdxfor.getSpin":"скорост на въртене [DIRECTION]","gdxfor.getTilt":"наклон на ъгъла [TILT]","gdxfor.isFreeFalling":"падане? ","gdxfor.isTilted":"наклон [TILT]?","gdxfor.pulled":"издърпан","gdxfor.pushed":"натиснат","gdxfor.shaken":"разтърсен","gdxfor.startedFalling":"започна да пада","gdxfor.tiltDirectionMenu.any":"който и да е","gdxfor.tiltDirectionMenu.back":"отзад","gdxfor.tiltDirectionMenu.front":"отпред","gdxfor.tiltDirectionMenu.left":"ляво","gdxfor.tiltDirectionMenu.right":"дясно","gdxfor.turnedFaceDown":"обърната с лицето надолу","gdxfor.turnedFaceUp":"обърната с лицето нагоре","gdxfor.whenForcePushedOrPulled":"когато сензор за сила [PUSH_PULL]","gdxfor.whenGesture":"когато [GESTURE]","gdxfor.whenTilted":"при наклон [TILT]","makeymakey.downArrow":"стрелка надолу","makeymakey.downArrowShort":"надолу","makeymakey.leftArrow":"лява стрелка","makeymakey.leftArrowShort":"наляво","makeymakey.rightArrow":"дясна стрелка","makeymakey.rightArrowShort":"надясно","makeymakey.spaceKey":"интервал","makeymakey.upArrow":"стрелка нагоре","makeymakey.upArrowShort":"нагоре","makeymakey.whenKeyPressed":"когато е натиснат клавиш [KEY]","makeymakey.whenKeysPressedInOrder":"когато [SEQUENCE] е натисната последователно","microbit.buttonsMenu.any":"произволен","microbit.clearDisplay":"изчисти екрана","microbit.defaultTextToDisplay":"Hello!","microbit.displaySymbol":"покажи [MATRIX]","microbit.displayText":"покажи текст [TEXT]","microbit.gesturesMenu.jumped":"подхвърлен","microbit.gesturesMenu.moved":"преместен","microbit.gesturesMenu.shaken":"разтърсен","microbit.isButtonPressed":"[BTN] бутон натиснат ли е?","microbit.isTilted":"наклонен [DIRECTION]?","microbit.pinStateMenu.off":"изключено","microbit.pinStateMenu.on":"включено","microbit.tiltAngle":"наклон на ъгъла [DIRECTION]","microbit.tiltDirectionMenu.any":"произволен","microbit.tiltDirectionMenu.back":"отзад","microbit.tiltDirectionMenu.front":"отпред","microbit.tiltDirectionMenu.left":"наляво","microbit.tiltDirectionMenu.right":"надясно","microbit.whenButtonPressed":"когато [BTN] бутон е натиснат","microbit.whenGesture":"когато [GESTURE]","microbit.whenPinConnected":"когато пин [PIN] е свързан","microbit.whenTilted":"при наклон [DIRECTION]","music.categoryName":"Музика","music.changeTempo":"увеличи темпо с [TEMPO]","music.drumBass":"(2) Бас Барабан","music.drumBongo":"(13) Бонго","music.drumCabasa":"(15) Кабаса","music.drumClaves":"(9) Клавес","music.drumClosedHiHat":"(6) Затворен педален чинел","music.drumConga":"(14) Конга","music.drumCowbell":"(11) Пастирски Звънец","music.drumCrashCymbal":"(4) Краш чинел","music.drumCuica":"(18) Куика","music.drumGuiro":"(16) Гуиро","music.drumHandClap":"(8) Ръкопляскане","music.drumOpenHiHat":"(5) Отворен педален чинел","music.drumSideStick":"(3) Малък барабан","music.drumSnare":"(1) Малък Барабан","music.drumTambourine":"(7) Дайре","music.drumTriangle":"(12) Триъгълник","music.drumVibraslap":"(17) Вибраслап","music.drumWoodBlock":"(10) Дървени Блокчета","music.getTempo":"темпо","music.instrumentBass":"(6) Контрабас","music.instrumentBassoon":"(14) Фагот","music.instrumentCello":"(8) Виолончело","music.instrumentChoir":"(15) Хор","music.instrumentClarinet":"(10) Кларинет","music.instrumentElectricGuitar":"(5) Електрическа Китара","music.instrumentElectricPiano":"(2) Електрическо Пиано","music.instrumentFlute":"(12) Флейта","music.instrumentGuitar":"(4) Китара","music.instrumentMarimba":"(19) Маримба","music.instrumentMusicBox":"(17) Музикална Кутия","music.instrumentOrgan":"(3) Орган","music.instrumentPiano":"(1) Пиано","music.instrumentPizzicato":"(7) Пицикато","music.instrumentSaxophone":"(11) Саксофон","music.instrumentSteelDrum":"(18) Стилпан","music.instrumentSynthLead":"(20) Synth Lead","music.instrumentSynthPad":"(21) Полисинтезатор","music.instrumentTrombone":"(9) Тромбон","music.instrumentVibraphone":"(16) Вибрафон","music.instrumentWoodenFlute":"(13) Дървена Флейта","music.midiPlayDrumForBeats":"изсвири барабан [DRUM] за [BEATS] времена","music.midiSetInstrument":"задай инструмента на [INSTRUMENT]","music.playDrumForBeats":"изсвири барабан [DRUM] за [BEATS] времена","music.playNoteForBeats":"изсвири нота [NOTE] за [BEATS] времена","music.restForBeats":"спри за [BEATS] времена","music.setInstrument":"направи инструмента на [INSTRUMENT]","music.setTempo":"направи темпо на [TEMPO]","pen.categoryName":"Молив","pen.changeColorParam":"промени [COLOR_PARAM] на молива с/ъс [VALUE]","pen.changeHue":"промени цвета на молива с [HUE]","pen.changeShade":"промени плътността на молива с/ъс [SHADE]","pen.changeSize":"промени pen size by [SIZE]","pen.clear":"изтрий всичко","pen.colorMenu.brightness":"яркост","pen.colorMenu.color":"цвят","pen.colorMenu.saturation":"наситеност","pen.colorMenu.transparency":"прозрачност","pen.penDown":"молив долу","pen.penUp":"молив горе","pen.setColor":"направи цвета на молива [COLOR]","pen.setColorParam":"направи [COLOR_PARAM] на молива на [VALUE]","pen.setHue":"направи цвета на молива [HUE]","pen.setShade":"направи яркостта на молива [SHADE]","pen.setSize":"направи дебелината на молива [SIZE]","pen.stamp":"отпечати","text2speech.alto":"нормален","text2speech.categoryName":"Текст към Реч","text2speech.defaultTextToSpeak":"здравей","text2speech.giant":"великан","text2speech.kitten":"коте","text2speech.setLanguageBlock":"промени езика на [LANGUAGE]","text2speech.setVoiceBlock":"направи звука на [VOICE]","text2speech.speakAndWaitBlock":"кажи [WORDS]","text2speech.squeak":"скърцане","text2speech.tenor":"висок","translate.categoryName":"Преведи","translate.defaultTextToTranslate":"здравей","translate.translateBlock":"преведи [WORDS] на [LANGUAGE]","translate.viewerLanguage":"език","videoSensing.categoryName":"Видео Усет","videoSensing.direction":"посока","videoSensing.motion":"движение","videoSensing.off":"изключено","videoSensing.on":"включено","videoSensing.onFlipped":"включи огледално","videoSensing.setVideoTransparency":"направи плътност на видеото на [TRANSPARENCY]","videoSensing.sprite":"спрайт","videoSensing.stage":"сцена","videoSensing.videoOn":"видео [ATTRIBUTE] на [SUBJECT]","videoSensing.videoToggle":"[VIDEO_STATE] видео","videoSensing.whenMotionGreaterThan":"когато видео движение > [REFERENCE]","wedo2.getDistance":"разстояние","wedo2.getTiltAngle":"наклон на ъгъла [TILT_DIRECTION]","wedo2.isTilted":"наклонен [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"натам","wedo2.motorDirection.forward":"насам","wedo2.motorDirection.reverse":"обръщане","wedo2.motorId.a":"мотор A","wedo2.motorId.all":"всички мотори","wedo2.motorId.b":"Мотор B","wedo2.motorId.default":"мотор","wedo2.motorOff":"изключи [MOTOR_ID]","wedo2.motorOn":"включи [MOTOR_ID]","wedo2.motorOnFor":"включи [MOTOR_ID] за [DURATION] секунди","wedo2.playNoteFor":"изсвири тон [NOTE] за [DURATION] секунди","wedo2.setLightHue":"задай цвета на светлината на [HUE]","wedo2.setMotorDirection":"задай на [MOTOR_ID] посока [MOTOR_DIRECTION]","wedo2.startMotorPower":"направи мощност на [MOTOR_ID] на [POWER]","wedo2.tiltDirection.any":"произволен","wedo2.tiltDirection.down":"надолу","wedo2.tiltDirection.left":"наляво","wedo2.tiltDirection.right":"надясно","wedo2.tiltDirection.up":"нагоре","wedo2.whenDistance":"когато дистанция [OP] [REFERENCE]","wedo2.whenTilted":"при наклон [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Цвят","paint.paintEditor.saturation":"Наситеност","paint.paintEditor.brightness":"Яркост","paint.paintEditor.costume":"Костюм","paint.paintEditor.group":"Групиране","paint.paintEditor.ungroup":"Разгрупиране","paint.paintEditor.undo":"Отмяна","paint.paintEditor.redo":"Повтаряне","paint.paintEditor.forward":"Напред","paint.paintEditor.backward":"Назад","paint.paintEditor.front":"Отпред","paint.paintEditor.back":"Отзад","paint.paintEditor.more":"Още","paint.modeTools.brushSize":"Размер","paint.modeTools.eraserSize":"Размер на гумата","paint.modeTools.copy":"Копиране","paint.modeTools.paste":"Поставяне","paint.modeTools.delete":"Изтриване","paint.modeTools.curved":"Заоблен","paint.modeTools.pointed":"Заострен","paint.modeTools.thickness":"Дебелина","paint.modeTools.flipHorizontal":"Хоризонтално обръщане","paint.modeTools.flipVertical":"Вертикално обръщане","paint.modeTools.filled":"Запълнен","paint.modeTools.outlined":"Подчертан","paint.paintEditor.bitmap":"Преобразуване в растерен режим","paint.paintEditor.vector":"Преобразуване във векторен режим","paint.paintEditor.fill":"Запълване","paint.paintEditor.stroke":"Подчертаване","paint.brushMode.brush":"Четка","paint.eraserMode.eraser":"Гума","paint.fillMode.fill":"Запълване","paint.lineMode.line":"Линия","paint.ovalMode.oval":"Окръжност","paint.rectMode.rect":"Правоъгълник","paint.reshapeMode.reshape":"Оформяне","paint.roundedRectMode.roundedRect":"Заоблен правоъгълник","paint.selectMode.select":"Маркиране","paint.textMode.text":"Текст","paint.colorPicker.swap":"Замяна"},"ca":{"gui.alerts.tryAgain":"Torna-ho a intentar","gui.alerts.download":"Descarrega","gui.connection.reconnect":"Torna a connectar","gui.backpack.costumeLabel":"vestit","gui.backpack.soundLabel":"so","gui.backpack.scriptLabel":"programa","gui.backpack.spriteLabel":"personatge","gui.backpack.header":"Motxilla","gui.backpack.errorBackpack":"Error al carregar la motxilla","gui.backpack.loadingBackpack":"Carregant...","gui.backpack.more":"Més","gui.backpack.emptyBackpack":"La motxilla està buida","gui.unsupportedBrowser.label":"Aquest navegador no està suportat","gui.cards.all-tutorials":"Tutorials","gui.cards.shrink":"Encongeix","gui.cards.expand":"Desplega","gui.cards.close":"Tanca","gui.cards.more-things-to-try":"Més coses per provar!","gui.cards.see-more":"Veure més","gui.comingSoon.message1":"Hi estem treballant {emoji}","gui.comingSoon.message2":"Properament...","gui.comingSoon.message3":"Hi estem treballant {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"No s\'ha trobat cap dispositiu","gui.connection.auto-scanning.prescan":"Situa el dispositiu a prop i llavors inicia la cerca.","gui.connection.auto-scanning.pressbutton":"Prem el botó del teu dispositiu.","gui.connection.auto-scanning.start-search":"Comença a buscar","gui.connection.connecting-searchbutton":"Cercant...","gui.connection.auto-scanning.try-again":"Prova de nou","gui.connection.connected":"Connectat","gui.connection.disconnect":"Desconnecta","gui.connection.go-to-editor":"Vés a l\'Editor","gui.connection.connecting-cancelbutton":"Connectant...","gui.connection.error.errorMessage":"Vaja, alguna cosa ha anat malament.","gui.connection.error.tryagainbutton":"Prova de nou","gui.connection.error.helpbutton":"Ajuda","gui.connection.peripheral-name-label":"Nom del dispositiu","gui.connection.connect":"Connecta","gui.connection.scanning.lookingforperipherals":"Buscant dispositius","gui.connection.scanning.noPeripheralsFound":"No s\'ha trobat cap dispositiu","gui.connection.scanning.instructions":"Selecciona el teu dispositiu a la llista de dalt.","gui.connection.search":"Actualitza","gui.connection.unavailable.installscratchlink":"Comprova que has instal·lat l\'Scratch Link i s\'està executant","gui.connection.unavailable.enablebluetooth":"Comprova que el Bluetooth està habilitat","gui.connection.unavailable.tryagainbutton":"Prova de nou","gui.connection.unavailable.helpbutton":"Ajuda","gui.controls.go":"Vés","gui.controls.stop":"Atura","gui.crashMessage.label":"Vaja! Alguna cosa ha anat malament.","gui.crashMessage.errorNumber":"El teu error ha estat registrat amb l\'id {errorId}","gui.crashMessage.reload":"Recarrega","gui.customProcedures.myblockModalTitle":"Crea un bloc","gui.customProcedures.addAnInputNumberText":"Afegeix una entrada","gui.customProcedures.numberTextType":"nombre o text","gui.customProcedures.addAnInputBoolean":"Afegeix una entrada","gui.customProcedures.booleanType":"booleà","gui.customProcedures.addALabel":"Afegeix una etiqueta","gui.customProcedures.runWithoutScreenRefresh":"Funciona sense refrescar la pantalla","gui.customProcedures.cancel":"Cancel·la","gui.customProcedures.ok":"D\'acord","gui.SpriteInfo.direction":"Direcció","gui.directionPicker.rotationStyles.allAround":"Al voltant","gui.directionPicker.rotationStyles.leftRight":"Esquerra/Dreta","gui.directionPicker.rotationStyles.dontRotate":"No giris","gui.gui.addExtension":"Afegeix una Extensió","gui.gui.codeTab":"Codi","gui.gui.backdropsTab":"Fons","gui.gui.costumesTab":"Vestits","gui.gui.soundsTab":"Sons","gui.extensionLibrary.comingSoon":"Properament","gui.extensionLibrary.requires":"Requisits","gui.extensionLibrary.collaboration":"En col·laboració amb","gui.library.filterPlaceholder":"Cerca","gui.library.allTag":"Tots","gui.loader.headline":"S\'està carregant el projecte","gui.loader.creating":"Creant projecte","gui.authorInfo.byUser":"per {username}","gui.menuBar.seeProjectPage":"Veure la pàgina del projecte","gui.menuBar.LanguageSelector":"tria l\'idioma","gui.menuBar.tutorialsLibrary":"Tutorials","gui.menuBar.restoreSprite":"Recupera el personatge","gui.menuBar.restoreSound":"Recupera el so","gui.menuBar.restoreCostume":"Recupera el vestit","gui.menuBar.restore":"Recupera","gui.menuBar.saveNow":"Desa ara","gui.menuBar.saveAsCopy":"Desa una còpia","gui.menuBar.remix":"Reinventa","gui.menuBar.new":"Nou","gui.menuBar.file":"Fitxer","gui.menuBar.downloadToComputer":"Desa al teu ordinador","gui.menuBar.edit":"Edita","gui.menuBar.turboModeOff":"Desactiva el Mode Turbo","gui.menuBar.turboModeOn":"Activa el Mode Turbo","gui.gui.projectTitlePlaceholder":"Títol del projecte aquí","gui.menuBar.isShared":"Compartit","gui.menuBar.share":"Comparteix","gui.modal.help":"Ajuda","gui.modal.back":"Enrere","gui.monitor.listMonitor.empty":"(buida)","gui.monitor.listMonitor.listLength":"llargada {length}","gui.monitor.contextMenu.default":"pantalla normal","gui.monitor.contextMenu.large":"pantalla gran","gui.monitor.contextMenu.slider":"lliscador","gui.monitor.contextMenu.sliderRange":"canvia el rang del lliscador","gui.monitor.contextMenu.import":"importa","gui.monitor.contextMenu.export":"exporta","gui.monitor.contextMenu.hide":"amaga\'t","gui.playButton.play":"Reprodueix","gui.playButton.stop":"Atura","gui.gui.variableScopeOptionAllSprites":"Per a tots els personatges","gui.gui.variableScopeOptionSpriteOnly":"Només per a aquest personatge","gui.gui.cloudVariableOption":"Variable al núvol (emmagatzemada en el servidor)","gui.gui.variablePromptAllSpritesMessage":"Aquesta variable estarà disponible per a tots els personatges.","gui.gui.listPromptAllSpritesMessage":"Aquesta llista estarà disponible per a tots els sprites.","gui.prompt.cancel":"Cancel·la","gui.prompt.ok":"D\'acord","gui.playbackStep.stopMsg":"Atura","gui.playbackStep.playMsg":"Reprodueix","gui.playbackStep.loadingMsg":"Carregant...","gui.playbackStep.saveMsg":"Desa","gui.playbackStep.reRecordMsg":"Torna a gravar","gui.recordModal.title":"Grava un so","gui.recordingStep.beginRecord":"Comença la gravació fent clic al botó de sota","gui.recordingStep.permission":"{arrow}Necessitem el teu permís per utilitzar el teu micròfon","gui.recordingStep.stop":"Atura la gravació","gui.recordingStep.record":"Enregistra","gui.sliderModal.min":"valor mínim","gui.sliderModal.max":"valor màxim","gui.sliderModal.title":"Canvia el rang del lliscador","gui.sliderPrompt.cancel":"Cancel·la","gui.sliderPrompt.ok":"D\'acord","gui.soundEditor.sound":"So","gui.soundEditor.play":"Reprodueix","gui.soundEditor.stop":"Atura","gui.soundEditor.copy":"Copia","gui.soundEditor.paste":"Enganxa","gui.soundEditor.copyToNew":"Copia en un nou so","gui.soundEditor.delete":"Elimina","gui.soundEditor.save":"Desa","gui.soundEditor.undo":"Desfés","gui.soundEditor.redo":"Torna-hi","gui.soundEditor.faster":"Més ràpid","gui.soundEditor.slower":"Més lent","gui.soundEditor.echo":"Eco","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Més fort","gui.soundEditor.softer":"Més fluix","gui.soundEditor.reverse":"Inverteix","gui.soundEditor.fadeOut":"Fosa de tancament","gui.soundEditor.fadeIn":"Fosa d\'obertura","gui.soundEditor.mute":"Silencia","gui.SpriteInfo.spritePlaceholder":"Nom","gui.SpriteInfo.sprite":"Personatge","gui.SpriteInfo.show":"Mostra","gui.SpriteInfo.size":"Mida","gui.spriteSelectorItem.contextMenuDuplicate":"duplica","gui.spriteSelectorItem.contextMenuExport":"exporta","gui.spriteSelectorItem.contextMenuDelete":"esborra","gui.spriteSelector.addSpriteFromLibrary":"Tria un personatge","gui.spriteSelector.addSpriteFromPaint":"Dibuixa","gui.spriteSelector.addSpriteFromSurprise":"Sorpresa","gui.spriteSelector.addSpriteFromFile":"Puja un personatge","gui.stageHeader.stageSizeLarge":"Canvia a vista àmplia","gui.stageHeader.stageSizeSmall":"Canvia a vista petita","gui.stageHeader.stageSizeFull":"Canvia a mode Pantalla completa","gui.stageHeader.stageSizeUnFull":"Surt del mode Pantalla completa","gui.stageHeader.fullscreenControl":"Control de pantalla completa","gui.spriteSelector.addBackdropFromLibrary":"Tria un fons","gui.stageSelector.addBackdropFromPaint":"Pintar","gui.stageSelector.addBackdropFromSurprise":"Sorpresa","gui.stageSelector.addBackdropFromFile":"Puja un fons","gui.stageSelector.stage":"Escenari","gui.stageSelector.backdrops":"Fons","gui.telemetryOptIn.label":"Informa d\'estadístiques per millorar Scratch","gui.telemetryOptIn.body1":"L\'equip Scratch sempre busca comprendre millor com s\'utilitza Scratch a tot el món. Per ajudar a donar suport, podeu permetre que Scratch enviï automàticament informació d\'ús a l\'equip Scratch.","gui.telemetryOptIn.body2":"La informació que recopilem inclou selecció de llenguatges, blocs d\'ús i alguns esdeveniments, com desar, carregar i penjar un projecte. NO recopilem cap informació personal. Si us plau mireu la nostra {privacyPolicyLink} per a més informació.","gui.telemetryOptIn.privacyPolicyLink":"Política de Privacitat","gui.telemetryOptIn.optInText":"Comparteix les meves dades d\'ús amb l\'equip de Scratch","gui.telemetryOptIn.optInTooltip":"Activa la telemetria","gui.telemetryOptIn.optOutText":"No comparteixis les meves dades d\'ús amb l\'equip de Scratch","gui.telemetryOptIn.optOutTooltip":"Desactiva la telemetria","gui.telemetryOptIn.settingWasUpdated":"S\'ha actualitzat la configuració.","gui.telemetryOptIn.buttonClose":"Tanca","gui.turboMode.active":"Mode Turbo","gui.webglModal.label":"El teu navegador no suporta WebGL","gui.webglModal.webgllink":"no suporta WebGL","gui.costumeLibrary.chooseABackdrop":"Tria un fons","gui.costumeLibrary.chooseACostume":"Tria un vestit","gui.costumeTab.addBackdropFromLibrary":"Tria un fons","gui.costumeTab.addCostumeFromLibrary":"Tria un vestit","gui.costumeTab.addBlankCostume":"Dibuixa un nou vestit","gui.costumeTab.addSurpriseCostume":"Sorpresa","gui.costumeTab.addFileBackdrop":"Puja un fons","gui.costumeTab.addFileCostume":"Puja un vestit","gui.extensionLibrary.chooseAnExtension":"Tria una extensió","gui.extensionLibrary.extensionUrl":"Escriu la URL de l\'extensió","gui.monitors.importListColumnPrompt":"Quina columna s\'ha d\'utilitzar (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"No s\'ha pogut començar a gravar","gui.soundLibrary.chooseASound":"Tria un so","gui.soundTab.fileUploadSound":"Puja un so","gui.soundTab.surpriseSound":"Sorpresa","gui.soundTab.recordSound":"Enregistra","gui.soundTab.addSoundFromLibrary":"Tria un so","gui.spriteLibrary.chooseASprite":"Tria un personatge","gui.tipsLibrary.tutorials":"Tria un tutorial","gui.alerts.createsuccess":"Nou projecte creat.","gui.alerts.createcopysuccess":"Projecte desat com a còpia.","gui.alerts.createremixsuccess":"Projecte desat com a reinvenció.","gui.alerts.creating":"Creant nou...","gui.alerts.creatingCopy":"Copiant projecte...","gui.alerts.creatingRemix":"Reinventant projecte...","gui.alerts.creatingError":"No s\'ha pogut crear el projecte. Torna a intentar-ho!","gui.alerts.savingError":"No s\'ha pogut desar el projecte.","gui.alerts.savesuccess":"Projecte guardat.","gui.alerts.saving":"Desant projecte...","gui.alerts.cloudInfo":"Tingues en compte que les variables del núvol només admeten nombres, no lletres o símbols. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Aprèn més.","gui.alerts.importing":"Important...","gui.defaultProject.variable":"la meva variable","gui.extension.music.name":"Música","gui.extension.music.description":"Toca instruments i tambors.","gui.extension.pen.name":"Llapis","gui.extension.pen.description":"Dibuixa amb els teus personatges.","gui.extension.videosensing.name":"Detecció de vídeo","gui.extension.videosensing.description":"Detecta moviment amb la càmera.","gui.extension.text2speech.name":"De text a parla","gui.extension.text2speech.description":"Fes que els teus projectes parlin.","gui.extension.translate.name":"Tradueix","gui.extension.translate.description":"Tradueix text en molts idiomes.","gui.extension.makeymakey.description":"Converteix qualsevol cosa en una tecla.","gui.extension.microbit.description":"Connecta els projectes amb el món.","gui.extension.microbit.connectingMessage":"Connectant","gui.extension.ev3.description":"Construeix robots interactius i més.","gui.extension.ev3.connectingMessage":"Connectant. Assegura\'t que el codi en el teu EV3 és 1234.","gui.extension.boost.description":"Porta a la vida les creacions.","gui.extension.boost.connectingMessage":"Connectant","gui.extension.wedo2.description":"Construeix amb motors i sensors.","gui.extension.wedo2.connectingMessage":"Connectant","gui.extension.gdxfor.description":"Detecta quan s\'empeny, s\'estira, es mou i es gira.","gui.extension.gdxfor.connectingMessage":"Connectant","gui.libraryTags.all":"Tots","gui.libraryTags.animals":"Animals","gui.libraryTags.dance":"Balla","gui.libraryTags.effects":"Efectes","gui.libraryTags.fantasy":"Fantasia","gui.libraryTags.fashion":"Moda","gui.libraryTags.food":"Menjar","gui.libraryTags.indoors":"Interiors","gui.libraryTags.loops":"Repeticions","gui.libraryTags.music":"Música","gui.libraryTags.notes":"Notes musicals","gui.libraryTags.outdoors":"Exteriors","gui.libraryTags.patterns":"Patrons","gui.libraryTags.people":"Gent","gui.libraryTags.percussion":"Percussió","gui.libraryTags.space":"Espai","gui.libraryTags.sports":"Esports","gui.libraryTags.underwater":"Sota l\'aigua","gui.libraryTags.voice":"Veu","gui.libraryTags.wacky":"Divertit","gui.libraryTags.animation":"Animació","gui.libraryTags.art":"Art","gui.libraryTags.games":"Jocs","gui.libraryTags.stories":"Històries","gui.libraryTags.letters":"Lletres","gui.opcodeLabels.direction":"direcció","gui.opcodeLabels.xposition":"posició x","gui.opcodeLabels.yposition":"posició y","gui.opcodeLabels.size":"mida","gui.opcodeLabels.costumename":"nom del vestit","gui.opcodeLabels.costumenumber":"número de vestit","gui.opcodeLabels.backdropname":"nom del fons","gui.opcodeLabels.backdropnumber":"número de fons","gui.opcodeLabels.volume":"volum","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"resposta","gui.opcodeLabels.loudness":"volum del so","gui.opcodeLabels.username":"nom d\'usuari","gui.opcodeLabels.year":"any","gui.opcodeLabels.month":"mes","gui.opcodeLabels.date":"data","gui.opcodeLabels.dayofweek":"dia de la setmana","gui.opcodeLabels.hour":"hora","gui.opcodeLabels.minute":"minut","gui.opcodeLabels.second":"segon","gui.opcodeLabels.timer":"cronòmetre","gui.sharedMessages.backdrop":"fons{index}","gui.sharedMessages.costume":"vestit{index}","gui.sharedMessages.sprite":"Personatge{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Vols substituir els continguts del projecte actual?","gui.sharedMessages.loadFromComputerTitle":"Carrega des del teu ordinador","boost.color.any":"qualsevol color","boost.color.black":"negre","boost.color.blue":"blau","boost.color.green":"verd","boost.color.red":"vermell","boost.color.white":"blanc","boost.color.yellow":"groc","boost.getMotorPosition":"posició del motor [MOTOR_REPORTER_ID]","boost.getTiltAngle":"angle d\'inclinació [TILT_DIRECTION]","boost.motorDirection.backward":"cap aquí","boost.motorDirection.forward":"cap allà","boost.motorDirection.reverse":"invertit","boost.motorOff":"apaga el motor [MOTOR_ID]","boost.motorOn":"activa el motor [MOTOR_ID]","boost.motorOnFor":"activa el motor [MOTOR_ID] durant [DURATION] segons","boost.motorOnForRotation":"activa el motor [MOTOR_ID] durant [ROTATION] rotacions","boost.seeingColor":"detecta el bloc [COLOR]?","boost.setLightHue":"fixa el color del llum a [HUE]","boost.setMotorDirection":"fixa la direcció del motor [MOTOR_ID] a [MOTOR_DIRECTION]","boost.setMotorPower":"fixa la velocitat del motor [MOTOR_ID] a [POWER] %","boost.tiltDirection.any":"qualsevol","boost.tiltDirection.down":"avall","boost.tiltDirection.left":"esquerra","boost.tiltDirection.right":"dreta","boost.tiltDirection.up":"amunt","boost.whenColor":"quan detecti el bloc [COLOR]","boost.whenTilted":"quan la inclinació [TILT_DIRECTION_ANY]","ev3.beepNote":"fes sonar la nota [NOTE] durant [TIME] segons","ev3.buttonPressed":"botó [PORT] premut?","ev3.getBrightness":"brillantor","ev3.getDistance":"distància","ev3.getMotorPosition":"posició del motor [PORT]","ev3.motorSetPower":"motor [PORT] potència [POWER] %","ev3.motorTurnClockwise":"motor [PORT] cap aquí durant [TIME] segons","ev3.motorTurnCounterClockwise":"motor [PORT] cap allà durant [TIME] segons","ev3.whenBrightnessLessThan":"quan la brillantor < [DISTANCE]","ev3.whenButtonPressed":"quan el botó [PORT] es premi","ev3.whenDistanceLessThan":"quan la distància < [DISTANCE]","gdxfor.getAcceleration":"acceleració [DIRECTION]","gdxfor.getForce":"força","gdxfor.getSpin":"velocitat de gir [DIRECTION]","gdxfor.getTilt":"angle d\'inclinació [TILT]","gdxfor.isFreeFalling":"caient?","gdxfor.isTilted":"inclinat [TILT]?","gdxfor.pulled":"tirat","gdxfor.pushed":"empès","gdxfor.shaken":"es sacsegi","gdxfor.startedFalling":"ha començat a caure","gdxfor.tiltDirectionMenu.any":"qualsevol","gdxfor.tiltDirectionMenu.back":"darrere","gdxfor.tiltDirectionMenu.front":"davant","gdxfor.tiltDirectionMenu.left":"esquerra","gdxfor.tiltDirectionMenu.right":"dreta","gdxfor.turnedFaceDown":"girat cara avall","gdxfor.turnedFaceUp":"girat cara amunt","gdxfor.whenForcePushedOrPulled":"quan el sensor de força [PUSH_PULL]","gdxfor.whenGesture":"quan [GESTURE]","gdxfor.whenTilted":"quan s\'inclini [TILT]","makeymakey.downArrow":"fletxa avall","makeymakey.downArrowShort":"avall","makeymakey.leftArrow":"fletxa esquerra","makeymakey.leftArrowShort":"esquerra","makeymakey.rightArrow":"fletxa dreta","makeymakey.rightArrowShort":"dreta","makeymakey.spaceKey":"espai","makeymakey.upArrow":"fletxa amunt","makeymakey.upArrowShort":"amunt","makeymakey.whenKeyPressed":"quan la tecla [KEY] es premi","makeymakey.whenKeysPressedInOrder":"quan [SEQUENCE] es premin en ordre","microbit.buttonsMenu.any":"qualsevol","microbit.clearDisplay":"no mostris res","microbit.defaultTextToDisplay":"Hola!","microbit.displaySymbol":"mostra [MATRIX]","microbit.displayText":"mostra text [TEXT]","microbit.gesturesMenu.jumped":"salti","microbit.gesturesMenu.moved":"es mogui","microbit.gesturesMenu.shaken":"es sacsegi","microbit.isButtonPressed":"[BTN] botó premut?","microbit.isTilted":"inclinat [DIRECTION]?","microbit.pinStateMenu.off":"apaga","microbit.pinStateMenu.on":"activa","microbit.tiltAngle":"angle d\'inclinació [DIRECTION]","microbit.tiltDirectionMenu.any":"qualsevol","microbit.tiltDirectionMenu.back":"darrere","microbit.tiltDirectionMenu.front":"al davant","microbit.tiltDirectionMenu.left":"esquerra","microbit.tiltDirectionMenu.right":"dreta","microbit.whenButtonPressed":"quan el botó [BTN] es premi","microbit.whenGesture":"quan [GESTURE]","microbit.whenPinConnected":"quan el pin [PIN] connectat","microbit.whenTilted":"quan s\'inclini [DIRECTION]","music.categoryName":"Música","music.changeTempo":"augmenta [TEMPO] el tempo","music.drumBass":"(2) Bombo","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabassa","music.drumClaves":"(9) Claus","music.drumClosedHiHat":"(6) Xarles tancat","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Esquella","music.drumCrashCymbal":"(4) Platets","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Aplaudiment","music.drumOpenHiHat":"(5) Xarles obert","music.drumSideStick":"(3) Cop lateral","music.drumSnare":"(1) Tambor militar petit","music.drumTambourine":"(7) Tamborí","music.drumTriangle":"(12) Triangle","music.drumVibraslap":"(17) Vibra-Slap","music.drumWoodBlock":"(10) Bloc de fusta","music.getTempo":"tempo","music.instrumentBass":"(6) Baix","music.instrumentBassoon":"(14) Fagot","music.instrumentCello":"(8) Violoncel","music.instrumentChoir":"(15) Cor","music.instrumentClarinet":"(10) Clarinet","music.instrumentElectricGuitar":"(5) Guitarra elèctrica","music.instrumentElectricPiano":"(2) Piano elèctric","music.instrumentFlute":"(12) Flauta","music.instrumentGuitar":"(4) Guitarra","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Caixa de música","music.instrumentOrgan":"(3) Orgue","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxòfon","music.instrumentSteelDrum":"(18) Tambor d\'acer","music.instrumentSynthLead":"(20) Sintetitzador solista","music.instrumentSynthPad":"(21) Sintetitzador de fons","music.instrumentTrombone":"(9) Trombó","music.instrumentVibraphone":"(16) Vibràfon","music.instrumentWoodenFlute":"(13) Flauta dolça","music.midiPlayDrumForBeats":"toca el tambor [DRUM] durant [BEATS] pulsacions","music.midiSetInstrument":"fixa l\'instrument a [INSTRUMENT]","music.playDrumForBeats":"toca el tambor [DRUM] durant [BEATS] pulsacions","music.playNoteForBeats":"toca la nota [NOTE] durant [BEATS] pulsacions","music.restForBeats":"espera [BEATS] pulsacions","music.setInstrument":"fixa instrument a [INSTRUMENT]","music.setTempo":"fixa el tempo a [TEMPO]","pen.categoryName":"Llapis","pen.changeColorParam":"augmenta [COLOR_PARAM] del llapis en [VALUE]","pen.changeHue":"augmenta [HUE] el color del llapis","pen.changeShade":"augmenta [SHADE] la intensitat del llapis","pen.changeSize":"augmenta [SIZE] la mida del llapis","pen.clear":"esborra-ho tot","pen.colorMenu.brightness":"brillantor","pen.colorMenu.color":"color","pen.colorMenu.saturation":"saturació","pen.colorMenu.transparency":"transparència","pen.penDown":"baixa el llapis","pen.penUp":"puja el llapis","pen.setColor":"fixa el color del llapis a [COLOR]","pen.setColorParam":"fixa [COLOR_PARAM] del llapis a [VALUE]","pen.setHue":"fixa el color del llapis a [HUE]","pen.setShade":"fixa la intensitat del llapis a [SHADE]","pen.setSize":"fixa la mida del llapis a [SIZE]","pen.stamp":"estampa","text2speech.alto":"contralt","text2speech.categoryName":"De text a parla","text2speech.defaultTextToSpeak":"hola","text2speech.giant":"gegant","text2speech.kitten":"gatet","text2speech.setLanguageBlock":"fixa l\'idioma a [LANGUAGE]","text2speech.setVoiceBlock":"fixa la veu a [VOICE]","text2speech.speakAndWaitBlock":"parla [WORDS]","text2speech.squeak":"veu divertida","text2speech.tenor":"tenor","translate.categoryName":"Tradueix","translate.defaultTextToTranslate":"hola","translate.translateBlock":"tradueix [WORDS] a [LANGUAGE]","translate.viewerLanguage":"idioma","videoSensing.categoryName":"Captura de vídeo","videoSensing.direction":"direcció","videoSensing.motion":"moviment","videoSensing.off":"apaga","videoSensing.on":"activa","videoSensing.onFlipped":"voltejat actiu","videoSensing.setVideoTransparency":"fixa la transparència del vídeo a [TRANSPARENCY]","videoSensing.sprite":"personatge","videoSensing.stage":"escenari","videoSensing.videoOn":"vídeo [ATTRIBUTE] a [SUBJECT]","videoSensing.videoToggle":"posa vídeo [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"quan el moviment de vídeo > [REFERENCE]","wedo2.getDistance":"distància","wedo2.getTiltAngle":"angle d\'inclinació [TILT_DIRECTION]","wedo2.isTilted":"inclinat [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"cap aquí","wedo2.motorDirection.forward":"cap allà","wedo2.motorDirection.reverse":"invertit","wedo2.motorId.a":"motor A","wedo2.motorId.all":"tots els motors","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"apaga motor [MOTOR_ID]","wedo2.motorOn":"activa el motor [MOTOR_ID]","wedo2.motorOnFor":"activa [MOTOR_ID] durant [DURATION] segons","wedo2.playNoteFor":"toca la nota [NOTE] durant [DURATION] segons","wedo2.setLightHue":"fixa el color del llum a [HUE]","wedo2.setMotorDirection":"fixa la direcció de [MOTOR_ID] a [MOTOR_DIRECTION]","wedo2.startMotorPower":"fixa la potència de [MOTOR_ID] a [POWER]","wedo2.tiltDirection.any":"qualsevol","wedo2.tiltDirection.down":"avall","wedo2.tiltDirection.left":"esquerra","wedo2.tiltDirection.right":"dreta","wedo2.tiltDirection.up":"amunt","wedo2.whenDistance":"quan la distància [OP] [REFERENCE]","wedo2.whenTilted":"quan la inclinació [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Color","paint.paintEditor.saturation":"Saturació","paint.paintEditor.brightness":"Lluminositat","paint.paintEditor.costume":"Vestit","paint.paintEditor.group":"Agrupa","paint.paintEditor.ungroup":"Desagrupa","paint.paintEditor.undo":"Desfés","paint.paintEditor.redo":"Torna-hi","paint.paintEditor.forward":"Endavant","paint.paintEditor.backward":"Enrere","paint.paintEditor.front":"Al davant","paint.paintEditor.back":"Al darrere","paint.paintEditor.more":"Més","paint.modeTools.brushSize":"Mida","paint.modeTools.eraserSize":"Ample de l\'esborrador","paint.modeTools.copy":"Copia","paint.modeTools.paste":"Enganxa","paint.modeTools.delete":"Elimina","paint.modeTools.curved":"Corbat","paint.modeTools.pointed":"Afila conjunt de punts","paint.modeTools.thickness":"Gruix","paint.modeTools.flipHorizontal":"Gira horitzontalment","paint.modeTools.flipVertical":"Gira verticalment","paint.modeTools.filled":"Omplert","paint.modeTools.outlined":"Contorn","paint.paintEditor.bitmap":"Converteix a mapa de bits","paint.paintEditor.vector":"Converteix a vectorial","paint.paintEditor.fill":"Omple","paint.paintEditor.stroke":"Línia exterior","paint.brushMode.brush":"Pinzell","paint.eraserMode.eraser":"Goma d\'esborrar","paint.fillMode.fill":"Omple","paint.lineMode.line":"Línia","paint.ovalMode.oval":"Cercle","paint.rectMode.rect":"Rectangle","paint.reshapeMode.reshape":"Redibuixa","paint.roundedRectMode.roundedRect":"Rectangle amb cantonades arrodonides","paint.selectMode.select":"Selecciona","paint.textMode.text":"Text","paint.colorPicker.swap":"Intercanvia","tw.alerts.autosaving":"S\'està creant un punt de restauració...","tw.alerts.lostPeripheralConnection":"S\'ha perdut la connexió a {extensionName}.","tw.alerts.savedToDisk":"Desat al teu ordinador.","tw.backpack.rename":"Nou nom:","tw.browserModal.desc":"Assegura\'t que fas servir una versió recent de Google Chrome, Mozilla Firefox, Microsoft Edge o Apple Safari.","tw.cantUseCloud":"Tot i que pots crear variables al núvol, no funcionaran tret que aquest projecte es carregui a Scratch o es converteixi amb una eina com ara {packager}.","tw.changeUsername.cannotChangeWhileRunning":"El nom d\'usuari no es pot modificar si el projecte s\'està executant.","tw.cloudVariableBadge":"Aquest projecte utilitza variables al núvol. El TurboWarp utilitza el seu propi servidor variable de núvol independent de Scratch. Vés amb molt de compte amb la suplantació d\'identitat, ja que qualsevol pot canviar el seu nom d\'usuari per qualsevol.{learnMore}","tw.code":"Codi font","tw.confirmIncompatibleExtension":"Aquesta extensió és incompatible amb Scratch. Els projectes fets amb ell no es poden penjar al lloc web del Scratch. Segur que vols activar-lo?","tw.customExtension.description":"Carrega extensions personalitzades desde d\'una URL. Per a desenvolupadors. Experimental.","tw.customExtension.name":"Extensió personalitzada","tw.featuredProjectsStudio":"Veure l\'estudi a Scratch.","tw.feedback":"Comentaris i errors interns","tw.feedbackButton":"Comentaris del TurboWarp","tw.footer.credits":"Crèdits","tw.footer.disclaimer":"TurboWarp no està afiliat a Scratch, al Scratch Team o la Scratch Foundation.","tw.footer.donate":"Fes una donació","tw.footer.embed":"Incrustació web","tw.footer.fosshost":"Allotjament web proporcionat per Fosshost","tw.footer.parameters":"Paràmetres d\'URL","tw.footer.translate":"Ajudeu-nos a traduir el TurboWarp","tw.gui.crashMessage.description":"Ho sentim molt, però sembla que la pàgina s\'ha bloquejat. Actualitza la pàgina per tornar-ho a provar.","tw.gui.defaultProjectTitle":"Projecte","tw.guiDefaultTitle":"Executa projectes del Scratch més ràpid","tw.home.credit":"Notes i crèdits","tw.home.description":"TurboWarp és un mod del Scratch que compila els projectes al JavaScript per fer-los funcionar molt més ràpid. Prova introduint l\'identificador/ID o l\'URL del projecte a dalt o triant un projecte destacat a continuació.","tw.home.instructions":"Instruccions","tw.input.tooltip":"Copia i enganxa un enllaç d\'un projecte del Scratch aquí!","tw.interpolationEnabled":"Interpolació","tw.invalidParameters.clones":"El paràmetre d\'URL \\"clone\\" no és correcte","tw.invalidParameters.fps":"El paràmetre d\'URL \\"fps\\" no és correcte","tw.loadError":"No s\'ha pogut carregar el projecte: {error}","tw.loader.assets.known":"Baixant assets ({complete}/{total}) …","tw.loader.assets.unknown":"Baixant assets…","tw.loader.data":"S\'estan baixant les dades del projecte...","tw.loader.generic":"S\'està carregant el projecte...","tw.menuBar.60off":"Desactiva el mode de 60 FPS","tw.menuBar.60on":"Activa el mode de 60 FPS","tw.menuBar.advanced":"Avançat","tw.menuBar.changeUsername":"Canvia el nom d\'usuari","tw.menuBar.cloudOff":"Desactiva les variables al núvol","tw.menuBar.cloudOn":"Activa les variables al núvol","tw.menuBar.cloudUnavailable":"Les variables al núvol no estan disponibles","tw.menuBar.cloudUnavailableAlert":"No es poden utilitzar variables del núvol, probablement perquè heu obert l\'editor.","tw.menuBar.loadRestorePoint":"Carregar punt de restauració","tw.menuBar.moreSettings":"Configuració avançada","tw.menuBar.newFramerate":"Nova velocitat de fotogrames:","tw.menuBar.package":"Empaquetar projecte","tw.menuBar.reportError1":"Alguns scripts no s\'han pogut compilar.","tw.menuBar.reportError2":"Això és un error. Informeu-ho si us plau.","tw.menuBar.saveAs":"Desa com a {file}","tw.menuBar.seeInside":"Veure per dins","tw.oldDownload":"Desa com fitxer separat...","tw.paint.alpha":"Opacitat","tw.privacy":"Política de privacitat","tw.restorePoint.confirm":"L\'editor registra automàticament un punt de restauració en cas que alguna cosa surti malament i oblidis desar els canvis. No hauríes de confiar en això i no és pot garantir que recuperi el vostre projecte. Vols intentar carregar-lo?","tw.restorePoint.loadFail":"No s\'ha pogut carregar el punt de restauració: {error}","tw.saveAs":"Desa com a...","tw.saveTo":"Desa a {file}","tw.scratchUnsafeCloud":"Si fass aquesta variable al núvol, el projecte superarà el límit de {number} variables de l\'Scratch i algunes variables no funcionaran si penges el projecte a l\'Scratch.","tw.settingsModal.customStageSize":"Mida personalitzada de l\'escenari:","tw.settingsModal.customStageSizeHelp":"Canvia la mida de l\'escenari Scratch de 480x360 a una altra mida. Prova 640x360 per fer que l\'escenari sigui panoràmic. Molt pocs projectes ho gestionen correctament.","tw.settingsModal.dangerZone":"Zona perillosa","tw.settingsModal.disableCompiler":"Desactiva el compilador","tw.settingsModal.disableCompilerHelp":"Desactiva el compilador del TurboWarp. És possible que vulguis activar-lo mentre edites projectes perquè els scripts s\'actualitzin immediatament. En cas contrari, no hauríes d\'activar-ho mai.","tw.settingsModal.featured":"Destacat","tw.settingsModal.fps":"60 FPS (FPS Personalitzats)","tw.settingsModal.fpsHelp":"Executa scripts 60 vegades per segon en lloc de 30. La gran majoria dels projectes no executaran correctament amb aquesta funció. Hauríes de provar la interpolació amb el mode 60 FPS desactivat si és el cas.{customFramerate}.","tw.settingsModal.fpsHelp.customFramerate":"Fes click per utilitzar una velocitat de fotogrames diferent de 30 o 60","tw.settingsModal.help":"Feu click per obtenir ajuda","tw.settingsModal.highQualityPen":"Llapis d\'alta qualitat","tw.settingsModal.highQualityPenHelp":"Permet que els projectes amb l\'extensiu de llapis es mostrin a resolucions més altes i desactiva alguns arrodoniments de coordenades a l\'editor. No tots els projectes es beneficien d\'aquesta eina i pot afectar el rendiment.","tw.settingsModal.infiniteClones":"Clons infinits","tw.settingsModal.infiniteClonesHelp":"Desactiva el límit de 300 clons d\'Scratch.","tw.settingsModal.interpolation":"Interpolació","tw.settingsModal.interpolationHelp":"Fa que els projectes semblin més suaus i fluids interpolant el moviment dels personatges. La interpolació no s\'ha d\'utilitzar en projectes 3D, traçadors de raigs/raytracers, projectes amb l\'extensió de llapis i projectes amb lag, ja que la interpolació farà que funcionin més lent sense que semblin suaus.","tw.settingsModal.largeStageWarning":"No es recomana utilitzar una mida d\'escenari personalitzada tan gran! En comptes d\'això, utilitza una mida inferior amb la mateixa relació d\'aspecte i deixa que el mode de pantalla completa l\'augmenti perquè coincideixi amb la pantalla de l\'usuari.","tw.settingsModal.removeFencing":"Eliminar les limitacions de pantalla","tw.settingsModal.removeFencingHelp":"Permet que els personatges es moguin fora de la pantalla, siguin tan grans o tan petits com vulguin, i fa que els blocs que es pugin fer click funcionin fora de la pantalla.","tw.settingsModal.removeLimits":"Elimina els límits","tw.settingsModal.removeMiscLimits":"Treure límits miscel·lanis","tw.settingsModal.removeMiscLimitsHelp":"Elimina els límits d\'efectes de so i els límits de mida del llapis.","tw.settingsModal.storeProjectOptions":"Emmagatzema la configuració al projecte","tw.settingsModal.storeProjectOptionsHelp":"Emmagatzema la configuració seleccionada al projecte perquè s\'apliquin automàticament quan TurboWarp carregui aquest projecte. El temporitzador Warp i el \\"Desactiva el compilador\\" no es desaran.","tw.settingsModal.title":"Configuració avançada","tw.settingsModal.warpTimer":"Temporitzador Warp","tw.settingsModal.warpTimerHelp":"Fa que els scripts comprovin si estan encallars en un bucle llarg o infinit i s\'executen a una velocitat de fotogrames baixa en lloc d\'enganxar-se fins que s\'acabi el bucle. Això corregeix la majoria de crashes, però té un impacte significatiu en el rendiment, de manera que només està activat de manera predeterminada a l\'editor.","tw.spriteSelectorItem.rename":"renombra","tw.studioview.authorAttribution":"fet per {author}","tw.studioview.error":"S\'ha produït un error al carregar la següent pàgina dels projectes.","tw.studioview.hoverText":"{title}, fet per {author}","tw.twExtension.description":"Blocs estrany snous. No compatible amb l\'Scratch.","tw.twExtension.name":"Blocs del TurboWarp","tw.unshared.1":"Els projectes no compartits ja no seran accessibles amb el seu ID en algun moment a causa dels propers canvis a l\'API de Scratch.","tw.unshared.2":"Per a més informació, visita: {link}","tw.usernameModal.help":"Aquest valor s\'emmagatzemarà a les del vostre explorador. Es pot registrar quan interaccionis amb projectes que contenen variables al núvol.","tw.usernameModal.help2":"Els valors que no corresponen a un compte del Scratch vàlid normalment seran rebutjats pel nostre servidor de variables al núvol. Us recomanem que ho deixis tal qual o que el canvïs pel teu nom d\'usuari del Scratch.","tw.usernameModal.mustChange":"Ho sentim, el servidor de variables al núvol creu que el teu nom d\'usuari pot ser insegur. Si us plau, canvia-ho per una altre o {resetIt}.","tw.usernameModal.mustChange.resetIt":"reseteja-ho (recomanat)","tw.usernameModal.reset":"Restableix","tw.usernameModal.title":"Canvia el nom d\'usuari","tw.viewFeaturedProjects":"Fes click per veure els projectes destacats.","tw.viewOnScratch":"Veure a l\'Scratch","tw.webglModal.description":"Desafortunadament, sembla que el teu explorador o ordinador {webGlLink}. Aquesta tecnologia és necessària perquè aquest lloc web funcioni. Prova d\'actualitzar el navegador i els controladors/drivers de gràfics o reinicieu l\'ordinador."},"cs":{"gui.alerts.tryAgain":"Zkusit znovu","gui.alerts.download":"Stáhnout","gui.connection.reconnect":"Znovu připojit","gui.backpack.costumeLabel":"kostým","gui.backpack.soundLabel":"zvuk","gui.backpack.scriptLabel":"skript","gui.backpack.spriteLabel":"postava","gui.backpack.header":"Batoh","gui.backpack.errorBackpack":"Chyba při načítání batohu","gui.backpack.loadingBackpack":"Nahrávám..","gui.backpack.more":"Více","gui.backpack.emptyBackpack":"Batoh je prázdný","gui.unsupportedBrowser.label":"Prohlížeč není podporován","gui.cards.all-tutorials":"Návody","gui.cards.shrink":"Zmenši","gui.cards.expand":"Zvětši","gui.cards.close":"Zavřít","gui.cards.more-things-to-try":"Více věcí na vyzkoušení!","gui.cards.see-more":"Další informace","gui.comingSoon.message1":"Neboj, pracujeme na tom {emoji}","gui.comingSoon.message2":"Již brzy...","gui.comingSoon.message3":"Pracujeme na tom {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Nenalezena žádná zařízení","gui.connection.auto-scanning.prescan":"Umísti své zařízení na dosah, pak začni vyhledávat.","gui.connection.auto-scanning.pressbutton":"Stiskni tlačítko na svém zařízení.","gui.connection.auto-scanning.start-search":"Start vyhledávání","gui.connection.connecting-searchbutton":"Vyhledávám...","gui.connection.auto-scanning.try-again":"Zkus znovu","gui.connection.connected":"Propojeno","gui.connection.disconnect":"Odpojit","gui.connection.go-to-editor":"Jít do editoru","gui.connection.connecting-cancelbutton":"Propojování...","gui.connection.error.errorMessage":"Běda, zdá se, že se něco pokazilo.","gui.connection.error.tryagainbutton":"Zkus znovu","gui.connection.error.helpbutton":"Pomoc","gui.connection.peripheral-name-label":"Název zařízení","gui.connection.connect":"Propojit","gui.connection.scanning.lookingforperipherals":"Hledám zařízení","gui.connection.scanning.noPeripheralsFound":"Nenalezena žádná zařízení","gui.connection.scanning.instructions":"Vyber své zařízení ze seznamu výše.","gui.connection.search":"Aktualizovat","gui.connection.unavailable.installscratchlink":"Ujisti se, že máš Scratch Link nainstalovaný a spuštěný","gui.connection.unavailable.enablebluetooth":"Zkontroluj, zda máš zapnuté Bluetooth","gui.connection.unavailable.tryagainbutton":"Zkus znovu","gui.connection.unavailable.helpbutton":"Pomoc","gui.controls.go":"Spustit","gui.controls.stop":"Zastavit","gui.crashMessage.label":"Jejda! Něco se pokazilo.","gui.crashMessage.errorNumber":"Tvá chyba byla evidována s id {errorId}","gui.crashMessage.reload":"Znovu načíst","gui.customProcedures.myblockModalTitle":"Vytvořit blok","gui.customProcedures.addAnInputNumberText":"Přidej parametr","gui.customProcedures.numberTextType":"číslo nebo text","gui.customProcedures.addAnInputBoolean":"Přidat vstup","gui.customProcedures.booleanType":"logický","gui.customProcedures.addALabel":"Přidej popisek","gui.customProcedures.runWithoutScreenRefresh":"Spustit bez obnovy obrazovky","gui.customProcedures.cancel":"Zrušit","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Směr","gui.directionPicker.rotationStyles.allAround":"Dokola","gui.directionPicker.rotationStyles.leftRight":"Vlevo/vpravo","gui.directionPicker.rotationStyles.dontRotate":"Neotáčet","gui.gui.addExtension":"Přidej rozšíření","gui.gui.codeTab":"Scénáře","gui.gui.backdropsTab":"Pozadí","gui.gui.costumesTab":"Kostýmy","gui.gui.soundsTab":"Zvuky","gui.extensionLibrary.comingSoon":"Již brzy","gui.extensionLibrary.requires":"Vyžaduje","gui.extensionLibrary.collaboration":"Spolupráce s","gui.library.filterPlaceholder":"Hledat","gui.library.allTag":"Všechno","gui.loader.headline":"Nahrávám projekt...","gui.loader.creating":"Vytváření projektu","gui.authorInfo.byUser":"od uživatele {username}","gui.menuBar.seeProjectPage":"Shlédni stránku projektu","gui.menuBar.LanguageSelector":"výběr jazyka","gui.menuBar.tutorialsLibrary":"Návody","gui.menuBar.restoreSprite":"Obnovit postavu","gui.menuBar.restoreSound":"Obnovit zvuk","gui.menuBar.restoreCostume":"Obnovit kostým","gui.menuBar.restore":"Obnovit","gui.menuBar.saveNow":"Uložit aktuální stav","gui.menuBar.saveAsCopy":"Uložit jako kopii","gui.menuBar.remix":"Vytvoř si kopii","gui.menuBar.new":"Nový","gui.menuBar.file":"Soubor","gui.menuBar.downloadToComputer":"Ulož do svého počítače","gui.menuBar.edit":"Upravit","gui.menuBar.turboModeOff":"Vypni turbo režim","gui.menuBar.turboModeOn":"Zapni turbo režim","gui.gui.projectTitlePlaceholder":"Název projektu","gui.menuBar.isShared":"Sdílené","gui.menuBar.share":"Sdílet","gui.modal.help":"Pomoc","gui.modal.back":"Zpět","gui.monitor.listMonitor.empty":"(prázdný)","gui.monitor.listMonitor.listLength":"délka {length}","gui.monitor.contextMenu.default":"normální zobrazení","gui.monitor.contextMenu.large":"zvětšené zobrazení","gui.monitor.contextMenu.slider":"posuvník","gui.monitor.contextMenu.sliderRange":"změnit rozsah posuvníku","gui.monitor.contextMenu.import":"import","gui.monitor.contextMenu.export":"export","gui.monitor.contextMenu.hide":"skryj se","gui.playButton.play":"Hraj","gui.playButton.stop":"Zastav","gui.gui.variableScopeOptionAllSprites":"Pro všechny postavy","gui.gui.variableScopeOptionSpriteOnly":"Jen pro tuto postavu","gui.gui.cloudVariableOption":"cloudová proměnná (uložená na serveru)","gui.gui.variablePromptAllSpritesMessage":"Tato proměnná bude dostupná všem postavám.","gui.gui.listPromptAllSpritesMessage":"Tento seznam bude dostupný pro všechny postavy.","gui.prompt.cancel":"Zrušit","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Zastavit","gui.playbackStep.playMsg":"Přehrát","gui.playbackStep.loadingMsg":"Nahrávám..","gui.playbackStep.saveMsg":"Uložit","gui.playbackStep.reRecordMsg":"Znovu nahrát","gui.recordModal.title":"Nahrát zvuk","gui.recordingStep.beginRecord":"Začni natáčet kliknutím na tlačítko níže","gui.recordingStep.permission":"{arrow}Potřebujeme povolení k používání tvého mikrofonu","gui.recordingStep.stop":"Zastavit natáčení","gui.recordingStep.record":"Nahraj","gui.sliderModal.min":"Nejmenší hodnota","gui.sliderModal.max":"Největší hodnota","gui.sliderModal.title":"Změnit rozsah posuvníku","gui.sliderPrompt.cancel":"Zrušit","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Zvuk","gui.soundEditor.play":"Hraj","gui.soundEditor.stop":"Zastavit","gui.soundEditor.copy":"Zkopírovat","gui.soundEditor.paste":"Vložit","gui.soundEditor.copyToNew":"Zkopírovat do nového","gui.soundEditor.delete":"Odstranit","gui.soundEditor.save":"Uložit","gui.soundEditor.undo":"Zpět","gui.soundEditor.redo":"Znovu","gui.soundEditor.faster":"Rychleji","gui.soundEditor.slower":"Pomaleji","gui.soundEditor.echo":"Ozvěna","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Zesílit","gui.soundEditor.softer":"Zeslabit","gui.soundEditor.reverse":"Pozpátku","gui.soundEditor.fadeOut":"Postupné ztišení","gui.soundEditor.fadeIn":"Postupný náběh","gui.soundEditor.mute":"Ztišit","gui.SpriteInfo.spritePlaceholder":"Název","gui.SpriteInfo.sprite":"Postava","gui.SpriteInfo.show":"Ukázat","gui.SpriteInfo.size":"Velikost","gui.spriteSelectorItem.contextMenuDuplicate":"zkopíruj","gui.spriteSelectorItem.contextMenuExport":"export","gui.spriteSelectorItem.contextMenuDelete":"smazat","gui.spriteSelector.addSpriteFromLibrary":"Vyber postavu","gui.spriteSelector.addSpriteFromPaint":"Kreslit","gui.spriteSelector.addSpriteFromSurprise":"Překvapení","gui.spriteSelector.addSpriteFromFile":"Nahrát postavu","gui.stageHeader.stageSizeLarge":"Přepni na velkou scénu","gui.stageHeader.stageSizeSmall":"Přepni na malou scénu","gui.stageHeader.stageSizeFull":"Vstup do režimu celé obrazovky","gui.stageHeader.stageSizeUnFull":"Ukončit režim celé obrazovky","gui.stageHeader.fullscreenControl":"Ovládání celé obrazovky","gui.spriteSelector.addBackdropFromLibrary":"Vybrat pozadí","gui.stageSelector.addBackdropFromPaint":"Kresli","gui.stageSelector.addBackdropFromSurprise":"Překvapení","gui.stageSelector.addBackdropFromFile":"Nahrát pozadí","gui.stageSelector.stage":"Scéna","gui.stageSelector.backdrops":"Pozadí","gui.telemetryOptIn.label":"Hlášení statistik kvůli vylepšení Scratch","gui.telemetryOptIn.body1":"Tým Scratch se neustále snaží o lepší pochopení toho, jak je Scratch ve světě užíván. Pro podporu tohoto úsilí můžeš povolit programu Scratch,\\n aby zasílal automaticky informace o používání do týmu Scratch.","gui.telemetryOptIn.body2":"Sbírané informace obsahují volbu jazyka, použití bloků a některé události, jako ukládání, stahování a nahrávání projektu. NESBÍRÁME žádné osobní informace. Prosím navštiv naši stránku {privacyPolicyLink} pro další informace.","gui.telemetryOptIn.privacyPolicyLink":"Zásady ochrany osobních údajů","gui.telemetryOptIn.optInText":"Sdílet moje údaje o používání s týmem Scratch","gui.telemetryOptIn.optInTooltip":"Povolit telemetrii","gui.telemetryOptIn.optOutText":"Nesdílet moje údaje o používání s týmem Scratch","gui.telemetryOptIn.optOutTooltip":"Vypnout telemetrii","gui.telemetryOptIn.settingWasUpdated":"Tvoje nastavení bylo aktualizováno","gui.telemetryOptIn.buttonClose":"Zavřít","gui.turboMode.active":"Turbo režim","gui.webglModal.label":"Tvůj prohlížeč nepodporuje WebGL","gui.webglModal.webgllink":"nepodporuje WebGL","gui.costumeLibrary.chooseABackdrop":"Vybrat pozadí","gui.costumeLibrary.chooseACostume":"Vyber kostým","gui.costumeTab.addBackdropFromLibrary":"Vybrat pozadí","gui.costumeTab.addCostumeFromLibrary":"Vyber kostým","gui.costumeTab.addBlankCostume":"Kreslit","gui.costumeTab.addSurpriseCostume":"Překvapení","gui.costumeTab.addFileBackdrop":"Nahrát pozadí","gui.costumeTab.addFileCostume":"Nahrát kostým","gui.extensionLibrary.chooseAnExtension":"Vyber rozšíření","gui.extensionLibrary.extensionUrl":"Zadej URL rozšíření","gui.monitors.importListColumnPrompt":"Který sloupec se má použít (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Nemohu začít nahrávat","gui.soundLibrary.chooseASound":"Vybrat zvuk","gui.soundTab.fileUploadSound":"Nahrát zvuk","gui.soundTab.surpriseSound":"Překvapení","gui.soundTab.recordSound":"Nahraj","gui.soundTab.addSoundFromLibrary":"Vyber zvuk.","gui.spriteLibrary.chooseASprite":"Vyber si postavu","gui.tipsLibrary.tutorials":"Vyber si návod","gui.alerts.createsuccess":"Vytvořen nový projekt.","gui.alerts.createcopysuccess":"Projekt uložen jako kopie.","gui.alerts.createremixsuccess":"Projekt uložen jako remix.","gui.alerts.creating":"Vytvářím nový...","gui.alerts.creatingCopy":"Kopíruji projekt...","gui.alerts.creatingRemix":"Remixuji projekt...","gui.alerts.creatingError":"Nelze vytvořit projekt. Zkuste to znovu!","gui.alerts.savingError":"Projekt nemohl být uložen.","gui.alerts.savesuccess":"Projekt uložen.","gui.alerts.saving":"Ukládám projekt...","gui.alerts.cloudInfo":"Všimni si, prosím, že cloudové proměnné podporují jen čísla, ne písmena nebo symboly. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Další poučení.","gui.alerts.importing":"Importování...","gui.defaultProject.variable":"moje proměnná","gui.extension.music.name":"Hudba","gui.extension.music.description":"Hraní na nástroje a bicí.","gui.extension.pen.name":"Pero","gui.extension.pen.description":"Kreslení s tvými postavami.","gui.extension.videosensing.name":"Vnímání videa","gui.extension.videosensing.description":"Zjišťování pohybu kamerou.","gui.extension.text2speech.name":"Text na hlas","gui.extension.text2speech.description":"Nech svůj projekt mluvit.","gui.extension.translate.name":"Překlad","gui.extension.translate.description":"Překládání textu do mnoha jazyků.","gui.extension.makeymakey.description":"Udělej vše do klíče.","gui.extension.microbit.description":"Propojení tvých projektů se světem.","gui.extension.microbit.connectingMessage":"Propojování","gui.extension.ev3.description":"Stavění interaktivních robotů a mnoho dalšího.","gui.extension.ev3.connectingMessage":"Propojuje se. Ujisti, se že PIN na svém EV3 máš nastavený na 1234.","gui.extension.boost.description":"Oživit robotická stvoření.","gui.extension.boost.connectingMessage":"Propojování","gui.extension.wedo2.description":"Stavění s motory a čidly.","gui.extension.wedo2.connectingMessage":"Propojování","gui.extension.gdxfor.description":"Vnímá strkání, tažení, pohyb a točení.","gui.extension.gdxfor.connectingMessage":"Propojování","gui.libraryTags.all":"Všechno","gui.libraryTags.animals":"Zvířata","gui.libraryTags.dance":"Tanec","gui.libraryTags.effects":"Efekty","gui.libraryTags.fantasy":"Fantazie","gui.libraryTags.fashion":"Móda","gui.libraryTags.food":"Jídlo","gui.libraryTags.indoors":"Uvnitř","gui.libraryTags.loops":"Smyčky","gui.libraryTags.music":"Hudba","gui.libraryTags.notes":"Noty","gui.libraryTags.outdoors":"Vnější","gui.libraryTags.patterns":"Vzory","gui.libraryTags.people":"Lidé","gui.libraryTags.percussion":"Bicí","gui.libraryTags.space":"Vesmír","gui.libraryTags.sports":"Sporty","gui.libraryTags.underwater":"Podvodní","gui.libraryTags.voice":"Hlasy","gui.libraryTags.wacky":"Divné","gui.libraryTags.animation":"Animace","gui.libraryTags.art":"Umění","gui.libraryTags.games":"Hry","gui.libraryTags.stories":"Příběhy","gui.libraryTags.letters":"Písmena","gui.opcodeLabels.direction":"směr","gui.opcodeLabels.xposition":"x","gui.opcodeLabels.yposition":"y","gui.opcodeLabels.size":"velikost","gui.opcodeLabels.costumename":"název kostýmu","gui.opcodeLabels.costumenumber":"číslo kostýmu","gui.opcodeLabels.backdropname":"název pozadí","gui.opcodeLabels.backdropnumber":"číslo pozadí","gui.opcodeLabels.volume":"hlasitost","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"odpověď","gui.opcodeLabels.loudness":"hlasitost","gui.opcodeLabels.username":"jméno uživatele","gui.opcodeLabels.year":"rok","gui.opcodeLabels.month":"měsíc","gui.opcodeLabels.date":"den v měsíci","gui.opcodeLabels.dayofweek":"den týdne","gui.opcodeLabels.hour":"hodina","gui.opcodeLabels.minute":"minuta","gui.opcodeLabels.second":"sekunda","gui.opcodeLabels.timer":"stopky","gui.sharedMessages.backdrop":"pozadí{index}","gui.sharedMessages.costume":"kostým{index}","gui.sharedMessages.sprite":"Postava{index}","gui.sharedMessages.pop":"prask","gui.sharedMessages.replaceProjectWarning":"Nahradit obsah aktuálního projektu?","gui.sharedMessages.loadFromComputerTitle":"Načti z tvého počítače","boost.color.any":"libovolná barva","boost.color.black":"černá","boost.color.blue":"modrá","boost.color.green":"zelená","boost.color.red":"červená","boost.color.white":"bílá","boost.color.yellow":"žlutá","boost.getMotorPosition":"pozice motoru [MOTOR_REPORTER_ID]","boost.getTiltAngle":"úhel náklonu [TILT_DIRECTION]","boost.motorDirection.backward":"jinak","boost.motorDirection.forward":"takto","boost.motorDirection.reverse":"pozpátku","boost.motorOff":"vypni motor [MOTOR_ID]","boost.motorOn":"zapni motor [MOTOR_ID]","boost.motorOnFor":"zapni motor [MOTOR_ID] na [DURATION] sekundy","boost.motorOnForRotation":"zapni motor [MOTOR_ID] na [ROTATION] otočky","boost.seeingColor":"je vidět [COLOR] cihla?","boost.setLightHue":"nastav barvu světla na [HUE]","boost.setMotorDirection":"nastav směr motoru [MOTOR_ID] na [MOTOR_DIRECTION]","boost.setMotorPower":"nastav rychlost motoru [MOTOR_ID] na [POWER] %","boost.tiltDirection.any":"libovolný","boost.tiltDirection.down":"dolů","boost.tiltDirection.left":"vlevo","boost.tiltDirection.right":"vpravo","boost.tiltDirection.up":"nahoru","boost.whenColor":"když je vidět [COLOR] cihla","boost.whenTilted":"když nakloněný [TILT_DIRECTION_ANY]","ev3.beepNote":"hraj notu [NOTE] příštích [TIME] sekund","ev3.buttonPressed":"je tlačítko [PORT] stisknuto?","ev3.getBrightness":"jas","ev3.getDistance":"vzdálenost","ev3.getMotorPosition":"pozice motoru [PORT]","ev3.motorSetPower":"nastav motoru [PORT] rychlost [POWER] %","ev3.motorTurnClockwise":"toč motorem [PORT] ve směru hodin [TIME] sekund","ev3.motorTurnCounterClockwise":"toč motorem [PORT] proti směru hodin [TIME] sekund","ev3.whenBrightnessLessThan":"když je jas < [DISTANCE]","ev3.whenButtonPressed":"po stisku tlačítka [PORT]","ev3.whenDistanceLessThan":"když vzdálenost < [DISTANCE]","gdxfor.getAcceleration":"zrychlení [DIRECTION]","gdxfor.getForce":"síla","gdxfor.getSpin":"rychlost otáčení [DIRECTION]","gdxfor.getTilt":"úhel náklonu [TILT]","gdxfor.isFreeFalling":"padá?","gdxfor.isTilted":"nakloněné [TILT]?","gdxfor.pulled":"tažený","gdxfor.pushed":"tlačený","gdxfor.shaken":"se třese","gdxfor.startedFalling":"počátek pádu","gdxfor.tiltDirectionMenu.any":"libovolný","gdxfor.tiltDirectionMenu.back":"dozadu","gdxfor.tiltDirectionMenu.front":"dopředu","gdxfor.tiltDirectionMenu.left":"vlevo","gdxfor.tiltDirectionMenu.right":"vpravo","gdxfor.turnedFaceDown":"otočený lícem dolů","gdxfor.turnedFaceUp":"otočený lícem nahoru","gdxfor.whenForcePushedOrPulled":"když senzor síly [PUSH_PULL]","gdxfor.whenGesture":"když [GESTURE]","gdxfor.whenTilted":"když nakloněný [TILT]","makeymakey.downArrow":"šipka dolů","makeymakey.downArrowShort":"dolů","makeymakey.leftArrow":"šipka vlevo","makeymakey.leftArrowShort":"vlevo","makeymakey.rightArrow":"šipka vpravo","makeymakey.rightArrowShort":"vpravo","makeymakey.spaceKey":"mezerník","makeymakey.upArrow":"šipka nahoru","makeymakey.upArrowShort":"nahoru","makeymakey.whenKeyPressed":"když je stisknuta klávesa [KEY]","makeymakey.whenKeysPressedInOrder":"když [SEQUENCE] stisknuto postupně","microbit.buttonsMenu.any":"libovolný","microbit.clearDisplay":"smaž displej","microbit.defaultTextToDisplay":"Ahoj!","microbit.displaySymbol":"zobraz [MATRIX]","microbit.displayText":"displej textu [TEXT]","microbit.gesturesMenu.jumped":"poskočí","microbit.gesturesMenu.moved":"se pohne","microbit.gesturesMenu.shaken":"se zatřese","microbit.isButtonPressed":"tlačítko [BTN] stisknuto?","microbit.isTilted":"nakloněno [DIRECTION]?","microbit.pinStateMenu.off":"vypnuto","microbit.pinStateMenu.on":"zapnuto","microbit.tiltAngle":"úhel náklonu [DIRECTION]","microbit.tiltDirectionMenu.any":"libovolně","microbit.tiltDirectionMenu.back":"dozadu","microbit.tiltDirectionMenu.front":"dopředu","microbit.tiltDirectionMenu.left":"vlevo","microbit.tiltDirectionMenu.right":"vpravo","microbit.whenButtonPressed":"po stisku tlačítka [BTN]","microbit.whenGesture":"když [GESTURE]","microbit.whenPinConnected":"když je pin [PIN] propojený","microbit.whenTilted":"když nakloněný [DIRECTION]","music.categoryName":"Hudba","music.changeTempo":"změň tempo o [TEMPO]","music.drumBass":"(2) Velký buben","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Kabasa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) Uzavřený hi-hat","music.drumConga":"(14) Konga","music.drumCowbell":"(11) Kravský zvonec","music.drumCrashCymbal":"(4) Crash činel","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Tlesknutí","music.drumOpenHiHat":"(5) Otevřený hi-hat","music.drumSideStick":"(3) Okraj bubínku","music.drumSnare":"(1) Malý bubínek virbl","music.drumTambourine":"(7) Tamburína","music.drumTriangle":"(12) Triangl","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Dřevěný blok","music.getTempo":"tempo","music.instrumentBass":"(6) Kontrabas","music.instrumentBassoon":"(14) Fagot","music.instrumentCello":"(8) Violoncello","music.instrumentChoir":"(15) Sbor","music.instrumentClarinet":"(10) Klarinet","music.instrumentElectricGuitar":"(5) Elektronická kytara","music.instrumentElectricPiano":"(2) Elektronické piáno","music.instrumentFlute":"(12) Flétna","music.instrumentGuitar":"(4) Kytara","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Hrací skříňka","music.instrumentOrgan":"(3) Varhany","music.instrumentPiano":"(1) Piáno","music.instrumentPizzicato":"(7) Drnkání prstem","music.instrumentSaxophone":"(11) Saxofon","music.instrumentSteelDrum":"(18) Ocelový buben","music.instrumentSynthLead":"(20) Syntetizátor sólo","music.instrumentSynthPad":"(21) Syntetizátor pozadí","music.instrumentTrombone":"(9) Trombón","music.instrumentVibraphone":"(16) Vibrafon","music.instrumentWoodenFlute":"(13) Dřevěná flétna","music.midiPlayDrumForBeats":"bubnuj [DRUM] příštích [BEATS] taktů","music.midiSetInstrument":"nastav nástroj na [INSTRUMENT]","music.playDrumForBeats":"bubnuj [DRUM] příštích [BEATS] taktů","music.playNoteForBeats":"hraj notu [NOTE] příštích [BEATS] taktů","music.restForBeats":"pauza [BEATS] taktů","music.setInstrument":"nastav nástroj na [INSTRUMENT]","music.setTempo":"nastav tempo na [TEMPO]","pen.categoryName":"Pero","pen.changeColorParam":"změň [COLOR_PARAM] pera o [VALUE]","pen.changeHue":"změň barvu pera o [HUE]","pen.changeShade":"změň odstín pera o [SHADE]","pen.changeSize":"změň tloušťku pera o [SIZE]","pen.clear":"smaž","pen.colorMenu.brightness":"jas","pen.colorMenu.color":"barva","pen.colorMenu.saturation":"sytost","pen.colorMenu.transparency":"průhlednost","pen.penDown":"pero zapni","pen.penUp":"pero vypni","pen.setColor":"nastav barvu pera na [COLOR]","pen.setColorParam":"nastav [COLOR_PARAM] pera na [VALUE]","pen.setHue":"nastav barvu pera na [HUE]","pen.setShade":"nastav odstín pera na [SHADE]","pen.setSize":"nastav tloušťku pera na [SIZE]","pen.stamp":"otiskni se","text2speech.alto":"alt","text2speech.categoryName":"Text na hlas","text2speech.defaultTextToSpeak":"ahoj","text2speech.giant":"obr","text2speech.kitten":"kotě","text2speech.setLanguageBlock":"nastav jazyk na [LANGUAGE]","text2speech.setVoiceBlock":"nastav hlas na [VOICE]","text2speech.speakAndWaitBlock":"řekni [WORDS]","text2speech.squeak":"kvik","text2speech.tenor":"tenor","translate.categoryName":"Překlad","translate.defaultTextToTranslate":"ahoj","translate.translateBlock":"přelož [WORDS] do [LANGUAGE]","translate.viewerLanguage":"jazyk","videoSensing.categoryName":"Vnímání videa","videoSensing.direction":"směr","videoSensing.motion":"pohyb","videoSensing.off":"vypni","videoSensing.on":"zapni","videoSensing.onFlipped":"na převrácené straně","videoSensing.setVideoTransparency":"nastav průhlednost videa na [TRANSPARENCY]","videoSensing.sprite":"postava","videoSensing.stage":"scéna","videoSensing.videoOn":"video [ATTRIBUTE] na [SUBJECT]","videoSensing.videoToggle":"[VIDEO_STATE] video","videoSensing.whenMotionGreaterThan":"při pohybu na videu > [REFERENCE]","wedo2.getDistance":"vzdálenost","wedo2.getTiltAngle":"úhel náklonu [TILT_DIRECTION]","wedo2.isTilted":"nakloněno [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"proti směru hodin","wedo2.motorDirection.forward":"po směru hodin","wedo2.motorDirection.reverse":"pozpátku","wedo2.motorId.a":"motor A","wedo2.motorId.all":"všechny motory","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"vypni [MOTOR_ID]","wedo2.motorOn":"zapni [MOTOR_ID]","wedo2.motorOnFor":"zapni [MOTOR_ID] na [DURATION] sekund","wedo2.playNoteFor":"hraj notu [NOTE] příštích [DURATION] sekund","wedo2.setLightHue":"nastav barvu světla na [HUE]","wedo2.setMotorDirection":"nastav [MOTOR_ID] směrem [MOTOR_DIRECTION]","wedo2.startMotorPower":"pro [MOTOR_ID] nastav rychlost [POWER]","wedo2.tiltDirection.any":"libovolně","wedo2.tiltDirection.down":"dolů","wedo2.tiltDirection.left":"vlevo","wedo2.tiltDirection.right":"vpravo","wedo2.tiltDirection.up":"nahoru","wedo2.whenDistance":"když vzdálenost [OP] [REFERENCE]","wedo2.whenTilted":"když nakloněný [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Barva","paint.paintEditor.saturation":"Sytost","paint.paintEditor.brightness":"Světlost","paint.paintEditor.costume":"Kostým","paint.paintEditor.group":"Seskupit","paint.paintEditor.ungroup":"Odskupit","paint.paintEditor.undo":"Vrátit","paint.paintEditor.redo":"Znovu provést","paint.paintEditor.forward":"Dopředu","paint.paintEditor.backward":"Dozadu","paint.paintEditor.front":"Dopředu","paint.paintEditor.back":"Zpět","paint.paintEditor.more":"Více","paint.modeTools.brushSize":"Velikost","paint.modeTools.eraserSize":"Velikost gumy","paint.modeTools.copy":"Zkopírovat","paint.modeTools.paste":"Vložit","paint.modeTools.delete":"Odstranit","paint.modeTools.curved":"Zakřivit","paint.modeTools.pointed":"Zašpičatět","paint.modeTools.thickness":"Tloušťka","paint.modeTools.flipHorizontal":"Přetočit horizontálně","paint.modeTools.flipVertical":"Přetočit vertikálně","paint.modeTools.filled":"Výplň","paint.modeTools.outlined":"Obrys","paint.paintEditor.bitmap":"Převést do bitmapy","paint.paintEditor.vector":"Převeď na vektor","paint.paintEditor.fill":"Vyplnit","paint.paintEditor.stroke":"Obrys","paint.brushMode.brush":"Štětec","paint.eraserMode.eraser":"Guma","paint.fillMode.fill":"Vyplnit","paint.lineMode.line":"Úsečka","paint.ovalMode.oval":"Kružnice","paint.rectMode.rect":"Obdélník","paint.reshapeMode.reshape":"Změna tvaru","paint.roundedRectMode.roundedRect":"Zaoblený obdélník","paint.selectMode.select":"Výběr","paint.textMode.text":"Text","paint.colorPicker.swap":"Záměna","tw.alerts.autosaving":"Vytvářím bod obnovení...","tw.alerts.savedToDisk":"Uloženo na váš počítač.","tw.backpack.rename":"Nové jméno:","tw.browserModal.desc":"Ujistěte se, že používáte nejnovější verzi Google Chrome, Mozilla Firefox, Microsoft Edge nebo Apple Safari.","tw.changeUsername.cannotChangeWhileRunning":"Jméno nemůže být změněno, když běží projekt.","tw.cloudVariableBadge":"Tento projekt používá cloudové proměnné. TurboWarp používá vlastní server cloudových proměň. Dávejte pozor na falešné osoby, protože každý může změnit svoje jméno na cokoliv. {learnMore}","tw.code":"Zdrojový kód","tw.confirmIncompatibleExtension":"Toto rozšíření není kompatibilní se Scratchem. Projekty vytvořené s tímto rozšířením nemůžou být nahrány na stránku Scratch. Jste si jisti, že chcete toto rozšíření aktivovat?","tw.customExtension.description":"Načíst vlastní rozšíření z odkazů. Pro vývojáře. Experimentální.","tw.customExtension.name":"Vlastní rozšíření","tw.featuredProjectsStudio":"Zhlédnout studio na Scratchi.","tw.feedback":"Zpětná vazba & chyby","tw.feedbackButton":"Zpětná vazba TurboWarp","tw.footer.credits":"Příspěvky","tw.footer.disclaimer":"TurboWarp nemá žádnou souvislost se Scratchem, tým Scratche nebo nadace Scratche.","tw.footer.embed":"Vkládání","tw.footer.fosshost":"Hostování poskytuje Fosshost","tw.footer.parameters":"Parametry odkazu","tw.footer.translate":"Pomozte přeložit TurboWarp","tw.fps":"{framerate}FPS","tw.gui.defaultProjectTitle":"Projekt","tw.guiDefaultTitle":"Zrychlit projekty Scratch","tw.home.credit":"Poznámky a příspěvky","tw.home.description":"TurboWarp je modifikace Scratche, která kompiluje projekty do JavaScriptu, aby byly rychlejší. Zkuste vložit ID projektu, odkaz projektu nebo vyberte jeden z vybraných projektů dole.","tw.home.instructions":"Instrukce","tw.input.tooltip":"Sem zkopírujte a vložte link projektu Scratch!","tw.interpolationEnabled":"Interpolace","tw.invalidParameters.clones":"\\"clone\\" parametr odkazu je neplatný","tw.invalidParameters.fps":"\\"fps\\" parametr odkazu je neplatný","tw.loader.assets.known":"Stahuji soubory ({complete}/{total}) ...","tw.loader.assets.unknown":"Stahuji soubory ...","tw.loader.data":"Stahuji data projektu ...","tw.loader.generic":"Načítám projekt ...","tw.menuBar.60off":"Vypnout režím 60 FPS","tw.menuBar.60on":"Zapnout režim 60 FPS","tw.menuBar.addons":"Doplňky","tw.menuBar.advanced":"Pokročilé","tw.menuBar.changeUsername":"Změnit jméno","tw.menuBar.cloudOff":"Vypnout cloudové proměnné","tw.menuBar.cloudOn":"Zapnout cloudové proměnné","tw.menuBar.cloudUnavailable":"Cloudové proměnné nejsou dostupné","tw.menuBar.cloudUnavailableAlert":"Nelze použít cloudové proměnné, protože jste pravděpodobně otevřeli editor.","tw.menuBar.compileError":"{sprite}:{error}","tw.menuBar.loadRestorePoint":"Načíst bod obnovení","tw.menuBar.moreSettings":"Pokročilé nastavení","tw.menuBar.newFramerate":"Nová snímková frekvence:","tw.menuBar.reportError1":"Některé skripty se nemohly zkompilovat.","tw.menuBar.reportError2":"Toto je chyba, prosíme, nahlaste ji.","tw.menuBar.saveAs":"Uložit jako {file}","tw.menuBar.seeInside":"Pohlédnout dovnitř","tw.paint.alpha":"Průhlednost","tw.privacy":"Zásady ochrany osobních údajů","tw.saveAs":"Uložit jako...","tw.saveTo":"Uložit jako {file}","tw.settingsModal.customStageSize":"Vlastní velikost scény","tw.settingsModal.customStageSizeHelp":"Změní velikost scény Scratche z 480x360 na něco jiného. Zkuste 640x360, aby se změnilo rozlišení na širokoúhlé. Velmi málo projektů to zvládne.","tw.settingsModal.dangerZone":"Zóna nebezpečí","tw.settingsModal.disableCompiler":"Deaktivovat kompilátor","tw.settingsModal.disableCompilerHelp":"Deaktivuje kompilátor TurboWarp. Možná toto budete chtít aktivovat když upravujete projekty, aby se skripty okamžitě aktualizovaly. Jinak byste neměli toto aktivovat.","tw.settingsModal.featured":"Vybrané","tw.settingsModal.fps":"60 FPS (Vlastní FPS)","tw.settingsModal.fpsHelp":"Spouští skripty 60krát za sekundu místo 30krát za sekundu. Většina projektů nebude fungovat správně s tímto nastavením. Měli byste zkusit interpolaci s deaktivovaným režimem 60 FPS, jestli se toto děje. {customFramerate}.","tw.settingsModal.fpsHelp.customFramerate":"Klikněte sem pro použití jiné snímkové frekvence než 30 nebo 60","tw.settingsModal.help":"Klikněte sem pro pomoc","tw.settingsModal.highQualityPen":"Pero s vysokým rozlišením","tw.settingsModal.highQualityPenHelp":"Povolí projekty s perem, aby kreslili na větších rozlišeních a deaktivuje některé zaokrouhlování souřadnic v editoru. Ne všechny projekty mají výhodu v tomto nastavení a může to ovlivnit výkon. ","tw.settingsModal.infiniteClones":"Nekonečné klony","tw.settingsModal.infiniteClonesHelp":"Deaktivuje limit 300 klonů Scratche","tw.settingsModal.interpolation":"Interpolace","tw.settingsModal.interpolationHelp":"Zrychlí projekty interpolací pohybu postav. Interpolace by se neměla používat na 3D projektech, raytracerech, projekty s perem a zpomalených projektech, protože je interpolace zpomalí bez jejich zrychlení.","tw.settingsModal.largeStageWarning":"Používání vlastní obrovské velikosti scény není doporučeno! Místo toho používejte menší velikost se stejnými poměry stran a nechte režim plné obrazovky zvětšit rozlišení, aby se srovnalo s displejem uživatele.","tw.settingsModal.removeFencing":"Odstranit hranice","tw.settingsModal.removeLimits":"Odstranit limity","tw.settingsModal.removeMiscLimits":"Odstranit různé limity","tw.settingsModal.removeMiscLimitsHelp":"Odstraní limity zvukových efektů a velikosti pera.","tw.settingsModal.storeProjectOptions":"Ukládat nastavení v projektu","tw.settingsModal.title":"Pokročilé nastavení","tw.settingsModal.warpTimer":"Warp časovač","tw.settingsModal.warpTimerHelp":"Skripty zkontrolují, jestli nejsou zaseklé ve dlouhém nebo nekonečném cyklu a poběží na malé snímkové frekvenci místo zaseknutí než se cyklus dokončí. Toto opraví většinu zastavení, ale má velký vliv na výkon, takže toto je jen výchozně aktivované v editoru.","tw.spriteSelectorItem.rename":"přejmenovat","tw.studioview.authorAttribution":"od {author}","tw.studioview.error":"Při načítání další stránky projektů nastala chyba.","tw.studioview.hoverText":"{title} od {author}","tw.twExtension.description":"Zvláštní nové bloky. Nekompatibilní se Scratchem.","tw.twExtension.name":"Bloky TurboWarp","tw.usernameModal.help":"Tato hodnota bude uložena ve vašem prohlížeči. Může být zapsaná, když upravujete projekty které mají cloudové proměnné.","tw.usernameModal.mustChange":"Omlouváme se, server cloudových proměň si myslí, že vaše jméno není bezpečné. Prosíme, změňte jméno nebo {resetIt}.","tw.usernameModal.mustChange.resetIt":"obnovit (doporučeno)","tw.usernameModal.reset":"Obnovit","tw.usernameModal.title":"Změnit jméno","tw.viewFeaturedProjects":"Klikněte sem pro zhlédnutí vybraných projektů.","tw.viewOnScratch":"Zhlédnout projekt na Scratchi","tw.webglModal.description":"Bohužel to vypadá, že váš prohlížeč nebo počítač {webGlLink}. Tato technologie je potřebná pro tuto stránku. Zkuste aktualizovat váš prohlížeč a grafické ovladače, nebo restartujte počítač."},"cy":{"gui.alerts.tryAgain":"Ceisio Eto","gui.alerts.download":"Llwytho i lawr","gui.connection.reconnect":"Ailgysyslltu","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Pecyn Cefn","gui.backpack.errorBackpack":"Gwall wrth lwytho\'r pecyn cefn","gui.backpack.loadingBackpack":"Llwytho...","gui.backpack.more":"Rhagor","gui.backpack.emptyBackpack":"Mae pecyn cefn yn wag","gui.unsupportedBrowser.label":"Nid yw eich porwr yn cael ei gynnal","gui.cards.all-tutorials":"Tiwtorialau","gui.cards.shrink":"Lleihau","gui.cards.expand":"Ehangu","gui.cards.close":"Cau","gui.cards.more-things-to-try":"Pethau eraill i\'w gwneud!","gui.cards.see-more":"Gweld rhagor","gui.comingSoon.message1":"Peidiwch poeni, rydym wrthi {emoji}","gui.comingSoon.message2":"Yn Dod Cyn Bo Hir","gui.comingSoon.message3":"Rydym yn gweithio arno {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Heb ganfod dyfais","gui.connection.auto-scanning.prescan":"Cadwch eich dyfais wrth law, yna cychwyn chwilio.","gui.connection.auto-scanning.pressbutton":"Pwyswch y botwm ar eich dyfais.","gui.connection.auto-scanning.start-search":"Cychwyn Chwilio","gui.connection.connecting-searchbutton":"Chwilio...","gui.connection.auto-scanning.try-again":"Ceisio eto","gui.connection.connected":"Wedi cysylltu","gui.connection.disconnect":"Datgysylltu","gui.connection.go-to-editor":"Mynd i\'r Golygydd","gui.connection.connecting-cancelbutton":"Cysylltu...","gui.connection.error.errorMessage":"Wps! Aeth rhywbeth o\'i le","gui.connection.error.tryagainbutton":"Ceisio eto","gui.connection.error.helpbutton":"Cymorth","gui.connection.peripheral-name-label":"Enw dyfais","gui.connection.connect":"Cysylltu","gui.connection.scanning.lookingforperipherals":"Chwilio am ddyfeisiau","gui.connection.scanning.noPeripheralsFound":"Heb ganfod dyfais","gui.connection.scanning.instructions":"Dewis y ddyfais o\'r rhestr uchod","gui.connection.search":"Adnewyddu","gui.connection.unavailable.installscratchlink":"Gwnewch yn siwr fod Scratch Link wedi ei osod ac yn rhedeg","gui.connection.unavailable.enablebluetooth":"Gwirio fod Bluetooth wedi ei alluogi","gui.connection.unavailable.tryagainbutton":"Ceisio eto","gui.connection.unavailable.helpbutton":"Cymorth","gui.controls.go":"Mynd","gui.controls.stop":"Aros","gui.crashMessage.label":"Wps! Aeth rhywbeth o\'i le","gui.crashMessage.errorNumber":"Cofnodwyd eich gwall gydag id {errorId}","gui.crashMessage.reload":"Ail-lwytho","gui.customProcedures.myblockModalTitle":"Creu Bloc","gui.customProcedures.addAnInputNumberText":"Ychwanegu mewnbwn","gui.customProcedures.numberTextType":"rhif neu destun","gui.customProcedures.addAnInputBoolean":"Ychwanegu mewnbwn","gui.customProcedures.booleanType":"boole","gui.customProcedures.addALabel":"Ychwanegwch label","gui.customProcedures.runWithoutScreenRefresh":"Yn rhedeg heb adnewyddu\'r sgrin","gui.customProcedures.cancel":"Diddymu","gui.customProcedures.ok":"Iawn","gui.SpriteInfo.direction":"Cyfeiriad","gui.directionPicker.rotationStyles.allAround":"O Amgylch","gui.directionPicker.rotationStyles.leftRight":"Chwith/De","gui.directionPicker.rotationStyles.dontRotate":"Peidiwch troi","gui.gui.addExtension":"Ychwanegu Estyniad","gui.gui.codeTab":"Cod","gui.gui.backdropsTab":"Cefnlenni","gui.gui.costumesTab":"Gwisgoedd","gui.gui.soundsTab":"Seiniau","gui.extensionLibrary.comingSoon":"Yn Dod Cyn Bo Hir","gui.extensionLibrary.requires":"Angen","gui.extensionLibrary.collaboration":"Cydweithio gyda","gui.library.filterPlaceholder":"Chwilio","gui.library.allTag":"Y Cyfan","gui.loader.headline":"Llwytho Project","gui.loader.creating":"Yn Creu Project","gui.authorInfo.byUser":"gan {username}","gui.menuBar.seeProjectPage":"Gweld y Dudalen Project","gui.menuBar.LanguageSelector":"dewisydd iaith","gui.menuBar.tutorialsLibrary":"Tiwtorialau","gui.menuBar.restoreSprite":"Adfer Corlun","gui.menuBar.restoreSound":"Adfer Sain","gui.menuBar.restoreCostume":"Adfer Gwisg","gui.menuBar.restore":"Adfer","gui.menuBar.saveNow":"Cadw nawr","gui.menuBar.saveAsCopy":"Cadw fel copi","gui.menuBar.remix":"Ailgymysgu","gui.menuBar.new":"Newydd","gui.menuBar.file":"Ffeil","gui.menuBar.downloadToComputer":"Cadw i\'ch cyfrifiadur","gui.menuBar.edit":"Golygu","gui.menuBar.turboModeOff":"Diffodd y Modd Tyrbo","gui.menuBar.turboModeOn":"`Cychwyn y Modd Tyrbo","gui.gui.projectTitlePlaceholder":"Teitl project yma","gui.menuBar.isShared":"Wedi eu Rhannu","gui.menuBar.share":"Rhannu","gui.modal.help":"Cymorth","gui.modal.back":"Nôl","gui.monitor.listMonitor.empty":"(gwag)","gui.monitor.listMonitor.listLength":"hyd {length}","gui.monitor.contextMenu.default":"darlleniad arferol","gui.monitor.contextMenu.large":"sgrîn fawr","gui.monitor.contextMenu.slider":"llithrydd","gui.monitor.contextMenu.sliderRange":"newid ystod llithrydd","gui.monitor.contextMenu.import":"mewnforio","gui.monitor.contextMenu.export":"allforio","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Chwarae","gui.playButton.stop":"Aros","gui.gui.variableScopeOptionAllSprites":"Ar gyfer pob ciplun","gui.gui.variableScopeOptionSpriteOnly":"Ar gyfer y ciplun yma\'n unig","gui.gui.cloudVariableOption":"Newidyn cwmwl (cedwir ar y gweinydd)","gui.gui.variablePromptAllSpritesMessage":"Bydd y newidyn yma ar gael ar gyfer pob corlun.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Diddymu","gui.prompt.ok":"Iawn","gui.playbackStep.stopMsg":"Aros","gui.playbackStep.playMsg":"Chwarae","gui.playbackStep.loadingMsg":"Llwytho...","gui.playbackStep.saveMsg":"Cadw","gui.playbackStep.reRecordMsg":"Ail Recordio","gui.recordModal.title":"Recordio Sain","gui.recordingStep.beginRecord":"Cychwyn recordio drwy glicio ar y botwm isod","gui.recordingStep.permission":"{arrow}Rydym angen eich caniatâd i ddefnyddio eich meicroffon","gui.recordingStep.stop":"Atal y recordio","gui.recordingStep.record":"Recordio","gui.sliderModal.min":"Lleiafswm gwerth","gui.sliderModal.max":"Uchafswm gwerth","gui.sliderModal.title":"Newid ystod llithrydd","gui.sliderPrompt.cancel":"Diddymu","gui.sliderPrompt.ok":"Iawn","gui.soundEditor.sound":"Sain","gui.soundEditor.play":"Chwarae","gui.soundEditor.stop":"Aros","gui.soundEditor.copy":"Copïo","gui.soundEditor.paste":"Gludo","gui.soundEditor.copyToNew":"Copïo i\'r Newydd","gui.soundEditor.delete":"Dileu","gui.soundEditor.save":"Cadw","gui.soundEditor.undo":"Dadwneud","gui.soundEditor.redo":"Ailwneud","gui.soundEditor.faster":"Yn gyflymach","gui.soundEditor.slower":"Arafach","gui.soundEditor.echo":"Atsain","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Yn uwch","gui.soundEditor.softer":"Yn feddalach","gui.soundEditor.reverse":"Gwrthdroi","gui.soundEditor.fadeOut":"Pylu allan","gui.soundEditor.fadeIn":"Pylu mewn","gui.soundEditor.mute":"Tewi","gui.SpriteInfo.spritePlaceholder":"Enw","gui.SpriteInfo.sprite":"Ciplun","gui.SpriteInfo.show":"Dangos","gui.SpriteInfo.size":"Maint","gui.spriteSelectorItem.contextMenuDuplicate":"dyblygu","gui.spriteSelectorItem.contextMenuExport":"allforio","gui.spriteSelectorItem.contextMenuDelete":"dileu","gui.spriteSelector.addSpriteFromLibrary":"Dewiswch Gorlun","gui.spriteSelector.addSpriteFromPaint":"Paentio","gui.spriteSelector.addSpriteFromSurprise":"Annisgwyl","gui.spriteSelector.addSpriteFromFile":"Llwytho Corlun i Fyny","gui.stageHeader.stageSizeLarge":"Newid i lwyfan mawr","gui.stageHeader.stageSizeSmall":"Newid i lwyfan bach","gui.stageHeader.stageSizeFull":"Mynd i\'r modd sgrin llawn","gui.stageHeader.stageSizeUnFull":"Gadael y modd sgrin llawn","gui.stageHeader.fullscreenControl":"Rheolydd Sgrin Llawn","gui.spriteSelector.addBackdropFromLibrary":"Dewiswch Gefnlen","gui.stageSelector.addBackdropFromPaint":"Paent","gui.stageSelector.addBackdropFromSurprise":"Annisgwyl","gui.stageSelector.addBackdropFromFile":"Llwytho\'r Gefnlen i Fyny","gui.stageSelector.stage":"Llwyfan","gui.stageSelector.backdrops":"Cefnlenni","gui.telemetryOptIn.label":"Adrodd ystadegau er mwyn gwella Scratch","gui.telemetryOptIn.body1":"Mae Tîm Scratch yn chwilio\'n barhaus am ffyrdd i ddeall yn well sut mae Scratch yn cael ei ddefnyddio o amgylch y byd. I helpu i gefnogi\'r ymdrech, gallwch ganiatáu i Scratch anfon manylion defnydd at Dîm Scratch.","gui.telemetryOptIn.body2":"Mae\'rr manylion rydym ynn eu casglu yn cynnwys dewis iaith, dewis blociau a rhai digwyddiadau fel, cadw, llwytho a llwytho project i fyny. NID YDYM yn casglu unrhyw fanylion personol. Darllenwch ein {privacyPolicyLink} am ragor o wybodaeth.","gui.telemetryOptIn.privacyPolicyLink":"Polisi Preifatrwydd","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Modd Tyrbo","gui.webglModal.label":"Nid yw eich Porwr yn Cynnal WebGL","gui.webglModal.webgllink":"nid yw\'#n cynnal WebGL","gui.costumeLibrary.chooseABackdrop":"Dewiswch Gefnlen","gui.costumeLibrary.chooseACostume":"Dewiswch Wisg","gui.costumeTab.addBackdropFromLibrary":"Dewiswch Gefnlen","gui.costumeTab.addCostumeFromLibrary":"Dewiswch Wisg","gui.costumeTab.addBlankCostume":"Paentio","gui.costumeTab.addSurpriseCostume":"Annisgwyl","gui.costumeTab.addFileBackdrop":"Llwytho Cefnlen i Fyny","gui.costumeTab.addFileCostume":"Llwytho Gwisg i Fyny","gui.extensionLibrary.chooseAnExtension":"Dewis Estyniad","gui.extensionLibrary.extensionUrl":"Rhowch URL yr estyniad","gui.monitors.importListColumnPrompt":"Pa golofn ddylai gael ei defnyddio (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Methwyd cychwyn recordio","gui.soundLibrary.chooseASound":"Dewiswch Sain","gui.soundTab.fileUploadSound":"Llwytho Sain i Fyny...","gui.soundTab.surpriseSound":"Annisgwyl","gui.soundTab.recordSound":"Recordio","gui.soundTab.addSoundFromLibrary":"Dewis Sain","gui.spriteLibrary.chooseASprite":"Dewis Corlun","gui.tipsLibrary.tutorials":"Dewis Tiwtorial","gui.alerts.createsuccess":"Project newydd wedi\'i greu","gui.alerts.createcopysuccess":"Project wedi ei gadw fel copi.","gui.alerts.createremixsuccess":"Project wedi\'i gadw fel ailgymysgiad.","gui.alerts.creating":"Creu un newydd...","gui.alerts.creatingCopy":"Copïo project...","gui.alerts.creatingRemix":"Ailgymysgu project...","gui.alerts.creatingError":"Methu creu\'r project. Ceisiwch eto!","gui.alerts.savingError":"Methodd y project gadw.","gui.alerts.savesuccess":"Project wedi\'i gadw.","gui.alerts.saving":"Yn cadw project...","gui.alerts.cloudInfo":"Sylwch, dim ond rhifau, nid llythrennau na symbolau mae amrywiolion cwmwl yn eu cynnal. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Dysgu rhagor.","gui.alerts.importing":"Mewnforio...","gui.defaultProject.variable":"fy newidyn","gui.extension.music.name":"Cerddoriaeth","gui.extension.music.description":"Chwarae offerynau a drymiau","gui.extension.pen.name":"Pin","gui.extension.pen.description":"Lluniadu gyda\'ch corluniau.","gui.extension.videosensing.name":"Synhwyro Fideo","gui.extension.videosensing.description":"Synhwyro symudiad gyda\'r camera","gui.extension.text2speech.name":"Testun i Leferydd","gui.extension.text2speech.description":"Gwnewch i\'ch projectau siarad.","gui.extension.translate.name":"Cyfieithu","gui.extension.translate.description":"Cyfieithu testun i lawer o ieithoedd.","gui.extension.makeymakey.description":"Gwneud unrhywbeth yn allwedd.","gui.extension.microbit.description":"Cysylltu eich project â\'r byd.","gui.extension.microbit.connectingMessage":"Cysylltu","gui.extension.ev3.description":"Adeiladu robotiaid rhyngweithiol a mwy.","gui.extension.ev3.connectingMessage":"Wrthi\'n cysylltu. Gwnewch yn siwr fod y PIN ar eich EV3 wedi ei osod i 1234.","gui.extension.boost.description":"Dod â creadigaethau robotig yn fyw.","gui.extension.boost.connectingMessage":"Cysylltu","gui.extension.wedo2.description":"Adeiladu gyda moduron a synwyryddion","gui.extension.wedo2.connectingMessage":"Cysylltu","gui.extension.gdxfor.description":"Synhwyro gwthio, tynnu, symudiad a throelli.","gui.extension.gdxfor.connectingMessage":"Cysylltu","gui.libraryTags.all":"Y Cyfan","gui.libraryTags.animals":"Anifeiliaid","gui.libraryTags.dance":"Dawns","gui.libraryTags.effects":"Effeithiau","gui.libraryTags.fantasy":"Ffantasi","gui.libraryTags.fashion":"Ffasiwn","gui.libraryTags.food":"Bwyd","gui.libraryTags.indoors":"Dan do","gui.libraryTags.loops":"Cylchoedd","gui.libraryTags.music":"Cerddoriaeth","gui.libraryTags.notes":"Nodiadau","gui.libraryTags.outdoors":"Tu allan","gui.libraryTags.patterns":"Patrymau","gui.libraryTags.people":"Pobl","gui.libraryTags.percussion":"Offerynnau taro","gui.libraryTags.space":"Gofod","gui.libraryTags.sports":"Chwaraeon","gui.libraryTags.underwater":"O dan y dŵr","gui.libraryTags.voice":"Llais","gui.libraryTags.wacky":"Gwirion","gui.libraryTags.animation":"Animeiddio","gui.libraryTags.art":"Celf","gui.libraryTags.games":"Gemau","gui.libraryTags.stories":"Straeon","gui.libraryTags.letters":"Llythyrau","gui.opcodeLabels.direction":"cyfeiriad","gui.opcodeLabels.xposition":"safle x","gui.opcodeLabels.yposition":"safle y","gui.opcodeLabels.size":"maint","gui.opcodeLabels.costumename":"enw\'r wisg","gui.opcodeLabels.costumenumber":"rhif gwisg","gui.opcodeLabels.backdropname":"enw cefnlen","gui.opcodeLabels.backdropnumber":"rhif cefnlen","gui.opcodeLabels.volume":"lefel sain","gui.opcodeLabels.tempo":"amseriad","gui.opcodeLabels.answer":"ateb","gui.opcodeLabels.loudness":"cryfder sain","gui.opcodeLabels.username":"enw defnyddiwr","gui.opcodeLabels.year":"blwyddyn","gui.opcodeLabels.month":"mis","gui.opcodeLabels.date":"dyddiad","gui.opcodeLabels.dayofweek":"diwrnod o\'r wythnos","gui.opcodeLabels.hour":"awr","gui.opcodeLabels.minute":"munud","gui.opcodeLabels.second":"eiliad","gui.opcodeLabels.timer":"amserydd","gui.sharedMessages.backdrop":"cefnlen {index}","gui.sharedMessages.costume":"gwisg{index}","gui.sharedMessages.sprite":"Corlun{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Newid cynnwys y project hwn?","gui.sharedMessages.loadFromComputerTitle":"Llwytho o\'ch cyfrifiadur","boost.color.any":"unrhyw liw","boost.color.black":"du","boost.color.blue":"glas","boost.color.green":"gwyrdd","boost.color.red":"coch","boost.color.white":"gwyn","boost.color.yellow":"melyn","boost.getMotorPosition":"safle [MOTOR_REPORTER_ID]  modur","boost.getTiltAngle":"ongl gogwyddo [TILT_DIRECTION]","boost.motorDirection.backward":"ffordd acw","boost.motorDirection.forward":"ffordd yma","boost.motorDirection.reverse":"gwrthdroi","boost.motorOff":"diffodd [MOTOR_ID]","boost.motorOn":"cychwyn [MOTOR_ID]","boost.motorOnFor":"cychwyn [MOTOR_ID] am [DURATION] eiliad","boost.motorOnForRotation":"cychwyn [MOTOR_ID] am [ROTATION] troad","boost.seeingColor":"gweld bric [COLOR]?","boost.setLightHue":"gosod lliw\'r golau i [HUE]","boost.setMotorDirection":"gosod cyfeiriad modur [MOTOR_ID] i [MOTOR_DIRECTION]","boost.setMotorPower":"gosod cyflymder modur [MOTOR_ID] i [POWER]","boost.tiltDirection.any":"unrhyw","boost.tiltDirection.down":"i lawr","boost.tiltDirection.left":"chwith","boost.tiltDirection.right":"de","boost.tiltDirection.up":"i fyny","boost.whenColor":"pan welir bric [COLOR] ","boost.whenTilted":"pan mae wedi ei ogwyddo [TILT_DIRECTION_ANY]","ev3.beepNote":"bipio nodyn [NOTE] am [TIME]eiliad","ev3.buttonPressed":"botwm [PORT] wedi ei bwyso?","ev3.getBrightness":"disgleirdeb","ev3.getDistance":"pellter","ev3.getMotorPosition":"safle [PORT]modur ","ev3.motorSetPower":"gosod pŵer modur [PORT] i [POWER] %","ev3.motorTurnClockwise":"modur [PORT] yn troi ffordd hyn am [TIME] eiliad","ev3.motorTurnCounterClockwise":"modur [PORT] yn troi ffordd yna am [TIME] eiliad","ev3.whenBrightnessLessThan":"pan mae\'r disgleirdeb < [DISTANCE]","ev3.whenButtonPressed":"pan mae\'r botwm [PORT]yn cael ei bwyso","ev3.whenDistanceLessThan":"pan mae\'r pellter < [DISTANCE]","gdxfor.getAcceleration":"cyflymu [DIRECTION]","gdxfor.getForce":"grym","gdxfor.getSpin":"cyflymder troelli [DIRECTION]","gdxfor.getTilt":"ongl gogwyddo [TILT]","gdxfor.isFreeFalling":"yn syrthio?","gdxfor.isTilted":"gogwyddo [TILT]?","gdxfor.pulled":"tynnwyd","gdxfor.pushed":"gwthiwyd","gdxfor.shaken":"ysgydwyd","gdxfor.startedFalling":"wedi cychwyn syrthio","gdxfor.tiltDirectionMenu.any":"unrhyw","gdxfor.tiltDirectionMenu.back":"cefn","gdxfor.tiltDirectionMenu.front":"blaen","gdxfor.tiltDirectionMenu.left":"chwith","gdxfor.tiltDirectionMenu.right":"de","gdxfor.turnedFaceDown":"wedi ei droi\'n wyneb i waered","gdxfor.turnedFaceUp":"wedi ei droi wyneb i fyny","gdxfor.whenForcePushedOrPulled":"pan mae synhwyrydd grym [PUSH_PULL]","gdxfor.whenGesture":"pan [GESTURE]","gdxfor.whenTilted":"pan mae wedi gogwyddo [TILT]","makeymakey.downArrow":"saeth i lawr","makeymakey.downArrowShort":"i lawr","makeymakey.leftArrow":"saeth chwith","makeymakey.leftArrowShort":"chwith","makeymakey.rightArrow":"saeth de","makeymakey.rightArrowShort":"de","makeymakey.spaceKey":"bwlch","makeymakey.upArrow":"saeth i fyny","makeymakey.upArrowShort":"i fyny","makeymakey.whenKeyPressed":"pan mae [KEY] allwedd wedi\'i phwyso","makeymakey.whenKeysPressedInOrder":"pan mae [SEQUENCE] wedi\'i bwyso mewn trefn","microbit.buttonsMenu.any":"unrhyw","microbit.clearDisplay":"clirio\'r dangosydd","microbit.defaultTextToDisplay":"Helo!","microbit.displaySymbol":"dangos [MATRIX]","microbit.displayText":"dangos testun [TEXT]","microbit.gesturesMenu.jumped":"neidiodd","microbit.gesturesMenu.moved":"symudodd","microbit.gesturesMenu.shaken":"ysgydwyd","microbit.isButtonPressed":"botwm [BTN] wedi ei bwyso?","microbit.isTilted":"[DIRECTION] ar ogwydd?","microbit.pinStateMenu.off":"i ffwrdd","microbit.pinStateMenu.on":"ymlaen","microbit.tiltAngle":"ongl gogwydd [DIRECTION]","microbit.tiltDirectionMenu.any":"unrhyw","microbit.tiltDirectionMenu.back":"cefn","microbit.tiltDirectionMenu.front":"blaen","microbit.tiltDirectionMenu.left":"chwith","microbit.tiltDirectionMenu.right":"de","microbit.whenButtonPressed":"pan mae botwm [BTN] yn cael ei bwyso","microbit.whenGesture":"pan [GESTURE]","microbit.whenPinConnected":"pan mae pin [PIN] wedi ei gysylltu","microbit.whenTilted":"pan mae wedi gogwyddo i\'r [DIRECTION]","music.categoryName":"Cerddoriaeth","music.changeTempo":"Newid tempo gan [TEMPO]","music.drumBass":"(2) Drwm Bas","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Clafiau","music.drumClosedHiHat":"(^) Symbalau Pedal Troed Caeëdig","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Cloch Buwch","music.drumCrashCymbal":"(4) Symbal","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Clap Llaw","music.drumOpenHiHat":"(5) Symbalau Pedal Troed Agored","music.drumSideStick":"(3) Pren ochr","music.drumSnare":"(1) Drwm Gwifrau","music.drumTambourine":"(7) Tambwrîn","music.drumTriangle":"(12) Triongl","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Bloc Pren","music.getTempo":"amseriad","music.instrumentBass":"(6) Bas","music.instrumentBassoon":"(14) Basŵn","music.instrumentCello":"(8) Sielo","music.instrumentChoir":"(15) Côr","music.instrumentClarinet":"(10) Clarinét","music.instrumentElectricGuitar":"(5) Gitâr Drydan","music.instrumentElectricPiano":"(2) Piano Trydan","music.instrumentFlute":"(12) Ffliwt","music.instrumentGuitar":"(4) Gitâr","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Blwch Cerddoriaeth","music.instrumentOrgan":"(3) Organ","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Sacsoffon","music.instrumentSteelDrum":"(18) Drwm Dur","music.instrumentSynthLead":"(20) Synth Blaen","music.instrumentSynthPad":"(21) Pad Synth","music.instrumentTrombone":"(9) Trombôn","music.instrumentVibraphone":"(16) Fibraffon","music.instrumentWoodenFlute":"(13) Ffliwt Pren","music.midiPlayDrumForBeats":"chwarae drwm [DRUM] am [BEATS] guriad","music.midiSetInstrument":"gosod offeryn i [INSTRUMENT]","music.playDrumForBeats":"chwarae drwm [DRUM] am [BEATS] curiad","music.playNoteForBeats":"chwarae nodyn[NOTE]am [BEATS]curiad","music.restForBeats":"oedi am [BEATS]curiad","music.setInstrument":"gosod offeryn i [INSTRUMENT]","music.setTempo":"gosod tempo [TEMPO]","pen.categoryName":"Pin","pen.changeColorParam":"newid pin [COLOR_PARAM]gan [VALUE]","pen.changeHue":"newid lliw pin gan [HUE]","pen.changeShade":"newid arlliw pin gan [SHADE]","pen.changeSize":"newid maint pin gan [SIZE]","pen.clear":"dileu popeth","pen.colorMenu.brightness":"disgleirdeb","pen.colorMenu.color":"lliw","pen.colorMenu.saturation":"dirlawnder","pen.colorMenu.transparency":"tryloywder","pen.penDown":"pin i lawr","pen.penUp":"pin i fyny","pen.setColor":"gosod lliw pin i [COLOR]","pen.setColorParam":"gosod y pin [COLOR_PARAM]i [VALUE]","pen.setHue":"gosod lliw pin i [HUE]","pen.setShade":"gosod arlliw pin i [SHADE]","pen.setSize":"gosod maint pin i [SIZE]","pen.stamp":"stampio","text2speech.alto":"alto","text2speech.categoryName":"Testun i Leferydd","text2speech.defaultTextToSpeak":"helo","text2speech.giant":"cawr","text2speech.kitten":"cath fach","text2speech.setLanguageBlock":"gosod iaith i [LANGUAGE]","text2speech.setVoiceBlock":"gosod llais i [VOICE]","text2speech.speakAndWaitBlock":"siarad [WORDS]","text2speech.squeak":"gwich","text2speech.tenor":"tenor","translate.categoryName":"Cyfieithu","translate.defaultTextToTranslate":"helo","translate.translateBlock":"cyfieithu[WORDS] i\'r [LANGUAGE]","translate.viewerLanguage":"iaith","videoSensing.categoryName":"Synhwyro Fideo","videoSensing.direction":"cyfeiriad","videoSensing.motion":"symudiad","videoSensing.off":"i ffwrdd","videoSensing.on":"ymlaen","videoSensing.onFlipped":"wrth ei fflipio","videoSensing.setVideoTransparency":"gosod tryloywder fideo i [TRANSPARENCY]","videoSensing.sprite":"corlun","videoSensing.stage":"llwyfan","videoSensing.videoOn":"fideo [ATTRIBUTE] ar [SUBJECT]","videoSensing.videoToggle":"troi fideo [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"pan mae symud fideo > [REFERENCE]","wedo2.getDistance":"pellter","wedo2.getTiltAngle":"ongl gogwyddo [TILT_DIRECTION]","wedo2.isTilted":"wedi ei ogwyddo [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"ffordd acw","wedo2.motorDirection.forward":"ffordd yma","wedo2.motorDirection.reverse":"gwrthdroi","wedo2.motorId.a":"modur A","wedo2.motorId.all":"pob modur","wedo2.motorId.b":"modur B","wedo2.motorId.default":"modur","wedo2.motorOff":"diffodd [MOTOR_ID]","wedo2.motorOn":"cychwyn [MOTOR_ID]","wedo2.motorOnFor":"cychwyn [MOTOR_ID] am [DURATION] eiliad","wedo2.playNoteFor":"chwarae nodyn [NOTE] am [DURATION] eiliad","wedo2.setLightHue":"gosod lliw\'r golau i [HUE]","wedo2.setMotorDirection":"gosod cyfeiriad [MOTOR_ID] i [MOTOR_DIRECTION]","wedo2.startMotorPower":"gosod pŵer [MOTOR_ID] i [POWER]","wedo2.tiltDirection.any":"unrhyw","wedo2.tiltDirection.down":"i lawr","wedo2.tiltDirection.left":"chwith","wedo2.tiltDirection.right":"de","wedo2.tiltDirection.up":"i fyny","wedo2.whenDistance":"pam mae\'r pellter [OP] [REFERENCE]","wedo2.whenTilted":"pan mae wedi ei ogwyddo [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Lliw","paint.paintEditor.saturation":"Dirlawnder","paint.paintEditor.brightness":"Disgleirdeb","paint.paintEditor.costume":"Gwisg","paint.paintEditor.group":"Grŵp","paint.paintEditor.ungroup":"Dad-grwpio","paint.paintEditor.undo":"Dadwneud","paint.paintEditor.redo":"Ailwneud","paint.paintEditor.forward":"Ymlaen","paint.paintEditor.backward":"Nôl","paint.paintEditor.front":"Blaen","paint.paintEditor.back":"Nôl","paint.paintEditor.more":"Rhagor","paint.modeTools.brushSize":"Maint","paint.modeTools.eraserSize":"Maint rhwbiwr","paint.modeTools.copy":"Copïo","paint.modeTools.paste":"Gludo","paint.modeTools.delete":"Dileu","paint.modeTools.curved":"Crwm","paint.modeTools.pointed":"Gyda Blaen","paint.modeTools.thickness":"Trwch","paint.modeTools.flipHorizontal":"Fflipio\'n Llorweddol","paint.modeTools.flipVertical":"Fflipio\'n Fertigol","paint.modeTools.filled":"Llanwyd","paint.modeTools.outlined":"Amlinellwyd","paint.paintEditor.bitmap":"Trosi i Ddidfap","paint.paintEditor.vector":"Trosi i Fector","paint.paintEditor.fill":"Llanw","paint.paintEditor.stroke":"Amlinell","paint.brushMode.brush":"Brwsh","paint.eraserMode.eraser":"Rhwbiwr","paint.fillMode.fill":"Llanw","paint.lineMode.line":"Llinell","paint.ovalMode.oval":"Cylch","paint.rectMode.rect":"Petryal","paint.reshapeMode.reshape":"Ail siapio","paint.roundedRectMode.roundedRect":"Petryal Crwm","paint.selectMode.select":"Dewis","paint.textMode.text":"Testun","paint.colorPicker.swap":"Cyfnewid"},"da":{"gui.alerts.tryAgain":"Prøv igen","gui.alerts.download":"Gem","gui.connection.reconnect":"Forbind igen","gui.backpack.costumeLabel":"kostume","gui.backpack.soundLabel":"lyd","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Rygsæk","gui.backpack.errorBackpack":"Fejl, kan ikke indlæse rygsækken","gui.backpack.loadingBackpack":"Indlæser ...","gui.backpack.more":"Mere","gui.backpack.emptyBackpack":"Rygsækken er tom","gui.unsupportedBrowser.label":"Browseren kan ikke bruges","gui.cards.all-tutorials":"Vejledninger","gui.cards.shrink":"Mindre","gui.cards.expand":"Udvid","gui.cards.close":"Luk","gui.cards.more-things-to-try":"Flere ting, som du kan prøve!","gui.cards.see-more":"Se mere","gui.comingSoon.message1":"Du skal ikke bekymre dig, vi arbejder på sagen {emoji}","gui.comingSoon.message2":"Kommer snart...","gui.comingSoon.message3":"Vi arbejder på sagen {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Ingen enheder fundet","gui.connection.auto-scanning.prescan":"Stil din enhed tæt på, derefter begynd at søge","gui.connection.auto-scanning.pressbutton":"Tryk på knappen på din device","gui.connection.auto-scanning.start-search":"Start søgningen","gui.connection.connecting-searchbutton":"Søger...","gui.connection.auto-scanning.try-again":"Prøv igen","gui.connection.connected":"Forbundet","gui.connection.disconnect":"Afbryd","gui.connection.go-to-editor":"Gå til editor","gui.connection.connecting-cancelbutton":"Forbinder...","gui.connection.error.errorMessage":"Ups, det ser ud som om at noget gik galt.","gui.connection.error.tryagainbutton":"Prøv igen","gui.connection.error.helpbutton":"Hjælp","gui.connection.peripheral-name-label":"Navn på enhed","gui.connection.connect":"Forbind","gui.connection.scanning.lookingforperipherals":"Søger efter enheder","gui.connection.scanning.noPeripheralsFound":"Ingen enheder fundet","gui.connection.scanning.instructions":"Vælg din enhed fra listen herover.","gui.connection.search":"Opdater","gui.connection.unavailable.installscratchlink":"Vær sikker på at Scratch linket er installeret og kører","gui.connection.unavailable.enablebluetooth":"Tjek at Bluetooth er slået til","gui.connection.unavailable.tryagainbutton":"Prøv igen","gui.connection.unavailable.helpbutton":"Hjælp","gui.controls.go":"Gå","gui.controls.stop":"Stop","gui.crashMessage.label":"Ups! Noget gik galt.","gui.crashMessage.errorNumber":"Din fejl er registreret med id {errorId}","gui.crashMessage.reload":"Genindlæs","gui.customProcedures.myblockModalTitle":"Lav en brik","gui.customProcedures.addAnInputNumberText":"Tilføj input","gui.customProcedures.numberTextType":"tal eller tekst","gui.customProcedures.addAnInputBoolean":"Tilføj input","gui.customProcedures.booleanType":"boolean","gui.customProcedures.addALabel":"Tilføj en label","gui.customProcedures.runWithoutScreenRefresh":"Kør uden skærmopdatering","gui.customProcedures.cancel":"Annuller","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Retning","gui.directionPicker.rotationStyles.allAround":"Alle retninger","gui.directionPicker.rotationStyles.leftRight":"Venstre/højre","gui.directionPicker.rotationStyles.dontRotate":"Drej ikke","gui.gui.addExtension":"Tilføj udvidelse","gui.gui.codeTab":"Kode","gui.gui.backdropsTab":"Baggrunde","gui.gui.costumesTab":"Kostumer","gui.gui.soundsTab":"Lyde","gui.extensionLibrary.comingSoon":"Kommer snart","gui.extensionLibrary.requires":"Kræver","gui.extensionLibrary.collaboration":"Samarbejde med","gui.library.filterPlaceholder":"Søg","gui.library.allTag":"Alle","gui.loader.headline":"Indlæser projekt","gui.loader.creating":"Laver projekt","gui.authorInfo.byUser":"af {username}","gui.menuBar.seeProjectPage":"Se projekt side","gui.menuBar.LanguageSelector":"valg af sprog","gui.menuBar.tutorialsLibrary":"Vejledninger","gui.menuBar.restoreSprite":"Gendan Sprite","gui.menuBar.restoreSound":"Gendan lyd","gui.menuBar.restoreCostume":"Gendan kostume","gui.menuBar.restore":"Gendan","gui.menuBar.saveNow":"Gem nu","gui.menuBar.saveAsCopy":"Gem som kopi","gui.menuBar.remix":"Remix","gui.menuBar.new":"Ny","gui.menuBar.file":"Fil","gui.menuBar.downloadToComputer":"Gem på din computer","gui.menuBar.edit":"Redigér","gui.menuBar.turboModeOff":"Slå turbo fra","gui.menuBar.turboModeOn":"Sæt turbo på","gui.gui.projectTitlePlaceholder":"Skriv projektets navn her","gui.menuBar.isShared":"Delte","gui.menuBar.share":"Del","gui.modal.help":"Hjælp","gui.modal.back":"Tilbage","gui.monitor.listMonitor.empty":"(tom)","gui.monitor.listMonitor.listLength":"længde {length}","gui.monitor.contextMenu.default":"normal visning","gui.monitor.contextMenu.large":"stor visning","gui.monitor.contextMenu.slider":"skyder","gui.monitor.contextMenu.sliderRange":"ændre på skyderens rækkevidde","gui.monitor.contextMenu.import":"importer","gui.monitor.contextMenu.export":"eksporter","gui.monitor.contextMenu.hide":"skjul","gui.playButton.play":"Leg","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"For alle sprites","gui.gui.variableScopeOptionSpriteOnly":"Kun for denne sprite","gui.gui.cloudVariableOption":"Sky variabler (gemt på server)","gui.gui.variablePromptAllSpritesMessage":"Denne variabel kan bruges ved alle sprites.","gui.gui.listPromptAllSpritesMessage":"Denne liste kan bruges ved alle sprites.","gui.prompt.cancel":"Annuller","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Stop","gui.playbackStep.playMsg":"Spil","gui.playbackStep.loadingMsg":"Indlæser ...","gui.playbackStep.saveMsg":"Gem","gui.playbackStep.reRecordMsg":"Optag igen","gui.recordModal.title":"Optag lyd","gui.recordingStep.beginRecord":"Begynd at optage ved at klikke på knappen herunder","gui.recordingStep.permission":"{arrow}Vi skal bruge din tilladelse til at bruge din mikrofon","gui.recordingStep.stop":"Stop med at optage","gui.recordingStep.record":"Optag","gui.sliderModal.min":"Minimumsværdi","gui.sliderModal.max":"Maksimumværdi","gui.sliderModal.title":"Ændre på skyderens rækkevidde","gui.sliderPrompt.cancel":"Annuller","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Lyd","gui.soundEditor.play":"Spil","gui.soundEditor.stop":"Stop","gui.soundEditor.copy":"Kopier","gui.soundEditor.paste":"Sæt ind","gui.soundEditor.copyToNew":"Kopier til ny","gui.soundEditor.delete":"Slet","gui.soundEditor.save":"Gem","gui.soundEditor.undo":"Fortryd","gui.soundEditor.redo":"Gør om","gui.soundEditor.faster":"Hurtigere","gui.soundEditor.slower":"Langsommere","gui.soundEditor.echo":"Ekko","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Højere","gui.soundEditor.softer":"Blødere","gui.soundEditor.reverse":"Baglæns","gui.soundEditor.fadeOut":"Nedtoning","gui.soundEditor.fadeIn":"Optoning","gui.soundEditor.mute":"Slå lyden fra","gui.SpriteInfo.spritePlaceholder":"Navn","gui.SpriteInfo.sprite":"Sprite","gui.SpriteInfo.show":"Vis","gui.SpriteInfo.size":"Størrelse","gui.spriteSelectorItem.contextMenuDuplicate":"kopier","gui.spriteSelectorItem.contextMenuExport":"eksporter","gui.spriteSelectorItem.contextMenuDelete":"slet","gui.spriteSelector.addSpriteFromLibrary":"Vælg en sprite","gui.spriteSelector.addSpriteFromPaint":"Tegn","gui.spriteSelector.addSpriteFromSurprise":"Overraskelse","gui.spriteSelector.addSpriteFromFile":"Hent sprite","gui.stageHeader.stageSizeLarge":"Skift til stor scene","gui.stageHeader.stageSizeSmall":"Skift til lille scene","gui.stageHeader.stageSizeFull":"Gå til fuld skærm","gui.stageHeader.stageSizeUnFull":"Gå ud af fuld skærm","gui.stageHeader.fullscreenControl":"Fuld skærm","gui.spriteSelector.addBackdropFromLibrary":"Vælg en baggrund","gui.stageSelector.addBackdropFromPaint":"Tegn","gui.stageSelector.addBackdropFromSurprise":"Overraskelse","gui.stageSelector.addBackdropFromFile":"Hent baggrund","gui.stageSelector.stage":"Scene","gui.stageSelector.backdrops":"Baggrunde","gui.telemetryOptIn.label":"Rapporter statistik for at forbedre Scratch","gui.telemetryOptIn.body1":"Scratch Teamet prøver altid på at blive bedre til at forstå hvordan Scratch bliver brugt rundt omkring i verden. For at støtte dette arbejde kan du give tilladelse til, at Scratch automatisk sender information til Scratch Teamet om hvordan du bruger det.","gui.telemetryOptIn.body2":"Dén information som vi indsamler, inkluderer sprogvalg, brugen af brikker og nogle funktioner såsom at gemme, åbne og uploade et projekt. . Vi indsamler IKKE personlige informationer. Se vores politik om personlige oplysninger {privacyPolicyLink} hvis du vil vide mere.","gui.telemetryOptIn.privacyPolicyLink":"Politik om private oplysninger","gui.telemetryOptIn.optInText":"Del mine brugsdata med Scratch Teamet","gui.telemetryOptIn.optInTooltip":"Aktivér telemetri","gui.telemetryOptIn.optOutText":"Del ikke mine brugsdata med Scratch Teamet","gui.telemetryOptIn.optOutTooltip":"Deaktivér telemetri","gui.telemetryOptIn.settingWasUpdated":"Dine indstillinger er opdateret.","gui.telemetryOptIn.buttonClose":"Luk","gui.turboMode.active":"Sæt turbo på","gui.webglModal.label":"Din browser understøtter ikke WebGL","gui.webglModal.webgllink":"understøtter ikke WebGL","gui.costumeLibrary.chooseABackdrop":"Vælg en baggrund","gui.costumeLibrary.chooseACostume":"Vælg et kostume","gui.costumeTab.addBackdropFromLibrary":"Vælg en baggrund","gui.costumeTab.addCostumeFromLibrary":"Vælg et kostume","gui.costumeTab.addBlankCostume":"Tegn","gui.costumeTab.addSurpriseCostume":"Overraskelse","gui.costumeTab.addFileBackdrop":"Hent baggrund","gui.costumeTab.addFileCostume":"Hent kostume","gui.extensionLibrary.chooseAnExtension":"Vælg en udvidelse","gui.extensionLibrary.extensionUrl":"Indtast udvidelsens URL","gui.monitors.importListColumnPrompt":"Hvilken kolonne skal bruges (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Kunne ikke starte optagelsen","gui.soundLibrary.chooseASound":"Vælg en lyd","gui.soundTab.fileUploadSound":"Hent lyd","gui.soundTab.surpriseSound":"Overraskelse","gui.soundTab.recordSound":"Optag","gui.soundTab.addSoundFromLibrary":"Vælg en lyd","gui.spriteLibrary.chooseASprite":"Vælg en sprite","gui.tipsLibrary.tutorials":"Vælg en vejledning","gui.alerts.createsuccess":"Et nyt projekt er lavet.","gui.alerts.createcopysuccess":"Projekt gemt som en kopi.","gui.alerts.createremixsuccess":"Projekt gemt som et remix.","gui.alerts.creating":"Laver nyt...","gui.alerts.creatingCopy":"Kopierer projekt...","gui.alerts.creatingRemix":"Remixer projekt...","gui.alerts.creatingError":"Kunne ikke lave projektet. Prøv igen!","gui.alerts.savingError":"Projektet kunne ikke gemmes.","gui.alerts.savesuccess":"Projekt er gemt.","gui.alerts.saving":"Gemmer projekt...","gui.alerts.cloudInfo":"Vær opmærksom på at sky variabler kun kan indeholde tal, ikke bogstaver eller symboler. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Lær mere.","gui.alerts.importing":"Importerer...","gui.defaultProject.variable":"min variabel","gui.extension.music.name":"Musik","gui.extension.music.description":"Spil på instrumenter og trommer","gui.extension.pen.name":"Pen","gui.extension.pen.description":"Tegn med dine sprites.","gui.extension.videosensing.name":"Video Registrering","gui.extension.videosensing.description":"Registrerer bevægelse med kameraet","gui.extension.text2speech.name":"Tekst til tale","gui.extension.text2speech.description":"Få dine projekter til at tale.","gui.extension.translate.name":"Oversæt","gui.extension.translate.description":"Oversæt tekst til mange sprog.","gui.extension.makeymakey.description":"Gør alting til en tast","gui.extension.microbit.description":"Forbind dine projekter med den fysiske verden.","gui.extension.microbit.connectingMessage":"Forbinder","gui.extension.ev3.description":"Byg interaktive robotter og mere.","gui.extension.ev3.connectingMessage":"Forbinder. Vær sikker på at pin\'en på din EV3 er sat til 1234.","gui.extension.boost.description":"Gør dine robtter levende.","gui.extension.boost.connectingMessage":"Forbinder","gui.extension.wedo2.description":"Byg med motorer og sensorer","gui.extension.wedo2.connectingMessage":"Forbinder","gui.extension.gdxfor.description":"Registrér skub, træk, bevægelse og drejen rundt.","gui.extension.gdxfor.connectingMessage":"Forbinder","gui.libraryTags.all":"Alle","gui.libraryTags.animals":"Dyr","gui.libraryTags.dance":"Dans","gui.libraryTags.effects":"Effekter","gui.libraryTags.fantasy":"Fantasi","gui.libraryTags.fashion":"Mode","gui.libraryTags.food":"Mad","gui.libraryTags.indoors":"Indendørs","gui.libraryTags.loops":"Gentagelser","gui.libraryTags.music":"Musik","gui.libraryTags.notes":"Noder","gui.libraryTags.outdoors":"Udendørs","gui.libraryTags.patterns":"Mønstre","gui.libraryTags.people":"Mennesker","gui.libraryTags.percussion":"Slagtøj","gui.libraryTags.space":"Rummet","gui.libraryTags.sports":"Sport","gui.libraryTags.underwater":"Under vandet","gui.libraryTags.voice":"Stemme","gui.libraryTags.wacky":"Skør","gui.libraryTags.animation":"Animation","gui.libraryTags.art":"Kunst","gui.libraryTags.games":"Spil","gui.libraryTags.stories":"Historier","gui.libraryTags.letters":"Bogstaver","gui.opcodeLabels.direction":"retning","gui.opcodeLabels.xposition":"x position","gui.opcodeLabels.yposition":"y position","gui.opcodeLabels.size":"størrelse","gui.opcodeLabels.costumename":"navn på kostume","gui.opcodeLabels.costumenumber":"kostume nummer","gui.opcodeLabels.backdropname":"navn på baggrund","gui.opcodeLabels.backdropnumber":"baggrund nummer","gui.opcodeLabels.volume":"lydstyrke","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"svar","gui.opcodeLabels.loudness":"lydstyrke","gui.opcodeLabels.username":"brugernavn","gui.opcodeLabels.year":"år","gui.opcodeLabels.month":"måned","gui.opcodeLabels.date":"dato","gui.opcodeLabels.dayofweek":"ugedag","gui.opcodeLabels.hour":"time","gui.opcodeLabels.minute":"minut","gui.opcodeLabels.second":"sekund","gui.opcodeLabels.timer":"stopur","gui.sharedMessages.backdrop":"baggrund{index}","gui.sharedMessages.costume":"kostume{index}","gui.sharedMessages.sprite":"Sprite{index}","gui.sharedMessages.pop":"knald","gui.sharedMessages.replaceProjectWarning":"Erstat indholdet af det nuværende projekt?","gui.sharedMessages.loadFromComputerTitle":"Hent fra din computer","boost.color.any":"alle farver","boost.color.black":"sort","boost.color.blue":"blå","boost.color.green":"grøm","boost.color.red":"rød","boost.color.white":"hvid","boost.color.yellow":"gul","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] position","boost.getTiltAngle":"vippet vinkel [TILT_DIRECTION]","boost.motorDirection.backward":"den vej","boost.motorDirection.forward":"den anden vej","boost.motorDirection.reverse":"skift retning","boost.motorOff":"sluk motor [MOTOR_ID]","boost.motorOn":"tænd motor [MOTOR_ID]","boost.motorOnFor":"tænd motor [MOTOR_ID] i [DURATION] sekunder","boost.motorOnForRotation":"tænd motor [MOTOR_ID] i [ROTATION] rotationer","boost.seeingColor":"ser [COLOR] brik?","boost.setLightHue":"sæt farven på lyset til [HUE]","boost.setMotorDirection":"sæt motor [MOTOR_ID] retning til [MOTOR_DIRECTION]","boost.setMotorPower":"sæt motor [MOTOR_ID] hastighed til [POWER] %","boost.tiltDirection.any":"vilkårlig","boost.tiltDirection.down":"ned","boost.tiltDirection.left":"venstre","boost.tiltDirection.right":"højre","boost.tiltDirection.up":"op","boost.whenColor":"når [COLOR] brikken ses","boost.whenTilted":"er vippet [TILT_DIRECTION_ANY]","ev3.beepNote":"spil tone [NOTE] i [TIME] sekunder","ev3.buttonPressed":"tryksensor [PORT] trykket ind?","ev3.getBrightness":"lysstyrke","ev3.getDistance":"afstand","ev3.getMotorPosition":"motor [PORT] position","ev3.motorSetPower":"motor [PORT] indstil styrke [POWER] %","ev3.motorTurnClockwise":"motor [PORT] drej en vej i [TIME] sekunder","ev3.motorTurnCounterClockwise":"motor [PORT] drej anden vej i [TIME] sekunder","ev3.whenBrightnessLessThan":"når lysstyrke < [DISTANCE]","ev3.whenButtonPressed":"tryksensor [PORT] trykket ind","ev3.whenDistanceLessThan":"når afstanden < [DISTANCE]","gdxfor.getAcceleration":"acceleration [DIRECTION]","gdxfor.getForce":"kraft","gdxfor.getSpin":"spin hastighed [DIRECTION]","gdxfor.getTilt":"vippet vinkel [TILT]","gdxfor.isFreeFalling":"falder?","gdxfor.isTilted":"vippet [TILT]?","gdxfor.pulled":"trukket","gdxfor.pushed":"skubbet","gdxfor.shaken":"rystet","gdxfor.startedFalling":"begyndte at falde","gdxfor.tiltDirectionMenu.any":"vilkårlig","gdxfor.tiltDirectionMenu.back":"bagover","gdxfor.tiltDirectionMenu.front":"fremover","gdxfor.tiltDirectionMenu.left":"venstre","gdxfor.tiltDirectionMenu.right":"højre","gdxfor.turnedFaceDown":"vendt nedad","gdxfor.turnedFaceUp":"vendt opad","gdxfor.whenForcePushedOrPulled":"når kraft sensor [PUSH_PULL]","gdxfor.whenGesture":"når [GESTURE]","gdxfor.whenTilted":"når vippet [TILT]","makeymakey.downArrow":"pil nedad","makeymakey.downArrowShort":"ned","makeymakey.leftArrow":"venstre pil","makeymakey.leftArrowShort":"venstre","makeymakey.rightArrow":"højre pil","makeymakey.rightArrowShort":"højre","makeymakey.spaceKey":"mellemrum","makeymakey.upArrow":"pil opad","makeymakey.upArrowShort":"op","makeymakey.whenKeyPressed":"når [KEY] tast er trykket","makeymakey.whenKeysPressedInOrder":"når [SEQUENCE] er trykket i rækkefølge","microbit.buttonsMenu.any":"vilkårlig","microbit.clearDisplay":"ryd display","microbit.defaultTextToDisplay":"Hej!","microbit.displaySymbol":"vis [MATRIX]","microbit.displayText":"vis tekst [TEXT]","microbit.gesturesMenu.jumped":"hoppet","microbit.gesturesMenu.moved":"bevæget","microbit.gesturesMenu.shaken":"rystet","microbit.isButtonPressed":"[BTN] knap trykket?","microbit.isTilted":"vippet [DIRECTION]?","microbit.pinStateMenu.off":"slukket","microbit.pinStateMenu.on":"tændt","microbit.tiltAngle":"vippet [DIRECTION]","microbit.tiltDirectionMenu.any":"vilkårlig","microbit.tiltDirectionMenu.back":"bagover","microbit.tiltDirectionMenu.front":"fremover","microbit.tiltDirectionMenu.left":"venstre","microbit.tiltDirectionMenu.right":"højre","microbit.whenButtonPressed":"tryksensor [BTN] trykket ind","microbit.whenGesture":"når [GESTURE]","microbit.whenPinConnected":"når pin [PIN] er forbundet","microbit.whenTilted":"er vippet [DIRECTION]","music.categoryName":"Musik","music.changeTempo":"ændre tempo med [TEMPO]","music.drumBass":"(2) Stortromme","music.drumBongo":"(13) Bongotromme","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) Lukket hi-hat","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Koklokke","music.drumCrashCymbal":"(4) Bækken","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Klap med hænderne","music.drumOpenHiHat":"(5) Åben hi-hat","music.drumSideStick":"(3) Kantslag","music.drumSnare":"(1) Lilletromme","music.drumTambourine":"(7) Tamburin","music.drumTriangle":"(12) Triangel","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Træklods","music.getTempo":"tempo","music.instrumentBass":"(6) Bas","music.instrumentBassoon":"(14) Fagot","music.instrumentCello":"(8) Cello","music.instrumentChoir":"(15) Kor","music.instrumentClarinet":"(10) Klarinet","music.instrumentElectricGuitar":"(5) Elektrisk guitar","music.instrumentElectricPiano":"(2) Elektrisk klaver","music.instrumentFlute":"(12) Fløjte","music.instrumentGuitar":"(4) Guitar","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Spilledåse","music.instrumentOrgan":"(3) Orgel","music.instrumentPiano":"(1) Klaver","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxofon","music.instrumentSteelDrum":"(18) Ståltromme","music.instrumentSynthLead":"(20) Synth Lead","music.instrumentSynthPad":"(21) Synth Pad","music.instrumentTrombone":"(9) Trækbasun","music.instrumentVibraphone":"(16) Vibrafon","music.instrumentWoodenFlute":"(13) Træfløjte","music.midiPlayDrumForBeats":"spil tromme [DRUM] i [BEATS] slag","music.midiSetInstrument":"skift instrument til [INSTRUMENT]","music.playDrumForBeats":"spil [DRUM] i [BEATS] slag","music.playNoteForBeats":"spil node [NOTE] i [BEATS] slag","music.restForBeats":"pause i [BEATS] slag","music.setInstrument":"skift instrument til [INSTRUMENT]","music.setTempo":"sæt tempo til [TEMPO]","pen.categoryName":"Pen","pen.changeColorParam":"ændre pen [COLOR_PARAM] med [VALUE]","pen.changeHue":"ændre penfarve med [HUE]","pen.changeShade":"ændre skyggen på pennen med [SHADE]","pen.changeSize":"ændre pen størrelse med[SIZE]","pen.clear":"slet alt","pen.colorMenu.brightness":"lysstyrke","pen.colorMenu.color":"farve","pen.colorMenu.saturation":"farvemætning","pen.colorMenu.transparency":"gennemsigtighed","pen.penDown":"pen ned","pen.penUp":"pen op","pen.setColor":"skift penfarve til [COLOR]","pen.setColorParam":"sæt pen [COLOR_PARAM] til [VALUE]","pen.setHue":"sæt penfarve til [HUE]","pen.setShade":"sæt skyggen på pennen til [SHADE]","pen.setSize":"sæt penstørrelse til [SIZE]","pen.stamp":"stempel","text2speech.alto":"kvinde","text2speech.categoryName":"Tekst til tale","text2speech.defaultTextToSpeak":"hej","text2speech.giant":"kæmpe","text2speech.kitten":"killing","text2speech.setLanguageBlock":"sæt sprog til [LANGUAGE]","text2speech.setVoiceBlock":"indstil stemme til [VOICE]","text2speech.speakAndWaitBlock":"sig [WORDS]","text2speech.squeak":"knirkende","text2speech.tenor":"mand","translate.categoryName":"Oversæt","translate.defaultTextToTranslate":"hej","translate.translateBlock":"oversæt [WORDS] til [LANGUAGE]","translate.viewerLanguage":"sprog","videoSensing.categoryName":"Video Registrering","videoSensing.direction":"retning","videoSensing.motion":"bevægelse","videoSensing.off":"slukket","videoSensing.on":"tændt","videoSensing.onFlipped":"spejlvendt","videoSensing.setVideoTransparency":"sæt video gennemsigtighed til [TRANSPARENCY]","videoSensing.sprite":"sprite","videoSensing.stage":"scene","videoSensing.videoOn":"video [ATTRIBUTE] på [SUBJECT]","videoSensing.videoToggle":"video [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"når video bevægelse > [REFERENCE]","wedo2.getDistance":"afstand","wedo2.getTiltAngle":"vippet vinkel [TILT_DIRECTION]","wedo2.isTilted":"vippet [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"den vej","wedo2.motorDirection.forward":"den anden vej","wedo2.motorDirection.reverse":"skift retning","wedo2.motorId.a":"motor A","wedo2.motorId.all":"alle motorer","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"sluk [MOTOR_ID] ","wedo2.motorOn":"tænd [MOTOR_ID]","wedo2.motorOnFor":"tænd [MOTOR_ID] i [DURATION] sekunder","wedo2.playNoteFor":"spil node [NOTE] i [DURATION] sekunder","wedo2.setLightHue":"sæt farven på lyset til [HUE]","wedo2.setMotorDirection":"sæt [MOTOR_ID] retning til [MOTOR_DIRECTION]","wedo2.startMotorPower":"sæt [MOTOR_ID] styrke til [POWER]","wedo2.tiltDirection.any":"vilkårlig","wedo2.tiltDirection.down":"ned","wedo2.tiltDirection.left":"venstre","wedo2.tiltDirection.right":"højre","wedo2.tiltDirection.up":"op","wedo2.whenDistance":"når afstanden [OP] [REFERENCE]","wedo2.whenTilted":"er vippet [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Farve","paint.paintEditor.saturation":"Farvemætning","paint.paintEditor.brightness":"Lysstyrke","paint.paintEditor.costume":"Kostume","paint.paintEditor.group":"Gruppe","paint.paintEditor.ungroup":"Opdel","paint.paintEditor.undo":"Fortryd","paint.paintEditor.redo":"Gør om","paint.paintEditor.forward":"Forrest","paint.paintEditor.backward":"Bagerst","paint.paintEditor.front":"Foran","paint.paintEditor.back":"Bagved","paint.paintEditor.more":"Mere","paint.modeTools.brushSize":"Størrelse","paint.modeTools.eraserSize":"Viskelæderets størrelse","paint.modeTools.copy":"Kopier","paint.modeTools.paste":"Sæt ind","paint.modeTools.delete":"Slet","paint.modeTools.curved":"Buet","paint.modeTools.pointed":"Spids","paint.modeTools.thickness":"Tykkelse","paint.modeTools.flipHorizontal":"Vend venstre-højre","paint.modeTools.flipVertical":"Vend op og ned","paint.modeTools.filled":"Fyldt","paint.modeTools.outlined":"Kant streg","paint.paintEditor.bitmap":"Konverter til Bitmap","paint.paintEditor.vector":"Konverter til Vektor","paint.paintEditor.fill":"Fyld","paint.paintEditor.stroke":"Kant","paint.brushMode.brush":"Pensel","paint.eraserMode.eraser":"Viskelæder","paint.fillMode.fill":"Fyld","paint.lineMode.line":"Linje","paint.ovalMode.oval":"Cirkel","paint.rectMode.rect":"Rektangel","paint.reshapeMode.reshape":"Omform","paint.roundedRectMode.roundedRect":"Afrundet rektangel","paint.selectMode.select":"Vælg","paint.textMode.text":"Tekst","paint.colorPicker.swap":"Byt"},"de":{"gui.alerts.tryAgain":"Erneut versuchen","gui.alerts.download":"Herunterladen","gui.connection.reconnect":"Erneut verbinden","gui.backpack.costumeLabel":"Kostüm","gui.backpack.soundLabel":"Klang","gui.backpack.scriptLabel":"Skript","gui.backpack.spriteLabel":"Figur","gui.backpack.header":"Lager","gui.backpack.errorBackpack":"Fehler beim Laden des Lagers","gui.backpack.loadingBackpack":"Wird geladen ...","gui.backpack.more":"Mehr","gui.backpack.emptyBackpack":"Das Lager ist leer","gui.unsupportedBrowser.label":"Browser wird nicht unterstützt","gui.cards.all-tutorials":"Tutorials","gui.cards.shrink":"Zuklappen","gui.cards.expand":"Aufklappen","gui.cards.close":"Schließen","gui.cards.more-things-to-try":"Probiere mehr Dinge aus","gui.cards.see-more":"Mehr erfahren","gui.comingSoon.message1":"Keine Sorge, wir kümmern uns darum {emoji}","gui.comingSoon.message2":"Bald verfügbar ...","gui.comingSoon.message3":"Wir arbeiten daran {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Keine Geräte gefunden","gui.connection.auto-scanning.prescan":"Starte die Suche, wenn du ein Gerät in der Nähe hast.","gui.connection.auto-scanning.pressbutton":"Drücke den Button an deinem Gerät.","gui.connection.auto-scanning.start-search":"Suche starten","gui.connection.connecting-searchbutton":"Suche läuft...","gui.connection.auto-scanning.try-again":"Versuche es noch einmal","gui.connection.connected":"Verbunden","gui.connection.disconnect":"Trenne","gui.connection.go-to-editor":"Gehe zum Editor","gui.connection.connecting-cancelbutton":"Ich verbinde...","gui.connection.error.errorMessage":"Hoppla, etwas hat wohl nicht funktioniert.","gui.connection.error.tryagainbutton":"Versuche es noch einmal","gui.connection.error.helpbutton":"Hilfe","gui.connection.peripheral-name-label":"Gerätename","gui.connection.connect":"Verbinde","gui.connection.scanning.lookingforperipherals":"Suche Geräte","gui.connection.scanning.noPeripheralsFound":"Keine Geräte gefunden","gui.connection.scanning.instructions":"Wähle dein Gerät oben in der Liste.","gui.connection.search":"Erneuere","gui.connection.unavailable.installscratchlink":"Überprüfe, ob du Scratch Link installiert hast und ob das Program läuft","gui.connection.unavailable.enablebluetooth":"Überprüfe, ob Bluetooth aktiviert ist","gui.connection.unavailable.tryagainbutton":"Versuche es noch einmal","gui.connection.unavailable.helpbutton":"Hilfe","gui.controls.go":"Los","gui.controls.stop":"Stopp","gui.crashMessage.label":"Hoppla! Da ist was schief gegangen.","gui.crashMessage.errorNumber":"Der Fehler wurde unter der ID {errorId} gespeichert.","gui.crashMessage.reload":"Neu laden","gui.customProcedures.myblockModalTitle":"Neuer Block","gui.customProcedures.addAnInputNumberText":"Eingabefeld hinzufügen","gui.customProcedures.numberTextType":"Zahl oder Text","gui.customProcedures.addAnInputBoolean":"Eingabefeld hinzufügen","gui.customProcedures.booleanType":"Wahrheitswert","gui.customProcedures.addALabel":"Beschriftung hinzufügen","gui.customProcedures.runWithoutScreenRefresh":"Ohne Bildschirmaktualisierung laufen lassen","gui.customProcedures.cancel":"Abbrechen","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Richtung","gui.directionPicker.rotationStyles.allAround":"Rundherum","gui.directionPicker.rotationStyles.leftRight":"Links/Rechts","gui.directionPicker.rotationStyles.dontRotate":"Nicht drehen","gui.gui.addExtension":"Erweiterung hinzufügen","gui.gui.codeTab":"Skripte","gui.gui.backdropsTab":"Bühnenbilder","gui.gui.costumesTab":"Kostüme","gui.gui.soundsTab":"Klänge","gui.extensionLibrary.comingSoon":"Bald verfügbar","gui.extensionLibrary.requires":"Erfordert","gui.extensionLibrary.collaboration":"Zusammenarbeit mit","gui.library.filterPlaceholder":"Suche","gui.library.allTag":"Alles","gui.loader.headline":"Projekt wird geladen","gui.loader.creating":"Projekt wird erstellt","gui.authorInfo.byUser":"von {username}","gui.menuBar.seeProjectPage":"Zeige Projektseite","gui.menuBar.LanguageSelector":"Sprachauswahl","gui.menuBar.tutorialsLibrary":"Tutorials","gui.menuBar.restoreSprite":"Figur wiederherstellen","gui.menuBar.restoreSound":"Klang wiederherstellen","gui.menuBar.restoreCostume":"Kostüm wiederherstellen","gui.menuBar.restore":"Wiederherstellen","gui.menuBar.saveNow":"Jetzt speichern","gui.menuBar.saveAsCopy":"Eine Kopie speichern","gui.menuBar.remix":"Remixen","gui.menuBar.new":"Neu","gui.menuBar.file":"Datei","gui.menuBar.downloadToComputer":"Auf deinem Computer speichern","gui.menuBar.edit":"Bearbeiten","gui.menuBar.turboModeOff":"Turbo-Modus ausschalten","gui.menuBar.turboModeOn":"Turbo-Modus einschalten","gui.gui.projectTitlePlaceholder":"Projekttitel","gui.menuBar.isShared":"Veröffentlicht","gui.menuBar.share":"Veröffentlichen","gui.modal.help":"Hilfe","gui.modal.back":"Zurück","gui.monitor.listMonitor.empty":"(leer)","gui.monitor.listMonitor.listLength":"Länge: {length}","gui.monitor.contextMenu.default":"Normale Anzeigengröße","gui.monitor.contextMenu.large":"Großanzeige","gui.monitor.contextMenu.slider":"Schieberegler","gui.monitor.contextMenu.sliderRange":"Wertebereich des Schiebereglers ändern","gui.monitor.contextMenu.import":"Importieren","gui.monitor.contextMenu.export":"Exportieren","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Abspielen","gui.playButton.stop":"Stopp","gui.gui.variableScopeOptionAllSprites":"Für alle Figuren","gui.gui.variableScopeOptionSpriteOnly":"Nur für diese Figur","gui.gui.cloudVariableOption":"Cloud-Variable (auf dem Server gespeichert)","gui.gui.variablePromptAllSpritesMessage":"Diese Variable wird für alle Figuren verfügbar sein.","gui.gui.listPromptAllSpritesMessage":"Diese Liste wird für alle Figuren sichtbar sein.","gui.prompt.cancel":"Abbrechen","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Stopp","gui.playbackStep.playMsg":"Abspielen","gui.playbackStep.loadingMsg":"Wird geladen ...","gui.playbackStep.saveMsg":"Speichern","gui.playbackStep.reRecordMsg":"Erneut aufnehmen","gui.recordModal.title":"Klang aufnehmen","gui.recordingStep.beginRecord":"Starte die Aufnahme, indem du auf den Knopf unten klickst","gui.recordingStep.permission":"{arrow}Wir benötigen deine Zustimmung, um dein Mikrofon zu benutzen","gui.recordingStep.stop":"Aufnahme beenden","gui.recordingStep.record":"Aufnehmen","gui.sliderModal.min":"Kleinster Wert","gui.sliderModal.max":"Größter Wert","gui.sliderModal.title":"Wertebereich des Schiebereglers ändern","gui.sliderPrompt.cancel":"Abbrechen","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Klang","gui.soundEditor.play":"Abspielen","gui.soundEditor.stop":"Stopp","gui.soundEditor.copy":"Kopieren","gui.soundEditor.paste":"Einfügen","gui.soundEditor.copyToNew":"Duplizieren","gui.soundEditor.delete":"Löschen","gui.soundEditor.save":"Speichern","gui.soundEditor.undo":"Rückgängig","gui.soundEditor.redo":"Wiederherstellen","gui.soundEditor.faster":"Schneller","gui.soundEditor.slower":"Langsamer","gui.soundEditor.echo":"Echo","gui.soundEditor.robot":"Roboter","gui.soundEditor.louder":"Lauter","gui.soundEditor.softer":"Leiser","gui.soundEditor.reverse":"Umkehren","gui.soundEditor.fadeOut":"Ausblenden","gui.soundEditor.fadeIn":"Einblenden","gui.soundEditor.mute":"Stummschalten","gui.SpriteInfo.spritePlaceholder":"Name","gui.SpriteInfo.sprite":"Figur","gui.SpriteInfo.show":"Zeige dich","gui.SpriteInfo.size":"Größe","gui.spriteSelectorItem.contextMenuDuplicate":"Duplizieren","gui.spriteSelectorItem.contextMenuExport":"Exportieren","gui.spriteSelectorItem.contextMenuDelete":"Löschen","gui.spriteSelector.addSpriteFromLibrary":"Figur wählen","gui.spriteSelector.addSpriteFromPaint":"Malen","gui.spriteSelector.addSpriteFromSurprise":"Überraschung","gui.spriteSelector.addSpriteFromFile":"Figur hochladen","gui.stageHeader.stageSizeLarge":"Schalte auf große Bühne um","gui.stageHeader.stageSizeSmall":"Schalte auf kleine Bühne um","gui.stageHeader.stageSizeFull":"Vollbildmodus","gui.stageHeader.stageSizeUnFull":"Vollbildmodus verlassen","gui.stageHeader.fullscreenControl":"Vollbildkontrolle","gui.spriteSelector.addBackdropFromLibrary":"Bühnenbild wählen","gui.stageSelector.addBackdropFromPaint":"Malen","gui.stageSelector.addBackdropFromSurprise":"Überraschung","gui.stageSelector.addBackdropFromFile":"Bühnenbild hochladen","gui.stageSelector.stage":"Bühne","gui.stageSelector.backdrops":"Bühnenbilder","gui.telemetryOptIn.label":"Statistiken zur Verbesserung von Scratch übermitteln","gui.telemetryOptIn.body1":"Das Scratch-Team interessiert sich dafür, wie Scratch weltweit verwendet wird. Um dabei zu helfen, kannst du Scratch erlauben, Daten über seine Verwendung automatisch an das Scratch-Team zu schicken.","gui.telemetryOptIn.body2":"Die Informationen, die wir sammeln, umfassen Sprachauswahl, Verwendung der Blöcke sowie Vorgänge wie Speichern, Laden und Hochladen von Projekten. Wir sammeln KEINERLEI personenbezogene Informationen. Weitere Informationen dazu finden sich unter {privacyPolicyLink}.","gui.telemetryOptIn.privacyPolicyLink":"Datenschutzrichtlinien","gui.telemetryOptIn.optInText":"Meine Nutzungsdaten mit dem Scratch-Team teilen","gui.telemetryOptIn.optInTooltip":"Telemetrie aktivieren","gui.telemetryOptIn.optOutText":"Meine Nutzungsdaten nicht mit dem Scratch-Team teilen","gui.telemetryOptIn.optOutTooltip":"Telemetrie deaktivieren","gui.telemetryOptIn.settingWasUpdated":"Deine Einstellung wurde aktualisiert.","gui.telemetryOptIn.buttonClose":"Schließen","gui.turboMode.active":"Turbo-Modus","gui.webglModal.label":"Dein Browser unterstützt kein WebGL","gui.webglModal.webgllink":"unterstützt kein WebGL","gui.costumeLibrary.chooseABackdrop":"Wähle ein Bühnenbild","gui.costumeLibrary.chooseACostume":"Wähle ein Kostüm","gui.costumeTab.addBackdropFromLibrary":"Wähle ein Bühnenbild","gui.costumeTab.addCostumeFromLibrary":"Wähle ein Kostüm","gui.costumeTab.addBlankCostume":"Malen","gui.costumeTab.addSurpriseCostume":"Überraschung","gui.costumeTab.addFileBackdrop":"Bühnenbild hochladen","gui.costumeTab.addFileCostume":"Kostüm hochladen","gui.extensionLibrary.chooseAnExtension":"Erweiterung auswählen","gui.extensionLibrary.extensionUrl":"Gib die URL der Erweiterung ein","gui.monitors.importListColumnPrompt":"Welche Spalte soll verwendet werden (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Aufnahme konnte nicht gestartet werden","gui.soundLibrary.chooseASound":"Klang wählen","gui.soundTab.fileUploadSound":"Klang hochladen","gui.soundTab.surpriseSound":"Überraschung","gui.soundTab.recordSound":"Aufnehmen","gui.soundTab.addSoundFromLibrary":"Klang wählen","gui.spriteLibrary.chooseASprite":"Figur wählen","gui.tipsLibrary.tutorials":"Wähle ein Tutorial","gui.alerts.createsuccess":"Ein neues Projekt wurde erstellt.","gui.alerts.createcopysuccess":"Das Projekt wurde als Kopie gespeichert.","gui.alerts.createremixsuccess":"Das Projekt wurde als Remix gespeichert.","gui.alerts.creating":"Ein neues Projekt wird erzeugt...","gui.alerts.creatingCopy":"Das Projekt wird kopiert...","gui.alerts.creatingRemix":"Das Projekt wird remixt...","gui.alerts.creatingError":"Das Projekt konnte nicht erstellt werden. Versuche es bitte erneut! ","gui.alerts.savingError":"Das Projekt konnte nicht gespeichert werden.","gui.alerts.savesuccess":"Das Projekt wurde gespeichert.","gui.alerts.saving":"Das Projekt wird gespeichert...","gui.alerts.cloudInfo":"Beachte bitte, dass Cloud-Variablen nur Zahlen unterstützen, keine Buchstaben oder Symbole. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Erfahre mehr.","gui.alerts.importing":"Importiere...","gui.defaultProject.variable":"meine Variable","gui.extension.music.name":"Musik","gui.extension.music.description":"Spiele Instrumente und Schlagzeug.","gui.extension.pen.name":"Malstift","gui.extension.pen.description":"Zeichne mit deinen Figuren.","gui.extension.videosensing.name":"Video-Erfassung","gui.extension.videosensing.description":"Erfasse Bewegung mit der Kamera.","gui.extension.text2speech.name":"Text zu Sprache","gui.extension.text2speech.description":"Bring deinen Projekten das Sprechen bei.","gui.extension.translate.name":"Übersetzen","gui.extension.translate.description":"Übersetze den Text in viele Sprachen.","gui.extension.makeymakey.description":"Mach alles zu einer Taste.","gui.extension.microbit.description":"Verbinde deine Projekte mit der realen Welt.","gui.extension.microbit.connectingMessage":"Verbinde","gui.extension.ev3.description":"Baue interaktive Roboter und mehr.","gui.extension.ev3.connectingMessage":"Verbinde. Stelle sicher, dass das Kennwort auf deiner EV3 auf 1234 gesetzt ist.","gui.extension.boost.description":"Erwecke Roboterkreationen zum Leben.","gui.extension.boost.connectingMessage":"Verbinde","gui.extension.wedo2.description":"Baue mit Motoren und Sensoren.","gui.extension.wedo2.connectingMessage":"Verbinde","gui.extension.gdxfor.description":"Spüre Druck, Zug, Bewegung und Drehung","gui.extension.gdxfor.connectingMessage":"Verbinde","gui.libraryTags.all":"Alles","gui.libraryTags.animals":"Tiere","gui.libraryTags.dance":"Tanz","gui.libraryTags.effects":"Effekte","gui.libraryTags.fantasy":"Fantasie","gui.libraryTags.fashion":"Mode","gui.libraryTags.food":"Essen","gui.libraryTags.indoors":"Innenräume","gui.libraryTags.loops":"Schleifen","gui.libraryTags.music":"Musik","gui.libraryTags.notes":"Noten","gui.libraryTags.outdoors":"Landschaften","gui.libraryTags.patterns":"Muster","gui.libraryTags.people":"Personen","gui.libraryTags.percussion":"Schlagwerk","gui.libraryTags.space":"Weltraum","gui.libraryTags.sports":"Sport","gui.libraryTags.underwater":"Unterwasserwelt","gui.libraryTags.voice":"Stimmen","gui.libraryTags.wacky":"Verrücktes","gui.libraryTags.animation":"Animationen","gui.libraryTags.art":"Kunst","gui.libraryTags.games":"Spiele","gui.libraryTags.stories":"Geschichten","gui.libraryTags.letters":"Buchstaben","gui.opcodeLabels.direction":"Richtung","gui.opcodeLabels.xposition":"x-Position","gui.opcodeLabels.yposition":"y-Position","gui.opcodeLabels.size":"Größe","gui.opcodeLabels.costumename":"Kostümname","gui.opcodeLabels.costumenumber":"Kostümnummer","gui.opcodeLabels.backdropname":"Bühnenbildname","gui.opcodeLabels.backdropnumber":"Bühnenbildnummer","gui.opcodeLabels.volume":"Lautstärke","gui.opcodeLabels.tempo":"Tempo","gui.opcodeLabels.answer":"Antwort","gui.opcodeLabels.loudness":"Lautstärke","gui.opcodeLabels.username":"Benutzername","gui.opcodeLabels.year":"Jahr","gui.opcodeLabels.month":"Monat","gui.opcodeLabels.date":"Datum","gui.opcodeLabels.dayofweek":"Wochentag","gui.opcodeLabels.hour":"Stunde","gui.opcodeLabels.minute":"Minute","gui.opcodeLabels.second":"Sekunde","gui.opcodeLabels.timer":"Stoppuhr","gui.sharedMessages.backdrop":"Bühnenbild{index}","gui.sharedMessages.costume":"Kostüm{index}","gui.sharedMessages.sprite":"Figur{index}","gui.sharedMessages.pop":"Plopp","gui.sharedMessages.replaceProjectWarning":"Inhalte des aktuellen Projektes ersetzen?","gui.sharedMessages.loadFromComputerTitle":"Von deinem Computer hochladen","boost.color.any":"Irgendeine Farbe","boost.color.black":"Schwarz","boost.color.blue":"Blau","boost.color.green":"Grün","boost.color.red":"Rot","boost.color.white":"Weiss","boost.color.yellow":"Gelb","boost.getMotorPosition":"Position des Motors [MOTOR_REPORTER_ID]","boost.getTiltAngle":"Neigungswinkel [TILT_DIRECTION]","boost.motorDirection.backward":"linksherum","boost.motorDirection.forward":"rechtsherum","boost.motorDirection.reverse":"andersherum","boost.motorOff":"Schalte Motor [MOTOR_ID] aus","boost.motorOn":"Schalte Motor [MOTOR_ID] ein","boost.motorOnFor":"Schalte Motor [MOTOR_ID] für [DURATION] Sekunden ein","boost.motorOnForRotation":"Schalte Motor [MOTOR_ID] für [ROTATION] Umdrehungen ein","boost.seeingColor":"Sehe Farbe [COLOR]?","boost.setLightHue":"setze Lichtfarbe auf [HUE]","boost.setMotorDirection":"Setze Richtung von Motor [MOTOR_ID] auf [MOTOR_DIRECTION]","boost.setMotorPower":"Setze von Motor [MOTOR_ID] die Geschwindigkeit auf [POWER]%","boost.tiltDirection.any":"irgendwohin","boost.tiltDirection.down":"nach unten","boost.tiltDirection.left":"nach links","boost.tiltDirection.right":"nach rechts","boost.tiltDirection.up":"nach oben","boost.whenColor":"Wenn [COLOR] gesehen wird","boost.whenTilted":"Wenn [TILT_DIRECTION_ANY] geneigt","ev3.beepNote":"piepse Note [NOTE] für [TIME] Sek.","ev3.buttonPressed":"Knopf [PORT] gedrückt?","ev3.getBrightness":"Helligkeit","ev3.getDistance":"Abstand","ev3.getMotorPosition":"Position von Motor [PORT]","ev3.motorSetPower":"setze Leistung von Motor [PORT] auf [POWER]%","ev3.motorTurnClockwise":"drehe Motor [PORT] für [TIME]Sekunden rechtsherum","ev3.motorTurnCounterClockwise":"drehe Motor [PORT]für [TIME]Sekunden linksherum","ev3.whenBrightnessLessThan":"Wenn Helligkeit < [DISTANCE]","ev3.whenButtonPressed":"Wenn der Knopf [PORT] gedrückt wird","ev3.whenDistanceLessThan":"Wenn Abstand < [DISTANCE]","gdxfor.getAcceleration":"Beschleunigung [DIRECTION]","gdxfor.getForce":"Kraft","gdxfor.getSpin":"Rotationsgeschwindigkeit [DIRECTION]","gdxfor.getTilt":"Neigungswinkel [TILT]","gdxfor.isFreeFalling":"fallend?","gdxfor.isTilted":"geneigt [TILT]?","gdxfor.pulled":"gezogen","gdxfor.pushed":"gedrückt","gdxfor.shaken":"geschüttelt","gdxfor.startedFalling":"begonnen zu fallen","gdxfor.tiltDirectionMenu.any":"irgendwohin","gdxfor.tiltDirectionMenu.back":"nach hinten","gdxfor.tiltDirectionMenu.front":"nach vorne","gdxfor.tiltDirectionMenu.left":"nach links","gdxfor.tiltDirectionMenu.right":"nach rechts","gdxfor.turnedFaceDown":"nach unten gerichtet","gdxfor.turnedFaceUp":"nach oben gerichtet","gdxfor.whenForcePushedOrPulled":"Wenn Kraftsensor [PUSH_PULL]","gdxfor.whenGesture":"Wenn [GESTURE]","gdxfor.whenTilted":"Wenn geneigt [TILT]","makeymakey.downArrow":"Pfeil nach unten","makeymakey.downArrowShort":"nach unten","makeymakey.leftArrow":"Pfeil nach links","makeymakey.leftArrowShort":"nach links","makeymakey.rightArrow":"Pfeil nach rechts","makeymakey.rightArrowShort":"nach rechts","makeymakey.spaceKey":"Leertaste","makeymakey.upArrow":"Pfeil nach oben","makeymakey.upArrowShort":"nach oben","makeymakey.whenKeyPressed":"Wenn Taste [KEY] gedrückt","makeymakey.whenKeysPressedInOrder":"Wenn [SEQUENCE] der Reihe nach gedrückt","microbit.buttonsMenu.any":"beliebiger","microbit.clearDisplay":"zeige nichts an","microbit.defaultTextToDisplay":"Hallo!","microbit.displaySymbol":"zeige [MATRIX] an","microbit.displayText":"zeige Text [TEXT] an","microbit.gesturesMenu.jumped":"hochgehüpft","microbit.gesturesMenu.moved":"bewegt","microbit.gesturesMenu.shaken":"geschüttelt","microbit.isButtonPressed":"Knopf [BTN] gedrückt? ","microbit.isTilted":"[DIRECTION] geneigt?","microbit.pinStateMenu.off":"aus","microbit.pinStateMenu.on":"an","microbit.tiltAngle":"Neigungswinkel [DIRECTION]","microbit.tiltDirectionMenu.any":"beliebig","microbit.tiltDirectionMenu.back":"nach hinten","microbit.tiltDirectionMenu.front":"nach vorne","microbit.tiltDirectionMenu.left":"nach links","microbit.tiltDirectionMenu.right":"nach rechts","microbit.whenButtonPressed":"Wenn Knopf [BTN]gedrückt wird","microbit.whenGesture":"Wenn [GESTURE]","microbit.whenPinConnected":"Wenn Pin [PIN] angeschlossen ist","microbit.whenTilted":"Wenn [DIRECTION] geneigt","music.categoryName":"Musik","music.changeTempo":"ändere Tempo um [TEMPO]","music.drumBass":"(2) Basstrommel","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Klangstäbe","music.drumClosedHiHat":"(6) Geschlossene Hi-Hat","music.drumConga":"(14) Konga","music.drumCowbell":"(11) Kuhglocke","music.drumCrashCymbal":"(4) Crash-Becken","music.drumCuica":"(18) Cuíca","music.drumGuiro":"(16) Güiro","music.drumHandClap":"(8) Klatschen","music.drumOpenHiHat":"(5) Offene Hi-Hat","music.drumSideStick":"(3) Side-Stick","music.drumSnare":"(1) Snare-Drum","music.drumTambourine":"(7) Tamburin","music.drumTriangle":"(12) Triangel","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Holzblock","music.getTempo":"Tempo","music.instrumentBass":"(6) Bass-Gitarre","music.instrumentBassoon":"(14) Fagott","music.instrumentCello":"(8) Cello","music.instrumentChoir":"(15) Chor","music.instrumentClarinet":"(10) Klarinette","music.instrumentElectricGuitar":"(5) E-Gitarre","music.instrumentElectricPiano":"(2) E-Piano","music.instrumentFlute":"(12) Querflöte","music.instrumentGuitar":"(4) Gitarre","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Musikbox","music.instrumentOrgan":"(3) Orgel","music.instrumentPiano":"(1) Klavier","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxophon","music.instrumentSteelDrum":"(18) Steel-Drum","music.instrumentSynthLead":"(20) Lead-Synthesizer","music.instrumentSynthPad":"(21) Pad-Synthesizer","music.instrumentTrombone":"(9) Posaune","music.instrumentVibraphone":"(16) Vibraphon","music.instrumentWoodenFlute":"(13) Blockflöte","music.midiPlayDrumForBeats":"spiele Schlaginstrument [DRUM] für [BEATS] Schläge","music.midiSetInstrument":"setze Instrument auf [INSTRUMENT]","music.playDrumForBeats":"spiele Schlaginstrument [DRUM] für [BEATS] Schläge","music.playNoteForBeats":"spiele Ton [NOTE] für [BEATS] Schläge","music.restForBeats":"pausiere [BEATS] Schläge","music.setInstrument":"setze Instrument auf [INSTRUMENT]","music.setTempo":"setze Tempo auf [TEMPO]","pen.categoryName":"Malstift","pen.changeColorParam":"ändere Stift [COLOR_PARAM] um [VALUE]","pen.changeHue":"ändere Stiftfarbe um [HUE]","pen.changeShade":"ändere Farbstärke um [SHADE]","pen.changeSize":"ändere Stiftdicke um [SIZE]","pen.clear":"lösche alles","pen.colorMenu.brightness":"Helligkeit","pen.colorMenu.color":"Farbe","pen.colorMenu.saturation":"Sättigung","pen.colorMenu.transparency":"Transparenz","pen.penDown":"schalte Stift ein","pen.penUp":"schalte Stift aus","pen.setColor":"setze Stiftfarbe auf [COLOR]","pen.setColorParam":"setze Stift [COLOR_PARAM] auf [VALUE]","pen.setHue":"setze Stiftfarbe auf [HUE]","pen.setShade":"setze Farbstärke auf [SHADE]","pen.setSize":"setze Stiftdicke auf [SIZE]","pen.stamp":"hinterlasse Abdruck","text2speech.alto":"Alt","text2speech.categoryName":"Text zu Sprache","text2speech.defaultTextToSpeak":"Hallo","text2speech.giant":"Riese","text2speech.kitten":"Kätzchen","text2speech.setLanguageBlock":"setze Sprache auf [LANGUAGE]","text2speech.setVoiceBlock":"ändere die Stimme zu [VOICE]","text2speech.speakAndWaitBlock":"sage [WORDS]","text2speech.squeak":"Quietschen","text2speech.tenor":"Tenor","translate.categoryName":"Übersetzung","translate.defaultTextToTranslate":"Hallo","translate.translateBlock":"übersetze [WORDS] nach [LANGUAGE]","translate.viewerLanguage":"Sprache","videoSensing.categoryName":"Video-Erfassung","videoSensing.direction":"Richtung","videoSensing.motion":"Bewegung","videoSensing.off":"aus","videoSensing.on":"an","videoSensing.onFlipped":"auf gespiegelt","videoSensing.setVideoTransparency":"setze Video-Transparenz auf [TRANSPARENCY]","videoSensing.sprite":"Figur","videoSensing.stage":"Bühne","videoSensing.videoOn":"Video-[ATTRIBUTE] von [SUBJECT]","videoSensing.videoToggle":"schalte Video [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"Wenn Video-Bewegung > [REFERENCE]","wedo2.getDistance":"Abstand","wedo2.getTiltAngle":"Neigungswinkel [TILT_DIRECTION]","wedo2.isTilted":"[TILT_DIRECTION_ANY] geneigt?","wedo2.motorDirection.backward":"linksherum","wedo2.motorDirection.forward":"rechtsherum","wedo2.motorDirection.reverse":"andersherum","wedo2.motorId.a":"Motor A","wedo2.motorId.all":"alle Motoren","wedo2.motorId.b":"Motor B","wedo2.motorId.default":"Motor","wedo2.motorOff":"schalte [MOTOR_ID] aus","wedo2.motorOn":"schalte [MOTOR_ID] an","wedo2.motorOnFor":"schalte [MOTOR_ID] für [DURATION] Sekunden an","wedo2.playNoteFor":"spiele Note [NOTE] für [DURATION] Sekunden","wedo2.setLightHue":"setze Lichtfarbe auf [HUE]","wedo2.setMotorDirection":"setze Richtung von [MOTOR_ID] auf [MOTOR_DIRECTION]","wedo2.startMotorPower":"setze Leistung von [MOTOR_ID] auf [POWER]","wedo2.tiltDirection.any":"beliebig","wedo2.tiltDirection.down":"nach unten","wedo2.tiltDirection.left":"nach links","wedo2.tiltDirection.right":"nach rechts","wedo2.tiltDirection.up":"nach oben","wedo2.whenDistance":"Wenn Abstand [OP] [REFERENCE]","wedo2.whenTilted":"Wenn [TILT_DIRECTION_ANY] geneigt","paint.paintEditor.hue":"Farbe","paint.paintEditor.saturation":"Sättigung","paint.paintEditor.brightness":"Helligkeit","paint.paintEditor.costume":"Kostüm","paint.paintEditor.group":"Gruppieren","paint.paintEditor.ungroup":"Gruppierung aufheben","paint.paintEditor.undo":"Rückgängig","paint.paintEditor.redo":"Wiederherstellen","paint.paintEditor.forward":"nach vorne","paint.paintEditor.backward":"nach hinten","paint.paintEditor.front":"Ganz nach vorne","paint.paintEditor.back":"Ganz nach hinten","paint.paintEditor.more":"Mehr","paint.modeTools.brushSize":"Größe","paint.modeTools.eraserSize":"Radiererbreite","paint.modeTools.copy":"Kopieren","paint.modeTools.paste":"Einfügen","paint.modeTools.delete":"Löschen","paint.modeTools.curved":"gekrümmt","paint.modeTools.pointed":"gerade","paint.modeTools.thickness":"Linienstärke","paint.modeTools.flipHorizontal":"Horizontal spiegeln","paint.modeTools.flipVertical":"Vertikal spiegeln","paint.modeTools.filled":"Ausgefüllt","paint.modeTools.outlined":"Umrandet","paint.paintEditor.bitmap":"In Rastergrafik umwandeln","paint.paintEditor.vector":"In Vektorgrafik umwandeln","paint.paintEditor.fill":"Füllfarbe","paint.paintEditor.stroke":"Randfarbe","paint.brushMode.brush":"Pinsel","paint.eraserMode.eraser":"Radierer","paint.fillMode.fill":"Fülleimer","paint.lineMode.line":"Linie","paint.ovalMode.oval":"Kreis","paint.rectMode.rect":"Rechteck","paint.reshapeMode.reshape":"Verformen","paint.roundedRectMode.roundedRect":"Abgerundetes Rechteck ","paint.selectMode.select":"Auswählen","paint.textMode.text":"Text","paint.colorPicker.swap":"Tauschen","tw.alerts.autosaving":"Wiederherstellungspunkt wird erstellt...","tw.alerts.lostPeripheralConnection":"Verbindung zu {extensionName} verloren.","tw.alerts.savedToDisk":"Auf deinem Computer gespeichert.","tw.backpack.rename":"Neuer Name:","tw.browserModal.desc":"Überprüfe, ob du eine neuere Versionvon Google Chrome, Mozilla Firefox, Microsoft Edge oder Apple Safari verwendest.","tw.cantUseCloud":"Obwohl du Cloud-Variablen erstellen kannst, werden sie bis zum Hochladen auf Scratch oder auf einem Tool wie dem {packager} nicht funktionieren.","tw.changeUsername.cannotChangeWhileRunning":"Der Benutzername kann nicht geändert werden, während das Projekt ausgeführt wird.","tw.cloudVariableBadge":"Dieses Projekt verwendet Cloudvariablen. TurboWarp verwendet einen eigenen Cloudvariablenserver unabhängig von Scratch. Vergiss nicht, dass jeder seinen Benutzernamen auf alles ändern kann. {learnMore}","tw.code":"Quellcode","tw.confirmIncompatibleExtension":"Diese Erweiterung ist nicht mit Scratch kompatibel. Projekte, die damit entwickelt werden, können nicht auf die Scratch-Website geladen werden. Bist du sicher, dass du sie aktivieren willst?","tw.customExtension.description":"Benutzerdefinierte Erweiterungen von URLs laden. Für Entwickler. Experimentell.","tw.customExtension.name":"Benutzerdefinierte Erweiterung","tw.featuredProjectsStudio":"Studio auf Scratch anzeigen.","tw.feedback":"Feedback & Fehler","tw.feedbackButton":"Feedback","tw.footer.credits":"Danksagungen","tw.footer.disclaimer":"TurboWarp ist nicht mit Scratch, dem Scratch-Team oder der Scratch-Stiftung verbunden.","tw.footer.donate":"Spenden","tw.footer.embed":"Einbettung","tw.footer.fosshost":"Von Fosshost gehosted","tw.footer.parameters":"URL-Parameter","tw.footer.translate":"Hilf mit beim Übersetzen von TurboWarp","tw.gui.crashMessage.description":"Es tut uns leid, anscheinend ist die Seite abgestürzt. Bitte aktualisiere die Seite und versuche es erneut.","tw.gui.defaultProjectTitle":"Projekt","tw.guiDefaultTitle":"Scratch-Projekte schneller ausführen","tw.home.credit":"Anmerkungen und Danksagungen","tw.home.description":"TurboWarp ist ein Scratch-Mod, das Projekte in JavaScript kompiliert, um sie sehr schnell auszuführen. Probiere es aus, indem du eine Projekt-ID oder -URL oben eingibst, oder ein vorgestelltes Projekt unten auswählst.","tw.home.instructions":"Anleitung","tw.input.tooltip":"Kopiere den Link zu einem Scratch-Projekt und füge ihn hier ein!","tw.invalidParameters.clones":"URL-Parameter \\"clone\\" ist ungültig","tw.invalidParameters.fps":"URL-Parameter \\"fps\\" ist ungültig","tw.loadError":"Fehler beim Laden des Projekts: {error}","tw.loader.assets.known":"Ressourcen werden heruntergeladen ({complete}/{total}) ...","tw.loader.assets.unknown":"Ressourcen werden heruntergeladen ...","tw.loader.data":"Projektdaten werden heruntergeladen ...","tw.loader.generic":"Projekt wird geladen ...","tw.menuBar.60off":"60 FPS-Modus ausschalten","tw.menuBar.60on":"60 FPS-Modus einschalten","tw.menuBar.advanced":"Erweitert","tw.menuBar.changeUsername":"Benutzernamen ändern","tw.menuBar.cloudOff":"Cloud-Variablen ausschalten","tw.menuBar.cloudOn":"Cloud-Variablen einschalten","tw.menuBar.cloudUnavailable":"Cloud-Variablen sind nicht Verfügbar","tw.menuBar.cloudUnavailableAlert":"Kann Cloud-Variablen nicht verwenden, wahrscheinlich, weil du den Editor geöffnet hast.","tw.menuBar.loadRestorePoint":"Wiederherstellungspunkt laden","tw.menuBar.moreSettings":"Erweitert","tw.menuBar.newFramerate":"Neue Framefrequenz:","tw.menuBar.package":"Paketisieren","tw.menuBar.reportError1":"Manche Skripte konnten nicht kompiliert werden.","tw.menuBar.reportError2":"Dies ist ein Fehler. Bitte melde ihn.","tw.menuBar.saveAs":"Speichern unter {file}","tw.menuBar.seeInside":"Schau hinein","tw.oldDownload":"Kopie speichern unter...","tw.openAdvanced":"Öffne die fortgeschrittenen Einstellungen","tw.paint.alpha":"Durchsichtigkeit","tw.privacy":"Datenschutzerklärung","tw.restorePoint.confirm":"Der Editor speichert einen automatischen Wiederherstellungspunkt, falls du vergessen hast zu speichern und ein Fehler auftritt. Du solltest dich nicht darauf verlassen und wir können nicht garantieren, dass dein Projekt wiederhergestellt wird. Versuchen, ihn zu laden?","tw.restorePoint.loadFail":"Backup konnte nicht geladen werden: {error}","tw.saveAs":"Speichern unter...","tw.saveTo":"Speichern unter {file}","tw.scratchUnsafeCloud":"Falls du diese Cloudvariable machst, wird dieses Projekt die maximale Anzahl von {number} Variablen überschreiten, und manche von ihnen werden beim Hochladen auf Scratch nicht funktionieren.","tw.settingsModal.customStageSize":"Benutzerdefinierte Bühnengröße:","tw.settingsModal.customStageSizeHelp":"Ändert die Größe der Bühne von 480x360 zu etwas anderem. Versuche 640x360, um die Bühen erweitert zu machen. Sehr wenige Projekte behandlen diese Einstellung richtig.","tw.settingsModal.dangerZone":"Gefahrenzone","tw.settingsModal.disableCompiler":"Compiler ausschalten","tw.settingsModal.disableCompilerHelp":"Deaktiviert den TurboWarp-Compiler. Du möchtest dies vielleicht während dem Bearbeiten von Projekten aktivieren, damit die Skripte sofort aktualisiert werden, ansonsten solltest du dies nicht aktivieren.","tw.settingsModal.featured":"Vorgestellt","tw.settingsModal.fps":"60 FPS (Benutzerdefinierte FPS)","tw.settingsModal.fpsHelp":"Führt Skripte 60 anstatt 30 Mal pro Sekunde aus. Die meisten Projekte werden mit diesem nicht richtig funktionieren. Falls dies der Fall ist, solltest du Interpolation ohne 60 FPS verwenden. {customFramerate}.","tw.settingsModal.fpsHelp.customFramerate":"Klicke, um eine andere Framefrequenz als 30 oder 60 zu verwenden","tw.settingsModal.help":"Klicke für Hilfe","tw.settingsModal.highQualityPen":"Stift mit Hoher Qualität","tw.settingsModal.highQualityPenHelp":"Erlaubt Stiftprojekte mit höherer Auflösung zu rendern und deaktiviert manche Koordinatenrundungen im Editor. Nicht alle Projekte haben einen Vorteil von dieser EInstellung, und sie könnte die Leistung beeinflussen.","tw.settingsModal.infiniteClones":"Unendliche Klone","tw.settingsModal.infiniteClonesHelp":"Deaktiviert Scratch\'s Limit von 300 Klonen.","tw.settingsModal.interpolationHelp":"Macht, dass es so aussieht, als würde ein Projekt glätter ausgeführt werden, indem es die Bewegungen der Figuren interpoliert. Interpolation sollte nicht auf 3D-Projekten, Raytracern, Stiftprojekten und laggenden Projekten verwendet werden, da die Interpolation sie langsamer ausführen wird.","tw.settingsModal.largeStageWarning":"Es wird nicht empfohlen, die Bühne so groß zu machen! Verwende stattdessen eine kleinere Zahl mit der gleichen Ansichtsratio und lass den Vollbildschirm sie größer machen, um sie mit dem Display des Benutzers anzupassen.","tw.settingsModal.removeFencing":"Einzäunung entfernen","tw.settingsModal.removeFencingHelp":"Lässt zu, dass sich Figuren über den Bildschirm hinaus bewegen, so groß oder so klein werden, wie sie wollen und macht die Erkennung von Berührungen zwischen Figuren außerhalb des Bildschirms möglich.","tw.settingsModal.removeLimits":"Limits enfernen","tw.settingsModal.removeMiscLimits":"Verschiedene Begrenzungen entfernen","tw.settingsModal.removeMiscLimitsHelp":"Entfernt Begrenzungen bei Klangeffekten und bei der Stiftgröße.","tw.settingsModal.storeProjectOptions":"Einstellungen im Projekt speichern","tw.settingsModal.storeProjectOptionsHelp":"Speichert die ausgewählten Einstellungen im Projekt, damit sie beim Laden in TurboWarp automatisch angewendet werden. Der Compiler und der Warp Timer werden nicht gespeichert.","tw.settingsModal.title":"Erweiterte Einstellungen","tw.settingsModal.warpTimerHelp":"Überprüft, ob Skripte in einer langen oder endlosen Schleife feststecken, und führt sie mit einer niedrigeren Framefrequenz aus, anstatt sie auf das Ende der Schleife warten zu zu lassen. was die meisten Abstürze verbessert aber einen bedeutenden Einfluss auf die Leistung hat, deshalb ist es standardmäßig außerhalb des Editors deaktiviert.","tw.spriteSelectorItem.rename":"umbenennnen","tw.stereoAlert":"Dieses Stereo geräusch zu ändern wird es zu Mono umwandeln, ohne dass man es wieder zurückumwandeln kann.","tw.studioview.authorAttribution":"von {author}","tw.studioview.error":"Es gab einen Fehler beim Laden der nächsten Seite von Projekten.","tw.studioview.hoverText":"{title} von {author}","tw.tooLarge":"Dieses Geräusch könnte zu groß sein um es auf Scratch hochzuladen.","tw.twExtension.description":"Seltsame neue Blöcke. Funktionieren nicht auf Scratch.","tw.twExtension.name":"TurboWarp-Blöcke","tw.unshared.1":"Der Zugriff auf nicht veröffentlichte Projekte wird in Zukunft aufgrund von kommenden Änderungen in der Scratch-API nicht mehr möglich sein.","tw.unshared.2":"Mehr Informationen unter: {link}","tw.unshared.cache":"Falls das Projekt erst vor Kurzem veröffentlicht wurde, wird diese Nachricht möglicherweise für einige Minuten erscheinen.","tw.usernameModal.help":"Dieser Wert wird in deinem Browserspeicher gespeichert. Er könnte geloggt werden, wenn du mit Projekten, die Cloudvariablen enthalten, interagierst.","tw.usernameModal.help2":"Werte, die nicht mit einem gültigen Scratch-Konto entsprechen, werden normalerweise vom Cloudserver abgelehnt. Es ist empfohlen, diesen Wert so zu lassen, wie er ist, oder ihn auf deinen Scratch-Benutzernamen zu setzen.","tw.usernameModal.mustChange":"Es tut uns Leid, der Cloudvariablenserver denkt, dass dein Benutzername unsicher sein könnte. Bitte ändere ihn oder {resetIt}.","tw.usernameModal.mustChange.resetIt":"setze ihn zurück (empfohlen)","tw.usernameModal.reset":"Zurücksetzen","tw.usernameModal.title":"Benutzernamen ändern","tw.viewFeaturedProjects":"Klicke, um vorgestellte Projekte anzusehen.","tw.viewOnScratch":"Projekt auf Scratch anzeigen","tw.webglModal.description":"Leider sieht es aus, als würde dein Computer oder Browser {webGlLink}. Diese Technologie ist erforderlich, damit diese Seite funktioniert. Versuche, deinen Browser und deine Grafiktreiber zu aktualisieren, oder deinen Computer neu zu starten."},"et":{"gui.alerts.tryAgain":"Proovi uuesti","gui.alerts.download":"Laadi alla","gui.connection.reconnect":"Ühenda uuesti","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Seljakott","gui.backpack.errorBackpack":"Viga seljakoti laadimisel","gui.backpack.loadingBackpack":"Laadib...","gui.backpack.more":"Rohkem","gui.backpack.emptyBackpack":"Seljakott on tühi","gui.unsupportedBrowser.label":"Veebilehitsejat ei toetata","gui.cards.all-tutorials":"Õpetused","gui.cards.shrink":"Shrink","gui.cards.expand":"Expand","gui.cards.close":"Sulge","gui.cards.more-things-to-try":"Proovi veel asju!","gui.cards.see-more":"Vaata veel","gui.comingSoon.message1":"Ära muretse, tegeleme sellega {emoji}","gui.comingSoon.message2":"Ilmub varsti...","gui.comingSoon.message3":"Tegeleme sellega {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Seadmeid ei leidnud","gui.connection.auto-scanning.prescan":"Kui seade on olemas, siis alusta otsimist.","gui.connection.auto-scanning.pressbutton":"Vajuta oma seadme nuppu.","gui.connection.auto-scanning.start-search":"Alusta otsimist","gui.connection.connecting-searchbutton":"Otsing...","gui.connection.auto-scanning.try-again":"Proovi uuesti","gui.connection.connected":"Ühendatud","gui.connection.disconnect":"Ühenda lahti","gui.connection.go-to-editor":"Mine redaktorisse","gui.connection.connecting-cancelbutton":"Ühendub...","gui.connection.error.errorMessage":"Oih! Midagi läks valesti.","gui.connection.error.tryagainbutton":"Proovi uuesti","gui.connection.error.helpbutton":"Abi","gui.connection.peripheral-name-label":"Seadme nimi","gui.connection.connect":"Ühenda","gui.connection.scanning.lookingforperipherals":"Seadmete otsimine","gui.connection.scanning.noPeripheralsFound":"Seadmeid ei leidnud","gui.connection.scanning.instructions":"Vali oma seade loendist.","gui.connection.search":"Värskenda","gui.connection.unavailable.installscratchlink":"Hoolitse, et Scratch Link on installeeritud ja töötab","gui.connection.unavailable.enablebluetooth":"Kontrolli, et Bluetooth on lubatud","gui.connection.unavailable.tryagainbutton":"Proovi uuesti","gui.connection.unavailable.helpbutton":"Abi","gui.controls.go":"Mine","gui.controls.stop":"Stopp","gui.crashMessage.label":"Oih! Midagi läks valesti.","gui.crashMessage.errorNumber":"See viga logiti tunnusega {errorId}","gui.crashMessage.reload":"Laadi uuesti","gui.customProcedures.myblockModalTitle":"Loo Plokk","gui.customProcedures.addAnInputNumberText":"Lisa parameeter","gui.customProcedures.numberTextType":"arv või tekst","gui.customProcedures.addAnInputBoolean":"Lisa parameeter","gui.customProcedures.booleanType":"tõeväärtus","gui.customProcedures.addALabel":"Lisa märgend","gui.customProcedures.runWithoutScreenRefresh":"Täida ekraanikuva uuendamata","gui.customProcedures.cancel":"Katkesta","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Suund","gui.directionPicker.rotationStyles.allAround":"suvaline","gui.directionPicker.rotationStyles.leftRight":"vasak/parem","gui.directionPicker.rotationStyles.dontRotate":"ei pöördu","gui.gui.addExtension":"Lisa laiendus","gui.gui.codeTab":"Kood","gui.gui.backdropsTab":"Taustad","gui.gui.costumesTab":"Kostüümid","gui.gui.soundsTab":"Helid","gui.extensionLibrary.comingSoon":"Ilmub varsti...","gui.extensionLibrary.requires":"Nõuded","gui.extensionLibrary.collaboration":"Koostöö","gui.library.filterPlaceholder":"Otsing","gui.library.allTag":"Kõik","gui.loader.headline":"Projekti laadimine","gui.loader.creating":"Projekti loomine","gui.authorInfo.byUser":" {username}","gui.menuBar.seeProjectPage":"Vaata projektilehte","gui.menuBar.LanguageSelector":"Vali keel","gui.menuBar.tutorialsLibrary":"Juhendid","gui.menuBar.restoreSprite":"Taasta sprait","gui.menuBar.restoreSound":"Taasta heli","gui.menuBar.restoreCostume":"Taasta kostüüm","gui.menuBar.restore":"Taasta","gui.menuBar.saveNow":"Salvesta nüüd","gui.menuBar.saveAsCopy":"Salvesta koopiana","gui.menuBar.remix":"Remiksi","gui.menuBar.new":"Uus","gui.menuBar.file":"Fail","gui.menuBar.downloadToComputer":"Salvesta oma arvutisse","gui.menuBar.edit":"Redigeeri","gui.menuBar.turboModeOff":"Turborežiim välja","gui.menuBar.turboModeOn":"Turborežiim sisse","gui.gui.projectTitlePlaceholder":"Projekti nimetus","gui.menuBar.isShared":"Jagatud","gui.menuBar.share":"Jaga","gui.modal.help":"Abi","gui.modal.back":"Tagasi","gui.monitor.listMonitor.empty":"(tühi)","gui.monitor.listMonitor.listLength":"{length} pikkus","gui.monitor.contextMenu.default":"tavaline näidik","gui.monitor.contextMenu.large":"suur näidik","gui.monitor.contextMenu.slider":"liugur","gui.monitor.contextMenu.sliderRange":"change slider range","gui.monitor.contextMenu.import":"import","gui.monitor.contextMenu.export":"export","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Play","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"Kõikide spraitide jaoks","gui.gui.variableScopeOptionSpriteOnly":"Ainult selle spraidi jaoks","gui.gui.cloudVariableOption":"Pilvemuutuja (serveris)","gui.gui.variablePromptAllSpritesMessage":"See muutuja on kättesaadav kõigile spraitidele","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Katkesta","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Stopp","gui.playbackStep.playMsg":"Käivita","gui.playbackStep.loadingMsg":"Laadib...","gui.playbackStep.saveMsg":"Salvesta","gui.playbackStep.reRecordMsg":"Salvesta uuesti","gui.recordModal.title":"Salvesta heli","gui.recordingStep.beginRecord":"Salvestamise alustamiseks vajuta allolevale nupule","gui.recordingStep.permission":"{arrow} Vajame luba mikrofoni kasutamiseks","gui.recordingStep.stop":"Lõpeta salvestamine","gui.recordingStep.record":"Salvesta","gui.sliderModal.min":"Minimum value","gui.sliderModal.max":"Maximum value","gui.sliderModal.title":"Change slider range","gui.sliderPrompt.cancel":"Cancel","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Heli","gui.soundEditor.play":"Käivita","gui.soundEditor.stop":"Stopp","gui.soundEditor.copy":"Copy","gui.soundEditor.paste":"Paste","gui.soundEditor.copyToNew":"Copy to New","gui.soundEditor.delete":"Delete","gui.soundEditor.save":"Salvesta","gui.soundEditor.undo":"Võta tagasi","gui.soundEditor.redo":"Tee uuesti","gui.soundEditor.faster":"Kiiremini","gui.soundEditor.slower":"Aeglasemalt","gui.soundEditor.echo":"Kaja","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Valjemini","gui.soundEditor.softer":"Pehmemalt","gui.soundEditor.reverse":"Tagurpidi","gui.soundEditor.fadeOut":"Fade out","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Mute","gui.SpriteInfo.spritePlaceholder":"Nimi","gui.SpriteInfo.sprite":"Sprait","gui.SpriteInfo.show":"Näita","gui.SpriteInfo.size":"Suurus","gui.spriteSelectorItem.contextMenuDuplicate":"paljunda","gui.spriteSelectorItem.contextMenuExport":"eksport","gui.spriteSelectorItem.contextMenuDelete":"eemalda","gui.spriteSelector.addSpriteFromLibrary":"Vali sprait","gui.spriteSelector.addSpriteFromPaint":"Joonista","gui.spriteSelector.addSpriteFromSurprise":"Juhuslik","gui.spriteSelector.addSpriteFromFile":"Laadi sprait","gui.stageHeader.stageSizeLarge":"Suurem lava","gui.stageHeader.stageSizeSmall":"Väiksem lava","gui.stageHeader.stageSizeFull":"Täisekraan","gui.stageHeader.stageSizeUnFull":"Sulge täisekraan","gui.stageHeader.fullscreenControl":"Täisekraan sisse/välja","gui.spriteSelector.addBackdropFromLibrary":"Vali taust","gui.stageSelector.addBackdropFromPaint":"Joonista","gui.stageSelector.addBackdropFromSurprise":"Juhuslik","gui.stageSelector.addBackdropFromFile":"Laadi taust","gui.stageSelector.stage":"Lava","gui.stageSelector.backdrops":"Taustad","gui.telemetryOptIn.label":"Report statistics to improve Scratch","gui.telemetryOptIn.body1":"The Scratch Team is always looking to better understand how Scratch is used around the world. To help support this effort, you can allow Scratch to automatically send usage information to the Scratch Team.","gui.telemetryOptIn.body2":"The information we collect includes language selection, blocks usage, and some events like saving, loading, and uploading a project. We DO NOT collect any personal information. Please see our {privacyPolicyLink} for more information.","gui.telemetryOptIn.privacyPolicyLink":"Privacy Policy","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Turborežiim","gui.webglModal.label":"Su veebilehitseja ei toeta WebGL-i","gui.webglModal.webgllink":"ei toeta WebGL-i","gui.costumeLibrary.chooseABackdrop":"Vali taust","gui.costumeLibrary.chooseACostume":"Vali kostüüm","gui.costumeTab.addBackdropFromLibrary":"Vali taust","gui.costumeTab.addCostumeFromLibrary":"Vali kostüüm","gui.costumeTab.addBlankCostume":"Joonista","gui.costumeTab.addSurpriseCostume":"Juhuslik","gui.costumeTab.addFileBackdrop":"Laadi taust","gui.costumeTab.addFileCostume":"Laadi kostüüm","gui.extensionLibrary.chooseAnExtension":"Vali laiendus","gui.extensionLibrary.extensionUrl":"Lisa laienduse URL","gui.monitors.importListColumnPrompt":"Which column should be used (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Ei saa salvestada...","gui.soundLibrary.chooseASound":"Vali heli","gui.soundTab.fileUploadSound":"Laadi heli","gui.soundTab.surpriseSound":"Juhuslik","gui.soundTab.recordSound":"Salvesta","gui.soundTab.addSoundFromLibrary":"Vali heli","gui.spriteLibrary.chooseASprite":"Vali sprait","gui.tipsLibrary.tutorials":"Vali juhend","gui.alerts.createsuccess":"Loodi uus projekt.","gui.alerts.createcopysuccess":"Projekt salvestati koopiana.","gui.alerts.createremixsuccess":"Projekt salvestati remiksina.","gui.alerts.creating":"Projekti loomine...","gui.alerts.creatingCopy":"Projekti kopeerimine...","gui.alerts.creatingRemix":"Projekti remiksimine...","gui.alerts.creatingError":"Projekti loomine ei õnnestunud. Palun proovi uuesti!","gui.alerts.savingError":"Projekti salvestamine ei õnnestu.","gui.alerts.savesuccess":"Projekt on salvestatud.","gui.alerts.saving":"Projekti salvestamine...","gui.alerts.cloudInfo":"Palun arvesta, et pilvemuutujad taluvad vaid numbred, mitte tähti või muid sümboleid. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Lisainfo.","gui.alerts.importing":"Importing…","gui.defaultProject.variable":"minu muutuja","gui.extension.music.name":"Muusika","gui.extension.music.description":"Mängi pille ja trumme.","gui.extension.pen.name":"Pliiats","gui.extension.pen.description":"Joonista spraitidega","gui.extension.videosensing.name":"Videoandurid","gui.extension.videosensing.description":"Kaamerapildi liikumise tajumine","gui.extension.text2speech.name":"Teksti muutmine kõneks","gui.extension.text2speech.description":"Pane oma projekt rääkima","gui.extension.translate.name":"Tõlgi","gui.extension.translate.description":"Tõlgi tekst eri keeltesse","gui.extension.makeymakey.description":"Muuda kõik võtmeks","gui.extension.microbit.description":"Ühenda oma projektid pärismaailmaga.","gui.extension.microbit.connectingMessage":"Ühendamine","gui.extension.ev3.description":"Ehita interaktiivseid roboteid ja muud","gui.extension.ev3.connectingMessage":"Ühendamine. Kontrolli, kas EV3 pin-kood on 1234.","gui.extension.boost.description":"Bring robotic creations to life.","gui.extension.boost.connectingMessage":"Connecting","gui.extension.wedo2.description":"Ehita mootorite ja anduritega.","gui.extension.wedo2.connectingMessage":"Ühendamine","gui.extension.gdxfor.description":"Sense push, pull, motion, and spin.","gui.extension.gdxfor.connectingMessage":"Connecting","gui.libraryTags.all":"Kõik","gui.libraryTags.animals":"Loomad","gui.libraryTags.dance":"Tantsimine","gui.libraryTags.effects":"Efektid","gui.libraryTags.fantasy":"Fantaasia","gui.libraryTags.fashion":"Mood","gui.libraryTags.food":"Toit","gui.libraryTags.indoors":"Ruumis","gui.libraryTags.loops":"Kordused","gui.libraryTags.music":"Muusika","gui.libraryTags.notes":"Noodid","gui.libraryTags.outdoors":"Õues","gui.libraryTags.patterns":"Mustrid","gui.libraryTags.people":"Inimesed","gui.libraryTags.percussion":"Löökpillid","gui.libraryTags.space":"Kosmos","gui.libraryTags.sports":"Sport","gui.libraryTags.underwater":"Vee all","gui.libraryTags.voice":"Hääled","gui.libraryTags.wacky":"Jabur","gui.libraryTags.animation":"Animatsioon","gui.libraryTags.art":"Kunst","gui.libraryTags.games":"Mängud","gui.libraryTags.stories":"Lood","gui.libraryTags.letters":"Tähed","gui.opcodeLabels.direction":"suund","gui.opcodeLabels.xposition":"x","gui.opcodeLabels.yposition":"y","gui.opcodeLabels.size":"suurus","gui.opcodeLabels.costumename":"kostüümi nimi","gui.opcodeLabels.costumenumber":"kostüümi nr","gui.opcodeLabels.backdropname":"tausta nimi","gui.opcodeLabels.backdropnumber":"tausta nr","gui.opcodeLabels.volume":"helitugevus","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"vastus","gui.opcodeLabels.loudness":"valjus","gui.opcodeLabels.username":"kasutajanimi","gui.opcodeLabels.year":"aasta","gui.opcodeLabels.month":"kuu","gui.opcodeLabels.date":"kuupäev","gui.opcodeLabels.dayofweek":"nädalapäev","gui.opcodeLabels.hour":"tunnid","gui.opcodeLabels.minute":"minutid","gui.opcodeLabels.second":"sekundid","gui.opcodeLabels.timer":"taimer","gui.sharedMessages.backdrop":"taust{index}","gui.sharedMessages.costume":"kostüüm{index}","gui.sharedMessages.sprite":"Sprait{index}","gui.sharedMessages.pop":"pops","gui.sharedMessages.replaceProjectWarning":"Replace contents of the current project?","gui.sharedMessages.loadFromComputerTitle":"Load from your computer","boost.color.any":"any color","boost.color.black":"black","boost.color.blue":"blue","boost.color.green":"green","boost.color.red":"red","boost.color.white":"white","boost.color.yellow":"yellow","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] position","boost.getTiltAngle":"tilt angle [TILT_DIRECTION]","boost.motorDirection.backward":"that way","boost.motorDirection.forward":"this way","boost.motorDirection.reverse":"reverse","boost.motorOff":"turn motor [MOTOR_ID] off","boost.motorOn":"turn motor [MOTOR_ID] on","boost.motorOnFor":"turn motor [MOTOR_ID] for [DURATION] seconds","boost.motorOnForRotation":"turn motor [MOTOR_ID] for [ROTATION] rotations","boost.seeingColor":"seeing [COLOR] brick?","boost.setLightHue":"set light color to [HUE]","boost.setMotorDirection":"set motor [MOTOR_ID] direction [MOTOR_DIRECTION]","boost.setMotorPower":"set motor [MOTOR_ID] speed to [POWER] %","boost.tiltDirection.any":"any","boost.tiltDirection.down":"down","boost.tiltDirection.left":"left","boost.tiltDirection.right":"right","boost.tiltDirection.up":"up","boost.whenColor":"when [COLOR] brick seen","boost.whenTilted":"when tilted [TILT_DIRECTION_ANY]","ev3.beepNote":"mängi nooti [NOTE] [TIME] sek","ev3.buttonPressed":"nupp [PORT] all?","ev3.getBrightness":"heledus","ev3.getDistance":"kaugus","ev3.getMotorPosition":"mootori [PORT] positsioon","ev3.motorSetPower":"võta mootori [PORT] võimsus [POWER] %","ev3.motorTurnClockwise":"pööra mootor [PORT] päripäeva [TIME] sek","ev3.motorTurnCounterClockwise":"pööra mootor [PORT] vastupäeva [TIME] sek","ev3.whenBrightnessLessThan":"kui heledus < [DISTANCE]","ev3.whenButtonPressed":"kui nupp [PORT] all","ev3.whenDistanceLessThan":"kui kaugus < [DISTANCE]","gdxfor.getAcceleration":"acceleration [DIRECTION]","gdxfor.getForce":"force","gdxfor.getSpin":"spin speed [DIRECTION]","gdxfor.getTilt":"tilt angle [TILT]","gdxfor.isFreeFalling":"falling?","gdxfor.isTilted":"tilted [TILT]?","gdxfor.pulled":"pulled","gdxfor.pushed":"pushed","gdxfor.shaken":"shaken","gdxfor.startedFalling":"started falling","gdxfor.tiltDirectionMenu.any":"any","gdxfor.tiltDirectionMenu.back":"back","gdxfor.tiltDirectionMenu.front":"front","gdxfor.tiltDirectionMenu.left":"left","gdxfor.tiltDirectionMenu.right":"right","gdxfor.turnedFaceDown":"turned face down","gdxfor.turnedFaceUp":"turned face up","gdxfor.whenForcePushedOrPulled":"when force sensor [PUSH_PULL]","gdxfor.whenGesture":"when [GESTURE]","gdxfor.whenTilted":"when tilted [TILT]","makeymakey.downArrow":"nool alla","makeymakey.downArrowShort":"alla","makeymakey.leftArrow":"nool vasakule","makeymakey.leftArrowShort":"vasakule","makeymakey.rightArrow":"nool paremale","makeymakey.rightArrowShort":"paremale","makeymakey.spaceKey":"tühik","makeymakey.upArrow":"nool üles","makeymakey.upArrowShort":"üles","makeymakey.whenKeyPressed":"when [KEY] key pressed","makeymakey.whenKeysPressedInOrder":"when [SEQUENCE] pressed in order","microbit.buttonsMenu.any":"mõni","microbit.clearDisplay":"tühjenda kuva","microbit.defaultTextToDisplay":"Tere!","microbit.displaySymbol":"kuva [MATRIX]","microbit.displayText":"kuva tekst [TEXT]","microbit.gesturesMenu.jumped":"hüppas","microbit.gesturesMenu.moved":"liikus","microbit.gesturesMenu.shaken":"rappus","microbit.isButtonPressed":"[BTN] nupp all?","microbit.isTilted":"kallutatud [DIRECTION]?","microbit.pinStateMenu.off":"väljas","microbit.pinStateMenu.on":"sees","microbit.tiltAngle":"kaldenurk [DIRECTION]","microbit.tiltDirectionMenu.any":"mõni","microbit.tiltDirectionMenu.back":"tagasi","microbit.tiltDirectionMenu.front":"edasi","microbit.tiltDirectionMenu.left":"vasakule","microbit.tiltDirectionMenu.right":"paremale","microbit.whenButtonPressed":"kui [BTN] nupp all","microbit.whenGesture":"kui [GESTURE]","microbit.whenPinConnected":"Kui [PIN] ühendas","microbit.whenTilted":"kui kallutatud [DIRECTION]","music.categoryName":"Muusika","music.changeTempo":"muuda tempot [TEMPO] võrra","music.drumBass":"(2) Basstrumm","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Pulgad","music.drumClosedHiHat":"(6) Suletud Hi-Hat","music.drumConga":"(14) Konga","music.drumCowbell":"(11) Lehmakell","music.drumCrashCymbal":"(4) Taldrikud","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Käteplaks","music.drumOpenHiHat":"(5) Lahtine Hi-Hat","music.drumSideStick":"(3) Trummi serv","music.drumSnare":"(1) Soolotrumm","music.drumTambourine":"(7) Tamburiin","music.drumTriangle":"(12) Triangel","music.drumVibraslap":"(17) Põskvibrafon","music.drumWoodBlock":"(10) Puitklots","music.getTempo":"tempo","music.instrumentBass":"(6) Bass","music.instrumentBassoon":"(14) Fagott","music.instrumentCello":"(8) Tšello","music.instrumentChoir":"(15) Koor","music.instrumentClarinet":"(10) Klarnet","music.instrumentElectricGuitar":"(5) Elektrikitarr","music.instrumentElectricPiano":"(2) Elektriklaver","music.instrumentFlute":"(12) Flööt","music.instrumentGuitar":"(4) Kitarr","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Mängutoos","music.instrumentOrgan":"(3) Orel","music.instrumentPiano":"(1) Klaver","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saksofon","music.instrumentSteelDrum":"(18) Terastrumm","music.instrumentSynthLead":"(20) Süntesaatori soolo","music.instrumentSynthPad":"(21) Süntesaatori taust","music.instrumentTrombone":"(9) Tromboon","music.instrumentVibraphone":"(16) Vibrafon","music.instrumentWoodenFlute":"(13) Puitflööt","music.midiPlayDrumForBeats":"mängi trummi [DRUM] kestusega [BEATS]","music.midiSetInstrument":"võta instrumendiks [INSTRUMENT]","music.playDrumForBeats":"mängi trummi [DRUM] kestusega [BEATS]","music.playNoteForBeats":"mängi nooti [NOTE] [BEATS] lööki","music.restForBeats":"paus [BEATS] lööki","music.setInstrument":"võta instrumendiks [INSTRUMENT]","music.setTempo":"võta tempoks [TEMPO]","pen.categoryName":"Pliiats","pen.changeColorParam":"muuda pliiatsi [COLOR_PARAM] [VALUE] võrra","pen.changeHue":"muuda pliiatsi värvi [HUE] võrra","pen.changeShade":"muuda pliiatsi varjundit [SHADE] võrra","pen.changeSize":"muuda pliiatsi suurust [SIZE] võrra","pen.clear":"kustuta kõik","pen.colorMenu.brightness":"heledus","pen.colorMenu.color":"värv","pen.colorMenu.saturation":"küllastus","pen.colorMenu.transparency":"läbipaistvus","pen.penDown":"pliiats alla","pen.penUp":"pliiats üles","pen.setColor":"võta pliiatsi värviks [COLOR]","pen.setColorParam":"võta pliiatsi [COLOR_PARAM] [VALUE]","pen.setHue":"võta pliiatsi värviks [HUE]","pen.setShade":"võta pliiatsi varjundiks [SHADE]","pen.setSize":"võta pliiatsi suuruseks [SIZE]","pen.stamp":"jäljend","text2speech.alto":"alt","text2speech.categoryName":"Text to Speech","text2speech.defaultTextToSpeak":"hello","text2speech.giant":"mörin","text2speech.kitten":"kiisu","text2speech.setLanguageBlock":"võta keeleks [LANGUAGE]","text2speech.setVoiceBlock":"võta hääleks [VOICE]","text2speech.speakAndWaitBlock":"ütle [WORDS]","text2speech.squeak":"piiksumine","text2speech.tenor":"tenor","translate.categoryName":"Tõlgi","translate.defaultTextToTranslate":"tere","translate.translateBlock":"tõlgi [WORDS] [LANGUAGE] keelde","translate.viewerLanguage":"keel","videoSensing.categoryName":"Videoandurid","videoSensing.direction":"suund","videoSensing.motion":"liikumine","videoSensing.off":"välja","videoSensing.on":"sisse","videoSensing.onFlipped":"peegeldatuna","videoSensing.setVideoTransparency":"võta video läbipaistvus [TRANSPARENCY]","videoSensing.sprite":"sprait","videoSensing.stage":"lava","videoSensing.videoOn":"[SUBJECT] video [ATTRIBUTE] ","videoSensing.videoToggle":"lülita video [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"kui video liikumine > [REFERENCE]","wedo2.getDistance":"kaugus","wedo2.getTiltAngle":"kaldenurk [TILT_DIRECTION]","wedo2.isTilted":"kallutatud [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"tagurpidi","wedo2.motorDirection.forward":"edaspidi","wedo2.motorDirection.reverse":"vastupidi","wedo2.motorId.a":"mootor A","wedo2.motorId.all":"kõik mootorid","wedo2.motorId.b":"mootor B","wedo2.motorId.default":"mootor","wedo2.motorOff":"lülita [MOTOR_ID] välja","wedo2.motorOn":"lülita [MOTOR_ID] sisse","wedo2.motorOnFor":"lülita [MOTOR_ID] sisse [DURATION] sek","wedo2.playNoteFor":"mängi nooti [NOTE] [DURATION] sek","wedo2.setLightHue":"võta LED värviks [HUE]","wedo2.setMotorDirection":"võta [MOTOR_ID] suunaks [MOTOR_DIRECTION]","wedo2.startMotorPower":"võta [MOTOR_ID] võimsuseks [POWER]","wedo2.tiltDirection.any":"mingi","wedo2.tiltDirection.down":"alla","wedo2.tiltDirection.left":"vasakule","wedo2.tiltDirection.right":"paremale","wedo2.tiltDirection.up":"üles","wedo2.whenDistance":"kui kaugus [OP] [REFERENCE]","wedo2.whenTilted":"kui kallutatud [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Värv","paint.paintEditor.saturation":"Küllastus","paint.paintEditor.brightness":"Heledus","paint.paintEditor.costume":"Kostüüm","paint.paintEditor.group":"Rühmita","paint.paintEditor.ungroup":"Tühista rühmitus","paint.paintEditor.undo":"Võta tagasi","paint.paintEditor.redo":"Tee uuesti","paint.paintEditor.forward":"Ettepoole","paint.paintEditor.backward":"Tahapoole","paint.paintEditor.front":"Esiplaanile","paint.paintEditor.back":"Tahaplaanile","paint.paintEditor.more":"Rohkem","paint.modeTools.brushSize":"Suurus","paint.modeTools.eraserSize":"Kustutaja suurus","paint.modeTools.copy":"Kopeeri","paint.modeTools.paste":"Kleebi","paint.modeTools.delete":"Kustuta","paint.modeTools.curved":"Kõver","paint.modeTools.pointed":"Teravatipuline","paint.modeTools.thickness":"Paksus","paint.modeTools.flipHorizontal":"Horisontaalne peegeldus","paint.modeTools.flipVertical":"Vertikaalne peegeldus","paint.modeTools.filled":"Täidetud","paint.modeTools.outlined":"Piirjoonega","paint.paintEditor.bitmap":"Rastergraafikasse","paint.paintEditor.vector":"Vektorgraafikasse","paint.paintEditor.fill":"Täide","paint.paintEditor.stroke":"Piirjoon","paint.brushMode.brush":"Pintsel","paint.eraserMode.eraser":"Kustutaja","paint.fillMode.fill":"Täide","paint.lineMode.line":"Joon","paint.ovalMode.oval":"Ring","paint.rectMode.rect":"Ristkülik","paint.reshapeMode.reshape":"Kuju muutmine","paint.roundedRectMode.roundedRect":"Ümarate nurkadega ristkülik","paint.selectMode.select":"Vali","paint.textMode.text":"Tekst","paint.colorPicker.swap":"Vaheta"},"el":{"gui.alerts.tryAgain":"Δοκίμασε Ξανά","gui.alerts.download":"Λήψη","gui.connection.reconnect":"Επανασύνδεση","gui.backpack.costumeLabel":"ενδυμασία","gui.backpack.soundLabel":"ήχος","gui.backpack.scriptLabel":"σενάριο","gui.backpack.spriteLabel":"αντικείμενο","gui.backpack.header":"Σακίδιο","gui.backpack.errorBackpack":"Σφάλμα κατά τη φόρτωση σακιδίου","gui.backpack.loadingBackpack":"Γίνεται φόρτωση...","gui.backpack.more":"Περισσότερα","gui.backpack.emptyBackpack":"Το σακίδιο είναι άδειο","gui.unsupportedBrowser.label":"Ο φυλλομετρητής δεν υποστηρίζεται","gui.cards.all-tutorials":"Εκπαιδευτικό υλικό","gui.cards.shrink":"Σύμπτυξη","gui.cards.expand":"Ανάπτυξη","gui.cards.close":"Κλείσιμο","gui.cards.more-things-to-try":"Περισσότερα πράγματα για να δοκιμάσετε!","gui.cards.see-more":"Δείτε περισσότερα","gui.comingSoon.message1":"Μην ανησυχείτε, το επεξεργαζόμαστε {emoji}","gui.comingSoon.message2":"Έρχεται Σύντομα...","gui.comingSoon.message3":"Το επεξεργαζόμαστε {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Δε βρέθηκαν συσκευές","gui.connection.auto-scanning.prescan":"Έχετε τη συσκευή σας κοντά, και έπειτα ξεκινήστε την αναζήτηση.","gui.connection.auto-scanning.pressbutton":"Πατήστε το κουμπί στη συσκευή σας.","gui.connection.auto-scanning.start-search":"Έναρξη Αναζήτησης","gui.connection.connecting-searchbutton":"Αναζήτηση...","gui.connection.auto-scanning.try-again":"Δοκιμάστε ξανά","gui.connection.connected":"Συνδέθηκε","gui.connection.disconnect":"Αποσύνδεση","gui.connection.go-to-editor":"Πήγαινε στον Επεξεργαστή","gui.connection.connecting-cancelbutton":"Σύνδεση...","gui.connection.error.errorMessage":"Ωπ, φαίνεται ότι κάτι πήγε στραβά.","gui.connection.error.tryagainbutton":"Δοκιμάστε ξανά","gui.connection.error.helpbutton":"Βοήθεια","gui.connection.peripheral-name-label":"Όνομα συσκευής","gui.connection.connect":"Σύνδεση","gui.connection.scanning.lookingforperipherals":"Αναζήτηση για συσκευές","gui.connection.scanning.noPeripheralsFound":"Δε βρέθηκαν συσκευές","gui.connection.scanning.instructions":"Διάλεξε τη συσκευή σου από την παραπάνω λίστα.","gui.connection.search":"Ανανέωση","gui.connection.unavailable.installscratchlink":"Βεβαιωθείτε ότι έχετε εγκαταστήσει το πρόγραμμα Scratch Link και ότι αυτό εκτελείται.","gui.connection.unavailable.enablebluetooth":"Ελέγξτε ότι το Bluetooth είναι ενεργοποιημένο","gui.connection.unavailable.tryagainbutton":"Δοκιμάστε ξανά","gui.connection.unavailable.helpbutton":"Βοήθεια","gui.controls.go":"Ξεκίνα","gui.controls.stop":"Σταμάτα","gui.crashMessage.label":"Ωπ! Κάτι πήγε στραβά.","gui.crashMessage.errorNumber":"Το σφάλμα σας καταχωρήθηκε με id {errorId}","gui.crashMessage.reload":"Επαναφόρτωση","gui.customProcedures.myblockModalTitle":"Δημιούργησε ένα τετράγωνο εντολών","gui.customProcedures.addAnInputNumberText":"Πρόσθεσε είσοδο δεδομένων","gui.customProcedures.numberTextType":"αριθμός ή κείμενο","gui.customProcedures.addAnInputBoolean":"Πρόσθεσε είσοδο δεδομένων","gui.customProcedures.booleanType":"λογική","gui.customProcedures.addALabel":"Πρόσθεσε ετικέτα","gui.customProcedures.runWithoutScreenRefresh":"Εκτέλεση χωρίς ανανέωση οθόνης","gui.customProcedures.cancel":"Ακύρωση","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Κατεύθυνση","gui.directionPicker.rotationStyles.allAround":"Πλήρης Περιστροφή","gui.directionPicker.rotationStyles.leftRight":"Αριστερά/Δεξιά","gui.directionPicker.rotationStyles.dontRotate":"Χωρίς περιστροφή","gui.gui.addExtension":"Προσθήκη Επέκτασης","gui.gui.codeTab":"Κώδικας","gui.gui.backdropsTab":"Yπόβαθρα","gui.gui.costumesTab":"Ενδυμασίες","gui.gui.soundsTab":"Ήχοι","gui.extensionLibrary.comingSoon":"Έρχεται Σύντομα","gui.extensionLibrary.requires":"Απαιτεί","gui.extensionLibrary.collaboration":"Σε συνεργασία με ","gui.library.filterPlaceholder":"Αναζήτηση","gui.library.allTag":"Όλα","gui.loader.headline":"Φόρτωση Έργου","gui.loader.creating":"Δημιουργία έργου","gui.authorInfo.byUser":"από {username}","gui.menuBar.seeProjectPage":"Δείτε τη Σελίδα του Έργου","gui.menuBar.LanguageSelector":"επιλογέας γλώσσας","gui.menuBar.tutorialsLibrary":"Εκπαιδευτικό υλικό","gui.menuBar.restoreSprite":"Επαναφορά Αντικείμενου","gui.menuBar.restoreSound":"Επαναφορά Ήχου","gui.menuBar.restoreCostume":"Επαναφορά Ενδυμασίας","gui.menuBar.restore":"Επαναφορά","gui.menuBar.saveNow":"Αποθήκευση τώρα","gui.menuBar.saveAsCopy":"Αποθήκευση ως Αντιγράφου","gui.menuBar.remix":"Ανάμειξη","gui.menuBar.new":"Νέο Έργο","gui.menuBar.file":"Αρχείο","gui.menuBar.downloadToComputer":"Αποθήκευση στον υπολογιστή σου","gui.menuBar.edit":"Επεξεργασία","gui.menuBar.turboModeOff":"Απενεργοποίηση Κατάστασης Turbo","gui.menuBar.turboModeOn":"Ενεργοποίηση Κατάστασης Turbo","gui.gui.projectTitlePlaceholder":"Τίτλος Έργου εδώ","gui.menuBar.isShared":"Σε κοινή χρήση","gui.menuBar.share":"Μοιραστείτε","gui.modal.help":"Βοήθεια","gui.modal.back":"Πίσω","gui.monitor.listMonitor.empty":"(άδεια)","gui.monitor.listMonitor.listLength":"μήκος {length}","gui.monitor.contextMenu.default":"κανονική προβολή κειμένου","gui.monitor.contextMenu.large":"μεγάλη προβολή κειμένου","gui.monitor.contextMenu.slider":"γραμμή κύλισης","gui.monitor.contextMenu.sliderRange":"αλλαγή εύρους γραμμής κύλισης","gui.monitor.contextMenu.import":"εισαγωγή","gui.monitor.contextMenu.export":"εξαγωγή","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Αναπαραγωγή","gui.playButton.stop":"Διακοπή","gui.gui.variableScopeOptionAllSprites":"Για όλα τα αντικείμενα","gui.gui.variableScopeOptionSpriteOnly":"Μόνο για αυτό το αντικείμενο","gui.gui.cloudVariableOption":"Μεταβλητή cloud (αποθηκευμένη στον server)","gui.gui.variablePromptAllSpritesMessage":"Η μεταβλητή αυτή είναι διαθέσιμη σε όλα τα αντικείμενα.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Ακύρωση","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Διακοπή","gui.playbackStep.playMsg":"Αναπαραγωγή","gui.playbackStep.loadingMsg":"Γίνεται φόρτωση...","gui.playbackStep.saveMsg":"Αποθήκευση","gui.playbackStep.reRecordMsg":"Επανάληψη εγγραφής","gui.recordModal.title":"Εγγραφή Ήχου","gui.recordingStep.beginRecord":"Ξεκίνα την ηχογράφηση πατώντας το παρακάτω κουμπί","gui.recordingStep.permission":"{arrow}Χρειαζόμαστε την άδεια σου για τη χρήση του μικρόφωνου","gui.recordingStep.stop":"Τέλος ηχογράφησης","gui.recordingStep.record":"Ηχογράφηση","gui.sliderModal.min":"Ελάχιστη τιμή","gui.sliderModal.max":"Μέγιστη τιμή","gui.sliderModal.title":"Αλλαγή εύρους γραμμής κύλισης","gui.sliderPrompt.cancel":"Ακύρωση","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Ήχος","gui.soundEditor.play":"Αναπαραγωγή","gui.soundEditor.stop":"Διακοπή","gui.soundEditor.copy":"Αντιγραφή","gui.soundEditor.paste":"Επικόλληση","gui.soundEditor.copyToNew":"Αντιγραφή σε Νέο","gui.soundEditor.delete":"Διαγραφή","gui.soundEditor.save":"Αποθήκευση","gui.soundEditor.undo":"Αναίρεση","gui.soundEditor.redo":"Επανάληψη","gui.soundEditor.faster":"Γρηγορότερα","gui.soundEditor.slower":"Πιο αργά","gui.soundEditor.echo":"Ηχώ","gui.soundEditor.robot":"Ρομπότ","gui.soundEditor.louder":"Δυνατότερα","gui.soundEditor.softer":"Απαλότερα","gui.soundEditor.reverse":"Αντιστροφή","gui.soundEditor.fadeOut":"Σβήσιμο","gui.soundEditor.fadeIn":"Σταδιακή είσοδος","gui.soundEditor.mute":"Σίγαση","gui.SpriteInfo.spritePlaceholder":"Όνομα","gui.SpriteInfo.sprite":"Αντικείμενο","gui.SpriteInfo.show":"Προβολή","gui.SpriteInfo.size":"Μέγεθος","gui.spriteSelectorItem.contextMenuDuplicate":"διπλασιασμός","gui.spriteSelectorItem.contextMenuExport":"εξαγωγή","gui.spriteSelectorItem.contextMenuDelete":"διαγραφή","gui.spriteSelector.addSpriteFromLibrary":"Επιλέξτε ένα Αντικείμενο","gui.spriteSelector.addSpriteFromPaint":"Ζωγραφική","gui.spriteSelector.addSpriteFromSurprise":"Έκπληξη","gui.spriteSelector.addSpriteFromFile":"Μεταφόρτωση Αντικείμενου","gui.stageHeader.stageSizeLarge":"Εναλλαγή σε μεγάλη σκηνή","gui.stageHeader.stageSizeSmall":"Εναλλαγή σε μικρή σκηνή","gui.stageHeader.stageSizeFull":"Προβολή πλήρους οθόνης","gui.stageHeader.stageSizeUnFull":"Έξοδος από προβολή πλήρους οθόνης","gui.stageHeader.fullscreenControl":"Έλεγχος Πλήρους Οθόνης","gui.spriteSelector.addBackdropFromLibrary":"Επιλέξτε Υπόβαθρο","gui.stageSelector.addBackdropFromPaint":"Ζωγραφική","gui.stageSelector.addBackdropFromSurprise":"Έκπληξη","gui.stageSelector.addBackdropFromFile":"Μεταφόρτωση Υποβάθρου","gui.stageSelector.stage":"Σκηνή","gui.stageSelector.backdrops":"Yπόβαθρα","gui.telemetryOptIn.label":"Αναφορά στατιστικών για βελτίωση του Scratch","gui.telemetryOptIn.body1":"Η Ομάδα του Scratch επιζητά πάντοτε να κατανοήσει καλύτερα τον τρόπο χρήσης του Scratch σε όλον τον κόσμο. Για να συνδράμετε στην υποστήριξη αυτής της προσπάθειας, μπορείτε να επιτρέψετε στο Scratch να αποστέλλει αυτόματα πληροφορίες χρήσης στην ομάδα του Scratch.","gui.telemetryOptIn.body2":"Οι πληροφορίες που συλλέγουμε περιλαμβάνουν επιλογή γλώσσας, χρήση εντολών, και κάποια γεγονότα όπως αποθήκευση, φόρτωση, και ανέβασμα ενός έργου. ΔΕ συλλέγουμε καμία προσωπική πληροφορία. Παρακαλούμε να δείτε την {privacyPolicyLink}μας για περισσότερες πληροφορίες.","gui.telemetryOptIn.privacyPolicyLink":"Πολιτική Απορρήτου","gui.telemetryOptIn.optInText":"Κοινή χρήση των δεδομένων χρήσης μου με την Ομάδα του Scratch","gui.telemetryOptIn.optInTooltip":"Ενεργοποίηση τηλεμετρίας","gui.telemetryOptIn.optOutText":"Όχι κοινή χρήση των δεδομένων χρήσης μου με την Ομάδα του Scratch","gui.telemetryOptIn.optOutTooltip":"Απενεργοποίηση τηλεμετρίας","gui.telemetryOptIn.settingWasUpdated":"Η ρύθμισή σας ενημερώθηκε.","gui.telemetryOptIn.buttonClose":"Κλείσιμο","gui.turboMode.active":"Λειτουργία Turbo","gui.webglModal.label":"Ο φυλλομετρητής σας δεν υποστηρίζει WebGL","gui.webglModal.webgllink":"δεν υποστηρίζει WebGL","gui.costumeLibrary.chooseABackdrop":"Επιλέξτε Υπόβαθρο","gui.costumeLibrary.chooseACostume":"Επιλέξτε Ενδυμασία","gui.costumeTab.addBackdropFromLibrary":"Επιλέξτε Υπόβαθρο","gui.costumeTab.addCostumeFromLibrary":"Επιλέξτε Ενδυμασία","gui.costumeTab.addBlankCostume":"Ζωγραφική","gui.costumeTab.addSurpriseCostume":"Έκπληξη","gui.costumeTab.addFileBackdrop":"Μεταφόρτωση Υποβάθρου","gui.costumeTab.addFileCostume":"Μεταφόρτωση Ενδυμασίας","gui.extensionLibrary.chooseAnExtension":"Επιλέξτε μια Επέκταση","gui.extensionLibrary.extensionUrl":"Εισάγετε το URL της επέκτασης","gui.monitors.importListColumnPrompt":"Ποια στήλη να χρησιμοποιηθεί (1-{numberOfColumns});","gui.recordingStep.alertMsg":"Η εγγραφή δεν ήταν δυνατό να ξεκινήσει","gui.soundLibrary.chooseASound":"Διάλεξε Ήχο","gui.soundTab.fileUploadSound":"Μεταφόρτωση Ήχου","gui.soundTab.surpriseSound":"Έκπληξη","gui.soundTab.recordSound":"Ηχογράφηση","gui.soundTab.addSoundFromLibrary":"Διάλεξε Ήχο","gui.spriteLibrary.chooseASprite":"Διάλεξε Αντικείμενο","gui.tipsLibrary.tutorials":"Διάλεξε Εκπαιδευτικό Υλικό","gui.alerts.createsuccess":"Δημιουργήθηκε νέο έργο.","gui.alerts.createcopysuccess":"Το έργο αποθηκεύτηκε ως αντίγραφο.","gui.alerts.createremixsuccess":"Το έργο αποθηκεύτηκε ως ανάμειξη.","gui.alerts.creating":"Γίνεται δημιουργία...","gui.alerts.creatingCopy":"Γίνεται αντιγραφή έργου...","gui.alerts.creatingRemix":"Γίνεται ανάμειξη έργου...","gui.alerts.creatingError":"Η δημιουργία του έργου απέτυχε. Παρακαλώ δοκιμάστε πάλι!","gui.alerts.savingError":"Το έργο δεν αποθηκεύτηκε.","gui.alerts.savesuccess":"Το έργο αποθηκεύτηκε.","gui.alerts.saving":"Αποθήκευση έργου...","gui.alerts.cloudInfo":"Επισημαίνεται ότι οι cloud μεταβλητές υποστηρίζουν μόνο αριθμούς, όχι γράμματα ή σύμβολα. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Μάθε περισσότερα.","gui.alerts.importing":"Γίνεται εισαγωγή...","gui.defaultProject.variable":"η μεταβλητή μου","gui.extension.music.name":"Μουσική","gui.extension.music.description":"Παίξε όργανα και τύμπανα.","gui.extension.pen.name":"Πένα","gui.extension.pen.description":"Σχεδίασε με τα αντικείμενά σου.","gui.extension.videosensing.name":"Προβολή από Κάμερα","gui.extension.videosensing.description":"Ανίχνευση κίνησης με την κάμερα.","gui.extension.text2speech.name":"Κείμενο σε Ομιλία","gui.extension.text2speech.description":"Κάνε τα έργα σου να μιλούν.","gui.extension.translate.name":"Μετάφραση","gui.extension.translate.description":"Μετάφρασε κείμενο σε πολλές γλώσσες.","gui.extension.makeymakey.description":"Μετάτρεψε οτιδήποτε σε πλήκτρο.","gui.extension.microbit.description":"Σύνδεσε τα έργα σου με τον πραγματικό κόσμο.","gui.extension.microbit.connectingMessage":"Γίνεται σύνδεση","gui.extension.ev3.description":"Φτιάξε διαδραστικά ρομπότ και άλλα.","gui.extension.ev3.connectingMessage":"Γίνεται σύνδεση. Βεβαιωθείτε ότι η ακίδα στο EV3 σας έχει οριστεί σε 1234.","gui.extension.boost.description":"Ζωντάνεψε ρομποτικές δημιουργίες.","gui.extension.boost.connectingMessage":"Γίνεται σύνδεση","gui.extension.wedo2.description":"Κατασκεύασε με κινητήρες και αισθητήρες.","gui.extension.wedo2.connectingMessage":"Γίνεται σύνδεση","gui.extension.gdxfor.description":"Ανίχνευσε σπρώξιμο, τράβηγμα, κίνηση, και περιστροφή.","gui.extension.gdxfor.connectingMessage":"Γίνεται σύνδεση","gui.libraryTags.all":"Όλα","gui.libraryTags.animals":"Ζώα","gui.libraryTags.dance":"Χορός","gui.libraryTags.effects":"Εφέ","gui.libraryTags.fantasy":"Φαντασία","gui.libraryTags.fashion":"Μόδα","gui.libraryTags.food":"Τρόφιμα","gui.libraryTags.indoors":"Εσωτερικοί χώροι","gui.libraryTags.loops":"Λούπες","gui.libraryTags.music":"Μουσική","gui.libraryTags.notes":"Νότες","gui.libraryTags.outdoors":"Εξωτερικοί Χώροι","gui.libraryTags.patterns":"Μοτίβα","gui.libraryTags.people":"Άνθρωποι","gui.libraryTags.percussion":"Κρουστά","gui.libraryTags.space":"Διάστημα","gui.libraryTags.sports":"Αθλήματα","gui.libraryTags.underwater":"Υποβρύχια","gui.libraryTags.voice":"Φωνή","gui.libraryTags.wacky":"Αστείοι ήχοι","gui.libraryTags.animation":"Κινούμενα σχέδια","gui.libraryTags.art":"Τέχνη","gui.libraryTags.games":"Παιχνίδια","gui.libraryTags.stories":"Ιστορίες","gui.libraryTags.letters":"Γράμματα","gui.opcodeLabels.direction":"κατεύθυνση","gui.opcodeLabels.xposition":"θέση x","gui.opcodeLabels.yposition":"θέση y","gui.opcodeLabels.size":"μέγεθος","gui.opcodeLabels.costumename":"όνομα ενδυμασίας","gui.opcodeLabels.costumenumber":"αριθμός ενδυμασίας","gui.opcodeLabels.backdropname":"όνομα υποβάθρου","gui.opcodeLabels.backdropnumber":"αριθμός υποβάθρου","gui.opcodeLabels.volume":"ένταση","gui.opcodeLabels.tempo":"ρυθμός","gui.opcodeLabels.answer":"απάντηση","gui.opcodeLabels.loudness":"ένταση","gui.opcodeLabels.username":"όνομα χρήστη","gui.opcodeLabels.year":"έτος","gui.opcodeLabels.month":"μήνας","gui.opcodeLabels.date":"ημερομηνία","gui.opcodeLabels.dayofweek":"μέρα της εβδομάδας","gui.opcodeLabels.hour":"ώρα","gui.opcodeLabels.minute":"λεπτό","gui.opcodeLabels.second":"δευτερόλεπτο","gui.opcodeLabels.timer":"χρονόμετρο","gui.sharedMessages.backdrop":"υπόβαθρο{index}","gui.sharedMessages.costume":"ενδυμασία{index}","gui.sharedMessages.sprite":"Αντικείμενο{index}","gui.sharedMessages.pop":"ποπ","gui.sharedMessages.replaceProjectWarning":"Αντικατάσταση περιεχομένων του παρόντος έργου;","gui.sharedMessages.loadFromComputerTitle":"Φόρτωση από τον υπολογιστή σου","boost.color.any":"όποιο χρώμα","boost.color.black":"μαύρο","boost.color.blue":"μπλε","boost.color.green":"πράσινο","boost.color.red":"κόκκινο","boost.color.white":"άσπρο","boost.color.yellow":"κίτρινο","boost.getMotorPosition":"θέση κινητήρα [MOTOR_REPORTER_ID]","boost.getTiltAngle":"γωνία κλίσης [TILT_DIRECTION]","boost.motorDirection.backward":"προς εκείνη την κατεύθυνση","boost.motorDirection.forward":"προς αυτήν την κατεύθυνση","boost.motorDirection.reverse":"αντιστροφή","boost.motorOff":"απενεργοποίησε κινητήρα [MOTOR_ID]","boost.motorOn":"ενεργοποίσε κινητήρα [MOTOR_ID]","boost.motorOnFor":"ενεργοποίησε κινητήρα [MOTOR_ID] για [DURATION] δευτ.","boost.motorOnForRotation":"ενεργοποίησε κινητήρα [MOTOR_ID] για [ROTATION] περιστροφές","boost.seeingColor":"βλέπει [COLOR] τούβλο;","boost.setLightHue":"όρισε χρώμα φωτός σε [HUE]","boost.setMotorDirection":"όρισε κατεύθυνση [MOTOR_DIRECTION] κινητήρα [MOTOR_ID]","boost.setMotorPower":"όρισε ταχύτητα κινητήρα [MOTOR_ID] σε [POWER] %","boost.tiltDirection.any":"οπουδήποτε","boost.tiltDirection.down":"κάτω","boost.tiltDirection.left":"αριστερά","boost.tiltDirection.right":"δεξιά","boost.tiltDirection.up":"πάνω","boost.whenColor":"όταν έχει δει [COLOR] τούβλο","boost.whenTilted":"όταν κλίση [TILT_DIRECTION_ANY]","ev3.beepNote":"παίξε τη νότα [NOTE] για [TIME] δευτ.","ev3.buttonPressed":"πατήθηκε το κουμπί [PORT];","ev3.getBrightness":"φωτεινότητα","ev3.getDistance":"απόσταση","ev3.getMotorPosition":"θέση κινητήρα [PORT]","ev3.motorSetPower":"κινητήρα [PORT] όρισε ισχύ [POWER] %","ev3.motorTurnClockwise":"κινητήρα [PORT] στρίψε προς αυτήν την κατεύθυνση για [TIME] δευτ.","ev3.motorTurnCounterClockwise":"κινητήρα [PORT] στρίψε προς την άλλη κατεύθυνση για [TIME] δευτ.","ev3.whenBrightnessLessThan":"όταν φωτεινότητα < [DISTANCE]","ev3.whenButtonPressed":"όταν πατηθεί το κουμπί [PORT] ","ev3.whenDistanceLessThan":"όταν απόσταση < [DISTANCE]","gdxfor.getAcceleration":"επιτάχυνση [DIRECTION]","gdxfor.getForce":"ισχύς","gdxfor.getSpin":"ταχύτητα περιστροφής [DIRECTION]","gdxfor.getTilt":"γωνία κλίσης [TILT]","gdxfor.isFreeFalling":"σε πτώση;","gdxfor.isTilted":"σε κλίση [TILT];","gdxfor.pulled":"τραβηχτεί","gdxfor.pushed":"πιεστεί","gdxfor.shaken":"τρανταχθεί","gdxfor.startedFalling":"αρχίσει πτώση","gdxfor.tiltDirectionMenu.any":"οπουδήποτε","gdxfor.tiltDirectionMenu.back":"πίσω","gdxfor.tiltDirectionMenu.front":"μπροστά","gdxfor.tiltDirectionMenu.left":"αριστερά","gdxfor.tiltDirectionMenu.right":"δεξιά","gdxfor.turnedFaceDown":"στραμμένο προς τα κάτω","gdxfor.turnedFaceUp":"στραμμένο προς τα πάνω","gdxfor.whenForcePushedOrPulled":"όταν αισθητήρας ισχύος [PUSH_PULL]","gdxfor.whenGesture":"όταν [GESTURE]","gdxfor.whenTilted":"όταν σε κλίση[TILT]","makeymakey.downArrow":"κάτω βέλος","makeymakey.downArrowShort":"κάτω","makeymakey.leftArrow":"αριστερό βέλος","makeymakey.leftArrowShort":"αριστερά","makeymakey.rightArrow":"δεξί βέλος","makeymakey.rightArrowShort":"δεξιά","makeymakey.spaceKey":"διάστημα","makeymakey.upArrow":"πάνω βέλος","makeymakey.upArrowShort":"πάνω","makeymakey.whenKeyPressed":"όταν πατηθεί το κουμπί [KEY]","makeymakey.whenKeysPressedInOrder":"όταν πατηθεί με σειρά [SEQUENCE]","microbit.buttonsMenu.any":"οποιοδήποτε","microbit.clearDisplay":"καθάρισε οθόνη","microbit.defaultTextToDisplay":"Hello!","microbit.displaySymbol":"εμφάνισε [MATRIX]","microbit.displayText":"εμφάνισε κείμενο [TEXT]","microbit.gesturesMenu.jumped":"αναπηδήσει","microbit.gesturesMenu.moved":"κινηθεί","microbit.gesturesMenu.shaken":"τρανταχθεί","microbit.isButtonPressed":"πατήθηκε το κουμπί [BTN];","microbit.isTilted":"σε κλίση [DIRECTION];","microbit.pinStateMenu.off":"ανενεργό","microbit.pinStateMenu.on":"ενεργό","microbit.tiltAngle":"γωνία κλίσης [DIRECTION]","microbit.tiltDirectionMenu.any":"οπουδήποτε","microbit.tiltDirectionMenu.back":"πίσω","microbit.tiltDirectionMenu.front":"μπροστά","microbit.tiltDirectionMenu.left":"αριστερά","microbit.tiltDirectionMenu.right":"δεξιά","microbit.whenButtonPressed":"όταν πατηθεί το κουμπί [BTN]","microbit.whenGesture":"όταν [GESTURE]","microbit.whenPinConnected":"όταν ακίδσ [PIN] συνδεθεί","microbit.whenTilted":"όταν σε κλίση [DIRECTION]","music.categoryName":"Μουσική","music.changeTempo":"άλλαξε ρυθμό κατά [TEMPO]","music.drumBass":"(2) Μπάσο Τύμπανο","music.drumBongo":"(13) Μπόνγκο","music.drumCabasa":"(15) Καμπάσα","music.drumClaves":"(9) Κλάβες","music.drumClosedHiHat":"(6) Κλειστά Πιατίνια","music.drumConga":"(14) Κόνγκα","music.drumCowbell":"(11) Κουδούνα","music.drumCrashCymbal":"(4) Κύμβαλο Crash","music.drumCuica":"(18) Κουίκα","music.drumGuiro":"(16) Γκουίρο","music.drumHandClap":"(8) Παλαμάκια","music.drumOpenHiHat":"(5) Ανοικτά Πιατίνια","music.drumSideStick":"(3) Side Stick","music.drumSnare":"(1) Ταμπούρο","music.drumTambourine":"(7) Ντέφι","music.drumTriangle":"(12) Τρίγωνο","music.drumVibraslap":"(17) Βίμπρασλαπ","music.drumWoodBlock":"(10) Ξύλινη Κασετίνα","music.getTempo":"ρυθμός","music.instrumentBass":"(6) Μπάσο","music.instrumentBassoon":"(14) Φαγκότο","music.instrumentCello":"(8) Τσέλο","music.instrumentChoir":"(15) Χορωδία","music.instrumentClarinet":"(10) Κλαρινέτο","music.instrumentElectricGuitar":"(5) Ηλεκτρική κιθάρα","music.instrumentElectricPiano":"(2) Ηλεκτρικό πιάνο","music.instrumentFlute":"(12) Φλάουτο","music.instrumentGuitar":"(4) Κιθάρα","music.instrumentMarimba":"(19) Μαρίμπα","music.instrumentMusicBox":"(17) Μουσικό Κουτί","music.instrumentOrgan":"(3) Εκκλησιαστικό Όργανο","music.instrumentPiano":"(1) Πιάνο","music.instrumentPizzicato":"(7) Πιτσικάτο","music.instrumentSaxophone":"(11) Σαξόφωνο","music.instrumentSteelDrum":"(18) Μεταλλικό Τύμπανο","music.instrumentSynthLead":"(20) Εισαγωγή Συνθεσάιζερ","music.instrumentSynthPad":"(21) Πληκτρολόγιο Συνθεσάιζερ","music.instrumentTrombone":"(9) Τρομπόνι","music.instrumentVibraphone":"(16) Βιμπράφωνο","music.instrumentWoodenFlute":"(13) Ξύλινο φλάουτο","music.midiPlayDrumForBeats":"παίξε τύμπανο [DRUM] για [BEATS] χτύπους","music.midiSetInstrument":"όρισε όργανο σε [INSTRUMENT]","music.playDrumForBeats":"παίξε τύμπανο [DRUM] για [BEATS] χτύπους","music.playNoteForBeats":"παίξε νότα [NOTE] για [BEATS] χτύπους","music.restForBeats":"κάνε παύση για [BEATS] χτύπους","music.setInstrument":"όρισε όργανο σε [INSTRUMENT]","music.setTempo":"όρισε ρυθμό σε [TEMPO]","pen.categoryName":"Πένα","pen.changeColorParam":"άλλαξε [COLOR_PARAM] πένας κατά [VALUE]","pen.changeHue":"άλλαξε χρώμα πένας κατά [HUE]","pen.changeShade":"άλλαξε σκιά πένας κατά [SHADE]","pen.changeSize":"άλλαξε μέγεθος πένας κατά [SIZE]","pen.clear":"καθάρισε όλα","pen.colorMenu.brightness":"φωτεινότητα","pen.colorMenu.color":"χρώμα","pen.colorMenu.saturation":"κορεσμό","pen.colorMenu.transparency":"διαφάνεια","pen.penDown":"κατέβασε πένα","pen.penUp":"σήκωσε πένα","pen.setColor":"όρισε χρώμα πένας σε [COLOR]","pen.setColorParam":"όρισε [COLOR_PARAM] πένας σε [VALUE]","pen.setHue":"όρισε χρώμα πένας σε [HUE]","pen.setShade":"όρισε σκιά πένας σε [SHADE]","pen.setSize":"όρισε μέγεθος πένας σε [SIZE]","pen.stamp":"σφραγίδα","text2speech.alto":"άλτο","text2speech.categoryName":"Κείμενο σε Ομιλία","text2speech.defaultTextToSpeak":"γεια","text2speech.giant":"γίγαντας","text2speech.kitten":"γατάκι","text2speech.setLanguageBlock":"όρισε γλώσσα σε [LANGUAGE]","text2speech.setVoiceBlock":"όρισε φωνή σε [VOICE]","text2speech.speakAndWaitBlock":"μίλησε [WORDS]","text2speech.squeak":"στριγκλιά ","text2speech.tenor":"τενόρος","translate.categoryName":"Μετάφρασε","translate.defaultTextToTranslate":"γεια","translate.translateBlock":"μετάφρασε [WORDS] σε [LANGUAGE]","translate.viewerLanguage":"γλώσσα","videoSensing.categoryName":"Προβολή από Κάμερα","videoSensing.direction":"κατεύθυνση","videoSensing.motion":"κίνηση","videoSensing.off":"απενεργοποιημένο","videoSensing.on":"ενεργοποιημένο","videoSensing.onFlipped":"αναστραμμένο","videoSensing.setVideoTransparency":"όρισε διαφάνεια βίντεο σε [TRANSPARENCY]","videoSensing.sprite":"αντικείμενο","videoSensing.stage":"σκηνή","videoSensing.videoOn":"βίντεο [ATTRIBUTE] για [SUBJECT]","videoSensing.videoToggle":"βίντεο [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"όταν κίνηση βίντεο > [REFERENCE]","wedo2.getDistance":"απόσταση","wedo2.getTiltAngle":"γωνία κλίσης [TILT_DIRECTION]","wedo2.isTilted":"έχει κλίση [TILT_DIRECTION_ANY];","wedo2.motorDirection.backward":"προς εκείνη την κατεύθυνση","wedo2.motorDirection.forward":"προς αυτήν την κατεύθυνση","wedo2.motorDirection.reverse":"αντιστροφή","wedo2.motorId.a":"κινητήρα A","wedo2.motorId.all":"όλους κινητήρες","wedo2.motorId.b":"κινητήρα B","wedo2.motorId.default":"κινητήρα","wedo2.motorOff":"απενεργοποίησε κινητήρα [MOTOR_ID]","wedo2.motorOn":"ενεργοποίησε κινητήρα [MOTOR_ID]","wedo2.motorOnFor":"ενεργοποίησε [MOTOR_ID] για [DURATION] δευτ.","wedo2.playNoteFor":"παίξε νότα [NOTE] για [DURATION] δευτ.","wedo2.setLightHue":"όρισε χρώμα φωτός σε [HUE]","wedo2.setMotorDirection":"όρισε κατεύθυνση [MOTOR_DIRECTION] στον [MOTOR_ID]","wedo2.startMotorPower":"όρισε ισχύ του [MOTOR_ID] σε [POWER]","wedo2.tiltDirection.any":"οπουδήποτε","wedo2.tiltDirection.down":"κάτω","wedo2.tiltDirection.left":"αριστερά","wedo2.tiltDirection.right":"δεξιά","wedo2.tiltDirection.up":"πάνω","wedo2.whenDistance":"όταν απόσταση [OP] [REFERENCE]","wedo2.whenTilted":"όταν κλίση [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Χρώμα","paint.paintEditor.saturation":"Κορεσμός","paint.paintEditor.brightness":"Φωτεινότητα","paint.paintEditor.costume":"Ενδυμασία","paint.paintEditor.group":"Ομαδοποίηση","paint.paintEditor.ungroup":"Διαχωρισμός","paint.paintEditor.undo":"Αναίρεση","paint.paintEditor.redo":"Επανάληψη","paint.paintEditor.forward":"Προς τα εμπρός","paint.paintEditor.backward":"Προς τα πίσω","paint.paintEditor.front":"Προσκήνιο","paint.paintEditor.back":"Παρασκήνιο","paint.paintEditor.more":"Περισσότερα","paint.modeTools.brushSize":"Μέγεθος","paint.modeTools.eraserSize":"Μέγεθος γόμας","paint.modeTools.copy":"Αντιγραφή","paint.modeTools.paste":"Επικόλληση","paint.modeTools.delete":"Διαγραφή","paint.modeTools.curved":"Καμπύλες","paint.modeTools.pointed":"Μυτερό","paint.modeTools.thickness":"Πάχος","paint.modeTools.flipHorizontal":"Οριζόντια Αναστροφή","paint.modeTools.flipVertical":"Κατακόρυφη Αναστροφή","paint.modeTools.filled":"Γεμάτο","paint.modeTools.outlined":"Με περίγραμμα","paint.paintEditor.bitmap":"Μετατροπή σε Ψηφιοαπεικόνιση (Bitmap)","paint.paintEditor.vector":"Μετατροπή σε Διάνυσμα (Vector)","paint.paintEditor.fill":"Γέμισμα","paint.paintEditor.stroke":"Περίγραμμα","paint.brushMode.brush":"Πινέλο","paint.eraserMode.eraser":"Γόμα","paint.fillMode.fill":"Γέμισμα","paint.lineMode.line":"Γραμμή","paint.ovalMode.oval":"Κύκλος","paint.rectMode.rect":"Ορθογώνιο","paint.reshapeMode.reshape":"Αλλαγή σχήματος","paint.roundedRectMode.roundedRect":"Στρογγυλεμένο Ορθογώνιο","paint.selectMode.select":"Επιλογή","paint.textMode.text":"Κείμενο","paint.colorPicker.swap":"Αντιμετάθεση"},"en":{"gui.alerts.tryAgain":"Try Again","gui.alerts.download":"Download","gui.connection.reconnect":"Reconnect","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Backpack","gui.backpack.errorBackpack":"Error loading backpack","gui.backpack.loadingBackpack":"Loading...","gui.backpack.more":"More","gui.backpack.emptyBackpack":"Backpack is empty","gui.unsupportedBrowser.label":"Browser is not supported","gui.cards.all-tutorials":"Tutorials","gui.cards.shrink":"Shrink","gui.cards.expand":"Expand","gui.cards.close":"Close","gui.cards.more-things-to-try":"More things to try!","gui.cards.see-more":"See more","gui.comingSoon.message1":"Don\'t worry, we\'re on it {emoji}","gui.comingSoon.message2":"Coming Soon...","gui.comingSoon.message3":"We\'re working on it {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"No devices found","gui.connection.auto-scanning.prescan":"Have your device nearby, then begin searching.","gui.connection.auto-scanning.pressbutton":"Press the button on your device.","gui.connection.auto-scanning.start-search":"Start Searching","gui.connection.connecting-searchbutton":"Searching...","gui.connection.auto-scanning.try-again":"Try again","gui.connection.connected":"Connected","gui.connection.disconnect":"Disconnect","gui.connection.go-to-editor":"Go to Editor","gui.connection.connecting-cancelbutton":"Connecting...","gui.connection.error.errorMessage":"Oops, looks like something went wrong.","gui.connection.error.tryagainbutton":"Try again","gui.connection.error.helpbutton":"Help","gui.connection.peripheral-name-label":"Device name","gui.connection.connect":"Connect","gui.connection.scanning.lookingforperipherals":"Looking for devices","gui.connection.scanning.noPeripheralsFound":"No devices found","gui.connection.scanning.instructions":"Select your device in the list above.","gui.connection.search":"Refresh","gui.connection.unavailable.installscratchlink":"Make sure you have Scratch Link installed and running","gui.connection.unavailable.enablebluetooth":"Check that Bluetooth is enabled","gui.connection.unavailable.tryagainbutton":"Try again","gui.connection.unavailable.helpbutton":"Help","gui.controls.go":"Go","gui.controls.stop":"Stop","gui.crashMessage.label":"Oops! Something went wrong.","gui.crashMessage.errorNumber":"Your error was logged with id {errorId}","gui.crashMessage.reload":"Reload","gui.customProcedures.myblockModalTitle":"Make a Block","gui.customProcedures.addAnInputNumberText":"Add an input","gui.customProcedures.numberTextType":"number or text","gui.customProcedures.addAnInputBoolean":"Add an input","gui.customProcedures.booleanType":"boolean","gui.customProcedures.addALabel":"Add a label","gui.customProcedures.runWithoutScreenRefresh":"Run without screen refresh","gui.customProcedures.cancel":"Cancel","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Direction","gui.directionPicker.rotationStyles.allAround":"All Around","gui.directionPicker.rotationStyles.leftRight":"Left/Right","gui.directionPicker.rotationStyles.dontRotate":"Do not rotate","gui.gui.addExtension":"Add Extension","gui.gui.codeTab":"Code","gui.gui.backdropsTab":"Backdrops","gui.gui.costumesTab":"Costumes","gui.gui.soundsTab":"Sounds","gui.extensionLibrary.comingSoon":"Coming Soon","gui.extensionLibrary.requires":"Requires","gui.extensionLibrary.collaboration":"Collaboration with","gui.library.filterPlaceholder":"Search","gui.library.allTag":"All","gui.loader.headline":"Loading Project","gui.loader.creating":"Creating Project","gui.authorInfo.byUser":"by {username}","gui.menuBar.seeProjectPage":"See Project Page","gui.menuBar.LanguageSelector":"language selector","gui.menuBar.tutorialsLibrary":"Tutorials","gui.menuBar.restoreSprite":"Restore Sprite","gui.menuBar.restoreSound":"Restore Sound","gui.menuBar.restoreCostume":"Restore Costume","gui.menuBar.restore":"Restore","gui.menuBar.saveNow":"Save now","gui.menuBar.saveAsCopy":"Save as a copy","gui.menuBar.remix":"Remix","gui.menuBar.new":"New","gui.menuBar.file":"File","gui.menuBar.downloadToComputer":"Save to your computer","gui.menuBar.edit":"Edit","gui.menuBar.turboModeOff":"Turn off Turbo Mode","gui.menuBar.turboModeOn":"Turn on Turbo Mode","gui.gui.projectTitlePlaceholder":"Project title here","gui.menuBar.isShared":"Shared","gui.menuBar.share":"Share","gui.modal.help":"Help","gui.modal.back":"Back","gui.monitor.listMonitor.empty":"(empty)","gui.monitor.listMonitor.listLength":"length {length}","gui.monitor.contextMenu.default":"normal readout","gui.monitor.contextMenu.large":"large readout","gui.monitor.contextMenu.slider":"slider","gui.monitor.contextMenu.sliderRange":"change slider range","gui.monitor.contextMenu.import":"import","gui.monitor.contextMenu.export":"export","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Play","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"For all sprites","gui.gui.variableScopeOptionSpriteOnly":"For this sprite only","gui.gui.cloudVariableOption":"Cloud variable (stored on server)","gui.gui.variablePromptAllSpritesMessage":"This variable will be available to all sprites.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Cancel","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Stop","gui.playbackStep.playMsg":"Play","gui.playbackStep.loadingMsg":"Loading...","gui.playbackStep.saveMsg":"Save","gui.playbackStep.reRecordMsg":"Re-record","gui.recordModal.title":"Record Sound","gui.recordingStep.beginRecord":"Begin recording by clicking the button below","gui.recordingStep.permission":"{arrow}We need your permission to use your microphone","gui.recordingStep.stop":"Stop recording","gui.recordingStep.record":"Record","gui.sliderModal.min":"Minimum value","gui.sliderModal.max":"Maximum value","gui.sliderModal.title":"Change slider range","gui.sliderPrompt.cancel":"Cancel","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Sound","gui.soundEditor.play":"Play","gui.soundEditor.stop":"Stop","gui.soundEditor.copy":"Copy","gui.soundEditor.paste":"Paste","gui.soundEditor.copyToNew":"Copy to New","gui.soundEditor.delete":"Delete","gui.soundEditor.save":"Save","gui.soundEditor.undo":"Undo","gui.soundEditor.redo":"Redo","gui.soundEditor.faster":"Faster","gui.soundEditor.slower":"Slower","gui.soundEditor.echo":"Echo","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Louder","gui.soundEditor.softer":"Softer","gui.soundEditor.reverse":"Reverse","gui.soundEditor.fadeOut":"Fade out","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Mute","gui.SpriteInfo.spritePlaceholder":"Name","gui.SpriteInfo.sprite":"Sprite","gui.SpriteInfo.show":"Show","gui.SpriteInfo.size":"Size","gui.spriteSelectorItem.contextMenuDuplicate":"duplicate","gui.spriteSelectorItem.contextMenuExport":"export","gui.spriteSelectorItem.contextMenuDelete":"delete","gui.spriteSelector.addSpriteFromLibrary":"Choose a Sprite","gui.spriteSelector.addSpriteFromPaint":"Paint","gui.spriteSelector.addSpriteFromSurprise":"Surprise","gui.spriteSelector.addSpriteFromFile":"Upload Sprite","gui.stageHeader.stageSizeLarge":"Switch to large stage","gui.stageHeader.stageSizeSmall":"Switch to small stage","gui.stageHeader.stageSizeFull":"Enter full screen mode","gui.stageHeader.stageSizeUnFull":"Exit full screen mode","gui.stageHeader.fullscreenControl":"Full Screen Control","gui.spriteSelector.addBackdropFromLibrary":"Choose a Backdrop","gui.stageSelector.addBackdropFromPaint":"Paint","gui.stageSelector.addBackdropFromSurprise":"Surprise","gui.stageSelector.addBackdropFromFile":"Upload Backdrop","gui.stageSelector.stage":"Stage","gui.stageSelector.backdrops":"Backdrops","gui.telemetryOptIn.label":"Report statistics to improve Scratch","gui.telemetryOptIn.body1":"The Scratch Team is always looking to better understand how Scratch is used around the world. To help support this effort, you can allow Scratch to automatically send usage information to the Scratch Team.","gui.telemetryOptIn.body2":"The information we collect includes language selection, blocks usage, and some events like saving, loading, and uploading a project. We DO NOT collect any personal information. Please see our {privacyPolicyLink} for more information.","gui.telemetryOptIn.privacyPolicyLink":"Privacy Policy","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Turbo Mode","gui.webglModal.label":"Your Browser Does Not Support WebGL","gui.webglModal.webgllink":"does not support WebGL","gui.costumeLibrary.chooseABackdrop":"Choose a Backdrop","gui.costumeLibrary.chooseACostume":"Choose a Costume","gui.costumeTab.addBackdropFromLibrary":"Choose a Backdrop","gui.costumeTab.addCostumeFromLibrary":"Choose a Costume","gui.costumeTab.addBlankCostume":"Paint","gui.costumeTab.addSurpriseCostume":"Surprise","gui.costumeTab.addFileBackdrop":"Upload Backdrop","gui.costumeTab.addFileCostume":"Upload Costume","gui.extensionLibrary.chooseAnExtension":"Choose an Extension","gui.extensionLibrary.extensionUrl":"Enter the URL of the extension","gui.monitors.importListColumnPrompt":"Which column should be used (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Could not start recording","gui.soundLibrary.chooseASound":"Choose a Sound","gui.soundTab.fileUploadSound":"Upload Sound","gui.soundTab.surpriseSound":"Surprise","gui.soundTab.recordSound":"Record","gui.soundTab.addSoundFromLibrary":"Choose a Sound","gui.spriteLibrary.chooseASprite":"Choose a Sprite","gui.tipsLibrary.tutorials":"Choose a Tutorial","gui.alerts.createsuccess":"New project created.","gui.alerts.createcopysuccess":"Project saved as a copy.","gui.alerts.createremixsuccess":"Project saved as a remix.","gui.alerts.creating":"Creating new…","gui.alerts.creatingCopy":"Copying project…","gui.alerts.creatingRemix":"Remixing project…","gui.alerts.creatingError":"Could not create the project. Please try again!","gui.alerts.savingError":"Project could not save.","gui.alerts.savesuccess":"Project saved.","gui.alerts.saving":"Saving project…","gui.alerts.cloudInfo":"Please note, cloud variables only support numbers, not letters or symbols. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Learn more.","gui.alerts.importing":"Importing…","gui.defaultProject.variable":"my variable","gui.extension.music.name":"Music","gui.extension.music.description":"Play instruments and drums.","gui.extension.pen.name":"Pen","gui.extension.pen.description":"Draw with your sprites.","gui.extension.videosensing.name":"Video Sensing","gui.extension.videosensing.description":"Sense motion with the camera.","gui.extension.text2speech.name":"Text to Speech","gui.extension.text2speech.description":"Make your projects talk.","gui.extension.translate.name":"Translate","gui.extension.translate.description":"Translate text into many languages.","gui.extension.makeymakey.description":"Make anything into a key.","gui.extension.microbit.description":"Connect your projects with the world.","gui.extension.microbit.connectingMessage":"Connecting","gui.extension.ev3.description":"Build interactive robots and more.","gui.extension.ev3.connectingMessage":"Connecting. Make sure the pin on your EV3 is set to 1234.","gui.extension.boost.description":"Bring robotic creations to life.","gui.extension.boost.connectingMessage":"Connecting","gui.extension.wedo2.description":"Build with motors and sensors.","gui.extension.wedo2.connectingMessage":"Connecting","gui.extension.gdxfor.description":"Sense push, pull, motion, and spin.","gui.extension.gdxfor.connectingMessage":"Connecting","gui.libraryTags.all":"All","gui.libraryTags.animals":"Animals","gui.libraryTags.dance":"Dance","gui.libraryTags.effects":"Effects","gui.libraryTags.fantasy":"Fantasy","gui.libraryTags.fashion":"Fashion","gui.libraryTags.food":"Food","gui.libraryTags.indoors":"Indoors","gui.libraryTags.loops":"Loops","gui.libraryTags.music":"Music","gui.libraryTags.notes":"Notes","gui.libraryTags.outdoors":"Outdoors","gui.libraryTags.patterns":"Patterns","gui.libraryTags.people":"People","gui.libraryTags.percussion":"Percussion","gui.libraryTags.space":"Space","gui.libraryTags.sports":"Sports","gui.libraryTags.underwater":"Underwater","gui.libraryTags.voice":"Voice","gui.libraryTags.wacky":"Wacky","gui.libraryTags.animation":"Animation","gui.libraryTags.art":"Art","gui.libraryTags.games":"Games","gui.libraryTags.stories":"Stories","gui.libraryTags.letters":"Letters","gui.opcodeLabels.direction":"direction","gui.opcodeLabels.xposition":"x position","gui.opcodeLabels.yposition":"y position","gui.opcodeLabels.size":"size","gui.opcodeLabels.costumename":"costume name","gui.opcodeLabels.costumenumber":"costume number","gui.opcodeLabels.backdropname":"backdrop name","gui.opcodeLabels.backdropnumber":"backdrop number","gui.opcodeLabels.volume":"volume","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"answer","gui.opcodeLabels.loudness":"loudness","gui.opcodeLabels.username":"username","gui.opcodeLabels.year":"year","gui.opcodeLabels.month":"month","gui.opcodeLabels.date":"date","gui.opcodeLabels.dayofweek":"day of week","gui.opcodeLabels.hour":"hour","gui.opcodeLabels.minute":"minute","gui.opcodeLabels.second":"second","gui.opcodeLabels.timer":"timer","gui.sharedMessages.backdrop":"backdrop{index}","gui.sharedMessages.costume":"costume{index}","gui.sharedMessages.sprite":"Sprite{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Replace contents of the current project?","gui.sharedMessages.loadFromComputerTitle":"Load from your computer","boost.color.any":"any color","boost.color.black":"black","boost.color.blue":"blue","boost.color.green":"green","boost.color.red":"red","boost.color.white":"white","boost.color.yellow":"yellow","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] position","boost.getTiltAngle":"tilt angle [TILT_DIRECTION]","boost.motorDirection.backward":"that way","boost.motorDirection.forward":"this way","boost.motorDirection.reverse":"reverse","boost.motorOff":"turn motor [MOTOR_ID] off","boost.motorOn":"turn motor [MOTOR_ID] on","boost.motorOnFor":"turn motor [MOTOR_ID] for [DURATION] seconds","boost.motorOnForRotation":"turn motor [MOTOR_ID] for [ROTATION] rotations","boost.seeingColor":"seeing [COLOR] brick?","boost.setLightHue":"set light color to [HUE]","boost.setMotorDirection":"set motor [MOTOR_ID] direction [MOTOR_DIRECTION]","boost.setMotorPower":"set motor [MOTOR_ID] speed to [POWER] %","boost.tiltDirection.any":"any","boost.tiltDirection.down":"down","boost.tiltDirection.left":"left","boost.tiltDirection.right":"right","boost.tiltDirection.up":"up","boost.whenColor":"when [COLOR] brick seen","boost.whenTilted":"when tilted [TILT_DIRECTION_ANY]","ev3.beepNote":"beep note [NOTE] for [TIME] secs","ev3.buttonPressed":"button [PORT] pressed?","ev3.getBrightness":"brightness","ev3.getDistance":"distance","ev3.getMotorPosition":"motor [PORT] position","ev3.motorSetPower":"motor [PORT] set power [POWER] %","ev3.motorTurnClockwise":"motor [PORT] turn this way for [TIME] seconds","ev3.motorTurnCounterClockwise":"motor [PORT] turn that way for [TIME] seconds","ev3.whenBrightnessLessThan":"when brightness < [DISTANCE]","ev3.whenButtonPressed":"when button [PORT] pressed","ev3.whenDistanceLessThan":"when distance < [DISTANCE]","gdxfor.getAcceleration":"acceleration [DIRECTION]","gdxfor.getForce":"force","gdxfor.getSpin":"spin speed [DIRECTION]","gdxfor.getTilt":"tilt angle [TILT]","gdxfor.isFreeFalling":"falling?","gdxfor.isTilted":"tilted [TILT]?","gdxfor.pulled":"pulled","gdxfor.pushed":"pushed","gdxfor.shaken":"shaken","gdxfor.startedFalling":"started falling","gdxfor.tiltDirectionMenu.any":"any","gdxfor.tiltDirectionMenu.back":"back","gdxfor.tiltDirectionMenu.front":"front","gdxfor.tiltDirectionMenu.left":"left","gdxfor.tiltDirectionMenu.right":"right","gdxfor.turnedFaceDown":"turned face down","gdxfor.turnedFaceUp":"turned face up","gdxfor.whenForcePushedOrPulled":"when force sensor [PUSH_PULL]","gdxfor.whenGesture":"when [GESTURE]","gdxfor.whenTilted":"when tilted [TILT]","makeymakey.downArrow":"down arrow","makeymakey.downArrowShort":"down","makeymakey.leftArrow":"left arrow","makeymakey.leftArrowShort":"left","makeymakey.rightArrow":"right arrow","makeymakey.rightArrowShort":"right","makeymakey.spaceKey":"space","makeymakey.upArrow":"up arrow","makeymakey.upArrowShort":"up","makeymakey.whenKeyPressed":"when [KEY] key pressed","makeymakey.whenKeysPressedInOrder":"when [SEQUENCE] pressed in order","microbit.buttonsMenu.any":"any","microbit.clearDisplay":"clear display","microbit.defaultTextToDisplay":"Hello!","microbit.displaySymbol":"display [MATRIX]","microbit.displayText":"display text [TEXT]","microbit.gesturesMenu.jumped":"jumped","microbit.gesturesMenu.moved":"moved","microbit.gesturesMenu.shaken":"shaken","microbit.isButtonPressed":"[BTN] button pressed?","microbit.isTilted":"tilted [DIRECTION]?","microbit.pinStateMenu.off":"off","microbit.pinStateMenu.on":"on","microbit.tiltAngle":"tilt angle [DIRECTION]","microbit.tiltDirectionMenu.any":"any","microbit.tiltDirectionMenu.back":"back","microbit.tiltDirectionMenu.front":"front","microbit.tiltDirectionMenu.left":"left","microbit.tiltDirectionMenu.right":"right","microbit.whenButtonPressed":"when [BTN] button pressed","microbit.whenGesture":"when [GESTURE]","microbit.whenPinConnected":"when pin [PIN] connected","microbit.whenTilted":"when tilted [DIRECTION]","music.categoryName":"Music","music.changeTempo":"change tempo by [TEMPO]","music.drumBass":"(2) Bass Drum","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) Closed Hi-Hat","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Cowbell","music.drumCrashCymbal":"(4) Crash Cymbal","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Hand Clap","music.drumOpenHiHat":"(5) Open Hi-Hat","music.drumSideStick":"(3) Side Stick","music.drumSnare":"(1) Snare Drum","music.drumTambourine":"(7) Tambourine","music.drumTriangle":"(12) Triangle","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Wood Block","music.getTempo":"tempo","music.instrumentBass":"(6) Bass","music.instrumentBassoon":"(14) Bassoon","music.instrumentCello":"(8) Cello","music.instrumentChoir":"(15) Choir","music.instrumentClarinet":"(10) Clarinet","music.instrumentElectricGuitar":"(5) Electric Guitar","music.instrumentElectricPiano":"(2) Electric Piano","music.instrumentFlute":"(12) Flute","music.instrumentGuitar":"(4) Guitar","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Music Box","music.instrumentOrgan":"(3) Organ","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxophone","music.instrumentSteelDrum":"(18) Steel Drum","music.instrumentSynthLead":"(20) Synth Lead","music.instrumentSynthPad":"(21) Synth Pad","music.instrumentTrombone":"(9) Trombone","music.instrumentVibraphone":"(16) Vibraphone","music.instrumentWoodenFlute":"(13) Wooden Flute","music.midiPlayDrumForBeats":"play drum [DRUM] for [BEATS] beats","music.midiSetInstrument":"set instrument to [INSTRUMENT]","music.playDrumForBeats":"play drum [DRUM] for [BEATS] beats","music.playNoteForBeats":"play note [NOTE] for [BEATS] beats","music.restForBeats":"rest for [BEATS] beats","music.setInstrument":"set instrument to [INSTRUMENT]","music.setTempo":"set tempo to [TEMPO]","pen.categoryName":"Pen","pen.changeColorParam":"change pen [COLOR_PARAM] by [VALUE]","pen.changeHue":"change pen color by [HUE]","pen.changeShade":"change pen shade by [SHADE]","pen.changeSize":"change pen size by [SIZE]","pen.clear":"erase all","pen.colorMenu.brightness":"brightness","pen.colorMenu.color":"color","pen.colorMenu.saturation":"saturation","pen.colorMenu.transparency":"transparency","pen.penDown":"pen down","pen.penUp":"pen up","pen.setColor":"set pen color to [COLOR]","pen.setColorParam":"set pen [COLOR_PARAM] to [VALUE]","pen.setHue":"set pen color to [HUE]","pen.setShade":"set pen shade to [SHADE]","pen.setSize":"set pen size to [SIZE]","pen.stamp":"stamp","text2speech.alto":"alto","text2speech.categoryName":"Text to Speech","text2speech.defaultTextToSpeak":"hello","text2speech.giant":"giant","text2speech.kitten":"kitten","text2speech.setLanguageBlock":"set language to [LANGUAGE]","text2speech.setVoiceBlock":"set voice to [VOICE]","text2speech.speakAndWaitBlock":"speak [WORDS]","text2speech.squeak":"squeak","text2speech.tenor":"tenor","translate.categoryName":"Translate","translate.defaultTextToTranslate":"hello","translate.translateBlock":"translate [WORDS] to [LANGUAGE]","translate.viewerLanguage":"language","videoSensing.categoryName":"Video Sensing","videoSensing.direction":"direction","videoSensing.motion":"motion","videoSensing.off":"off","videoSensing.on":"on","videoSensing.onFlipped":"on flipped","videoSensing.setVideoTransparency":"set video transparency to [TRANSPARENCY]","videoSensing.sprite":"sprite","videoSensing.stage":"stage","videoSensing.videoOn":"video [ATTRIBUTE] on [SUBJECT]","videoSensing.videoToggle":"turn video [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"when video motion > [REFERENCE]","wedo2.getDistance":"distance","wedo2.getTiltAngle":"tilt angle [TILT_DIRECTION]","wedo2.isTilted":"tilted [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"that way","wedo2.motorDirection.forward":"this way","wedo2.motorDirection.reverse":"reverse","wedo2.motorId.a":"motor A","wedo2.motorId.all":"all motors","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"turn [MOTOR_ID] off","wedo2.motorOn":"turn [MOTOR_ID] on","wedo2.motorOnFor":"turn [MOTOR_ID] on for [DURATION] seconds","wedo2.playNoteFor":"play note [NOTE] for [DURATION] seconds","wedo2.setLightHue":"set light color to [HUE]","wedo2.setMotorDirection":"set [MOTOR_ID] direction to [MOTOR_DIRECTION]","wedo2.startMotorPower":"set [MOTOR_ID] power to [POWER]","wedo2.tiltDirection.any":"any","wedo2.tiltDirection.down":"down","wedo2.tiltDirection.left":"left","wedo2.tiltDirection.right":"right","wedo2.tiltDirection.up":"up","wedo2.whenDistance":"when distance [OP] [REFERENCE]","wedo2.whenTilted":"when tilted [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Color","paint.paintEditor.saturation":"Saturation","paint.paintEditor.brightness":"Brightness","paint.paintEditor.costume":"Costume","paint.paintEditor.group":"Group","paint.paintEditor.ungroup":"Ungroup","paint.paintEditor.undo":"Undo","paint.paintEditor.redo":"Redo","paint.paintEditor.forward":"Forward","paint.paintEditor.backward":"Backward","paint.paintEditor.front":"Front","paint.paintEditor.back":"Back","paint.paintEditor.more":"More","paint.modeTools.brushSize":"Size","paint.modeTools.eraserSize":"Eraser size","paint.modeTools.copy":"Copy","paint.modeTools.paste":"Paste","paint.modeTools.delete":"Delete","paint.modeTools.curved":"Curved","paint.modeTools.pointed":"Pointed","paint.modeTools.thickness":"Thickness","paint.modeTools.flipHorizontal":"Flip Horizontal","paint.modeTools.flipVertical":"Flip Vertical","paint.modeTools.filled":"Filled","paint.modeTools.outlined":"Outlined","paint.paintEditor.bitmap":"Convert to Bitmap","paint.paintEditor.vector":"Convert to Vector","paint.paintEditor.fill":"Fill","paint.paintEditor.stroke":"Outline","paint.brushMode.brush":"Brush","paint.eraserMode.eraser":"Eraser","paint.fillMode.fill":"Fill","paint.lineMode.line":"Line","paint.ovalMode.oval":"Circle","paint.rectMode.rect":"Rectangle","paint.reshapeMode.reshape":"Reshape","paint.roundedRectMode.roundedRect":"Rounded Rectangle","paint.selectMode.select":"Select","paint.textMode.text":"Text","paint.colorPicker.swap":"Swap"},"es":{"gui.alerts.tryAgain":"Vuelve a intentarlo","gui.alerts.download":"Descargar","gui.connection.reconnect":"Reconectar","gui.backpack.costumeLabel":"disfraz","gui.backpack.soundLabel":"sonido","gui.backpack.scriptLabel":"programa","gui.backpack.spriteLabel":"objeto","gui.backpack.header":"Mochila","gui.backpack.errorBackpack":"Error al cargar la mochila","gui.backpack.loadingBackpack":"Cargando...","gui.backpack.more":"Más","gui.backpack.emptyBackpack":"La mochila está vacía","gui.unsupportedBrowser.label":"El navegador no es compatible","gui.cards.all-tutorials":"Tutoriales","gui.cards.shrink":"Encoger","gui.cards.expand":"Expandir","gui.cards.close":"Cerrar","gui.cards.more-things-to-try":"¡Más cosas para probar!","gui.cards.see-more":"Ver más","gui.comingSoon.message1":"No te preocupes, estamos en ello {emoji}","gui.comingSoon.message2":"Próximamente...","gui.comingSoon.message3":"Estamos trabajando en ello {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"No se han encontrado dispositivos","gui.connection.auto-scanning.prescan":"Ten tu dispositivo cerca, y entonces empieza a buscar.","gui.connection.auto-scanning.pressbutton":"Presiona el botón de tu dispositivo.","gui.connection.auto-scanning.start-search":"Empezar a buscar","gui.connection.connecting-searchbutton":"Buscando...","gui.connection.auto-scanning.try-again":"Intentar de nuevo","gui.connection.connected":"Conectado","gui.connection.disconnect":"Desconectar","gui.connection.go-to-editor":"Ir al editor","gui.connection.connecting-cancelbutton":"Conectando...","gui.connection.error.errorMessage":"Ups, parece que algo ha fallado.","gui.connection.error.tryagainbutton":"Intentar de nuevo","gui.connection.error.helpbutton":"Ayuda","gui.connection.peripheral-name-label":"Nombre del dispositivo","gui.connection.connect":"Conectar","gui.connection.scanning.lookingforperipherals":"Buscando dispositivos","gui.connection.scanning.noPeripheralsFound":"No se han encontrado dispositivos","gui.connection.scanning.instructions":"Elige tu dispositivo de la lista.","gui.connection.search":"Actualizar","gui.connection.unavailable.installscratchlink":"Asegúrate de que tienes Scratch Link instalado y abierto","gui.connection.unavailable.enablebluetooth":"Comprueba que Bluetooth esté habilitado","gui.connection.unavailable.tryagainbutton":"Intentar de nuevo","gui.connection.unavailable.helpbutton":"Ayuda","gui.controls.go":"Ir","gui.controls.stop":"Detener","gui.crashMessage.label":"¡Ups! Algo ha fallado.","gui.crashMessage.errorNumber":"Su error ha sido registrado con id {errorId}","gui.crashMessage.reload":"Volver a cargar","gui.customProcedures.myblockModalTitle":"Crear un bloque","gui.customProcedures.addAnInputNumberText":"Añadir una entrada","gui.customProcedures.numberTextType":"número o texto","gui.customProcedures.addAnInputBoolean":"Añadir una entrada","gui.customProcedures.booleanType":"lógica","gui.customProcedures.addALabel":"Añadir una etiqueta","gui.customProcedures.runWithoutScreenRefresh":"Ejecutar al instante","gui.customProcedures.cancel":"Cancelar","gui.customProcedures.ok":"Aceptar","gui.SpriteInfo.direction":"Dirección","gui.directionPicker.rotationStyles.allAround":"En todas direcciones","gui.directionPicker.rotationStyles.leftRight":"Izquierda/Derecha","gui.directionPicker.rotationStyles.dontRotate":"No rotar","gui.gui.addExtension":"Añadir extensión","gui.gui.codeTab":"Código","gui.gui.backdropsTab":"Fondos","gui.gui.costumesTab":"Disfraces","gui.gui.soundsTab":"Sonidos","gui.extensionLibrary.comingSoon":"Pronto","gui.extensionLibrary.requires":"Requiere","gui.extensionLibrary.collaboration":"En colaboración con","gui.library.filterPlaceholder":"Busca","gui.library.allTag":"Todos","gui.loader.headline":"Cargando proyecto","gui.loader.creating":"Creando el proyecto","gui.authorInfo.byUser":"por {username}","gui.menuBar.seeProjectPage":"Ver página del proyecto","gui.menuBar.LanguageSelector":"selector de idioma","gui.menuBar.tutorialsLibrary":"Tutoriales","gui.menuBar.restoreSprite":"Restaurar objeto","gui.menuBar.restoreSound":"Restaurar sonido","gui.menuBar.restoreCostume":"Restaurar disfraz","gui.menuBar.restore":"Restaurar","gui.menuBar.saveNow":"Guardar ahora","gui.menuBar.saveAsCopy":"Guardar una copia","gui.menuBar.remix":"Reinventar","gui.menuBar.new":"Nuevo","gui.menuBar.file":"Archivo","gui.menuBar.downloadToComputer":"Guardar en tu ordenador","gui.menuBar.edit":"Editar","gui.menuBar.turboModeOff":"Desactivar el modo Turbo","gui.menuBar.turboModeOn":"Activar el modo Turbo","gui.gui.projectTitlePlaceholder":"Nombre del proyecto aquí","gui.menuBar.isShared":"Compartidos","gui.menuBar.share":"Compartir","gui.modal.help":"Ayuda","gui.modal.back":"Atrás","gui.monitor.listMonitor.empty":"(vacía)","gui.monitor.listMonitor.listLength":"longitud {length}","gui.monitor.contextMenu.default":"tamaño normal","gui.monitor.contextMenu.large":"tamaño grande","gui.monitor.contextMenu.slider":"deslizador","gui.monitor.contextMenu.sliderRange":"cambiar rango del deslizador","gui.monitor.contextMenu.import":"importar","gui.monitor.contextMenu.export":"exportar","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Reproducir","gui.playButton.stop":"Detener","gui.gui.variableScopeOptionAllSprites":"Para todos los objetos","gui.gui.variableScopeOptionSpriteOnly":"Sólo para este objeto","gui.gui.cloudVariableOption":"Variable en la nube (guardada en el servidor)","gui.gui.variablePromptAllSpritesMessage":"Esta variable estará disponible en todos los objetos.","gui.gui.listPromptAllSpritesMessage":"Esta lista estará disponible para todos los objetos","gui.prompt.cancel":"Cancelar","gui.prompt.ok":"Aceptar","gui.playbackStep.stopMsg":"Detener","gui.playbackStep.playMsg":"Reproducir","gui.playbackStep.loadingMsg":"Cargando...","gui.playbackStep.saveMsg":"Guardar","gui.playbackStep.reRecordMsg":"Volver a grabar","gui.recordModal.title":"Grabar sonido","gui.recordingStep.beginRecord":"Comienza a grabar haciendo clic en el siguiente botón","gui.recordingStep.permission":"{arrow}Necesitamos tu permiso para usar el micrófono","gui.recordingStep.stop":"Dejar de grabar","gui.recordingStep.record":"Grabar","gui.sliderModal.min":"Valor mínimo","gui.sliderModal.max":"Valor máximo","gui.sliderModal.title":"Cambiar rango del deslizador","gui.sliderPrompt.cancel":"Cancelar","gui.sliderPrompt.ok":"Aceptar","gui.soundEditor.sound":"Sonido","gui.soundEditor.play":"Reproducir","gui.soundEditor.stop":"Detener","gui.soundEditor.copy":"Copiar","gui.soundEditor.paste":"Pegar","gui.soundEditor.copyToNew":"Copiar en nuevo","gui.soundEditor.delete":"Eliminar","gui.soundEditor.save":"Guardar","gui.soundEditor.undo":"Deshacer","gui.soundEditor.redo":"Rehacer","gui.soundEditor.faster":"Más rápido","gui.soundEditor.slower":"Más lento","gui.soundEditor.echo":"Eco","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Más fuerte","gui.soundEditor.softer":"Más suave","gui.soundEditor.reverse":"Invertir","gui.soundEditor.fadeOut":"Desaparecer","gui.soundEditor.fadeIn":"Aparecer","gui.soundEditor.mute":"Silenciar","gui.SpriteInfo.spritePlaceholder":"Nombre","gui.SpriteInfo.sprite":"Objeto","gui.SpriteInfo.show":"Mostrar","gui.SpriteInfo.size":"Tamaño","gui.spriteSelectorItem.contextMenuDuplicate":"duplicar","gui.spriteSelectorItem.contextMenuExport":"exportar","gui.spriteSelectorItem.contextMenuDelete":"borrar","gui.spriteSelector.addSpriteFromLibrary":"Elige un objeto","gui.spriteSelector.addSpriteFromPaint":"Pinta","gui.spriteSelector.addSpriteFromSurprise":"Sorpresa","gui.spriteSelector.addSpriteFromFile":"Subir objeto","gui.stageHeader.stageSizeLarge":"Cambiar a escenario grande","gui.stageHeader.stageSizeSmall":"Cambiar a escenario pequeño","gui.stageHeader.stageSizeFull":"Ir a modo pantalla completa","gui.stageHeader.stageSizeUnFull":"Salir del modo de pantalla completa","gui.stageHeader.fullscreenControl":"Control a pantalla completa","gui.spriteSelector.addBackdropFromLibrary":"Elige un fondo","gui.stageSelector.addBackdropFromPaint":"Pinta","gui.stageSelector.addBackdropFromSurprise":"Sorpresa","gui.stageSelector.addBackdropFromFile":"Carga un fondo","gui.stageSelector.stage":"Escenario","gui.stageSelector.backdrops":"Fondos","gui.telemetryOptIn.label":"Reportar las estadísticas para mejorar Scratch","gui.telemetryOptIn.body1":"El Equipo de Scratch busca comprender de la mejor forma cómo se utiliza Scratch en todo el mundo. Para apoyar estos esfuerzos, puede permitir que Scratch envíe información de uso de forma automática al Equipo de Scratch.","gui.telemetryOptIn.body2":"La información que recopilamos incluye selección de idioma, uso de bloques y algunos eventos como guardar, cargar y subir un proyecto. NO recogemos ninguna información personal. Por favor, consulta nuestra {privacyPolicyLink} para más información.","gui.telemetryOptIn.privacyPolicyLink":"Política de privacidad","gui.telemetryOptIn.optInText":"Compartir mis datos de uso con el Equipo de Scratch","gui.telemetryOptIn.optInTooltip":"Habilitar telemetría","gui.telemetryOptIn.optOutText":"No compartir mis datos de uso con el Equipo de Scratch","gui.telemetryOptIn.optOutTooltip":"Desactivar telemetría","gui.telemetryOptIn.settingWasUpdated":"Tu configuración se ha actualizado correctamente.","gui.telemetryOptIn.buttonClose":"Cerrar","gui.turboMode.active":"Modo Turbo","gui.webglModal.label":"Tu navegador no soporta WebGL","gui.webglModal.webgllink":"no soporta WebGL","gui.costumeLibrary.chooseABackdrop":"Elige un fondo","gui.costumeLibrary.chooseACostume":"Elige un disfraz","gui.costumeTab.addBackdropFromLibrary":"Elige un fondo","gui.costumeTab.addCostumeFromLibrary":"Elige un disfraz","gui.costumeTab.addBlankCostume":"Pinta","gui.costumeTab.addSurpriseCostume":"Sorpresa","gui.costumeTab.addFileBackdrop":"Carga un fondo","gui.costumeTab.addFileCostume":"Carga un disfraz","gui.extensionLibrary.chooseAnExtension":"Elige una extensión","gui.extensionLibrary.extensionUrl":"Introduce la URL de la extensión","gui.monitors.importListColumnPrompt":"¿Qué columna debe usarse (1- {numberOfColumns})?","gui.recordingStep.alertMsg":"No se ha podido empezar a grabar","gui.soundLibrary.chooseASound":"Elige un sonido","gui.soundTab.fileUploadSound":"Carga un sonido","gui.soundTab.surpriseSound":"Sorpresa","gui.soundTab.recordSound":"Grabar","gui.soundTab.addSoundFromLibrary":"Elige un sonido","gui.spriteLibrary.chooseASprite":"Elige un objeto","gui.tipsLibrary.tutorials":"Elige un tutorial","gui.alerts.createsuccess":"Nuevo proyecto creado.","gui.alerts.createcopysuccess":"Proyecto guardado como copia.","gui.alerts.createremixsuccess":"Proyecto guardado como reinvención.","gui.alerts.creating":"Creando nuevo...","gui.alerts.creatingCopy":"Copiando proyecto...","gui.alerts.creatingRemix":"Reinventando proyecto...","gui.alerts.creatingError":"No se ha podido crear el proyecto. Por favor, ¡inténtalo de nuevo!","gui.alerts.savingError":"No se ha podido guardar el proyecto.","gui.alerts.savesuccess":"Proyecto guardado.","gui.alerts.saving":"Guardando proyecto...","gui.alerts.cloudInfo":"Ten en cuenta que las variables en la nube solo admiten números, no letras ni símbolos. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Más información.","gui.alerts.importing":"Importando…","gui.defaultProject.variable":"mi variable","gui.extension.music.name":"Música","gui.extension.music.description":"Toca instrumentos y percusión.","gui.extension.pen.name":"Lápiz","gui.extension.pen.description":"Dibuja con tus objetos.","gui.extension.videosensing.name":"Sensor de vídeo","gui.extension.videosensing.description":"Detecta movimientos con la cámara.","gui.extension.text2speech.name":"Texto a voz","gui.extension.text2speech.description":"Haz que tus proyectos hablen.","gui.extension.translate.name":"Traducir","gui.extension.translate.description":"Traduce texto a muchos idiomas.","gui.extension.makeymakey.description":"Convierte cualquier cosa en una tecla.","gui.extension.microbit.description":"Conecta tus proyectos con el mundo.","gui.extension.microbit.connectingMessage":"Conectando","gui.extension.ev3.description":"Construye robots interactivos y mucho más.","gui.extension.ev3.connectingMessage":"Conectando. Asegúrate de que el PIN de tu EV3 es 1234.","gui.extension.boost.description":"Dale vida a tus creaciones robóticas.","gui.extension.boost.connectingMessage":"Conectando","gui.extension.wedo2.description":"Construye con motores y sensores.","gui.extension.wedo2.connectingMessage":"Conectando","gui.extension.gdxfor.description":"Detecta empuje, tirón, movimiento y giro.","gui.extension.gdxfor.connectingMessage":"Conectando","gui.libraryTags.all":"Todos","gui.libraryTags.animals":"Animales","gui.libraryTags.dance":"Bailar","gui.libraryTags.effects":"Efectos","gui.libraryTags.fantasy":"Fantasía","gui.libraryTags.fashion":"Moda","gui.libraryTags.food":"Comida","gui.libraryTags.indoors":"Interiores","gui.libraryTags.loops":"Bucles","gui.libraryTags.music":"Música","gui.libraryTags.notes":"Notas","gui.libraryTags.outdoors":"Exteriores","gui.libraryTags.patterns":"Patrones","gui.libraryTags.people":"Gente","gui.libraryTags.percussion":"Percusión","gui.libraryTags.space":"Espacio","gui.libraryTags.sports":"Deportes","gui.libraryTags.underwater":"Bajo el mar","gui.libraryTags.voice":"Voz","gui.libraryTags.wacky":"Locuras","gui.libraryTags.animation":"Animación","gui.libraryTags.art":"Arte","gui.libraryTags.games":"Juegos","gui.libraryTags.stories":"Historias","gui.libraryTags.letters":"Letras","gui.opcodeLabels.direction":"dirección","gui.opcodeLabels.xposition":"posición en x","gui.opcodeLabels.yposition":"posición en y","gui.opcodeLabels.size":"tamaño","gui.opcodeLabels.costumename":"nombre de disfraz","gui.opcodeLabels.costumenumber":"número de disfraz","gui.opcodeLabels.backdropname":"nombre de fondo","gui.opcodeLabels.backdropnumber":"número de fondo","gui.opcodeLabels.volume":"volumen","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"respuesta","gui.opcodeLabels.loudness":"volumen del sonido","gui.opcodeLabels.username":"nombre de usuario","gui.opcodeLabels.year":"año","gui.opcodeLabels.month":"mes","gui.opcodeLabels.date":"día","gui.opcodeLabels.dayofweek":"día de la semana","gui.opcodeLabels.hour":"hora","gui.opcodeLabels.minute":"minuto","gui.opcodeLabels.second":"segundo","gui.opcodeLabels.timer":"cronómetro","gui.sharedMessages.backdrop":"fondo{index}","gui.sharedMessages.costume":"disfraz{index}","gui.sharedMessages.sprite":"Objeto{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"¿Reemplazar el contenido del proyecto actual?","gui.sharedMessages.loadFromComputerTitle":"Cargar desde tu ordenador","boost.color.any":"de cualquier color","boost.color.black":"negra","boost.color.blue":"azul","boost.color.green":"verde","boost.color.red":"roja","boost.color.white":"blanca","boost.color.yellow":"amarilla","boost.getMotorPosition":"posición del motor [MOTOR_REPORTER_ID]","boost.getTiltAngle":"ángulo de inclinación hacia [TILT_DIRECTION]","boost.motorDirection.backward":"a un lado","boost.motorDirection.forward":"al otro lado","boost.motorDirection.reverse":"a la inversa","boost.motorOff":"apagar motor [MOTOR_ID]","boost.motorOn":"encender motor [MOTOR_ID]","boost.motorOnFor":"girar motor [MOTOR_ID] [DURATION] segundos","boost.motorOnForRotation":"girar motor [MOTOR_ID] [ROTATION] vueltas","boost.seeingColor":"¿ve pieza [COLOR]?","boost.setLightHue":"fijar color de la luz a [HUE]","boost.setMotorDirection":"fijar dirección del motor [MOTOR_ID] [MOTOR_DIRECTION]","boost.setMotorPower":"fijar velocidad del motor [MOTOR_ID] al [POWER] %","boost.tiltDirection.any":"cualquiera","boost.tiltDirection.down":"abajo","boost.tiltDirection.left":"izquierda","boost.tiltDirection.right":"derecha","boost.tiltDirection.up":"arriba","boost.whenColor":"cuando vea pieza [COLOR]","boost.whenTilted":"al inclinar hacia [TILT_DIRECTION_ANY]","ev3.beepNote":"tocar nota [NOTE] durante [TIME] segundos","ev3.buttonPressed":"¿botón [PORT] presionado?","ev3.getBrightness":"brillo","ev3.getDistance":"distancia","ev3.getMotorPosition":"posición del motor [PORT]","ev3.motorSetPower":"motor [PORT] fijar potencia a [POWER] %","ev3.motorTurnClockwise":"motor [PORT] girar a un lado [TIME] segundos","ev3.motorTurnCounterClockwise":"motor [PORT] girar al otro lado [TIME] segundos","ev3.whenBrightnessLessThan":"cuando brillo < [DISTANCE]","ev3.whenButtonPressed":"al presionar botón [PORT]","ev3.whenDistanceLessThan":"cuando distancia < [DISTANCE]","gdxfor.getAcceleration":"aceleración [DIRECTION]","gdxfor.getForce":"fuerza","gdxfor.getSpin":"velocidad de giro [DIRECTION]","gdxfor.getTilt":"ángulo de inclinación [TILT]","gdxfor.isFreeFalling":"¿cayendo?","gdxfor.isTilted":"¿inclinado [TILT]?","gdxfor.pulled":"empuje","gdxfor.pushed":"tire","gdxfor.shaken":"agitar","gdxfor.startedFalling":"comenzar a caer","gdxfor.tiltDirectionMenu.any":"en cualquier dirección","gdxfor.tiltDirectionMenu.back":"atrás","gdxfor.tiltDirectionMenu.front":"adelante","gdxfor.tiltDirectionMenu.left":"a la izquierda","gdxfor.tiltDirectionMenu.right":"a la derecha","gdxfor.turnedFaceDown":"girar hacia abajo","gdxfor.turnedFaceUp":"girar hacia arriba","gdxfor.whenForcePushedOrPulled":"cuando el sensor de fuerza [PUSH_PULL]","gdxfor.whenGesture":"al [GESTURE]","gdxfor.whenTilted":"al inclinar [TILT]","makeymakey.downArrow":"flecha abajo","makeymakey.downArrowShort":"abajo","makeymakey.leftArrow":"flecha izquierda","makeymakey.leftArrowShort":"izquierda","makeymakey.rightArrow":"flecha derecha","makeymakey.rightArrowShort":"derecha","makeymakey.spaceKey":"espacio","makeymakey.upArrow":"flecha arriba","makeymakey.upArrowShort":"arriba","makeymakey.whenKeyPressed":"al presionar tecla [KEY]","makeymakey.whenKeysPressedInOrder":"al presionar [SEQUENCE] en orden","microbit.buttonsMenu.any":"cualquiera","microbit.clearDisplay":"limpiar pantalla","microbit.defaultTextToDisplay":"¡Hola!","microbit.displaySymbol":"mostrar [MATRIX]","microbit.displayText":"mostrar texto [TEXT]","microbit.gesturesMenu.jumped":"saltar","microbit.gesturesMenu.moved":"mover","microbit.gesturesMenu.shaken":"agitar","microbit.isButtonPressed":"¿botón [BTN] presionado?","microbit.isTilted":"¿inclinado hacia [DIRECTION]?","microbit.pinStateMenu.off":"apagar","microbit.pinStateMenu.on":"encender","microbit.tiltAngle":"ángulo de inclinación hacia [DIRECTION]","microbit.tiltDirectionMenu.any":"cualquiera","microbit.tiltDirectionMenu.back":"atrás","microbit.tiltDirectionMenu.front":"delante","microbit.tiltDirectionMenu.left":"izquierda","microbit.tiltDirectionMenu.right":"derecha","microbit.whenButtonPressed":"al presionar botón [BTN]","microbit.whenGesture":"al [GESTURE]","microbit.whenPinConnected":"al conectar pin [PIN]","microbit.whenTilted":"al inclinar hacia [DIRECTION]","music.categoryName":"Música","music.changeTempo":"cambiar tempo por [TEMPO]","music.drumBass":"(2) Bombo","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) Charles cerrado","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Cencerro","music.drumCrashCymbal":"(4) Platillo crash","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Güiro","music.drumHandClap":"(8) Palmada","music.drumOpenHiHat":"(5) Charles abierto","music.drumSideStick":"(3) Golpe lateral","music.drumSnare":"(1) Caja","music.drumTambourine":"(7) Pandereta","music.drumTriangle":"(12) Triángulo","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Caja china","music.getTempo":"tempo","music.instrumentBass":"(6) Bajo","music.instrumentBassoon":"(14) Fagot","music.instrumentCello":"(8) Violonchelo","music.instrumentChoir":"(15) Coro","music.instrumentClarinet":"(10) Clarinete","music.instrumentElectricGuitar":"(5) Guitarra eléctrica","music.instrumentElectricPiano":"(2) Piano eléctrico","music.instrumentFlute":"(12) Flauta","music.instrumentGuitar":"(4) Guitarra","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Caja de música","music.instrumentOrgan":"(3) Órgano","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxofón","music.instrumentSteelDrum":"(18) Tambor metálico","music.instrumentSynthLead":"(20) Sintetizador melódico","music.instrumentSynthPad":"(21) Sintetizador de fondo","music.instrumentTrombone":"(9) Trombón","music.instrumentVibraphone":"(16) Vibráfono","music.instrumentWoodenFlute":"(13) Flauta de madera","music.midiPlayDrumForBeats":"tocar tambor [DRUM] durante [BEATS] tiempos","music.midiSetInstrument":"fijar instrumento a [INSTRUMENT]","music.playDrumForBeats":"tocar tambor [DRUM] durante [BEATS] tiempos","music.playNoteForBeats":"tocar nota [NOTE] durante [BEATS] tiempos","music.restForBeats":"silencio de [BEATS] tiempos","music.setInstrument":"fijar instrumento a [INSTRUMENT]","music.setTempo":"dar al tempo el valor [TEMPO]","pen.categoryName":"Lápiz","pen.changeColorParam":"cambiar [COLOR_PARAM] de lápiz por [VALUE]","pen.changeHue":"cambiar color de lápiz por [HUE]","pen.changeShade":"cambiar sombra de lápiz por [SHADE]","pen.changeSize":"cambiar tamaño de lápiz por [SIZE]","pen.clear":"borrar todo","pen.colorMenu.brightness":"brillo","pen.colorMenu.color":"color","pen.colorMenu.saturation":"saturación","pen.colorMenu.transparency":"transparencia","pen.penDown":"bajar lápiz","pen.penUp":"subir lápiz","pen.setColor":"fijar color de lápiz a [COLOR]","pen.setColorParam":"fijar [COLOR_PARAM] de lápiz a [VALUE]","pen.setHue":"fijar color de lápiz a [HUE]","pen.setShade":"fijar sombra de lápiz a [SHADE]","pen.setSize":"fijar tamaño de lápiz a [SIZE]","pen.stamp":"sellar","text2speech.alto":"contralto","text2speech.categoryName":"Texto a voz","text2speech.defaultTextToSpeak":"hola","text2speech.giant":"gigante","text2speech.kitten":"gatito","text2speech.setLanguageBlock":"fijar idioma a [LANGUAGE]","text2speech.setVoiceBlock":"asignar voz a [VOICE]","text2speech.speakAndWaitBlock":"decir [WORDS]","text2speech.squeak":"chillido","text2speech.tenor":"tenor","translate.categoryName":"Traducción","translate.defaultTextToTranslate":"hola","translate.translateBlock":"traducir [WORDS] al [LANGUAGE]","translate.viewerLanguage":"idioma","videoSensing.categoryName":"Sensor de video","videoSensing.direction":"dirección","videoSensing.motion":"movimiento","videoSensing.off":"apagar","videoSensing.on":"encender","videoSensing.onFlipped":"invertir","videoSensing.setVideoTransparency":"fijar transparencia de vídeo a [TRANSPARENCY]","videoSensing.sprite":"objeto","videoSensing.stage":"escenario","videoSensing.videoOn":"[ATTRIBUTE] de vídeo en [SUBJECT]","videoSensing.videoToggle":"[VIDEO_STATE] vídeo","videoSensing.whenMotionGreaterThan":"cuando movimiento de vídeo > [REFERENCE]","wedo2.getDistance":"distancia","wedo2.getTiltAngle":"ángulo de inclinación hacia [TILT_DIRECTION]","wedo2.isTilted":"¿inclinado hacia [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"un lado","wedo2.motorDirection.forward":"otro lado","wedo2.motorDirection.reverse":"inversa","wedo2.motorId.a":"motor A","wedo2.motorId.all":"todos los motores","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"apagar [MOTOR_ID]","wedo2.motorOn":"encender [MOTOR_ID]","wedo2.motorOnFor":"encender [MOTOR_ID] durante [DURATION] segundos","wedo2.playNoteFor":"tocar nota [NOTE] durante [DURATION] segundos","wedo2.setLightHue":"fijar color de la luz a [HUE]","wedo2.setMotorDirection":"fijar dirección de [MOTOR_ID] a [MOTOR_DIRECTION]","wedo2.startMotorPower":"fijar potencia de [MOTOR_ID] a [POWER]","wedo2.tiltDirection.any":"cualquier","wedo2.tiltDirection.down":"abajo","wedo2.tiltDirection.left":"izquierda","wedo2.tiltDirection.right":"derecha","wedo2.tiltDirection.up":"arriba","wedo2.whenDistance":"cuando distancia [OP] [REFERENCE]","wedo2.whenTilted":"al inclinar hacia [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Color","paint.paintEditor.saturation":"Saturación","paint.paintEditor.brightness":"Brillo","paint.paintEditor.costume":"Disfraz","paint.paintEditor.group":"Agrupar","paint.paintEditor.ungroup":"Desagrupar","paint.paintEditor.undo":"Deshacer","paint.paintEditor.redo":"Rehacer","paint.paintEditor.forward":"Adelante","paint.paintEditor.backward":"Atrás","paint.paintEditor.front":"Al frente","paint.paintEditor.back":"Al fondo","paint.paintEditor.more":"Más","paint.modeTools.brushSize":"Tamaño","paint.modeTools.eraserSize":"Tamaño de la goma","paint.modeTools.copy":"Copiar","paint.modeTools.paste":"Pegar","paint.modeTools.delete":"Eliminar","paint.modeTools.curved":"Curvado","paint.modeTools.pointed":"Recto","paint.modeTools.thickness":"Grosor","paint.modeTools.flipHorizontal":"Voltear horizontalmente","paint.modeTools.flipVertical":"Voltear verticalmente","paint.modeTools.filled":"Relleno","paint.modeTools.outlined":"Contorneado","paint.paintEditor.bitmap":"Convertir a mapa de bits","paint.paintEditor.vector":"Convertir a vector","paint.paintEditor.fill":"Rellenar","paint.paintEditor.stroke":"Borde","paint.brushMode.brush":"Pincel","paint.eraserMode.eraser":"Goma","paint.fillMode.fill":"Rellenar","paint.lineMode.line":"Línea","paint.ovalMode.oval":"Círculo","paint.rectMode.rect":"Rectángulo","paint.reshapeMode.reshape":"Volver a dar forma","paint.roundedRectMode.roundedRect":"Rectángulo con bordes redoneados","paint.selectMode.select":"Seleccionar","paint.textMode.text":"Texto","paint.colorPicker.swap":"Invertir","tw.alerts.autosaving":"Creando punto de restauración...","tw.alerts.lostPeripheralConnection":"Se perdió la conexión con {extensionName}.","tw.alerts.savedToDisk":"Guardado a tu computadora.","tw.backpack.rename":"Nuevo nombre:","tw.browserModal.desc":"Asegúrese de que esté usando una versión reciente de Google Chrome, Mozilla Firefox, Microsoft Edge o Apple Safari.","tw.cantUseCloud":"Aunque puedes crear variables en la nube, no fucionarán a menos que este proyecto se suba a Scratch o se convierta usando una herramienta como el {packager}.","tw.changeUsername.cannotChangeWhileRunning":"El nombre de usuario no puede ser cambiado mientras el proyecto se está ejecutando.","tw.cloudVariableBadge":"Este proyecto utiliza variables guardadas en la nube. TurboWarp usa su propio sistema de variables en la nube independiente a Scratch. Tenga cuidado con la suplantación de identidad, ya que se admite cambiar el nombre de usuario en uso dentro de TurboWarp a cualquiera. {learnMore}","tw.code":"Código Fuente","tw.confirmIncompatibleExtension":"Esta extensión es incompatible con Scratch. Proyectos hechos con ella no podrán ser subidos al sitio web de Scratch. ¿Está seguro de que quiere activarla?","tw.customExtension.description":"Carga extensiones personalizadas desde URLs. Para desarrolladores. Experimental","tw.customExtension.name":"Extensión Personalizada","tw.featuredProjectsStudio":"Ver estudio en Scratch","tw.feedback":"Comentarios y Bugs","tw.feedbackButton":"Enviar comentarios (feedback)","tw.footer.credits":"Créditos","tw.footer.disclaimer":"TurboWarp no está afiliado con Scratch, el equipo de Scratch o la Scratch Foundation.","tw.footer.donate":"Donar","tw.footer.embed":"Embedido","tw.footer.fosshost":"Hosting proporcionado por Fosshost","tw.footer.parameters":"Parámetros de URL","tw.footer.translate":"Ayudar a Traducir TurboWarp","tw.gui.crashMessage.description":"Lo lamentamos mucho, pero parece que la página dejó de funcionar. Por favor actualice la página para intentar de nuevo.","tw.gui.defaultProjectTitle":"Proyecto","tw.guiDefaultTitle":"Ejecute proyectos de Scratch más rápido","tw.home.credit":"Notas y Créditos","tw.home.description":"TurboWarp es un mod de Scratch que compila los proyectos a JavaScript para hacerlos ejecutar muy rápido. Pruébelo insertando un ID o URL de proyecto debajo o elija un proyecto destacado debajo.","tw.home.instructions":"Instrucciones","tw.input.tooltip":"¡Copie y pegue un enlace a un proyecto de Scratch aquí!","tw.interpolationEnabled":"Interpolación","tw.invalidParameters.clones":"Parámetro de URL «clone» es inválido","tw.invalidParameters.fps":"Parámetro de URL «fps» es inválido","tw.loadError":"No se ha podido cargar el proyecto: {error}","tw.loader.assets.known":"Descargando assets ({complete}/{total}) ...","tw.loader.assets.unknown":"Descargando assets ...","tw.loader.data":"Descargando información del proyecto...","tw.loader.generic":"Cargando proyecto ...","tw.menuBar.60off":"Desactivar modo 60 FPS","tw.menuBar.60on":"Activar modo 60 FPS","tw.menuBar.advanced":"Avanzado","tw.menuBar.changeUsername":"Cambiar Nombre de Usuario","tw.menuBar.cloudOff":"Desactivar Variables en la Nube","tw.menuBar.cloudOn":"Activar Variables en la Nube","tw.menuBar.cloudUnavailable":"Variables en la Nube no Disponibles","tw.menuBar.cloudUnavailableAlert":"No se pueden usar variables en la nube, probablemente porque abriste el editor.","tw.menuBar.loadRestorePoint":"Cargar punto de restauración","tw.menuBar.moreSettings":"Ajustes Avanzados","tw.menuBar.newFramerate":"Nuevo FPS:","tw.menuBar.package":"Convertir proyecto","tw.menuBar.reportError1":"Algunos scripts no pudieron ser compilados","tw.menuBar.reportError2":"Esto es un bug. Por favor repórtelo.","tw.menuBar.saveAs":"Guardar como {file}","tw.menuBar.seeInside":"Ver dentro","tw.oldDownload":"Guardar a archivo separado...","tw.openAdvanced":"Abrir opciones avanzadas","tw.paint.alpha":"Opacidad","tw.privacy":"Política de Privacidad","tw.restorePoint.confirm":"El editor automáticamente guarda un punto de restaurado en caso de que algo vaya mal y olvide guardar el progreso. No debería confiar en esto y no podemos garantizar que el proyecto será recuperado. ¿Intentar cargarlo?","tw.restorePoint.loadFail":"No se pudo cargar el punto de restaurado: {error}","tw.saveAs":"Guardar como...","tw.saveTo":"Guardar a {file}","tw.scratchUnsafeCloud":"Si hace esto una variable en la nube, el proyecto exederá el límite de Scratch de {number} variables y algunas variables no funcionarán si sube el proyecto a Scratch.","tw.settingsModal.customStageSize":"Tamaño Personalizado del Escenario:","tw.settingsModal.customStageSizeHelp":"Cambia el tamaño del escenario de Scratch de 480x360 a algo diferente. Pruebe 640x360 para hacer el escenario más ancho. Muy pocos proyectos manejarán esto adecuadamente.","tw.settingsModal.dangerZone":"Zona Peligrosa","tw.settingsModal.disableCompiler":"Desactivar Compilador","tw.settingsModal.disableCompilerHelp":"Desactiva el compilador de TurboWarp. Puede que quiera activar esto mientras edita proyectos para que sus scripts se actualicen inmediatamente. Si ese no es el caso, no debería activar esto nunca.","tw.settingsModal.featured":"Destacado","tw.settingsModal.fps":"60 FPS (FPS Personalizado)","tw.settingsModal.fpsHelp":"Ejecuta scripts 60 veces por segundo en vez de 30. La mayoría de los proyectos no funcionarán correctamente con esto activado. Debería probar Interpolación con modo 60 FPS desactivado si ese es el caso. {customFramerate}.","tw.settingsModal.fpsHelp.customFramerate":"Haga click para usar un framerate diferente a 30 o 60","tw.settingsModal.help":"Haga click para ayuda","tw.settingsModal.highQualityPen":"Lápiz de Alta Calidad","tw.settingsModal.highQualityPenHelp":"Permite a los proyectos que usen la extensión del Lápiz renderizar en una mayor resolución y desactiva el redondeo de coordenadas dentro del editor. No todos los proyectos se ven beneficiados de esta configuración, pues puede afectar negativamente el rendimiento. ","tw.settingsModal.infiniteClones":"Clones Infinitos","tw.settingsModal.infiniteClonesHelp":"Desactiva el límite de 300 clones de Scratch.","tw.settingsModal.interpolation":"Interpolación","tw.settingsModal.interpolationHelp":"Hace que los movimientos dentro de los proyectos se vean más suaves al interpolar los cambios de posición de los objetos. No es recomendable utilizar el ajuste de interpolación en proyectos 3D o proyectos que utilicen la extensión del Lápiz u otros proyectos que sean de bajo rendimiento, ya que esta función lo ralentizará aún más.","tw.settingsModal.largeStageWarning":"Usar un tamaño personalizado del escenario tan grande no es recomendado. En cambio, use un tamaño más pequeño con la misma relación de aspecto y permita que el modo pantalla completa agrande el escenario para cubrir toda la pantalla del usuario.","tw.settingsModal.removeFencing":"Quitar Fencing","tw.settingsModal.removeFencingHelp":"Permite a los objetos moverse afuera de la pantalla o hacerse tan grandes o chicos como deseen y hace funcionar los bloques \\"tocando\\" fuera de la pantalla.","tw.settingsModal.removeLimits":"Quitar Límites","tw.settingsModal.removeMiscLimits":"Quitar Límites Varios","tw.settingsModal.removeMiscLimitsHelp":"Elimina los límites de sonido y de tamaño del lápiz.","tw.settingsModal.storeProjectOptions":"Guardar ajustes en proyecto","tw.settingsModal.storeProjectOptionsHelp":"Guarda los ajustes seleccionados en el proyecto para que sean aplicados automáticamente cuando TurboWarp carga este proyecto. Warp Timer y desactivar compilador no serán guardados.","tw.settingsModal.title":"Ajustes Avanzados","tw.settingsModal.warpTimerHelp":"Hace que los scripts revisen si están atascados en un bucle infinito y si es así, hace que vayan a una menor tasa de refresco hasta que el bucle termine, logrando evitar la mayoría de colapsos por este tipo de errores. Este ajuste tiene un impacto negativo significante en el rendimiento, por lo que solo está habilitado por defecto en el editor.","tw.spriteSelectorItem.rename":"renombrar","tw.stereo":"Estéreo","tw.stereoAlert":"Editar este sonido estéreo lo convertirá irreversiblemente en mono.","tw.studioview.authorAttribution":"por {author}","tw.studioview.error":"Ocurrió un error cargando la siguiente página de proyectos.","tw.studioview.hoverText":"{title} por {author}","tw.tooLarge":"Este sonido podría ser demasiado grande como para cargarlo en Scratch.","tw.twExtension.description":"Bloques nuevos raros. No compatibles con Scratch.","tw.twExtension.name":"Bloques TurboWarp","tw.unshared.1":"Proyectos no compartidos no serán accesibles usando solamente su ID en algún punto debido a cambios en el API de Scratch por venir.","tw.unshared.2":"Para más información, visite: {link}","tw.unshared.cache":"Si el proyecto se a compartido recientemente, este mensaje podría aparecer incorrectamente por algunos minutos.","tw.usernameModal.help":"Este valor será guardado en el almacenamiento de su navegador. Es posible que sea usado cuando interactúe con proyectos que contengan variables en la nube.","tw.usernameModal.help2":"Valores que no corresponden a una cuenta de Scratch válida típicamente serán rechazadas por el servidor de variables en la nube. Se le recomienda dejarlo como está o cambiarlo a su nombre de usuario de Scratch.","tw.usernameModal.mustChange":"Lo sentimos, el servidor de variables en la nube piensa que tu nombre de usuario puede ser inseguro. Por favor cámbielo a otra cosa o {resetIt}.","tw.usernameModal.mustChange.resetIt":"resetéelo (recomendado)","tw.usernameModal.reset":"Reiniciar","tw.usernameModal.title":"Cambiar Nombre de Usuario","tw.viewFeaturedProjects":"Clickee para ver proyectos destacados.","tw.viewOnScratch":"Ver proyecto en Scratch","tw.webglModal.description":"Desafortunadamente parece que tu navegador o computadora {webGlLink}. Esta tecnología se necesita para que funcione este sitio. Intente actualizar su navegador y drivers gráficos o reinicie su computadora."},"es-419":{"gui.alerts.tryAgain":"Vuelve a intentar","gui.alerts.download":"Descargar","gui.connection.reconnect":"Reconectar","gui.backpack.costumeLabel":"disfraz","gui.backpack.soundLabel":"sonido","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"objeto","gui.backpack.header":"Mochila","gui.backpack.errorBackpack":"Error al cargar la mochila","gui.backpack.loadingBackpack":"Cargando...","gui.backpack.more":"Más","gui.backpack.emptyBackpack":"La mochila está vacía","gui.unsupportedBrowser.label":"El navegador no es compatible","gui.cards.all-tutorials":"Tutoriales","gui.cards.shrink":"Encoger","gui.cards.expand":"Expandir","gui.cards.close":"Cerrar","gui.cards.more-things-to-try":"¡Más cosas para probar!","gui.cards.see-more":"Ver más","gui.comingSoon.message1":"No te preocupes, estamos en eso {emoji}","gui.comingSoon.message2":"Próximamente...","gui.comingSoon.message3":"Estamos trabajando en ello {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"No se encontró ningún dispositivo","gui.connection.auto-scanning.prescan":"Ten tu dispositivo cerca, luego inicia la búsqueda.","gui.connection.auto-scanning.pressbutton":"Presiona el botón en tu dispositivo.","gui.connection.auto-scanning.start-search":"Inicia la búsqueda","gui.connection.connecting-searchbutton":"Buscando...","gui.connection.auto-scanning.try-again":"Volver a intentar","gui.connection.connected":"Conectado","gui.connection.disconnect":"Desconectar","gui.connection.go-to-editor":"Ir al Editor","gui.connection.connecting-cancelbutton":"Conectando...","gui.connection.error.errorMessage":"¡Uy! Parece que algo salió mal.","gui.connection.error.tryagainbutton":"Volver a intentar","gui.connection.error.helpbutton":"Ayuda","gui.connection.peripheral-name-label":"Nombre del dispositivo","gui.connection.connect":"Conectar","gui.connection.scanning.lookingforperipherals":"Buscando dispositivos","gui.connection.scanning.noPeripheralsFound":"No se encontró ningún dispositivo","gui.connection.scanning.instructions":"Selecciona tu dispositivo en la lista de arriba.","gui.connection.search":"Actualizar","gui.connection.unavailable.installscratchlink":"Asegúrate de tener Scratch Link instalado y corriendo","gui.connection.unavailable.enablebluetooth":"Revisa que el Bluetooth esté habilitado","gui.connection.unavailable.tryagainbutton":"Volver a intentar","gui.connection.unavailable.helpbutton":"Ayuda","gui.controls.go":"Ir","gui.controls.stop":"Detener","gui.crashMessage.label":"¡Uy! Algo salió mal.","gui.crashMessage.errorNumber":"Su error ha sido registrado con id {errorId}","gui.crashMessage.reload":"Recargar","gui.customProcedures.myblockModalTitle":"Crear un bloque","gui.customProcedures.addAnInputNumberText":"Agregar una entrada","gui.customProcedures.numberTextType":"número o texto","gui.customProcedures.addAnInputBoolean":"Agregar una entrada","gui.customProcedures.booleanType":"booleano","gui.customProcedures.addALabel":"Agregar una etiqueta","gui.customProcedures.runWithoutScreenRefresh":"Ejecutar sin actualizar la pantalla","gui.customProcedures.cancel":"Cancelar","gui.customProcedures.ok":"De acuerdo","gui.SpriteInfo.direction":"Dirección","gui.directionPicker.rotationStyles.allAround":"En todas direcciones","gui.directionPicker.rotationStyles.leftRight":"Izquierda/Derecha","gui.directionPicker.rotationStyles.dontRotate":"No rotar","gui.gui.addExtension":"Agregar Extensión","gui.gui.codeTab":"Código","gui.gui.backdropsTab":"Fondos","gui.gui.costumesTab":"Disfraces","gui.gui.soundsTab":"Sonidos","gui.extensionLibrary.comingSoon":"Próximamente","gui.extensionLibrary.requires":"Requiere","gui.extensionLibrary.collaboration":"Colaboración con","gui.library.filterPlaceholder":"Buscar","gui.library.allTag":"Todos","gui.loader.headline":"Cargando proyecto","gui.loader.creating":"Creando un proyecto","gui.authorInfo.byUser":"por {username}","gui.menuBar.seeProjectPage":"Ver página del proyecto","gui.menuBar.LanguageSelector":"Escoger el lenguaje","gui.menuBar.tutorialsLibrary":"Tutoriales","gui.menuBar.restoreSprite":"Restaurar Objeto","gui.menuBar.restoreSound":"Restaurar Sonido","gui.menuBar.restoreCostume":"Restaurar Disfraz","gui.menuBar.restore":"Restaurar","gui.menuBar.saveNow":"Guardar ahora","gui.menuBar.saveAsCopy":"Guardar como copia","gui.menuBar.remix":"Reinventar","gui.menuBar.new":"Nuevo","gui.menuBar.file":"Archivo","gui.menuBar.downloadToComputer":"Guardar en tu computador","gui.menuBar.edit":"Editar","gui.menuBar.turboModeOff":"Desactivar Modo turbo","gui.menuBar.turboModeOn":"Activar Modo turbo","gui.gui.projectTitlePlaceholder":"Título del proyecto aquí","gui.menuBar.isShared":"Compartidos","gui.menuBar.share":"Compartir","gui.modal.help":"Ayuda","gui.modal.back":"Regresar","gui.monitor.listMonitor.empty":"(vacío)","gui.monitor.listMonitor.listLength":"largo {length}","gui.monitor.contextMenu.default":"tamaño normal","gui.monitor.contextMenu.large":"tamaño grande","gui.monitor.contextMenu.slider":"deslizador","gui.monitor.contextMenu.sliderRange":"cambiar rango del deslizador","gui.monitor.contextMenu.import":"importar","gui.monitor.contextMenu.export":"exportar","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Reproducir","gui.playButton.stop":"Detener","gui.gui.variableScopeOptionAllSprites":"Para todos los objetos","gui.gui.variableScopeOptionSpriteOnly":"Sólo para este objeto","gui.gui.cloudVariableOption":"Variable de la nube (guardada en el servidor)","gui.gui.variablePromptAllSpritesMessage":"Esta variable estará disponible para todos los objetos.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Cancelar","gui.prompt.ok":"De acuerdo","gui.playbackStep.stopMsg":"Detener","gui.playbackStep.playMsg":"Reproducir","gui.playbackStep.loadingMsg":"Cargando...","gui.playbackStep.saveMsg":"Guardar","gui.playbackStep.reRecordMsg":"Volver a grabar","gui.recordModal.title":"Grabar Sonido","gui.recordingStep.beginRecord":"Empieza a grabar haciendo clic en el botón de abajo","gui.recordingStep.permission":"{arrow}Necesitamos permiso para utilizar tu micrófono","gui.recordingStep.stop":"Parar de grabar","gui.recordingStep.record":"Grabar","gui.sliderModal.min":"Valor mínimo","gui.sliderModal.max":"Valor máximo","gui.sliderModal.title":"Cambiar rango del deslizador","gui.sliderPrompt.cancel":"Cancelar","gui.sliderPrompt.ok":"De acuerdo","gui.soundEditor.sound":"Sonido","gui.soundEditor.play":"Jugar","gui.soundEditor.stop":"Detener","gui.soundEditor.copy":"Copiar","gui.soundEditor.paste":"Pegar","gui.soundEditor.copyToNew":"Copiar a uno nuevo","gui.soundEditor.delete":"Eliminar","gui.soundEditor.save":"Guardar","gui.soundEditor.undo":"Deshacer","gui.soundEditor.redo":"Rehacer","gui.soundEditor.faster":"Más rápido","gui.soundEditor.slower":"Más lento","gui.soundEditor.echo":"Eco","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Más fuerte","gui.soundEditor.softer":"Más suave","gui.soundEditor.reverse":"Reversa","gui.soundEditor.fadeOut":"Desvanecer","gui.soundEditor.fadeIn":"Aparecer","gui.soundEditor.mute":"Silenciar","gui.SpriteInfo.spritePlaceholder":"Nombre","gui.SpriteInfo.sprite":"Objeto","gui.SpriteInfo.show":"mostrar","gui.SpriteInfo.size":"Tamaño","gui.spriteSelectorItem.contextMenuDuplicate":"duplicar","gui.spriteSelectorItem.contextMenuExport":"exportar","gui.spriteSelectorItem.contextMenuDelete":"eliminar","gui.spriteSelector.addSpriteFromLibrary":"Elegir un objeto","gui.spriteSelector.addSpriteFromPaint":"Pintar","gui.spriteSelector.addSpriteFromSurprise":"Sorpresa","gui.spriteSelector.addSpriteFromFile":"Subir un objeto","gui.stageHeader.stageSizeLarge":"Cambiar a un escenario grande","gui.stageHeader.stageSizeSmall":"Cambiar a un escenario pequeño","gui.stageHeader.stageSizeFull":"Ingresar al modo de pantalla completa","gui.stageHeader.stageSizeUnFull":"Salir del modo de pantalla completa","gui.stageHeader.fullscreenControl":"Control de Pantalla Completa","gui.spriteSelector.addBackdropFromLibrary":"Elige un fondo","gui.stageSelector.addBackdropFromPaint":"Pintar","gui.stageSelector.addBackdropFromSurprise":"Sorpresa","gui.stageSelector.addBackdropFromFile":"Subir Fondo","gui.stageSelector.stage":"Escenario","gui.stageSelector.backdrops":"Fondos","gui.telemetryOptIn.label":"Reportar las estadísticas para mejorar Scratch","gui.telemetryOptIn.body1":"El equipo de Scratch siempre busca entender mejor cómo se usa Scratch en el mundo. Para aportar a esta iniciativa, puede permitir que Scratch envíe automáticamente la información de uso al equipo de Scratch.","gui.telemetryOptIn.body2":"La información que recopilamos incluye selección de idioma, uso de bloques y algunos eventos como guardar, cargar y subir un proyecto. NO recogemos ninguna información personal. Por favor vea nuestra {privacyPolicyLink} para más información.","gui.telemetryOptIn.privacyPolicyLink":"política de privacidad","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Habilitar telemetría","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Desactivar la telemetria","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Cerrar","gui.turboMode.active":"Modo Turbo","gui.webglModal.label":"Su navegador no es compatible con WebGL","gui.webglModal.webgllink":"no es compatible con WebGL","gui.costumeLibrary.chooseABackdrop":"Escoger un fondo","gui.costumeLibrary.chooseACostume":"Escoger un disfraz","gui.costumeTab.addBackdropFromLibrary":"Escoger un fondo","gui.costumeTab.addCostumeFromLibrary":"Escoger un disfraz","gui.costumeTab.addBlankCostume":"Pintar","gui.costumeTab.addSurpriseCostume":"Sorpresa","gui.costumeTab.addFileBackdrop":"Subir fondo","gui.costumeTab.addFileCostume":"Subir disfraz","gui.extensionLibrary.chooseAnExtension":"Eligir una extensión","gui.extensionLibrary.extensionUrl":"Ingrese la URL de la extensión","gui.monitors.importListColumnPrompt":"¿Qué columna debe usarse (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"No se pudo comenzar a grabar","gui.soundLibrary.chooseASound":"Elige un sonido","gui.soundTab.fileUploadSound":"Subir sonido","gui.soundTab.surpriseSound":"Sorpresa","gui.soundTab.recordSound":"Grabar","gui.soundTab.addSoundFromLibrary":"Elige un sonido","gui.spriteLibrary.chooseASprite":"Elige un objeto","gui.tipsLibrary.tutorials":"Elige un tutorial","gui.alerts.createsuccess":"Nuevo proyecto creado.","gui.alerts.createcopysuccess":"Proyecto guardado como copia.","gui.alerts.createremixsuccess":"Proyecto guardado como reinvención.","gui.alerts.creating":"Creando nuevo...","gui.alerts.creatingCopy":"Copiando proyecto...","gui.alerts.creatingRemix":"Reinventando proyecto...","gui.alerts.creatingError":"No pudimos crear el proyecto. ¡Por favor, inténtalo de nuevo!","gui.alerts.savingError":"El proyecto no se pudo guardar.","gui.alerts.savesuccess":"Proyecto guardado.","gui.alerts.saving":"Guardando proyecto...","gui.alerts.cloudInfo":"Tenga en cuenta que las variables de la nube solo admiten números, no letras ni símbolos. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Aprende más.","gui.alerts.importing":"Importando...","gui.defaultProject.variable":"mi variable","gui.extension.music.name":"Música","gui.extension.music.description":"Toca instrumentos y tambores.","gui.extension.pen.name":"Lápiz","gui.extension.pen.description":"Dibuja con tus objetos.","gui.extension.videosensing.name":"Sensor de video","gui.extension.videosensing.description":"Detecta movimiento con tu cámara","gui.extension.text2speech.name":"Texto a Voz","gui.extension.text2speech.description":"Haz que tu proyecto hable.","gui.extension.translate.name":"Traductor","gui.extension.translate.description":"Traduce texto a muchos lenguajes.","gui.extension.makeymakey.description":"Haz que cualquier cosa sea una tecla.","gui.extension.microbit.description":"Conecta tus proyectos con el mundo.","gui.extension.microbit.connectingMessage":"Conectando","gui.extension.ev3.description":"Construye robots interactivos y más.","gui.extension.ev3.connectingMessage":"Conectando. Asegúrate que el pin en tu EV3 sea 1234.","gui.extension.boost.description":"Dale vida a tus creaciones robóticas.","gui.extension.boost.connectingMessage":"Conectando","gui.extension.wedo2.description":"Construye con motores y sensores.","gui.extension.wedo2.connectingMessage":"Conectando","gui.extension.gdxfor.description":"Sensores de empuje, movimiento y giro.","gui.extension.gdxfor.connectingMessage":"Conectando","gui.libraryTags.all":"Todos","gui.libraryTags.animals":"Animales","gui.libraryTags.dance":"Bailes","gui.libraryTags.effects":"Efectos","gui.libraryTags.fantasy":"Fantasía","gui.libraryTags.fashion":"Moda","gui.libraryTags.food":"Alimento","gui.libraryTags.indoors":"Interiores","gui.libraryTags.loops":"Ciclos","gui.libraryTags.music":"Música","gui.libraryTags.notes":"Notas","gui.libraryTags.outdoors":"Exteriores","gui.libraryTags.patterns":"Patrones","gui.libraryTags.people":"Gente","gui.libraryTags.percussion":"Percusión","gui.libraryTags.space":"Espacio","gui.libraryTags.sports":"Deportes","gui.libraryTags.underwater":"Bajo el mar","gui.libraryTags.voice":"Voz","gui.libraryTags.wacky":"Loco","gui.libraryTags.animation":"Animación","gui.libraryTags.art":"Arte","gui.libraryTags.games":"Juegos","gui.libraryTags.stories":"Historias","gui.libraryTags.letters":"Letras","gui.opcodeLabels.direction":"dirección","gui.opcodeLabels.xposition":"posición x","gui.opcodeLabels.yposition":"posición y","gui.opcodeLabels.size":"tamaño","gui.opcodeLabels.costumename":"nombre del disfraz","gui.opcodeLabels.costumenumber":"número de disfraz","gui.opcodeLabels.backdropname":"nombre de fondo","gui.opcodeLabels.backdropnumber":"número de fondo","gui.opcodeLabels.volume":"volumen","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"respuesta","gui.opcodeLabels.loudness":"volumen del sonido","gui.opcodeLabels.username":"nombre de usuario","gui.opcodeLabels.year":"año","gui.opcodeLabels.month":"mes","gui.opcodeLabels.date":"fecha","gui.opcodeLabels.dayofweek":"día de la semana","gui.opcodeLabels.hour":"hora","gui.opcodeLabels.minute":"minuto","gui.opcodeLabels.second":"segundo","gui.opcodeLabels.timer":"cronómetro","gui.sharedMessages.backdrop":"fondo{index}","gui.sharedMessages.costume":"disfraz{index}","gui.sharedMessages.sprite":"Objeto{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"¿Reemplazar el contenido del proyecto actual?","gui.sharedMessages.loadFromComputerTitle":"Subir desde tu computador","boost.color.any":"de cualquier color","boost.color.black":"negra","boost.color.blue":"azul","boost.color.green":"verde","boost.color.red":"roja","boost.color.white":"blanca","boost.color.yellow":"amarilla","boost.getMotorPosition":"posición de motor [MOTOR_REPORTER_ID]","boost.getTiltAngle":"ángulo de inclinación hacia [TILT_DIRECTION]","boost.motorDirection.backward":"allá","boost.motorDirection.forward":"acá","boost.motorDirection.reverse":"reversa","boost.motorOff":"apagar motor [MOTOR_ID]","boost.motorOn":"encender motor [MOTOR_ID]","boost.motorOnFor":"girar motor [MOTOR_ID] durante [DURATION] segundos","boost.motorOnForRotation":"girar motor [MOTOR_ID] por [ROTATION] vueltas","boost.seeingColor":"¿viendo pieza [COLOR]?","boost.setLightHue":"fijar color de luz a [HUE]","boost.setMotorDirection":"fijar dirección de motor [MOTOR_ID] hacia [MOTOR_DIRECTION]","boost.setMotorPower":"fijar velocidad del motor [MOTOR_ID] a [POWER] %","boost.tiltDirection.any":"cualquier dirección","boost.tiltDirection.down":"abajo","boost.tiltDirection.left":"izquierda","boost.tiltDirection.right":"derecha","boost.tiltDirection.up":"arriba","boost.whenColor":"cuando vea pieza [COLOR]","boost.whenTilted":"al inclinar hacia [TILT_DIRECTION_ANY]","ev3.beepNote":"tocar nota [NOTE] durante [TIME] segundos","ev3.buttonPressed":"¿botón [PORT] presionado?","ev3.getBrightness":"brillo","ev3.getDistance":"distancia","ev3.getMotorPosition":"posición del motor [PORT] ","ev3.motorSetPower":"fijar potencia de motor [PORT] a [POWER]%","ev3.motorTurnClockwise":"girar motor [PORT] hacia acá durante [TIME] segundos","ev3.motorTurnCounterClockwise":"girar motor [PORT] hacia allá durante [TIME] segundos","ev3.whenBrightnessLessThan":"cuando brillo < [DISTANCE]","ev3.whenButtonPressed":"al presionar botón [PORT]","ev3.whenDistanceLessThan":"cuando distancia < [DISTANCE]","gdxfor.getAcceleration":"aceleración [DIRECTION]","gdxfor.getForce":"fuerza","gdxfor.getSpin":" velocidad de giro [DIRECTION]","gdxfor.getTilt":"ángulo de inclinación hacia [TILT]","gdxfor.isFreeFalling":"¿cayendo?","gdxfor.isTilted":"¿inclinado hacia [TILT]?","gdxfor.pulled":"tirado","gdxfor.pushed":"empujado","gdxfor.shaken":"agitar","gdxfor.startedFalling":"comenzar a caer","gdxfor.tiltDirectionMenu.any":"cualquier dirección","gdxfor.tiltDirectionMenu.back":"atrás","gdxfor.tiltDirectionMenu.front":"adelante","gdxfor.tiltDirectionMenu.left":"la izquierda","gdxfor.tiltDirectionMenu.right":"la derecha","gdxfor.turnedFaceDown":"estar hacia abajo","gdxfor.turnedFaceUp":"estar hacia arriba","gdxfor.whenForcePushedOrPulled":"cuando el sensor de fuerza es [PUSH_PULL]","gdxfor.whenGesture":"al [GESTURE]","gdxfor.whenTilted":"al inclinarse hacia [TILT]","makeymakey.downArrow":"flecha abajo","makeymakey.downArrowShort":"abajo","makeymakey.leftArrow":"flecha izquierda","makeymakey.leftArrowShort":"izquierda","makeymakey.rightArrow":"flecha derecha","makeymakey.rightArrowShort":"derecha","makeymakey.spaceKey":"espacio","makeymakey.upArrow":"flecha arriba","makeymakey.upArrowShort":"arriba","makeymakey.whenKeyPressed":"al presionar la tecla [KEY]","makeymakey.whenKeysPressedInOrder":"al presionar en orden [SEQUENCE] ","microbit.buttonsMenu.any":"cualquiera","microbit.clearDisplay":"limpiar pantalla","microbit.defaultTextToDisplay":"¡Hola!","microbit.displaySymbol":"mostrar [MATRIX]","microbit.displayText":"mostrar texto [TEXT]","microbit.gesturesMenu.jumped":"saltar","microbit.gesturesMenu.moved":"mover","microbit.gesturesMenu.shaken":"agitar","microbit.isButtonPressed":"¿botón [BTN] presionado?","microbit.isTilted":"¿inclinado hacia [DIRECTION]?","microbit.pinStateMenu.off":"apagado","microbit.pinStateMenu.on":"encendido","microbit.tiltAngle":"ángulo de inclinación hacia [DIRECTION]","microbit.tiltDirectionMenu.any":"cualquier dirección","microbit.tiltDirectionMenu.back":"atrás","microbit.tiltDirectionMenu.front":"delante","microbit.tiltDirectionMenu.left":"izquierda","microbit.tiltDirectionMenu.right":"derecha","microbit.whenButtonPressed":"al presionar botón [BTN]","microbit.whenGesture":"al [GESTURE]","microbit.whenPinConnected":"al conectar pin [PIN]","microbit.whenTilted":"al inclinar [DIRECTION]","music.categoryName":"Música","music.changeTempo":"cambiar el tempo en [TEMPO]","music.drumBass":"(2) Bombo","music.drumBongo":"(13) Bongó","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) Charles Cerrado","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Cencerro","music.drumCrashCymbal":"(4) Platillo Crash","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Güiro","music.drumHandClap":"(8) Aplauso","music.drumOpenHiHat":"(5) Charles abierto","music.drumSideStick":"(3) Golpe lateral","music.drumSnare":"(1) Caja","music.drumTambourine":"(7) Pandereta","music.drumTriangle":"(12) Triángulo","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Caja china","music.getTempo":"tempo","music.instrumentBass":"(6) Bajo","music.instrumentBassoon":"(14) Fagot","music.instrumentCello":"(8) Violonchelo","music.instrumentChoir":"(15) Coro","music.instrumentClarinet":"(10) Clarinete","music.instrumentElectricGuitar":"(5) Guitarra Eléctrica","music.instrumentElectricPiano":"(2) Piano Eléctrico","music.instrumentFlute":"(12) Flauta","music.instrumentGuitar":"(4) Guitarra","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Caja de música","music.instrumentOrgan":"(3) Órgano","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxofón","music.instrumentSteelDrum":"(18) Tambor metálico","music.instrumentSynthLead":"(20) Sintetizador melódico","music.instrumentSynthPad":"(21) Sintetizador de fondo","music.instrumentTrombone":"(9) Trombón","music.instrumentVibraphone":"(16) Vibráfono","music.instrumentWoodenFlute":"(13) Flauta de Madera","music.midiPlayDrumForBeats":"tocar tambor [DRUM] durante [BEATS] tiempos","music.midiSetInstrument":"fijar instrumento a [INSTRUMENT]","music.playDrumForBeats":"tocar tambor [DRUM] durante [BEATS] tiempos","music.playNoteForBeats":"tocar nota [NOTE] durante [BEATS] tiempos","music.restForBeats":"silenciar durante [BEATS] tiempos","music.setInstrument":"fijar instrumento a [INSTRUMENT]","music.setTempo":"fijar tempo a [TEMPO]","pen.categoryName":"Lápiz","pen.changeColorParam":"cambiar [COLOR_PARAM] de lápiz en [VALUE]","pen.changeHue":"cambiar color de lápiz en [HUE]","pen.changeShade":"cambiar sombra de lápiz en [SHADE]","pen.changeSize":"cambiar tamaño de lápiz en [SIZE]","pen.clear":"borrar todo","pen.colorMenu.brightness":"brillo","pen.colorMenu.color":"color","pen.colorMenu.saturation":"saturación","pen.colorMenu.transparency":"transparencia","pen.penDown":"bajar lápiz","pen.penUp":"subir lápiz","pen.setColor":"fijar color de lápiz a [COLOR]","pen.setColorParam":"fijar [COLOR_PARAM] de lápiz a [VALUE]","pen.setHue":"fijar color de lápiz a [HUE]","pen.setShade":"fijar sombra de lápiz a [SHADE]","pen.setSize":"fijar tamaño de lápiz a [SIZE]","pen.stamp":"sellar","text2speech.alto":"alto","text2speech.categoryName":"Texto a Voz","text2speech.defaultTextToSpeak":"hola","text2speech.giant":"gigante","text2speech.kitten":"gatito","text2speech.setLanguageBlock":"fijar idioma a [LANGUAGE]","text2speech.setVoiceBlock":"fijar voz a [VOICE]","text2speech.speakAndWaitBlock":"decir [WORDS]","text2speech.squeak":"chillido","text2speech.tenor":"tenor","translate.categoryName":"Traducir","translate.defaultTextToTranslate":"hola","translate.translateBlock":"traducir [WORDS] al [LANGUAGE]","translate.viewerLanguage":"idioma","videoSensing.categoryName":"Sensor de video","videoSensing.direction":"dirección","videoSensing.motion":"movimiento","videoSensing.off":"apagar","videoSensing.on":"encender","videoSensing.onFlipped":"invertir","videoSensing.setVideoTransparency":"fijar transparencia de video a [TRANSPARENCY]","videoSensing.sprite":"objeto","videoSensing.stage":"escenario","videoSensing.videoOn":"[ATTRIBUTE] del video en [SUBJECT]","videoSensing.videoToggle":"[VIDEO_STATE] video","videoSensing.whenMotionGreaterThan":"cuando el movimiento del video > [REFERENCE]","wedo2.getDistance":"distancia","wedo2.getTiltAngle":"ángulo de inclinación hacia [TILT_DIRECTION]","wedo2.isTilted":"¿inclinado hacia [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"allá","wedo2.motorDirection.forward":"acá","wedo2.motorDirection.reverse":"reversa","wedo2.motorId.a":"motor A","wedo2.motorId.all":"todos los motores","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"apagar [MOTOR_ID]","wedo2.motorOn":"encender [MOTOR_ID]","wedo2.motorOnFor":"encender [MOTOR_ID] durante [DURATION] segundos","wedo2.playNoteFor":"tocar nota [NOTE] durante [DURATION] segundos","wedo2.setLightHue":"fijar color de la luz a [HUE]","wedo2.setMotorDirection":"fijar dirección de [MOTOR_ID] hacia [MOTOR_DIRECTION]","wedo2.startMotorPower":"fijar potencia de [MOTOR_ID] a [POWER]","wedo2.tiltDirection.any":"cualquier dirección","wedo2.tiltDirection.down":"abajo","wedo2.tiltDirection.left":"izquierda","wedo2.tiltDirection.right":"derecha","wedo2.tiltDirection.up":"arriba","wedo2.whenDistance":"cuando distancia [OP] [REFERENCE]","wedo2.whenTilted":"al inclinar hacia [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Color","paint.paintEditor.saturation":"Saturación","paint.paintEditor.brightness":"Brillo","paint.paintEditor.costume":"Disfraz","paint.paintEditor.group":"Agrupar","paint.paintEditor.ungroup":"Desagrupar","paint.paintEditor.undo":"Deshacer","paint.paintEditor.redo":"Rehacer","paint.paintEditor.forward":"Adelante","paint.paintEditor.backward":"Atrás","paint.paintEditor.front":"Al frente","paint.paintEditor.back":"Al fondo","paint.paintEditor.more":"Más","paint.modeTools.brushSize":"Tamaño","paint.modeTools.eraserSize":"Tamaño del borrador","paint.modeTools.copy":"Copiar","paint.modeTools.paste":"Pegar","paint.modeTools.delete":"Eliminar","paint.modeTools.curved":"Curvo","paint.modeTools.pointed":"Puntiagudo","paint.modeTools.thickness":"Grosor","paint.modeTools.flipHorizontal":"Voltear horizontal","paint.modeTools.flipVertical":"Voltear vertical","paint.modeTools.filled":"Relleno","paint.modeTools.outlined":"Con contorno","paint.paintEditor.bitmap":"Convertir a mapa de bits","paint.paintEditor.vector":"Convertir a vector","paint.paintEditor.fill":"Relleno","paint.paintEditor.stroke":"Contorno","paint.brushMode.brush":"Pincel","paint.eraserMode.eraser":"Borrador","paint.fillMode.fill":"Relleno","paint.lineMode.line":"Línea","paint.ovalMode.oval":"Círculo","paint.rectMode.rect":"Rectángulo","paint.reshapeMode.reshape":"Cambiar forma","paint.roundedRectMode.roundedRect":"Rectángulo redondeado","paint.selectMode.select":"Seleccionar","paint.textMode.text":"Texto","paint.colorPicker.swap":"Intercambiar","tw.alerts.autosaving":"Creando punto de restauración...","tw.alerts.lostPeripheralConnection":"Se perdió la conexión con {extensionName}.","tw.alerts.savedToDisk":"Guardado a tu computadora.","tw.backpack.rename":"Nuevo nombre:","tw.browserModal.desc":"Asegúrese de que esté usando una versión reciente de Google Chrome, Mozilla Firefox, Microsoft Edge o Apple Safari.","tw.cantUseCloud":"Aunque puedes crear variables en la nube, no fucionarán a menos que este proyecto se suba a Scratch o se convierta usando una herramienta como el {packager}.","tw.changeUsername.cannotChangeWhileRunning":"El nombre de usuario no puede ser cambiado mientras el proyecto se está ejecutando.","tw.cloudVariableBadge":"Este proyecto utiliza variables guardadas en la nube. TurboWarp usa su propio sistema de variables en la nube independiente a Scratch. Tenga cuidado con la suplantación de identidad, ya que se admite cambiar el nombre de usuario en uso dentro de TurboWarp a cualquiera. {learnMore}","tw.code":"Código Fuente","tw.confirmIncompatibleExtension":"Esta extensión es incompatible con Scratch. Proyectos hechos con ella no podrán ser subidos al sitio web de Scratch. ¿Está seguro de que quiere activarla?","tw.customExtension.description":"Carga extensiones personalizadas desde URLs. Para desarrolladores. Experimental","tw.customExtension.name":"Extensión Personalizada","tw.featuredProjectsStudio":"Ver estudio en Scratch","tw.feedback":"Comentarios y Bugs","tw.feedbackButton":"Enviar comentarios (feedback)","tw.footer.credits":"Créditos","tw.footer.disclaimer":"TurboWarp no está afiliado con Scratch, el equipo de Scratch o la Scratch Foundation.","tw.footer.donate":"Donar","tw.footer.embed":"Embedido","tw.footer.fosshost":"Hosting proporcionado por Fosshost","tw.footer.parameters":"Parámetros de URL","tw.footer.translate":"Ayudar a Traducir TurboWarp","tw.gui.crashMessage.description":"Lo lamentamos mucho, pero parece que la página dejó de funcionar. Por favor actualice la página para intentar de nuevo.","tw.gui.defaultProjectTitle":"Proyecto","tw.guiDefaultTitle":"Ejecute proyectos de Scratch más rápido","tw.home.credit":"Notas y Créditos","tw.home.description":"TurboWarp es un mod de Scratch que compila los proyectos a JavaScript para hacerlos ejecutar muy rápido. Pruébelo insertando un ID o URL de proyecto debajo o elija un proyecto destacado debajo.","tw.home.instructions":"Instrucciones","tw.input.tooltip":"¡Copie y pegue un enlace a un proyecto de Scratch aquí!","tw.interpolationEnabled":"Interpolación","tw.invalidParameters.clones":"Parámetro de URL «clone» es inválido","tw.invalidParameters.fps":"Parámetro de URL «fps» es inválido","tw.loadError":"No se ha podido cargar el proyecto: {error}","tw.loader.assets.known":"Descargando assets ({complete}/{total}) ...","tw.loader.assets.unknown":"Descargando assets ...","tw.loader.data":"Descargando información del proyecto...","tw.loader.generic":"Cargando proyecto ...","tw.menuBar.60off":"Desactivar modo 60 FPS","tw.menuBar.60on":"Activar modo 60 FPS","tw.menuBar.advanced":"Avanzado","tw.menuBar.changeUsername":"Cambiar Nombre de Usuario","tw.menuBar.cloudOff":"Desactivar Variables en la Nube","tw.menuBar.cloudOn":"Activar Variables en la Nube","tw.menuBar.cloudUnavailable":"Variables en la Nube no Disponibles","tw.menuBar.cloudUnavailableAlert":"No se pueden usar variables en la nube, probablemente porque abriste el editor.","tw.menuBar.loadRestorePoint":"Cargar punto de restauración","tw.menuBar.moreSettings":"Ajustes Avanzados","tw.menuBar.newFramerate":"Nuevo FPS:","tw.menuBar.package":"Convertir proyecto","tw.menuBar.reportError1":"Algunos scripts no pudieron ser compilados","tw.menuBar.reportError2":"Esto es un bug. Por favor repórtelo.","tw.menuBar.saveAs":"Guardar como {file}","tw.menuBar.seeInside":"Ver dentro","tw.oldDownload":"Guardar a archivo separado...","tw.openAdvanced":"Abrir opciones avanzadas","tw.paint.alpha":"Opacidad","tw.privacy":"Política de Privacidad","tw.restorePoint.confirm":"El editor automáticamente guarda un punto de restaurado en caso de que algo vaya mal y olvide guardar el progreso. No debería confiar en esto y no podemos garantizar que el proyecto será recuperado. ¿Intentar cargarlo?","tw.restorePoint.loadFail":"No se pudo cargar el punto de restaurado: {error}","tw.saveAs":"Guardar como...","tw.saveTo":"Guardar a {file}","tw.scratchUnsafeCloud":"Si hace esto una variable en la nube, el proyecto exederá el límite de Scratch de {number} variables y algunas variables no funcionarán si sube el proyecto a Scratch.","tw.settingsModal.customStageSize":"Tamaño Personalizado del Escenario:","tw.settingsModal.customStageSizeHelp":"Cambia el tamaño del escenario de Scratch de 480x360 a algo diferente. Pruebe 640x360 para hacer el escenario más ancho. Muy pocos proyectos manejarán esto adecuadamente.","tw.settingsModal.dangerZone":"Zona Peligrosa","tw.settingsModal.disableCompiler":"Desactivar Compilador","tw.settingsModal.disableCompilerHelp":"Desactiva el compilador de TurboWarp. Puede que quiera activar esto mientras edita proyectos para que sus scripts se actualicen inmediatamente. Si ese no es el caso, no debería activar esto nunca.","tw.settingsModal.featured":"Destacado","tw.settingsModal.fps":"60 FPS (FPS Personalizado)","tw.settingsModal.fpsHelp":"Ejecuta scripts 60 veces por segundo en vez de 30. La mayoría de los proyectos no funcionarán correctamente con esto activado. Debería probar Interpolación con modo 60 FPS desactivado si ese es el caso. {customFramerate}.","tw.settingsModal.fpsHelp.customFramerate":"Haga click para usar un framerate diferente a 30 o 60","tw.settingsModal.help":"Haga click para ayuda","tw.settingsModal.highQualityPen":"Lápiz de Alta Calidad","tw.settingsModal.highQualityPenHelp":"Permite a los proyectos que usen la extensión del Lápiz renderizar en una mayor resolución y desactiva el redondeo de coordenadas dentro del editor. No todos los proyectos se ven beneficiados de esta configuración, pues puede afectar negativamente el rendimiento. ","tw.settingsModal.infiniteClones":"Clones Infinitos","tw.settingsModal.infiniteClonesHelp":"Desactiva el límite de 300 clones de Scratch.","tw.settingsModal.interpolation":"Interpolación","tw.settingsModal.interpolationHelp":"Hace que los movimientos dentro de los proyectos se vean más suaves al interpolar los cambios de posición de los objetos. No es recomendable utilizar el ajuste de interpolación en proyectos 3D o proyectos que utilicen la extensión del Lápiz u otros proyectos que sean de bajo rendimiento, ya que esta función lo ralentizará aún más.","tw.settingsModal.largeStageWarning":"Usar un tamaño personalizado del escenario tan grande no es recomendado. En cambio, use un tamaño más pequeño con la misma relación de aspecto y permita que el modo pantalla completa agrande el escenario para cubrir toda la pantalla del usuario.","tw.settingsModal.removeFencing":"Quitar Fencing","tw.settingsModal.removeFencingHelp":"Permite a los objetos moverse afuera de la pantalla o hacerse tan grandes o chicos como deseen y hace funcionar los bloques \\"tocando\\" fuera de la pantalla.","tw.settingsModal.removeLimits":"Quitar Límites","tw.settingsModal.removeMiscLimits":"Quitar Límites Varios","tw.settingsModal.removeMiscLimitsHelp":"Elimina los límites de sonido y de tamaño del lápiz.","tw.settingsModal.storeProjectOptions":"Guardar ajustes en proyecto","tw.settingsModal.storeProjectOptionsHelp":"Guarda los ajustes seleccionados en el proyecto para que sean aplicados automáticamente cuando TurboWarp carga este proyecto. Warp Timer y desactivar compilador no serán guardados.","tw.settingsModal.title":"Ajustes Avanzados","tw.settingsModal.warpTimerHelp":"Hace que los scripts revisen si están atascados en un bucle infinito y si es así, hace que vayan a una menor tasa de refresco hasta que el bucle termine, logrando evitar la mayoría de colapsos por este tipo de errores. Este ajuste tiene un impacto negativo significante en el rendimiento, por lo que solo está habilitado por defecto en el editor.","tw.spriteSelectorItem.rename":"renombrar","tw.stereo":"Estéreo","tw.stereoAlert":"Editar este sonido estéreo lo convertirá irreversiblemente en mono.","tw.studioview.authorAttribution":"por {author}","tw.studioview.error":"Ocurrió un error cargando la siguiente página de proyectos.","tw.studioview.hoverText":"{title} por {author}","tw.tooLarge":"Este sonido podría ser demasiado grande como para cargarlo en Scratch.","tw.twExtension.description":"Bloques nuevos raros. No compatibles con Scratch.","tw.twExtension.name":"Bloques TurboWarp","tw.unshared.1":"Proyectos no compartidos no serán accesibles usando solamente su ID en algún punto debido a cambios en el API de Scratch por venir.","tw.unshared.2":"Para más información, visite: {link}","tw.unshared.cache":"Si el proyecto se a compartido recientemente, este mensaje podría aparecer incorrectamente por algunos minutos.","tw.usernameModal.help":"Este valor será guardado en el almacenamiento de su navegador. Es posible que sea usado cuando interactúe con proyectos que contengan variables en la nube.","tw.usernameModal.help2":"Valores que no corresponden a una cuenta de Scratch válida típicamente serán rechazadas por el servidor de variables en la nube. Se le recomienda dejarlo como está o cambiarlo a su nombre de usuario de Scratch.","tw.usernameModal.mustChange":"Lo sentimos, el servidor de variables en la nube piensa que tu nombre de usuario puede ser inseguro. Por favor cámbielo a otra cosa o {resetIt}.","tw.usernameModal.mustChange.resetIt":"resetéelo (recomendado)","tw.usernameModal.reset":"Reiniciar","tw.usernameModal.title":"Cambiar Nombre de Usuario","tw.viewFeaturedProjects":"Clickee para ver proyectos destacados.","tw.viewOnScratch":"Ver proyecto en Scratch","tw.webglModal.description":"Desafortunadamente parece que tu navegador o computadora {webGlLink}. Esta tecnología se necesita para que funcione este sitio. Intente actualizar su navegador y drivers gráficos o reinicie su computadora."},"eo":{"gui.alerts.tryAgain":"Reprovi","gui.alerts.download":"Elŝuti","gui.connection.reconnect":"Rekonekti","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Dorsosako","gui.backpack.errorBackpack":"Eraro dum malfermo de dorsosako","gui.backpack.loadingBackpack":"Ŝargado...","gui.backpack.more":"Pli","gui.backpack.emptyBackpack":"Dorsosako estas malplena","gui.unsupportedBrowser.label":"Scratch ne funkcias kun via TTT-legilo","gui.cards.all-tutorials":"Instruilo","gui.cards.shrink":"Malgrandigi","gui.cards.expand":"Vidigi","gui.cards.close":"Fermi","gui.cards.more-things-to-try":"Aliaj aferoj por provi!","gui.cards.see-more":"Vidi pli","gui.comingSoon.message1":"Ne zorgu, ni baldaŭ okupiĝos pri tio {emoji}","gui.comingSoon.message2":"Venos baldaŭ...","gui.comingSoon.message3":"Ni laboras pri tio {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Neniu aparato trovita","gui.connection.auto-scanning.prescan":"Alproksimigu vian aparaton, kaj ekigi la serĉon.","gui.connection.auto-scanning.pressbutton":"Tuŝu la butonon sur via aparato.","gui.connection.auto-scanning.start-search":"Komenci serĉi","gui.connection.connecting-searchbutton":"Serĉado...","gui.connection.auto-scanning.try-again":"Reprovi","gui.connection.connected":"Konektita","gui.connection.disconnect":"Malkonekti","gui.connection.go-to-editor":"Iri al Redaktilo","gui.connection.connecting-cancelbutton":"Konektado...","gui.connection.error.errorMessage":"Ups, ŝajne okazis ia eraro.","gui.connection.error.tryagainbutton":"Reprovi","gui.connection.error.helpbutton":"Helpo","gui.connection.peripheral-name-label":"Nomo de aparato","gui.connection.connect":"Konekti","gui.connection.scanning.lookingforperipherals":"Serĉado por aparatoj...","gui.connection.scanning.noPeripheralsFound":"Neniu aparato trovita","gui.connection.scanning.instructions":"Elektu vian aparaton el la ĉi-supra listo.","gui.connection.search":"Re-serĉi","gui.connection.unavailable.installscratchlink":"Kontrolu, ke Scratch Link estas instalita kaj aktuale funkcias","gui.connection.unavailable.enablebluetooth":"Kontrolu, ke Bluetooth estas ŝaltita","gui.connection.unavailable.tryagainbutton":"Reprovi","gui.connection.unavailable.helpbutton":"Helpo","gui.controls.go":"Ek!","gui.controls.stop":"Halti","gui.crashMessage.label":"Ups! Eraro okazis.","gui.crashMessage.errorNumber":"Via eraro estas registrita kun la ID {errorId}","gui.crashMessage.reload":"Reŝargi","gui.customProcedures.myblockModalTitle":"Krei blokon","gui.customProcedures.addAnInputNumberText":"Aldoni enigon","gui.customProcedures.numberTextType":"numero aŭ teksto","gui.customProcedures.addAnInputBoolean":"Aldoni enigon","gui.customProcedures.booleanType":"bulea","gui.customProcedures.addALabel":"Aldoni etikedon","gui.customProcedures.runWithoutScreenRefresh":"Rulumi sen redesegni la ekranon","gui.customProcedures.cancel":"Rezigni","gui.customProcedures.ok":"Bone","gui.SpriteInfo.direction":"Direkto","gui.directionPicker.rotationStyles.allAround":"turniĝi libere","gui.directionPicker.rotationStyles.leftRight":"nur dekstre-maldekstre","gui.directionPicker.rotationStyles.dontRotate":"ne turniĝi","gui.gui.addExtension":"Aldoni kromaĵon","gui.gui.codeTab":"Skriptoj","gui.gui.backdropsTab":"Fonoj","gui.gui.costumesTab":"Kostumoj","gui.gui.soundsTab":"Sonoj","gui.extensionLibrary.comingSoon":"Baldaŭ venos","gui.extensionLibrary.requires":"Bezonas","gui.extensionLibrary.collaboration":"Kunlaboro kun","gui.library.filterPlaceholder":"Serĉi","gui.library.allTag":"Ĉion","gui.loader.headline":"Ŝargado de projekto","gui.loader.creating":"Kreado de projekto","gui.authorInfo.byUser":"de {username}","gui.menuBar.seeProjectPage":"Vidi projektan paĝon","gui.menuBar.LanguageSelector":"elektilo por lingvoj","gui.menuBar.tutorialsLibrary":"Instruilo","gui.menuBar.restoreSprite":"Malfari forigon de rolulo","gui.menuBar.restoreSound":"Malfari forigon de sono","gui.menuBar.restoreCostume":"Malfari forigon de kostumo","gui.menuBar.restore":"Malfari forigon","gui.menuBar.saveNow":"Konservi nun","gui.menuBar.saveAsCopy":"Konservi kiel kopion","gui.menuBar.remix":"Remiksi","gui.menuBar.new":"Nova","gui.menuBar.file":"Dosiero","gui.menuBar.downloadToComputer":"Konservi ĉe via komputilo","gui.menuBar.edit":"Redakti","gui.menuBar.turboModeOff":"Malŝalti turbinan reĝimon","gui.menuBar.turboModeOn":"Ŝalti turbinan reĝimon","gui.gui.projectTitlePlaceholder":"Sentitola projekto","gui.menuBar.isShared":"Kunhavigita","gui.menuBar.share":"Kunhavigi","gui.modal.help":"Helpo","gui.modal.back":"Reen","gui.monitor.listMonitor.empty":"(malplena)","gui.monitor.listMonitor.listLength":"longo {length}","gui.monitor.contextMenu.default":"kutima montrilo","gui.monitor.contextMenu.large":"granda indikilo","gui.monitor.contextMenu.slider":"ŝovilo","gui.monitor.contextMenu.sliderRange":"ŝanĝi amplekson de ŝovilo","gui.monitor.contextMenu.import":"importi","gui.monitor.contextMenu.export":"eksporti","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Aǔdigi","gui.playButton.stop":"Halti","gui.gui.variableScopeOptionAllSprites":"Por ĉiuj roluloj","gui.gui.variableScopeOptionSpriteOnly":"Nur por tiu ĉi rolulo","gui.gui.cloudVariableOption":"Ennuba variablo (stokita ĉe la servilo)","gui.gui.variablePromptAllSpritesMessage":"Tiu ĉi variablo estos atingebla de ĉiu rolulo.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Rezigni","gui.prompt.ok":"Bone","gui.playbackStep.stopMsg":"Halti","gui.playbackStep.playMsg":"Aǔdigi","gui.playbackStep.loadingMsg":"Ŝargado...","gui.playbackStep.saveMsg":"Konservi","gui.playbackStep.reRecordMsg":"Re-registri","gui.recordModal.title":"Registri sonon","gui.recordingStep.beginRecord":"Komenci registri per la butono sube","gui.recordingStep.permission":"{arrow} Ni bezonas vian permeson por uzi vian mikrofonon","gui.recordingStep.stop":"Fini registri","gui.recordingStep.record":"Registri","gui.sliderModal.min":"Minimuma valoro","gui.sliderModal.max":"Maksimuma valoro","gui.sliderModal.title":"Ŝanĝi amplekson de ŝovilo","gui.sliderPrompt.cancel":"Rezigni","gui.sliderPrompt.ok":"Bone","gui.soundEditor.sound":"Sono","gui.soundEditor.play":"Aǔdigi","gui.soundEditor.stop":"Halti","gui.soundEditor.copy":"Kopii","gui.soundEditor.paste":"Alglui","gui.soundEditor.copyToNew":"Kopii al nova","gui.soundEditor.delete":"Forigi","gui.soundEditor.save":"Konservi","gui.soundEditor.undo":"Malfari","gui.soundEditor.redo":"Refari","gui.soundEditor.faster":"Plirapidigi","gui.soundEditor.slower":"Malplirapidigi","gui.soundEditor.echo":"Eĥo","gui.soundEditor.robot":"Roboto","gui.soundEditor.louder":"Plilaŭtigi","gui.soundEditor.softer":"Malplilaŭtigi","gui.soundEditor.reverse":"Inversigi","gui.soundEditor.fadeOut":"Poiome mallaŭtigi","gui.soundEditor.fadeIn":"Poiome laŭtigi","gui.soundEditor.mute":"Silentigi","gui.SpriteInfo.spritePlaceholder":"Nomo","gui.SpriteInfo.sprite":"Rolulo","gui.SpriteInfo.show":"Montri","gui.SpriteInfo.size":"Grandeco","gui.spriteSelectorItem.contextMenuDuplicate":"duplikati","gui.spriteSelectorItem.contextMenuExport":"eksporti","gui.spriteSelectorItem.contextMenuDelete":"forigi","gui.spriteSelector.addSpriteFromLibrary":"Elekti rolulon","gui.spriteSelector.addSpriteFromPaint":"Desegni","gui.spriteSelector.addSpriteFromSurprise":"Hazarda","gui.spriteSelector.addSpriteFromFile":"Alŝuti rolulon","gui.stageHeader.stageSizeLarge":"Ŝanĝi al granda scenejo","gui.stageHeader.stageSizeSmall":"Ŝanĝi al malgranda scenejo","gui.stageHeader.stageSizeFull":"Uzi plenan ekranon","gui.stageHeader.stageSizeUnFull":"Ne uzi plenan ekranon","gui.stageHeader.fullscreenControl":"Regilo de plenekrana reĝimo","gui.spriteSelector.addBackdropFromLibrary":"Elekti scenejon","gui.stageSelector.addBackdropFromPaint":"Desegni","gui.stageSelector.addBackdropFromSurprise":"Hazarda","gui.stageSelector.addBackdropFromFile":"Alŝuti scenejon","gui.stageSelector.stage":"Scenejo","gui.stageSelector.backdrops":"Fonoj","gui.telemetryOptIn.label":"Raporti statistikojn por plibonigi Scratch","gui.telemetryOptIn.body1":"La skipo de Scratch ĉiam volas pli bone kompreni kiel Scratch uziĝas ĉirkaŭ la mondo. Por helpi kun tio, vi povas permesi, ke Scratch resendu anonimajn informojn pri via uzo al la skipo de Scratch.","gui.telemetryOptIn.body2":"La informoj kolektitaj estas ekzemple pri la lingvo, la blokoj uzitaj, kaj kelkaj eventoj kiel konservi, ŝargi, alŝuti, k.s. Ni NENIAM kolektas personajn informojn pri vi. Nia {privacyPolicyLink} enhavas pli da informoj pri tio. ","gui.telemetryOptIn.privacyPolicyLink":"Privateca Politiko","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Rapidega Reĝimo","gui.webglModal.label":"WebGL ne funkcias en via retumilo.","gui.webglModal.webgllink":"mankas WebGL","gui.costumeLibrary.chooseABackdrop":"Elekti scenejon","gui.costumeLibrary.chooseACostume":"Elekti kostumon","gui.costumeTab.addBackdropFromLibrary":"Elekti scenejon","gui.costumeTab.addCostumeFromLibrary":"Elekti kostumon","gui.costumeTab.addBlankCostume":"Desegni","gui.costumeTab.addSurpriseCostume":"Hazarda","gui.costumeTab.addFileBackdrop":"Alŝuti scenejon","gui.costumeTab.addFileCostume":"Alŝuti kostumon","gui.extensionLibrary.chooseAnExtension":"Elekti kromprogramon","gui.extensionLibrary.extensionUrl":"Tajpu la URL-on de la kromprogramo","gui.monitors.importListColumnPrompt":"Kiun kolumnon ni uzu? (inter 1 kaj {numberOfColumns})","gui.recordingStep.alertMsg":"Ne eblis komenci registri","gui.soundLibrary.chooseASound":"Elekti sonon","gui.soundTab.fileUploadSound":"Alŝuti sonon","gui.soundTab.surpriseSound":"Hazarda","gui.soundTab.recordSound":"Registri","gui.soundTab.addSoundFromLibrary":"Elekti sonon","gui.spriteLibrary.chooseASprite":"Elekti rolulon","gui.tipsLibrary.tutorials":"Elekti lernilon","gui.alerts.createsuccess":"Nova projekto kreita.","gui.alerts.createcopysuccess":"Projekto konservita kiel kopio","gui.alerts.createremixsuccess":"Projekto konservita kiel remikso.","gui.alerts.creating":"Kreado de nova...","gui.alerts.creatingCopy":"Kopiado de projekto...","gui.alerts.creatingRemix":"Remiksado de projekto...","gui.alerts.creatingError":"Ne eblis krei la projekton. Bonvolu reprovi!","gui.alerts.savingError":"Ne eblis konservi la projekton.","gui.alerts.savesuccess":"Projekto konservita.","gui.alerts.saving":"Konservado de projekto...","gui.alerts.cloudInfo":"Notu, ke nuba variablo povas teni nur numeron, ne literojn nek simbolojn. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Lerni pli pri tio.","gui.alerts.importing":"Importado...","gui.defaultProject.variable":"mia variablo","gui.extension.music.name":"Muziko","gui.extension.music.description":"Ludi instrumentojn kaj tamburojn.","gui.extension.pen.name":"Skribilo","gui.extension.pen.description":"Desegni per viaj roluloj.","gui.extension.videosensing.name":"Video-sentiloj","gui.extension.videosensing.description":"Detekti movojn per la kamerao","gui.extension.text2speech.name":"Teksto al parolado","gui.extension.text2speech.description":"Paroligi viajn projektojn","gui.extension.translate.name":"Traduki","gui.extension.translate.description":"Traduki tekston al multaj lingvoj.","gui.extension.makeymakey.description":"Fari butonon el io ajn.","gui.extension.microbit.description":"Konekti viajn projektojn al la mondo.","gui.extension.microbit.connectingMessage":"Konektado","gui.extension.ev3.description":"Konstrui interaktivajn robotojn, kaj pli.","gui.extension.ev3.connectingMessage":"Konektado daŭras... Kontrolu, ke vi agordis la sekretan numeron de via EV3 al 1234.","gui.extension.boost.description":"Vivigi robotajn kreaĵojn.","gui.extension.boost.connectingMessage":"Konektado","gui.extension.wedo2.description":"Konstrui per motoroj kaj detektiloj","gui.extension.wedo2.connectingMessage":"Konektado","gui.extension.gdxfor.description":"Detekti puŝojn, tirojn, movojn kaj turnojn","gui.extension.gdxfor.connectingMessage":"Konektado","gui.libraryTags.all":"Ĉion","gui.libraryTags.animals":"Bestoj","gui.libraryTags.dance":"Danci","gui.libraryTags.effects":"Efektoj","gui.libraryTags.fantasy":"Fantazio","gui.libraryTags.fashion":"Modo","gui.libraryTags.food":"Nutraĵoj","gui.libraryTags.indoors":"En konstruaĵo","gui.libraryTags.loops":"Iteracioj","gui.libraryTags.music":"Muziko","gui.libraryTags.notes":"Notoj","gui.libraryTags.outdoors":"Ekstere","gui.libraryTags.patterns":"Ŝablonoj","gui.libraryTags.people":"Homoj","gui.libraryTags.percussion":"Frapinstrumentoj","gui.libraryTags.space":"La Kosmo","gui.libraryTags.sports":"Sportoj","gui.libraryTags.underwater":"Subakve","gui.libraryTags.voice":"Voĉo","gui.libraryTags.wacky":"Frenezaĵoj","gui.libraryTags.animation":"Animacio","gui.libraryTags.art":"Arto","gui.libraryTags.games":"Ludoj","gui.libraryTags.stories":"Rakontoj","gui.libraryTags.letters":"Literoj","gui.opcodeLabels.direction":"orientiĝo","gui.opcodeLabels.xposition":"x-pozicio","gui.opcodeLabels.yposition":"y-pozicio","gui.opcodeLabels.size":"grando","gui.opcodeLabels.costumename":"nomo de kostumo","gui.opcodeLabels.costumenumber":"numero de kostumo","gui.opcodeLabels.backdropname":"nomo de fono","gui.opcodeLabels.backdropnumber":"numero de fono","gui.opcodeLabels.volume":"laŭteco","gui.opcodeLabels.tempo":"rapido","gui.opcodeLabels.answer":"respondo","gui.opcodeLabels.loudness":"laŭto","gui.opcodeLabels.username":"salutnomo","gui.opcodeLabels.year":"jaro","gui.opcodeLabels.month":"monato","gui.opcodeLabels.date":"dato","gui.opcodeLabels.dayofweek":"tago de la semajno","gui.opcodeLabels.hour":"horo","gui.opcodeLabels.minute":"minuto","gui.opcodeLabels.second":"sekundo","gui.opcodeLabels.timer":"horloĝo","gui.sharedMessages.backdrop":"fono n-ro {index}","gui.sharedMessages.costume":"kostumo n-ro {index}","gui.sharedMessages.sprite":"rolulo n-ro {index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Forigi enhavon de aktuala projekto, ĉu?","gui.sharedMessages.loadFromComputerTitle":"Alŝuti de via komputilo","boost.color.any":"iu ajn koloro","boost.color.black":"nigra","boost.color.blue":"blua","boost.color.green":"verda","boost.color.red":"ruĝa","boost.color.white":"blanka","boost.color.yellow":"flava","boost.getMotorPosition":"pozicio de motoro [MOTOR_REPORTER_ID]","boost.getTiltAngle":"angulo de klino [TILT_DIRECTION]","boost.motorDirection.backward":"tien","boost.motorDirection.forward":"ĉi tien","boost.motorDirection.reverse":"renversi","boost.motorOff":"malŝalti motoron [MOTOR_ID]","boost.motorOn":"ŝalti motoron [MOTOR_ID]","boost.motorOnFor":"ŝalti motoron [MOTOR_ID] dum [DURATION] sekundoj","boost.motorOnForRotation":"ŝalti motoron [MOTOR_ID] dum [ROTATION] turnoj","boost.seeingColor":"ĉu [COLOR] briko videblas?","boost.setLightHue":"kolorigi LED al [HUE]","boost.setMotorDirection":"motoro [MOTOR_ID] turniĝu [MOTOR_DIRECTION]","boost.setMotorPower":"motoro [MOTOR_ID] turniĝu kun rapideco [POWER] %","boost.tiltDirection.any":"iu ajn","boost.tiltDirection.down":"malsupre","boost.tiltDirection.left":"maldekstra","boost.tiltDirection.right":"dekstre","boost.tiltDirection.up":"supre","boost.whenColor":"kiam [COLOR] briko videblas","boost.whenTilted":"kiam klinita [TILT_DIRECTION_ANY]","ev3.beepNote":"sonorigi noton [NOTE] dum [TIME] sekundoj","ev3.buttonPressed":"ĉu butono [PORT] estas premita?","ev3.getBrightness":"heleco","ev3.getDistance":"distanco","ev3.getMotorPosition":"pozicio de motoro ĉe pordo [PORT]","ev3.motorSetPower":"motoro ĉe pordo [PORT] turniĝu kun rapideco [POWER] %","ev3.motorTurnClockwise":"motoro ĉe pordo [PORT] turniĝu dekstrume dum [TIME] sekundoj","ev3.motorTurnCounterClockwise":"motoro ĉe pordo [PORT] turniĝu maldekstrume dum [TIME] sekundoj","ev3.whenBrightnessLessThan":"kiam brileco < [DISTANCE]","ev3.whenButtonPressed":"kiam butono ĉe pordo [PORT] estas premita","ev3.whenDistanceLessThan":"kiam distanco < [DISTANCE]","gdxfor.getAcceleration":"akcelo [DIRECTION]","gdxfor.getForce":"forto","gdxfor.getSpin":"rapideco de turnado [DIRECTION]","gdxfor.getTilt":"angulo de klino [TILT]","gdxfor.isFreeFalling":"ĉu falanta?","gdxfor.isTilted":"ĉu klinita [TILT]?","gdxfor.pulled":"tirita","gdxfor.pushed":"puŝita","gdxfor.shaken":"ŝancelita","gdxfor.startedFalling":"ekfalas","gdxfor.tiltDirectionMenu.any":"iu ajn","gdxfor.tiltDirectionMenu.back":"fona","gdxfor.tiltDirectionMenu.front":"malfona","gdxfor.tiltDirectionMenu.left":"maldekstra","gdxfor.tiltDirectionMenu.right":"dekstre","gdxfor.turnedFaceDown":"turnita frontosuben","gdxfor.turnedFaceUp":"turnita frontosupren","gdxfor.whenForcePushedOrPulled":"kiam fortodetektilo [PUSH_PULL]","gdxfor.whenGesture":"kiam [GESTURE]","gdxfor.whenTilted":"kiam klinita [TILT]","makeymakey.downArrow":"sago malsupra","makeymakey.downArrowShort":"malsupre","makeymakey.leftArrow":"sago maldekstra","makeymakey.leftArrowShort":"maldekstra","makeymakey.rightArrow":"sago dekstra","makeymakey.rightArrowShort":"dekstre","makeymakey.spaceKey":"spacetklavo","makeymakey.upArrow":"sago supra","makeymakey.upArrowShort":"supre","makeymakey.whenKeyPressed":"kiam klavo [KEY] premita","makeymakey.whenKeysPressedInOrder":"kiam sinsekvo [SEQUENCE] tajpita","microbit.buttonsMenu.any":"iu ajn","microbit.clearDisplay":"viŝi matricon","microbit.defaultTextToDisplay":"Saluton!","microbit.displaySymbol":"afiŝi [MATRIX]","microbit.displayText":"afiŝi tekston [TEXT]","microbit.gesturesMenu.jumped":"saltigita","microbit.gesturesMenu.moved":"movita","microbit.gesturesMenu.shaken":"ŝancelita","microbit.isButtonPressed":"ĉu butono [BTN] premita?","microbit.isTilted":"ĉu klinita [DIRECTION]?","microbit.pinStateMenu.off":"malŝaltita","microbit.pinStateMenu.on":"ŝaltita","microbit.tiltAngle":"angulo de kliniĝo [DIRECTION]","microbit.tiltDirectionMenu.any":"iu","microbit.tiltDirectionMenu.back":"reen","microbit.tiltDirectionMenu.front":"malfona","microbit.tiltDirectionMenu.left":"maldekstra","microbit.tiltDirectionMenu.right":"dekstre","microbit.whenButtonPressed":"kiam butono [BTN] premita","microbit.whenGesture":"kiam [GESTURE]","microbit.whenPinConnected":"kiam stifto [PIN] konektita","microbit.whenTilted":"kiam klinita [DIRECTION]","music.categoryName":"Muziko","music.changeTempo":"ŝanĝi muziktempon je [TEMPO]","music.drumBass":"(2) Bastamburo","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Kabaso","music.drumClaves":"(9) Klaveo","music.drumClosedHiHat":"(6) Fermita ĉarlestono","music.drumConga":"(14) Kongao","music.drumCowbell":"(11) Bovtintilo","music.drumCrashCymbal":"(4) cimbalo","music.drumCuica":"(18) Kuiko","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Manfrapo","music.drumOpenHiHat":"(5) Malferma ĉarlestono","music.drumSideStick":"(3) Batil-flanke","music.drumSnare":"(1) Tambureto","music.drumTambourine":"(7) Tamburino","music.drumTriangle":"(12) Triangulo","music.drumVibraslap":"(17) Vibrafrapo","music.drumWoodBlock":"(10) Lignobloko","music.getTempo":"rapido","music.instrumentBass":"(6) Baso","music.instrumentBassoon":"(14) Fagoto","music.instrumentCello":"(8) Violonĉelo","music.instrumentChoir":"(15) Ĥoro","music.instrumentClarinet":"(10) Klarneto","music.instrumentElectricGuitar":"(5) Elektra gitaro","music.instrumentElectricPiano":"(2) Elektra piano","music.instrumentFlute":"(12) Transversa fluto","music.instrumentGuitar":"(4) Gitaro","music.instrumentMarimba":"(19) Marimbo","music.instrumentMusicBox":"(17) Musik-skatolo","music.instrumentOrgan":"(3) Orgeno","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saksofono","music.instrumentSteelDrum":"(18) Ŝtaltamburo","music.instrumentSynthLead":"(20) Sintezilo 1","music.instrumentSynthPad":"(21) Sintezilo 2","music.instrumentTrombone":"(9) Trombono","music.instrumentVibraphone":"(16) Vibrafono","music.instrumentWoodenFlute":"(13) Ligna fluto","music.midiPlayDrumForBeats":"ludi tamburon [DRUM] dum [BEATS] taktoj","music.midiSetInstrument":"elekti instrumenton [INSTRUMENT]","music.playDrumForBeats":"ludi tamburon [DRUM] dum [BEATS] taktoj","music.playNoteForBeats":"ludi noton [NOTE] dum [BEATS] taktoj","music.restForBeats":"silenti dum [BEATS] taktoj","music.setInstrument":"elekti instrumenton [INSTRUMENT]","music.setTempo":"agordi muziktempon al [TEMPO]","pen.categoryName":"Skribilo","pen.changeColorParam":"ŝanĝi skribilon [COLOR_PARAM] je [VALUE]","pen.changeHue":"ŝanĝi koloron de skribilo de [HUE]","pen.changeShade":"ŝanĝi kolornuancon de skribilo de [SHADE]","pen.changeSize":"ŝanĝi grandon de skribilo de [SIZE]","pen.clear":"forigi ĉion","pen.colorMenu.brightness":"heleca","pen.colorMenu.color":"kolora","pen.colorMenu.saturation":"satureco","pen.colorMenu.transparency":"travedebleco","pen.penDown":"ekskribi","pen.penUp":"ĉesi skribi","pen.setColor":"kolorigi skribilon al [COLOR]","pen.setColorParam":"agordi [COLOR_PARAM] de skribilo al [VALUE]","pen.setHue":"kolorigi skribilon al [HUE]","pen.setShade":"agordi kolornuancon de skribilo al [SHADE]","pen.setSize":"agordi grandon de skribilo al [SIZE]","pen.stamp":"stampi","text2speech.alto":"aldo","text2speech.categoryName":"Teksto al parolado","text2speech.defaultTextToSpeak":"saluton","text2speech.giant":"gigantulo","text2speech.kitten":"katido","text2speech.setLanguageBlock":"agordi lingvon al [LANGUAGE]","text2speech.setVoiceBlock":"agordi voĉon al [VOICE]","text2speech.speakAndWaitBlock":"diri [WORDS]","text2speech.squeak":"muso","text2speech.tenor":"tenoro","translate.categoryName":"Traduki","translate.defaultTextToTranslate":"saluton","translate.translateBlock":"traduki [WORDS] al [LANGUAGE]","translate.viewerLanguage":"lingvo","videoSensing.categoryName":"Video-detektiloj","videoSensing.direction":"orientiĝo","videoSensing.motion":"movado","videoSensing.off":"malŝaltita","videoSensing.on":"ŝaltita","videoSensing.onFlipped":"ŝaltita kaj inversita","videoSensing.setVideoTransparency":"agordi travideblecon de video al [TRANSPARENCY]","videoSensing.sprite":"rolulo","videoSensing.stage":"scenejo","videoSensing.videoOn":"[ATTRIBUTE] de video sur [SUBJECT]","videoSensing.videoToggle":"agordi videon [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"kiam movo en video > [REFERENCE]","wedo2.getDistance":"distanco","wedo2.getTiltAngle":"angulo de klino [TILT_DIRECTION]","wedo2.isTilted":"ĉu inklinita [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"tien","wedo2.motorDirection.forward":"ĉi tien","wedo2.motorDirection.reverse":"renversi","wedo2.motorId.a":"motoro A","wedo2.motorId.all":"ĉiuj motoroj","wedo2.motorId.b":"motoro B","wedo2.motorId.default":"motoro","wedo2.motorOff":"malŝalti [MOTOR_ID]","wedo2.motorOn":"ŝalti [MOTOR_ID]","wedo2.motorOnFor":"ŝalti [MOTOR_ID] dum [DURATION] sekundoj","wedo2.playNoteFor":"ludi noton [NOTE] dum [DURATION] sekundoj","wedo2.setLightHue":"kolorigi LED al [HUE]","wedo2.setMotorDirection":"agordi direkton de [MOTOR_ID] al [MOTOR_DIRECTION]","wedo2.startMotorPower":"agordi rapidecon de [MOTOR_ID] al [POWER]","wedo2.tiltDirection.any":"iu","wedo2.tiltDirection.down":"malsupre","wedo2.tiltDirection.left":"maldekstra","wedo2.tiltDirection.right":"dekstre","wedo2.tiltDirection.up":"supre","wedo2.whenDistance":"kiam distanco [OP] [REFERENCE]","wedo2.whenTilted":"kiam klinita [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Koloro","paint.paintEditor.saturation":"Satureco","paint.paintEditor.brightness":"Heleco","paint.paintEditor.costume":"Kostumo","paint.paintEditor.group":"Grupo","paint.paintEditor.ungroup":"Malgrupigi","paint.paintEditor.undo":"Malfari","paint.paintEditor.redo":"Refari","paint.paintEditor.forward":"supren","paint.paintEditor.backward":"malsupren","paint.paintEditor.front":"al la supro","paint.paintEditor.back":"Reen","paint.paintEditor.more":"Pli","paint.modeTools.brushSize":"Grandeco","paint.modeTools.eraserSize":"grando de forviŝilo","paint.modeTools.copy":"Kopii","paint.modeTools.paste":"Alglui","paint.modeTools.delete":"Forigi","paint.modeTools.curved":"Kurbigi","paint.modeTools.pointed":"akrigi","paint.modeTools.thickness":"Larĝo","paint.modeTools.flipHorizontal":"inversi horizontale","paint.modeTools.flipVertical":"inversi vertikale","paint.modeTools.filled":"Plenigita","paint.modeTools.outlined":"Konturo","paint.paintEditor.bitmap":"Konverti al rastruma bildo","paint.paintEditor.vector":"Konverti al vektora bildo","paint.paintEditor.fill":"Plenigi","paint.paintEditor.stroke":"Konturo","paint.brushMode.brush":"Peniko","paint.eraserMode.eraser":"Forviŝilo","paint.fillMode.fill":"Plenigi","paint.lineMode.line":"Linio","paint.ovalMode.oval":"Cirklo","paint.rectMode.rect":"Rektangulo","paint.reshapeMode.reshape":"Ŝanĝi formon","paint.roundedRectMode.roundedRect":"Rondigita rektangulo","paint.selectMode.select":"Elekti","paint.textMode.text":"Teksto","paint.colorPicker.swap":"Interŝanĝi"},"eu":{"gui.alerts.tryAgain":"Saiatu berriro","gui.alerts.download":"Deskargatu","gui.connection.reconnect":"Birkonektatu","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"soinua","gui.backpack.scriptLabel":"script-a","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Motxila","gui.backpack.errorBackpack":"Errorea motxila kargatzean","gui.backpack.loadingBackpack":"Kargatzen...","gui.backpack.more":"Gehiago","gui.backpack.emptyBackpack":"Motxila hutsik dago","gui.unsupportedBrowser.label":"Nabigatzailea ez da onartzen","gui.cards.all-tutorials":"Tutorialak","gui.cards.shrink":"Shrink","gui.cards.expand":"Expand","gui.cards.close":"Itxi","gui.cards.more-things-to-try":"Probatzeko gauza gehiago!","gui.cards.see-more":"Ikusi gehiago","gui.comingSoon.message1":"Lasai, horretan gabiltza {emoji}","gui.comingSoon.message2":"Laster ...","gui.comingSoon.message3":"Horretan ari gara {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Ez da gailurik aurkitu","gui.connection.auto-scanning.prescan":"Gailua hurbil badaukazu, hasi bilatzen.","gui.connection.auto-scanning.pressbutton":"Sakatu zure gailuko botoia.","gui.connection.auto-scanning.start-search":"Hasi bilatzen","gui.connection.connecting-searchbutton":"Bilatzen...","gui.connection.auto-scanning.try-again":"Saiatu berriro","gui.connection.connected":"Konektatuta","gui.connection.disconnect":"Konexiorik gabe","gui.connection.go-to-editor":"Joan editorera","gui.connection.connecting-cancelbutton":"Konektatzen...","gui.connection.error.errorMessage":"Ene! Ematen du zerbait oker dabilela","gui.connection.error.tryagainbutton":"Saiatu berriro","gui.connection.error.helpbutton":"Laguntza","gui.connection.peripheral-name-label":"Gailuaren izena","gui.connection.connect":"Konektatu","gui.connection.scanning.lookingforperipherals":"Gailuak bilatzen","gui.connection.scanning.noPeripheralsFound":"Ez da gailurik aurkitu","gui.connection.scanning.instructions":"Hautatu zure gailua goiko zerrendan.","gui.connection.search":"Freskatu","gui.connection.unavailable.installscratchlink":"Egiaztatu Scratch Link instalatuta duzula eta martxan dagoela","gui.connection.unavailable.enablebluetooth":"Egiaztatu bluetootha aktibo dagoela","gui.connection.unavailable.tryagainbutton":"Saiatu berriro","gui.connection.unavailable.helpbutton":"Laguntza","gui.controls.go":"Abiatu","gui.controls.stop":"Gelditu","gui.crashMessage.label":"Ene! Zerbaitek huts egin du","gui.crashMessage.errorNumber":"Zure errorea id honekin erregistratu da: {errorId}","gui.crashMessage.reload":"Kargatu berriro","gui.customProcedures.myblockModalTitle":"Sortu bloke bat","gui.customProcedures.addAnInputNumberText":"Gehitu sarrera bat","gui.customProcedures.numberTextType":"zenbakia edo testua","gui.customProcedures.addAnInputBoolean":"Gehitu sarrera bat","gui.customProcedures.booleanType":"boolearra","gui.customProcedures.addALabel":"Gehitu etiketa bat","gui.customProcedures.runWithoutScreenRefresh":"Abiatu pantaila eguneratu gabe","gui.customProcedures.cancel":"Utzi","gui.customProcedures.ok":"Ados","gui.SpriteInfo.direction":"Norabidea","gui.directionPicker.rotationStyles.allAround":"Norabide guztietara","gui.directionPicker.rotationStyles.leftRight":"Ezker/Eskuin","gui.directionPicker.rotationStyles.dontRotate":"Ez biratu","gui.gui.addExtension":"Gehitu gehigarri bat","gui.gui.codeTab":"Kodea","gui.gui.backdropsTab":"Atzeko oihalak","gui.gui.costumesTab":"Tankerak","gui.gui.soundsTab":"Soinuak","gui.extensionLibrary.comingSoon":"Laster","gui.extensionLibrary.requires":"Eskakizunak","gui.extensionLibrary.collaboration":"Hauekin elkar lanean","gui.library.filterPlaceholder":"Bilatu","gui.library.allTag":"Guztiak","gui.loader.headline":"Proiektua kargatzen","gui.loader.creating":"Proiektua sortzen","gui.authorInfo.byUser":"egilea {username}","gui.menuBar.seeProjectPage":"Ikusi proiektuaren orria","gui.menuBar.LanguageSelector":"hizkuntza hautatzailea","gui.menuBar.tutorialsLibrary":"Tutorialak","gui.menuBar.restoreSprite":"Berreskuratu pertsonaia","gui.menuBar.restoreSound":"Berreskuratu soinua","gui.menuBar.restoreCostume":"Berreskuratu tankera","gui.menuBar.restore":"Berreskuratu","gui.menuBar.saveNow":"Gorde orain","gui.menuBar.saveAsCopy":"Gorde kopia gisa","gui.menuBar.remix":"Birnahastu","gui.menuBar.new":"Berria","gui.menuBar.file":"Fitxategia","gui.menuBar.downloadToComputer":"Gorde zure ordenagailuan","gui.menuBar.edit":"Editatu","gui.menuBar.turboModeOff":"Itzali turbo modua","gui.menuBar.turboModeOn":"Piztu turbo modua","gui.gui.projectTitlePlaceholder":"Hemen proiektuaren titulua","gui.menuBar.isShared":"Partekatuak","gui.menuBar.share":"Partekatu","gui.modal.help":"Laguntza","gui.modal.back":"Atzera","gui.monitor.listMonitor.empty":"(hutsik)","gui.monitor.listMonitor.listLength":"luzera {length}","gui.monitor.contextMenu.default":"ohiko tamaina","gui.monitor.contextMenu.large":"tamaina handia","gui.monitor.contextMenu.slider":"graduatzailea","gui.monitor.contextMenu.sliderRange":"aldatu graduatzailearen mugak","gui.monitor.contextMenu.import":"inportatu","gui.monitor.contextMenu.export":"esportatu","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Erreproduzitu","gui.playButton.stop":"Gelditu","gui.gui.variableScopeOptionAllSprites":"Pertsonai guztientzat","gui.gui.variableScopeOptionSpriteOnly":"Pertsonai honentzat soilik","gui.gui.cloudVariableOption":"Hodei-aldagaia (zerbitzarian gordea)","gui.gui.variablePromptAllSpritesMessage":"Aldagai hau pertsonai guztientzat erabili daiteke.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Utzi","gui.prompt.ok":"Ados","gui.playbackStep.stopMsg":"Gelditu","gui.playbackStep.playMsg":"Erreproduzitu","gui.playbackStep.loadingMsg":"Kargatzen...","gui.playbackStep.saveMsg":"Gorde","gui.playbackStep.reRecordMsg":"Grabatu berriz","gui.recordModal.title":"Grabatu soinua","gui.recordingStep.beginRecord":"Hasi grabaketa beheko botoia sakatuz","gui.recordingStep.permission":"{arrow}Zure mikrofonoa erabiltzeko baimena behar dugu","gui.recordingStep.stop":"Gelditu grabaketa","gui.recordingStep.record":"Grabatu","gui.sliderModal.min":"Minimum value","gui.sliderModal.max":"Maximum value","gui.sliderModal.title":"Aldatu graduatzailearen mugak","gui.sliderPrompt.cancel":"Utzi","gui.sliderPrompt.ok":"Ados","gui.soundEditor.sound":"Soinua","gui.soundEditor.play":"Erreproduzitu","gui.soundEditor.stop":"Gelditu","gui.soundEditor.copy":"Kopiatu","gui.soundEditor.paste":"Itsatsi","gui.soundEditor.copyToNew":"Kopiatu berrira","gui.soundEditor.delete":"Ezabatu","gui.soundEditor.save":"Gorde","gui.soundEditor.undo":"Desegin","gui.soundEditor.redo":"Berregin","gui.soundEditor.faster":"Azkarrago","gui.soundEditor.slower":"Motelago","gui.soundEditor.echo":"Oihartzuna","gui.soundEditor.robot":"Robota","gui.soundEditor.louder":"Ozenago","gui.soundEditor.softer":"Isilago","gui.soundEditor.reverse":"Alderantzikatu","gui.soundEditor.fadeOut":"Fade out","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Mute","gui.SpriteInfo.spritePlaceholder":"Izena","gui.SpriteInfo.sprite":"Pertsonaia","gui.SpriteInfo.show":"Erakutsi","gui.SpriteInfo.size":"Tamaina","gui.spriteSelectorItem.contextMenuDuplicate":"bikoiztu","gui.spriteSelectorItem.contextMenuExport":"esportatu","gui.spriteSelectorItem.contextMenuDelete":"ezabatu","gui.spriteSelector.addSpriteFromLibrary":"Aukeratu pertsonai bat","gui.spriteSelector.addSpriteFromPaint":"Margotu","gui.spriteSelector.addSpriteFromSurprise":"Ezustekoa","gui.spriteSelector.addSpriteFromFile":"Kargatu pertsonaia","gui.stageHeader.stageSizeLarge":"Aldatu eszena handira","gui.stageHeader.stageSizeSmall":"Aldatu eszena txikira","gui.stageHeader.stageSizeFull":"Sartu pantaila osoko moduan","gui.stageHeader.stageSizeUnFull":"Atera pantaila osoko modutik","gui.stageHeader.fullscreenControl":"Pantaila osoa","gui.spriteSelector.addBackdropFromLibrary":"Aukeratu atzeko oihal bat","gui.stageSelector.addBackdropFromPaint":"Margotu","gui.stageSelector.addBackdropFromSurprise":"Ezustekoa","gui.stageSelector.addBackdropFromFile":"Kargatu atzeko oihala","gui.stageSelector.stage":"Eszena","gui.stageSelector.backdrops":"Atzeko oihalak","gui.telemetryOptIn.label":"Report statistics to improve Scratch","gui.telemetryOptIn.body1":"The Scratch Team is always looking to better understand how Scratch is used around the world. To help support this effort, you can allow Scratch to automatically send usage information to the Scratch Team.","gui.telemetryOptIn.body2":"The information we collect includes language selection, blocks usage, and some events like saving, loading, and uploading a project. We DO NOT collect any personal information. Please see our {privacyPolicyLink} for more information.","gui.telemetryOptIn.privacyPolicyLink":"Privacy Policy","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Itxi","gui.turboMode.active":"Turbo modua","gui.webglModal.label":"Zure nabigatzaileak ez du WebGL onartzen","gui.webglModal.webgllink":"ez duela WebGL onartzen","gui.costumeLibrary.chooseABackdrop":"Aukeratu atzeko oihal bat","gui.costumeLibrary.chooseACostume":"Aukeratu tankera bat","gui.costumeTab.addBackdropFromLibrary":"Aukeratu atzeko oihal bat","gui.costumeTab.addCostumeFromLibrary":"Aukeratu tankera bat","gui.costumeTab.addBlankCostume":"Margotu","gui.costumeTab.addSurpriseCostume":"Ezustekoa","gui.costumeTab.addFileBackdrop":"Kargatu atzeko oihala","gui.costumeTab.addFileCostume":"Kargatu tankera","gui.extensionLibrary.chooseAnExtension":"Aukeratu gehigarri bat","gui.extensionLibrary.extensionUrl":"Sartu gehigarriaren URLa","gui.monitors.importListColumnPrompt":"Which column should be used (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Ezin izan da hasi grabatzen","gui.soundLibrary.chooseASound":"Aukeratu soinu bat","gui.soundTab.fileUploadSound":"Kargatu soinua","gui.soundTab.surpriseSound":"Ezustekoa","gui.soundTab.recordSound":"Grabatu","gui.soundTab.addSoundFromLibrary":"Aukeratu soinu bat","gui.spriteLibrary.chooseASprite":"Aukeratu pertsonai bat","gui.tipsLibrary.tutorials":"Aukeratu tutorial bat","gui.alerts.createsuccess":"Sortu da proiektu berria.","gui.alerts.createcopysuccess":"Project saved as a copy.","gui.alerts.createremixsuccess":"Project saved as a remix.","gui.alerts.creating":"Creating new…","gui.alerts.creatingCopy":"Copying project…","gui.alerts.creatingRemix":"Remixing project…","gui.alerts.creatingError":"Ezin izan da proiektua sortu. Saiatu berriro!","gui.alerts.savingError":"Ezin izan da proiektua gorde.","gui.alerts.savesuccess":"Proiektua gorde da.","gui.alerts.saving":"Proiektua gordetzen...","gui.alerts.cloudInfo":"Please note, cloud variables only support numbers, not letters or symbols. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Learn more.","gui.alerts.importing":"Inportatzen...","gui.defaultProject.variable":"nire aldagaia","gui.extension.music.name":"Musika","gui.extension.music.description":"Jo musika tresnak eta danborrak.","gui.extension.pen.name":"Arkatza","gui.extension.pen.description":"Marraztu zure pertsonaiaz.","gui.extension.videosensing.name":"Bideo-sentsorea","gui.extension.videosensing.description":"Atzeman mugimendua kameraren bidez","gui.extension.text2speech.name":"Testua irakurri","gui.extension.text2speech.description":"Eman hitza zure proiektuei","gui.extension.translate.name":"Itzuli","gui.extension.translate.description":"Itzuli testua hainbat hizkuntzatara","gui.extension.makeymakey.description":"Egin edozer tekla batekin.","gui.extension.microbit.description":"Konektatu zure proiektuak munduarekin.","gui.extension.microbit.connectingMessage":"Konektatzen","gui.extension.ev3.description":"Eraiki robot interaktiboak eta gauza gehiago.","gui.extension.ev3.connectingMessage":"Konektatzen. Egiaztatu zure EV3ko PINa 1234 gisa ezarrita dagoela.","gui.extension.boost.description":"Bring robotic creations to life.","gui.extension.boost.connectingMessage":"Konektatzen","gui.extension.wedo2.description":"Eraiki motorra eta sentsoreen bidez.","gui.extension.wedo2.connectingMessage":"Konektatzen","gui.extension.gdxfor.description":"Sense push, pull, motion, and spin.","gui.extension.gdxfor.connectingMessage":"Konektatzen","gui.libraryTags.all":"Guztiak","gui.libraryTags.animals":"Animaliak","gui.libraryTags.dance":"Dantza","gui.libraryTags.effects":"Efektuak","gui.libraryTags.fantasy":"Fantasia","gui.libraryTags.fashion":"Moda","gui.libraryTags.food":"Janaria","gui.libraryTags.indoors":"Barnealdeak","gui.libraryTags.loops":"Begiztak","gui.libraryTags.music":"Musika","gui.libraryTags.notes":"Notak","gui.libraryTags.outdoors":"Kanpoaldeak","gui.libraryTags.patterns":"Patroiak","gui.libraryTags.people":"Jendea","gui.libraryTags.percussion":"Perkusioa","gui.libraryTags.space":"Espazioa","gui.libraryTags.sports":"Kirolak","gui.libraryTags.underwater":"Itsaspean","gui.libraryTags.voice":"Ahotsa","gui.libraryTags.wacky":"Zoroa","gui.libraryTags.animation":"Animazioa","gui.libraryTags.art":"Artea","gui.libraryTags.games":"Jolasak","gui.libraryTags.stories":"Istorioak","gui.libraryTags.letters":"Hizkiak","gui.opcodeLabels.direction":"norabidea","gui.opcodeLabels.xposition":"x kokapena","gui.opcodeLabels.yposition":"y kokapena","gui.opcodeLabels.size":"tamaina","gui.opcodeLabels.costumename":"tankeraren izena","gui.opcodeLabels.costumenumber":"pertsonaia zenbakia","gui.opcodeLabels.backdropname":"atzeko oihalaren izena","gui.opcodeLabels.backdropnumber":"atzeko oihal zenbakia","gui.opcodeLabels.volume":"bolumena","gui.opcodeLabels.tempo":"tempoa","gui.opcodeLabels.answer":"erantzuna","gui.opcodeLabels.loudness":"ozentasuna","gui.opcodeLabels.username":"erabiltzaile-izena","gui.opcodeLabels.year":"urtea","gui.opcodeLabels.month":"hilabetea","gui.opcodeLabels.date":"data","gui.opcodeLabels.dayofweek":"asteko eguna","gui.opcodeLabels.hour":"ordua","gui.opcodeLabels.minute":"minutua","gui.opcodeLabels.second":"segundoa","gui.opcodeLabels.timer":"kronometroa","gui.sharedMessages.backdrop":"atzeko oihala{index}","gui.sharedMessages.costume":"tankera{index}","gui.sharedMessages.sprite":"Personaia{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Replace contents of the current project?","gui.sharedMessages.loadFromComputerTitle":"Kargatu zure ordenagailutik","boost.color.any":"any color","boost.color.black":"black","boost.color.blue":"blue","boost.color.green":"green","boost.color.red":"red","boost.color.white":"white","boost.color.yellow":"yellow","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] position","boost.getTiltAngle":"tilt angle [TILT_DIRECTION]","boost.motorDirection.backward":"that way","boost.motorDirection.forward":"this way","boost.motorDirection.reverse":"reverse","boost.motorOff":"turn motor [MOTOR_ID] off","boost.motorOn":"turn motor [MOTOR_ID] on","boost.motorOnFor":"turn motor [MOTOR_ID] for [DURATION] seconds","boost.motorOnForRotation":"turn motor [MOTOR_ID] for [ROTATION] rotations","boost.seeingColor":"seeing [COLOR] brick?","boost.setLightHue":"set light color to [HUE]","boost.setMotorDirection":"set motor [MOTOR_ID] direction [MOTOR_DIRECTION]","boost.setMotorPower":"set motor [MOTOR_ID] speed to [POWER] %","boost.tiltDirection.any":"any","boost.tiltDirection.down":"down","boost.tiltDirection.left":"left","boost.tiltDirection.right":"right","boost.tiltDirection.up":"up","boost.whenColor":"when [COLOR] brick seen","boost.whenTilted":"when tilted [TILT_DIRECTION_ANY]","ev3.beepNote":"jo [NOTE] nota [TIME] segundoz","ev3.buttonPressed":" [PORT] botoia sakatuta dago?","ev3.getBrightness":"distira","ev3.getDistance":"distantzia","ev3.getMotorPosition":" [PORT] motorraren kokapena","ev3.motorSetPower":"ezarri [PORT] motorra % [POWER] potentzian","ev3.motorTurnClockwise":"biratu [PORT] motorra norabide honetan [TIME] segundoz","ev3.motorTurnCounterClockwise":"biratu [PORT] motorra norabide horretan [TIME] segundoz","ev3.whenBrightnessLessThan":"distira < [DISTANCE] denean","ev3.whenButtonPressed":" [PORT] botoia sakatzean","ev3.whenDistanceLessThan":"distantzia < [DISTANCE] denean","gdxfor.getAcceleration":"acceleration [DIRECTION]","gdxfor.getForce":"force","gdxfor.getSpin":"spin speed [DIRECTION]","gdxfor.getTilt":"tilt angle [TILT]","gdxfor.isFreeFalling":"falling?","gdxfor.isTilted":"tilted [TILT]?","gdxfor.pulled":"pulled","gdxfor.pushed":"pushed","gdxfor.shaken":"shaken","gdxfor.startedFalling":"started falling","gdxfor.tiltDirectionMenu.any":"any","gdxfor.tiltDirectionMenu.back":"back","gdxfor.tiltDirectionMenu.front":"front","gdxfor.tiltDirectionMenu.left":"left","gdxfor.tiltDirectionMenu.right":"right","gdxfor.turnedFaceDown":"turned face down","gdxfor.turnedFaceUp":"turned face up","gdxfor.whenForcePushedOrPulled":"when force sensor [PUSH_PULL]","gdxfor.whenGesture":"when [GESTURE]","gdxfor.whenTilted":"when tilted [TILT]","makeymakey.downArrow":"behera gezia","makeymakey.downArrowShort":"behera","makeymakey.leftArrow":"ezkerrera gezia","makeymakey.leftArrowShort":"ezkerra","makeymakey.rightArrow":"eskuinera gezia","makeymakey.rightArrowShort":"eskuina","makeymakey.spaceKey":"zuriunea","makeymakey.upArrow":"gora gezia","makeymakey.upArrowShort":"gora","makeymakey.whenKeyPressed":"when [KEY] key pressed","makeymakey.whenKeysPressedInOrder":"when [SEQUENCE] pressed in order","microbit.buttonsMenu.any":"edozein","microbit.clearDisplay":"garbitu pantaila","microbit.defaultTextToDisplay":"Kaixo!","microbit.displaySymbol":"bistaratu [MATRIX]","microbit.displayText":"bistaratu [TEXT] testua","microbit.gesturesMenu.jumped":"salto egina","microbit.gesturesMenu.moved":"mugitua","microbit.gesturesMenu.shaken":"astindua","microbit.isButtonPressed":"[BTN] botoia sakatuta dago?","microbit.isTilted":" [DIRECTION]-ra okertuta dago?","microbit.pinStateMenu.off":"itzalita","microbit.pinStateMenu.on":"piztuta","microbit.tiltAngle":"okertu angelua [DIRECTION]","microbit.tiltDirectionMenu.any":"edozein","microbit.tiltDirectionMenu.back":"atzealdea","microbit.tiltDirectionMenu.front":"aurrealdea","microbit.tiltDirectionMenu.left":"ezkerra","microbit.tiltDirectionMenu.right":"eskuina","microbit.whenButtonPressed":"[BTN] botoia sakatzean","microbit.whenGesture":"[GESTURE] antzematean","microbit.whenPinConnected":"[PIN] pina konektatuta dagoenean","microbit.whenTilted":" [DIRECTION]-ra okertuta dagoenean","music.categoryName":"Musika","music.changeTempo":"aldatu tempoa [TEMPO] unitate","music.drumBass":"(2) Dunbala","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Kabasa","music.drumClaves":"(9) Klabeak","music.drumClosedHiHat":"(6) Charleston txindata itxiak","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Zintzarria","music.drumCrashCymbal":"(4) Txindata","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Txaloa","music.drumOpenHiHat":"(5) Charleston txindata irekiak","music.drumSideStick":"(3) Albo kolpea","music.drumSnare":"(1) Kaxa danborra","music.drumTambourine":"(7) Panderoa","music.drumTriangle":"(12) Triangelua","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Egur blokea","music.getTempo":"tempoa","music.instrumentBass":"(6) Baxua","music.instrumentBassoon":"(14) Fagota","music.instrumentCello":"(8) Txeloa","music.instrumentChoir":"(15) Korua","music.instrumentClarinet":"(10) Klarinetea","music.instrumentElectricGuitar":"(5) Gitarra elektrikoa","music.instrumentElectricPiano":"(2) Piano elektrikoa","music.instrumentFlute":"(12) Txirula","music.instrumentGuitar":"(4) Gitarra","music.instrumentMarimba":"(19) Marinba","music.instrumentMusicBox":"(17) Musika kaxa","music.instrumentOrgan":"(3) Organoa","music.instrumentPiano":"(1) Pianoa","music.instrumentPizzicato":"(7) Pizzikatoa","music.instrumentSaxophone":"(11) Saxofoia","music.instrumentSteelDrum":"(18) Altzairuzko danborra","music.instrumentSynthLead":"(20) Synth Lead","music.instrumentSynthPad":"(21) Synth Pad","music.instrumentTrombone":"(9) Tronboia","music.instrumentVibraphone":"(16) Bibrafonoa","music.instrumentWoodenFlute":"(13) Zurezko txirula","music.midiPlayDrumForBeats":"play drum [DRUM] for [BEATS] beats","music.midiSetInstrument":"ezarri tresna: [INSTRUMENT]","music.playDrumForBeats":"jo [DRUM]danborrean [BEATS] pultsuz","music.playNoteForBeats":"jo [NOTE] nota [BEATS] pultsuz","music.restForBeats":"isilunea [BEATS] pultsuz","music.setInstrument":"ezarri [INSTRUMENT] tresna","music.setTempo":"ezarri [TEMPO] tempoa","pen.categoryName":"Arkatza","pen.changeColorParam":"aldatu arkatzaren [COLOR_PARAM][VALUE] unitate","pen.changeHue":"aldatu arkatzaren kolorea [HUE] tonu","pen.changeShade":"aldatu arkatzaren itzala [SHADE] unitate","pen.changeSize":"aldatu arkatzaren tamaina [SIZE] unitate","pen.clear":"ezabatu guztia","pen.colorMenu.brightness":"distira","pen.colorMenu.color":"kolorea","pen.colorMenu.saturation":"asetasuna","pen.colorMenu.transparency":"gardentasuna","pen.penDown":"jaitsi arkatza ","pen.penUp":"igo arkatza","pen.setColor":"ezarri arkatzaren kolorea: [COLOR]","pen.setColorParam":"ezarri arkatzaren [COLOR_PARAM]: [VALUE]","pen.setHue":"ezarri arkatzaren kolorea: [HUE]","pen.setShade":"ezarri arkatzaren itzala: [SHADE]","pen.setSize":"ezarri arkatzaren tamaina: [SIZE]","pen.stamp":"zigilatu","text2speech.alto":"altua","text2speech.categoryName":"Text to Speech","text2speech.defaultTextToSpeak":"hello","text2speech.giant":"erraldoia","text2speech.kitten":"katutxoa","text2speech.setLanguageBlock":"ezarri hizkuntza: [LANGUAGE]","text2speech.setVoiceBlock":"ezarri ahotsa: [VOICE]","text2speech.speakAndWaitBlock":"esan [WORDS]","text2speech.squeak":"kirrinka","text2speech.tenor":"tenorea","translate.categoryName":"Itzuli","translate.defaultTextToTranslate":"kaixo","translate.translateBlock":"itzuli [WORDS] [LANGUAGE]-ra","translate.viewerLanguage":"hizkuntza","videoSensing.categoryName":"Bideo-sentsorea","videoSensing.direction":"norabidea","videoSensing.motion":"mugimendua","videoSensing.off":"itzali","videoSensing.on":"piztu","videoSensing.onFlipped":"piztu alderantziz","videoSensing.setVideoTransparency":"ezarri bideo gardentasuna: [TRANSPARENCY]","videoSensing.sprite":"pertsonaia","videoSensing.stage":"eszena","videoSensing.videoOn":"bideo- [ATTRIBUTE] hemen: [SUBJECT]","videoSensing.videoToggle":" [VIDEO_STATE] bideoa","videoSensing.whenMotionGreaterThan":"bideo-mugimendua > [REFERENCE] denean","wedo2.getDistance":"distantzia","wedo2.getTiltAngle":"inklinazio angelua [TILT_DIRECTION]","wedo2.isTilted":"[TILT_DIRECTION_ANY] okertuta?","wedo2.motorDirection.backward":"norabide horretan","wedo2.motorDirection.forward":"norabide honetan","wedo2.motorDirection.reverse":"alderantzikatu","wedo2.motorId.a":"A motorra","wedo2.motorId.all":"motor guztiak","wedo2.motorId.b":"B motorra","wedo2.motorId.default":"motorra","wedo2.motorOff":"itzali [MOTOR_ID]","wedo2.motorOn":"piztu [MOTOR_ID] ","wedo2.motorOnFor":"piztu [MOTOR_ID] [DURATION] segundoz","wedo2.playNoteFor":"jo [NOTE] nota [DURATION] segundoz","wedo2.setLightHue":"ezarri argiaren kolorea: [HUE]","wedo2.setMotorDirection":"ezarri [MOTOR_ID] norabidea: [MOTOR_DIRECTION]","wedo2.startMotorPower":"ezarri [MOTOR_ID] potentzia: [POWER]","wedo2.tiltDirection.any":"edozein","wedo2.tiltDirection.down":"behera","wedo2.tiltDirection.left":"ezkerra","wedo2.tiltDirection.right":"eskuina","wedo2.tiltDirection.up":"gora","wedo2.whenDistance":"distantzia [OP] [REFERENCE] denean","wedo2.whenTilted":"okertasuna [TILT_DIRECTION_ANY] denean","paint.paintEditor.hue":"Kolorea","paint.paintEditor.saturation":"Asetasuna","paint.paintEditor.brightness":"Distira","paint.paintEditor.costume":"Tankera","paint.paintEditor.group":"Taldekatu","paint.paintEditor.ungroup":"Desegin taldea","paint.paintEditor.undo":"Desegin","paint.paintEditor.redo":"Berregin","paint.paintEditor.forward":"Aurrealderantz","paint.paintEditor.backward":"Atzealderantz","paint.paintEditor.front":"Aurrealdera","paint.paintEditor.back":"Atzealdera","paint.paintEditor.more":"Gehiago","paint.modeTools.brushSize":"Tamaina","paint.modeTools.eraserSize":"Ezabatzailearen tamaina","paint.modeTools.copy":"Kopiatu","paint.modeTools.paste":"Itsatsi","paint.modeTools.delete":"Ezabatu","paint.modeTools.curved":"Kurbatua","paint.modeTools.pointed":"Zorrotza","paint.modeTools.thickness":"Lodiera","paint.modeTools.flipHorizontal":"Islatu horizontalki","paint.modeTools.flipVertical":"Islatu bertikalki","paint.modeTools.filled":"Betea","paint.modeTools.outlined":"Eskematizatua","paint.paintEditor.bitmap":"Bihurtu Bitmap","paint.paintEditor.vector":"Bihurtu bektore","paint.paintEditor.fill":"Bete","paint.paintEditor.stroke":"Eskema","paint.brushMode.brush":"Pintzela","paint.eraserMode.eraser":"Ezabatzailea","paint.fillMode.fill":"Bete","paint.lineMode.line":"Marra","paint.ovalMode.oval":"Zirkuloa","paint.rectMode.rect":"Laukizuzena","paint.reshapeMode.reshape":"Aldatu forma","paint.roundedRectMode.roundedRect":"Laukizuzen biribildua","paint.selectMode.select":"Hautatu","paint.textMode.text":"Testua","paint.colorPicker.swap":"Trukatu"},"fa":{"gui.alerts.tryAgain":"دوباره تلاش کنید","gui.alerts.download":"دانلود","gui.connection.reconnect":"اتصال دوباره","gui.backpack.costumeLabel":"حالت","gui.backpack.soundLabel":"صدا","gui.backpack.scriptLabel":"برنامه","gui.backpack.spriteLabel":"شکلک","gui.backpack.header":"کوله پشتی","gui.backpack.errorBackpack":"خطا در بارگیری کوله پشتی","gui.backpack.loadingBackpack":"در حال بارگذاری...","gui.backpack.more":"بیشتر","gui.backpack.emptyBackpack":"کوله پشتی خالی است","gui.unsupportedBrowser.label":"مرورگر پشتیبانی نمی‌شود","gui.cards.all-tutorials":"آموزش‌ها","gui.cards.shrink":"جمع کردن","gui.cards.expand":"باز کردن","gui.cards.close":"بستن","gui.cards.more-things-to-try":"چیز‌های بیشتری را امتحان کنید!","gui.cards.see-more":"بیشتر ببینید","gui.comingSoon.message1":"نگران نباشید، ما داریم روی آن کار می‌کنیم {emoji}","gui.comingSoon.message2":"به زودی...","gui.comingSoon.message3":"ما در حال کار بر روی آن هستیم {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"هیچ دستگاهی پیدا نشد","gui.connection.auto-scanning.prescan":"دستگاه خود را نزدیک نگه دارید، سپس شروع به جستجو کنید.","gui.connection.auto-scanning.pressbutton":"دکمه‌ی روی دستگاه خود را فشار دهید.","gui.connection.auto-scanning.start-search":"شروع جستجو","gui.connection.connecting-searchbutton":"در حال جستجو ...","gui.connection.auto-scanning.try-again":"دوباره تلاش کنید","gui.connection.connected":"متصل شد","gui.connection.disconnect":"قطع","gui.connection.go-to-editor":"برو به ویرایشگر","gui.connection.connecting-cancelbutton":"در حال اتصال","gui.connection.error.errorMessage":"ببخشید، به نظر می‌رسد که یک چیزی اشتباه شده است.","gui.connection.error.tryagainbutton":"دوباره تلاش کنید","gui.connection.error.helpbutton":"راهنما","gui.connection.peripheral-name-label":"نام دستگاه","gui.connection.connect":"اتصال","gui.connection.scanning.lookingforperipherals":"در حال جستجوی دستگاه‌ها","gui.connection.scanning.noPeripheralsFound":"هیچ دستگاهی پیدا نشد","gui.connection.scanning.instructions":"دستگاه خود را از لیست زیر انتخاب کنید.","gui.connection.search":"تازه کردن","gui.connection.unavailable.installscratchlink":"مطمئن شوید که Scratch Link نصب و همچنین اجرا شده است.","gui.connection.unavailable.enablebluetooth":"فعال بودن بلوتوث را بررسی کنید","gui.connection.unavailable.tryagainbutton":"دوباره تلاش کنید","gui.connection.unavailable.helpbutton":"راهنما","gui.controls.go":"برو","gui.controls.stop":"توقف","gui.crashMessage.label":"اوه! به نظر می‌رسد که چیزی اشتباه شده است.","gui.crashMessage.errorNumber":"خطای شما با شناسه‌ی {errorId} وارد شد.","gui.crashMessage.reload":"بارگذاری مجدد","gui.customProcedures.myblockModalTitle":"ایجاد یک قطعه","gui.customProcedures.addAnInputNumberText":"افزودن یک ورودی","gui.customProcedures.numberTextType":"عددی یا متنی","gui.customProcedures.addAnInputBoolean":"افزودن یک ورودی","gui.customProcedures.booleanType":"منطقی","gui.customProcedures.addALabel":"افزودن یک برچسب","gui.customProcedures.runWithoutScreenRefresh":"اجرا بدون تازه سازی صفحه","gui.customProcedures.cancel":"لغو","gui.customProcedures.ok":"تایید","gui.SpriteInfo.direction":"جهت","gui.directionPicker.rotationStyles.allAround":"همه طرف","gui.directionPicker.rotationStyles.leftRight":"چپ/راست","gui.directionPicker.rotationStyles.dontRotate":"گردش ممنوع","gui.gui.addExtension":"اضافه کردن افزونه","gui.gui.codeTab":"کد","gui.gui.backdropsTab":"پس‌زمینه","gui.gui.costumesTab":"حالت‌ها","gui.gui.soundsTab":"صداها","gui.extensionLibrary.comingSoon":"به زودی","gui.extensionLibrary.requires":"مورد نیاز","gui.extensionLibrary.collaboration":"همکاری با","gui.library.filterPlaceholder":"جستجو","gui.library.allTag":"همه","gui.loader.headline":"در حال بارگیری پروژه","gui.loader.creating":"در حال ایجاد پروژه","gui.authorInfo.byUser":"توسط {username}","gui.menuBar.seeProjectPage":"مشاهده صفحه‌‎ی پروژه","gui.menuBar.LanguageSelector":"انتخاب‌گر زبان","gui.menuBar.tutorialsLibrary":"آموزش‌ها","gui.menuBar.restoreSprite":"بازیابی شکلک ","gui.menuBar.restoreSound":"بازیابی صدا","gui.menuBar.restoreCostume":"بازیابی حالت","gui.menuBar.restore":"بازیابی","gui.menuBar.saveNow":"الان ذخیره کن","gui.menuBar.saveAsCopy":"ذخیره به عنوان یک کپی","gui.menuBar.remix":"باز‌ترکیب","gui.menuBar.new":"جدید","gui.menuBar.file":"فایل","gui.menuBar.downloadToComputer":"ذخیره در کامپیوتر شما","gui.menuBar.edit":"ویرایش","gui.menuBar.turboModeOff":"خاموش کردن حالت سریع","gui.menuBar.turboModeOn":"روشن کردن حالت سریع","gui.gui.projectTitlePlaceholder":"اینجا برای نام پروژه است","gui.menuBar.isShared":"به اشتراک گذاشته شده","gui.menuBar.share":"به اشتراک گذاشتن","gui.modal.help":"راهنما","gui.modal.back":"بازگشت","gui.monitor.listMonitor.empty":"(خالی)","gui.monitor.listMonitor.listLength":"طول {length}","gui.monitor.contextMenu.default":"نمایشگر عادی","gui.monitor.contextMenu.large":"نمایشگر بزرگ","gui.monitor.contextMenu.slider":"اسلایدر","gui.monitor.contextMenu.sliderRange":"تغییر محدوده‌ی اسلایدر","gui.monitor.contextMenu.import":"خواندن داده‌ها از فایل","gui.monitor.contextMenu.export":"ذخیره داده‌ها در فایل","gui.monitor.contextMenu.hide":"پنهان شو","gui.playButton.play":"پخش","gui.playButton.stop":"توقف","gui.gui.variableScopeOptionAllSprites":"برای همه‌ی شکلک‌ها","gui.gui.variableScopeOptionSpriteOnly":"فقط برای این شکلک","gui.gui.cloudVariableOption":"متغیر ابری (در سرور ذخیره می‌شود)","gui.gui.variablePromptAllSpritesMessage":"این متغیر در دسترس همه‌ی شکلک‌ها خواهد بود.","gui.gui.listPromptAllSpritesMessage":"این لیست در دسترس همه‌ی شکلک‌ها خواهد بود.","gui.prompt.cancel":"لغو","gui.prompt.ok":"تایید","gui.playbackStep.stopMsg":"توقف","gui.playbackStep.playMsg":"پخش","gui.playbackStep.loadingMsg":"بارگذاری...","gui.playbackStep.saveMsg":"ذخیره","gui.playbackStep.reRecordMsg":"ضبط مجدد","gui.recordModal.title":"ضبط صدا","gui.recordingStep.beginRecord":"با کلیک روی دکمه‌ی زیر ضبط را شروع کنید","gui.recordingStep.permission":"{arrow}برای استفاده از میکروفون شما، به اجازه‌ی شما نیاز داریم","gui.recordingStep.stop":"توقف ضبط","gui.recordingStep.record":"ضبط","gui.sliderModal.min":"کم‌ترین مقدار","gui.sliderModal.max":"بیشترین مقدار","gui.sliderModal.title":"تغییر محدوده‌ی اسلایدر","gui.sliderPrompt.cancel":"لغو","gui.sliderPrompt.ok":"باشه","gui.soundEditor.sound":"صدا","gui.soundEditor.play":"پخش","gui.soundEditor.stop":"توقف","gui.soundEditor.copy":"کپی","gui.soundEditor.paste":"جای‌گذاری","gui.soundEditor.copyToNew":"کپی در صدایی جدید","gui.soundEditor.delete":"حذف","gui.soundEditor.save":"ذخیره","gui.soundEditor.undo":"واگـرد","gui.soundEditor.redo":"باز انجام","gui.soundEditor.faster":"سریع‌تر","gui.soundEditor.slower":"آهسته‌تر","gui.soundEditor.echo":"پژواک","gui.soundEditor.robot":"ربات","gui.soundEditor.louder":"بلند‌تر","gui.soundEditor.softer":"آرام‌تر","gui.soundEditor.reverse":"معکوس","gui.soundEditor.fadeOut":"محو شدن در انتها","gui.soundEditor.fadeIn":"محو شدن در ابتدا","gui.soundEditor.mute":"بی‌صدا","gui.SpriteInfo.spritePlaceholder":"نام","gui.SpriteInfo.sprite":"شکلک","gui.SpriteInfo.show":"نمایش","gui.SpriteInfo.size":"اندازه","gui.spriteSelectorItem.contextMenuDuplicate":"تکثیر","gui.spriteSelectorItem.contextMenuExport":"ذخیره در فایل","gui.spriteSelectorItem.contextMenuDelete":"حذف","gui.spriteSelector.addSpriteFromLibrary":"شکلکی را انتخاب کنید","gui.spriteSelector.addSpriteFromPaint":"نقاشی","gui.spriteSelector.addSpriteFromSurprise":"غافل‌گیر کننده","gui.spriteSelector.addSpriteFromFile":"بارگذاری شکلک","gui.stageHeader.stageSizeLarge":"تغییر به صحنه بزرگ","gui.stageHeader.stageSizeSmall":"تغییر به صحنه کوچک","gui.stageHeader.stageSizeFull":"ورود به نمای تمام صفحه","gui.stageHeader.stageSizeUnFull":"خروج از نمای تمام صفحه","gui.stageHeader.fullscreenControl":"نمای تمام صفحه","gui.spriteSelector.addBackdropFromLibrary":"پس‌زمینه‌ای را انتخاب کنید","gui.stageSelector.addBackdropFromPaint":"نقاشی","gui.stageSelector.addBackdropFromSurprise":"غافل‌گیر کننده","gui.stageSelector.addBackdropFromFile":"بارگذاری پس‌زمینه","gui.stageSelector.stage":"صحنه","gui.stageSelector.backdrops":"پس‌زمینه‌ها","gui.telemetryOptIn.label":"گزارش دادن آمار برای بهبود اسکرچ","gui.telemetryOptIn.body1":"گروه اسکرچ همیشه به دنبال درک بهتر چگونگی استفاده از برنامه اسکرچ در سراسر دنیا، هستند. برای کمک به پشتیبانی از این تلاش، شما می‌توانید به برنامه‌ی اسکرچ اجازه دهید تا به‌طور خودکار،اطلاعات استفاده را به تیم اسکرچ ارسال نماید.","gui.telemetryOptIn.body2":"اطلاعاتی که ما جمع آوری می کنیم شامل انتخاب زبان، استفاده از قطعه‌ها و بعضی رویدادها مانند ذخیره سازی، بارگذاری و آپلود کردن یک پروژه می‌شود. ما هیچ‌گونه اطلاعات شخصی را جمع آوری نمی‌کنیم. لطفاً برای اطلاعات بیشتر {privacyPolicyLink} را مشاهده کنید.","gui.telemetryOptIn.privacyPolicyLink":"حریم خصوصی","gui.telemetryOptIn.optInText":"اطلاعات استفاده من را با تیم اسکرچ به اشتراک بگذارید","gui.telemetryOptIn.optInTooltip":"فعال کردن اندازه گیری از دور","gui.telemetryOptIn.optOutText":"اطلاعات استفاده من را با تیم اسکرچ به اشتراک نگذارید","gui.telemetryOptIn.optOutTooltip":"غیر‌فعال کردن اندازه گیری از دور","gui.telemetryOptIn.settingWasUpdated":"تنظیمات شما به‌روز شد.","gui.telemetryOptIn.buttonClose":"بستن","gui.turboMode.active":"حالت سریع","gui.webglModal.label":"مرورگری که شما استفاده می‌کنید، قابلیت WebGL را پشتیبانی نمی‌کند.","gui.webglModal.webgllink":"قابلیت WebGL پشتیبانی نمی‌شود","gui.costumeLibrary.chooseABackdrop":"پس‌زمینه‌ای را انتخاب کنید","gui.costumeLibrary.chooseACostume":"حالتی را انتخاب کنید","gui.costumeTab.addBackdropFromLibrary":"پس‌زمینه‌ای را انتخاب کنید","gui.costumeTab.addCostumeFromLibrary":"حالتی را انتخاب کنید","gui.costumeTab.addBlankCostume":"نقاشی","gui.costumeTab.addSurpriseCostume":"غافل‌گیر کننده","gui.costumeTab.addFileBackdrop":"آپلود پس‌زمینه","gui.costumeTab.addFileCostume":"بارگذاری حالت","gui.extensionLibrary.chooseAnExtension":"افزونه‌ای را انتخاب کنید","gui.extensionLibrary.extensionUrl":"آدرس اینترنتی افزونه را وارد کنید","gui.monitors.importListColumnPrompt":"کدام ستون باید استفاده شود (1-{numberOfColumns} ) ؟","gui.recordingStep.alertMsg":"نمی‌توان ضبط را شروع کرد","gui.soundLibrary.chooseASound":"صدایی را انتخاب کنید","gui.soundTab.fileUploadSound":"بارگذاری صدا","gui.soundTab.surpriseSound":"غافل‌گیر کننده","gui.soundTab.recordSound":"ضبط","gui.soundTab.addSoundFromLibrary":"صدایی را انتخاب کنید","gui.spriteLibrary.chooseASprite":"شکلکی را انتخاب کنید","gui.tipsLibrary.tutorials":"آموزشی را انتخاب کنید","gui.alerts.createsuccess":"پروژه‌ای جدید ایجاد شد.","gui.alerts.createcopysuccess":"کپی پروژه ذخیره شد.","gui.alerts.createremixsuccess":"پروژه به‌عنوان یک بازترکیب ذخیره شد.","gui.alerts.creating":"در حال ایجاد جدید ...","gui.alerts.creatingCopy":"در حال ایجاد یک کپی از پروژه...","gui.alerts.creatingRemix":"در حال بازترکیب پروژه...","gui.alerts.creatingError":"نتوانستیم پروژه را بسازیم. لطفاً دوباره تلاش کنید!","gui.alerts.savingError":"پروژه ذخیره نشد.","gui.alerts.savesuccess":"پروژه ذخیره شد.","gui.alerts.saving":"در حال ذخیره‌ی پروژه...","gui.alerts.cloudInfo":"لطفاً توجه کنید، متغیرهای ابری فقط از اعداد پشتیبانی می‌کنند و حروف و علائم را پشتیبانی نمی‌کنند. {learnMoreLink} ","gui.alerts.cloudInfoLearnMore":"بیشتر بدانید.","gui.alerts.importing":"درحال وارد کردن...","gui.defaultProject.variable":"متغیر من","gui.extension.music.name":"موسیقی","gui.extension.music.description":"ساز‌ها و طبل‌ها را بنوازید.","gui.extension.pen.name":"قلم","gui.extension.pen.description":"شکلک‌های خودتان را نقاشی کنید.","gui.extension.videosensing.name":"تشخیص ویدئویی","gui.extension.videosensing.description":"حرکتی را با دوربین تشخیص دهید.","gui.extension.text2speech.name":"متن به گفتار","gui.extension.text2speech.description":"پروژه‌های خود را سخن‌گو کنید.","gui.extension.translate.name":"ترجمه","gui.extension.translate.description":"متنی را به زبان‌های مختلف ترجمه کنید.","gui.extension.makeymakey.description":"همه چیز را درون یک کلید قرار دهید.","gui.extension.microbit.description":"پروژه‌تان را به دنیای فیزیکی متصل کنید.","gui.extension.microbit.connectingMessage":"درحال اتصال","gui.extension.ev3.description":"ربات‌های قابل هدایت و ... بسازید.","gui.extension.ev3.connectingMessage":"در حال اتصال. مطمئن شوید که مقدار پین دستگاه EV3 شما به 1234 تنظیم شده است.","gui.extension.boost.description":"به ساخته‌های رباتی زندگی ببخشید.","gui.extension.boost.connectingMessage":"درحال اتصال","gui.extension.wedo2.description":"با موتور‌ها و حسگر‌ها بسازید.","gui.extension.wedo2.connectingMessage":"درحال اتصال","gui.extension.gdxfor.description":"تشخیص فشار، کشش، حرکت و چرخش.","gui.extension.gdxfor.connectingMessage":"درحال اتصال","gui.libraryTags.all":"همه","gui.libraryTags.animals":"حیوانات","gui.libraryTags.dance":"رقص","gui.libraryTags.effects":"جلوه‌ها","gui.libraryTags.fantasy":"خیالی","gui.libraryTags.fashion":"سبک","gui.libraryTags.food":"خوراکی","gui.libraryTags.indoors":"داخل خانه","gui.libraryTags.loops":"تکرار شونده","gui.libraryTags.music":"موسیقی","gui.libraryTags.notes":"نت‌ها","gui.libraryTags.outdoors":"بیرون","gui.libraryTags.patterns":"الگو‌ها","gui.libraryTags.people":"مردم","gui.libraryTags.percussion":"موسیقی ضربی","gui.libraryTags.space":"فضایی","gui.libraryTags.sports":"ورزش‌ها","gui.libraryTags.underwater":"زیر آب","gui.libraryTags.voice":"صدا","gui.libraryTags.wacky":"گیج","gui.libraryTags.animation":"انمیشن","gui.libraryTags.art":"هنری","gui.libraryTags.games":"بازی‌ها","gui.libraryTags.stories":"داستان‌ها","gui.libraryTags.letters":"حروف","gui.opcodeLabels.direction":"جهت","gui.opcodeLabels.xposition":"موقعیت x","gui.opcodeLabels.yposition":"موقعیت y","gui.opcodeLabels.size":"اندازه","gui.opcodeLabels.costumename":"نام حالت","gui.opcodeLabels.costumenumber":"شماره‌ی حالت","gui.opcodeLabels.backdropname":"نام پس‌زمینه","gui.opcodeLabels.backdropnumber":"شماره‌ی پس‌زمینه","gui.opcodeLabels.volume":"بلندی صدا","gui.opcodeLabels.tempo":"سرعت نواختن","gui.opcodeLabels.answer":"پاسخ","gui.opcodeLabels.loudness":"بلندی صدا","gui.opcodeLabels.username":"نام کاربری","gui.opcodeLabels.year":"سال","gui.opcodeLabels.month":"ماه","gui.opcodeLabels.date":"تاریخ","gui.opcodeLabels.dayofweek":"روز هفته","gui.opcodeLabels.hour":"ساعت","gui.opcodeLabels.minute":"دقیقه","gui.opcodeLabels.second":"ثانیه","gui.opcodeLabels.timer":"زمان‌سنج","gui.sharedMessages.backdrop":"پس‌زمینه‌ی {index}","gui.sharedMessages.costume":"حالت {index}","gui.sharedMessages.sprite":"شکلک {index}","gui.sharedMessages.pop":"ترکیدن","gui.sharedMessages.replaceProjectWarning":"محتویات پروژه فعلی جایگزین گردد؟","gui.sharedMessages.loadFromComputerTitle":"بارگذاری از کامپیوتر شما","boost.color.any":"هر رنگی","boost.color.black":"سیاه","boost.color.blue":"آبی","boost.color.green":"سبز","boost.color.red":"قرمز","boost.color.white":"سفید","boost.color.yellow":"زرد","boost.getMotorPosition":" موقعیت [MOTOR_REPORTER_ID] موتور","boost.getTiltAngle":"زاویه‌ی کج شدن [TILT_DIRECTION]","boost.motorDirection.backward":"پادساعتگرد","boost.motorDirection.forward":"ساعتگرد","boost.motorDirection.reverse":"برعکس","boost.motorOff":"موتور [MOTOR_ID] خاموش شود","boost.motorOn":"موتور [MOTOR_ID] روشن شود","boost.motorOnFor":"موتور [MOTOR_ID] به‌ مدت [DURATION] ثانیه بچرخد","boost.motorOnForRotation":"موتور [MOTOR_ID] [ROTATION] دور بچرخد","boost.seeingColor":"قطعه [COLOR] را دید؟","boost.setLightHue":"رنگ [HUE] شود","boost.setMotorDirection":"جهت موتور [MOTOR_ID] [MOTOR_DIRECTION] شود","boost.setMotorPower":"سرعت موتور [MOTOR_ID] % [POWER] شود","boost.tiltDirection.any":"هر سمتی","boost.tiltDirection.down":"پایین","boost.tiltDirection.left":"به سمت چپ","boost.tiltDirection.right":"به سمت راست","boost.tiltDirection.up":"بالا","boost.whenColor":"وقتی قطعه‌ی [COLOR] را دید","boost.whenTilted":"وقتی [TILT_DIRECTION_ANY] کج شد","ev3.beepNote":"نت [NOTE] را به مدت [TIME] ثانیه بزن","ev3.buttonPressed":"دکمه‌ی [PORT] فشرده شده؟","ev3.getBrightness":"روشنایی","ev3.getDistance":"فاصله","ev3.getMotorPosition":"موقعیت موتور [PORT]","ev3.motorSetPower":"قدرت موتور [PORT] % [POWER] شود","ev3.motorTurnClockwise":"موتور [PORT] به مدت [TIME] ثانیه ساعتگرد بچرخد","ev3.motorTurnCounterClockwise":"موتور [PORT] به مدت [TIME] ثانیه پادساعتگرد بچرخد","ev3.whenBrightnessLessThan":"وقتی [DISTANCE] > روشنایی","ev3.whenButtonPressed":"وقتی دکمه‌ی [PORT] فشار داده شد","ev3.whenDistanceLessThan":"وقتی [DISTANCE] > فاصله","gdxfor.getAcceleration":"شتاب [DIRECTION]","gdxfor.getForce":"نیرو","gdxfor.getSpin":"سرعت چرخش [DIRECTION]","gdxfor.getTilt":"زاویه‌ی شیب [TILT]","gdxfor.isFreeFalling":"در حال سقوطه؟","gdxfor.isTilted":"[TILT] کج شده؟","gdxfor.pulled":"کشیده شد","gdxfor.pushed":"فشرده","gdxfor.shaken":"تکان داده شد","gdxfor.startedFalling":"سقوط شروع شد","gdxfor.tiltDirectionMenu.any":"هر سمتی","gdxfor.tiltDirectionMenu.back":"به سمت عقب","gdxfor.tiltDirectionMenu.front":"به سمت جلو","gdxfor.tiltDirectionMenu.left":"به سمت چپ","gdxfor.tiltDirectionMenu.right":"به سمت راست","gdxfor.turnedFaceDown":"رو به پایین شد","gdxfor.turnedFaceUp":"رو به بالا شد","gdxfor.whenForcePushedOrPulled":"وقتی حسگر نیرو [PUSH_PULL]","gdxfor.whenGesture":"وقتی [GESTURE]","gdxfor.whenTilted":"وقتی [TILT] کج شد","makeymakey.downArrow":"جهت پایین","makeymakey.downArrowShort":"پایین","makeymakey.leftArrow":"جهت چپ","makeymakey.leftArrowShort":"چپ","makeymakey.rightArrow":"جهت راست","makeymakey.rightArrowShort":"راست","makeymakey.spaceKey":"فاصله","makeymakey.upArrow":"جهت بالا","makeymakey.upArrowShort":"بالا","makeymakey.whenKeyPressed":"وقتی کلید [KEY] فشرده شد","makeymakey.whenKeysPressedInOrder":"وقتی [SEQUENCE] به ترتیب فشرده شدند","microbit.buttonsMenu.any":"A یا B","microbit.clearDisplay":"پاک کردن صفحه‌ی نمایش","microbit.defaultTextToDisplay":"Salam!","microbit.displaySymbol":"نمایش [MATRIX]","microbit.displayText":"نمایش متن [TEXT]","microbit.gesturesMenu.jumped":"پرید","microbit.gesturesMenu.moved":"حرکت کرد","microbit.gesturesMenu.shaken":"تکان داده شد","microbit.isButtonPressed":"دکمه‌ی [BTN] فشار داده شد؟","microbit.isTilted":"[DIRECTION] کج شد؟","microbit.pinStateMenu.off":"خاموش","microbit.pinStateMenu.on":"روشن","microbit.tiltAngle":"زاویه‌ی شیب [DIRECTION]","microbit.tiltDirectionMenu.any":"هر سمتی","microbit.tiltDirectionMenu.back":"به سمت عقب","microbit.tiltDirectionMenu.front":"به سمت جلو","microbit.tiltDirectionMenu.left":"به سمت چپ","microbit.tiltDirectionMenu.right":"به سمت راست","microbit.whenButtonPressed":"وقتی دکمه [BTN] فشار داده شد","microbit.whenGesture":"وقتی [GESTURE]","microbit.whenPinConnected":"وقتی پین [PIN] وصل شد","microbit.whenTilted":"وقتی [DIRECTION] کج شد","music.categoryName":"موسیقی","music.changeTempo":"تغییر سرعت نواختن به اندازه [TEMPO] تا","music.drumBass":"(2) طبل بزرگ بم","music.drumBongo":"(13) طبل بانگو","music.drumCabasa":"(15) جغجغه‌ی کاباسا","music.drumClaves":"(9) چوب‌های کلیوز","music.drumClosedHiHat":"(6) ضرب دوسنج موازی نزدیک به هم","music.drumConga":"(14) تیمپوی مدل کنگا","music.drumCowbell":"(11) زنگ مدل کبل","music.drumCrashCymbal":"(4) سنج تک پایه دار","music.drumCuica":"(18) طبل مدل کویکا","music.drumGuiro":"(16) جغجغه‌ی چوبی گویرو","music.drumHandClap":"(8) دست زدن","music.drumOpenHiHat":"(5) سنج دوگانه‌ی موازی ضربه‌ای با چوب","music.drumSideStick":"(3) ضربه ی کنار چوب ","music.drumSnare":"(1) طبل کوچک","music.drumTambourine":"(7) دایره زنگی","music.drumTriangle":"(12) زنگ مثلثی","music.drumVibraslap":"(17) ضربه‌ی ارتعاشی","music.drumWoodBlock":"(10) قطعه‌ی چوب ","music.getTempo":"سرعت نواختن","music.instrumentBass":"(6) گیتار بیس","music.instrumentBassoon":"(14) باسون","music.instrumentCello":"(8) ویولن سل","music.instrumentChoir":"(15) گروه کر","music.instrumentClarinet":"(10) کلارینت","music.instrumentElectricGuitar":"(5) گیتار الکتریک","music.instrumentElectricPiano":"(2) پیانو الکتریک","music.instrumentFlute":"(12) فلوت","music.instrumentGuitar":"(4) گیتار","music.instrumentMarimba":"(19) سنتور چوبی آفریقایی مدل ماریمبا","music.instrumentMusicBox":"(17) جعبه‌ی موسیقی","music.instrumentOrgan":"(3) ارگ","music.instrumentPiano":"(1) پیانو","music.instrumentPizzicato":"(7)صدای پیتزیکاتو","music.instrumentSaxophone":"(11) ساکسیفون","music.instrumentSteelDrum":"(18) طبل فولادی","music.instrumentSynthLead":"(20) صدای زیر ساز برقی ","music.instrumentSynthPad":"(21) صدای پایدار ساز برقی","music.instrumentTrombone":"(9) ترومبون","music.instrumentVibraphone":"(16) ویبرافون","music.instrumentWoodenFlute":"(13) فلوت چوبی","music.midiPlayDrumForBeats":"نواختن درامز [DRUM] در مدت [BEATS] ضرب","music.midiSetInstrument":"ساز [INSTRUMENT] شود","music.playDrumForBeats":"نواختن درامز [DRUM] در مدت [BEATS] ضرب","music.playNoteForBeats":"نواختن نت [NOTE] در مدت [BEATS] ضرب","music.restForBeats":" [BEATS] ضرب سکوت کن","music.setInstrument":"ساز [INSTRUMENT] شود","music.setTempo":"سرعت نواختن [TEMPO] شود","pen.categoryName":"قلم","pen.changeColorParam":"تغییر [COLOR_PARAM] قلم به اندازه [VALUE] تا","pen.changeHue":"تغییر رنگ قلم به اندازه [HUE] تا","pen.changeShade":"تغییر سایه قلم به اندازه [SHADE] تا","pen.changeSize":"تغییر ضخامت قلم به اندازه [SIZE] تا","pen.clear":"همه را پاک کن","pen.colorMenu.brightness":"روشنایی","pen.colorMenu.color":"رنگ","pen.colorMenu.saturation":"شدت رنگ","pen.colorMenu.transparency":"شفافیت","pen.penDown":"قلم پایین بیاید","pen.penUp":"قلم بالا برود","pen.setColor":"رنگ قلم [COLOR] شود","pen.setColorParam":"[COLOR_PARAM] [VALUE] شود","pen.setHue":"رنگ قلم [HUE] شود","pen.setShade":"سایه‌ی قلم [SHADE] شود","pen.setSize":"ضخامت قلم [SIZE] شود","pen.stamp":"مُـهـر بزن","text2speech.alto":"زیر","text2speech.categoryName":"متن به گفتار","text2speech.defaultTextToSpeak":"سلام","text2speech.giant":"غول","text2speech.kitten":"بچه گربه‌ای","text2speech.setLanguageBlock":"زبان [LANGUAGE] شود","text2speech.setVoiceBlock":"صدا [VOICE] شود","text2speech.speakAndWaitBlock":"بگو [WORDS]","text2speech.squeak":"کودکانه","text2speech.tenor":"بم","translate.categoryName":"ترجمه","translate.defaultTextToTranslate":"سلام","translate.translateBlock":" ترجمه کن [WORDS] را به [LANGUAGE]","translate.viewerLanguage":"زبان","videoSensing.categoryName":"تشخیص ویدئو","videoSensing.direction":"جهت","videoSensing.motion":"حرکت","videoSensing.off":"خاموش","videoSensing.on":"روشن","videoSensing.onFlipped":"روشن و قرینه","videoSensing.setVideoTransparency":"شفافیت ویدئو [TRANSPARENCY] شود","videoSensing.sprite":"شکلک","videoSensing.stage":"صحنه","videoSensing.videoOn":"[ATTRIBUTE] ویدئو بر روی [SUBJECT]","videoSensing.videoToggle":"تشخیص ویدئویی [VIDEO_STATE] شود","videoSensing.whenMotionGreaterThan":"وقتی [REFERENCE] < حرکت ویدئو","wedo2.getDistance":"فاصله","wedo2.getTiltAngle":"زاویه‌ ی کج شدن [TILT_DIRECTION]","wedo2.isTilted":"[TILT_DIRECTION_ANY] کج شده؟","wedo2.motorDirection.backward":"پادساعتگرد","wedo2.motorDirection.forward":"ساعتگرد","wedo2.motorDirection.reverse":"برعکس","wedo2.motorId.a":"موتور A","wedo2.motorId.all":"همه‌ی موتورها","wedo2.motorId.b":"موتور B","wedo2.motorId.default":"موتور","wedo2.motorOff":"[MOTOR_ID] خاموش شود","wedo2.motorOn":" [MOTOR_ID] روشن شود","wedo2.motorOnFor":"روشن کردن [MOTOR_ID] به مدت [DURATION] ثانیه","wedo2.playNoteFor":"نواختن نت [NOTE] در مدت [DURATION] ثانیه","wedo2.setLightHue":"رنگ نور [HUE] شود","wedo2.setMotorDirection":"جهت [MOTOR_ID] [MOTOR_DIRECTION] شود","wedo2.startMotorPower":"قدرت [MOTOR_ID] [POWER] شود","wedo2.tiltDirection.any":"هر سمتی","wedo2.tiltDirection.down":"پایین","wedo2.tiltDirection.left":"چپ","wedo2.tiltDirection.right":"راست","wedo2.tiltDirection.up":"بالا","wedo2.whenDistance":"وقتی [REFERENCE] [OP] فاصله‌","wedo2.whenTilted":"وقتی به [TILT_DIRECTION_ANY] کج شد","paint.paintEditor.hue":"رنگ","paint.paintEditor.saturation":"شدت رنگ","paint.paintEditor.brightness":"روشنایی","paint.paintEditor.costume":"حالت","paint.paintEditor.group":"گروه","paint.paintEditor.ungroup":"تفکیک","paint.paintEditor.undo":"واگـرد","paint.paintEditor.redo":"باز انجام","paint.paintEditor.forward":"جلوتر","paint.paintEditor.backward":"عقب‌تر","paint.paintEditor.front":"اولین","paint.paintEditor.back":"آخرین","paint.paintEditor.more":"بیشتر","paint.modeTools.brushSize":"اندازه","paint.modeTools.eraserSize":"اندازه‌ی پاک‌ کن","paint.modeTools.copy":"کپی","paint.modeTools.paste":"جای‌گذاری","paint.modeTools.delete":"حذف","paint.modeTools.curved":"خمیده","paint.modeTools.pointed":"تیز","paint.modeTools.thickness":"ضخامت","paint.modeTools.flipHorizontal":"قرینه عمودی","paint.modeTools.flipVertical":"قرینه‌ی افقی","paint.modeTools.filled":"تو پُــر","paint.modeTools.outlined":"تو خالی","paint.paintEditor.bitmap":"تبدیل به بیت‌مپ","paint.paintEditor.vector":"تبدیل به حالت برداری","paint.paintEditor.fill":"رنگ","paint.paintEditor.stroke":"خط دور","paint.brushMode.brush":"قلم‌مو","paint.eraserMode.eraser":"پاک‌ کن","paint.fillMode.fill":"سطل رنگ","paint.lineMode.line":"خط","paint.ovalMode.oval":"دایره","paint.rectMode.rect":"مستطیل","paint.reshapeMode.reshape":"تغییر شکل","paint.roundedRectMode.roundedRect":"مستطیل دور گرد","paint.selectMode.select":"انتخاب","paint.textMode.text":"متن","paint.colorPicker.swap":"جابه‌جا"},"fil":{"gui.alerts.tryAgain":"Subukan Muli","gui.alerts.download":"I-download","gui.connection.reconnect":"Kumonekta Ulit","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"tunog","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Backpack","gui.backpack.errorBackpack":"Nagka-error sa pag-load sa backpack","gui.backpack.loadingBackpack":"Naglo-load...","gui.backpack.more":"Higit pa","gui.backpack.emptyBackpack":"Walang laman ang backpack","gui.unsupportedBrowser.label":"Di suportado ang browser","gui.cards.all-tutorials":"Mga Tutorial","gui.cards.shrink":"Paliitin","gui.cards.expand":"Palakihin","gui.cards.close":"Isara","gui.cards.more-things-to-try":"Maraming masusubukan!","gui.cards.see-more":"Tingnan pa","gui.comingSoon.message1":"Wag kang mag-alala, ginagawa na namin ito{emoji}","gui.comingSoon.message2":"Abangan...","gui.comingSoon.message3":"Ginagawa na namin ito {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Walang nakitang device","gui.connection.auto-scanning.prescan":"Ilapit ang iyong device, tapos simulan ang paghahanap.","gui.connection.auto-scanning.pressbutton":"Pindutin ang button ng iyong device.","gui.connection.auto-scanning.start-search":"Simulan ang Paghahanap","gui.connection.connecting-searchbutton":"Naghahanap...","gui.connection.auto-scanning.try-again":"Subukan muli","gui.connection.connected":"Konektado","gui.connection.disconnect":"Nadiskonekta","gui.connection.go-to-editor":"Pumunta sa Editor","gui.connection.connecting-cancelbutton":"Kumokonekta...","gui.connection.error.errorMessage":"Hala, mukha yatang may mali.","gui.connection.error.tryagainbutton":"Subukan muli","gui.connection.error.helpbutton":"Tulong","gui.connection.peripheral-name-label":"Pangalan ng device","gui.connection.connect":"Ikonekta","gui.connection.scanning.lookingforperipherals":"Naghahanap ng mga device","gui.connection.scanning.noPeripheralsFound":"Walang nahanap na device","gui.connection.scanning.instructions":"Piliin ang iyong device sa listahan sa taas.","gui.connection.search":"I-refresh","gui.connection.unavailable.installscratchlink":"Siguraduhing naka-install at nakabukas ang Scratch Link","gui.connection.unavailable.enablebluetooth":"Siguraduhing nakabukas ang Bluetooth","gui.connection.unavailable.tryagainbutton":"Subukan muli","gui.connection.unavailable.helpbutton":"Tulong","gui.controls.go":"Magsimula","gui.controls.stop":"Itigil","gui.crashMessage.label":"Hala! May mali.","gui.crashMessage.errorNumber":"Nai-log ang iyong error na may id na {errorId}","gui.crashMessage.reload":"I-reload","gui.customProcedures.myblockModalTitle":"Gumawa ng Block","gui.customProcedures.addAnInputNumberText":"Magdagdag ng input","gui.customProcedures.numberTextType":"bilang o teksto","gui.customProcedures.addAnInputBoolean":"Magdagdag ng input","gui.customProcedures.booleanType":"boolean","gui.customProcedures.addALabel":"Magdagdag ng label","gui.customProcedures.runWithoutScreenRefresh":"Patakbuhin nang walang refresh ng screen","gui.customProcedures.cancel":"Ikansela","gui.customProcedures.ok":"Sige","gui.SpriteInfo.direction":"Direksyon","gui.directionPicker.rotationStyles.allAround":"Lahatan","gui.directionPicker.rotationStyles.leftRight":"Kaliwa/Kanan","gui.directionPicker.rotationStyles.dontRotate":"Wag paikutin","gui.gui.addExtension":"Magdagdag ng Extension","gui.gui.codeTab":"Code","gui.gui.backdropsTab":"Mga Likod","gui.gui.costumesTab":"Mga Costume","gui.gui.soundsTab":"Mga Tunog","gui.extensionLibrary.comingSoon":"Abangan","gui.extensionLibrary.requires":"Kailangan ng","gui.extensionLibrary.collaboration":"Collaboration kasama ang","gui.library.filterPlaceholder":"Maghanap","gui.library.allTag":"Lahat","gui.loader.headline":"Nilo-load ang Proyekto","gui.loader.creating":"Ginagawa ang Proyekto","gui.authorInfo.byUser":"ni {username}","gui.menuBar.seeProjectPage":"Tingnan ang Pahina ng Proyekto","gui.menuBar.LanguageSelector":"tagapili ng wika","gui.menuBar.tutorialsLibrary":"Mga Tutorial","gui.menuBar.restoreSprite":"I-restore ang Sprite","gui.menuBar.restoreSound":"I-restore ang Tunog","gui.menuBar.restoreCostume":"I-restore ang Costume","gui.menuBar.restore":"I-restore","gui.menuBar.saveNow":"I-save na","gui.menuBar.saveAsCopy":"I-save bilang kopya","gui.menuBar.remix":"I-remix","gui.menuBar.new":"Bago","gui.menuBar.file":"File","gui.menuBar.downloadToComputer":"I-save sa kompyuter mo","gui.menuBar.edit":"Baguhin","gui.menuBar.turboModeOff":"Isara ang Turbo Mode","gui.menuBar.turboModeOn":"Buksan ang Turbo Mode","gui.gui.projectTitlePlaceholder":"Pangalan ng proyekto dito","gui.menuBar.isShared":"Ibinahagi","gui.menuBar.share":"Ibahagi","gui.modal.help":"Tulong","gui.modal.back":"Balik","gui.monitor.listMonitor.empty":"(walang laman)","gui.monitor.listMonitor.listLength":"haba {length}","gui.monitor.contextMenu.default":"normal na readout","gui.monitor.contextMenu.large":"malaking readout","gui.monitor.contextMenu.slider":"slider","gui.monitor.contextMenu.sliderRange":"palitan ang slider range","gui.monitor.contextMenu.import":"i-import","gui.monitor.contextMenu.export":"i-export","gui.monitor.contextMenu.hide":"itago","gui.playButton.play":"I-play","gui.playButton.stop":"Itigil","gui.gui.variableScopeOptionAllSprites":"Para sa lahat ng sprite","gui.gui.variableScopeOptionSpriteOnly":"Para lang sa sprite na ito","gui.gui.cloudVariableOption":"Variable sa cloud (nakalagay sa server)","gui.gui.variablePromptAllSpritesMessage":"Magagamit ang variable na ito sa lahat ng sprite.","gui.gui.listPromptAllSpritesMessage":"Magagamit ang listahan na ito ng lahat ng sprite.","gui.prompt.cancel":"Ikansela","gui.prompt.ok":"Sige","gui.playbackStep.stopMsg":"Itigil","gui.playbackStep.playMsg":"I-play","gui.playbackStep.loadingMsg":"Naglo-load...","gui.playbackStep.saveMsg":"I-save","gui.playbackStep.reRecordMsg":"Muling mag-record","gui.recordModal.title":"Mag-record ng Tunog","gui.recordingStep.beginRecord":"Pindutin ang button sa baba para makapag-record","gui.recordingStep.permission":"{arrow} Kailangan namin ng permiso mo para magamit ang iyong mikropono","gui.recordingStep.stop":"Itigil ang pag-record","gui.recordingStep.record":"Mag-record","gui.sliderModal.min":"Pinakamababa","gui.sliderModal.max":"Pinakamataas","gui.sliderModal.title":"Baguhin ang slider range","gui.sliderPrompt.cancel":"Kanselahin","gui.sliderPrompt.ok":"Sige","gui.soundEditor.sound":"Tunog","gui.soundEditor.play":"I-play","gui.soundEditor.stop":"Itigil","gui.soundEditor.copy":"Kopyahin","gui.soundEditor.paste":"I-paste","gui.soundEditor.copyToNew":"Kopyahin sa Bago","gui.soundEditor.delete":"Burahin","gui.soundEditor.save":"I-save","gui.soundEditor.undo":"I-undo","gui.soundEditor.redo":"I-redo","gui.soundEditor.faster":"Pabilisin","gui.soundEditor.slower":"Pabagalin","gui.soundEditor.echo":"Alingawngaw","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Palakasin","gui.soundEditor.softer":"Pahinain","gui.soundEditor.reverse":"Baligtarin","gui.soundEditor.fadeOut":"I-fadeout","gui.soundEditor.fadeIn":"I-fadein","gui.soundEditor.mute":"I-mute","gui.SpriteInfo.spritePlaceholder":"Pangalan","gui.SpriteInfo.sprite":"Sprite","gui.SpriteInfo.show":"Ipakita","gui.SpriteInfo.size":"Laki","gui.spriteSelectorItem.contextMenuDuplicate":"doblehin","gui.spriteSelectorItem.contextMenuExport":"i-export","gui.spriteSelectorItem.contextMenuDelete":"burahin","gui.spriteSelector.addSpriteFromLibrary":"Pumili ng Sprite","gui.spriteSelector.addSpriteFromPaint":"Pinta","gui.spriteSelector.addSpriteFromSurprise":"Sorpresa","gui.spriteSelector.addSpriteFromFile":"Mag-upload ng Sprite","gui.stageHeader.stageSizeLarge":"Lumipat sa malaking stage","gui.stageHeader.stageSizeSmall":"Lumipat sa maliit na stage","gui.stageHeader.stageSizeFull":"Pumasok sa fullscreen","gui.stageHeader.stageSizeUnFull":"Lumabas sa fullscreen","gui.stageHeader.fullscreenControl":"Kontrol sa fullscreen","gui.spriteSelector.addBackdropFromLibrary":"Pumili ng Likod","gui.stageSelector.addBackdropFromPaint":"Pinta","gui.stageSelector.addBackdropFromSurprise":"Sorpresa","gui.stageSelector.addBackdropFromFile":"Mag-upload ng Likod","gui.stageSelector.stage":"Stage","gui.stageSelector.backdrops":"Mga Likod","gui.telemetryOptIn.label":"Mag-ulat ng mga statistics para mapaganda pa ang Scratch","gui.telemetryOptIn.body1":"Palaging inaalam po ng Scratch Team kung papaano ginagamit ang Scratch sa iba\'t ibang panig ng mundo. Para makatulong, pwede niyo pong payagan ang Scrath na kusang magpadala ng impormasyon sa paggamit sa Scratch Team.","gui.telemetryOptIn.body2":"Ang mga impormasyon na kinokolekta po namin ay ang wikang pinili, paggamit sa mga block, at ilang mga pangyayari tulad ng pag-save, pag-load, at pag-upload sa isang proyekto. HINDI PO NAMIN kokolektahin ang kahit anong personal na impormasyon. Pakitingnan po ang aming {privacyPolicyLink} para sa karagdagang impormasyon.","gui.telemetryOptIn.privacyPolicyLink":"Patakaran sa Pagkapribado","gui.telemetryOptIn.optInText":"Ibahagi ang data ng paggamit ko sa Scratch Team","gui.telemetryOptIn.optInTooltip":"Buksan ang telemetry","gui.telemetryOptIn.optOutText":"Wag ibahagi ang data ng paggamit ko sa Scratch Team","gui.telemetryOptIn.optOutTooltip":"Isara ang telemetry","gui.telemetryOptIn.settingWasUpdated":"Na-update na ang pagsasaayos mo.","gui.telemetryOptIn.buttonClose":"Isara","gui.turboMode.active":"Turbo Mode","gui.webglModal.label":"Di suportado ng browser mo ang WebGL","gui.webglModal.webgllink":"di suportado ang WebGL","gui.costumeLibrary.chooseABackdrop":"Pumili ng Likod","gui.costumeLibrary.chooseACostume":"Pumili ng Costume","gui.costumeTab.addBackdropFromLibrary":"Pumili ng Likod","gui.costumeTab.addCostumeFromLibrary":"Pumili ng Costume","gui.costumeTab.addBlankCostume":"Pinta","gui.costumeTab.addSurpriseCostume":"Sorpresa","gui.costumeTab.addFileBackdrop":"Mag-upload ng Likod","gui.costumeTab.addFileCostume":"Mag-upload ng Costume","gui.extensionLibrary.chooseAnExtension":"Pumili ng Extension","gui.extensionLibrary.extensionUrl":"I-type ang URL ng extension","gui.monitors.importListColumnPrompt":"Anong hanay ang dapat gamitin (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Di masimulan ang pag-record","gui.soundLibrary.chooseASound":"Pumili ng Tunog","gui.soundTab.fileUploadSound":"Mag-upload ng Tunog","gui.soundTab.surpriseSound":"Sorpresa","gui.soundTab.recordSound":"Mag-record","gui.soundTab.addSoundFromLibrary":"Pumili ng Tunog","gui.spriteLibrary.chooseASprite":"Pumili ng Sprite","gui.tipsLibrary.tutorials":"Pumili ng Tutorial","gui.alerts.createsuccess":"Nagawa na ang bagong proyeko.","gui.alerts.createcopysuccess":"Nai-save na ang proyekto bilang kopya.","gui.alerts.createremixsuccess":"Nai-save na ang proyekto bilang remix.","gui.alerts.creating":"Gumagawa ng bago...","gui.alerts.creatingCopy":"Kinokopya ang proyekto...","gui.alerts.creatingRemix":"Rine-remix ang proyeko...","gui.alerts.creatingError":"Di magawa ang proyekto. Pakisubukan muli!","gui.alerts.savingError":"Di mai-save ang proyekto.","gui.alerts.savesuccess":"Nai-save na ang proyekto.","gui.alerts.saving":"Sine-save ang proyekto...","gui.alerts.cloudInfo":"Tandaan, sinusuportahan lang ng mga variable sa cloud ang mga bilang, hindi letra o simbolo. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Matuto pa.","gui.alerts.importing":"Ini-import...","gui.defaultProject.variable":"variable ko","gui.extension.music.name":"Musika","gui.extension.music.description":"Mag-play ng mga instrumento at tambol.","gui.extension.pen.name":"Panulat","gui.extension.pen.description":"Gumuhit gamit ang mga sprite mo.","gui.extension.videosensing.name":"Video Sensing","gui.extension.videosensing.description":"I-sense ang galaw gamit ang kamera.","gui.extension.text2speech.name":"Text to Speech","gui.extension.text2speech.description":"Pasalitain ang mga proyekto mo.","gui.extension.translate.name":"Magsalin","gui.extension.translate.description":"Isalin ang teksto sa ibang mga wika.","gui.extension.makeymakey.description":"Gawing key ang kahit ano.","gui.extension.microbit.description":"Ikonekta ang mga proyekto mo sa mundo.","gui.extension.microbit.connectingMessage":"Kinokonekta","gui.extension.ev3.description":"Gumawa ng mga interactive na robot at marami pa.","gui.extension.ev3.connectingMessage":"Kinokonekta. Siguraduhing nakatakda ang pin ng EV3 mo sa 1234.","gui.extension.boost.description":"Bigyang-buhay ang mga robot mo.","gui.extension.boost.connectingMessage":"Kinokonekta","gui.extension.wedo2.description":"Gumawa kasama ang mga motor at sensor.","gui.extension.wedo2.connectingMessage":"Kinokonekta","gui.extension.gdxfor.description":"I-sense ang pagtulak, paghila, paggalaw, at pag-ikot.","gui.extension.gdxfor.connectingMessage":"Kinokonekta","gui.libraryTags.all":"Lahat","gui.libraryTags.animals":"Mga Hayop","gui.libraryTags.dance":"Sayaw","gui.libraryTags.effects":"Mga Epekto","gui.libraryTags.fantasy":"Pantasya","gui.libraryTags.fashion":"Fashion","gui.libraryTags.food":"Pagkain","gui.libraryTags.indoors":"Loob","gui.libraryTags.loops":"Mga Loop","gui.libraryTags.music":"Musika","gui.libraryTags.notes":"Mga Nota","gui.libraryTags.outdoors":"Labas","gui.libraryTags.patterns":"Mga Pattern","gui.libraryTags.people":"Mga Tao","gui.libraryTags.percussion":"Percussion","gui.libraryTags.space":"Kalawakan","gui.libraryTags.sports":"Palakasan","gui.libraryTags.underwater":"Katubigan","gui.libraryTags.voice":"Boses","gui.libraryTags.wacky":"Wacky","gui.libraryTags.animation":"Animation","gui.libraryTags.art":"Sining","gui.libraryTags.games":"Mga Laro","gui.libraryTags.stories":"Mga Kuwento","gui.libraryTags.letters":"Mga Letra","gui.opcodeLabels.direction":"direksyon","gui.opcodeLabels.xposition":"posisyong x","gui.opcodeLabels.yposition":"posisyong y","gui.opcodeLabels.size":"laki","gui.opcodeLabels.costumename":"pangalan ng costume","gui.opcodeLabels.costumenumber":"bilang ng costume","gui.opcodeLabels.backdropname":"pangalan ng likod","gui.opcodeLabels.backdropnumber":"bilang ng likod","gui.opcodeLabels.volume":"volume","gui.opcodeLabels.tempo":"bilis","gui.opcodeLabels.answer":"sagot","gui.opcodeLabels.loudness":"lakas","gui.opcodeLabels.username":"username","gui.opcodeLabels.year":"taon","gui.opcodeLabels.month":"buwan","gui.opcodeLabels.date":"petsa","gui.opcodeLabels.dayofweek":"araw ng linggo","gui.opcodeLabels.hour":"oras","gui.opcodeLabels.minute":"minuto","gui.opcodeLabels.second":"segundo","gui.opcodeLabels.timer":"timer","gui.sharedMessages.backdrop":"likod{index}","gui.sharedMessages.costume":"costume{index}","gui.sharedMessages.sprite":"Sprite{index}","gui.sharedMessages.pop":"putok","gui.sharedMessages.replaceProjectWarning":"Palitan ang nilalaman ng kasalukuyang proyekto?","gui.sharedMessages.loadFromComputerTitle":"I-load mula sa kompyuter mo","boost.color.any":"kahit anong kulay","boost.color.black":"itim","boost.color.blue":"bughaw","boost.color.green":"berde","boost.color.red":"pula","boost.color.white":"puti","boost.color.yellow":"dilaw","boost.getMotorPosition":"posisyon ng motor na [MOTOR_REPORTER_ID]","boost.getTiltAngle":"anggulo ng pagtagilid [TILT_DIRECTION]","boost.motorDirection.backward":"papunta doon","boost.motorDirection.forward":"papunta rito","boost.motorDirection.reverse":"pabalik","boost.motorOff":"isara ang motor na [MOTOR_ID]","boost.motorOn":"buksan ang motor na [MOTOR_ID]","boost.motorOnFor":"buksan ang motor na [MOTOR_ID] nang [DURATION] (na) segundo","boost.motorOnForRotation":"buksan ang motor na [MOTOR_ID] nang [ROTATION] (na) ikot","boost.seeingColor":"nakikita ang brick na [COLOR]?","boost.setLightHue":"itakda ang kulay ng ilaw bilang [HUE]","boost.setMotorDirection":"itakda sa direksyong [MOTOR_DIRECTION] ang motor na [MOTOR_ID]","boost.setMotorPower":"itakda sa bilis na [POWER] % ang motor na [MOTOR_ID]","boost.tiltDirection.any":"kahit ano","boost.tiltDirection.down":"baba","boost.tiltDirection.left":"kaliwa","boost.tiltDirection.right":"kanan","boost.tiltDirection.up":"taas","boost.whenColor":"kapag nakita ang brick na [COLOR]","boost.whenTilted":"kapag nakatagilid [TILT_DIRECTION_ANY]","ev3.beepNote":"i-beep ang notang [NOTE] nang [TIME] (na) segundo","ev3.buttonPressed":"pinindot ang button na [PORT]?","ev3.getBrightness":"liwanag","ev3.getDistance":"layo","ev3.getMotorPosition":"posisyon ng motor na [PORT]","ev3.motorSetPower":"itakda ang lakas na [POWER] % sa motor na [PORT]","ev3.motorTurnClockwise":"paikutin dito nang [TIME] (na) seguno ang motor na [PORT]","ev3.motorTurnCounterClockwise":"paikutin doon nang [TIME] (na) segundo ang motor na [PORT]","ev3.whenBrightnessLessThan":"kapag ang liwanag < [DISTANCE]","ev3.whenButtonPressed":"kapag pinindot ang button na [PORT]","ev3.whenDistanceLessThan":"kapag ang layo < [DISTANCE]","gdxfor.getAcceleration":"pagbilis [DIRECTION]","gdxfor.getForce":"pwersa","gdxfor.getSpin":"bilis ng pag-ikot [DIRECTION]","gdxfor.getTilt":"anggulo ng pagtagilid [TILT]","gdxfor.isFreeFalling":"nahuhulog?","gdxfor.isTilted":"nakatagilid [TILT]?","gdxfor.pulled":"hinila","gdxfor.pushed":"tinulak","gdxfor.shaken":"niyugyog","gdxfor.startedFalling":"nagsimulang mahulog","gdxfor.tiltDirectionMenu.any":"kahit ano","gdxfor.tiltDirectionMenu.back":"likod","gdxfor.tiltDirectionMenu.front":"harap","gdxfor.tiltDirectionMenu.left":"kaliwa","gdxfor.tiltDirectionMenu.right":"kanan","gdxfor.turnedFaceDown":"nakaharap pababa","gdxfor.turnedFaceUp":"nakaharap pataas","gdxfor.whenForcePushedOrPulled":"kapag ang sensor ng pwersa ay [PUSH_PULL]","gdxfor.whenGesture":"kapag [GESTURE]","gdxfor.whenTilted":"kapag nakatagilid [TILT]","makeymakey.downArrow":"pababang arrow","makeymakey.downArrowShort":"baba","makeymakey.leftArrow":"kaliwang arrow","makeymakey.leftArrowShort":"kaliwa","makeymakey.rightArrow":"kanang arrow","makeymakey.rightArrowShort":"kanan","makeymakey.spaceKey":"space","makeymakey.upArrow":"pataas na arrow","makeymakey.upArrowShort":"taas","makeymakey.whenKeyPressed":"kapag pinindot ang key na [KEY]","makeymakey.whenKeysPressedInOrder":"kapag diretsong pinindot ang [SEQUENCE]","microbit.buttonsMenu.any":"kahit ano","microbit.clearDisplay":"linisin ang display","microbit.defaultTextToDisplay":"Kamusta","microbit.displaySymbol":"i-display ang [MATRIX]","microbit.displayText":"i-display ang teksto na [TEXT]","microbit.gesturesMenu.jumped":"tumalon","microbit.gesturesMenu.moved":"gumalaw","microbit.gesturesMenu.shaken":"niyugyog","microbit.isButtonPressed":"pinindot ang button na [BTN]?","microbit.isTilted":"nakatagilid [DIRECTION]?","microbit.pinStateMenu.off":"nakasara","microbit.pinStateMenu.on":"nakabukas","microbit.tiltAngle":"anggulo ng pagtagilid [DIRECTION]","microbit.tiltDirectionMenu.any":"kahit ano","microbit.tiltDirectionMenu.back":"likod","microbit.tiltDirectionMenu.front":"harap","microbit.tiltDirectionMenu.left":"kaliwa","microbit.tiltDirectionMenu.right":"kanan","microbit.whenButtonPressed":"kapag pinindot ang button na [BTN]","microbit.whenGesture":"kapag [GESTURE]","microbit.whenPinConnected":"kapag konektado ang pin na [PIN]","microbit.whenTilted":"kapag nakatagilid [DIRECTION]","music.categoryName":"Musika","music.changeTempo":"baguhin ang bilis nang [TEMPO]","music.drumBass":"(2) Bass Drum","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) Closed Hi-Hat","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Cowbell","music.drumCrashCymbal":"(4) Crash Cymbal","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Hand Clap","music.drumOpenHiHat":"(5) Open Hi-Hat","music.drumSideStick":"(3) Side Stick","music.drumSnare":"(1) Snare Drum","music.drumTambourine":"(7) Tambourine","music.drumTriangle":"(12) Triangle","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Wood Block","music.getTempo":"bilis","music.instrumentBass":"(6) Bass","music.instrumentBassoon":"(14) Bassoon","music.instrumentCello":"(8) Cello","music.instrumentChoir":"(15) Choir","music.instrumentClarinet":"(10) Clarinet","music.instrumentElectricGuitar":"(5) Electric Guitar","music.instrumentElectricPiano":"(2) Electric Piano","music.instrumentFlute":"(12) Flute","music.instrumentGuitar":"(4) Guitar","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Music Box","music.instrumentOrgan":"(3) Organ","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxophone","music.instrumentSteelDrum":"(18) Steel Drum","music.instrumentSynthLead":"(20) Synth Lead","music.instrumentSynthPad":"(21) Synth Pad","music.instrumentTrombone":"(9) Trombone","music.instrumentVibraphone":"(16) Vibraphone","music.instrumentWoodenFlute":"(13) Wooden Flute","music.midiPlayDrumForBeats":"i-play ang tambol na [DRUM] nang [BEATS] (na) beat","music.midiSetInstrument":"itakda ang instrumento bilang [INSTRUMENT]","music.playDrumForBeats":"i-play ang tambol na [DRUM] nang [BEATS] (na) beat","music.playNoteForBeats":"i-play ang notang [NOTE] nang [BEATS] (na) beat","music.restForBeats":"magpahinga nang [BEATS] (na) beat","music.setInstrument":"itakda ang instrumento bilang [INSTRUMENT]","music.setTempo":"itakda ang bilis bilang [TEMPO]","pen.categoryName":"Panulat","pen.changeColorParam":"baguhin ang panulat [COLOR_PARAM] ng [VALUE]","pen.changeHue":"baguhin ang kulay ng panulat sa [HUE]","pen.changeShade":"baguhin ang shade ng panulat sa [SHADE]","pen.changeSize":"baguhin ang laki ng panulat nang [SIZE]","pen.clear":"burahin lahat","pen.colorMenu.brightness":"liwanag","pen.colorMenu.color":"kulay","pen.colorMenu.saturation":"tingkad","pen.colorMenu.transparency":"labo","pen.penDown":"ibaba ang panulat","pen.penUp":"itaas ang panulat","pen.setColor":"itakda ang kulay ng panulat sa [COLOR]","pen.setColorParam":"itakda ang panulat [COLOR_PARAM] sa [VALUE]","pen.setHue":"itakda ang kulay ng panulat sa [HUE]","pen.setShade":"itakda ang shade ng panulat sa [SHADE]","pen.setSize":"itakda ang laki ng panulat sa [SIZE]","pen.stamp":"i-stamp","text2speech.alto":"alto","text2speech.categoryName":"Text to Speech","text2speech.defaultTextToSpeak":"kamusta","text2speech.giant":"higante","text2speech.kitten":"kuting","text2speech.setLanguageBlock":"itakda ang wika sa [LANGUAGE]","text2speech.setVoiceBlock":"itakda ang boses sa [VOICE]","text2speech.speakAndWaitBlock":"sabihin ang [WORDS]","text2speech.squeak":"squeak","text2speech.tenor":"tenor","translate.categoryName":"Magsalin","translate.defaultTextToTranslate":"kamusta","translate.translateBlock":"isalin ang [WORDS] sa [LANGUAGE]","translate.viewerLanguage":"wika","videoSensing.categoryName":"Video Sensing","videoSensing.direction":"direksyon","videoSensing.motion":"galaw","videoSensing.off":"sarado","videoSensing.on":"bukas","videoSensing.onFlipped":"pabaligtad","videoSensing.setVideoTransparency":"itakda ang labo ng video sa [TRANSPARENCY]","videoSensing.sprite":"sprite","videoSensing.stage":"stage","videoSensing.videoOn":"[ATTRIBUTE] ng video sa [SUBJECT]","videoSensing.videoToggle":"itakda ang video sa [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"kapag ang paggalaw sa video > [REFERENCE]","wedo2.getDistance":"layo","wedo2.getTiltAngle":"anggulo ng pagtagilid [TILT_DIRECTION]","wedo2.isTilted":"nakatagilid [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"papunta doon","wedo2.motorDirection.forward":"papunta rito","wedo2.motorDirection.reverse":"pabalik","wedo2.motorId.a":"motor A","wedo2.motorId.all":"lahat ng motor","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"patayin ang [MOTOR_ID]","wedo2.motorOn":"buksan ang [MOTOR_ID]","wedo2.motorOnFor":"buksan ang [MOTOR_ID] nang [DURATION] (na) segundo","wedo2.playNoteFor":"i-play ang notang [NOTE] nang [DURATION] (na) segundo","wedo2.setLightHue":"itakda ang kulay ng ilaw bilang [HUE]","wedo2.setMotorDirection":"itakda ang direksyon ng [MOTOR_ID] sa [MOTOR_DIRECTION]","wedo2.startMotorPower":"itakda ang lakas ng [MOTOR_ID] sa [POWER]","wedo2.tiltDirection.any":"kahit ano","wedo2.tiltDirection.down":"baba","wedo2.tiltDirection.left":"kaliwa","wedo2.tiltDirection.right":"kanan","wedo2.tiltDirection.up":"taas","wedo2.whenDistance":"kapag ang layo [OP] [REFERENCE]","wedo2.whenTilted":"kapag nakatagilid [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Kulay","paint.paintEditor.saturation":"Tingkad","paint.paintEditor.brightness":"Liwanag","paint.paintEditor.costume":"Costume","paint.paintEditor.group":"Igrupo","paint.paintEditor.ungroup":"Wag igrupo","paint.paintEditor.undo":"I-undo","paint.paintEditor.redo":"I-redo","paint.paintEditor.forward":"Iharap","paint.paintEditor.backward":"Ilikod","paint.paintEditor.front":"Harap","paint.paintEditor.back":"Balik","paint.paintEditor.more":"Higit pa","paint.modeTools.brushSize":"Laki","paint.modeTools.eraserSize":"Laki ng pambura","paint.modeTools.copy":"Kopyahin","paint.modeTools.paste":"I-paste","paint.modeTools.delete":"Burahin","paint.modeTools.curved":"Nakakurba","paint.modeTools.pointed":"Matulis","paint.modeTools.thickness":"Kapal","paint.modeTools.flipHorizontal":"Baligtarin Pahiga","paint.modeTools.flipVertical":"Baligtarin Patayo","paint.modeTools.filled":"Kinulayan","paint.modeTools.outlined":"Nakabakas","paint.paintEditor.bitmap":"I-convert sa Bitmap","paint.paintEditor.vector":"I-convert sa Vector","paint.paintEditor.fill":"Kulayan","paint.paintEditor.stroke":"Bakas","paint.brushMode.brush":"Brush","paint.eraserMode.eraser":"Pambura","paint.fillMode.fill":"Kulayan","paint.lineMode.line":"Linya","paint.ovalMode.oval":"Bilog","paint.rectMode.rect":"Parihaba","paint.reshapeMode.reshape":"Ibahin ang hugis","paint.roundedRectMode.roundedRect":"Parihabang pabilog","paint.selectMode.select":"Pumili","paint.textMode.text":"Teksto","paint.colorPicker.swap":"Magpalitan"},"fr":{"gui.alerts.tryAgain":"Essayer à nouveau","gui.alerts.download":"Télécharger","gui.connection.reconnect":"Se reconnecter","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"son","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Sac à dos","gui.backpack.errorBackpack":"Erreur lors du chargement du sac à dos","gui.backpack.loadingBackpack":"Chargement...","gui.backpack.more":"Plus","gui.backpack.emptyBackpack":"Le sac à dos est vide","gui.unsupportedBrowser.label":"Navigateur non pris en charge","gui.cards.all-tutorials":"Tutoriels","gui.cards.shrink":"Réduire","gui.cards.expand":"Agrandir","gui.cards.close":"Fermer","gui.cards.more-things-to-try":"Plus de choses à essayer !","gui.cards.see-more":"Voir plus","gui.comingSoon.message1":"Ne t\'inquiète pas, nous y travaillons {emoji}","gui.comingSoon.message2":"Ça arrive bientôt...","gui.comingSoon.message3":"Nous y travaillons {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Aucun appareil trouvé","gui.connection.auto-scanning.prescan":"Assurez-vous d\'avoir votre appareil à proximité puis commencez la recherche.","gui.connection.auto-scanning.pressbutton":"Appuyez sur le bouton de votre appareil.","gui.connection.auto-scanning.start-search":"Commencer la recherche","gui.connection.connecting-searchbutton":"Recherche en cours...","gui.connection.auto-scanning.try-again":"Essayer à nouveau","gui.connection.connected":"Connecté","gui.connection.disconnect":"Se déconnecter","gui.connection.go-to-editor":"Aller à l\'Éditeur","gui.connection.connecting-cancelbutton":"Connexion...","gui.connection.error.errorMessage":"Oups, on dirait que quelque chose s\'est mal passé.","gui.connection.error.tryagainbutton":"Essayer à nouveau","gui.connection.error.helpbutton":"Aide","gui.connection.peripheral-name-label":"Nom de l\'appareil","gui.connection.connect":"Se connecter","gui.connection.scanning.lookingforperipherals":"Recherche d\'appareils en cours","gui.connection.scanning.noPeripheralsFound":"Aucun appareil trouvé","gui.connection.scanning.instructions":"Sélectionnez un appareil dans la liste ci-dessus.","gui.connection.search":"Rafraîchir","gui.connection.unavailable.installscratchlink":"Veillez à ce que vous ayez Scratch Link d\'installé et lancé","gui.connection.unavailable.enablebluetooth":"Vérifiez que le Bluetooth soit activé","gui.connection.unavailable.tryagainbutton":"Essayer à nouveau","gui.connection.unavailable.helpbutton":"Aide","gui.controls.go":"Commencer","gui.controls.stop":"Stop","gui.crashMessage.label":"Oups ! Quelque chose s\'est mal passé.","gui.crashMessage.errorNumber":"Votre erreur a été enregistrée avec l\'identificateur {errorId}.","gui.crashMessage.reload":"Recharger","gui.customProcedures.myblockModalTitle":"Créer un bloc","gui.customProcedures.addAnInputNumberText":"Ajouter une entrée","gui.customProcedures.numberTextType":"nombre ou texte","gui.customProcedures.addAnInputBoolean":"Ajouter une entrée","gui.customProcedures.booleanType":"booléenne","gui.customProcedures.addALabel":"Ajouter une étiquette","gui.customProcedures.runWithoutScreenRefresh":"Exécuter sans rafraîchissement d\'écran","gui.customProcedures.cancel":"Annuler","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Direction","gui.directionPicker.rotationStyles.allAround":"Tout autour","gui.directionPicker.rotationStyles.leftRight":"Gauche/Droite","gui.directionPicker.rotationStyles.dontRotate":"Ne pivote pas","gui.gui.addExtension":"Ajouter une extension","gui.gui.codeTab":"Code","gui.gui.backdropsTab":"Arrière-plans","gui.gui.costumesTab":"Costumes","gui.gui.soundsTab":"Sons","gui.extensionLibrary.comingSoon":"Ça arrive bientôt","gui.extensionLibrary.requires":"Nécessite","gui.extensionLibrary.collaboration":"En collaboration avec ","gui.library.filterPlaceholder":"Rechercher","gui.library.allTag":"Tout","gui.loader.headline":"Chargement du projet","gui.loader.creating":" Création du projet","gui.authorInfo.byUser":"créé par {username}","gui.menuBar.seeProjectPage":"Voir la page du projet","gui.menuBar.LanguageSelector":"sélecteur de langue","gui.menuBar.tutorialsLibrary":"Tutoriels","gui.menuBar.restoreSprite":"Restaurer le sprite","gui.menuBar.restoreSound":"Restaurer le son","gui.menuBar.restoreCostume":"Restaurer le costume","gui.menuBar.restore":"Restaurer","gui.menuBar.saveNow":"Enregistrer maintenant","gui.menuBar.saveAsCopy":"Enregistrer comme copie","gui.menuBar.remix":"Remix","gui.menuBar.new":"Nouveau","gui.menuBar.file":"Fichier","gui.menuBar.downloadToComputer":"Sauvegarder sur votre ordinateur","gui.menuBar.edit":"Modifier","gui.menuBar.turboModeOff":"Désactiver le mode Turbo","gui.menuBar.turboModeOn":"Activer le mode Turbo","gui.gui.projectTitlePlaceholder":"Titre du projet ici","gui.menuBar.isShared":"Partagé","gui.menuBar.share":"Partager","gui.modal.help":"Aide","gui.modal.back":"Retour","gui.monitor.listMonitor.empty":"(vide)","gui.monitor.listMonitor.listLength":"longueur {length}","gui.monitor.contextMenu.default":"lecture normale","gui.monitor.contextMenu.large":"grande lecture","gui.monitor.contextMenu.slider":"barre de défilement","gui.monitor.contextMenu.sliderRange":"modifier les valeurs de la barre de défilement","gui.monitor.contextMenu.import":"importer","gui.monitor.contextMenu.export":"exporter","gui.monitor.contextMenu.hide":"cacher","gui.playButton.play":"Jouer","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"Pour tous les sprites","gui.gui.variableScopeOptionSpriteOnly":"Pour ce sprite uniquement","gui.gui.cloudVariableOption":"Variable serveur (stockée sur le Cloud)","gui.gui.variablePromptAllSpritesMessage":"La variable sera disponible pour tous les sprites.","gui.gui.listPromptAllSpritesMessage":"Cette liste sera disponible pour tous les sprites.","gui.prompt.cancel":"Annuler","gui.prompt.ok":"Ok","gui.playbackStep.stopMsg":"Stop","gui.playbackStep.playMsg":"Jouer","gui.playbackStep.loadingMsg":"Chargement...","gui.playbackStep.saveMsg":"Sauvegarder","gui.playbackStep.reRecordMsg":"Réenregistrer","gui.recordModal.title":"Enregistre un Son","gui.recordingStep.beginRecord":"Commence à enregistrer en cliquant sur le bouton ci-dessous.","gui.recordingStep.permission":"{arrow}Nous avons besoin de votre permission pour utiliser votre micro","gui.recordingStep.stop":"Arrêter l\'enregistrement","gui.recordingStep.record":"Enregistrer","gui.sliderModal.min":"Valeur minimum","gui.sliderModal.max":"Valeur maximum","gui.sliderModal.title":"Modifier les valeurs de la barre de défilement","gui.sliderPrompt.cancel":"Annuler","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Son","gui.soundEditor.play":"Jouer","gui.soundEditor.stop":"Stop","gui.soundEditor.copy":"Copier","gui.soundEditor.paste":"Coller","gui.soundEditor.copyToNew":"Copier dans un nouveau","gui.soundEditor.delete":"Supprimer","gui.soundEditor.save":"Enregistrer","gui.soundEditor.undo":"Restaurer","gui.soundEditor.redo":"Refaire","gui.soundEditor.faster":"Plus vite","gui.soundEditor.slower":"Moins vite","gui.soundEditor.echo":"Echo","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Plus fort","gui.soundEditor.softer":"Plus doux","gui.soundEditor.reverse":"Inverser","gui.soundEditor.fadeOut":"Fondu de fermeture","gui.soundEditor.fadeIn":"Fondu d\'ouverture","gui.soundEditor.mute":"Muet","gui.SpriteInfo.spritePlaceholder":"Nom","gui.SpriteInfo.sprite":"Sprite","gui.SpriteInfo.show":"Afficher","gui.SpriteInfo.size":"Taille","gui.spriteSelectorItem.contextMenuDuplicate":"dupliquer","gui.spriteSelectorItem.contextMenuExport":"exporter","gui.spriteSelectorItem.contextMenuDelete":"supprimer","gui.spriteSelector.addSpriteFromLibrary":"Choisir un sprite","gui.spriteSelector.addSpriteFromPaint":"Peindre","gui.spriteSelector.addSpriteFromSurprise":"Surprise","gui.spriteSelector.addSpriteFromFile":"Importer un sprite","gui.stageHeader.stageSizeLarge":"Passer à la grande scène","gui.stageHeader.stageSizeSmall":"Passer à la petite scène","gui.stageHeader.stageSizeFull":"Entrer en mode plein-écran","gui.stageHeader.stageSizeUnFull":"Sortir du mode plein-écran","gui.stageHeader.fullscreenControl":"Contrôle du plein écran","gui.spriteSelector.addBackdropFromLibrary":"Choisir un arrière-plan","gui.stageSelector.addBackdropFromPaint":"Peindre","gui.stageSelector.addBackdropFromSurprise":"Surprise","gui.stageSelector.addBackdropFromFile":"Importer un arrière-plan","gui.stageSelector.stage":"Scène","gui.stageSelector.backdrops":"Arrière-plans","gui.telemetryOptIn.label":"Envoyer des statistiques pour améliorer Scratch","gui.telemetryOptIn.body1":"L\'Equipe Scratch cherche à toujours mieux comprendre comment Scratch est utilisé dans le monde. Pour nous aider, vous pouvez autoriser Scratch à envoyer automatiquement des rapports d\'utilisation à l\'Equipe Scratch.","gui.telemetryOptIn.body2":"Les informations que nous collectons incluent la langue sélectionnée, la fréquence d\'utilisation des blocs et de certains événements, comme les sauvegardes, l\'ouverture de projet et la publication de projets. Nous ne collectons PAS d\'informations personnelles. Voir notre {privacyPolicyLink} pour plus d\'informations.","gui.telemetryOptIn.privacyPolicyLink":"Politique de confidentialité","gui.telemetryOptIn.optInText":"Partager mes données d\'utilisation avec l\'Équipe Scratch","gui.telemetryOptIn.optInTooltip":"Activer la télémétrie","gui.telemetryOptIn.optOutText":"Ne pas partager mes données d\'utilisation avec l\'Équipe Scratch","gui.telemetryOptIn.optOutTooltip":"Désactiver la télémétrie","gui.telemetryOptIn.settingWasUpdated":"Vos préférences ont été mises à jour.","gui.telemetryOptIn.buttonClose":"Fermer","gui.turboMode.active":"Mode Turbo","gui.webglModal.label":"Votre navigateur ne supporte pas WebGL","gui.webglModal.webgllink":"ne supporte pas WebGL","gui.costumeLibrary.chooseABackdrop":"Choisir un arrière-plan","gui.costumeLibrary.chooseACostume":"Choisir un costume","gui.costumeTab.addBackdropFromLibrary":"Choisir un arrière-plan","gui.costumeTab.addCostumeFromLibrary":"Choisir un costume","gui.costumeTab.addBlankCostume":"Peindre","gui.costumeTab.addSurpriseCostume":"Surprise","gui.costumeTab.addFileBackdrop":"Importer un arrière-plan","gui.costumeTab.addFileCostume":"Importer un Costume","gui.extensionLibrary.chooseAnExtension":"Choisis une extension","gui.extensionLibrary.extensionUrl":"Entrer l\'URL de l\'extension","gui.monitors.importListColumnPrompt":"Quelle colonne doit être utilisée (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Impossible de démarrer l\'enregistrement","gui.soundLibrary.chooseASound":"Choisir un son","gui.soundTab.fileUploadSound":"Importer un son","gui.soundTab.surpriseSound":"Surprise","gui.soundTab.recordSound":"Enregistrer","gui.soundTab.addSoundFromLibrary":"Choisir un son","gui.spriteLibrary.chooseASprite":"Choisir un sprite","gui.tipsLibrary.tutorials":"Choisis un tutoriel","gui.alerts.createsuccess":"Nouveau projet créé.","gui.alerts.createcopysuccess":" Projet enregistré en copie.","gui.alerts.createremixsuccess":" Projet enregistré en remix.","gui.alerts.creating":"Création d\'un nouveau projet...","gui.alerts.creatingCopy":"Copie du projet...","gui.alerts.creatingRemix":"Remixage du projet...","gui.alerts.creatingError":"Impossible de créer le projet. Merci de réessayer !","gui.alerts.savingError":"Le projet n\'a pas pu être sauvegardé.","gui.alerts.savesuccess":"Projet enregistré.","gui.alerts.saving":"Sauvegarde du projet...","gui.alerts.cloudInfo":"Veuillez noter que les variables serveurs ne prennent en charge que les chiffres, pas les lettres ni les symboles. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"En savoir plus.","gui.alerts.importing":"Importation en cours...","gui.defaultProject.variable":"ma variable","gui.extension.music.name":"Musique","gui.extension.music.description":"Jouer des instruments et du tambour.","gui.extension.pen.name":"Stylo","gui.extension.pen.description":"Dessiner avec vos sprites.","gui.extension.videosensing.name":"Détection vidéo","gui.extension.videosensing.description":"Capter du mouvement avec la caméra.","gui.extension.text2speech.name":"Synthèse vocale","gui.extension.text2speech.description":"Fais parler tes projets.","gui.extension.translate.name":"Traduire","gui.extension.translate.description":"Traduire du texte dans différentes langues.","gui.extension.makeymakey.description":"Transforme n\'importe quoi en touche.","gui.extension.microbit.description":"Connecter vos projets avec le monde.","gui.extension.microbit.connectingMessage":"Connexion","gui.extension.ev3.description":"Construire des robots interactifs et plus.","gui.extension.ev3.connectingMessage":"Connexion. Vérifiez que le pin sur votre EV3 est mis sur 1234.","gui.extension.boost.description":"Donner vie à des créations robotiques.","gui.extension.boost.connectingMessage":"Connexion","gui.extension.wedo2.description":"Construire avec des moteurs et des capteurs.","gui.extension.wedo2.connectingMessage":"Connexion","gui.extension.gdxfor.description":"Sentir quand on pousse, tire, bouge et tourne.","gui.extension.gdxfor.connectingMessage":"Connexion","gui.libraryTags.all":"Tout","gui.libraryTags.animals":"Animaux","gui.libraryTags.dance":"Danser","gui.libraryTags.effects":"Effets","gui.libraryTags.fantasy":"Fantaisie","gui.libraryTags.fashion":"Mode","gui.libraryTags.food":"Nourriture","gui.libraryTags.indoors":"Intérieur","gui.libraryTags.loops":"Boucles","gui.libraryTags.music":"Musique","gui.libraryTags.notes":"Notes","gui.libraryTags.outdoors":"Dehors","gui.libraryTags.patterns":"Motifs","gui.libraryTags.people":"Gens","gui.libraryTags.percussion":"Percussion","gui.libraryTags.space":"Espace","gui.libraryTags.sports":"Sports","gui.libraryTags.underwater":"Monde aquatique","gui.libraryTags.voice":"Voix","gui.libraryTags.wacky":"Farfelu","gui.libraryTags.animation":"Animation","gui.libraryTags.art":"Art","gui.libraryTags.games":"Jeux","gui.libraryTags.stories":"Histoires","gui.libraryTags.letters":"Lettres","gui.opcodeLabels.direction":"direction","gui.opcodeLabels.xposition":"abscisse x","gui.opcodeLabels.yposition":"ordonnée y","gui.opcodeLabels.size":"taille","gui.opcodeLabels.costumename":"nom du costume","gui.opcodeLabels.costumenumber":"numéro de costume","gui.opcodeLabels.backdropname":"nom de l\'arrière-plan","gui.opcodeLabels.backdropnumber":"numéro d\'arrière-plan","gui.opcodeLabels.volume":"volume","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"réponse","gui.opcodeLabels.loudness":"volume sonore","gui.opcodeLabels.username":"nom d\'utilisateur","gui.opcodeLabels.year":"année","gui.opcodeLabels.month":"mois","gui.opcodeLabels.date":"date","gui.opcodeLabels.dayofweek":"jour de la semaine","gui.opcodeLabels.hour":"heure","gui.opcodeLabels.minute":"minute","gui.opcodeLabels.second":"seconde","gui.opcodeLabels.timer":"chronomètre","gui.sharedMessages.backdrop":"arrière-plan{index}","gui.sharedMessages.costume":"costume{index}","gui.sharedMessages.sprite":"Sprite{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":" Remplacer le contenu du projet actuel ?","gui.sharedMessages.loadFromComputerTitle":"Importer depuis votre ordinateur","boost.color.any":"de n\'importe quelle couleur","boost.color.black":"noire","boost.color.blue":"bleue","boost.color.green":"verte","boost.color.red":"rouge","boost.color.white":"blanche","boost.color.yellow":"jaune","boost.getMotorPosition":"position du moteur [MOTOR_REPORTER_ID]","boost.getTiltAngle":"angle d\'inclinaison [TILT_DIRECTION]","boost.motorDirection.backward":"par là","boost.motorDirection.forward":"par ici","boost.motorDirection.reverse":"inversée","boost.motorOff":"éteindre le moteur [MOTOR_ID]","boost.motorOn":"allumer le moteur [MOTOR_ID]","boost.motorOnFor":"faire tourner le moteur [MOTOR_ID] pendant [DURATION] secondes","boost.motorOnForRotation":"faire tourner le moteur [MOTOR_ID] de [ROTATION] rotations","boost.seeingColor":"brique [COLOR] vue ?","boost.setLightHue":"mettre la couleur de la lampe à [HUE]","boost.setMotorDirection":"mettre la direction du moteur [MOTOR_ID] à [MOTOR_DIRECTION]","boost.setMotorPower":"mettre la vitesse du moteur [MOTOR_ID] à [POWER] %","boost.tiltDirection.any":"n\'importe laquelle","boost.tiltDirection.down":"vers le bas","boost.tiltDirection.left":"à gauche","boost.tiltDirection.right":"à droite","boost.tiltDirection.up":"vers le haut","boost.whenColor":"quand une brique [COLOR] est vue","boost.whenTilted":"quand incliné [TILT_DIRECTION_ANY]","ev3.beepNote":"jouer la note [NOTE] pendant [TIME] secondes","ev3.buttonPressed":"bouton [PORT] appuyé ?","ev3.getBrightness":"luminosité","ev3.getDistance":"distance","ev3.getMotorPosition":"position du moteur [PORT]","ev3.motorSetPower":"mettre la puissance du moteur [PORT] à [POWER] %","ev3.motorTurnClockwise":"faire tourner le moteur [PORT] dans ce sens-ci pendant [TIME] secondes","ev3.motorTurnCounterClockwise":"faire tourner le moteur [PORT] dans ce sens-là pendant [TIME] secondes","ev3.whenBrightnessLessThan":"quand la luminosité < [DISTANCE]","ev3.whenButtonPressed":"quand le bouton [PORT] est appuyé","ev3.whenDistanceLessThan":"quand la distance < [DISTANCE]","gdxfor.getAcceleration":"accélération [DIRECTION]","gdxfor.getForce":"force","gdxfor.getSpin":"vitesse de rotation [DIRECTION]","gdxfor.getTilt":"angle d\'inclinaison [TILT]","gdxfor.isFreeFalling":"tombe ?","gdxfor.isTilted":"incliné [TILT] ?","gdxfor.pulled":"tiré","gdxfor.pushed":"poussé","gdxfor.shaken":"secoué","gdxfor.startedFalling":"commençant à tomber","gdxfor.tiltDirectionMenu.any":"n\'importe laquelle","gdxfor.tiltDirectionMenu.back":"en arrière","gdxfor.tiltDirectionMenu.front":"en avant","gdxfor.tiltDirectionMenu.left":"à gauche","gdxfor.tiltDirectionMenu.right":"à droite","gdxfor.turnedFaceDown":"tourné vers le bas","gdxfor.turnedFaceUp":"tourné vers le haut","gdxfor.whenForcePushedOrPulled":"quand le capteur de force est [PUSH_PULL]","gdxfor.whenGesture":"quand [GESTURE]","gdxfor.whenTilted":"quand incliné [TILT]","makeymakey.downArrow":"flèche bas","makeymakey.downArrowShort":"bas","makeymakey.leftArrow":"flèche gauche","makeymakey.leftArrowShort":"gauche","makeymakey.rightArrow":"flèche droite","makeymakey.rightArrowShort":"droite","makeymakey.spaceKey":"espace","makeymakey.upArrow":"flèche haut","makeymakey.upArrowShort":"haut","makeymakey.whenKeyPressed":"quand la touche [KEY] pressée","makeymakey.whenKeysPressedInOrder":"quand [SEQUENCE] sont pressés dans l\'ordre","microbit.buttonsMenu.any":"n\'importe lequel","microbit.clearDisplay":"effacer l\'écran","microbit.defaultTextToDisplay":"Bonjour !","microbit.displaySymbol":"afficher [MATRIX]","microbit.displayText":"afficher le texte [TEXT]","microbit.gesturesMenu.jumped":"sauté","microbit.gesturesMenu.moved":"bougé","microbit.gesturesMenu.shaken":"secoué","microbit.isButtonPressed":"bouton [BTN] appuyé ?","microbit.isTilted":"incliné [DIRECTION] ?","microbit.pinStateMenu.off":"désactivée","microbit.pinStateMenu.on":"activée","microbit.tiltAngle":"angle d\'inclinaison [DIRECTION]","microbit.tiltDirectionMenu.any":"dans n\'importe quelle direction","microbit.tiltDirectionMenu.back":"en arrière","microbit.tiltDirectionMenu.front":"en avant","microbit.tiltDirectionMenu.left":"à gauche","microbit.tiltDirectionMenu.right":"à droite","microbit.whenButtonPressed":"quand le bouton [BTN] est appuyé","microbit.whenGesture":"quand [GESTURE]","microbit.whenPinConnected":"quand la broche [PIN] est connectée","microbit.whenTilted":"quand incliné [DIRECTION]","music.categoryName":"Musique","music.changeTempo":"ajouter [TEMPO] au tempo","music.drumBass":"(2) Grosse caisse","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) Charleston fermé","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Sonnaille","music.drumCrashCymbal":"(4) Cymbale crash","music.drumCuica":"(18) Cuíca","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Claquement de main","music.drumOpenHiHat":"(5) Charleston ouvert","music.drumSideStick":"(3) Side Stick","music.drumSnare":"(1) Caisse claire","music.drumTambourine":"(7) Tambourin","music.drumTriangle":"(12) Triangle","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Wood-block","music.getTempo":"tempo","music.instrumentBass":"(6) Basse","music.instrumentBassoon":"(14) Basson","music.instrumentCello":"(8) Violoncelle","music.instrumentChoir":"(15) Chorale","music.instrumentClarinet":"(10) Clarinette","music.instrumentElectricGuitar":"(5) Guitare électrique","music.instrumentElectricPiano":"(2) Piano électrique","music.instrumentFlute":"(12) Flûte","music.instrumentGuitar":"(4) Guitare","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Boîte à musique","music.instrumentOrgan":"(3) Orgue","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxophone","music.instrumentSteelDrum":"(18) Steel Drum","music.instrumentSynthLead":"(20) Lead synthétisé","music.instrumentSynthPad":"(21) Pad synthétisé","music.instrumentTrombone":"(9) Trombone","music.instrumentVibraphone":"(16) Vibraphone","music.instrumentWoodenFlute":"(13) Flûte en bois","music.midiPlayDrumForBeats":"jouer du tambour [DRUM] pendant [BEATS] temps","music.midiSetInstrument":"choisir l\'instrument n° [INSTRUMENT]","music.playDrumForBeats":"jouer du tambour [DRUM] pendant [BEATS] temps","music.playNoteForBeats":"jouer la note [NOTE] pendant [BEATS] temps","music.restForBeats":"faire une pause pendant [BEATS] temps","music.setInstrument":"choisir l\'instrument n° [INSTRUMENT]","music.setTempo":"mettre le tempo à [TEMPO]","pen.categoryName":"Stylo","pen.changeColorParam":"ajouter [VALUE] à la [COLOR_PARAM] du stylo","pen.changeHue":"ajouter [HUE] à la couleur du stylo","pen.changeShade":"ajouter [SHADE] à l\'intensité du stylo","pen.changeSize":"ajouter [SIZE] à la taille du stylo","pen.clear":"effacer tout","pen.colorMenu.brightness":"luminosité","pen.colorMenu.color":"couleur","pen.colorMenu.saturation":"saturation","pen.colorMenu.transparency":"transparence","pen.penDown":"stylo en position d\'écriture","pen.penUp":"relever le stylo","pen.setColor":"mettre la couleur du stylo à [COLOR]","pen.setColorParam":"mettre la [COLOR_PARAM] du stylo à [VALUE]","pen.setHue":"mettre la couleur du stylo à [HUE]","pen.setShade":"mettre l\'intensité du stylo à [SHADE]","pen.setSize":"mettre la taille du stylo à [SIZE]","pen.stamp":"estampiller","text2speech.alto":"alto","text2speech.categoryName":"Synthèse vocale","text2speech.defaultTextToSpeak":"bonjour","text2speech.giant":"géant","text2speech.kitten":"chaton","text2speech.setLanguageBlock":"mettre la langue à [LANGUAGE]","text2speech.setVoiceBlock":"choisir la voix du [VOICE]","text2speech.speakAndWaitBlock":"prononcer [WORDS]","text2speech.squeak":"piailler","text2speech.tenor":"ténor","translate.categoryName":"Traduire","translate.defaultTextToTranslate":"bonjour","translate.translateBlock":"traduire [WORDS] en [LANGUAGE]","translate.viewerLanguage":"langue","videoSensing.categoryName":"Détection vidéo","videoSensing.direction":"direction","videoSensing.motion":"mouvement","videoSensing.off":"désactiver","videoSensing.on":"activer","videoSensing.onFlipped":"inverser","videoSensing.setVideoTransparency":"mettre la transparence de la vidéo à [TRANSPARENCY]","videoSensing.sprite":"sprite","videoSensing.stage":"scène","videoSensing.videoOn":"[ATTRIBUTE] de la vidéo de [SUBJECT]","videoSensing.videoToggle":"[VIDEO_STATE] la vidéo","videoSensing.whenMotionGreaterThan":"quand le mouvement de la vidéo > [REFERENCE]","wedo2.getDistance":"distance","wedo2.getTiltAngle":"angle d\'inclinaison [TILT_DIRECTION]","wedo2.isTilted":"incliné [TILT_DIRECTION_ANY] ?","wedo2.motorDirection.backward":"par là","wedo2.motorDirection.forward":"par ici","wedo2.motorDirection.reverse":"inversé","wedo2.motorId.a":"moteur A","wedo2.motorId.all":"tous les moteurs","wedo2.motorId.b":"moteur B","wedo2.motorId.default":"moteur","wedo2.motorOff":"éteindre le moteur [MOTOR_ID]","wedo2.motorOn":"allumer le moteur [MOTOR_ID]","wedo2.motorOnFor":"allumer le moteur [MOTOR_ID] pendant [DURATION] secondes","wedo2.playNoteFor":"jouer la note [NOTE] pendant [DURATION] secondes","wedo2.setLightHue":"mettre la couleur de la lampe à [HUE]","wedo2.setMotorDirection":"mettre la direction du moteur [MOTOR_ID] à [MOTOR_DIRECTION]","wedo2.startMotorPower":"mettre la puissance du moteur [MOTOR_ID] à [POWER]","wedo2.tiltDirection.any":"dans n\'importe quelle direction","wedo2.tiltDirection.down":"vers le bas","wedo2.tiltDirection.left":"à gauche","wedo2.tiltDirection.right":"à droite","wedo2.tiltDirection.up":"vers le haut","wedo2.whenDistance":"quand la distance [OP] [REFERENCE]","wedo2.whenTilted":"quand incliné [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Couleur","paint.paintEditor.saturation":"Saturation","paint.paintEditor.brightness":"Luminosité","paint.paintEditor.costume":"Costume","paint.paintEditor.group":"Grouper","paint.paintEditor.ungroup":"Dégrouper","paint.paintEditor.undo":"Restaurer","paint.paintEditor.redo":"Refaire","paint.paintEditor.forward":"Avancer","paint.paintEditor.backward":"Reculer","paint.paintEditor.front":"Avant-plan","paint.paintEditor.back":"Arrière-plan","paint.paintEditor.more":"Plus","paint.modeTools.brushSize":"Taille","paint.modeTools.eraserSize":"Taille de la gomme","paint.modeTools.copy":"Copier","paint.modeTools.paste":"Coller","paint.modeTools.delete":"Supprimer","paint.modeTools.curved":"Courbé","paint.modeTools.pointed":"Pointu","paint.modeTools.thickness":"Épaisseur","paint.modeTools.flipHorizontal":"Retourner horizontalement","paint.modeTools.flipVertical":"Retourner verticalement","paint.modeTools.filled":"Plein","paint.modeTools.outlined":"Contours","paint.paintEditor.bitmap":"Convertir en bitmap","paint.paintEditor.vector":"Convertir en Vecteur","paint.paintEditor.fill":"Remplissage","paint.paintEditor.stroke":"Contour","paint.brushMode.brush":"Pinceau","paint.eraserMode.eraser":"Gomme","paint.fillMode.fill":"Remplissage","paint.lineMode.line":"Ligne","paint.ovalMode.oval":"Cercle","paint.rectMode.rect":"Rectangle","paint.reshapeMode.reshape":"Redessiner","paint.roundedRectMode.roundedRect":"Rectangle arrondi","paint.selectMode.select":"Sélectionner","paint.textMode.text":"Texte","paint.colorPicker.swap":"Inverser","tw.alerts.autosaving":"Création d\'un point de restauration…","tw.alerts.lostPeripheralConnection":"Le périphérique {extensionName} vient d’être déconnecté.","tw.alerts.savedToDisk":"Enregistré sur votre ordinateur.","tw.backpack.rename":"Nouveau nom :","tw.browserModal.desc":"Vérifiez que vous utilisez une version récente de Google Chrome, Mozilla Firefox, Micorsoft Edge ou Apple Safari.","tw.cantUseCloud":"Bien que vous puissiez créer des variables cloud, elles ne fonctionneront que si ce projet est téléchargé sur Scratch ou converti à l\'aide d\'un outil comme le{packager}.","tw.changeUsername.cannotChangeWhileRunning":"Le nom d\'utilisateur ne peut pas être modifié pendant l\'exécution du projet.","tw.cloudVariableBadge":"Ce projet utilise des variables cloud. TurboWarp utilise son propre serveur de variables cloud indépendant de Scratch. Méfiez-vous de l\'usurpation d\'identité car n\'importe qui peut changer son nom d\'utilisateur en n\'importe quoi.{learnMore}","tw.code":"Code source","tw.confirmIncompatibleExtension":"Cette extension est incompatible avec Scratch. Les projets réalisés avec lui ne peuvent pas être téléchargés sur le site Web de Scratch. Voulez-vous vraiment l\'activer ?","tw.customExtension.description":"Chargez des extensions personnalisées à partir d\'URL. Pour les développeurs. Expérimental.","tw.customExtension.name":"Extension customisée","tw.featuredProjectsStudio":"Voir le studio sur scratch.","tw.feedback":"retour et signalement de bugues","tw.feedbackButton":"Retours sur TurboWarp","tw.footer.credits":"Crédits","tw.footer.disclaimer":"TurboWarp n\'est pas affilié à Scratch, à l\'équipe Scratch ou à la Fondation Scratch.","tw.footer.donate":"Faire un don","tw.footer.embed":"Intégrer","tw.footer.fosshost":"Hébergement fourni par Fosshost","tw.footer.parameters":"Paramères URL","tw.footer.translate":"Aide pour traduire TurboWarp","tw.gui.crashMessage.description":"Nous sommes vraiment désolés, mais il semble que TurboWarp a crashé. Veuillez actualiser la page pour réessayer.","tw.gui.defaultProjectTitle":"Projet","tw.guiDefaultTitle":"Exécute les projets Scratch plus rapidement","tw.home.credit":"Notes et Crédits","tw.home.description":"TurboWarp est un Scratch mod qui compile les projets en JavaScript pour qu\'ils soient éxécutés plus rapidement. Pour l\'essayer, Entrez une URL ou l\'ID d\'un projet ci-dessus ou choisissez l\'un des projets sélectionné.","tw.input.tooltip":"Copie et colle le lien d\'un projet Scratch ici !","tw.invalidParameters.clones":"Le paramètre d\'URL \\"clone\\" n\'est pas valide.","tw.invalidParameters.fps":"Le paramètre d\'URL \\"fps\\" n\'est pas valide.","tw.loadError":"Impossible de charger le projet : {error}","tw.loader.assets.known":"Téléchargement des assets ({complete}/{total}) ...","tw.loader.assets.unknown":"Téléchargement des assets ...","tw.loader.data":"Téléchargement des données du projet …","tw.loader.generic":"Lecture du projet ...","tw.menuBar.60off":"Désactiver le mode 60 FPS","tw.menuBar.60on":"Activer le mode 60 FPS","tw.menuBar.advanced":"Avancé","tw.menuBar.changeUsername":"Changer le nom d\'utilisateur","tw.menuBar.cloudOff":"Désactiver les variables cloud","tw.menuBar.cloudOn":"Activer les variables cloud","tw.menuBar.cloudUnavailable":"Les variables cloud ne sont pas disponibles","tw.menuBar.cloudUnavailableAlert":"Impossible d\'utiliser les variables cloud, probablement parce que vous avez ouvert l\'éditeur.","tw.menuBar.compileError":"{sprite} : {error}","tw.menuBar.loadRestorePoint":"Restaurer à la dernière sauvegarde ","tw.menuBar.moreSettings":"Paramètres Avancés","tw.menuBar.newFramerate":"Nouveau ratio d\'images par seconde :","tw.menuBar.package":"Empaqueter le projet","tw.menuBar.reportError1":"Certains scripts ne peuvent pas être compilés.","tw.menuBar.reportError2":"Ceci est un bug. Merci de le signaler.","tw.menuBar.saveAs":"Enregistrer sous {file}","tw.menuBar.seeInside":"Voir à l\'intérieur","tw.oldDownload":"Enregistrer dans un fichier séparé...","tw.paint.alpha":"Opacité","tw.privacy":"Politique de Confidentialité","tw.restorePoint.confirm":"L\'éditeur enregistre automatiquement un point de restauration en cas de problème et que vous oubliez de sauvegarder. Vous ne devriez pas vous fier à cela et nous ne pouvons pas garantir qu\'il récupérera votre projet. Essayez de le charger ?","tw.restorePoint.loadFail":"Impossible de charger le point de restauration :{error}","tw.saveAs":"Enregistrer sous...","tw.saveTo":"Sauvegarder sous {file}","tw.scratchUnsafeCloud":"Si vous créez cette variable cloud, le projet dépassera la limite de Scratch de {number} variables, et certaines variables ne fonctionneront pas si vous téléchargez le projet dans Scratch.","tw.settingsModal.customStageSize":"Taille de la scène personnalisé :","tw.settingsModal.customStageSizeHelp":"Change la taille de la scène Scratch de 480x360 à autre chose. Essayez 640x360 pour rendre la scène grand écran. Très peu de projets gèrent cela correctement.","tw.settingsModal.dangerZone":"Zone de danger","tw.settingsModal.disableCompiler":"Désactiver le compilateur","tw.settingsModal.disableCompilerHelp":"Désactive le compilateur de TurboWarp. Utile si vous souhaitez modifier votre programme pendant que ce dernier est en train de tourner. Autrement, éviter d\'activer cette option.","tw.settingsModal.featured":"En vedette","tw.settingsModal.fps":"60 FPS (personnalisé)","tw.settingsModal.fpsHelp":"Exécute les scripts 60 fois par seconde au lieu de 30. La plupart des projets ne fonctionneront pas correctement si cette option est activée. Vous devriez essayer l\'interpolation avec le mode 60 FPS désactivé si tel est le cas.{customFramerate}","tw.settingsModal.fpsHelp.customFramerate":"Clique pour utiliser un autre ratio d\'images par seconde (FPS) que 30 ou 60","tw.settingsModal.help":"Clique pour obtenir de l\'aide","tw.settingsModal.highQualityPen":"Stylo de haute qualité","tw.settingsModal.highQualityPenHelp":"Permet aux projets utilisant le stylo d\'utiliser une plus grande résolution et permet de désactiver certains arrondis dans les coordonnées de l\'éditeur. Tout le projet ne bénéfie pas de ce paramètre et il peut impacter la performance.","tw.settingsModal.infiniteClones":"Clones Infinis","tw.settingsModal.infiniteClonesHelp":"Désactive la limite de 300 clones de Scratch","tw.settingsModal.interpolationHelp":"Rend les projets plus fluides en interpolant le mouvement du sprite. L\'interpolation ne doit pas être utilisée sur les projets 3D, les lanceurs de rayons, les projets de stylet et les projets décalés, car l\'interpolation les ralentira sans les rendre plus lisses.","tw.settingsModal.largeStageWarning":"Utiliser une taille de scène personnalisée plus large n\'est pas recommandé. Utilisez plutôt cette option pour une taille plus petite et avec le même ration longueur/largeur pour que le projet soit facilement utilisable par n\'importe quel utilisateur.","tw.settingsModal.removeFencing":"Supprimer les limites","tw.settingsModal.removeFencingHelp":"Permet aux sprites de se déplacer hors de l\'écran, de devenir aussi grands ou aussi petits qu\'ils le souhaitent et de faire fonctionner les blocs tactiles hors de l\'écran.","tw.settingsModal.removeLimits":"Supprimer les limites","tw.settingsModal.removeMiscLimits":"Supprimer diverses limites","tw.settingsModal.removeMiscLimitsHelp":"Supprime les limites des effets sonores ou celles de la taille du stylo.","tw.settingsModal.storeProjectOptions":"Sauvegarder les paramètres du projet.","tw.settingsModal.storeProjectOptionsHelp":"Stocke les paramètres sélectionnés dans le projet afin qu\'ils soient automatiquement appliqués lorsque TurboWarp charge ce projet. Le temporisateur Warp et le compilateur désactivé ne seront pas enregistrés.","tw.settingsModal.title":"Paramètres Avancés","tw.settingsModal.warpTimer":"Vérificateur de boucles infinies.","tw.settingsModal.warpTimerHelp":"Vérifie si les scripts sont bloqués dans des boucles infinies, et le cas échéant, fait tourner le programme a une vitesse très réduite pour empêcher le logiciel de crasher. Cela peut cependant fortement impacter les performances du programme.","tw.spriteSelectorItem.rename":"renommer","tw.stereo":"Stéréo","tw.studioview.authorAttribution":"Fait par {author}","tw.studioview.error":"Il y a eu une erreur dans le chargement de la page suivante des projets","tw.studioview.hoverText":"{title} fait par {author}","tw.tooLarge":"Ce son peut être trop volumineux pour être chargé dans Scratch.","tw.twExtension.description":"De nouveaux blocs étranges. Non compatible avec Scratch.","tw.twExtension.name":"Blocs TurboWarp","tw.unshared.1":"Les projets non partagés ne seront plus accessibles en utilisant uniquement leur ID a cause de futurs changements de l\' API de Scratch.","tw.unshared.2":"Pour plus d\'informations, visitez : {link}","tw.usernameModal.help":"Cette valeur sera stockée dans la mémoire de votre navigateur. Il peut être consigné lorsque vous interagissez avec des projets contenant des variables cloud.","tw.usernameModal.help2":"Les valeurs qui ne correspondent pas à un compte Scratch valide seront généralement rejetées par le serveur de variables cloud. Nous vous recommandons de le laisser tel quel ou de le remplacer par votre nom d\'utilisateur Scratch.","tw.usernameModal.mustChange":"Désolé, le serveur de variables cloud pense que votre nom d\'utilisateur n\'est peut-être pas sûr. Veuillez le changer pour autre chose ou{resetIt}.","tw.usernameModal.mustChange.resetIt":"réinitialiser (recommandé)","tw.usernameModal.reset":"Réinitialiser","tw.usernameModal.title":"Changer votre nom d\'utilisateur","tw.viewFeaturedProjects":"Cliquez pour voir les projets sélectionnés.","tw.viewOnScratch":"Voir le projet sur Scratch","tw.webglModal.description":"Malheureusement, cela ressemble à votre navigateur ou à votre ordinateur{webGlLink}. Cette technologie est nécessaire au fonctionnement de ce site. Essayez de mettre à jour votre navigateur et vos pilotes graphiques ou de redémarrer votre ordinateur."},"fy":{"gui.alerts.tryAgain":"Besykje nochris","gui.alerts.download":"Dellade","gui.connection.reconnect":"Opnij ferbine","gui.backpack.costumeLabel":"kostúm","gui.backpack.soundLabel":"lûd","gui.backpack.scriptLabel":"skript","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Rêchsek","gui.backpack.errorBackpack":"Flater by laden fan rêchsek","gui.backpack.loadingBackpack":"Lade ...","gui.backpack.more":"Mear","gui.backpack.emptyBackpack":"Rêchsek is leech","gui.unsupportedBrowser.label":"Browser wurdt net stipe","gui.cards.all-tutorials":"Tutorials","gui.cards.shrink":"Lytser meitsje","gui.cards.expand":"Mear sjen litte","gui.cards.close":"Slute","gui.cards.more-things-to-try":"Mear dingen om te besykjen!","gui.cards.see-more":"Mear sjen","gui.comingSoon.message1":"Gjin need, wy wurkje deroan {emoji}","gui.comingSoon.message2":"Meikoarten...","gui.comingSoon.message3":"Wy wurkje deroan {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Gjin apparaten fûn","gui.connection.auto-scanning.prescan":"Hâld jo apparaat klear en begjin mei sykjen.","gui.connection.auto-scanning.pressbutton":"Druk op de knop op jo apparaat.","gui.connection.auto-scanning.start-search":"Begjin mei sykjen","gui.connection.connecting-searchbutton":"Sykje...","gui.connection.auto-scanning.try-again":"Besykje nochris","gui.connection.connected":"Ferbûn","gui.connection.disconnect":"Ferbining ferbrekke","gui.connection.go-to-editor":"Gean nei Editor","gui.connection.connecting-cancelbutton":"Ferbine...","gui.connection.error.errorMessage":"Oeps, it liket derop dat der wat misgie.","gui.connection.error.tryagainbutton":"Besykje nochris","gui.connection.error.helpbutton":"Help","gui.connection.peripheral-name-label":"Namme fan it apparaat","gui.connection.connect":"Ferbine","gui.connection.scanning.lookingforperipherals":"Sykje nei apparaten","gui.connection.scanning.noPeripheralsFound":"Gjin apparaten fûn","gui.connection.scanning.instructions":"Selektearje jo apparaat yn boppesteande list.","gui.connection.search":"Fernije","gui.connection.unavailable.installscratchlink":"Soargje derfoar dat jo Scratch Link ynstallearre en aktyf hawwe","gui.connection.unavailable.enablebluetooth":"Kontrolearje oft Bluetooth ynskeakele is","gui.connection.unavailable.tryagainbutton":"Besykje nochris","gui.connection.unavailable.helpbutton":"Help","gui.controls.go":"Start","gui.controls.stop":"Stop","gui.crashMessage.label":"Oeps! Der is wat misgien.","gui.crashMessage.errorNumber":"Jo flater is oanmeld mei id {errorId}","gui.crashMessage.reload":"Op \'e nij lade","gui.customProcedures.myblockModalTitle":"Meitsje in Blok","gui.customProcedures.addAnInputNumberText":"Foegje in ynput ta","gui.customProcedures.numberTextType":"getal of tekst","gui.customProcedures.addAnInputBoolean":"Foegje in ynput ta","gui.customProcedures.booleanType":"boolean","gui.customProcedures.addALabel":"Foegje in kaartsje ta","gui.customProcedures.runWithoutScreenRefresh":"Utfiere sûnder skermfernijing","gui.customProcedures.cancel":"Ofbrekke","gui.customProcedures.ok":"Okee","gui.SpriteInfo.direction":"Rjochting","gui.directionPicker.rotationStyles.allAround":"Oeral","gui.directionPicker.rotationStyles.leftRight":"Links/Rjochts","gui.directionPicker.rotationStyles.dontRotate":"Net draaie","gui.gui.addExtension":"Ekstinsje tafoegje","gui.gui.codeTab":"Koade","gui.gui.backdropsTab":"Eftergrûnen","gui.gui.costumesTab":"Kostúms","gui.gui.soundsTab":"Lûden","gui.extensionLibrary.comingSoon":"Meikoarten","gui.extensionLibrary.requires":"Fereasket","gui.extensionLibrary.collaboration":"Gearwurking mei","gui.library.filterPlaceholder":"Sykje","gui.library.allTag":"Alle","gui.loader.headline":"Projekt wurdt laden","gui.loader.creating":"Projekt wurdt oanmakke","gui.authorInfo.byUser":"troch {username}","gui.menuBar.seeProjectPage":"Besjoch projektpagina","gui.menuBar.LanguageSelector":"taalkiezer","gui.menuBar.tutorialsLibrary":"Tutorials","gui.menuBar.restoreSprite":"Sprite weromsette","gui.menuBar.restoreSound":"Lûd weromsette","gui.menuBar.restoreCostume":"Kostúm weromsette","gui.menuBar.restore":"Weromsette","gui.menuBar.saveNow":"No bewarje","gui.menuBar.saveAsCopy":"Bewarje as kopy","gui.menuBar.remix":"Mjukse","gui.menuBar.new":"Nij","gui.menuBar.file":"Bestân","gui.menuBar.downloadToComputer":"Bewarje op jo kompjûter","gui.menuBar.edit":"Bewurkje","gui.menuBar.turboModeOff":"Turbo-modus útsette","gui.menuBar.turboModeOn":"Turbo-modus oansette","gui.gui.projectTitlePlaceholder":"Projektitel hjir","gui.menuBar.isShared":"Dield","gui.menuBar.share":"Diele","gui.modal.help":"Help","gui.modal.back":"Werom","gui.monitor.listMonitor.empty":"(leech)","gui.monitor.listMonitor.listLength":"lingte {length}","gui.monitor.contextMenu.default":"normale útfier","gui.monitor.contextMenu.large":"grutte útfier","gui.monitor.contextMenu.slider":"skúfútfier","gui.monitor.contextMenu.sliderRange":"feroarje skúfberik","gui.monitor.contextMenu.import":"ymportearje","gui.monitor.contextMenu.export":"eksportearje","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Ofspylje","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"Foar alle sprites","gui.gui.variableScopeOptionSpriteOnly":"Allinich foar dizze sprite","gui.gui.cloudVariableOption":"Cloud-fariabele (opslein op server)","gui.gui.variablePromptAllSpritesMessage":"Dizze fariabele sil beskikber wêze foar alle sprites.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Ofbrekke","gui.prompt.ok":"Okee","gui.playbackStep.stopMsg":"Stop","gui.playbackStep.playMsg":"Ofspylje","gui.playbackStep.loadingMsg":"Lade...","gui.playbackStep.saveMsg":"Bewarje","gui.playbackStep.reRecordMsg":"Opnij opnimme","gui.recordModal.title":"Lûd opnimme","gui.recordingStep.beginRecord":"Begjin opname troch te klikken op de knop hjirûnder","gui.recordingStep.permission":"{arrow}Wy hawwe jo tastimming nedich om jo mikrofoan te brûken","gui.recordingStep.stop":"Stopje de opname","gui.recordingStep.record":"Opnimme","gui.sliderModal.min":"Minimumwearde","gui.sliderModal.max":"Maksimumwearde","gui.sliderModal.title":"Feroarje skúfberik","gui.sliderPrompt.cancel":"Ofbrekke","gui.sliderPrompt.ok":"Okee","gui.soundEditor.sound":"Lûd","gui.soundEditor.play":"Ofspylje","gui.soundEditor.stop":"Stop","gui.soundEditor.copy":"Kopiearje","gui.soundEditor.paste":"Plakke","gui.soundEditor.copyToNew":"Kopiearje nei Nij","gui.soundEditor.delete":"Fuortsmite","gui.soundEditor.save":"Bewarje","gui.soundEditor.undo":"Ungedien meitsje","gui.soundEditor.redo":"Op \'e nij dwaan","gui.soundEditor.faster":"Flugger","gui.soundEditor.slower":"Stadiger","gui.soundEditor.echo":"Echo","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Lûder","gui.soundEditor.softer":"Sêfter","gui.soundEditor.reverse":"Efterút","gui.soundEditor.fadeOut":"Uitferfage","gui.soundEditor.fadeIn":"Ynferfage","gui.soundEditor.mute":"Lûd út","gui.SpriteInfo.spritePlaceholder":"Namme","gui.SpriteInfo.sprite":"Sprite","gui.SpriteInfo.show":"Sjen litte","gui.SpriteInfo.size":"Grutte","gui.spriteSelectorItem.contextMenuDuplicate":"duplisearje","gui.spriteSelectorItem.contextMenuExport":"eksportearje","gui.spriteSelectorItem.contextMenuDelete":"fuortsmite","gui.spriteSelector.addSpriteFromLibrary":"Kies in Sprite","gui.spriteSelector.addSpriteFromPaint":"Paint","gui.spriteSelector.addSpriteFromSurprise":"Ferrassing","gui.spriteSelector.addSpriteFromFile":"Sprite ynlade","gui.stageHeader.stageSizeLarge":"Wikselje nei grut poadium","gui.stageHeader.stageSizeSmall":"Wikselje nei lyts poadium","gui.stageHeader.stageSizeFull":"Folslein skerm","gui.stageHeader.stageSizeUnFull":"Folslein skerm ôfslute","gui.stageHeader.fullscreenControl":"Folslein skerm","gui.spriteSelector.addBackdropFromLibrary":"Kies in eftergrûn","gui.stageSelector.addBackdropFromPaint":"Paint","gui.stageSelector.addBackdropFromSurprise":"Ferrassing","gui.stageSelector.addBackdropFromFile":"Eftergrûn ynlade","gui.stageSelector.stage":"Poadium","gui.stageSelector.backdrops":"Eftergrûnen","gui.telemetryOptIn.label":"Rapportearje statistiken om Scratch te ferbetterjen","gui.telemetryOptIn.body1":"It Scratch Team wol hieltyd better begripe hoe\'t Scratch oer de hiele wrâld brûkt wurdt. Om dy ynspanning te stypjen, kinne jo Scratch tastean om ynformaasje oer it gebrûk automatysk nei it Scratch Team te stjoeren.","gui.telemetryOptIn.body2":"De ynformaasje dy\'t wy sammelje omfettet taalseleksje, it gebrûk fan blokken, en guon saken lykas in projekt opslaan, lade en ynlade. Wy sammelje GJIN persoanlike ynformaasje. Besjoch ek ús {privacyPolicyLink} foar mear ynformaasje.","gui.telemetryOptIn.privacyPolicyLink":"Privacybelied","gui.telemetryOptIn.optInText":"Diel myn gebrûkgegevens mei it Scratch Team","gui.telemetryOptIn.optInTooltip":"Telemetry ynskeakelje","gui.telemetryOptIn.optOutText":"Diel myn gebrûkgegevens net mei it Scratch Team","gui.telemetryOptIn.optOutTooltip":"Telemetry útsette","gui.telemetryOptIn.settingWasUpdated":"Jo ynstelling is bywurke.","gui.telemetryOptIn.buttonClose":"Slute","gui.turboMode.active":"Turbo Modus","gui.webglModal.label":"Jo browser stipet WebGL net","gui.webglModal.webgllink":"stipet WebGL net","gui.costumeLibrary.chooseABackdrop":"Kies in eftergrûn","gui.costumeLibrary.chooseACostume":"Kies in kostúm","gui.costumeTab.addBackdropFromLibrary":"Kies in eftergrûn","gui.costumeTab.addCostumeFromLibrary":"Kies in kostúm","gui.costumeTab.addBlankCostume":"Leech kostúm","gui.costumeTab.addSurpriseCostume":"Ferrassing","gui.costumeTab.addFileBackdrop":"Eftergrûn ynlade","gui.costumeTab.addFileCostume":"Kostúm ynlade","gui.extensionLibrary.chooseAnExtension":"Kies in ekstinsje","gui.extensionLibrary.extensionUrl":"Fier de URL fan de ekstinsje yn","gui.monitors.importListColumnPrompt":"Hokker kolom moat brûkt wurde (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Koe de opname net begjinne","gui.soundLibrary.chooseASound":"Kies in lûd","gui.soundTab.fileUploadSound":"Lûd ynlade","gui.soundTab.surpriseSound":"Ferrassing","gui.soundTab.recordSound":"Opnimme","gui.soundTab.addSoundFromLibrary":"Kies in Lûd","gui.spriteLibrary.chooseASprite":"Kies in Sprite","gui.tipsLibrary.tutorials":"Kies in Tutorial","gui.alerts.createsuccess":"Nij projekt makke.","gui.alerts.createcopysuccess":"Projekt bewarre as kopy.","gui.alerts.createremixsuccess":"Projekt bewarre as mjuks.","gui.alerts.creating":"Nij oanmeitsje ...","gui.alerts.creatingCopy":"Projekt kopiearje...","gui.alerts.creatingRemix":"Projekt mikse...","gui.alerts.creatingError":"Koe it projekt net oanmeitsje. Besykje it nochris!","gui.alerts.savingError":"Koe it projekt net bewarje.","gui.alerts.savesuccess":"Projekt bewarre.","gui.alerts.saving":"Projekt bewarje...","gui.alerts.cloudInfo":"Tink derom, wolkefariabelen stypje allinich getallen, gjin letters of symboalen. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Kom mear te witten.","gui.alerts.importing":"Ymportearje...","gui.defaultProject.variable":"myn fariabele","gui.extension.music.name":"Muzyk","gui.extension.music.description":"Spylje ynstruminten en trommels.","gui.extension.pen.name":"Pinne","gui.extension.pen.description":"Tekenje mei jo Sprites.","gui.extension.videosensing.name":"Video Sensing","gui.extension.videosensing.description":"Fernim beweging mei de kamera.","gui.extension.text2speech.name":"Tekst nei spraak","gui.extension.text2speech.description":"Lit jo projekten prate.","gui.extension.translate.name":"Oersette","gui.extension.translate.description":"Tekst oersette nei in protte talen.","gui.extension.makeymakey.description":"Meitsje fan alles in kaai.","gui.extension.microbit.description":"Ferbyn jo projekten mei de wrâld.","gui.extension.microbit.connectingMessage":"Ferbine","gui.extension.ev3.description":"Bou ynteraktive robots en mear.","gui.extension.ev3.connectingMessage":"Ferbine. Soargje derfoar dat de pin op jo EV3 op 1234 is ynsteld.","gui.extension.boost.description":"Bring robotkreaasjes ta libben.","gui.extension.boost.connectingMessage":"Ferbine","gui.extension.wedo2.description":"Bouwe mei motors en sensoaren.","gui.extension.wedo2.connectingMessage":"Ferbine","gui.extension.gdxfor.description":"Fernim triuwe, lûke, beweging en draaie.","gui.extension.gdxfor.connectingMessage":"Ferbine","gui.libraryTags.all":"Alle","gui.libraryTags.animals":"Bisten","gui.libraryTags.dance":"Dûnsje","gui.libraryTags.effects":"Effekten","gui.libraryTags.fantasy":"Fantasij","gui.libraryTags.fashion":"Moade","gui.libraryTags.food":"Iten","gui.libraryTags.indoors":"Binnen","gui.libraryTags.loops":"Lussen","gui.libraryTags.music":"Muzyk","gui.libraryTags.notes":"Oantekeningen","gui.libraryTags.outdoors":"Bûten","gui.libraryTags.patterns":"Patroanen","gui.libraryTags.people":"Minsken","gui.libraryTags.percussion":"Slachwurk","gui.libraryTags.space":"Romte","gui.libraryTags.sports":"Sport","gui.libraryTags.underwater":"Under wetter","gui.libraryTags.voice":"Stim","gui.libraryTags.wacky":"Gek","gui.libraryTags.animation":"Animaasje","gui.libraryTags.art":"Keunst","gui.libraryTags.games":"Spultsjes","gui.libraryTags.stories":"Ferhalen","gui.libraryTags.letters":"Letters","gui.opcodeLabels.direction":"rjochting","gui.opcodeLabels.xposition":"posysje fan x","gui.opcodeLabels.yposition":"posysje fan y","gui.opcodeLabels.size":"grutte","gui.opcodeLabels.costumename":"namme fan kostúm","gui.opcodeLabels.costumenumber":"kostúmnûmer","gui.opcodeLabels.backdropname":"namme fan eftergrûn","gui.opcodeLabels.backdropnumber":"eftergrûnnûmer","gui.opcodeLabels.volume":"folume","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"antwurd","gui.opcodeLabels.loudness":"lûdens","gui.opcodeLabels.username":"brûkersnamme","gui.opcodeLabels.year":"jier","gui.opcodeLabels.month":"moanne","gui.opcodeLabels.date":"datum","gui.opcodeLabels.dayofweek":"dei fan \'e wike","gui.opcodeLabels.hour":"oere","gui.opcodeLabels.minute":"minút","gui.opcodeLabels.second":"sekonde","gui.opcodeLabels.timer":"timer","gui.sharedMessages.backdrop":"eftergrûn{index}","gui.sharedMessages.costume":"kostúm{index}","gui.sharedMessages.sprite":"Sprite{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Ynhâld ferfange fan dit projekt?","gui.sharedMessages.loadFromComputerTitle":"Ynlade fan jo kompjûter ôf","boost.color.any":"elke kleur","boost.color.black":"swart","boost.color.blue":"blau","boost.color.green":"grien","boost.color.red":"read","boost.color.white":"wyt","boost.color.yellow":"giel","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] posysje","boost.getTiltAngle":"kantelhoek [TILT_DIRECTION]","boost.motorDirection.backward":"op dy manier","boost.motorDirection.forward":"dizze manier","boost.motorDirection.reverse":"omkeare","boost.motorOff":"set motor [MOTOR_ID] út","boost.motorOn":"set motor [MOTOR_ID] oan","boost.motorOnFor":"lit motor [MOTOR_ID] [DURATION] sekonden draaie","boost.motorOnForRotation":"lit motor [MOTOR_ID] [ROTATION] rûntsjes draaie","boost.seeingColor":"is it [COLOR] stientsje te sjen?","boost.setLightHue":"stel de kleur fan it ljocht yn op [HUE]","boost.setMotorDirection":"set motor [MOTOR_ID] yn de rjochting [MOTOR_DIRECTION]","boost.setMotorPower":"set motor [MOTOR_ID] op [POWER]% snelheid","boost.tiltDirection.any":"elk","boost.tiltDirection.down":"nei ûnder","boost.tiltDirection.left":"links","boost.tiltDirection.right":"rjochts","boost.tiltDirection.up":"omheech","boost.whenColor":"as it [COLOR] stientsje te sjen is","boost.whenTilted":"as kantele [TILT_DIRECTION_ANY]","ev3.beepNote":"lit [NOTE] [TIME] sekonden hearre","ev3.buttonPressed":"knop [PORT] yndrukt?","ev3.getBrightness":"helderheid","ev3.getDistance":"ôfstân","ev3.getMotorPosition":"motor [PORT] posysje","ev3.motorSetPower":"stel motor [PORT] yn op [POWER]% krêft","ev3.motorTurnClockwise":"draai motor [PORT] dizze kant út foar [TIME] sekonden","ev3.motorTurnCounterClockwise":"draai motor [PORT] dy kant út foar [TIME] sekonden","ev3.whenBrightnessLessThan":"as helderheid <[DISTANCE]","ev3.whenButtonPressed":"as knop [PORT] yndrukt wurdt","ev3.whenDistanceLessThan":"wannear\'t ôfstân <[DISTANCE]","gdxfor.getAcceleration":"fersnelling [DIRECTION]","gdxfor.getForce":"krêft","gdxfor.getSpin":"draaisnelheid [DIRECTION]","gdxfor.getTilt":"kantelhoeke [TILT]","gdxfor.isFreeFalling":"falt?","gdxfor.isTilted":"kantele [TILT]?","gdxfor.pulled":"lutsen","gdxfor.pushed":"treaun","gdxfor.shaken":"skodde","gdxfor.startedFalling":"begûn te fallen","gdxfor.tiltDirectionMenu.any":"elk","gdxfor.tiltDirectionMenu.back":"efterút","gdxfor.tiltDirectionMenu.front":"foarkant","gdxfor.tiltDirectionMenu.left":"links","gdxfor.tiltDirectionMenu.right":"rjochts","gdxfor.turnedFaceDown":"nei ûnder rjochte","gdxfor.turnedFaceUp":"nei boppe rjochte","gdxfor.whenForcePushedOrPulled":"as krêftsensor [PUSH_PULL]","gdxfor.whenGesture":"as [GESTURE]","gdxfor.whenTilted":"as kantele [TILT]","makeymakey.downArrow":"pylkje nei ûnder","makeymakey.downArrowShort":"nei ûnder","makeymakey.leftArrow":"pylje nei links","makeymakey.leftArrowShort":"links","makeymakey.rightArrow":"pylkje nei rjochts","makeymakey.rightArrowShort":"rjochts","makeymakey.spaceKey":"spaasje","makeymakey.upArrow":" pylkje omheech","makeymakey.upArrowShort":"omheech","makeymakey.whenKeyPressed":"as [KEY] toets yndrukt wurdt","makeymakey.whenKeysPressedInOrder":"as [SEQUENCE] yn folchoarder yndrukt wurdt","microbit.buttonsMenu.any":"elk","microbit.clearDisplay":"Skerm skjinmeitsje","microbit.defaultTextToDisplay":"Hoi!","microbit.displaySymbol":"skerm [MATRIX]","microbit.displayText":"skerm tekst [TEXT]","microbit.gesturesMenu.jumped":"sprong","microbit.gesturesMenu.moved":"bewege","microbit.gesturesMenu.shaken":"skodde","microbit.isButtonPressed":"[BTN] knop yndrukt?","microbit.isTilted":"kantele [DIRECTION]?","microbit.pinStateMenu.off":"út","microbit.pinStateMenu.on":"op","microbit.tiltAngle":"kantelhoek [DIRECTION]","microbit.tiltDirectionMenu.any":"elk","microbit.tiltDirectionMenu.back":"nei achter","microbit.tiltDirectionMenu.front":"nei foaren","microbit.tiltDirectionMenu.left":"nei links","microbit.tiltDirectionMenu.right":"nei rjochts","microbit.whenButtonPressed":"as [BTN] knop yndrukt wurdt","microbit.whenGesture":"as [GESTURE]","microbit.whenPinConnected":"as pin [PIN] ferbûn is","microbit.whenTilted":"as kantele nei [DIRECTION]","music.categoryName":"Muzyk","music.changeTempo":"tempo feroarje mei [TEMPO]","music.drumBass":"(2) Bass Drum","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Klaves","music.drumClosedHiHat":"(6) Sletten Hi-Hat","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Cowbell","music.drumCrashCymbal":"(4) Crash Bekken","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Hânklap","music.drumOpenHiHat":"(5) Iepen Hi-Hat","music.drumSideStick":"(3) Side Stick","music.drumSnare":"(1) Snaartrom","music.drumTambourine":"(7) Tamboeryn","music.drumTriangle":"(12) Triangel","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Houtblok","music.getTempo":"tempo","music.instrumentBass":"(6) Bas","music.instrumentBassoon":"(14) Fagot","music.instrumentCello":"(8) Tsjello","music.instrumentChoir":"(15) Koar","music.instrumentClarinet":"(10) Klarinet","music.instrumentElectricGuitar":"(5) Elektryske Gitaar","music.instrumentElectricPiano":"(2) Elektryske Piano","music.instrumentFlute":"(12) Fluit","music.instrumentGuitar":"(4) Gitaar","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Muzykdoaze","music.instrumentOrgan":"(3) Oargel","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saksofoan","music.instrumentSteelDrum":"(18) Stieltrommel","music.instrumentSynthLead":"(20) Synth Lead","music.instrumentSynthPad":"(21) Synth Pad","music.instrumentTrombone":"(9) Tromboane","music.instrumentVibraphone":"(16) Vibrafoan","music.instrumentWoodenFlute":"(13) Houten fluit","music.midiPlayDrumForBeats":"spylje trommel [DRUM] foar [BEATS] beats","music.midiSetInstrument":"ynstrumint ynstelle op [INSTRUMENT]","music.playDrumForBeats":"spylje trommel [DRUM] foar [BEATS] beats","music.playNoteForBeats":"play noat [NOTE] foar [BEATS] beats","music.restForBeats":"rêst foar [BEATS] beats","music.setInstrument":"ynstrumint ynstelle op [INSTRUMENT]","music.setTempo":"set tempo yn op [TEMPO]","pen.categoryName":"Pinne","pen.changeColorParam":"feroarje pinne [COLOR_PARAM] troch [VALUE]","pen.changeHue":"feroarje pennekleur troch [HUE]","pen.changeShade":"feroarje penskerm troch [SHADE]","pen.changeSize":"pennegrutte feroarje mei [SIZE]","pen.clear":"wiskje alles","pen.colorMenu.brightness":"helderheid","pen.colorMenu.color":"kleur","pen.colorMenu.saturation":"sêding","pen.colorMenu.transparency":"transparânsje","pen.penDown":"pen omleech","pen.penUp":"pen omheech","pen.setColor":"set pennekleur yn op [COLOR]","pen.setColorParam":"set pinne [COLOR_PARAM] yn op [VALUE]","pen.setHue":"set pennekleur yn op [HUE]","pen.setShade":"set penskerm op [SHADE]","pen.setSize":"set pennegrutte yn op [SIZE]","pen.stamp":"stimpel","text2speech.alto":"alto","text2speech.categoryName":"Tekst nei spraak","text2speech.defaultTextToSpeak":"Hoi","text2speech.giant":"reus","text2speech.kitten":"kitten","text2speech.setLanguageBlock":"set taal yn op [LANGUAGE]","text2speech.setVoiceBlock":"set stim op [VOICE]","text2speech.speakAndWaitBlock":"sprekke [WORDS]","text2speech.squeak":"piipje","text2speech.tenor":"tenoar","translate.categoryName":"Oersette","translate.defaultTextToTranslate":"Hoi","translate.translateBlock":"oersette [WORDS] nei [LANGUAGE]","translate.viewerLanguage":"taal","videoSensing.categoryName":"Fideo Fiele","videoSensing.direction":"rjochting","videoSensing.motion":"moasje","videoSensing.off":"út","videoSensing.on":"op","videoSensing.onFlipped":"op omdraaid","videoSensing.setVideoTransparency":"set fideotransparânsje yn op [TRANSPARENCY]","videoSensing.sprite":"sprite","videoSensing.stage":"poadium","videoSensing.videoOn":"fideo [ATTRIBUTE] op [SUBJECT]","videoSensing.videoToggle":"keare fideo [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"wannear fideobeweging> [REFERENCE]","wedo2.getDistance":"ôfstân","wedo2.getTiltAngle":"kantelhoek [TILT_DIRECTION]","wedo2.isTilted":"kantele [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"op dy manier","wedo2.motorDirection.forward":"dizze manier","wedo2.motorDirection.reverse":"omkeare","wedo2.motorId.a":"motor A","wedo2.motorId.all":"alle motors","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"set [MOTOR_ID] út","wedo2.motorOn":"skeakelje [MOTOR_ID] yn","wedo2.motorOnFor":"skeakelje [MOTOR_ID] [DURATION] sekonden yn","wedo2.playNoteFor":"spylje noat [NOTE] foar [DURATION] sekonden","wedo2.setLightHue":"set ljochtkleur yn op [HUE]","wedo2.setMotorDirection":"set [MOTOR_ID] rjochting yn op [MOTOR_DIRECTION]","wedo2.startMotorPower":"set [MOTOR_ID] macht yn op [POWER]","wedo2.tiltDirection.any":"elk","wedo2.tiltDirection.down":"omleech","wedo2.tiltDirection.left":"links","wedo2.tiltDirection.right":"rjochts","wedo2.tiltDirection.up":"op","wedo2.whenDistance":"wannear ôfstân [OP] [REFERENCE]","wedo2.whenTilted":"as kantele [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Kleur","paint.paintEditor.saturation":"Sêding","paint.paintEditor.brightness":"Helderheid","paint.paintEditor.costume":"Kostúm","paint.paintEditor.group":"Groep","paint.paintEditor.ungroup":"Ut groep helje","paint.paintEditor.undo":"Ungedien meitsje","paint.paintEditor.redo":"Op \'e nij dwaan","paint.paintEditor.forward":"Foarút","paint.paintEditor.backward":"Efterút","paint.paintEditor.front":"Foarkant","paint.paintEditor.back":"Werom","paint.paintEditor.more":"Mear","paint.modeTools.brushSize":"Grutte","paint.modeTools.eraserSize":"Gumgrutte","paint.modeTools.copy":"Kopiearje","paint.modeTools.paste":"Plakke","paint.modeTools.delete":"Fuorthelje","paint.modeTools.curved":"Bûgd","paint.modeTools.pointed":"Oanwiisd","paint.modeTools.thickness":"Dikte","paint.modeTools.flipHorizontal":"Horizontaal omdraaie","paint.modeTools.flipVertical":"Fertikaal omdraaie","paint.modeTools.filled":"Folle","paint.modeTools.outlined":"Bûtenste râne","paint.paintEditor.bitmap":"Omsette nei Bitmap","paint.paintEditor.vector":"Omsette nei Fektor","paint.paintEditor.fill":"Folje","paint.paintEditor.stroke":"Râne","paint.brushMode.brush":"Kwast","paint.eraserMode.eraser":"Gum","paint.fillMode.fill":"Folje","paint.lineMode.line":"Rigel","paint.ovalMode.oval":"Sirkel","paint.rectMode.rect":"Rjochthoek","paint.reshapeMode.reshape":"Foarm feroarje","paint.roundedRectMode.roundedRect":"Rjochthoek mei rûne hoeken","paint.selectMode.select":"Selektearje","paint.textMode.text":"Tekst","paint.colorPicker.swap":"Ruilje"},"ga":{"gui.alerts.tryAgain":"Bain Triail Eile As","gui.alerts.download":"Íoslódáil","gui.connection.reconnect":"Athcheangail","gui.backpack.costumeLabel":"culaith","gui.backpack.soundLabel":"fuaim","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprid","gui.backpack.header":"Mála Droma","gui.backpack.errorBackpack":"Earráid agus an mála droma á lódáil","gui.backpack.loadingBackpack":"Á Lódáil...","gui.backpack.more":"Tuilleadh","gui.backpack.emptyBackpack":"Tá an mála droma folamh","gui.unsupportedBrowser.label":"Ní thacaímid leis an mbrabhsálaí seo","gui.cards.all-tutorials":"Cúrsaí Teagaisc","gui.cards.shrink":"Laghdaigh","gui.cards.expand":"Leathnaigh","gui.cards.close":"Dún","gui.cards.more-things-to-try":"Tuilleadh rudaí le triail a bhaint astu!","gui.cards.see-more":"Tuilleadh","gui.comingSoon.message1":"Ná buair do cheann, táimid ag plé leis {emoji}","gui.comingSoon.message2":"Le teacht go luath...","gui.comingSoon.message3":"Táimid ag plé leis {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Níor aimsíodh aon ghléas","gui.connection.auto-scanning.prescan":"Coinnigh do ghléas in aice láimhe, ansin déan cuardach.","gui.connection.auto-scanning.pressbutton":"Brúigh an cnaipe ar do ghléas.","gui.connection.auto-scanning.start-search":"Déan Cuardach","gui.connection.connecting-searchbutton":"Cuardach ar siúl...","gui.connection.auto-scanning.try-again":"Bain triail eile as","gui.connection.connected":"Ceangailte","gui.connection.disconnect":"Dícheangail","gui.connection.go-to-editor":"Fill ar an Eagarthóir","gui.connection.connecting-cancelbutton":"Ag ceangal...","gui.connection.error.errorMessage":"Úps, dealraíonn sé go ndeachaigh rud éigin in abar.","gui.connection.error.tryagainbutton":"Bain triail eile as","gui.connection.error.helpbutton":"Cabhair","gui.connection.peripheral-name-label":"Ainm an ghléis","gui.connection.connect":"Ceangail","gui.connection.scanning.lookingforperipherals":"Ag lorg gléasanna","gui.connection.scanning.noPeripheralsFound":"Níor aimsíodh aon ghléas","gui.connection.scanning.instructions":"Roghnaigh do ghléas sa liosta thuas.","gui.connection.search":"Athnuaigh","gui.connection.unavailable.installscratchlink":"Deimhnigh gur shuiteáil tú Scratch Link agus go bhfuil sé ar siúl","gui.connection.unavailable.enablebluetooth":"Deimhnigh go bhfuil Bluetooth cumasaithe","gui.connection.unavailable.tryagainbutton":"Bain triail eile as","gui.connection.unavailable.helpbutton":"Cabhair","gui.controls.go":"Tosaigh","gui.controls.stop":"Stop","gui.crashMessage.label":"Úps! Tharla earráid.","gui.crashMessage.errorNumber":"Scríobhadh an earráid seo sa logchomhad le ID {errorId}","gui.crashMessage.reload":"Athlódáil","gui.customProcedures.myblockModalTitle":"Cruthaigh Bloc","gui.customProcedures.addAnInputNumberText":"Cuir réimse ionchurtha leis","gui.customProcedures.numberTextType":"uimhir nó téacs","gui.customProcedures.addAnInputBoolean":"Cuir réimse ionchurtha leis","gui.customProcedures.booleanType":"athróg Boole","gui.customProcedures.addALabel":"Cuir lipéad leis","gui.customProcedures.runWithoutScreenRefresh":"Rith gan an scáileán a athnuachan","gui.customProcedures.cancel":"Cealaigh","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Treo","gui.directionPicker.rotationStyles.allAround":"Timpeall ar fad","gui.directionPicker.rotationStyles.leftRight":"Clé/Deas","gui.directionPicker.rotationStyles.dontRotate":"Ná rothlaigh","gui.gui.addExtension":"Cuir Breiseán Leis","gui.gui.codeTab":"Cód","gui.gui.backdropsTab":"Cúlraí","gui.gui.costumesTab":"Cultacha","gui.gui.soundsTab":"Fuaimeanna","gui.extensionLibrary.comingSoon":"Le teacht go luath","gui.extensionLibrary.requires":"Riachtanais","gui.extensionLibrary.collaboration":"I gcomhar le","gui.library.filterPlaceholder":"Cuardaigh","gui.library.allTag":"Uile","gui.loader.headline":"Tionscadal á Lódáil","gui.loader.creating":"Tionscadal a Chruthú","gui.authorInfo.byUser":"le {username}","gui.menuBar.seeProjectPage":"Leathanach an Tionscadail","gui.menuBar.LanguageSelector":"roghnóir teanga","gui.menuBar.tutorialsLibrary":"Cúrsaí Teagaisc","gui.menuBar.restoreSprite":"Athchóirigh an Sprid","gui.menuBar.restoreSound":"Athchóirigh an Fhuaim Scriosta","gui.menuBar.restoreCostume":"Athchóirigh an Chulaith Scriosta","gui.menuBar.restore":"Athchóirigh","gui.menuBar.saveNow":"Sábháil anois","gui.menuBar.saveAsCopy":"Sábháil mar chóip","gui.menuBar.remix":"Athmheasc","gui.menuBar.new":"Nua","gui.menuBar.file":"Comhad","gui.menuBar.downloadToComputer":"Sábháil ar do ríomhaire","gui.menuBar.edit":"Eagar","gui.menuBar.turboModeOff":"Múch an Mód Turbó","gui.menuBar.turboModeOn":"Tosaigh an Mód Turbó","gui.gui.projectTitlePlaceholder":"Teideal an tionscadail anseo","gui.menuBar.isShared":"Comhroinnte","gui.menuBar.share":"Comhroinn","gui.modal.help":"Cabhair","gui.modal.back":"Ar ais","gui.monitor.listMonitor.empty":"(folamh)","gui.monitor.listMonitor.listLength":"fad {length}","gui.monitor.contextMenu.default":"gnáth-asléamh","gui.monitor.contextMenu.large":"asléamh mór","gui.monitor.contextMenu.slider":"sleamhnán","gui.monitor.contextMenu.sliderRange":"athraigh raon an tsleamhnáin","gui.monitor.contextMenu.import":"iompórtáil","gui.monitor.contextMenu.export":"easpórtáil","gui.monitor.contextMenu.hide":"folaigh","gui.playButton.play":"Seinn","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"Na sprideanna go léir","gui.gui.variableScopeOptionSpriteOnly":"An sprid seo amháin","gui.gui.cloudVariableOption":"Néalathróg (sábháilte ar an bhfreastalaí)","gui.gui.variablePromptAllSpritesMessage":"Beidh an athróg seo ar fáil do gach sprid.","gui.gui.listPromptAllSpritesMessage":"Beidh an liosta seo ar fáil do gach sprid.","gui.prompt.cancel":"Cealaigh","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Stop","gui.playbackStep.playMsg":"Seinn","gui.playbackStep.loadingMsg":"Á Lódáil...","gui.playbackStep.saveMsg":"Sábháil","gui.playbackStep.reRecordMsg":"Ataifead","gui.recordModal.title":"Taifeadadh","gui.recordingStep.beginRecord":"Cliceáil an cnaipe thíos chun an taifeadadh a thosú","gui.recordingStep.permission":"{arrow}Tá do chead ag teastáil uainn chun an micreafón a úsáid","gui.recordingStep.stop":"Stop ag taifeadadh","gui.recordingStep.record":"Taifead","gui.sliderModal.min":"Íosluach","gui.sliderModal.max":"Uasluach","gui.sliderModal.title":"Athraigh raon an tsleamhnáin","gui.sliderPrompt.cancel":"Cealaigh","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Fuaim","gui.soundEditor.play":"Seinn","gui.soundEditor.stop":"Stop","gui.soundEditor.copy":"Cóipeáil","gui.soundEditor.paste":"Greamaigh","gui.soundEditor.copyToNew":"Cóipeáil mar fhuaim nua","gui.soundEditor.delete":"Scrios","gui.soundEditor.save":"Sábháil","gui.soundEditor.undo":"Cealaigh","gui.soundEditor.redo":"Athdhéan","gui.soundEditor.faster":"Níos Sciobtha","gui.soundEditor.slower":"Níos Moille","gui.soundEditor.echo":"Macalla","gui.soundEditor.robot":"Róbat","gui.soundEditor.louder":"Níos Airde","gui.soundEditor.softer":"Níos Ciúine","gui.soundEditor.reverse":"Aisiompaigh","gui.soundEditor.fadeOut":"Céimnigh amach","gui.soundEditor.fadeIn":"Céimnigh isteach","gui.soundEditor.mute":"Balbhaigh","gui.SpriteInfo.spritePlaceholder":"Ainm","gui.SpriteInfo.sprite":"Sprid","gui.SpriteInfo.show":"Taispeáin","gui.SpriteInfo.size":"Méid","gui.spriteSelectorItem.contextMenuDuplicate":"cóip","gui.spriteSelectorItem.contextMenuExport":"easpórtáil","gui.spriteSelectorItem.contextMenuDelete":"scrios","gui.spriteSelector.addSpriteFromLibrary":"Roghnaigh Sprid","gui.spriteSelector.addSpriteFromPaint":"Péint","gui.spriteSelector.addSpriteFromSurprise":"Randamach","gui.spriteSelector.addSpriteFromFile":"Uaslódáil Sprid","gui.stageHeader.stageSizeLarge":"Úsáid stáitse mór","gui.stageHeader.stageSizeSmall":"Úsáid stáitse beag","gui.stageHeader.stageSizeFull":"Mód lánscáileáin","gui.stageHeader.stageSizeUnFull":"Scoir den lánscáileán","gui.stageHeader.fullscreenControl":"Rialú Lánscáileáin","gui.spriteSelector.addBackdropFromLibrary":"Roghnaigh Cúlra","gui.stageSelector.addBackdropFromPaint":"Péint","gui.stageSelector.addBackdropFromSurprise":"Randamach","gui.stageSelector.addBackdropFromFile":"Uaslódáil Cúlra","gui.stageSelector.stage":"Stáitse","gui.stageSelector.backdrops":"Cúlraí","gui.telemetryOptIn.label":"Roinn staitisticí linn chun Scratch a fheabhsú","gui.telemetryOptIn.body1":"Bíonn Foireann Scratch ag lorg tuiscint níos fearr ar na bealaí a úsáidtear Scratch timpeall an domhain. Chun cabhrú leis seo, is féidir leat cead a thabhairt do Scratch faisnéis úsáide a sheoladh chuig Foireann Scratch go huathoibríoch.","gui.telemetryOptIn.body2":"I measc na faisnéise a bhailímid: do rogha teanga, na blocanna a úsáideann tú, agus uaireanta a dhéanann tú sábháil, lódáil, nó uaslódáil ar thionscadal. NÍ BHAILÍMID aon sonraí pearsanta. Féach ar ár {privacyPolicyLink} chun tuilleadh eolais a fháil.","gui.telemetryOptIn.privacyPolicyLink":"bPolasaí Príobháideachta","gui.telemetryOptIn.optInText":"Comhroinn mo chuid sonraí úsáide le Foireann Scratch","gui.telemetryOptIn.optInTooltip":"Cumasaigh teiliméadaracht","gui.telemetryOptIn.optOutText":"Ná comhroinn mo chuid sonraí úsáide le Foireann Scratch","gui.telemetryOptIn.optOutTooltip":"Díchumasaigh teiliméadaracht","gui.telemetryOptIn.settingWasUpdated":"Sábháladh do rogha.","gui.telemetryOptIn.buttonClose":"Dún","gui.turboMode.active":"Mód Turbó","gui.webglModal.label":"Ní thacaíonn do bhrabhsálaí le WebGL","gui.webglModal.webgllink":"nach dtacaíonn do bhrabhsálaí le WebGL","gui.costumeLibrary.chooseABackdrop":"Roghnaigh Cúlra","gui.costumeLibrary.chooseACostume":"Roghnaigh Culaith","gui.costumeTab.addBackdropFromLibrary":"Roghnaigh Cúlra","gui.costumeTab.addCostumeFromLibrary":"Roghnaigh Culaith","gui.costumeTab.addBlankCostume":"Péint","gui.costumeTab.addSurpriseCostume":"Randamach","gui.costumeTab.addFileBackdrop":"Uaslódáil Cúlra","gui.costumeTab.addFileCostume":"Uaslódáil Culaith","gui.extensionLibrary.chooseAnExtension":"Roghnaigh Breiseán","gui.extensionLibrary.extensionUrl":"Cuir isteach URL an bhreiseáin","gui.monitors.importListColumnPrompt":"An colún le húsáid (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Níorbh fhéidir taifead a thosú","gui.soundLibrary.chooseASound":"Roghnaigh Fuaim","gui.soundTab.fileUploadSound":"Uaslódáil Comhad Fuaime","gui.soundTab.surpriseSound":"Randamach","gui.soundTab.recordSound":"Taifead","gui.soundTab.addSoundFromLibrary":"Roghnaigh Fuaim","gui.spriteLibrary.chooseASprite":"Roghnaigh Sprid","gui.tipsLibrary.tutorials":"Roghnaigh Cúrsa Teagaisc","gui.alerts.createsuccess":"Cruthaíodh an tionscadal nua.","gui.alerts.createcopysuccess":"Sábháladh cóip den tionscadal.","gui.alerts.createremixsuccess":"Sábháladh leagan athmheasctha den tionscadal.","gui.alerts.creating":"Tionscadal nua á chruthú...","gui.alerts.creatingCopy":"An tionscadal á chóipeáil...","gui.alerts.creatingRemix":"An tionscadal á athmheascadh...","gui.alerts.creatingError":"Níorbh fhéidir an tionscadal a chruthú. Bain triail eile as!","gui.alerts.savingError":"Níorbh fhéidir an tionscadal an shábháil.","gui.alerts.savesuccess":"Sábháladh an tionscadal.","gui.alerts.saving":"An tionscadal á shábháil...","gui.alerts.cloudInfo":"Ní féidir leat litreacha nó siombailí a shábháil i néalathróga, uimhreacha amháin. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Tuilleadh eolais.","gui.alerts.importing":"Á Iompórtáil...","gui.defaultProject.variable":"m\'athróg","gui.extension.music.name":"Ceol","gui.extension.music.description":"Casadh ceoil le hionstraimí agus le drumaí.","gui.extension.pen.name":"Peann","gui.extension.pen.description":"Dearadh le do chuid sprideanna.","gui.extension.videosensing.name":"Físbhraiteacht","gui.extension.videosensing.description":"Gluaiseacht a bhrath leis an gceamara.","gui.extension.text2speech.name":"Téacs-go-Caint","gui.extension.text2speech.description":"Tabhair cumas cainte do do thionscadail.","gui.extension.translate.name":"Aistriúchán","gui.extension.translate.description":"Aistriúcháin i mórán teangacha.","gui.extension.makeymakey.description":"Déan eochair as aon rud.","gui.extension.microbit.description":"Cuir do chuid tionscadal os comhair an domhain.","gui.extension.microbit.connectingMessage":"Ceangal","gui.extension.ev3.description":"Róbait idirghníomhacha agus tuilleadh.","gui.extension.ev3.connectingMessage":"Ag ceangal. Deimhnigh gurb é 1234 an PIN ar do EV3.","gui.extension.boost.description":"Cuir beocht i róbat.","gui.extension.boost.connectingMessage":"Ceangal","gui.extension.wedo2.description":"Tógáil le mótair agus le braiteoirí.","gui.extension.wedo2.connectingMessage":"Ceangal","gui.extension.gdxfor.description":"Breiseán a bhraitheann brú, tarraingt, gluaiseacht, agus casadh.","gui.extension.gdxfor.connectingMessage":"Ceangal","gui.libraryTags.all":"Uile","gui.libraryTags.animals":"Ainmhithe","gui.libraryTags.dance":"Damhsa","gui.libraryTags.effects":"Maisíochtaí","gui.libraryTags.fantasy":"Fantaisíocht","gui.libraryTags.fashion":"Faisean","gui.libraryTags.food":"Bia","gui.libraryTags.indoors":"Taobh Istigh","gui.libraryTags.loops":"Lúba","gui.libraryTags.music":"Ceol","gui.libraryTags.notes":"Nótaí","gui.libraryTags.outdoors":"Amuigh Faoin Aer","gui.libraryTags.patterns":"Patrúin","gui.libraryTags.people":"Daoine","gui.libraryTags.percussion":"Cnaguirlisí","gui.libraryTags.space":"Spás","gui.libraryTags.sports":"Spórt","gui.libraryTags.underwater":"Faoi uisce","gui.libraryTags.voice":"Guth","gui.libraryTags.wacky":"Wacky","gui.libraryTags.animation":"Beochan","gui.libraryTags.art":"Ealaín","gui.libraryTags.games":"Cluichí","gui.libraryTags.stories":"Scéalta","gui.libraryTags.letters":"Litreacha","gui.opcodeLabels.direction":"treo","gui.opcodeLabels.xposition":"ionad x","gui.opcodeLabels.yposition":"ionad y","gui.opcodeLabels.size":"méid","gui.opcodeLabels.costumename":"ainm na culaithe","gui.opcodeLabels.costumenumber":"uimhir na culaithe","gui.opcodeLabels.backdropname":"ainm an chúlra","gui.opcodeLabels.backdropnumber":"uimhir an chúlra","gui.opcodeLabels.volume":"airde","gui.opcodeLabels.tempo":"luas","gui.opcodeLabels.answer":"freagra","gui.opcodeLabels.loudness":"treise","gui.opcodeLabels.username":"ainm úsáideora","gui.opcodeLabels.year":"bliain","gui.opcodeLabels.month":"mí","gui.opcodeLabels.date":"dáta","gui.opcodeLabels.dayofweek":"lá den tseachtain","gui.opcodeLabels.hour":"uair","gui.opcodeLabels.minute":"nóiméad","gui.opcodeLabels.second":"soicind","gui.opcodeLabels.timer":"amadóir","gui.sharedMessages.backdrop":"cúlra{index}","gui.sharedMessages.costume":"culaith{index}","gui.sharedMessages.sprite":"Sprid{index}","gui.sharedMessages.pop":"pléasc","gui.sharedMessages.replaceProjectWarning":"An bhfuil tú cinnte gur mhaith leat ábhar an tionscadail reatha a fhorscríobh?","gui.sharedMessages.loadFromComputerTitle":"Lódáil ó do ríomhaire","boost.color.any":"dath ar bith","boost.color.black":"dubh","boost.color.blue":"gorm","boost.color.green":"uaine","boost.color.red":"dearg","boost.color.white":"bán","boost.color.yellow":"buí","boost.getMotorPosition":"ionad mótair [MOTOR_REPORTER_ID]","boost.getTiltAngle":"uillinn chlaonta [TILT_DIRECTION]","boost.motorDirection.backward":"an treo sin","boost.motorDirection.forward":"an treo seo","boost.motorDirection.reverse":"droim ar ais","boost.motorOff":"múch mótar [MOTOR_ID]","boost.motorOn":"cuir mótar [MOTOR_ID] ar siúl","boost.motorOnFor":"cas mótar [MOTOR_ID] ar feadh [DURATION] soicind","boost.motorOnForRotation":"cas mótar [MOTOR_ID] ar feadh [ROTATION] rothlú","boost.seeingColor":"an bhfeictear bríce [COLOR]?","boost.setLightHue":"socraigh dath an tsolais: [HUE]","boost.setMotorDirection":"socraigh treo mótair [MOTOR_ID]: [MOTOR_DIRECTION]","boost.setMotorPower":"socraigh luas mótair [MOTOR_ID]: [POWER] %","boost.tiltDirection.any":"ceann ar bith","boost.tiltDirection.down":"síos","boost.tiltDirection.left":"ar chlé","boost.tiltDirection.right":"ar dheis","boost.tiltDirection.up":"suas","boost.whenColor":"nuair a fheictear bríce [COLOR]","boost.whenTilted":"agus claonta [TILT_DIRECTION_ANY]","ev3.beepNote":"seinn nóta [NOTE] mar bhíp ar feadh [TIME] soicind","ev3.buttonPressed":"cnaipe [PORT] brúite?","ev3.getBrightness":"gile","ev3.getDistance":"fad slí","ev3.getMotorPosition":"treoshuíomh mótair [PORT]","ev3.motorSetPower":"socraigh cumhacht mhótar [PORT]: [POWER]%","ev3.motorTurnClockwise":"cas mótar [PORT] sa treo seo ar feadh [TIME] soicind","ev3.motorTurnCounterClockwise":"cas mótar [PORT] sa treo sin ar feadh [TIME] soicind","ev3.whenBrightnessLessThan":"agus gile < [DISTANCE]","ev3.whenButtonPressed":"agus cnaipe [PORT] brúite","ev3.whenDistanceLessThan":"agus fad < [DISTANCE]","gdxfor.getAcceleration":"luasghéarú [DIRECTION]","gdxfor.getForce":"fórsa","gdxfor.getSpin":"luas casta [DIRECTION]","gdxfor.getTilt":"uillinn chlaonta [TILT]","gdxfor.isFreeFalling":"ag titim?","gdxfor.isTilted":"claonta [TILT]?","gdxfor.pulled":"tarraingthe","gdxfor.pushed":"brúite","gdxfor.shaken":"croite","gdxfor.startedFalling":"tús titime","gdxfor.tiltDirectionMenu.any":"ceann ar bith","gdxfor.tiltDirectionMenu.back":"cúl","gdxfor.tiltDirectionMenu.front":"tosach","gdxfor.tiltDirectionMenu.left":"ar chlé","gdxfor.tiltDirectionMenu.right":"ar dheis","gdxfor.turnedFaceDown":"casta béal faoi","gdxfor.turnedFaceUp":"casta béal suas","gdxfor.whenForcePushedOrPulled":"nuair atá an braiteoir fórsa [PUSH_PULL]","gdxfor.whenGesture":"nuair a bhraitear [GESTURE]","gdxfor.whenTilted":"agus claonta [TILT]","makeymakey.downArrow":"saighead síos","makeymakey.downArrowShort":"síos","makeymakey.leftArrow":"saighead chlé","makeymakey.leftArrowShort":"ar chlé","makeymakey.rightArrow":"saighead dheas","makeymakey.rightArrowShort":"ar dheis","makeymakey.spaceKey":"spás","makeymakey.upArrow":"saighead suas","makeymakey.upArrowShort":"suas","makeymakey.whenKeyPressed":"nuair a bhrúitear eochair [KEY]","makeymakey.whenKeysPressedInOrder":"nuair a bhrúitear [SEQUENCE] in ord","microbit.buttonsMenu.any":"ceann ar bith","microbit.clearDisplay":"glan an scáileán","microbit.defaultTextToDisplay":"Dia dhuit!","microbit.displaySymbol":"taispeáin [MATRIX]","microbit.displayText":"taispeáin téacs [TEXT]","microbit.gesturesMenu.jumped":"léimthe","microbit.gesturesMenu.moved":"bogtha","microbit.gesturesMenu.shaken":"croite","microbit.isButtonPressed":"cnaipe [BTN] brúite?","microbit.isTilted":"claonta [DIRECTION]?","microbit.pinStateMenu.off":"as","microbit.pinStateMenu.on":"ann","microbit.tiltAngle":"uillinn [DIRECTION]","microbit.tiltDirectionMenu.any":"ceann ar bith","microbit.tiltDirectionMenu.back":"cúl","microbit.tiltDirectionMenu.front":"tosach","microbit.tiltDirectionMenu.left":"ar chlé","microbit.tiltDirectionMenu.right":"ar dheis","microbit.whenButtonPressed":"agus cnaipe [BTN] brúite","microbit.whenGesture":"nuair a bhraitear [GESTURE]","microbit.whenPinConnected":"nuair atá pionna [PIN] ceangailte","microbit.whenTilted":"agus claonta i dtreo [DIRECTION]","music.categoryName":"Ceol","music.changeTempo":"athraigh an luas de [TEMPO]","music.drumBass":"(2) Dord-Druma","music.drumBongo":"(13) Bongó","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Clabhaí","music.drumClosedHiHat":"(6) Ard-hata dúnta","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Clog Bó","music.drumCrashCymbal":"(4) Ciombal Plimpe","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guíoró","music.drumHandClap":"(8) Bualadh Bos","music.drumOpenHiHat":"(5) Ard-Hata Oscailte","music.drumSideStick":"(3) Maide Taoibh","music.drumSnare":"(1) Sreangdhruma","music.drumTambourine":"(7) Tambóirín","music.drumTriangle":"(12) Triantán","music.drumVibraslap":"(17) Vibreaslap","music.drumWoodBlock":"(10) Bloc Adhmaid","music.getTempo":"luas","music.instrumentBass":"(6) Dord","music.instrumentBassoon":"(14) Basún","music.instrumentCello":"(8) Dordveidhil","music.instrumentChoir":"(15) Cór","music.instrumentClarinet":"(10) Clairinéad","music.instrumentElectricGuitar":"(5) Giotár Leictreach","music.instrumentElectricPiano":"(2) Pianó Leictreach","music.instrumentFlute":"(12) Fliúit","music.instrumentGuitar":"(4) Giotár","music.instrumentMarimba":"(19) Mairimbe","music.instrumentMusicBox":"(17) Ceolbhosca","music.instrumentOrgan":"(3) Orgán","music.instrumentPiano":"(1) Pianó","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Sacsafón","music.instrumentSteelDrum":"(18) Druma Cruach","music.instrumentSynthLead":"(20) Príomhshintéiseoir","music.instrumentSynthPad":"(21) Ceapshintéiseoir","music.instrumentTrombone":"(9) Trombón","music.instrumentVibraphone":"(16) Vibreafón","music.instrumentWoodenFlute":"(13) Fliúit Adhmaid","music.midiPlayDrumForBeats":"seinn druma [DRUM] ar feadh [BEATS] buille","music.midiSetInstrument":"socraigh an ionstraim: [INSTRUMENT]","music.playDrumForBeats":"seinn druma [DRUM] ar feadh [BEATS] buille","music.playNoteForBeats":"seinn nóta [NOTE] ar feadh [BEATS] buille","music.restForBeats":"stad ar feadh [BEATS] buille","music.setInstrument":"socraigh an ionstraim: [INSTRUMENT]","music.setTempo":"socraigh an luas: [TEMPO]","pen.categoryName":"Peann","pen.changeColorParam":"athraigh [COLOR_PARAM] an phinn de [VALUE]","pen.changeHue":"athraigh dath an phinn de [HUE]","pen.changeShade":"athraigh dorchadas an phinn de [SHADE]","pen.changeSize":"athraigh méid an phinn de [SIZE]","pen.clear":"scrios uile","pen.colorMenu.brightness":"gile","pen.colorMenu.color":"dath","pen.colorMenu.saturation":"sáithiú","pen.colorMenu.transparency":"trédhearcacht","pen.penDown":"peann síos","pen.penUp":"peann suas","pen.setColor":"socraigh dath an phinn: [COLOR]","pen.setColorParam":"socraigh [COLOR_PARAM] an phinn: [VALUE]","pen.setHue":"socraigh dath an phinn: [HUE]","pen.setShade":"socraigh dorchadas an phinn: [SHADE]","pen.setSize":"socraigh méid an phinn: [SIZE]","pen.stamp":"stampa","text2speech.alto":"alt","text2speech.categoryName":"Téacs-go-Caint","text2speech.defaultTextToSpeak":"dia dhuit","text2speech.giant":"fathach","text2speech.kitten":"piscín","text2speech.setLanguageBlock":"socraigh an teanga: [LANGUAGE]","text2speech.setVoiceBlock":"socraigh an guth: [VOICE]","text2speech.speakAndWaitBlock":"abair [WORDS]","text2speech.squeak":"gíog","text2speech.tenor":"teanór","translate.categoryName":"Aistriúchán","translate.defaultTextToTranslate":"dia dhuit","translate.translateBlock":"aistrigh [WORDS] go [LANGUAGE]","translate.viewerLanguage":"teanga","videoSensing.categoryName":"Físbhraiteacht","videoSensing.direction":"treo","videoSensing.motion":"gluaiseacht","videoSensing.off":"as","videoSensing.on":"ann","videoSensing.onFlipped":"ann-smeachta","videoSensing.setVideoTransparency":"socraigh an trédhearcacht físe: [TRANSPARENCY]","videoSensing.sprite":"sprid","videoSensing.stage":"stáitse","videoSensing.videoOn":"[ATTRIBUTE] físe ar [SUBJECT]","videoSensing.videoToggle":"cas an físeán [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"Nuair atá físghluaiseacht > [REFERENCE]","wedo2.getDistance":"fad slí","wedo2.getTiltAngle":"uillinn chlaonta [TILT_DIRECTION]","wedo2.isTilted":"claonta [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"an treo sin","wedo2.motorDirection.forward":"an treo seo","wedo2.motorDirection.reverse":"droim ar ais","wedo2.motorId.a":"mótar A","wedo2.motorId.all":"gach mótar","wedo2.motorId.b":"mótar B","wedo2.motorId.default":"mótar","wedo2.motorOff":"múch [MOTOR_ID]","wedo2.motorOn":"cuir [MOTOR_ID] ar siúl","wedo2.motorOnFor":"cuir [MOTOR_ID] ar siúl ar feadh [DURATION] soicind","wedo2.playNoteFor":"seinn nóta [NOTE] ar feadh [DURATION] soicind","wedo2.setLightHue":"socraigh dath an tsolais: [HUE]","wedo2.setMotorDirection":"socraigh treo [MOTOR_ID]: [MOTOR_DIRECTION]","wedo2.startMotorPower":"socraigh cumhacht [MOTOR_ID]: [POWER]","wedo2.tiltDirection.any":"ceann ar bith","wedo2.tiltDirection.down":"síos","wedo2.tiltDirection.left":"ar chlé","wedo2.tiltDirection.right":"ar dheis","wedo2.tiltDirection.up":"suas","wedo2.whenDistance":"agus fad [OP] [REFERENCE]","wedo2.whenTilted":"agus claonta [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Dath","paint.paintEditor.saturation":"Sáithiú","paint.paintEditor.brightness":"Gile","paint.paintEditor.costume":"Culaith","paint.paintEditor.group":"Grúpa","paint.paintEditor.ungroup":"Díghrúpáil","paint.paintEditor.undo":"Cealaigh","paint.paintEditor.redo":"Athdhéan","paint.paintEditor.forward":"Ar aghaidh","paint.paintEditor.backward":"Ar gcúl","paint.paintEditor.front":"Chun tosaigh","paint.paintEditor.back":"Chun deiridh","paint.paintEditor.more":"Tuilleadh","paint.modeTools.brushSize":"Méid","paint.modeTools.eraserSize":"Méid an léirscriosáin","paint.modeTools.copy":"Cóipeáil","paint.modeTools.paste":"Greamaigh","paint.modeTools.delete":"Scrios","paint.modeTools.curved":"Cuartha","paint.modeTools.pointed":"Bioraithe","paint.modeTools.thickness":"Leithead","paint.modeTools.flipHorizontal":"Smeach go cothrománach","paint.modeTools.flipVertical":"Smeach go hingearach","paint.modeTools.filled":"Líonta","paint.modeTools.outlined":"Imlínithe","paint.paintEditor.bitmap":"Tiontaigh go mapa giotán","paint.paintEditor.vector":"Mód Veicteora","paint.paintEditor.fill":"Líon","paint.paintEditor.stroke":"Imlíne","paint.brushMode.brush":"Scuab","paint.eraserMode.eraser":"Léirscriosán","paint.fillMode.fill":"Líon","paint.lineMode.line":"Líne","paint.ovalMode.oval":"Ciorcal","paint.rectMode.rect":"Dronuilleog","paint.reshapeMode.reshape":"Athdheilbhigh","paint.roundedRectMode.roundedRect":"Dronuilleog Chruinn","paint.selectMode.select":"Roghnaigh","paint.textMode.text":"Téacs","paint.colorPicker.swap":"Babhtáil"},"gd":{"gui.alerts.tryAgain":"Feuch ris a-rithist","gui.alerts.download":"Luchdaich a-nuas","gui.connection.reconnect":"Ath-cheangail","gui.backpack.costumeLabel":"dreach","gui.backpack.soundLabel":"fuaim","gui.backpack.scriptLabel":"sgriobt","gui.backpack.spriteLabel":"sprìd","gui.backpack.header":"Màla-droma","gui.backpack.errorBackpack":"Mearachd le luchdadh na màla-droma","gui.backpack.loadingBackpack":"’Ga luchdadh…","gui.backpack.more":"Barrachd","gui.backpack.emptyBackpack":"Tha a’ mhàla-droma falamh","gui.unsupportedBrowser.label":"Cha chuir sinn taic ris a’ bhrabhsair","gui.cards.all-tutorials":"Oideachadh","gui.cards.shrink":"Crùb","gui.cards.expand":"Leudaich","gui.cards.close":"Dùin","gui.cards.more-things-to-try":"Barrachd rudan ri am feuchainn!","gui.cards.see-more":"Seall a bharrachd","gui.comingSoon.message1":"Na gabh dragh, tha sinn ag obair air {emoji}","gui.comingSoon.message2":"Ri thighinn a dh’aithghearr…","gui.comingSoon.message3":"Tha sinn ag obair air {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Cha deach uidheam a lorg","gui.connection.auto-scanning.prescan":"Cuir an t-uidheam agad faisg air is dèan lorg an uairsin.","gui.connection.auto-scanning.pressbutton":"Brùth air a’ phutan air an uidheam agad.","gui.connection.auto-scanning.start-search":"Dèan lorg","gui.connection.connecting-searchbutton":"Ga lorg…","gui.connection.auto-scanning.try-again":"Feuch ris a‑rithist","gui.connection.connected":"Ceangailte","gui.connection.disconnect":"Bris an ceangal","gui.connection.go-to-editor":"Rach dhan deasaiche","gui.connection.connecting-cancelbutton":"Ga cheangal…","gui.connection.error.errorMessage":"Oich, tha coltas gun deach rudeigin ceàrr.","gui.connection.error.tryagainbutton":"Feuch ris a‑rithist","gui.connection.error.helpbutton":"Cobhair","gui.connection.peripheral-name-label":"Ainm an uidheim","gui.connection.connect":"Ceangail","gui.connection.scanning.lookingforperipherals":"A’ lorg nan uidheaman","gui.connection.scanning.noPeripheralsFound":"Cha deach uidheam a lorg","gui.connection.scanning.instructions":"Tagh an t‑uidheam agad san liosta gu h‑àrd.","gui.connection.search":"Ath-nuadhaich","gui.connection.unavailable.installscratchlink":"Dèan cinnteach gun deach Scratch Link a stàladh ’s gu bheil e ga ruith","gui.connection.unavailable.enablebluetooth":"Dèan cinnteach gu bheil Bluetooth an comas","gui.connection.unavailable.tryagainbutton":"Feuch ris a‑rithist","gui.connection.unavailable.helpbutton":"Cobhair","gui.controls.go":"Siuthad","gui.controls.stop":"Cuir stad air","gui.crashMessage.label":"Oich! Chaidh rudeigin ceàrr.","gui.crashMessage.errorNumber":"Chaidh a’ mhearachd agad a chlàradh le ID {errorId}","gui.crashMessage.reload":"Ath-luchdaich","gui.customProcedures.myblockModalTitle":"Cruthaich bloca","gui.customProcedures.addAnInputNumberText":"Cuir raon ris","gui.customProcedures.numberTextType":"àireamh no teacsa","gui.customProcedures.addAnInputBoolean":"Cuir raon ris","gui.customProcedures.booleanType":"Booleach","gui.customProcedures.addALabel":"Cuir leubail ris","gui.customProcedures.runWithoutScreenRefresh":"Ruith às aonais ath-nuadhachadh na sgrìn","gui.customProcedures.cancel":"Sguir dheth","gui.customProcedures.ok":"Ceart ma-thà","gui.SpriteInfo.direction":"Comhair","gui.directionPicker.rotationStyles.allAround":"Cuairt shlàn","gui.directionPicker.rotationStyles.leftRight":"Gu clì/deas","gui.directionPicker.rotationStyles.dontRotate":"Na cuairtich","gui.gui.addExtension":"Cuir leudachan ris","gui.gui.codeTab":"Còd","gui.gui.backdropsTab":"Cùlaibhean","gui.gui.costumesTab":"Dreachan","gui.gui.soundsTab":"Fuaimean","gui.extensionLibrary.comingSoon":"Ri thighinn a dh’aithghearr","gui.extensionLibrary.requires":"Riatanasan","gui.extensionLibrary.collaboration":"Co-obrachadh le","gui.library.filterPlaceholder":"Lorg","gui.library.allTag":"Na h-uile","gui.loader.headline":"A’ luchdadh a’ phròiseict","gui.loader.creating":"A’ cruthachadh pròiseact","gui.authorInfo.byUser":"le {username}","gui.menuBar.seeProjectPage":"Seall duilleag a’ phròiseict","gui.menuBar.LanguageSelector":"roghnaichear nan cànan","gui.menuBar.tutorialsLibrary":"Oideachadh","gui.menuBar.restoreSprite":"Aisig an an sprìd","gui.menuBar.restoreSound":"Aisig an fhuaim","gui.menuBar.restoreCostume":"Aisig an dreach","gui.menuBar.restore":"Aisig","gui.menuBar.saveNow":"Sàbhail an-dràsta","gui.menuBar.saveAsCopy":"Sàbhail mar lethbhreac","gui.menuBar.remix":"Ath-mheasgaich","gui.menuBar.new":"Ùr","gui.menuBar.file":"Faidhle","gui.menuBar.downloadToComputer":"Sàbhail air a’ choimpiutair agad","gui.menuBar.edit":"Deasaich","gui.menuBar.turboModeOff":"Cuir dheth am modh turbo","gui.menuBar.turboModeOn":"Cuir air am modh turbo","gui.gui.projectTitlePlaceholder":"Cuir ainm a’ pròiseict an-seo","gui.menuBar.isShared":"Air a cho-roinneadh","gui.menuBar.share":"Co-roinn","gui.modal.help":"Cobhair","gui.modal.back":"Air ais","gui.monitor.listMonitor.empty":"(falamh)","gui.monitor.listMonitor.listLength":"faide {length}","gui.monitor.contextMenu.default":"sealladh àbhaisteach","gui.monitor.contextMenu.large":"sealladh mòr","gui.monitor.contextMenu.slider":"an sleamhnachan","gui.monitor.contextMenu.sliderRange":"atharraich rainse an t-sleamhnachain","gui.monitor.contextMenu.import":"ion-phortaich","gui.monitor.contextMenu.export":"às-phortaich","gui.monitor.contextMenu.hide":"falaich","gui.playButton.play":"Cluich","gui.playButton.stop":"Cuir stad air","gui.gui.variableScopeOptionAllSprites":"Airson a h‑uile sprìd","gui.gui.variableScopeOptionSpriteOnly":"Airson na sprìde seo a‑mhàin","gui.gui.cloudVariableOption":"Caochladair neòil (ga stòradh air an fhrithealaiche)","gui.gui.variablePromptAllSpritesMessage":"Bidh an caochladair seo ri làimh dhan a h‑uile sprìd.","gui.gui.listPromptAllSpritesMessage":"Bidh an liosta seo ri làimh dhan a h‑uile sprìd.","gui.prompt.cancel":"Sguir dheth","gui.prompt.ok":"Ceart ma-thà","gui.playbackStep.stopMsg":"Cuir stad air","gui.playbackStep.playMsg":"Cluich","gui.playbackStep.loadingMsg":"Ga luchdadh…","gui.playbackStep.saveMsg":"Sàbhail","gui.playbackStep.reRecordMsg":"Clàraich a‑rithist e","gui.recordModal.title":"Clàraich fuaim","gui.recordingStep.beginRecord":"Briog air a’ phutan gu h-ìosal a thòiseachadh leis a’ chlàradh","gui.recordingStep.permission":"{arrow}Tha sinn feumach air cead gus am micreofon agad a chleachdadh","gui.recordingStep.stop":"Cuir stad air a’ chlàradh","gui.recordingStep.record":"Clàraich","gui.sliderModal.min":"Luach as lugha","gui.sliderModal.max":"Luach as motha","gui.sliderModal.title":"Atharraich rainse an t-sleamhnachain","gui.sliderPrompt.cancel":"Sguir dheth","gui.sliderPrompt.ok":"Ceart ma-thà","gui.soundEditor.sound":"Fuaim","gui.soundEditor.play":"Cluich","gui.soundEditor.stop":"Cuir stad air","gui.soundEditor.copy":"Dèan lethbhreac","gui.soundEditor.paste":"Cuir ann","gui.soundEditor.copyToNew":"Cuir lethbhreac gu fear ùr","gui.soundEditor.delete":"Sguab às","gui.soundEditor.save":"Sàbhail","gui.soundEditor.undo":"Neo-dhèan","gui.soundEditor.redo":"Ath-dhèan","gui.soundEditor.faster":"Nas luaithe","gui.soundEditor.slower":"Nas maille","gui.soundEditor.echo":"Mac-talla","gui.soundEditor.robot":"Robotair","gui.soundEditor.louder":"Nas àirde","gui.soundEditor.softer":"Nas ìsle","gui.soundEditor.reverse":"Contrarra","gui.soundEditor.fadeOut":"Crìon a-mach","gui.soundEditor.fadeIn":"Crìon a-steach","gui.soundEditor.mute":"Mùch","gui.SpriteInfo.spritePlaceholder":"Ainm","gui.SpriteInfo.sprite":"Sprìd","gui.SpriteInfo.show":"Seall","gui.SpriteInfo.size":"Meud","gui.spriteSelectorItem.contextMenuDuplicate":"dùblaich","gui.spriteSelectorItem.contextMenuExport":"às-phortaich","gui.spriteSelectorItem.contextMenuDelete":"sguab às","gui.spriteSelector.addSpriteFromLibrary":"Tagh sprìd","gui.spriteSelector.addSpriteFromPaint":"Peant","gui.spriteSelector.addSpriteFromSurprise":"Tagh tè dhomh","gui.spriteSelector.addSpriteFromFile":"Luchdaich suas sprìd","gui.stageHeader.stageSizeLarge":"Atharraich gu àrd-ùrlar mòr","gui.stageHeader.stageSizeSmall":"Atharraich gu àrd-ùrlar beag","gui.stageHeader.stageSizeFull":"Modh na làn-sgrìn","gui.stageHeader.stageSizeUnFull":"Fàg modh na làn-sgrìn","gui.stageHeader.fullscreenControl":"Toglaich am modh làn-sgrìn","gui.spriteSelector.addBackdropFromLibrary":"Tagh cùlaibh","gui.stageSelector.addBackdropFromPaint":"Peant","gui.stageSelector.addBackdropFromSurprise":"Tagh fear dhomh","gui.stageSelector.addBackdropFromFile":"Luchdaich suas cùlaibh","gui.stageSelector.stage":"Àrd-ùrlar","gui.stageSelector.backdrops":"Cùlaibhean","gui.telemetryOptIn.label":"Aithris stadastaireachd a chum leasachadh Scratch","gui.telemetryOptIn.body1":"Mu mhiann le sgioba Scratch tuigsinn mar a thathar a’ cleachdadh Scratch air feadh an t-saoghail. Airson taic a chur ri sin, ’s urrainn dhut cead a thoirt do Scratch ach an cuir sinn fiosrachadh mun chleachdadh gu sgioba Scratch gu fèin-obrachail.","gui.telemetryOptIn.body2":"Gabhaidh am fiosrachadh a chruinnicheas sinn a-staigh roghainn a’ chànan, cleachdadh nam blocaichean agus chuid a thachartasan, can sàbhaladh, luchdadh is luchdadh suas pròiseict. Cha chruinnich sinn fiosrachadh pearsanta idir. Seall am {privacyPolicyLink} againn airson barrachd fiorachaidh.","gui.telemetryOptIn.privacyPolicyLink":"Poileasaidh prìobhaideachd","gui.telemetryOptIn.optInText":"Co-roinn dàta a’ chleachdaidh agam le sgioba Scratch","gui.telemetryOptIn.optInTooltip":"Cuir an telemeatraidh an comas","gui.telemetryOptIn.optOutText":"Na co-roinn dàta a’ chleachdaidh agam le sgioba Scratch","gui.telemetryOptIn.optOutTooltip":"Cuir an telemeatraidh à comas","gui.telemetryOptIn.settingWasUpdated":"Chaidh an roghainn agad ùrachadh.","gui.telemetryOptIn.buttonClose":"Dùin","gui.turboMode.active":"Modh turbo","gui.webglModal.label":"Cha chuir am brabhsair agad taic ri WebGL","gui.webglModal.webgllink":"taic ri WebGL","gui.costumeLibrary.chooseABackdrop":"Tagh cùlaibh","gui.costumeLibrary.chooseACostume":"Tagh dreach","gui.costumeTab.addBackdropFromLibrary":"Tagh cùlaibh","gui.costumeTab.addCostumeFromLibrary":"Tagh dreach","gui.costumeTab.addBlankCostume":"Peant","gui.costumeTab.addSurpriseCostume":"Tagh fear dhomh","gui.costumeTab.addFileBackdrop":"Luchdaich suas cùlaibh","gui.costumeTab.addFileCostume":"Luchdaich suas dreach","gui.extensionLibrary.chooseAnExtension":"Tagh leudachan","gui.extensionLibrary.extensionUrl":"Cuir a‑steach URL an leudachain","gui.monitors.importListColumnPrompt":"Dè an colbh (1-{numberOfColumns}) a bu chòir dhuinn cleachdadh?","gui.recordingStep.alertMsg":"Cha b’ urrainn dhuinn tòiseachadh air a’ chlàradh","gui.soundLibrary.chooseASound":"Tagh fuaim","gui.soundTab.fileUploadSound":"Luchdaich suas fuaim","gui.soundTab.surpriseSound":"Tagh tè dhomh","gui.soundTab.recordSound":"Clàraich","gui.soundTab.addSoundFromLibrary":"Tagh fuaim","gui.spriteLibrary.chooseASprite":"Tagh sprìd","gui.tipsLibrary.tutorials":"Tagh oideachadh","gui.alerts.createsuccess":"Chaidh pròiseact ùr a chruthachadh.","gui.alerts.createcopysuccess":"Chaidh am pròiseact a shàbhaladh mar lethbhreac.","gui.alerts.createremixsuccess":"Chaidh am pròiseact a shàbhaladh mar ath-mheasgachadh.","gui.alerts.creating":"A’ cruthachadh fear ùr…","gui.alerts.creatingCopy":"A’ dèanamh lethbhreac den pròiseact…","gui.alerts.creatingRemix":"Ag ath-mheasgachadh a’ phròiseict…","gui.alerts.creatingError":"Cha b’ urrainn dhuinn am pròiseact a chruthachadh. Am feuch thu ris a-rithist?","gui.alerts.savingError":"Cha b’ urrainn dhuinn am pròiseact a shàbhaladh.","gui.alerts.savesuccess":"Chaidh am pròiseact a shàbhaladh.","gui.alerts.saving":"A’ sàbhaladh a’ pròiseict…","gui.alerts.cloudInfo":"Thoir an aire nach cuir caochladairean neòil taic ach ri àireamhan seach litrichean no samhlaidhean. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Barrachd fiosrachaidh.","gui.alerts.importing":"Ga ion-phortadh…","gui.defaultProject.variable":"an caochladair agam","gui.extension.music.name":"Ceòl","gui.extension.music.description":"Cluich innealan-ciùil is drumaichean.","gui.extension.pen.name":"Peann","gui.extension.pen.description":"Tarraing leis na sprìdean agad.","gui.extension.videosensing.name":"Mothachadh video","gui.extension.videosensing.description":"Mothaich do ghluasad leis a’ chamara.","gui.extension.text2speech.name":"Teacsa na chainnt","gui.extension.text2speech.description":"Cuir comas bruidhinn air na pròiseactan agad.","gui.extension.translate.name":"Eadar-theangaich","gui.extension.translate.description":"Eadar-theangaich teacsa gu iomadh cànan.","gui.extension.makeymakey.description":"Dèan iuchair de rud sam bith.","gui.extension.microbit.description":"Ceanglaich na pròiseactan agad ris an t-saoghal.","gui.extension.microbit.connectingMessage":"Ceangal","gui.extension.ev3.description":"Tog robotairean eadar-ghnìomhach is a bharrachd.","gui.extension.ev3.connectingMessage":"’Ga cheangal. Dèan cinnteach gun deach am PIN aig an EV3 agad a shuidheachadh air 1234.","gui.extension.boost.description":"Beòthaich robotairean.","gui.extension.boost.connectingMessage":"Ceangal","gui.extension.wedo2.description":"Tog nithean le einnseanan is mothaichearan.","gui.extension.wedo2.connectingMessage":"Ceangal","gui.extension.gdxfor.description":"Mothaich do bhrùthadh, tarraing, gluasad is cuairteachadh.","gui.extension.gdxfor.connectingMessage":"Ceangal","gui.libraryTags.all":"Na h-uile","gui.libraryTags.animals":"Beathaichean","gui.libraryTags.dance":"Dannsa","gui.libraryTags.effects":"Èifeachdan","gui.libraryTags.fantasy":"Fantastachd","gui.libraryTags.fashion":"Fasan","gui.libraryTags.food":"Biadh","gui.libraryTags.indoors":"Taobh a-staigh","gui.libraryTags.loops":"Lùban","gui.libraryTags.music":"Ceòl","gui.libraryTags.notes":"Pongan","gui.libraryTags.outdoors":"Taobh a-muigh","gui.libraryTags.patterns":"Pàtranan","gui.libraryTags.people":"Daoine","gui.libraryTags.percussion":"Beum-ionnsramaid","gui.libraryTags.space":"Fànas","gui.libraryTags.sports":"Spòrs","gui.libraryTags.underwater":"Fon uisge","gui.libraryTags.voice":"Guth","gui.libraryTags.wacky":"Èibhinn","gui.libraryTags.animation":"Beòthachadh","gui.libraryTags.art":"Ealan","gui.libraryTags.games":"Geamannan","gui.libraryTags.stories":"Sgeòil","gui.libraryTags.letters":"Litrichean","gui.opcodeLabels.direction":"comhair","gui.opcodeLabels.xposition":"ionad x","gui.opcodeLabels.yposition":"ionad y","gui.opcodeLabels.size":"meud","gui.opcodeLabels.costumename":"ainm an dreacha","gui.opcodeLabels.costumenumber":"àireamh an dreacha","gui.opcodeLabels.backdropname":"ainm a’ chùlaibh","gui.opcodeLabels.backdropnumber":"àireamh a’ chùlaibh","gui.opcodeLabels.volume":"àirde na fuaime","gui.opcodeLabels.tempo":"luaths","gui.opcodeLabels.answer":"freagairt","gui.opcodeLabels.loudness":"àirde na fuaime","gui.opcodeLabels.username":"ainm-cleachdaiche","gui.opcodeLabels.year":"am bliadhna","gui.opcodeLabels.month":"am mìos","gui.opcodeLabels.date":"an ceann-là","gui.opcodeLabels.dayofweek":"latha na seachdaine","gui.opcodeLabels.hour":"an uair","gui.opcodeLabels.minute":"a’ mhionaid","gui.opcodeLabels.second":"an diog","gui.opcodeLabels.timer":"an tìmear","gui.sharedMessages.backdrop":"cùlaibh{index}","gui.sharedMessages.costume":"dreach{index}","gui.sharedMessages.sprite":"Sprìd{index}","gui.sharedMessages.pop":"cnap","gui.sharedMessages.replaceProjectWarning":"A bheil thu airson seo a chur an àite susbaint a’ phròiseict làithrich?","gui.sharedMessages.loadFromComputerTitle":"Luchdaich on choimpiutair agad","boost.color.any":"sam bith","boost.color.black":"dhubh","boost.color.blue":"ghorm","boost.color.green":"uaine","boost.color.red":"dhearg","boost.color.white":"gheal","boost.color.yellow":"bhuidhe","boost.getMotorPosition":"ionad a’ mhotair [MOTOR_REPORTER_ID]","boost.getTiltAngle":"ceàrn claonaidh [TILT_DIRECTION]","boost.motorDirection.backward":"an dàrna taobh","boost.motorDirection.forward":"an taobh eile","boost.motorDirection.reverse":"comhair contrarra","boost.motorOff":"cuir motar [MOTOR_ID] dheth","boost.motorOn":"cuir motar [MOTOR_ID] air","boost.motorOnFor":"cuairtich motar [MOTOR_ID] fad [DURATION] diog","boost.motorOnForRotation":"cuir [ROTATION] car air motar [MOTOR_ID]","boost.seeingColor":"thu a’ faicinn breige [COLOR]","boost.setLightHue":"suidhich dath an t-solais air [HUE]","boost.setMotorDirection":"cuir motar [MOTOR_ID] an comhair [MOTOR_DIRECTION]","boost.setMotorPower":"suidhich luaths a’ mhotair [MOTOR_ID] air [POWER] %","boost.tiltDirection.any":"sam bith","boost.tiltDirection.down":"sìos","boost.tiltDirection.left":"gu clì","boost.tiltDirection.right":"gu deas","boost.tiltDirection.up":"suas","boost.whenColor":"nuair a chì thu breige [COLOR]","boost.whenTilted":"le claonadh [TILT_DIRECTION_ANY]","ev3.beepNote":"bìd pong [NOTE] fad [TIME] diog","ev3.buttonPressed":"putan [PORT] ga bhrùthadh","ev3.getBrightness":"soilleireachd","ev3.getDistance":"astar","ev3.getMotorPosition":"ionad a’ mhotair [PORT]","ev3.motorSetPower":"suidhich cumhachd motar [PORT] air [POWER] %","ev3.motorTurnClockwise":"gluais motar [PORT] dhan dàrna taobh fad [TIME] diog","ev3.motorTurnCounterClockwise":"gluais motar [PORT] dhan taobh eile fad [TIME] diog","ev3.whenBrightnessLessThan":"nuair a thèid an t-soilleireachd < [DISTANCE]","ev3.whenButtonPressed":"le brùthadh air putan [PORT]","ev3.whenDistanceLessThan":"nuair a thèid an t-astar < [DISTANCE]","gdxfor.getAcceleration":"luathachadh [DIRECTION]","gdxfor.getForce":"forsa","gdxfor.getSpin":"luaths a’ chuir [DIRECTION]","gdxfor.getTilt":"ceàrn claonaidh [TILT]","gdxfor.isFreeFalling":"a’ tuiteam","gdxfor.isTilted":"claonadh [TILT] air","gdxfor.pulled":"tarraing","gdxfor.pushed":"brùthadh","gdxfor.shaken":"crith","gdxfor.startedFalling":"tòiseachadh tuiteim","gdxfor.tiltDirectionMenu.any":"sam bith","gdxfor.tiltDirectionMenu.back":"dhan chùlaibh","gdxfor.tiltDirectionMenu.front":"dhan bheulaibh","gdxfor.tiltDirectionMenu.left":"gu clì","gdxfor.tiltDirectionMenu.right":"gu deas","gdxfor.turnedFaceDown":"beul fodha","gdxfor.turnedFaceUp":"aghaidh os a chionn","gdxfor.whenForcePushedOrPulled":"le [PUSH_PULL] air mothaichear an fhorsa","gdxfor.whenGesture":"le mothachadh air [GESTURE]","gdxfor.whenTilted":"le claonadh [TILT]","makeymakey.downArrow":"saighead sìos","makeymakey.downArrowShort":"sìos","makeymakey.leftArrow":"saighead gu clì","makeymakey.leftArrowShort":"gu clì","makeymakey.rightArrow":"saighead gu deas","makeymakey.rightArrowShort":"gu deas","makeymakey.spaceKey":"spàs","makeymakey.upArrow":"saighead suas","makeymakey.upArrowShort":"suas","makeymakey.whenKeyPressed":"le brùthadh iuchrach [KEY]","makeymakey.whenKeysPressedInOrder":"nuair a bhrùthar air [SEQUENCE] às dèidh a chèile","microbit.buttonsMenu.any":"sam bith","microbit.clearDisplay":"falamhaich an sgrìn","microbit.defaultTextToDisplay":"Shin thu!","microbit.displaySymbol":"seall [MATRIX]","microbit.displayText":"seall an teacsa [TEXT]","microbit.gesturesMenu.jumped":"leum","microbit.gesturesMenu.moved":"gluasad","microbit.gesturesMenu.shaken":"crith","microbit.isButtonPressed":"putan [BTN] ga bhrùthadh","microbit.isTilted":"claonadh [DIRECTION] air","microbit.pinStateMenu.off":"dheth","microbit.pinStateMenu.on":"air","microbit.tiltAngle":"ceàrn claonaidh [DIRECTION]","microbit.tiltDirectionMenu.any":"sam bith","microbit.tiltDirectionMenu.back":"dhan chùlaibh","microbit.tiltDirectionMenu.front":"dhan bheulaibh","microbit.tiltDirectionMenu.left":"gu clì","microbit.tiltDirectionMenu.right":"gu deas","microbit.whenButtonPressed":"le brùthadh air putan [BTN]","microbit.whenGesture":"le mothachadh air [GESTURE]","microbit.whenPinConnected":"nuair a thèid prìne [PIN] a cheangal","microbit.whenTilted":"le claonadh [DIRECTION]","music.categoryName":"Ceòl","music.changeTempo":"atharraich an luaths le [TEMPO]","music.drumBass":"(2) Beus-dhruma","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) Hi-hat dùinte","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Clag bà","music.drumCrashCymbal":"(4) Ciombal crash","music.drumCuica":"(18) Cuíca","music.drumGuiro":"(16) Güiro","music.drumHandClap":"(8) Bualadh bhasan","music.drumOpenHiHat":"(5) Hi-hat fosgailte","music.drumSideStick":"(3) Taobh biorain","music.drumSnare":"(1) Druma-tormain","music.drumTambourine":"(7) Guit-dhruma","music.drumTriangle":"(12) Triantan","music.drumVibraslap":"(17) Crith-sgleog","music.drumWoodBlock":"(10) Bloca fiodha","music.getTempo":"luaths","music.instrumentBass":"(6) Beus","music.instrumentBassoon":"(14) Torm-fheadan","music.instrumentCello":"(8) Beus-fhìdheall","music.instrumentChoir":"(15) Còisir","music.instrumentClarinet":"(10) Clàirneid","music.instrumentElectricGuitar":"(5) Giotàr dealain","music.instrumentElectricPiano":"(2) Piàno dealain","music.instrumentFlute":"(12) Duiseal","music.instrumentGuitar":"(4) Giotàr","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Bogsa-ciùil","music.instrumentOrgan":"(3) Organ","music.instrumentPiano":"(1) Piàno","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Sacsafon","music.instrumentSteelDrum":"(18) Druma stàillinn","music.instrumentSynthLead":"(20) Sinteisear seirme","music.instrumentSynthPad":"(21) Sinteisear pada","music.instrumentTrombone":"(9) Trompan","music.instrumentVibraphone":"(16) Critheafon","music.instrumentWoodenFlute":"(13) Duiseal fiodha","music.midiPlayDrumForBeats":"cluich druma [DRUM] fad [BEATS] buille","music.midiSetInstrument":"suidhich an t‑inneal-ciùil air [INSTRUMENT]","music.playDrumForBeats":"cluich druma [DRUM] fad [BEATS] buille","music.playNoteForBeats":"cluich pong [NOTE] fad [BEATS] buille","music.restForBeats":"tost fad [BEATS] buille","music.setInstrument":"suidhich an t‑inneal-ciùil air [INSTRUMENT]","music.setTempo":"suidhich an luaths air [TEMPO]","pen.categoryName":"Peann","pen.changeColorParam":"atharraich [COLOR_PARAM] a’ phinn le [VALUE]","pen.changeHue":"atharraich dath a’ phinn le [HUE]","pen.changeShade":"atharraich tuar a’ phinn le [SHADE]","pen.changeSize":"atharraich meud a’ phinn le [SIZE]","pen.clear":"suath às na h‑uile","pen.colorMenu.brightness":"soilleireachd","pen.colorMenu.color":"dath","pen.colorMenu.saturation":"sàthachd","pen.colorMenu.transparency":"trìd-shoillearachd","pen.penDown":"peann sìos","pen.penUp":"peann suas","pen.setColor":"suidhich dath a’ phinn air [COLOR]","pen.setColorParam":"suidhich [COLOR_PARAM] a’ phinn air [VALUE]","pen.setHue":"suidhich dath a’ phinn air [HUE]","pen.setShade":"suidhich tuar a’ phinn air [SHADE]","pen.setSize":"suidhich meud a’ phinn air [SIZE]","pen.stamp":"stampa","text2speech.alto":"alto","text2speech.categoryName":"Teacsa na chainnt","text2speech.defaultTextToSpeak":"shin thu","text2speech.giant":"famhair","text2speech.kitten":"piseag","text2speech.setLanguageBlock":"suidhich an cànan air [LANGUAGE]","text2speech.setVoiceBlock":"suidhich a’ ghuth air [VOICE]","text2speech.speakAndWaitBlock":"can [WORDS] gu h-àrd","text2speech.squeak":"bìog","text2speech.tenor":"tenor","translate.categoryName":"Eadar-theangaich","translate.defaultTextToTranslate":"shin thu","translate.translateBlock":"eadar-theangaich [WORDS] gu [LANGUAGE]","translate.viewerLanguage":"cànan","videoSensing.categoryName":"Mothachadh video","videoSensing.direction":"comhair","videoSensing.motion":"gluasad","videoSensing.off":"dheth","videoSensing.on":"air","videoSensing.onFlipped":"air, le flip","videoSensing.setVideoTransparency":"suidhich trìd-shoillse a’ video air [TRANSPARENCY]","videoSensing.sprite":"an sprìd","videoSensing.stage":"an àrd-ùrlar","videoSensing.videoOn":"[ATTRIBUTE] a’ video air [SUBJECT]","videoSensing.videoToggle":"cuir a’ video [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"nuair a thèid gluasad a’ video > [REFERENCE]","wedo2.getDistance":"astar","wedo2.getTiltAngle":"ceàrn claonaidh [TILT_DIRECTION]","wedo2.isTilted":"claonadh [TILT_DIRECTION_ANY] air","wedo2.motorDirection.backward":"an dàrna taobh","wedo2.motorDirection.forward":"an taobh eile","wedo2.motorDirection.reverse":"comhair contrarra","wedo2.motorId.a":"motar A","wedo2.motorId.all":"a h-uile motar","wedo2.motorId.b":"motar B","wedo2.motorId.default":"motar","wedo2.motorOff":"cuir [MOTOR_ID] dheth","wedo2.motorOn":"cuir [MOTOR_ID] air","wedo2.motorOnFor":"cuir [MOTOR_ID] air fad [DURATION] diog","wedo2.playNoteFor":"cluich pong [NOTE] fad [DURATION] diog","wedo2.setLightHue":"suidhich dath an t-solais air [HUE]","wedo2.setMotorDirection":"suidhich comhair [MOTOR_ID] air [MOTOR_DIRECTION]","wedo2.startMotorPower":"suidhich cumhachd [MOTOR_ID] air [POWER]","wedo2.tiltDirection.any":"sam bith","wedo2.tiltDirection.down":"sìos","wedo2.tiltDirection.left":"gu clì","wedo2.tiltDirection.right":"gu deas","wedo2.tiltDirection.up":"suas","wedo2.whenDistance":"nuair a thèid an t-astar [OP] [REFERENCE]","wedo2.whenTilted":"le claonadh [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Dath","paint.paintEditor.saturation":"Sàthachd","paint.paintEditor.brightness":"Soilleireachd","paint.paintEditor.costume":"Dreach","paint.paintEditor.group":"Buidhnich","paint.paintEditor.ungroup":"Sgaoil am buidheann","paint.paintEditor.undo":"Neo-dhèan","paint.paintEditor.redo":"Ath-dhèan","paint.paintEditor.forward":"Gluais an comhair a’ bheòil","paint.paintEditor.backward":"Gluais an comhair a’ chùil","paint.paintEditor.front":"Gluais dhan fhìor-bheulaibh","paint.paintEditor.back":"Gluais dhan fhìor-chùlaibh","paint.paintEditor.more":"Barrachd","paint.modeTools.brushSize":"Meud na bruise","paint.modeTools.eraserSize":"Meud an t‑suathain","paint.modeTools.copy":"Dèan lethbhreac","paint.modeTools.paste":"Cuir ann","paint.modeTools.delete":"Sguab às","paint.modeTools.curved":"Cruinn","paint.modeTools.pointed":"Biorach","paint.modeTools.thickness":"Tiughad","paint.modeTools.flipHorizontal":"Flip air a’ chòmhnard","paint.modeTools.flipVertical":"Flip gu h‑inghearach","paint.modeTools.filled":"Lìonta","paint.modeTools.outlined":"Oir‑loidhne","paint.paintEditor.bitmap":"Iompaich na bitmap","paint.paintEditor.vector":"Iompaich na vector","paint.paintEditor.fill":"Lìonadh","paint.paintEditor.stroke":"Oir‑loidhne","paint.brushMode.brush":"Bruis","paint.eraserMode.eraser":"Suathan","paint.fillMode.fill":"Lìonadh","paint.lineMode.line":"Loidhne","paint.ovalMode.oval":"Cearcall","paint.rectMode.rect":"Ceart-cheàrnach","paint.reshapeMode.reshape":"Cumadh","paint.roundedRectMode.roundedRect":"Ceart-cheàrnach cruinnte","paint.selectMode.select":"Tagh","paint.textMode.text":"Teacsa","paint.colorPicker.swap":"Suaip"},"gl":{"gui.alerts.tryAgain":"Téntao de novo","gui.alerts.download":"Descargar","gui.connection.reconnect":"Reconectar","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"son","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Mochila","gui.backpack.errorBackpack":"Produciuse un erro ao cargar a mochila","gui.backpack.loadingBackpack":"A cargar...","gui.backpack.more":"Máis","gui.backpack.emptyBackpack":"A mochila está baleira","gui.unsupportedBrowser.label":"Este navegador non é compatíbel","gui.cards.all-tutorials":"Titoriais","gui.cards.shrink":"Recoller","gui.cards.expand":"Estender","gui.cards.close":"Pechar","gui.cards.more-things-to-try":"Máis cousas coas que experimentar!","gui.cards.see-more":"Ver máis","gui.comingSoon.message1":"Non te preocupes, andamos niso {emoji}","gui.comingSoon.message2":"Proximamente...","gui.comingSoon.message3":"Andamos a traballar nisto {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Non se atopou ningún dispositivo","gui.connection.auto-scanning.prescan":"Pon o dispositivo preto e comeza a buscar.","gui.connection.auto-scanning.pressbutton":"Preme o botón do dispositivo.","gui.connection.auto-scanning.start-search":"Comeza a buscar","gui.connection.connecting-searchbutton":"A buscar...","gui.connection.auto-scanning.try-again":"Téntao de novo","gui.connection.connected":"Conectado","gui.connection.disconnect":"Desconectar","gui.connection.go-to-editor":"Ir ao editor","gui.connection.connecting-cancelbutton":"A conectar...","gui.connection.error.errorMessage":"Vaites! Parece que algo foi mal.","gui.connection.error.tryagainbutton":"Téntao de novo","gui.connection.error.helpbutton":"Axuda","gui.connection.peripheral-name-label":"Nome do dispositivo","gui.connection.connect":"Conectar","gui.connection.scanning.lookingforperipherals":"A buscar dispositivos","gui.connection.scanning.noPeripheralsFound":"Non se atopou ningún dispositivo","gui.connection.scanning.instructions":"Selecciona o dispositivo na lista de arriba.","gui.connection.search":"Actualizar","gui.connection.unavailable.installscratchlink":"Comproba que Scratch Link estea instalado e en execución","gui.connection.unavailable.enablebluetooth":"Comproba que o Bluetooth estea activado","gui.connection.unavailable.tryagainbutton":"Téntao de novo","gui.connection.unavailable.helpbutton":"Axuda","gui.controls.go":"Ir","gui.controls.stop":"Parar","gui.crashMessage.label":"Vaites! Algo vai mal.","gui.crashMessage.errorNumber":"Informouse do fallo, con id {errorId}","gui.crashMessage.reload":"Actualizar","gui.customProcedures.myblockModalTitle":"Crear un bloque","gui.customProcedures.addAnInputNumberText":"Engadir unha entrada","gui.customProcedures.numberTextType":"número ou texto","gui.customProcedures.addAnInputBoolean":"Engadir unha entrada","gui.customProcedures.booleanType":"booleana","gui.customProcedures.addALabel":"Engadir unha etiqueta","gui.customProcedures.runWithoutScreenRefresh":"Executar sen actualizar a pantalla","gui.customProcedures.cancel":"Cancelar","gui.customProcedures.ok":"Aceptar","gui.SpriteInfo.direction":"Dirección","gui.directionPicker.rotationStyles.allAround":"En todas as direccións","gui.directionPicker.rotationStyles.leftRight":"Esquerda/Dereita","gui.directionPicker.rotationStyles.dontRotate":"Non rotar","gui.gui.addExtension":"Engadir extensión","gui.gui.codeTab":"Código","gui.gui.backdropsTab":"Fondos","gui.gui.costumesTab":"Traxes","gui.gui.soundsTab":"Sons","gui.extensionLibrary.comingSoon":"Proximamente","gui.extensionLibrary.requires":"Require","gui.extensionLibrary.collaboration":"En colaboración con","gui.library.filterPlaceholder":"Buscar","gui.library.allTag":"Todos","gui.loader.headline":"Estase a cargar o proxecto","gui.loader.creating":"Creando proxecto","gui.authorInfo.byUser":"de {username}","gui.menuBar.seeProjectPage":"Ver a páxina do proxecto","gui.menuBar.LanguageSelector":"selector de idioma","gui.menuBar.tutorialsLibrary":"Titoriais","gui.menuBar.restoreSprite":"Restaurar a figura","gui.menuBar.restoreSound":"Restaurar o son","gui.menuBar.restoreCostume":"Restaurar o traxe","gui.menuBar.restore":"Restaurar","gui.menuBar.saveNow":"Gardar agora","gui.menuBar.saveAsCopy":"Gardar como copia","gui.menuBar.remix":"Mesturar","gui.menuBar.new":"Novo","gui.menuBar.file":"Ficheiro","gui.menuBar.downloadToComputer":"Gardar no teu ordenador","gui.menuBar.edit":"Editar","gui.menuBar.turboModeOff":"Desactivar o modo turbo","gui.menuBar.turboModeOn":"Activar o modo turbo","gui.gui.projectTitlePlaceholder":"Aquí o título do proxecto","gui.menuBar.isShared":"Compartidos","gui.menuBar.share":"Compartir","gui.modal.help":"Axuda","gui.modal.back":"Atrás","gui.monitor.listMonitor.empty":"(baleiro)","gui.monitor.listMonitor.listLength":"lonxitude {length}","gui.monitor.contextMenu.default":"tamaño normal","gui.monitor.contextMenu.large":"tamaño grande","gui.monitor.contextMenu.slider":"barra de desprazamento","gui.monitor.contextMenu.sliderRange":"change slider range","gui.monitor.contextMenu.import":"importar","gui.monitor.contextMenu.export":"exportar","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Reproducir","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"Para todas as figuras","gui.gui.variableScopeOptionSpriteOnly":"Só para esta figura","gui.gui.cloudVariableOption":"Variábel na nube (gardada no servidor)","gui.gui.variablePromptAllSpritesMessage":"Esta variábel aplícase a todas as figuras.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Cancelar","gui.prompt.ok":"Aceptar","gui.playbackStep.stopMsg":"Parar","gui.playbackStep.playMsg":"Reproducir","gui.playbackStep.loadingMsg":"A cargar...","gui.playbackStep.saveMsg":"Gardar","gui.playbackStep.reRecordMsg":"Gravar outra vez","gui.recordModal.title":"Gravar son","gui.recordingStep.beginRecord":"Comeza a gravar premendo o botón de embaixo","gui.recordingStep.permission":"{arrow}Precisamos do teu permiso para usarmos o micrófono","gui.recordingStep.stop":"Parar de gravar","gui.recordingStep.record":"Gravar","gui.sliderModal.min":"Valor mínimo","gui.sliderModal.max":"Valor máximo","gui.sliderModal.title":"Cambiar o rango da barra de desprazamento","gui.sliderPrompt.cancel":"Cancelar","gui.sliderPrompt.ok":"Aceptar","gui.soundEditor.sound":"Son","gui.soundEditor.play":"Reproducir","gui.soundEditor.stop":"Parar","gui.soundEditor.copy":"Copiar","gui.soundEditor.paste":"Pegar","gui.soundEditor.copyToNew":"Copy to New","gui.soundEditor.delete":"Eliminar","gui.soundEditor.save":"Gardar","gui.soundEditor.undo":"Desfacer","gui.soundEditor.redo":"Refacer","gui.soundEditor.faster":"Máis rápido","gui.soundEditor.slower":"Máis lento","gui.soundEditor.echo":"Eco","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Máis forte","gui.soundEditor.softer":"Máis suave","gui.soundEditor.reverse":"Reverter","gui.soundEditor.fadeOut":"Fade out","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Silenciar","gui.SpriteInfo.spritePlaceholder":"Nome","gui.SpriteInfo.sprite":"Figura","gui.SpriteInfo.show":"Amosar","gui.SpriteInfo.size":"Tamaño","gui.spriteSelectorItem.contextMenuDuplicate":"duplicar","gui.spriteSelectorItem.contextMenuExport":"exportar","gui.spriteSelectorItem.contextMenuDelete":"eliminar","gui.spriteSelector.addSpriteFromLibrary":"Escoller unha figura","gui.spriteSelector.addSpriteFromPaint":"Pintar","gui.spriteSelector.addSpriteFromSurprise":"Sorpresa","gui.spriteSelector.addSpriteFromFile":"Cargar unha figura","gui.stageHeader.stageSizeLarge":"Pasar a un escenario grande","gui.stageHeader.stageSizeSmall":"Pasar a un escenario pequeno","gui.stageHeader.stageSizeFull":"Entrar no modo de pantalla completa","gui.stageHeader.stageSizeUnFull":"Saír do modo de pantalla completa","gui.stageHeader.fullscreenControl":"Control de pantalla completa","gui.spriteSelector.addBackdropFromLibrary":"Escoller un fondo","gui.stageSelector.addBackdropFromPaint":"Pintar","gui.stageSelector.addBackdropFromSurprise":"Sorpresa","gui.stageSelector.addBackdropFromFile":"Cargar un fondo","gui.stageSelector.stage":"Escenario","gui.stageSelector.backdrops":"Fondos","gui.telemetryOptIn.label":"Informar de estatísticas para mellorar o Scratch","gui.telemetryOptIn.body1":"O Equipo de Scratch está sempre tentando comprender mellor como se usa Scratch no mundo. Para axudar con este esforzo podes permitir que Scratch lle envíe automaticamente información de uso ao Equipo de Scratch.","gui.telemetryOptIn.body2":"A información que recollemos inclúe o idioma, os bloques utilizados e algúns actos como gardar, cargar e subir proxectos. NON recollemos información persoal. Consulta a nosa {privacyPolicyLink} para máis información.","gui.telemetryOptIn.privacyPolicyLink":"Política de privacidade","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Modo Turbo","gui.webglModal.label":"O navegador non admite WebGL","gui.webglModal.webgllink":"non é compatíbel con WebGL","gui.costumeLibrary.chooseABackdrop":"Escoller un fondo","gui.costumeLibrary.chooseACostume":"Escoller un traxe","gui.costumeTab.addBackdropFromLibrary":"Escoller un fondo","gui.costumeTab.addCostumeFromLibrary":"Escoller un traxe","gui.costumeTab.addBlankCostume":"Pintar","gui.costumeTab.addSurpriseCostume":"Sorpresa","gui.costumeTab.addFileBackdrop":"Cargar un fondo","gui.costumeTab.addFileCostume":"Cargar un traxe","gui.extensionLibrary.chooseAnExtension":"Escoller unha extensión","gui.extensionLibrary.extensionUrl":"Introduce o URL da extensión","gui.monitors.importListColumnPrompt":"Cal columna debe usarse (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Non foi posíbel comezar a gravar","gui.soundLibrary.chooseASound":"Escoller un son","gui.soundTab.fileUploadSound":"Cargar un son","gui.soundTab.surpriseSound":"Sorpresa","gui.soundTab.recordSound":"Gravar","gui.soundTab.addSoundFromLibrary":"Escoller un son","gui.spriteLibrary.chooseASprite":"Escoller unha figura","gui.tipsLibrary.tutorials":"Escoller un titorial","gui.alerts.createsuccess":"Creouse o novo proxecto.","gui.alerts.createcopysuccess":"O proxecto gardouse como unha copia.","gui.alerts.createremixsuccess":"O proxecto gardouse como unha recreación.","gui.alerts.creating":"Creando o novo proxecto...","gui.alerts.creatingCopy":"Copiando o proxecto...","gui.alerts.creatingRemix":"Recreando o proxecto...","gui.alerts.creatingError":"Non foi posíbel crear o proxecto. Téntao de novo.","gui.alerts.savingError":"Non foi posíbel gardar o proxecto.","gui.alerts.savesuccess":"Proxecto gardado.","gui.alerts.saving":"Gardando o proxecto...","gui.alerts.cloudInfo":"Por favor ten en conta que as variables na nube só aceptan números, non letras nin símbolos. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Saber máis.","gui.alerts.importing":"Estase a importar...","gui.defaultProject.variable":"a miña variábel","gui.extension.music.name":"Música","gui.extension.music.description":"Toca instrumentos e tambores.","gui.extension.pen.name":"Lapis","gui.extension.pen.description":"Debuxa coas túas figuras.","gui.extension.videosensing.name":"Sensor de vídeo","gui.extension.videosensing.description":"Sente movemento coa cámara.","gui.extension.text2speech.name":"Texto a fala","gui.extension.text2speech.description":"Fai que os teus proxectos falen.","gui.extension.translate.name":"Traducir","gui.extension.translate.description":"Traduce texto a moitos idiomas.","gui.extension.makeymakey.description":"Fai calquera cousa cunha tecla.","gui.extension.microbit.description":"Conecta os teus proxectos co mundo.","gui.extension.microbit.connectingMessage":"A conectar.","gui.extension.ev3.description":"Constrúe robots interactivos e máis.","gui.extension.ev3.connectingMessage":"A conectar. Comproba que o pin do teu EV3 é 1234.","gui.extension.boost.description":"Dalle vida aos robots.","gui.extension.boost.connectingMessage":"Connecting","gui.extension.wedo2.description":"Constrúe con motores e sensores.","gui.extension.wedo2.connectingMessage":"A conectar","gui.extension.gdxfor.description":"Sense push, pull, motion, and spin.","gui.extension.gdxfor.connectingMessage":"Connecting","gui.libraryTags.all":"Todas","gui.libraryTags.animals":"Animais","gui.libraryTags.dance":"Baile","gui.libraryTags.effects":"Efectos","gui.libraryTags.fantasy":"Fantasía","gui.libraryTags.fashion":"Moda","gui.libraryTags.food":"Comida","gui.libraryTags.indoors":"Interiores","gui.libraryTags.loops":"Bucles","gui.libraryTags.music":"Música","gui.libraryTags.notes":"Notas","gui.libraryTags.outdoors":"Exteriores","gui.libraryTags.patterns":"Patróns","gui.libraryTags.people":"Xente","gui.libraryTags.percussion":"Percusión","gui.libraryTags.space":"Espazo","gui.libraryTags.sports":"Deportes","gui.libraryTags.underwater":"Baixo a auga","gui.libraryTags.voice":"Voz","gui.libraryTags.wacky":"Extravagante","gui.libraryTags.animation":"Animación","gui.libraryTags.art":"Arte","gui.libraryTags.games":"Xogos","gui.libraryTags.stories":"Historias","gui.libraryTags.letters":"Letras","gui.opcodeLabels.direction":"dirección","gui.opcodeLabels.xposition":"posición en x","gui.opcodeLabels.yposition":"posición en y","gui.opcodeLabels.size":"tamaño","gui.opcodeLabels.costumename":"nome do traxe","gui.opcodeLabels.costumenumber":"número de traxe","gui.opcodeLabels.backdropname":"nome do fondo","gui.opcodeLabels.backdropnumber":"número de fondo","gui.opcodeLabels.volume":"volume","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"resposta","gui.opcodeLabels.loudness":"intensidade do son","gui.opcodeLabels.username":"nome de usuario","gui.opcodeLabels.year":"ano","gui.opcodeLabels.month":"mes","gui.opcodeLabels.date":"data","gui.opcodeLabels.dayofweek":"día da semana","gui.opcodeLabels.hour":"hora","gui.opcodeLabels.minute":"minuto","gui.opcodeLabels.second":"segundo","gui.opcodeLabels.timer":"cronómetro","gui.sharedMessages.backdrop":"fondo{index}","gui.sharedMessages.costume":"traxe {index}","gui.sharedMessages.sprite":"Figura{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Replace contents of the current project?","gui.sharedMessages.loadFromComputerTitle":"Cargar desde o teu ordenador","boost.color.any":"calquera cor","boost.color.black":"negro","boost.color.blue":"azul","boost.color.green":"verde","boost.color.red":"vermello","boost.color.white":"branco","boost.color.yellow":"amarelo","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] position","boost.getTiltAngle":"ángulo de inclinación [TILT_DIRECTION]","boost.motorDirection.backward":"recuar","boost.motorDirection.forward":"avanzar","boost.motorDirection.reverse":"inverter","boost.motorOff":"turn motor [MOTOR_ID] off","boost.motorOn":"turn motor [MOTOR_ID] on","boost.motorOnFor":"turn motor [MOTOR_ID] for [DURATION] seconds","boost.motorOnForRotation":"turn motor [MOTOR_ID] for [ROTATION] rotations","boost.seeingColor":"seeing [COLOR] brick?","boost.setLightHue":"pór a cor da luz a [HUE]","boost.setMotorDirection":"set motor [MOTOR_ID] direction [MOTOR_DIRECTION]","boost.setMotorPower":"set motor [MOTOR_ID] speed to [POWER] %","boost.tiltDirection.any":"calquera","boost.tiltDirection.down":"abaixo","boost.tiltDirection.left":"esquerda","boost.tiltDirection.right":"dereita","boost.tiltDirection.up":"arriba","boost.whenColor":"Ao ver un bloque [COLOR]","boost.whenTilted":"Cando estea inclinado cara [TILT_DIRECTION_ANY]","ev3.beepNote":"tocar a nota [NOTE] durante [TIME] segundos","ev3.buttonPressed":"está premido o botón [PORT]","ev3.getBrightness":"luminosidade","ev3.getDistance":"distancia","ev3.getMotorPosition":"posición do motor [PORT]","ev3.motorSetPower":"pór o motor [PORT] ao [POWER]% de potencia","ev3.motorTurnClockwise":"virar o motor [PORT] para aquí durante [TIME] segundos","ev3.motorTurnCounterClockwise":"virar o motor [PORT] para alá durante [TIME] segundos","ev3.whenBrightnessLessThan":"Cando o brillo < [DISTANCE]","ev3.whenButtonPressed":"Ao premer o botón [PORT]","ev3.whenDistanceLessThan":"Cando a distancia < [DISTANCE]","gdxfor.getAcceleration":"a aceleración [DIRECTION]","gdxfor.getForce":"a forza","gdxfor.getSpin":"a velocidade angular [DIRECTION]","gdxfor.getTilt":"tilt angle [TILT]","gdxfor.isFreeFalling":"está a caer?","gdxfor.isTilted":"tilted [TILT]?","gdxfor.pulled":"levou un tirón","gdxfor.pushed":"foi empurrado","gdxfor.shaken":"abalado","gdxfor.startedFalling":"comezou a caer","gdxfor.tiltDirectionMenu.any":"calquera","gdxfor.tiltDirectionMenu.back":"por detrás","gdxfor.tiltDirectionMenu.front":"adiante","gdxfor.tiltDirectionMenu.left":"a esquerda","gdxfor.tiltDirectionMenu.right":"a dereita","gdxfor.turnedFaceDown":"turned face down","gdxfor.turnedFaceUp":"turned face up","gdxfor.whenForcePushedOrPulled":"Cando o sensor de forza [PUSH_PULL]","gdxfor.whenGesture":"Cando é [GESTURE]","gdxfor.whenTilted":"when tilted [TILT]","makeymakey.downArrow":"frecha abaixo","makeymakey.downArrowShort":"abaixo","makeymakey.leftArrow":"frecha esquerda","makeymakey.leftArrowShort":"esquerda","makeymakey.rightArrow":"frecha dereita","makeymakey.rightArrowShort":"dereita","makeymakey.spaceKey":"espazo","makeymakey.upArrow":"frecha arriba","makeymakey.upArrowShort":"arriba","makeymakey.whenKeyPressed":"Ao premer a tecla [KEY]","makeymakey.whenKeysPressedInOrder":"Ao premer en orde [SEQUENCE]","microbit.buttonsMenu.any":"calquera","microbit.clearDisplay":"limpar a pantalla","microbit.defaultTextToDisplay":"Ola!","microbit.displaySymbol":"mostrar [MATRIX]","microbit.displayText":"mostrar o texto [TEXT]","microbit.gesturesMenu.jumped":"saltado","microbit.gesturesMenu.moved":"movido","microbit.gesturesMenu.shaken":"abalado","microbit.isButtonPressed":"está premido o botón [BTN]","microbit.isTilted":"inclinado cara [DIRECTION]","microbit.pinStateMenu.off":"apagado","microbit.pinStateMenu.on":"aceso","microbit.tiltAngle":"ángulo de inclinación cara [DIRECTION]","microbit.tiltDirectionMenu.any":"calquera","microbit.tiltDirectionMenu.back":"atrás","microbit.tiltDirectionMenu.front":"adiante","microbit.tiltDirectionMenu.left":"a esquerda","microbit.tiltDirectionMenu.right":"a dereita","microbit.whenButtonPressed":"Ao premer o botón [BTN]","microbit.whenGesture":"Cando é [GESTURE]","microbit.whenPinConnected":"Cando o pin [PIN] estea conectado","microbit.whenTilted":"Ao estar inclinado cara [DIRECTION]","music.categoryName":"Música","music.changeTempo":"aumentar o tempo en [TEMPO]","music.drumBass":"(2) Bombo","music.drumBongo":"(13) Bongó","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) Charles pechado","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Chocallo","music.drumCrashCymbal":"(4) Prato de ataque","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Güiro","music.drumHandClap":"(8) Palmada","music.drumOpenHiHat":"(5) Charles aberto","music.drumSideStick":"(3) Golpe lateral","music.drumSnare":"(1) Tambor de caixa","music.drumTambourine":"(7) Pandeireta","music.drumTriangle":"(12) Triángulo","music.drumVibraslap":"(17) Trafaplás","music.drumWoodBlock":"(10) Bloque de madeira","music.getTempo":"tempo","music.instrumentBass":"(6) Baixo","music.instrumentBassoon":"(14) Fagot","music.instrumentCello":"(8) Violonchelo","music.instrumentChoir":"(15) Coro","music.instrumentClarinet":"(10) Clarinete","music.instrumentElectricGuitar":"(5) Guitarra eléctrica","music.instrumentElectricPiano":"(2) Piano eléctrico","music.instrumentFlute":"(12) Frauta traveseira","music.instrumentGuitar":"(4) Guitarra","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Caixa de música","music.instrumentOrgan":"(3) Órgano","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxofón","music.instrumentSteelDrum":"(18) Tambor metálico","music.instrumentSynthLead":"(20) Sintetizador melódico","music.instrumentSynthPad":"(21) Sintetizador de fondo","music.instrumentTrombone":"(9) Trombón","music.instrumentVibraphone":"(16) Vibráfono","music.instrumentWoodenFlute":"(13) Frauta de madeira","music.midiPlayDrumForBeats":"tocar o tambor [DRUM] durante [BEATS] pulsos","music.midiSetInstrument":"tocar o instrumento [INSTRUMENT]","music.playDrumForBeats":"tocar o tambor [DRUM] durante [BEATS] pulsos","music.playNoteForBeats":"tocar a nota [NOTE] durante [BEATS] pulsos","music.restForBeats":"descanso de [BEATS] pulsos","music.setInstrument":"usar o instrumento [INSTRUMENT]","music.setTempo":"aplicar un tempo de [TEMPO]","pen.categoryName":"Lapis","pen.changeColorParam":"sumar [VALUE] á [COLOR_PARAM] do lapis","pen.changeHue":"sumar [HUE] á cor do lapis","pen.changeShade":"sumar [SHADE] a intensidade do lapis","pen.changeSize":"aumentar o tamaño do lapis en [SIZE]","pen.clear":"borrar todo","pen.colorMenu.brightness":"luminosidade","pen.colorMenu.color":"cor","pen.colorMenu.saturation":"saturación","pen.colorMenu.transparency":"transparencia","pen.penDown":"baixar o lapis","pen.penUp":"subir o lapis","pen.setColor":"usar un lapis de cor [COLOR]","pen.setColorParam":"pór a [COLOR_PARAM] do lapis en [VALUE]","pen.setHue":"usar un lapis de cor [HUE]","pen.setShade":"pór a intensidade do lapis a [SHADE]","pen.setSize":"usar un lapis de tamaño [SIZE]","pen.stamp":"selar","text2speech.alto":"alto","text2speech.categoryName":"Texto a fala","text2speech.defaultTextToSpeak":"Ola","text2speech.giant":"xigante","text2speech.kitten":"gatiño","text2speech.setLanguageBlock":"usar o idioma [LANGUAGE]","text2speech.setVoiceBlock":"darlle a voz de [VOICE]","text2speech.speakAndWaitBlock":"falar [WORDS]","text2speech.squeak":"bradar","text2speech.tenor":"tenor","translate.categoryName":"Traducir","translate.defaultTextToTranslate":"Ola","translate.translateBlock":"traducir [WORDS] a [LANGUAGE]","translate.viewerLanguage":"idioma","videoSensing.categoryName":"Sensor de vídeo","videoSensing.direction":"dirección","videoSensing.motion":"movemento","videoSensing.off":"apagado","videoSensing.on":"aceso","videoSensing.onFlipped":"ao voltear","videoSensing.setVideoTransparency":"pór a transparencia de vídeo en [TRANSPARENCY]","videoSensing.sprite":"figura","videoSensing.stage":"escenario","videoSensing.videoOn":"[ATTRIBUTE] de vídeo a [SUBJECT]","videoSensing.videoToggle":"vídeo [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"Cando o movemento de vídeo > [REFERENCE]","wedo2.getDistance":"distancia","wedo2.getTiltAngle":"ángulo de inclinación [TILT_DIRECTION]","wedo2.isTilted":"inclinado á [TILT_DIRECTION_ANY]","wedo2.motorDirection.backward":"cara alá","wedo2.motorDirection.forward":"por aquí","wedo2.motorDirection.reverse":"inverter","wedo2.motorId.a":"motor A","wedo2.motorId.all":"todos os motores","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"apagar [MOTOR_ID]","wedo2.motorOn":"acender [MOTOR_ID]","wedo2.motorOnFor":"acender [MOTOR_ID] durante [DURATION] segundos","wedo2.playNoteFor":"tocar a nota [NOTE] durante [DURATION] segundos","wedo2.setLightHue":"pór a cor da luz a [HUE]","wedo2.setMotorDirection":"trocar a dirección de [MOTOR_ID] por [MOTOR_DIRECTION]","wedo2.startMotorPower":"pór a potencia de [MOTOR_ID] a [POWER]","wedo2.tiltDirection.any":"calquera","wedo2.tiltDirection.down":"abaixo","wedo2.tiltDirection.left":"a esquerda","wedo2.tiltDirection.right":"a dereita","wedo2.tiltDirection.up":"arriba","wedo2.whenDistance":"Cando a distancia [OP] [REFERENCE]","wedo2.whenTilted":"Cando estea inclinado cara [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Cor","paint.paintEditor.saturation":"Saturación","paint.paintEditor.brightness":"Luminosidade","paint.paintEditor.costume":"Traxe","paint.paintEditor.group":"Agrupar","paint.paintEditor.ungroup":"Desagrupar","paint.paintEditor.undo":"Desfacer","paint.paintEditor.redo":"Refacer","paint.paintEditor.forward":"Adiante","paint.paintEditor.backward":"Atrás","paint.paintEditor.front":"Traer á fronte","paint.paintEditor.back":"Levar ao fondo","paint.paintEditor.more":"Máis","paint.modeTools.brushSize":"Tamaño","paint.modeTools.eraserSize":"Tamaño do borrador","paint.modeTools.copy":"Copiar","paint.modeTools.paste":"Pegar","paint.modeTools.delete":"Eliminar","paint.modeTools.curved":"A curvas","paint.modeTools.pointed":"Bordes Afiados","paint.modeTools.thickness":"Gordura","paint.modeTools.flipHorizontal":"Voltear en horizontal","paint.modeTools.flipVertical":"Voltear en vertical","paint.modeTools.filled":"Enchido","paint.modeTools.outlined":"Bordos","paint.paintEditor.bitmap":"Converter en mapa de bits","paint.paintEditor.vector":"Converter en vectores","paint.paintEditor.fill":"Recheo","paint.paintEditor.stroke":"Bordo","paint.brushMode.brush":"Pincel","paint.eraserMode.eraser":"Borrador","paint.fillMode.fill":"Encher","paint.lineMode.line":"Liña","paint.ovalMode.oval":"Círculo","paint.rectMode.rect":"Rectángulo","paint.reshapeMode.reshape":"Reformar","paint.roundedRectMode.roundedRect":"Rectángulo arredondado","paint.selectMode.select":"Seleccionar","paint.textMode.text":"Texto","paint.colorPicker.swap":"Trocar"},"ko":{"gui.alerts.tryAgain":"다시 시도","gui.alerts.download":"다운로드","gui.connection.reconnect":"다시 연결","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"개인 저장소","gui.backpack.errorBackpack":"개인 저장소를 불러오는 중 오류 ","gui.backpack.loadingBackpack":"로딩중...","gui.backpack.more":"더 보기","gui.backpack.emptyBackpack":"개인 저장소가 비었습니다","gui.unsupportedBrowser.label":"브라우저가 지원되지 않습니다.","gui.cards.all-tutorials":"튜토리얼","gui.cards.shrink":"Shrink","gui.cards.expand":"Expand","gui.cards.close":"닫기","gui.cards.more-things-to-try":"해 볼 만한 다른 것들!","gui.cards.see-more":"더 보기","gui.comingSoon.message1":"걱정 마세요, 작업 중입니다 {emoji}","gui.comingSoon.message2":"곧 이용 가능합니다...","gui.comingSoon.message3":"작업 중입니다 {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"발견된 기기가 없습니다","gui.connection.auto-scanning.prescan":"주변에 기기가 있는 지 확인 후 검색을 시작하세요. ","gui.connection.auto-scanning.pressbutton":"기기의 버튼을 누르세요","gui.connection.auto-scanning.start-search":"검색 시작","gui.connection.connecting-searchbutton":"검색 중...","gui.connection.auto-scanning.try-again":"다시 시도","gui.connection.connected":"연결됨 ","gui.connection.disconnect":"연결 끊기 ","gui.connection.go-to-editor":"편집기로 가기 ","gui.connection.connecting-cancelbutton":"연결 중...","gui.connection.error.errorMessage":"이런, 뭔가 잘못된 것 같네요. ","gui.connection.error.tryagainbutton":"다시 시도","gui.connection.error.helpbutton":"도움말","gui.connection.peripheral-name-label":"기기 이름","gui.connection.connect":"연결하기","gui.connection.scanning.lookingforperipherals":"기기를 찾는 중","gui.connection.scanning.noPeripheralsFound":"발견된 기기가 없습니다","gui.connection.scanning.instructions":"위의 목록에서 사용자의 기기를 선택하세요.","gui.connection.search":"새로 고침","gui.connection.unavailable.installscratchlink":"Scratch Link가 설치되었고 실행되는지 확인하세요","gui.connection.unavailable.enablebluetooth":"블루투스가 사용 가능한지 확인하세요","gui.connection.unavailable.tryagainbutton":"다시 시도","gui.connection.unavailable.helpbutton":"도움말","gui.controls.go":"시작하기","gui.controls.stop":"멈추기","gui.crashMessage.label":"이런! 무언가가 잘못되었습니다.","gui.crashMessage.errorNumber":"Your error was logged with id {errorId}","gui.crashMessage.reload":"새로 고침","gui.customProcedures.myblockModalTitle":"블록 만들기","gui.customProcedures.addAnInputNumberText":"입력값 추가하기","gui.customProcedures.numberTextType":"숫자 또는 문자열","gui.customProcedures.addAnInputBoolean":"입력값 추가하기","gui.customProcedures.booleanType":"논리값","gui.customProcedures.addALabel":"라벨 넣기","gui.customProcedures.runWithoutScreenRefresh":"화면 새로고침 없이 실행하기","gui.customProcedures.cancel":"취소","gui.customProcedures.ok":"확인","gui.SpriteInfo.direction":"방향","gui.directionPicker.rotationStyles.allAround":"회전하기","gui.directionPicker.rotationStyles.leftRight":"왼쪽/오른쪽","gui.directionPicker.rotationStyles.dontRotate":"회전하지 않기","gui.gui.addExtension":"확장 기능 추가하기","gui.gui.codeTab":"코드","gui.gui.backdropsTab":"배경","gui.gui.costumesTab":"모양","gui.gui.soundsTab":"소리","gui.extensionLibrary.comingSoon":"곧 이용 가능","gui.extensionLibrary.requires":"요구사항","gui.extensionLibrary.collaboration":"협력사","gui.library.filterPlaceholder":"검색","gui.library.allTag":"모두","gui.loader.headline":"프로젝트를 불러오는 중","gui.loader.creating":"생성된 프로젝트","gui.authorInfo.byUser":"제작자: {username}","gui.menuBar.seeProjectPage":"프로젝트 페이지 보기","gui.menuBar.LanguageSelector":"언어 선택기 ","gui.menuBar.tutorialsLibrary":"튜토리얼","gui.menuBar.restoreSprite":"스프라이트 되돌리기","gui.menuBar.restoreSound":"소리 되돌리기","gui.menuBar.restoreCostume":"모양 되돌리기","gui.menuBar.restore":"되돌리기","gui.menuBar.saveNow":"저장하기","gui.menuBar.saveAsCopy":"복사본 저장하기","gui.menuBar.remix":"리믹스","gui.menuBar.new":"새로 만들기","gui.menuBar.file":"파일","gui.menuBar.downloadToComputer":"컴퓨터에 저장하기 ","gui.menuBar.edit":"편집","gui.menuBar.turboModeOff":"터보 모드 끄기","gui.menuBar.turboModeOn":"터보 모드 켜기","gui.gui.projectTitlePlaceholder":"프로젝트 제목을 입력하세요","gui.menuBar.isShared":"공유됨","gui.menuBar.share":"공유","gui.modal.help":"도움말","gui.modal.back":"뒤로","gui.monitor.listMonitor.empty":"(비어 있음)","gui.monitor.listMonitor.listLength":"길이 {length}","gui.monitor.contextMenu.default":"변수이름-변수값 보기","gui.monitor.contextMenu.large":"변수값 크게 보기","gui.monitor.contextMenu.slider":"슬라이더 사용하기","gui.monitor.contextMenu.sliderRange":"change slider range","gui.monitor.contextMenu.import":"가져오기","gui.monitor.contextMenu.export":"내보내기","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Play","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"모든 스프라이트에서 사용","gui.gui.variableScopeOptionSpriteOnly":"이 스프라이트에서만 사용","gui.gui.cloudVariableOption":"클라우드 변수 (서버에 저장됨)","gui.gui.variablePromptAllSpritesMessage":"이 변수는 모든 스프라이트에서 사용할 수 있습니다.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"취소","gui.prompt.ok":"확인","gui.playbackStep.stopMsg":"멈추기","gui.playbackStep.playMsg":"재생","gui.playbackStep.loadingMsg":"로딩 중...","gui.playbackStep.saveMsg":"저장","gui.playbackStep.reRecordMsg":"다시 녹음하기","gui.recordModal.title":"소리 녹음하기","gui.recordingStep.beginRecord":"아래에 있는 버튼을 눌러서 녹음을 시작하세요","gui.recordingStep.permission":"{arrow}마이크를 사용하려면 사용자의 허락이 필요합니다","gui.recordingStep.stop":"녹음 멈추기","gui.recordingStep.record":"녹음하기","gui.sliderModal.min":"Minimum value","gui.sliderModal.max":"Maximum value","gui.sliderModal.title":"Change slider range","gui.sliderPrompt.cancel":"Cancel","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"소리","gui.soundEditor.play":"재생","gui.soundEditor.stop":"멈추기","gui.soundEditor.copy":"Copy","gui.soundEditor.paste":"Paste","gui.soundEditor.copyToNew":"Copy to New","gui.soundEditor.delete":"Delete","gui.soundEditor.save":"저장","gui.soundEditor.undo":"되돌리기","gui.soundEditor.redo":"재시도","gui.soundEditor.faster":"빠르게","gui.soundEditor.slower":"느리게","gui.soundEditor.echo":"메아리","gui.soundEditor.robot":"로봇","gui.soundEditor.louder":"크게","gui.soundEditor.softer":"작게","gui.soundEditor.reverse":"뒤집기","gui.soundEditor.fadeOut":"Fade out","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Mute","gui.SpriteInfo.spritePlaceholder":"이름","gui.SpriteInfo.sprite":"스프라이트","gui.SpriteInfo.show":"보이기","gui.SpriteInfo.size":"크기","gui.spriteSelectorItem.contextMenuDuplicate":"복사","gui.spriteSelectorItem.contextMenuExport":"내보내기","gui.spriteSelectorItem.contextMenuDelete":"삭제","gui.spriteSelector.addSpriteFromLibrary":"스프라이트 고르기","gui.spriteSelector.addSpriteFromPaint":"그리기","gui.spriteSelector.addSpriteFromSurprise":"서프라이즈","gui.spriteSelector.addSpriteFromFile":"스프라이트 업로드하기","gui.stageHeader.stageSizeLarge":"큰 무대로 전환하기","gui.stageHeader.stageSizeSmall":"작은 무대로 전환하기 ","gui.stageHeader.stageSizeFull":"전체 화면 모드로 전환하기 ","gui.stageHeader.stageSizeUnFull":"전체 화면 모드 종료하기","gui.stageHeader.fullscreenControl":"전체 화면","gui.spriteSelector.addBackdropFromLibrary":"배경 고르기","gui.stageSelector.addBackdropFromPaint":"그리기","gui.stageSelector.addBackdropFromSurprise":"서프라이즈 ","gui.stageSelector.addBackdropFromFile":"배경 업로드하기","gui.stageSelector.stage":"무대","gui.stageSelector.backdrops":"배경","gui.telemetryOptIn.label":"Report statistics to improve Scratch","gui.telemetryOptIn.body1":"The Scratch Team is always looking to better understand how Scratch is used around the world. To help support this effort, you can allow Scratch to automatically send usage information to the Scratch Team.","gui.telemetryOptIn.body2":"The information we collect includes language selection, blocks usage, and some events like saving, loading, and uploading a project. We DO NOT collect any personal information. Please see our {privacyPolicyLink} for more information.","gui.telemetryOptIn.privacyPolicyLink":"개인정보보호 정책","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"터보 모드","gui.webglModal.label":"브라우저가 WebGL을 지원하지 않습니다","gui.webglModal.webgllink":"WebGL을 지원하지 않는 상태","gui.costumeLibrary.chooseABackdrop":"배경 고르기","gui.costumeLibrary.chooseACostume":"모양 고르기","gui.costumeTab.addBackdropFromLibrary":"배경 고르기","gui.costumeTab.addCostumeFromLibrary":"모양 고르기","gui.costumeTab.addBlankCostume":"그리기","gui.costumeTab.addSurpriseCostume":"서프라이즈 ","gui.costumeTab.addFileBackdrop":"배경 업로드하기","gui.costumeTab.addFileCostume":"모양 업로드하기","gui.extensionLibrary.chooseAnExtension":"확장 기능 고르기","gui.extensionLibrary.extensionUrl":"Enter the URL of the extension","gui.monitors.importListColumnPrompt":"Which column should be used (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"녹음을 시작할 수 없음","gui.soundLibrary.chooseASound":"소리 고르기","gui.soundTab.fileUploadSound":"소리 업로드하기","gui.soundTab.surpriseSound":"서프라이즈 ","gui.soundTab.recordSound":"녹음하기","gui.soundTab.addSoundFromLibrary":"소리 고르기","gui.spriteLibrary.chooseASprite":"스프라이트 고르기","gui.tipsLibrary.tutorials":"튜토리얼 고르기","gui.alerts.createsuccess":"새 프로젝트가 생성되었습니다.","gui.alerts.createcopysuccess":"복사본으로 프로젝트가 저장되었습니다.","gui.alerts.createremixsuccess":"리믹스로 프로젝트가 저장되었습니다.","gui.alerts.creating":"새로 만드는 중...","gui.alerts.creatingCopy":"프로젝트 복사중...","gui.alerts.creatingRemix":"프로젝트 리믹스 중...","gui.alerts.creatingError":"프로젝트를 생성하지 못했습니다. 다시 시도해 주세요!","gui.alerts.savingError":"프로젝트를 저장하지 못했습니다.","gui.alerts.savesuccess":"프로젝트가 저장되었습니다.","gui.alerts.saving":"프로젝트 저장 중...","gui.alerts.cloudInfo":"클라우드 변수는 숫자만 지원하며 문자나 특수기호는 지원하지 않습니다. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"더 알아보기","gui.alerts.importing":"Importing…","gui.defaultProject.variable":"나의 변수","gui.extension.music.name":"음악","gui.extension.music.description":"악기와 타악기를 연주하세요.","gui.extension.pen.name":"펜","gui.extension.pen.description":"스프라이트를 사용하여 그려 보세요. ","gui.extension.videosensing.name":"비디오 감지","gui.extension.videosensing.description":"카메라를 이용하여 움직임을 감지해 보세요.","gui.extension.text2speech.name":"텍스트 음성 변환(TTS)","gui.extension.text2speech.description":"프로젝트가 말을 하도록 만들어 보세요.","gui.extension.translate.name":"번역","gui.extension.translate.description":"텍스트를 여러 가지 언어로 번역해 보세요.","gui.extension.makeymakey.description":"무엇이든지 키보드 자판으로 만들어 보세요.","gui.extension.microbit.description":"프로젝트를 세계와 연결해 보세요.","gui.extension.microbit.connectingMessage":"연결 중","gui.extension.ev3.description":"감지하고 반응하는 로봇 등을 만들어 보세요.","gui.extension.ev3.connectingMessage":"연결 중입니다. EV3의 pin이 1234로 설정되었는지 확인하세요.","gui.extension.boost.description":"Bring robotic creations to life.","gui.extension.boost.connectingMessage":"Connecting","gui.extension.wedo2.description":"모터 및 센서를 이용하여 만들어 보세요. ","gui.extension.wedo2.connectingMessage":"연결 중","gui.extension.gdxfor.description":"Sense push, pull, motion, and spin.","gui.extension.gdxfor.connectingMessage":"Connecting","gui.libraryTags.all":"모두","gui.libraryTags.animals":"동물","gui.libraryTags.dance":"댄스","gui.libraryTags.effects":"효과","gui.libraryTags.fantasy":"판타지","gui.libraryTags.fashion":"패션","gui.libraryTags.food":"음식","gui.libraryTags.indoors":"실내","gui.libraryTags.loops":"반복","gui.libraryTags.music":"음악","gui.libraryTags.notes":"음표","gui.libraryTags.outdoors":"실외","gui.libraryTags.patterns":"패턴","gui.libraryTags.people":"사람들","gui.libraryTags.percussion":"타악기","gui.libraryTags.space":"우주","gui.libraryTags.sports":"스포츠","gui.libraryTags.underwater":"바닷속","gui.libraryTags.voice":"목소리","gui.libraryTags.wacky":"엉뚱한 소리","gui.libraryTags.animation":"애니메이션","gui.libraryTags.art":"예술","gui.libraryTags.games":"게임","gui.libraryTags.stories":"이야기","gui.libraryTags.letters":"글자","gui.opcodeLabels.direction":"방향","gui.opcodeLabels.xposition":"x 좌표","gui.opcodeLabels.yposition":"y 좌표","gui.opcodeLabels.size":"크기","gui.opcodeLabels.costumename":"모양 이름","gui.opcodeLabels.costumenumber":"모양 번호","gui.opcodeLabels.backdropname":"배경 이름","gui.opcodeLabels.backdropnumber":"배경 번호","gui.opcodeLabels.volume":"음량","gui.opcodeLabels.tempo":"빠르기","gui.opcodeLabels.answer":"대답","gui.opcodeLabels.loudness":"음량","gui.opcodeLabels.username":"사용자 이름","gui.opcodeLabels.year":"년","gui.opcodeLabels.month":"월","gui.opcodeLabels.date":"일","gui.opcodeLabels.dayofweek":"요일","gui.opcodeLabels.hour":"시","gui.opcodeLabels.minute":"분","gui.opcodeLabels.second":"초","gui.opcodeLabels.timer":"타이머","gui.sharedMessages.backdrop":"배경 {index}","gui.sharedMessages.costume":"모양 {index}","gui.sharedMessages.sprite":"스프라이트 {index}","gui.sharedMessages.pop":"팝","gui.sharedMessages.replaceProjectWarning":"Replace contents of the current project?","gui.sharedMessages.loadFromComputerTitle":"Load from your computer","boost.color.any":"any color","boost.color.black":"black","boost.color.blue":"blue","boost.color.green":"green","boost.color.red":"red","boost.color.white":"white","boost.color.yellow":"yellow","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] position","boost.getTiltAngle":"tilt angle [TILT_DIRECTION]","boost.motorDirection.backward":"that way","boost.motorDirection.forward":"this way","boost.motorDirection.reverse":"reverse","boost.motorOff":"turn motor [MOTOR_ID] off","boost.motorOn":"turn motor [MOTOR_ID] on","boost.motorOnFor":"turn motor [MOTOR_ID] for [DURATION] seconds","boost.motorOnForRotation":"turn motor [MOTOR_ID] for [ROTATION] rotations","boost.seeingColor":"seeing [COLOR] brick?","boost.setLightHue":"set light color to [HUE]","boost.setMotorDirection":"set motor [MOTOR_ID] direction [MOTOR_DIRECTION]","boost.setMotorPower":"set motor [MOTOR_ID] speed to [POWER] %","boost.tiltDirection.any":"any","boost.tiltDirection.down":"down","boost.tiltDirection.left":"left","boost.tiltDirection.right":"right","boost.tiltDirection.up":"up","boost.whenColor":"when [COLOR] brick seen","boost.whenTilted":"when tilted [TILT_DIRECTION_ANY]","ev3.beepNote":"[TIME] 초 동안 [NOTE] 번 음 울리기","ev3.buttonPressed":" [PORT] 번 버튼이 눌러졌는가?","ev3.getBrightness":"밝기","ev3.getDistance":"거리","ev3.getMotorPosition":"모터 [PORT] 위치","ev3.motorSetPower":"[PORT] 모터 강도를 [POWER] %로 정하기","ev3.motorTurnClockwise":"[PORT] 모터를 [TIME] 초 동안 이쪽으로 돌리기","ev3.motorTurnCounterClockwise":"[PORT] 모터를 [TIME] 초 동안 저쪽으로 돌리기","ev3.whenBrightnessLessThan":"밝기 < [DISTANCE]일 때","ev3.whenButtonPressed":"[PORT] 번 버튼이 눌러졌을 때","ev3.whenDistanceLessThan":"거리 < [DISTANCE]일 때","gdxfor.getAcceleration":"acceleration [DIRECTION]","gdxfor.getForce":"force","gdxfor.getSpin":"spin speed [DIRECTION]","gdxfor.getTilt":"tilt angle [TILT]","gdxfor.isFreeFalling":"falling?","gdxfor.isTilted":"tilted [TILT]?","gdxfor.pulled":"pulled","gdxfor.pushed":"pushed","gdxfor.shaken":"shaken","gdxfor.startedFalling":"started falling","gdxfor.tiltDirectionMenu.any":"any","gdxfor.tiltDirectionMenu.back":"back","gdxfor.tiltDirectionMenu.front":"front","gdxfor.tiltDirectionMenu.left":"left","gdxfor.tiltDirectionMenu.right":"right","gdxfor.turnedFaceDown":"turned face down","gdxfor.turnedFaceUp":"turned face up","gdxfor.whenForcePushedOrPulled":"when force sensor [PUSH_PULL]","gdxfor.whenGesture":"when [GESTURE]","gdxfor.whenTilted":"when tilted [TILT]","makeymakey.downArrow":"down arrow","makeymakey.downArrowShort":"아래쪽","makeymakey.leftArrow":"left arrow","makeymakey.leftArrowShort":"왼쪽","makeymakey.rightArrow":"right arrow","makeymakey.rightArrowShort":"오른쪽","makeymakey.spaceKey":"스페이스","makeymakey.upArrow":"up arrow","makeymakey.upArrowShort":"위쪽","makeymakey.whenKeyPressed":"when [KEY] key pressed","makeymakey.whenKeysPressedInOrder":"when [SEQUENCE] pressed in order","microbit.buttonsMenu.any":"아무","microbit.clearDisplay":"화면 지우기","microbit.defaultTextToDisplay":"Hello!","microbit.displaySymbol":"[MATRIX] 보여주기","microbit.displayText":"글자 [TEXT] 보여주기","microbit.gesturesMenu.jumped":"점프하였을","microbit.gesturesMenu.moved":"움직일","microbit.gesturesMenu.shaken":"흔들어졌을","microbit.isButtonPressed":"[BTN] 버튼이 눌려졌는가?","microbit.isTilted":"[DIRECTION] 방향으로 기울어졌는가?","microbit.pinStateMenu.off":"끄기","microbit.pinStateMenu.on":"켜기","microbit.tiltAngle":"[DIRECTION] 방향으로 기울어진 각도","microbit.tiltDirectionMenu.any":"아무","microbit.tiltDirectionMenu.back":"뒤쪽","microbit.tiltDirectionMenu.front":"앞쪽","microbit.tiltDirectionMenu.left":"왼쪽","microbit.tiltDirectionMenu.right":"오른쪽","microbit.whenButtonPressed":"[BTN] 버튼이 눌러졌을 때","microbit.whenGesture":"[GESTURE] 때","microbit.whenPinConnected":"[PIN]번 핀이 연결되었을 때","microbit.whenTilted":"[DIRECTION] 방향으로 기울어졌을 때","music.categoryName":"음악","music.changeTempo":"빠르기를 [TEMPO] 만큼 바꾸기","music.drumBass":"(2) 베이스 드럼","music.drumBongo":"(13) 봉고","music.drumCabasa":"(15) 카바사","music.drumClaves":"(9) 클라베","music.drumClosedHiHat":"(6) 닫힌 하이햇","music.drumConga":"(14) 콩가","music.drumCowbell":"(11) 카우벨 ","music.drumCrashCymbal":"(4) 크래시 심벌","music.drumCuica":"(18) 쿠이카 ","music.drumGuiro":"(16) 귀로 ","music.drumHandClap":"(8) 박수","music.drumOpenHiHat":"(5) 열린 하이햇","music.drumSideStick":"(3) 사이드 스틱","music.drumSnare":"(1) 스네어 드럼 ","music.drumTambourine":"(7) 탬버린","music.drumTriangle":"(12) 트라이앵글 ","music.drumVibraslap":"(17) 비브라슬랩 ","music.drumWoodBlock":"(10) 나무 블록","music.getTempo":"빠르기","music.instrumentBass":"(6) 베이스","music.instrumentBassoon":"(14) 바순","music.instrumentCello":"(8) 첼로 ","music.instrumentChoir":"(15) 합창단 ","music.instrumentClarinet":"(10) 클라리넷 ","music.instrumentElectricGuitar":"(5) 전자 기타 ","music.instrumentElectricPiano":"(2) 전자 피아노 ","music.instrumentFlute":"(12) 플루트 ","music.instrumentGuitar":"(4) 기타","music.instrumentMarimba":"(19) 마림바 ","music.instrumentMusicBox":"(17) 뮤직 박스","music.instrumentOrgan":"(3) 오르간","music.instrumentPiano":"(1) 피아노","music.instrumentPizzicato":"(7) 피치카토 ","music.instrumentSaxophone":"(11) 색소폰 ","music.instrumentSteelDrum":"(18) 스틸 드럼 ","music.instrumentSynthLead":"(20) 신드 리드","music.instrumentSynthPad":"(21) 신드 패드 ","music.instrumentTrombone":"(9) 트럼본","music.instrumentVibraphone":"(16) 비브라폰","music.instrumentWoodenFlute":"(13) 나무 플루트 ","music.midiPlayDrumForBeats":"[DRUM]번 타악기를 [BEATS] 박자로 연주하기","music.midiSetInstrument":"악기를 [INSTRUMENT](으)로 정하기","music.playDrumForBeats":"[DRUM]번 타악기를 [BEATS] 박자로 연주하기","music.playNoteForBeats":"[NOTE]번 음을 [BEATS] 박자로 연주하기","music.restForBeats":"[BEATS] 박자 쉬기 ","music.setInstrument":"악기를 [INSTRUMENT](으)로 정하기","music.setTempo":"빠르기를 [TEMPO](으)로 정하기","pen.categoryName":"펜","pen.changeColorParam":"펜 [COLOR_PARAM]을(를) [VALUE]만큼 바꾸기","pen.changeHue":"펜 색깔을 [HUE]만큼 바꾸기","pen.changeShade":"펜 명암을 [SHADE] 만큼 바꾸기 ","pen.changeSize":"펜 굵기를 [SIZE] 만큼 바꾸기","pen.clear":"모두 지우기","pen.colorMenu.brightness":"명도","pen.colorMenu.color":"색깔","pen.colorMenu.saturation":"채도 ","pen.colorMenu.transparency":"투명도","pen.penDown":"펜 내리기","pen.penUp":"펜 올리기","pen.setColor":"펜 색깔을 [COLOR](으)로 정하기 ","pen.setColorParam":"펜 [COLOR_PARAM]을(를) [VALUE](으)로 정하기","pen.setHue":"펜 색깔을 [HUE](으)로 정하기","pen.setShade":"펜 명암을 [SHADE](으)로 정하기 ","pen.setSize":"펜 굵기를 [SIZE](으)로 정하기","pen.stamp":"도장찍기","text2speech.alto":"중고음","text2speech.categoryName":"Text to Speech","text2speech.defaultTextToSpeak":"안녕 ","text2speech.giant":"저음","text2speech.kitten":"고양이","text2speech.setLanguageBlock":"언어를 [LANGUAGE]로 정하기","text2speech.setVoiceBlock":"음성을 [VOICE]로 정하기","text2speech.speakAndWaitBlock":"[WORDS] 말하기","text2speech.squeak":"고음","text2speech.tenor":"중저음","translate.categoryName":"번역","translate.defaultTextToTranslate":"안녕 ","translate.translateBlock":"[WORDS]을(를) [LANGUAGE]로 번역하기","translate.viewerLanguage":"언어","videoSensing.categoryName":"비디오 감지","videoSensing.direction":"방향","videoSensing.motion":"동작","videoSensing.off":"끄기","videoSensing.on":"켜기","videoSensing.onFlipped":"뒤집힌 상태로 켜기","videoSensing.setVideoTransparency":"비디오 투명도를 [TRANSPARENCY] (으)로 정하기","videoSensing.sprite":"스프라이트","videoSensing.stage":"무대 ","videoSensing.videoOn":"비디오 [ATTRIBUTE]에 대한 [SUBJECT]에서의 관찰값","videoSensing.videoToggle":"비디오 [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"비디오 동작 > [REFERENCE]일 때 ","wedo2.getDistance":"거리","wedo2.getTiltAngle":"[TILT_DIRECTION] 방향으로 기울어진 각도","wedo2.isTilted":"[TILT_DIRECTION_ANY] 방향으로 기울어졌는가?","wedo2.motorDirection.backward":"저쪽","wedo2.motorDirection.forward":"이쪽","wedo2.motorDirection.reverse":"반대쪽","wedo2.motorId.a":"모터 A","wedo2.motorId.all":"모든 모터","wedo2.motorId.b":"모터 B","wedo2.motorId.default":"모터","wedo2.motorOff":"[MOTOR_ID] 끄기","wedo2.motorOn":"[MOTOR_ID] 켜기","wedo2.motorOnFor":"[DURATION] 초 동안 [MOTOR_ID] 켜기","wedo2.playNoteFor":"[NOTE] 번 음을 [DURATION]초 간 연주하기","wedo2.setLightHue":"빛의 색을 [HUE]로 정하기","wedo2.setMotorDirection":"[MOTOR_ID]의 방향을 [MOTOR_DIRECTION]으로 정하기","wedo2.startMotorPower":"[MOTOR_ID] 모터 강도를 [POWER]로 정하기","wedo2.tiltDirection.any":"아무","wedo2.tiltDirection.down":"아래쪽","wedo2.tiltDirection.left":"왼쪽","wedo2.tiltDirection.right":"오른쪽","wedo2.tiltDirection.up":"위쪽","wedo2.whenDistance":"거리 [OP] [REFERENCE] 일 때","wedo2.whenTilted":"[TILT_DIRECTION_ANY] 방향으로 기울일 때","paint.paintEditor.hue":"색상","paint.paintEditor.saturation":"채도","paint.paintEditor.brightness":"명도","paint.paintEditor.costume":"모양","paint.paintEditor.group":"그룹화 적용","paint.paintEditor.ungroup":"그룹화 해제","paint.paintEditor.undo":"되돌리기","paint.paintEditor.redo":"재시도","paint.paintEditor.forward":"앞으로","paint.paintEditor.backward":"뒤로","paint.paintEditor.front":"맨 앞으로","paint.paintEditor.back":"맨 뒤로","paint.paintEditor.more":"기타","paint.modeTools.brushSize":"크기","paint.modeTools.eraserSize":"지우개 크기","paint.modeTools.copy":"복사","paint.modeTools.paste":"붙이기","paint.modeTools.delete":"삭제","paint.modeTools.curved":"굽은 모양","paint.modeTools.pointed":"꺾인 모양","paint.modeTools.thickness":"굵기","paint.modeTools.flipHorizontal":"좌우 뒤집기","paint.modeTools.flipVertical":"상하 뒤집기","paint.modeTools.filled":"채우기","paint.modeTools.outlined":"윤곽선","paint.paintEditor.bitmap":"비트맵으로 바꾸기","paint.paintEditor.vector":"벡터로 바꾸기","paint.paintEditor.fill":"채우기 색","paint.paintEditor.stroke":"윤곽선 색","paint.brushMode.brush":"붓","paint.eraserMode.eraser":"지우개","paint.fillMode.fill":"채우기 색","paint.lineMode.line":"선","paint.ovalMode.oval":"원","paint.rectMode.rect":"직사각형","paint.reshapeMode.reshape":"형태 고치기","paint.roundedRectMode.roundedRect":"모서리가 둥근 직사각형","paint.selectMode.select":"선택","paint.textMode.text":"텍스트","paint.colorPicker.swap":"바꾸기","tw.alerts.autosaving":"복원 지점 생성 중...","tw.alerts.savedToDisk":"컴퓨터에 저장되었습니다.","tw.backpack.rename":"새로운 이름:","tw.browserModal.desc":"최신 버전의 크롬, Mozilla Firefox, Microsoft Edge 또는 Apple Safari를 사용하고 있는지 확인하세요.","tw.changeUsername.cannotChangeWhileRunning":"\'사용자 이름\'은 프로젝트가 실행되는 동안 변경될 수 없습니다.","tw.cloudVariableBadge":"이 프로젝트는 클라우드 변수를 사용합니다. 터보워프는 스크래치와 독립적인 클라우드 변수 서버를 사용합니다. 사용자 이름은 어떤 것으로든 바꿀 수 있으니 사칭을 주의하세요. {learnMore}","tw.code":"소스코드","tw.confirmIncompatibleExtension":"이 확장 기능은 스크래치에 호환되지 않습니다. 프로젝트가 스크래치 웹사이트에 업로드되 지 않을 수 있습니다. 확장 기능을 활성화할까요?","tw.customExtension.description":"URL에서 사용자 지정 확장 프로그램을 불러옵니다. 실험적 개발자 기능입니다.","tw.customExtension.name":"사용자 지정 확장 프로그램","tw.featuredProjectsStudio":"스크래치 스튜디오 보기","tw.feedback":"문의 및 버그 제보","tw.feedbackButton":"문의하기","tw.footer.credits":"크레딧","tw.footer.disclaimer":"TurboWarp는 스크래치, 스크래치 팀, 스크래치 재단에 소속되어 있지 않습니다.","tw.footer.embed":"임베딩","tw.footer.fosshost":"Fosshost에 의해 호스팅 됨","tw.footer.parameters":"URL 파라미터","tw.footer.translate":"번역 돕기","tw.gui.defaultProjectTitle":"프로젝트","tw.guiDefaultTitle":"스크래치 프로젝트를 더 빠르게 실행하기","tw.home.credit":"주의사항 및 크레딧","tw.home.description":"TurboWarp는 스크래치 프로젝트를 JavaScript로 컴파일하여 매우 빠르게 실행할 수 있도록 해주는 스크래치 모드입니다. \\n프로젝트 ID 또는 프로젝트 URL을 붙여넣거나, 아래의 특집 프로젝트를 선택해서 실행해 보세요.","tw.home.instructions":"소개","tw.input.tooltip":"스크래치 프로젝트 주소를 복사한 후 여기에 붙여넣기 하세요!","tw.interpolationEnabled":"보간법 활성화","tw.invalidParameters.clones":"\\"clone\\" URL 파라미터가 유효하지 않습니다","tw.invalidParameters.fps":"\\"fps\\" URL 파라미터가 유효하지 않습니다","tw.loadError":"프로젝트를 로드할 수 없습니다.\\n에러 : {error}","tw.loader.assets.known":"정보를 내려받는 중입니다({complete}/{total}) ...","tw.loader.assets.unknown":"정보를 내려받는 중입니다...","tw.loader.data":"프로젝트 자료를 내려받는 중입니다...","tw.loader.generic":"프로젝트를 불러오는 중입니다...","tw.menuBar.60off":"60 FPS 모드 비활성화","tw.menuBar.60on":"60 FPS 모드 활성화","tw.menuBar.addons":"애드온","tw.menuBar.advanced":"고급 설정","tw.menuBar.changeUsername":"사용자 이름 변경하기","tw.menuBar.cloudOff":"클라우드 변수 비활성화","tw.menuBar.cloudOn":"클라우드 변수 활성화","tw.menuBar.cloudUnavailable":"클라우드 변수를 이용할 수 없습니다","tw.menuBar.cloudUnavailableAlert":"에디터를 열었기 때문에 클라우드 변수를 사용할 수 없습니다.","tw.menuBar.loadRestorePoint":"복원 지점 불러오기","tw.menuBar.moreSettings":"고급 설정","tw.menuBar.newFramerate":"사용할 FPS:","tw.menuBar.reportError1":"일부 스크립트를 컴파일 할 수 없습니다.","tw.menuBar.reportError2":"이것은 버그입니다. 이 버그를 신고해 주세요.","tw.menuBar.saveAs":"{file}로 저장하기","tw.menuBar.seeInside":"스크립트 보기","tw.oldDownload":"다른 파일로 저장","tw.paint.alpha":"불투명도","tw.privacy":"개인정보 보호 정책","tw.saveAs":"다른 이름으로 저장","tw.saveTo":"{file}로 저장","tw.settingsModal.customStageSize":"무대 크기 변경하기","tw.settingsModal.customStageSizeHelp":"스크래치 무대 크기를 480x360외에 다른 것으로 바꿉니다. 넓은 화면을 시도해 보려면 640x360를 시도해 보세요. 매우 적은 프로젝트들은 제대로 작동할 것입니다.","tw.settingsModal.dangerZone":"위험한 기능","tw.settingsModal.disableCompiler":"컴파일러 비활성화하기","tw.settingsModal.disableCompilerHelp":"컴파일러를 비활성화합니다. 프로젝트를 편집하는 동안 스크립트가 즉시 업데이트되도록 하려면 컴파일러를 비활성화해도 됩니다. 이 경우가 아니라면 컴파일러를 비활성화하지 마세요.","tw.settingsModal.featured":"추천 기능","tw.settingsModal.fps":"60 FPS (또는 사용자 지정 FPS) 활성화","tw.settingsModal.fpsHelp":"스크립트를 초당 30회로 실행하는 대신 초당 60회 실행합니다. 대부분의 프로젝트는 이 기능이 활성화된 상태에서 제대로 작동하지 않으며, 이 같은 경우에는 60 FPS모드 대신 보간법을 사용해야 합니다. {customFramerate}","tw.settingsModal.fpsHelp.customFramerate":"30 또는 60 이외의 프레임률을 사용하려면 클릭합니다.","tw.settingsModal.help":"클릭하여 도움말 열기","tw.settingsModal.highQualityPen":"고품질 펜 활성화하기","tw.settingsModal.highQualityPenHelp":"펜 프로젝트가 더 높은 해상도에서 렌더링될 수 있도록 해주며, 에디터에서 적용되는 일부 좌표 반올림을 비활성화합니다. 이 옵션은 모든 프로젝트에 도움이 되지는 않으며 성능에 영향을 미칠 수 있습니다.","tw.settingsModal.infiniteClones":"무제한 복제본 활성화하기","tw.settingsModal.infiniteClonesHelp":"스크래치의 300개 복제본 제한을 비활성화합니다.","tw.settingsModal.interpolation":"보간법 활성화하기","tw.settingsModal.interpolationHelp":"스프라이트의 움직임을 보간해 프로젝트의 동작을 더 부드럽게 만듭니다. 보간법은 3D 프로젝트, 레이트레이서, 펜 프로젝트, 렉이 걸리는 프로젝트 등에서 사용할 경우 오히려 프로젝트를 더 느려지게 만들 수 있습니다.","tw.settingsModal.largeStageWarning":"사용자 지정 무대 크기는 권장되지 않습니다! 대신, 동일한 가로 세로 비율의 더 낮은 크기를 사용하고 전체 화면 모드가 사용자 디스플레이에 맞게 업스케일되도록 합니다.","tw.settingsModal.removeFencing":"무대 밖 동작 제한 풀기","tw.settingsModal.removeFencingHelp":"스프라이트가 화면 밖으로 나갈 수 있도록 하거나, 스프라이트가 원하는 만큼 커지거나 작아질 수 있도록 하거나, 충돌 감지 블록이 화면 밖에서도 작동할 수 있도록 합니다.","tw.settingsModal.removeLimits":"제한 풀기","tw.settingsModal.removeMiscLimits":"기타 몇몇 제한 풀기","tw.settingsModal.removeMiscLimitsHelp":"이미지 효과 제한과 펜 굵기 제한을 제거합니다.","tw.settingsModal.storeProjectOptions":"프로젝트에 고급 설정 저장하기","tw.settingsModal.storeProjectOptionsHelp":"TurboWarp가 이 프로젝트를 불러올 때 현재 설정이 자동으로 적용되도록 고급 설정을 프로젝트에 저장합니다. <워프 타이머>와 <컴파일러 비활성화하기>는 저장되지 않습니다.","tw.settingsModal.title":"고급 설정","tw.settingsModal.warpTimer":"워프 타이머","tw.settingsModal.warpTimerHelp":"루프가 끝날 때까지 중단되지 않고 스크립트가 긴 루프 또는 무한 루프에 갇혀 낮은 프레임률로 실행되는지 확인합니다. 이러면 대부분의 충돌이 해결되지만 성능에 큰 영향을 미치므로 기본적으로 편집기에서만 사용하도록 설정됩니다.","tw.spriteSelectorItem.rename":"이름 재설정하기","tw.studioview.authorAttribution":"제작자 : {author}","tw.studioview.error":"프로젝트의 다음 페이지를 불러오는 도중 오류가 발생했습니다.","tw.studioview.hoverText":"{author}의 \\"{title}\\"","tw.twExtension.description":"이상한 새 블럭들이죠. 스크래치와 호환되지 않습니다.","tw.twExtension.name":"TurboWarp 추가 블럭","tw.usernameModal.help":"이 값은 브라우저의 저장소에 저장됩니다. 클라우드 변수를 포함하는 프로젝트와 상호 작용할 때 기록될 수 있습니다.","tw.usernameModal.help2":"유효한 Scratch 계정에 대응하지 않는 사용자 이름은 클라우드 변수 서버에 의해 거부됩니다. 그대로 남기거나 당신의 Scratch 사용자 이름으로 변경하는 것을 추천합니다.","tw.usernameModal.mustChange":"클라우드 변수 서버가 당신의 사용자 이름이 안전하지 않다고 생각합니다. 다른 것으로 변경하거나 {resetIt} 해 주세요.","tw.usernameModal.mustChange.resetIt":"초기화하기 (권장됨)","tw.usernameModal.reset":"초기화하기","tw.usernameModal.title":"사용자 이름 변경하기","tw.viewFeaturedProjects":"특집 프로젝트를 보려면 클릭하세요.","tw.viewOnScratch":"프로젝트 스크래치에서 보기","tw.webglModal.description":"당신의 브라우저나 컴퓨터가 {webGlLink}. 이 기술은 TurboWarp를 실행하기 위해 필요합니다. 당신의 브라우저와 그래픽 드라이버를 업데이트하거나 컴퓨터를 재시작하세요."},"ha":{"gui.alerts.tryAgain":"sake gwadawa","gui.alerts.download":"saukar","gui.connection.reconnect":"Sake haɗawa","gui.backpack.costumeLabel":"fasali","gui.backpack.soundLabel":"sauti","gui.backpack.scriptLabel":"rubutun","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"masarrafa","gui.backpack.errorBackpack":"An samu kuskuren buɗe masarrafa","gui.backpack.loadingBackpack":"Ana buɗewa...","gui.backpack.more":"ƙari","gui.backpack.emptyBackpack":"babu komai a masarrafa ","gui.unsupportedBrowser.label":"Burausar ba ta daidaituwa","gui.cards.all-tutorials":"koyarwa","gui.cards.shrink":"Rage","gui.cards.expand":"Faɗaɗa","gui.cards.close":"Kulle","gui.cards.more-things-to-try":"Ƙarin abubuwan da za a gwada!","gui.cards.see-more":"Duba ƙari","gui.comingSoon.message1":"Kar ka damu, muna kan dubawa {emoji}","gui.comingSoon.message2":"Yana nan Tafe...","gui.comingSoon.message3":"Muna aiki a kai {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Babu na\'urorin da aka samu","gui.connection.auto-scanning.prescan":"Sanya na\'urarka a kusa, sannan ka fara bincike.","gui.connection.auto-scanning.pressbutton":"Danna madannin kan na\'urarka.","gui.connection.auto-scanning.start-search":"Fara Bincike","gui.connection.connecting-searchbutton":"Bincikawa...","gui.connection.auto-scanning.try-again":"Sake gwadawa","gui.connection.connected":"Yana sadarwa","gui.connection.disconnect":"Ba ya sadarwa","gui.connection.go-to-editor":"Je zuwa wajen gyara","gui.connection.connecting-cancelbutton":"Yana ƙoƙarin fara sadarwa...","gui.connection.error.errorMessage":"Kash, da alama wani abu ya kuskure.","gui.connection.error.tryagainbutton":"Sake gwadawa ","gui.connection.error.helpbutton":"Taimoko","gui.connection.peripheral-name-label":"Sunan na\'ura","gui.connection.connect":"Haɗa","gui.connection.scanning.lookingforperipherals":"Neman na\'urori","gui.connection.scanning.noPeripheralsFound":"Babu na\'urorin da aka samu","gui.connection.scanning.instructions":"Zaɓi na\'urar ka a cikin jerin da ke sama.","gui.connection.search":"Sake sabuntawa","gui.connection.unavailable.installscratchlink":"Tabbatar cewa kana da rubutaccen mahaɗar Scratch (link) a ciki kuma yana aiki","gui.connection.unavailable.enablebluetooth":"Duba cewa an kunna Bluetooth","gui.connection.unavailable.tryagainbutton":"Sake gwadawa ","gui.connection.unavailable.helpbutton":"taimoko","gui.controls.go":"Tafi","gui.controls.stop":"Dakata","gui.crashMessage.label":"Kash! wani abu ya samu matsala.","gui.crashMessage.errorNumber":"An shigar da kuskurenka da lambar {errorId}","gui.crashMessage.reload":"Sake buɗewa","gui.customProcedures.myblockModalTitle":"Yi wani tubali","gui.customProcedures.addAnInputNumberText":"Ƙara shigarwar","gui.customProcedures.numberTextType":"lamba ko rubutu","gui.customProcedures.addAnInputBoolean":"Kara shigawar","gui.customProcedures.booleanType":"boolean","gui.customProcedures.addALabel":"Ƙara laƙabi","gui.customProcedures.runWithoutScreenRefresh":"Tafi ba tare da sabunta allo ba","gui.customProcedures.cancel":"Soke","gui.customProcedures.ok":"TOH","gui.SpriteInfo.direction":"Mafuskanta","gui.directionPicker.rotationStyles.allAround":"Ko\'ina","gui.directionPicker.rotationStyles.leftRight":"Hagu/Dama","gui.directionPicker.rotationStyles.dontRotate":"Kar ka juya","gui.gui.addExtension":"Ƙara Ƙari","gui.gui.codeTab":"Lambar fasaha","gui.gui.backdropsTab":"Hotunan fage","gui.gui.costumesTab":"Fasali","gui.gui.soundsTab":"sauti","gui.extensionLibrary.comingSoon":"Yana nan tafe","gui.extensionLibrary.requires":"Abun buƙata","gui.extensionLibrary.collaboration":"Haɗin kai tare da","gui.library.filterPlaceholder":"Bincika","gui.library.allTag":"Duka","gui.loader.headline":"Ana buɗa aiki","gui.loader.creating":"Ana Ƙirƙirar Aiki","gui.authorInfo.byUser":"ta {username}","gui.menuBar.seeProjectPage":"Duba Shafin Aiki","gui.menuBar.LanguageSelector":"mazaɓar yare","gui.menuBar.tutorialsLibrary":"Koyarwa","gui.menuBar.restoreSprite":"Sabunta Sprite","gui.menuBar.restoreSound":"Sabunta sauti","gui.menuBar.restoreCostume":"Sabunta fasali","gui.menuBar.restore":"Sabuntawa","gui.menuBar.saveNow":"Ajiye yanzu","gui.menuBar.saveAsCopy":"Ajiye a matsayin kwafi","gui.menuBar.remix":"Remix","gui.menuBar.new":"Sabo","gui.menuBar.file":"Fayil","gui.menuBar.downloadToComputer":"Ajiye a kwamfutarka","gui.menuBar.edit":"Gyara","gui.menuBar.turboModeOff":"Kashe yanayin hanzari","gui.menuBar.turboModeOn":"Kunna yanayin hanzari","gui.gui.projectTitlePlaceholder":"Taken aikin anan","gui.menuBar.isShared":"An yaɗa","gui.menuBar.share":"Yaɗa","gui.modal.help":"taimako","gui.modal.back":"Baya","gui.monitor.listMonitor.empty":"(Ba komai)","gui.monitor.listMonitor.listLength":"Tsayi {length}","gui.monitor.contextMenu.default":"asalin karatu","gui.monitor.contextMenu.large":"babban karatu","gui.monitor.contextMenu.slider":"mai zamewa","gui.monitor.contextMenu.sliderRange":"canza kewayen mai zamewa","gui.monitor.contextMenu.import":"shigo da","gui.monitor.contextMenu.export":"fidda","gui.monitor.contextMenu.hide":"ɓoye","gui.playButton.play":"Kunna","gui.playButton.stop":"Dakata","gui.gui.variableScopeOptionAllSprites":"Ga duka sprites","gui.gui.variableScopeOptionSpriteOnly":"Ga wannan sprite ɗin kawai","gui.gui.cloudVariableOption":"Yanayin canjin girgije (an adana akan saba)","gui.gui.variablePromptAllSpritesMessage":"Wannan abun mai canzawa zai samu ga duka sprites.","gui.gui.listPromptAllSpritesMessage":"Wannan jerin zai samu ga duka sprites.","gui.prompt.cancel":"Soke","gui.prompt.ok":"TOH","gui.playbackStep.stopMsg":"Dakata","gui.playbackStep.playMsg":"Kunna","gui.playbackStep.loadingMsg":"Ana lodawa...","gui.playbackStep.saveMsg":"Ajiye","gui.playbackStep.reRecordMsg":"Sake-ɗaukar tariya","gui.recordModal.title":"ɗauki tariyar sauti","gui.recordingStep.beginRecord":"Fara ɗaukar tariya ta hanyar danna madannin da ke ƙasa","gui.recordingStep.permission":"{arrow}Muna buƙatar izinin ka domin yin amfani da na\'urar ɗaukar sautin ka","gui.recordingStep.stop":"Dakatar da ɗaukar tariya","gui.recordingStep.record":"ɗaukar tariya","gui.sliderModal.min":"Mafi ƙarancin ƙima","gui.sliderModal.max":"Mafi girman ƙima","gui.sliderModal.title":"Canza kewayon darjewa","gui.sliderPrompt.cancel":"Soke","gui.sliderPrompt.ok":"TOH","gui.soundEditor.sound":"Sauti","gui.soundEditor.play":"Kunna","gui.soundEditor.stop":"Dakata","gui.soundEditor.copy":"Kwafa","gui.soundEditor.paste":"Manna","gui.soundEditor.copyToNew":"Kwafa zuwa Sabo","gui.soundEditor.delete":"Goge","gui.soundEditor.save":"Ajiye","gui.soundEditor.undo":"warware ","gui.soundEditor.redo":"Sake yi","gui.soundEditor.faster":"Kara sauri","gui.soundEditor.slower":"Sannu a hankali","gui.soundEditor.echo":"amsa kuwa","gui.soundEditor.robot":"mutum-mutumi mai aiki da na\'urar fasaha","gui.soundEditor.louder":"Da ƙarfi","gui.soundEditor.softer":"Da laushi","gui.soundEditor.reverse":"da baya","gui.soundEditor.fadeOut":"ɓace a hankali","gui.soundEditor.fadeIn":"fito a hankali","gui.soundEditor.mute":"Yi shiru","gui.SpriteInfo.spritePlaceholder":"Suna","gui.SpriteInfo.sprite":"Sprite","gui.SpriteInfo.show":"Nuna","gui.SpriteInfo.size":"Girma","gui.spriteSelectorItem.contextMenuDuplicate":"kofi","gui.spriteSelectorItem.contextMenuExport":"fitarwa","gui.spriteSelectorItem.contextMenuDelete":"goge","gui.spriteSelector.addSpriteFromLibrary":"Zaɓi Sprite","gui.spriteSelector.addSpriteFromPaint":"Fenti","gui.spriteSelector.addSpriteFromSurprise":"Ban Mamaki","gui.spriteSelector.addSpriteFromFile":"Sanya Sprite","gui.stageHeader.stageSizeLarge":"Canja zuwa babban mataki","gui.stageHeader.stageSizeSmall":"Canja zuwa ƙaramin mataki","gui.stageHeader.stageSizeFull":"Shigar da yanayin cikakken allo","gui.stageHeader.stageSizeUnFull":"Fita daga yanayin cikakken allo","gui.stageHeader.fullscreenControl":"Ikon cikakken allo","gui.spriteSelector.addBackdropFromLibrary":"Zaɓi hoton fage","gui.stageSelector.addBackdropFromPaint":"Fenti","gui.stageSelector.addBackdropFromSurprise":"Ban Mamaki","gui.stageSelector.addBackdropFromFile":"Saka hoton fage","gui.stageSelector.stage":"Mataki","gui.stageSelector.backdrops":"hotunan fage","gui.telemetryOptIn.label":"Yi rahoton ƙididdiga dan inganta Scratch","gui.telemetryOptIn.body1":"Tawagar Scratch koyaushe tana neman fahimtar yadda ake amfani da Scratch a duniya. Dan taimakawa wannan ƙoƙarin, zaka iya ƙyale Scratch ya aika bayanan yadda ake amfani da shi da kansa zuwa Tawagar Scratch.","gui.telemetryOptIn.body2":"Bayanan da muke tattarawa sun haɗa da zaɓin harshe, amfanin tubali, da wasu abubuwan da ke faruwa kamar adanawa, buɗewa, da saka aiki. BA mu tattara kowanne bayanin sirri. Da fatan za a duba {privacyPolicyLink} dan ƙarin bayani.","gui.telemetryOptIn.privacyPolicyLink":" ƙa\'idojin sirri","gui.telemetryOptIn.optInText":"Yaɗa bayanan amfanin data na tare da Tawagar Scratch","gui.telemetryOptIn.optInTooltip":"Kunna telemetry","gui.telemetryOptIn.optOutText":"Kada ku yaɗa bayanan amfanin data na tare da Tawagar Scratch","gui.telemetryOptIn.optOutTooltip":"Kashe telemetry","gui.telemetryOptIn.settingWasUpdated":"An sabunta saitin ka.","gui.telemetryOptIn.buttonClose":"Kulle","gui.turboMode.active":"Yanayin hanzari","gui.webglModal.label":"Burauzar bata daidaituwa da WebGL","gui.webglModal.webgllink":"ba ya daidaituwa da WebGL","gui.costumeLibrary.chooseABackdrop":"Zaɓi hoton fage","gui.costumeLibrary.chooseACostume":"Zaɓi fasali","gui.costumeTab.addBackdropFromLibrary":"Zaɓi hoton fage","gui.costumeTab.addCostumeFromLibrary":"Zaɓi fasali","gui.costumeTab.addBlankCostume":"Fenti","gui.costumeTab.addSurpriseCostume":"Ban Mamaki","gui.costumeTab.addFileBackdrop":"Saka hoton fage","gui.costumeTab.addFileCostume":"Saka fasali","gui.extensionLibrary.chooseAnExtension":"Zaɓi ƙari","gui.extensionLibrary.extensionUrl":"shigar da URL ɗin ƙarin","gui.monitors.importListColumnPrompt":"Wanne ginshiƙi ya kamata a yi amfani da (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"An kasa fara ɗaukar tariya","gui.soundLibrary.chooseASound":"Zaɓi Sauti","gui.soundTab.fileUploadSound":"Saka sauti","gui.soundTab.surpriseSound":"Ban Mamaki","gui.soundTab.recordSound":"ɗaukar tariya","gui.soundTab.addSoundFromLibrary":"Zaɓi Sauti","gui.spriteLibrary.chooseASprite":"Zaɓi Sprite","gui.tipsLibrary.tutorials":"Zaɓi koyarwa","gui.alerts.createsuccess":"An ƙirƙiri sabon aiki.","gui.alerts.createcopysuccess":"An ajiye aikin a matsayin kwafi.","gui.alerts.createremixsuccess":"An ajiye aikin a matsayin remix.","gui.alerts.creating":"Ƙirƙirar sabo…","gui.alerts.creatingCopy":"Ana kwafin aikin…","gui.alerts.creatingRemix":"Ana sabunta aikin…","gui.alerts.creatingError":"An kasa haɗa aikin. A yi haƙuri a sake gwadawa!","gui.alerts.savingError":"an kasa ajiye aikin","gui.alerts.savesuccess":"An ajiye aikin.","gui.alerts.saving":"Ana Ajiye aikin…","gui.alerts.cloudInfo":"Dan Allah a lura, girgijen ma\'adanan kwamfuta mai iya canzawa ya na iya tallafawa lambobi ne kawai, banda haruffa ko alamomi.{learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Samu Ƙarin bayani","gui.alerts.importing":"Ana shigo da…","gui.defaultProject.variable":"abubuwa masu canzawa na","gui.extension.music.name":"Kiɗa","gui.extension.music.description":"Buga kayan kiɗa da ganga","gui.extension.pen.name":"Alƙalami","gui.extension.pen.description":"Zana da sprites dinka.","gui.extension.videosensing.name":"fasahar gano yanayin bidiyo ","gui.extension.videosensing.description":"gano motsi da kamara.","gui.extension.text2speech.name":"Rubutu zuwa Magana","gui.extension.text2speech.description":"Sanya ayyukanka suyi magana.","gui.extension.translate.name":"Fassara","gui.extension.translate.description":"Fassara rubutu zuwa yaruka da yawa.","gui.extension.makeymakey.description":"Maida komai zuma madanni.","gui.extension.microbit.description":"Sada ayyukanka zuwa ga duniya.","gui.extension.microbit.connectingMessage":"Yana Sadarwa","gui.extension.ev3.description":"Gina mutum-mutumi masu mu\'amala da kuma ƙari.","gui.extension.ev3.connectingMessage":"Yana sadarwa. Tabbatar cewa fin ɗin dake a EV3 ɗinka an saita shi zuwa 1234.","gui.extension.boost.description":"Maida ƙirƙire-ƙirƙiren mutum-mutumi masu fasaha zuwa rayuwa.","gui.extension.boost.connectingMessage":"Yana sadarwa","gui.extension.wedo2.description":"Gina tare da mota da kuma na\'urar ganowa","gui.extension.wedo2.connectingMessage":"Yana Sadarwa","gui.extension.gdxfor.description":"Gano turi, ja, motsi da juyi.","gui.extension.gdxfor.connectingMessage":"Yana sadarwa ","gui.libraryTags.all":"Duka","gui.libraryTags.animals":"dabbobi","gui.libraryTags.dance":"rawa","gui.libraryTags.effects":"Tasirin","gui.libraryTags.fantasy":"Ruɗi","gui.libraryTags.fashion":"Salon ƙawatarwa","gui.libraryTags.food":"Abinci","gui.libraryTags.indoors":"Daga ciki","gui.libraryTags.loops":"Maimaituwa","gui.libraryTags.music":"Waka","gui.libraryTags.notes":"Rubutu","gui.libraryTags.outdoors":"Daga waje","gui.libraryTags.patterns":"Tsaruka","gui.libraryTags.people":"Mutane","gui.libraryTags.percussion":"Goguwa","gui.libraryTags.space":"Gurbi","gui.libraryTags.sports":"Wasanni","gui.libraryTags.underwater":"Karkashin ruwa","gui.libraryTags.voice":"Murya","gui.libraryTags.wacky":"Marar tsari","gui.libraryTags.animation":"Zane mai motsi","gui.libraryTags.art":"Zanen fasaha","gui.libraryTags.games":"Wasanni","gui.libraryTags.stories":"Labarai","gui.libraryTags.letters":"harfofi","gui.opcodeLabels.direction":"mafuskanta","gui.opcodeLabels.xposition":"matsayin x","gui.opcodeLabels.yposition":"matsayin y","gui.opcodeLabels.size":"Girma","gui.opcodeLabels.costumename":"Sunan fasali","gui.opcodeLabels.costumenumber":"Lambar fasali ","gui.opcodeLabels.backdropname":"Sunan hoton fage ","gui.opcodeLabels.backdropnumber":"Lambar hoton fage ","gui.opcodeLabels.volume":"ƙarfin sauti","gui.opcodeLabels.tempo":"Saurin sauti","gui.opcodeLabels.answer":"Amsa","gui.opcodeLabels.loudness":"Yanayin ƙara","gui.opcodeLabels.username":"Sunnan mai amfani","gui.opcodeLabels.year":"Shekara","gui.opcodeLabels.month":"Wata","gui.opcodeLabels.date":"Kwanan wata","gui.opcodeLabels.dayofweek":"ranar mako","gui.opcodeLabels.hour":"sa\'a ","gui.opcodeLabels.minute":"minti ","gui.opcodeLabels.second":"Daƙiƙa","gui.opcodeLabels.timer":"Abun ƙidayar lokaci ","gui.sharedMessages.backdrop":"hoton fage {index}","gui.sharedMessages.costume":"Fasali{index}","gui.sharedMessages.sprite":"Sprite{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Shin za a canza abubuwan da ke cikin wannan aikin na yanzu?","gui.sharedMessages.loadFromComputerTitle":"buɗe daga kwanfutarka","boost.color.any":"kowane launi","boost.color.black":"baƙi","boost.color.blue":"shuɗi","boost.color.green":"kore","boost.color.red":"ja","boost.color.white":"fari","boost.color.yellow":"rawaya","boost.getMotorPosition":"matsayin moto [MOTOR_REPORTER_ID] ","boost.getTiltAngle":"karkata kwanar [TILT_DIRECTION]","boost.motorDirection.backward":"waccan hanyar","boost.motorDirection.forward":"wannan hanyar","boost.motorDirection.reverse":"da baya","boost.motorOff":"kashe motar [MOTOR_ID]","boost.motorOn":"kunna motar [MOTOR_ID]","boost.motorOnFor":"juya motar [MOTOR_ID] na daƙiƙoƙi [DURATION] ","boost.motorOnForRotation":"juya motar [MOTOR_ID] na juyawa [ROTATION] ","boost.seeingColor":"ganin tubalin [COLOR] ?","boost.setLightHue":"saita launin haske zuwa [HUE]","boost.setMotorDirection":"saita motar [MOTOR_ID] mafuskantar [MOTOR_DIRECTION]","boost.setMotorPower":"saita gudun motar [MOTOR_ID] zuwa [POWER] %","boost.tiltDirection.any":"kowanne ","boost.tiltDirection.down":"ƙasa","boost.tiltDirection.left":"hagu","boost.tiltDirection.right":"dama","boost.tiltDirection.up":"sama","boost.whenColor":"a lokacin da aka ga tubalin [COLOR] ","boost.whenTilted":"a lokacin da aka karkata [TILT_DIRECTION_ANY]","ev3.beepNote":"yi ƙaran bif ɗin [NOTE] na daƙiƙa [TIME]","ev3.buttonPressed":"an danna madannin [PORT] ?","ev3.getBrightness":"haske","ev3.getDistance":"nisa","ev3.getMotorPosition":"matsayin motar [PORT]","ev3.motorSetPower":"motar [PORT] saita ƙarfi [POWER] %","ev3.motorTurnClockwise":"motar [PORT] juya wannan hanyar na daƙiƙoƙi [TIME] ","ev3.motorTurnCounterClockwise":"motar [PORT] juya waccan hanyar na daƙiƙoƙi [TIME] ","ev3.whenBrightnessLessThan":"a lokacin da haske < [DISTANCE]","ev3.whenButtonPressed":"a lokacin da aka danna madannin [PORT] ","ev3.whenDistanceLessThan":"a lokacin da nisa < [DISTANCE]","gdxfor.getAcceleration":"sauri [DIRECTION]","gdxfor.getForce":"ƙarfi","gdxfor.getSpin":"gudun juyawa [DIRECTION]","gdxfor.getTilt":"karkata kwanar [TILT]","gdxfor.isFreeFalling":"faɗuwa?","gdxfor.isTilted":"an karkata [TILT]","gdxfor.pulled":"an ja","gdxfor.pushed":"an tura","gdxfor.shaken":"an girgiza","gdxfor.startedFalling":"ya fara faɗuwa","gdxfor.tiltDirectionMenu.any":"kowanne ","gdxfor.tiltDirectionMenu.back":"baya","gdxfor.tiltDirectionMenu.front":"gaba","gdxfor.tiltDirectionMenu.left":"hagu","gdxfor.tiltDirectionMenu.right":"dama","gdxfor.turnedFaceDown":"an juya fuskar na kallon ƙasa","gdxfor.turnedFaceUp":"an juya fuskar na kallon sama","gdxfor.whenForcePushedOrPulled":"a lokacin da na\'urar gano ƙarfi a [PUSH_PULL]","gdxfor.whenGesture":"a lokacin da [GESTURE]","gdxfor.whenTilted":"a lokacin da aka karkata [TILT]","makeymakey.downArrow":"kibiyar ƙasa","makeymakey.downArrowShort":"ƙasa","makeymakey.leftArrow":"kibiyar hagu","makeymakey.leftArrowShort":"hagu","makeymakey.rightArrow":"kibiyar dama","makeymakey.rightArrowShort":"dama","makeymakey.spaceKey":"gurbi","makeymakey.upArrow":"kibiyar sama","makeymakey.upArrowShort":"sama","makeymakey.whenKeyPressed":"a lokacin da aka danna madannin [KEY] ","makeymakey.whenKeysPressedInOrder":"a lokacin da aka danna [SEQUENCE] a tsari","microbit.buttonsMenu.any":"kowanne ","microbit.clearDisplay":"share nunawa","microbit.defaultTextToDisplay":"Barka!","microbit.displaySymbol":"nuna [MATRIX]","microbit.displayText":"nuna rubutun [TEXT]","microbit.gesturesMenu.jumped":"anyi tsalle","microbit.gesturesMenu.moved":"an motsa","microbit.gesturesMenu.shaken":"an girgiza","microbit.isButtonPressed":"an danna madannin [BTN] ?","microbit.isTilted":"an karkata [DIRECTION]? ","microbit.pinStateMenu.off":"kashe","microbit.pinStateMenu.on":"kunna","microbit.tiltAngle":"karkata kwanar [DIRECTION]","microbit.tiltDirectionMenu.any":"kowanne ","microbit.tiltDirectionMenu.back":"baya","microbit.tiltDirectionMenu.front":"gaba","microbit.tiltDirectionMenu.left":"hagu","microbit.tiltDirectionMenu.right":"dama","microbit.whenButtonPressed":"a lokacin da aka danna madannin [BTN]","microbit.whenGesture":"a lokacin da [GESTURE]","microbit.whenPinConnected":"a lokacin da mabudin sirri [PIN] ya sadu","microbit.whenTilted":"a lokacin da aka karkata [DIRECTION]","music.categoryName":"waƙa","music.changeTempo":"canza saurin da [TEMPO]","music.drumBass":"(2) ƙaran ganga","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) rufaffen Hi-Hat","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Cowbell","music.drumCrashCymbal":"(4) Crash Cymbal","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) tafin hannu","music.drumOpenHiHat":"(5) buda Hi-Hat","music.drumSideStick":"(3) Sandar gefe","music.drumSnare":"(1) Gangar Snare","music.drumTambourine":"(7) Tambourine","music.drumTriangle":"(12) alwatika","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Tubalin katako","music.getTempo":"sauri","music.instrumentBass":"(6) Bass","music.instrumentBassoon":"(14) Bassoon","music.instrumentCello":"(8) Cello","music.instrumentChoir":"(15) Mawaƙa","music.instrumentClarinet":"(10) Clarinet","music.instrumentElectricGuitar":"(5) Jitan wuta ","music.instrumentElectricPiano":"(2) Fiyanon wuta","music.instrumentFlute":"(12) Siriki","music.instrumentGuitar":"(4) Jita","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) akwatin kiɗa","music.instrumentOrgan":"(3) Sassa","music.instrumentPiano":"(1) Fiyano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxophone","music.instrumentSteelDrum":"(18) Gangar tasa","music.instrumentSynthLead":"(20) Synth Lead","music.instrumentSynthPad":"(21) Synth Pad","music.instrumentTrombone":"(9) Trombone","music.instrumentVibraphone":"(16) Vibraphone","music.instrumentWoodenFlute":"(13) Sirikin katako","music.midiPlayDrumForBeats":"buga gangar [DRUM] na bugun [BEATS]","music.midiSetInstrument":"saita kayan aikin zuwa [INSTRUMENT]","music.playDrumForBeats":"buga gangar [DRUM] na bugun [BEATS]","music.playNoteForBeats":"buga rubutun [NOTE] na bugun [BEATS]","music.restForBeats":"huta na bugun [BEATS]","music.setInstrument":"saita kayan aikin zuwa [INSTRUMENT]","music.setTempo":"saita saurin zuwa [TEMPO]","pen.categoryName":"alƙalami","pen.changeColorParam":"canja alƙalami [COLOR_PARAM] da [VALUE]","pen.changeHue":"canja launin alkalami da [HUE]","pen.changeShade":"canja launin zanen alkalami da [SHADE]","pen.changeSize":"canja girman alkalamin da [SIZE]","pen.clear":"share duka","pen.colorMenu.brightness":"haske","pen.colorMenu.color":"launi","pen.colorMenu.saturation":"yanayin launi","pen.colorMenu.transparency":"bayyanar da asali","pen.penDown":"alkalamin kasa","pen.penUp":"alkalamin sama","pen.setColor":"saita launin alƙalamin zuwa [COLOR]","pen.setColorParam":"saita alkalamin [COLOR_PARAM] zuwa [VALUE]","pen.setHue":"saita launin alkalami zuwa [HUE]","pen.setShade":"saita yanayin launin alkalami zuwa [SHADE]","pen.setSize":"saita girman alkalami zuwa [SIZE]","pen.stamp":"tambari","text2speech.alto":"alto","text2speech.categoryName":"rubutu zuwa jawabi","text2speech.defaultTextToSpeak":"barka","text2speech.giant":"basamude","text2speech.kitten":"kyanwa","text2speech.setLanguageBlock":"saita yare zuwa [LANGUAGE]","text2speech.setVoiceBlock":"saita murya zuwa [VOICE]","text2speech.speakAndWaitBlock":"yi magana[WORDS]","text2speech.squeak":"squeak","text2speech.tenor":"tenor","translate.categoryName":"fassara","translate.defaultTextToTranslate":"barka","translate.translateBlock":"fassara [WORDS] zuwa [LANGUAGE]","translate.viewerLanguage":"yare","videoSensing.categoryName":"fasahar gano yanayin bidiyo","videoSensing.direction":"mafuskanta","videoSensing.motion":"motsi","videoSensing.off":"kashe","videoSensing.on":"kunna","videoSensing.onFlipped":"kunna juyayye","videoSensing.setVideoTransparency":"Saita ganin bayyanar bidiyon zuwa [TRANSPARENCY]","videoSensing.sprite":"sprite","videoSensing.stage":"mataki","videoSensing.videoOn":"bidiyon [ATTRIBUTE] akan [SUBJECT]","videoSensing.videoToggle":"juya bidiyon [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"a lokacin da motsin bidiyon > [REFERENCE]","wedo2.getDistance":"nisa","wedo2.getTiltAngle":"karkata kwanan [TILT_DIRECTION]","wedo2.isTilted":"an karkata [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"waccan hanyar","wedo2.motorDirection.forward":"wannan hanyar","wedo2.motorDirection.reverse":"da baya","wedo2.motorId.a":"motar A","wedo2.motorId.all":"dukkan motoci","wedo2.motorId.b":"motar B","wedo2.motorId.default":"mota","wedo2.motorOff":"kashe [MOTOR_ID]","wedo2.motorOn":"kunna [MOTOR_ID]","wedo2.motorOnFor":"kunna [MOTOR_ID] na daƙiƙoƙi [DURATION] ","wedo2.playNoteFor":"kunna sautin [NOTE] na daƙiƙoƙi [DURATION]","wedo2.setLightHue":"saita launin haske zuwa [HUE]","wedo2.setMotorDirection":"saita mafuskantar [MOTOR_ID] zuwa [MOTOR_DIRECTION]","wedo2.startMotorPower":"saita ƙarfin [MOTOR_ID] zuwa [POWER] ","wedo2.tiltDirection.any":"kowanne ","wedo2.tiltDirection.down":"ƙasa","wedo2.tiltDirection.left":"hagu","wedo2.tiltDirection.right":"dama","wedo2.tiltDirection.up":"sama","wedo2.whenDistance":"a lokacin nisan [OP] [REFERENCE]","wedo2.whenTilted":"a lokacin da aka karkata [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"launi","paint.paintEditor.saturation":"Yanayin tumbatsa","paint.paintEditor.brightness":"yanayin haske","paint.paintEditor.costume":"Fasali ","paint.paintEditor.group":"Rukuni","paint.paintEditor.ungroup":"Raba rukuni","paint.paintEditor.undo":"warwarewa","paint.paintEditor.redo":"sake yi","paint.paintEditor.forward":"ci gaba","paint.paintEditor.backward":"ci baya","paint.paintEditor.front":"Gaba","paint.paintEditor.back":"Baya","paint.paintEditor.more":"ƙari","paint.modeTools.brushSize":"girma","paint.modeTools.eraserSize":"Girman abun gogewa","paint.modeTools.copy":"kwafa","paint.modeTools.paste":"manna","paint.modeTools.delete":"goge","paint.modeTools.curved":"mai lanƙwasa","paint.modeTools.pointed":"An nuna","paint.modeTools.thickness":"kauri","paint.modeTools.flipHorizontal":"Jefa a kwance","paint.modeTools.flipVertical":"Jefa a tsaye","paint.modeTools.filled":"an cika","paint.modeTools.outlined":"ƙayyadadde","paint.paintEditor.bitmap":"Maida zuwa bitmap","paint.paintEditor.vector":"maida zuwa tataccen zanen kwamfuta","paint.paintEditor.fill":"cika","paint.paintEditor.stroke":"ƙayyadewa","paint.brushMode.brush":"burushi","paint.eraserMode.eraser":"abun gogewa","paint.fillMode.fill":"cika","paint.lineMode.line":"layi","paint.ovalMode.oval":"da\'ira","paint.rectMode.rect":"murabba\'i mai dari","paint.reshapeMode.reshape":"sake siffantawa","paint.roundedRectMode.roundedRect":"Lanƙwasasshen murabba\'i mai dari ","paint.selectMode.select":"Zaɓa","paint.textMode.text":"rubutu","paint.colorPicker.swap":"musanya"},"hy":{"gui.alerts.tryAgain":"Կրկին փորձեք","gui.alerts.download":"Ներբեռնել","gui.connection.reconnect":"Վերամիացում","gui.backpack.costumeLabel":"զգեստ","gui.backpack.soundLabel":"ձայն","gui.backpack.scriptLabel":"սցենար","gui.backpack.spriteLabel":"կերպար","gui.backpack.header":"Ուսապարկ","gui.backpack.errorBackpack":"Չհաջողվեց բեռնել ուսապարկը","gui.backpack.loadingBackpack":"Բեռնում․․․","gui.backpack.more":"Ավելին","gui.backpack.emptyBackpack":"Ուսապարկը դատարկ է","gui.unsupportedBrowser.label":"Զննարկիչը չի սպասարկվում","gui.cards.all-tutorials":"Ձեռնարկներ","gui.cards.shrink":"Փոքրացնել","gui.cards.expand":"Ընդլայնել","gui.cards.close":"Փակել","gui.cards.more-things-to-try":"Փորձել ավելին","gui.cards.see-more":"Տեսնել ավելին","gui.comingSoon.message1":"Մի անհանգստացեք, մենք աշխատում ենք դրա վրա {emoji}","gui.comingSoon.message2":"Շուտով...","gui.comingSoon.message3":"Մենք աշխատում ենք դրա վրա {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Ոչ մի սարք չի գտնվել","gui.connection.auto-scanning.prescan":"Մոտեցրեք սարքը և սկսեք որոնումը:","gui.connection.auto-scanning.pressbutton":"Սեղմեք սարքի վրայի կոճակը։","gui.connection.auto-scanning.start-search":"Սկսել որոնումը","gui.connection.connecting-searchbutton":"Որոնում․․․","gui.connection.auto-scanning.try-again":"Կրկին փորձեք","gui.connection.connected":"Միացված է ","gui.connection.disconnect":"Անջատել","gui.connection.go-to-editor":"Գնալ խմբագիր","gui.connection.connecting-cancelbutton":"Միացում․․․","gui.connection.error.errorMessage":"Վա՜յ, կարծես սխալ է տեղի ունեցել:","gui.connection.error.tryagainbutton":"Կրկին փորձեք","gui.connection.error.helpbutton":"Օգնություն ","gui.connection.peripheral-name-label":"Սարքի անունը","gui.connection.connect":"Միանալ","gui.connection.scanning.lookingforperipherals":"Սարքերի որոնում","gui.connection.scanning.noPeripheralsFound":"Ոչ մի սարք չի գտնվել","gui.connection.scanning.instructions":"Վերը նշված ցուցակից ընտրեք Ձեր սարքը:","gui.connection.search":"Թարմացնել","gui.connection.unavailable.installscratchlink":"Համոզվեք, որ Scratch link-ն տեղադրված և գործարկված է","gui.connection.unavailable.enablebluetooth":"Ստուգեք, որ բլութութը միացած լինի","gui.connection.unavailable.tryagainbutton":"Կրկին փորձեք","gui.connection.unavailable.helpbutton":"Օգնություն ","gui.controls.go":"Գնալ","gui.controls.stop":"Դադար","gui.crashMessage.label":"Վա՜յ, ինչ որ բան այնպես չգնաց:","gui.crashMessage.errorNumber":"Ձեր սխալը գրանցվել է {errorId} id-ով ","gui.crashMessage.reload":"Նորից բեռնել","gui.customProcedures.myblockModalTitle":"Ստեղծել մասնիկ","gui.customProcedures.addAnInputNumberText":"Ավելացնել ներմուծման դաշտ","gui.customProcedures.numberTextType":"թվային կամ տեքստ","gui.customProcedures.addAnInputBoolean":"Ավելացնել ներմուծման դաշտ","gui.customProcedures.booleanType":"Տրամաբանական","gui.customProcedures.addALabel":"Ավելացնել պիտակ","gui.customProcedures.runWithoutScreenRefresh":"Գործարկել առանց էկրանը թարմացնելու","gui.customProcedures.cancel":"Չեղարկել","gui.customProcedures.ok":"Լավ","gui.SpriteInfo.direction":"Ուղղություն","gui.directionPicker.rotationStyles.allAround":"Շուրջ բոլորը","gui.directionPicker.rotationStyles.leftRight":"Ձախ/Աջ","gui.directionPicker.rotationStyles.dontRotate":"Չպտտել","gui.gui.addExtension":"Ավելացնել ընդլայնում","gui.gui.codeTab":"Սցենարներ","gui.gui.backdropsTab":"Ետնապատկեր","gui.gui.costumesTab":"Զգեստներ","gui.gui.soundsTab":"Ձայն","gui.extensionLibrary.comingSoon":"Շուտով","gui.extensionLibrary.requires":"Պահանջվում է","gui.extensionLibrary.collaboration":"Համագործակցությունը","gui.library.filterPlaceholder":"Որոնել","gui.library.allTag":"Բոլորը","gui.loader.headline":"Նախագծի բեռնում ․․․","gui.loader.creating":"Նախագծի ստեղծում","gui.authorInfo.byUser":"{username}-ի կողմից","gui.menuBar.seeProjectPage":"Տեսնել նախագծի էջը","gui.menuBar.LanguageSelector":"Լեզվի ընտրություն","gui.menuBar.tutorialsLibrary":"Ձեռնարկներ","gui.menuBar.restoreSprite":"Վերականգնել կերպարը","gui.menuBar.restoreSound":"Վերականգնել ձայնը","gui.menuBar.restoreCostume":"Վերականգնել զգեստը","gui.menuBar.restore":"Վերականգնել","gui.menuBar.saveNow":"Պահել հիմա","gui.menuBar.saveAsCopy":"Պահել, որպես պատճեն","gui.menuBar.remix":"Նոր տարբերակ","gui.menuBar.new":"Նոր","gui.menuBar.file":"Նիշք","gui.menuBar.downloadToComputer":"Պահել համակարգչում ","gui.menuBar.edit":"Խմբագրել","gui.menuBar.turboModeOff":"Անջատել արագացված ռեժիմը","gui.menuBar.turboModeOn":"Միացնել արագացված ռեժիմը","gui.gui.projectTitlePlaceholder":"Նախագծի անվանումն այստեղ","gui.menuBar.isShared":"Կիսված է","gui.menuBar.share":"Կիսվել","gui.modal.help":"Օգնություն ","gui.modal.back":"Հետ գնալ","gui.monitor.listMonitor.empty":"(դատարկ)","gui.monitor.listMonitor.listLength":"երկարություն {length}","gui.monitor.contextMenu.default":"Ընթերցման նորմալ էկրան","gui.monitor.contextMenu.large":"Ընթերցման մեծ էկրան","gui.monitor.contextMenu.slider":"սահիչ","gui.monitor.contextMenu.sliderRange":"փոխել սահիչի միջակայքը","gui.monitor.contextMenu.import":"ներմուծել","gui.monitor.contextMenu.export":"արտահանել","gui.monitor.contextMenu.hide":"թաքցնել","gui.playButton.play":"Արտաբերել","gui.playButton.stop":"Դադար","gui.gui.variableScopeOptionAllSprites":"Բոլոր կերպարների համար","gui.gui.variableScopeOptionSpriteOnly":"Միայն այս կերպարի համար","gui.gui.cloudVariableOption":"Ամպային փոփոխական (պահպանվում է սերվերում)","gui.gui.variablePromptAllSpritesMessage":"Այս փոփոխականը հասանելի կլինի բոլոր կերպարների համար։","gui.gui.listPromptAllSpritesMessage":"Սա հասանելի կլինի բոլոր կերպարների համար։","gui.prompt.cancel":"Չեղարկել","gui.prompt.ok":"Լավ","gui.playbackStep.stopMsg":"Դադար","gui.playbackStep.playMsg":"Արտաբերել","gui.playbackStep.loadingMsg":"Բեռնում․․․","gui.playbackStep.saveMsg":"Պահել","gui.playbackStep.reRecordMsg":"Վերաձայնագրել","gui.recordModal.title":"Ձայնագրություն","gui.recordingStep.beginRecord":"Սկսել ձայնագրությունը` սեղմելով ներգևի կոճակը","gui.recordingStep.permission":"{arrow} Խոսափողն օգտագործելու համար հարկավոր է Ձեր թույլտվությունը ","gui.recordingStep.stop":"Դադարեցնել ձայնագրումը","gui.recordingStep.record":"Ձայնագրել","gui.sliderModal.min":"Նվազագույն արժեք","gui.sliderModal.max":"Առավելագույն արժեք","gui.sliderModal.title":"Փոխել սահման միջակայքը","gui.sliderPrompt.cancel":"Չեղարկել","gui.sliderPrompt.ok":"Լավ","gui.soundEditor.sound":"Ձայն","gui.soundEditor.play":"Արտաբերել","gui.soundEditor.stop":"Դադար","gui.soundEditor.copy":"Պատճենել","gui.soundEditor.paste":"Զետեղել","gui.soundEditor.copyToNew":"Պատճենել նորին","gui.soundEditor.delete":"Ջնջել","gui.soundEditor.save":"Պահել","gui.soundEditor.undo":"Հետ գնալ","gui.soundEditor.redo":"Առաջ գնալ","gui.soundEditor.faster":"Ավելի արագ","gui.soundEditor.slower":"Ավելի դանդաղ","gui.soundEditor.echo":"Արձագանք","gui.soundEditor.robot":"Ռոբոտ","gui.soundEditor.louder":"Ավելի բարձր","gui.soundEditor.softer":"Ավելի մեղմ","gui.soundEditor.reverse":"Հակադարձել","gui.soundEditor.fadeOut":"Մարել","gui.soundEditor.fadeIn":"Հզորացնել","gui.soundEditor.mute":"Անձայն","gui.SpriteInfo.spritePlaceholder":"Անուն","gui.SpriteInfo.sprite":"Կերպար","gui.SpriteInfo.show":"Ցույց տալ","gui.SpriteInfo.size":"Չափս","gui.spriteSelectorItem.contextMenuDuplicate":"կրկնօրինակել","gui.spriteSelectorItem.contextMenuExport":"արտահանել","gui.spriteSelectorItem.contextMenuDelete":"ջնջել","gui.spriteSelector.addSpriteFromLibrary":"Ընտրել կերպարը","gui.spriteSelector.addSpriteFromPaint":"Նկարել","gui.spriteSelector.addSpriteFromSurprise":"Անակնկալ","gui.spriteSelector.addSpriteFromFile":"Վերբեռնել կերպար","gui.stageHeader.stageSizeLarge":"Անցնել մեծ բեմի","gui.stageHeader.stageSizeSmall":"Անցնել փոքր բեմի","gui.stageHeader.stageSizeFull":"Ակտիվացնել լիաէկրան ռեժիմը","gui.stageHeader.stageSizeUnFull":"Դուրս գալ լիաէկրան ռեժիմից","gui.stageHeader.fullscreenControl":"Լիաէկրան կառավարում","gui.spriteSelector.addBackdropFromLibrary":"Ընտրել ետնապատկերը","gui.stageSelector.addBackdropFromPaint":"Նկարել","gui.stageSelector.addBackdropFromSurprise":"Անակնկալ","gui.stageSelector.addBackdropFromFile":"Վերբեռնել ետնապատկեր","gui.stageSelector.stage":"Բեմ","gui.stageSelector.backdrops":"Ետնապատկեր","gui.telemetryOptIn.label":"Զեկուցել վիճակագրությունը Scratch-ը բարելավելու համար","gui.telemetryOptIn.body1":"Scratch -ի թիմը միշտ փորձում է ավելի լավ հասկանալ, թե ինչպես է Scratch-ն օգտագործվում ամբողջ աշխարհում: Այս ջանքերը սատարելու համար դուք կարող եք թույլ տալ, որ ծրագիրն ինքնաբերաբար ուղարկի օգտագործման տվյալները Scratch-ի թիմին:","gui.telemetryOptIn.body2":"Հավաքվող տվյալներն են՝ լեզվի ընտրությունը, մասնիկների օգտագործում, և որոշ իրադարձություններ, ոոնցից են պահպանումը, բեռնումն ու նախագծի վերբեռնումը ։ Մենք ՉԵՆՔ հավաքում անհատական տվյալներ։ Խնդրում ենք կարդալ {privacyPolicyLink} -ը՝ լրացուցիչ ինֆորմացիայի համար: ","gui.telemetryOptIn.privacyPolicyLink":"Գաղտնիության քաղաքականություն","gui.telemetryOptIn.optInText":"Scratch թիմի հետ կիսվել ծրագրի օգտագործման տվյալները","gui.telemetryOptIn.optInTooltip":"Ակտիվացնել հեռաչափումը","gui.telemetryOptIn.optOutText":"Scratch թիմի հետ չկիսվել ծրագրի օգտագործման տվյալները","gui.telemetryOptIn.optOutTooltip":"Անջատել հեռաչափումը","gui.telemetryOptIn.settingWasUpdated":"Կարգավորումները թարմացված են։","gui.telemetryOptIn.buttonClose":"Փակել","gui.turboMode.active":"Արագացված ռեժիմ","gui.webglModal.label":"Ձեր զննարկիչը չունի WebGL -ի հնարավորություն","gui.webglModal.webgllink":"չունի WebGL -ի հնարավորություն","gui.costumeLibrary.chooseABackdrop":"Ընտրել ետնապատկերը","gui.costumeLibrary.chooseACostume":"Ընտրել զգեստը","gui.costumeTab.addBackdropFromLibrary":"Ընտրել ետնապատկերը","gui.costumeTab.addCostumeFromLibrary":"Ընտրել զգեստը","gui.costumeTab.addBlankCostume":"Նկարել","gui.costumeTab.addSurpriseCostume":"Անակնկալ","gui.costumeTab.addFileBackdrop":"Վերբեռնել ետնապատկեր","gui.costumeTab.addFileCostume":"Վերբեռնել զգեստ","gui.extensionLibrary.chooseAnExtension":"Ընտրել ընդլայնումը","gui.extensionLibrary.extensionUrl":"Մուտքագրել ընդլայնման URL-ը","gui.monitors.importListColumnPrompt":"Ո՞ր սյունը պէտք է օգտագործվի (1-{numberOfColumns})։","gui.recordingStep.alertMsg":"Չհաջողվեց սկսել ձայնագրությունը","gui.soundLibrary.chooseASound":"Ընտրել ձայնը","gui.soundTab.fileUploadSound":"Վերբեռնել ձայն","gui.soundTab.surpriseSound":"Անակնկալ","gui.soundTab.recordSound":"Ձայնագրել","gui.soundTab.addSoundFromLibrary":"Ընտրել ձայնը","gui.spriteLibrary.chooseASprite":"Ընտրել կերպարը","gui.tipsLibrary.tutorials":"Ընտրել ձեռնարկը","gui.alerts.createsuccess":"Նոր նախագիծը ստեղծվել է ","gui.alerts.createcopysuccess":"Ծրագիրը պահպանվել է, որպես պատճեն:","gui.alerts.createremixsuccess":"Ծրագիրը պահպանվել է, որպես վերամշակում:","gui.alerts.creating":"Ստեղծվում է նորը...","gui.alerts.creatingCopy":"Նախագծի պատճենում․․․","gui.alerts.creatingRemix":"Նախագծի վերամշակում...","gui.alerts.creatingError":"Հնարավոր չէ ստեղծել նախագիծը: Խնդրում ենք կրկին փորձել։","gui.alerts.savingError":"Նախագիծը չի պահվել:","gui.alerts.savesuccess":"Նախագիծը պահվել է:","gui.alerts.saving":"Պահում է նախագիծը․․․","gui.alerts.cloudInfo":"Հիշեք, որ ամպային փոփոխականները կարող են միայն թվեր լինել, այլ ոչ տառեր կամ նիշեր։ {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Իմանալ ավելին:","gui.alerts.importing":"Ներմուծում ...","gui.defaultProject.variable":"իմ փոփոխականը","gui.extension.music.name":"Երաժշտություն","gui.extension.music.description":"Նվագել գործիքներով ու թմբուկներով։","gui.extension.pen.name":"Գրիչ","gui.extension.pen.description":"Նկարել Ձեր կերպարներով։","gui.extension.videosensing.name":"Տեսա\\nազդակ","gui.extension.videosensing.description":"Ճանաչել շարժումը տեսախցիկով","gui.extension.text2speech.name":"Տեքստը խոսքի վերածող","gui.extension.text2speech.description":"Տվեք նախագծերին խոսելու ունակություն","gui.extension.translate.name":"Թարգմանել","gui.extension.translate.description":"Թարգմանել տեքստը բազմաթիվ լեզուներով:","gui.extension.makeymakey.description":"Դարձրեք ցանկացած բան ստեղնով հրամանի","gui.extension.microbit.description":"Կապեք Ձեր նախագծերը աշխարհի հետ","gui.extension.microbit.connectingMessage":"Միացում","gui.extension.ev3.description":"Ստեղծել փոխգործակցող և այլ ռոբոտներ:","gui.extension.ev3.connectingMessage":"Միացում: Համոզվեք, որ Ձեր EV3-ի ծածկագիրը սահմնանված է 1234-ի։","gui.extension.boost.description":"Դարձրեք կենդանի ռոբոտներ:","gui.extension.boost.connectingMessage":"Միացում","gui.extension.wedo2.description":"Կառուցել շարժիչներով և տվիչներով։","gui.extension.wedo2.connectingMessage":"Միացում","gui.extension.gdxfor.description":"Չափում է հրման և քարշի ուժերը, շարժումը և շրջադարձը։","gui.extension.gdxfor.connectingMessage":"Միացում","gui.libraryTags.all":"Բոլորը","gui.libraryTags.animals":"Կենդանիներ","gui.libraryTags.dance":"Պարել","gui.libraryTags.effects":"Էֆեկտներ","gui.libraryTags.fantasy":"Երևակայական","gui.libraryTags.fashion":"Նորաձևություն","gui.libraryTags.food":"Ուտելիք","gui.libraryTags.indoors":"Ներսում","gui.libraryTags.loops":"Հանգույցներ","gui.libraryTags.music":"Երաժշտություն","gui.libraryTags.notes":"Նշումներ","gui.libraryTags.outdoors":"Դրսում","gui.libraryTags.patterns":"Նմուշներ","gui.libraryTags.people":"Մարդիկ","gui.libraryTags.percussion":"Հարվածային գործիքներ","gui.libraryTags.space":"Տարածություն","gui.libraryTags.sports":"Սպորտ","gui.libraryTags.underwater":"Ստորջրյա ","gui.libraryTags.voice":"Ձայն","gui.libraryTags.wacky":"Խենթ","gui.libraryTags.animation":"Անիմացիա","gui.libraryTags.art":"Արվեստ","gui.libraryTags.games":"Խաղեր","gui.libraryTags.stories":"Պատմություններ","gui.libraryTags.letters":"Տառեր","gui.opcodeLabels.direction":"ուղղություն","gui.opcodeLabels.xposition":"x -ը","gui.opcodeLabels.yposition":"y -ը","gui.opcodeLabels.size":"չափս","gui.opcodeLabels.costumename":"զգեստի անունը","gui.opcodeLabels.costumenumber":"զգեստի համարը","gui.opcodeLabels.backdropname":"ետնապատկերի անունը","gui.opcodeLabels.backdropnumber":"ետնապատկերի համարը","gui.opcodeLabels.volume":"ձայնը","gui.opcodeLabels.tempo":"տեմպ","gui.opcodeLabels.answer":"պատասխան","gui.opcodeLabels.loudness":"բարձրաձայն","gui.opcodeLabels.username":"մուտքանուն","gui.opcodeLabels.year":"տարի","gui.opcodeLabels.month":"ամիս","gui.opcodeLabels.date":"ամսաթիվ","gui.opcodeLabels.dayofweek":"շաբաթվա օր","gui.opcodeLabels.hour":"ժամ","gui.opcodeLabels.minute":"րոպե","gui.opcodeLabels.second":"երկրորդ","gui.opcodeLabels.timer":"վայրկյանաչափ","gui.sharedMessages.backdrop":"ետնապատկեր {index}","gui.sharedMessages.costume":"զգեստ {index}","gui.sharedMessages.sprite":"Կերպար {index}","gui.sharedMessages.pop":"փոփ","gui.sharedMessages.replaceProjectWarning":"Փոխարինե՞լ ընթացիկ նախագծի պարունակությունը:","gui.sharedMessages.loadFromComputerTitle":"Բեռնել համակարգչից","boost.color.any":"Ցանկացած գույն","boost.color.black":"Սև","boost.color.blue":"Կապույտ","boost.color.green":"Կանաչ","boost.color.red":"Կարմիր","boost.color.white":"Սպիտակ","boost.color.yellow":"Դեղին","boost.getMotorPosition":"տեղաշարժել [MOTOR_REPORTER_ID] ","boost.getTiltAngle":"թեքել անկյունը [TILT_DIRECTION]","boost.motorDirection.backward":"այդ ուղղությամբ","boost.motorDirection.forward":"այս ուղղությամբ","boost.motorDirection.reverse":"շրջել","boost.motorOff":"անջատել [MOTOR_ID]","boost.motorOn":"միացնել [MOTOR_ID]","boost.motorOnFor":"միացնել [MOTOR_ID] շարժիչը [DURATION] վայրկյանով","boost.motorOnForRotation":"պտտել [MOTOR_ID] շարժիչը [ROTATION] աստիճանով ","boost.seeingColor":"երևո՞ւմ է [COLOR] աղյուսը","boost.setLightHue":"սահմանել լույսի գույնը [HUE]","boost.setMotorDirection":"սահմանել [MOTOR_ID]-ի ուղղությունը [MOTOR_DIRECTION]","boost.setMotorPower":"սահմանել [MOTOR_ID]-ի արագությունը մինչև [POWER] %","boost.tiltDirection.any":"ցանկացած","boost.tiltDirection.down":"ներքև","boost.tiltDirection.left":"ձախ","boost.tiltDirection.right":"աջ","boost.tiltDirection.up":"վեր","boost.whenColor":"երբ երևում է [COLOR] աղյուսը","boost.whenTilted":"երբ թեքված է [TILT_DIRECTION_ANY]","ev3.beepNote":"միացնել [NOTE] ազդանշանաը [TIME] վայրկյան","ev3.buttonPressed":"կոճակ [PORT] սեղմվա՞ծ է","ev3.getBrightness":"պայծառություն","ev3.getDistance":"հեռավորություն","ev3.getMotorPosition":"շարժիչի [PORT] դիրքը ","ev3.motorSetPower":" շարժիչ [PORT] հզորությունը [POWER] %","ev3.motorTurnClockwise":"շարժիչ [PORT] պտտել այս կողմ [TIME] վայրկյանով","ev3.motorTurnCounterClockwise":"շարժիչ [PORT] պտտել այդ կողմ [TIME] վայրկյանով","ev3.whenBrightnessLessThan":"երբ պայծառությունը < [DISTANCE]","ev3.whenButtonPressed":"երբ [PORT] կոճակը սեղմված է","ev3.whenDistanceLessThan":"երբ հեռավորությունը < [DISTANCE]","gdxfor.getAcceleration":"արագացում [DIRECTION]","gdxfor.getForce":"ուժ","gdxfor.getSpin":"պտտման արագություն [DIRECTION]","gdxfor.getTilt":"անկյան թեքվածություն [TILT]","gdxfor.isFreeFalling":"ընկնում","gdxfor.isTilted":"թեքվա՞ծ [TILT]","gdxfor.pulled":"քաշված","gdxfor.pushed":"հրած","gdxfor.shaken":"թափահարած","gdxfor.startedFalling":"սկսել է ընկնել","gdxfor.tiltDirectionMenu.any":"ցանկացած","gdxfor.tiltDirectionMenu.back":"ետեվ","gdxfor.tiltDirectionMenu.front":"դիմաց","gdxfor.tiltDirectionMenu.left":"ձախ","gdxfor.tiltDirectionMenu.right":"աջ","gdxfor.turnedFaceDown":"գլուխը ներքև","gdxfor.turnedFaceUp":"գլուխը վերև","gdxfor.whenForcePushedOrPulled":"երբ ուժի տվիչը [PUSH_PULL] ","gdxfor.whenGesture":"երբ [GESTURE]","gdxfor.whenTilted":"երբ թեքություն կա [TILT]","makeymakey.downArrow":"վար սլաքը","makeymakey.downArrowShort":"ներքև","makeymakey.leftArrow":"ձախ սլաք","makeymakey.leftArrowShort":"ձախ","makeymakey.rightArrow":"աջ սլաքը ","makeymakey.rightArrowShort":"աջ","makeymakey.spaceKey":"բացատ","makeymakey.upArrow":" վեր սլաքը","makeymakey.upArrowShort":"վեր","makeymakey.whenKeyPressed":"երբ [KEY] ստեղնը սեղմված է","makeymakey.whenKeysPressedInOrder":"երբ [SEQUENCE] սեղմված է ըստ հաջորդականության","microbit.buttonsMenu.any":"ցանկացած","microbit.clearDisplay":"մաքրել էկրանը","microbit.defaultTextToDisplay":"Բարև","microbit.displaySymbol":"ցույց տալ [MATRIX]","microbit.displayText":"ցույց տալ տեքստ [TEXT]","microbit.gesturesMenu.jumped":"ցատկած","microbit.gesturesMenu.moved":"շարժված","microbit.gesturesMenu.shaken":"թափահարած","microbit.isButtonPressed":"[BTN] կոճակը սեղմվա՞ծ է","microbit.isTilted":"թեքվա՞ծ է [DIRECTION]","microbit.pinStateMenu.off":"Անջատել","microbit.pinStateMenu.on":"Միացնել","microbit.tiltAngle":"թեքել անկյունը [DIRECTION]","microbit.tiltDirectionMenu.any":"ցանկացած","microbit.tiltDirectionMenu.back":"ետ","microbit.tiltDirectionMenu.front":"դիմաց","microbit.tiltDirectionMenu.left":"ձախ","microbit.tiltDirectionMenu.right":"աջ","microbit.whenButtonPressed":"երբ [BTN] կոճակը սեղմված է","microbit.whenGesture":"երբ [GESTURE]","microbit.whenPinConnected":"երբ [PIN] փինը միացված է","microbit.whenTilted":"երբ թեքված է [DIRECTION]","music.categoryName":"Երաժշտություն","music.changeTempo":"փոխել տեմպը [TEMPO]-ով","music.drumBass":"(2) Բաս Թմբուկ","music.drumBongo":"(13) Բոնգո","music.drumCabasa":"(15) Կաբասա","music.drumClaves":"(9) Քլեյվս","music.drumClosedHiHat":"(6) Փակված Ծնծղա","music.drumConga":"(14) Քոնգա","music.drumCowbell":"(11) Կովի զանգակ","music.drumCrashCymbal":"(4) Թմբուկի բարձր ձայն","music.drumCuica":"(18) Կուիկա","music.drumGuiro":"(16) Գուիրո","music.drumHandClap":"(8) Ծափահարություն","music.drumOpenHiHat":"(5) Բաց Ծնծղա","music.drumSideStick":"(3) Կողային Փայտիկ","music.drumSnare":"(1) Փոքր Թմբուկ","music.drumTambourine":"(7) Դափ","music.drumTriangle":"(12) Եռանկյունի","music.drumVibraslap":"(17) Թրթռահարված","music.drumWoodBlock":"(10) Փայտե Տուփ","music.getTempo":"տեմպ","music.instrumentBass":"(6) Բաս","music.instrumentBassoon":"(14) Ֆագոտ","music.instrumentCello":"(8) Թավջութակ","music.instrumentChoir":"(15) Երգչախումբ","music.instrumentClarinet":"(10) Կլառնետ","music.instrumentElectricGuitar":"(5) Էլեկտրական Կիթառ","music.instrumentElectricPiano":"(2) Էլեկտրական Դաշնամուր","music.instrumentFlute":"(12) Ֆլեյտա","music.instrumentGuitar":"(4) Կիթառ","music.instrumentMarimba":"(19) Մարիմբա","music.instrumentMusicBox":"(17) Երաժշտական Տուփ ","music.instrumentOrgan":"(3) Երգեհոն","music.instrumentPiano":"(1) Դաշնամուր","music.instrumentPizzicato":"(7) Պիցցիկատո","music.instrumentSaxophone":"(11) Սաքսոֆոն","music.instrumentSteelDrum":"(18) Պողպատե Թմբուկ","music.instrumentSynthLead":"(20) Սինթեզատորի Մեղեդի","music.instrumentSynthPad":"(21) Սինթեզատորի Ակորդներ ","music.instrumentTrombone":"(9) Տրոմբոն","music.instrumentVibraphone":"(16) Վիբրաֆոն","music.instrumentWoodenFlute":"(13) Փայտե ֆլեյտա","music.midiPlayDrumForBeats":"նվագել թմբուկով [DRUM] [BEATS] տակտով","music.midiSetInstrument":"սահմանել երաժշտական գործիքը [INSTRUMENT]","music.playDrumForBeats":"նվագել թմբուկով [DRUM] [BEATS] տակտով","music.playNoteForBeats":"միացնել [NOTE] [BEATS] տակտերով","music.restForBeats":"դադարեցնել [BEATS] տակտով","music.setInstrument":"սահմանել երաժշտական գործիքը [INSTRUMENT]","music.setTempo":"սահմանել տեմպը [TEMPO]","pen.categoryName":"Գրիչ","pen.changeColorParam":"փոխել գրիչի գույնը [COLOR_PARAM] [VALUE]-ով","pen.changeHue":"փոխել գրիչի գույնը [HUE]-ով","pen.changeShade":"փոխել գրիչի ստվերը [SHADE]-ով","pen.changeSize":"փոխել գրիչի չափը [SIZE]-ով","pen.clear":"ջնջել բոլորը","pen.colorMenu.brightness":"պայծառություն","pen.colorMenu.color":"գույն","pen.colorMenu.saturation":"հագեցվածություն","pen.colorMenu.transparency":"թափանցիկություն","pen.penDown":"գրիչն իջեցնել","pen.penUp":"գրիչը բարձրացնել","pen.setColor":"սահմանել գրիչի գույնը [COLOR]","pen.setColorParam":"սահմենլ գրիչի [COLOR_PARAM] [VALUE]-ի","pen.setHue":"սահմանել գրիչի գույնը [HUE]","pen.setShade":"սահմանել գրիչի ստվերը [SHADE]","pen.setSize":"սահմանել գրիչի չափսը [SIZE]","pen.stamp":"կնիք","text2speech.alto":"ալտ","text2speech.categoryName":"Ավելացնել տեքստը խոսքի բլոկներին","text2speech.defaultTextToSpeak":"բարև","text2speech.giant":"հսկա","text2speech.kitten":"կատվի ձագ","text2speech.setLanguageBlock":"սահմանել լեզուն [LANGUAGE]","text2speech.setVoiceBlock":"սահմանել ձայնը [VOICE]","text2speech.speakAndWaitBlock":"ասել [WORDS]","text2speech.squeak":"ճզմել","text2speech.tenor":"տենոր","translate.categoryName":"Թարգմանել","translate.defaultTextToTranslate":"բարև","translate.translateBlock":"թարգմանել [WORDS]֊ը [LANGUAGE]","translate.viewerLanguage":"լեզու","videoSensing.categoryName":" Տեսա ազդակ","videoSensing.direction":"ուղղություն","videoSensing.motion":"շարժում","videoSensing.off":"Անջատել","videoSensing.on":"Միացնել","videoSensing.onFlipped":"արտացոլված","videoSensing.setVideoTransparency":" սահմանել տեսանյութի թափանցիկությունը [TRANSPARENCY]","videoSensing.sprite":"կերպար","videoSensing.stage":"բեմ","videoSensing.videoOn":"Տեսանյութի [ATTRIBUTE]֊ը [SUBJECT]֊ում","videoSensing.videoToggle":"միացնել տեսանյութը [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"երբ տեսանյութի շարժը > [REFERENCE]","wedo2.getDistance":"հեռավորություն","wedo2.getTiltAngle":"թեքել անկյունը [TILT_DIRECTION]","wedo2.isTilted":"թեքվա՞ծ է որևէ ուղղությամբ [TILT_DIRECTION_ANY]","wedo2.motorDirection.backward":"այդ ուղղությամբ","wedo2.motorDirection.forward":"այս ուղղությամբ","wedo2.motorDirection.reverse":"շրջել","wedo2.motorId.a":"շարժիչ Ա","wedo2.motorId.all":"բոլոր շարժիչները","wedo2.motorId.b":"շարժիչ Բ","wedo2.motorId.default":"շարժիչ","wedo2.motorOff":"անջատել [MOTOR_ID]","wedo2.motorOn":"միացնել [MOTOR_ID]","wedo2.motorOnFor":"միացնել [MOTOR_ID] շարժիչը [DURATION] վայրկյանով","wedo2.playNoteFor":"միացնել [NOTE] [DURATION] վայրկյանով","wedo2.setLightHue":"սահմանել լույսի գույնը [HUE]","wedo2.setMotorDirection":"սահմանել [MOTOR_ID] ուղղությունը դեպի [MOTOR_DIRECTION]","wedo2.startMotorPower":"սահմանել [MOTOR_ID] արագությունը մինչև [POWER] ","wedo2.tiltDirection.any":"ցանկացած","wedo2.tiltDirection.down":"ներքև","wedo2.tiltDirection.left":"ձախ","wedo2.tiltDirection.right":"աջ","wedo2.tiltDirection.up":"վեր","wedo2.whenDistance":"երբ հեռավորություն [OP] [REFERENCE]","wedo2.whenTilted":"երբ թեքված է [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Գույն","paint.paintEditor.saturation":"Հագեցվածություն","paint.paintEditor.brightness":"Պայծառություն","paint.paintEditor.costume":"Զգեստ","paint.paintEditor.group":"Խումբ","paint.paintEditor.ungroup":"Ցրել խումբը","paint.paintEditor.undo":"Հետ գնալ","paint.paintEditor.redo":"Առաջ գնալ","paint.paintEditor.forward":"Դեպի առաջ","paint.paintEditor.backward":"Դեպի հետ","paint.paintEditor.front":"Դիմաց","paint.paintEditor.back":"Հետ գնալ","paint.paintEditor.more":"Ավելին","paint.modeTools.brushSize":"Չափս","paint.modeTools.eraserSize":"Ռետինի չափսը","paint.modeTools.copy":"Պատճենել","paint.modeTools.paste":"Զետեղել","paint.modeTools.delete":"Ջնջել","paint.modeTools.curved":"Ծռված","paint.modeTools.pointed":"Նշված","paint.modeTools.thickness":"Հաստություն","paint.modeTools.flipHorizontal":"Հորիզոնական շրջադարձ","paint.modeTools.flipVertical":"Ուղղահայաց շրջադարձ","paint.modeTools.filled":"Լցված","paint.modeTools.outlined":"Եզրագծած","paint.paintEditor.bitmap":"Փոխակերպել կետապատկերայինի","paint.paintEditor.vector":"Փոխակերպել վեկտորի","paint.paintEditor.fill":"Լցնել","paint.paintEditor.stroke":"Եզրագիծ","paint.brushMode.brush":"Վրձին","paint.eraserMode.eraser":"Ռետին","paint.fillMode.fill":"Լցնել","paint.lineMode.line":"Գիծ","paint.ovalMode.oval":"Շրջանագիծ","paint.rectMode.rect":"Ուղղանկյուն","paint.reshapeMode.reshape":"Ձևափոխել","paint.roundedRectMode.roundedRect":"Կլորացված ուղղանկյուն","paint.selectMode.select":"Ընտրել","paint.textMode.text":"Տեքստ","paint.colorPicker.swap":"Փոխարինում"},"he":{"gui.alerts.tryAgain":"נסה שוב","gui.alerts.download":"הורד","gui.connection.reconnect":"התחברו שוב","gui.backpack.costumeLabel":"תלבושת","gui.backpack.soundLabel":"צליל","gui.backpack.scriptLabel":"תסריט","gui.backpack.spriteLabel":"דמות","gui.backpack.header":"תרמיל","gui.backpack.errorBackpack":"אירעה שגיאה בטעינת התרמיל","gui.backpack.loadingBackpack":"טוען...","gui.backpack.more":"עוד","gui.backpack.emptyBackpack":"התרמיל ריק","gui.unsupportedBrowser.label":"הדפדפן אינו נתמך","gui.cards.all-tutorials":"מדריכים","gui.cards.shrink":"הקטן","gui.cards.expand":"הרחב","gui.cards.close":"סגירה","gui.cards.more-things-to-try":"עוד דברים לנסות!","gui.cards.see-more":"ראו עוד","gui.comingSoon.message1":"אל דאגה, אנחנו מטפלים בזה {emoji}","gui.comingSoon.message2":"בקרוב ...","gui.comingSoon.message3":"אנחנו עובדים על זה {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"לא נמצאו מכשירים","gui.connection.auto-scanning.prescan":"במשכיר שלך בסמוך אליך אז התחל בחיפוש","gui.connection.auto-scanning.pressbutton":"לחץ את הכפתור על המכשיר שלך","gui.connection.auto-scanning.start-search":"התחל חיפוש","gui.connection.connecting-searchbutton":"מחפש...","gui.connection.auto-scanning.try-again":"נסו שוב","gui.connection.connected":"מחובר","gui.connection.disconnect":"התנתקו","gui.connection.go-to-editor":"עברו לעורך","gui.connection.connecting-cancelbutton":"מתחבר...","gui.connection.error.errorMessage":"אופס, נראה שמשהו השתבש.","gui.connection.error.tryagainbutton":"נסו שוב","gui.connection.error.helpbutton":"עזרה","gui.connection.peripheral-name-label":"שם מכשיר","gui.connection.connect":"התחברו","gui.connection.scanning.lookingforperipherals":"מחפש מכשירים","gui.connection.scanning.noPeripheralsFound":"לא נמצאו מכשירים","gui.connection.scanning.instructions":"בחרו את המכשיר שלכם מהרשימה למעלה","gui.connection.search":"ריענון","gui.connection.unavailable.installscratchlink":"וודאו שיש לכם Scratch Link מותקן ופועל.","gui.connection.unavailable.enablebluetooth":"וודאו שה־Bluetooth דלוק","gui.connection.unavailable.tryagainbutton":"נסו שוב","gui.connection.unavailable.helpbutton":"עזרה","gui.controls.go":"הפעל","gui.controls.stop":"עצירה","gui.crashMessage.label":"אופס! משהו השתבש","gui.crashMessage.errorNumber":"התקלה נרשמה עם מזהה {errorId}","gui.crashMessage.reload":"טעינה מחדש","gui.customProcedures.myblockModalTitle":"צרו לבנה","gui.customProcedures.addAnInputNumberText":"הוסיפו קלט","gui.customProcedures.numberTextType":"מספר או טקסט","gui.customProcedures.addAnInputBoolean":"הוסיפו קלט","gui.customProcedures.booleanType":"בוליאני","gui.customProcedures.addALabel":"הוסיפו תווית","gui.customProcedures.runWithoutScreenRefresh":"הפעלה ללא רענון מסך","gui.customProcedures.cancel":"ביטול","gui.customProcedures.ok":"אישור","gui.SpriteInfo.direction":"כיוון","gui.directionPicker.rotationStyles.allAround":"כל הכיוונים","gui.directionPicker.rotationStyles.leftRight":"שמאל-ימין","gui.directionPicker.rotationStyles.dontRotate":"לא לסובב","gui.gui.addExtension":"הוסיפו הרחבה","gui.gui.codeTab":"קוד","gui.gui.backdropsTab":"רקעים","gui.gui.costumesTab":"תלבושות","gui.gui.soundsTab":"צלילים","gui.extensionLibrary.comingSoon":"בקרוב","gui.extensionLibrary.requires":"דורש","gui.extensionLibrary.collaboration":"שיתוף פעולה עם","gui.library.filterPlaceholder":"חיפוש","gui.library.allTag":"הכול","gui.loader.headline":"העלו פרוייקט","gui.loader.creating":"יוצר פרויקט","gui.authorInfo.byUser":"מ{username}","gui.menuBar.seeProjectPage":"ראו דף פרויקט","gui.menuBar.LanguageSelector":"בחירת שפה","gui.menuBar.tutorialsLibrary":"מדריכים","gui.menuBar.restoreSprite":"שחזר דמות","gui.menuBar.restoreSound":"שחזר שמע","gui.menuBar.restoreCostume":"שחזר תלבושת","gui.menuBar.restore":"שחזר","gui.menuBar.saveNow":"שמור עכשיו","gui.menuBar.saveAsCopy":"שמירה כעותק","gui.menuBar.remix":"עריכה מחדש","gui.menuBar.new":"חדש","gui.menuBar.file":"קובץ","gui.menuBar.downloadToComputer":"הורידו למחשב","gui.menuBar.edit":"עריכה","gui.menuBar.turboModeOff":"כבו מצב טורבו","gui.menuBar.turboModeOn":"הפעילו מצב טורבו","gui.gui.projectTitlePlaceholder":"כתבו כאן את כותרת הפרויקט","gui.menuBar.isShared":"משותף","gui.menuBar.share":"שיתוף","gui.modal.help":"עזרה","gui.modal.back":"אחורה","gui.monitor.listMonitor.empty":"(ריק)","gui.monitor.listMonitor.listLength":"אורך {length}","gui.monitor.contextMenu.default":"תצוגה רגילה","gui.monitor.contextMenu.large":"תצוגה גדולה","gui.monitor.contextMenu.slider":"סרגל גרירה","gui.monitor.contextMenu.sliderRange":"שינוי טווח סרגל","gui.monitor.contextMenu.import":"יבוא","gui.monitor.contextMenu.export":"יצוא","gui.monitor.contextMenu.hide":"הסתר","gui.playButton.play":"נגן","gui.playButton.stop":"עצור","gui.gui.variableScopeOptionAllSprites":"לכל הדמויות","gui.gui.variableScopeOptionSpriteOnly":"רק לדמות זו","gui.gui.cloudVariableOption":"משתנה ענן (מאוחסן בשרת)","gui.gui.variablePromptAllSpritesMessage":"המשתנה הזה יהיה זמין לכל הדמויות","gui.gui.listPromptAllSpritesMessage":"רשימה זו תהיה זמינה לכל הדמויות","gui.prompt.cancel":"ביטול","gui.prompt.ok":"אישור","gui.playbackStep.stopMsg":"עצירה","gui.playbackStep.playMsg":"נגינה","gui.playbackStep.loadingMsg":"טוען...","gui.playbackStep.saveMsg":"שמירה","gui.playbackStep.reRecordMsg":"הקליטו מחדש","gui.recordModal.title":"הקליטו צליל","gui.recordingStep.beginRecord":"לחצו על הכפתור למטה להתחלת הקלטה","gui.recordingStep.permission":"{arrow}אנו זקוקים לרשות להשתמש במיקרופון","gui.recordingStep.stop":"עצירת הקלטה","gui.recordingStep.record":"הקלטה","gui.sliderModal.min":"הערך הקטן ביותר","gui.sliderModal.max":"הערך הגדול ביותר ","gui.sliderModal.title":"שינוי טווח סרגל","gui.sliderPrompt.cancel":"ביטול","gui.sliderPrompt.ok":"אישור","gui.soundEditor.sound":"צליל","gui.soundEditor.play":"נגינה","gui.soundEditor.stop":"עצירה","gui.soundEditor.copy":"העתק","gui.soundEditor.paste":"הדבק","gui.soundEditor.copyToNew":"העתק לחדש","gui.soundEditor.delete":"מחק","gui.soundEditor.save":"שמירה","gui.soundEditor.undo":"ביטול","gui.soundEditor.redo":"שחזור","gui.soundEditor.faster":"מהר יותר","gui.soundEditor.slower":"איטי יותר","gui.soundEditor.echo":"הד","gui.soundEditor.robot":"רובוט","gui.soundEditor.louder":"חזק יותר","gui.soundEditor.softer":"חלש יותר","gui.soundEditor.reverse":"הפוך","gui.soundEditor.fadeOut":"דעיכה","gui.soundEditor.fadeIn":"התעצמות","gui.soundEditor.mute":"השתקה","gui.SpriteInfo.spritePlaceholder":"שם","gui.SpriteInfo.sprite":"דמות","gui.SpriteInfo.show":"הצגה","gui.SpriteInfo.size":"גודל","gui.spriteSelectorItem.contextMenuDuplicate":"שכפול","gui.spriteSelectorItem.contextMenuExport":"יצוא","gui.spriteSelectorItem.contextMenuDelete":"מחיקה","gui.spriteSelector.addSpriteFromLibrary":"בחרו דמות","gui.spriteSelector.addSpriteFromPaint":"צייר","gui.spriteSelector.addSpriteFromSurprise":"הפתעה","gui.spriteSelector.addSpriteFromFile":"העלו דמות","gui.stageHeader.stageSizeLarge":"עברו לבמה גדולה","gui.stageHeader.stageSizeSmall":"עברו לבמה קטנה","gui.stageHeader.stageSizeFull":"כניסה למסך מלא","gui.stageHeader.stageSizeUnFull":"יציאה ממסך מלא","gui.stageHeader.fullscreenControl":"בקרת מסך מלא","gui.spriteSelector.addBackdropFromLibrary":"בחרו רקע","gui.stageSelector.addBackdropFromPaint":"צייר","gui.stageSelector.addBackdropFromSurprise":"הפתעה","gui.stageSelector.addBackdropFromFile":"העלו רקע","gui.stageSelector.stage":"במה","gui.stageSelector.backdrops":"רקע","gui.telemetryOptIn.label":"דיווח סטטיסטיקה לשיפור סקראץ\'","gui.telemetryOptIn.body1":"צוות סקראץ\' תמיד מנסה להבין טוב יותר כיצד משתמשים בסקראץ\' מסביב לעולם. לתמיכה במאמץ זה, אתם יכולים לאפשר לסקראץ\' לשלוח באופן אוטומטי מידע לצוות.","gui.telemetryOptIn.body2":"המידע שאנו אוספים כולל בחירת שפה, לבנים, שימוש ואירועים כמו שמירה, טעינה והעלאת פרויקט. אנו לא אוספים אף מידע אישי. למידע נוסף ראו את {privacyPolicyLink} שלנו.","gui.telemetryOptIn.privacyPolicyLink":"מדיניות פרטיות","gui.telemetryOptIn.optInText":"שיתוף נתוני הפעילות שלי עם צוות סקראץ\'","gui.telemetryOptIn.optInTooltip":"הפעלת טלמטריה","gui.telemetryOptIn.optOutText":"ביטול שיתוף נתוני הפעילות שלי עם צוות סקראץ\'","gui.telemetryOptIn.optOutTooltip":"כבוי טלמטריה","gui.telemetryOptIn.settingWasUpdated":"הגדרות עודכנו.","gui.telemetryOptIn.buttonClose":"סגירה","gui.turboMode.active":"מצב טורבו","gui.webglModal.label":"הדפדפן שלך אינו תומך ב־WebGL","gui.webglModal.webgllink":"אינו תומך ב־WebGL","gui.costumeLibrary.chooseABackdrop":"בחרו רקע","gui.costumeLibrary.chooseACostume":"בחרו תלבושת","gui.costumeTab.addBackdropFromLibrary":"בחרו רקע","gui.costumeTab.addCostumeFromLibrary":"בחרו תלבושת","gui.costumeTab.addBlankCostume":"צייר","gui.costumeTab.addSurpriseCostume":"הפתעות","gui.costumeTab.addFileBackdrop":"העלו רקע","gui.costumeTab.addFileCostume":"העלו תלבושת","gui.extensionLibrary.chooseAnExtension":"בחרו הרחבה","gui.extensionLibrary.extensionUrl":"הכניסו את ה־URL של ההרחבה","gui.monitors.importListColumnPrompt":"באיזה טור להשתמש ({numberOfColumns} - 1)?","gui.recordingStep.alertMsg":"לא ניתן להתחיל הקלטה","gui.soundLibrary.chooseASound":"בחרו צליל","gui.soundTab.fileUploadSound":"העלו צליל","gui.soundTab.surpriseSound":"הפתעה","gui.soundTab.recordSound":"הקלטה","gui.soundTab.addSoundFromLibrary":"בחרו צליל","gui.spriteLibrary.chooseASprite":"בחרו דמות","gui.tipsLibrary.tutorials":"בחרו מדריך","gui.alerts.createsuccess":"פרויקט חדש נוצר","gui.alerts.createcopysuccess":"פרויקט נשמר כעותק","gui.alerts.createremixsuccess":"פרויקט נשמר כעריכה מחדש","gui.alerts.creating":"יוצר חדש...","gui.alerts.creatingCopy":"מעתיק פרויקט...","gui.alerts.creatingRemix":"עריכה מחדש...","gui.alerts.creatingError":"לא יכולנו ליצור את הפרויקט. נסה שוב!","gui.alerts.savingError":"הפרויקט לא נשמר","gui.alerts.savesuccess":"פרויקט נשמר.","gui.alerts.saving":"שומר פרויקט...","gui.alerts.cloudInfo":"שימו לב כי משתני ענן תומכים רק במספרים, ולא באותיות או בסמלים. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"למדו עוד.","gui.alerts.importing":"מייבא...","gui.defaultProject.variable":"המשתנה שלי","gui.extension.music.name":"מוזיקה","gui.extension.music.description":"נגנו בכלי נגינה ובתופים","gui.extension.pen.name":"עט","gui.extension.pen.description":"ציירו עם הדמות שלכם","gui.extension.videosensing.name":"חיישן מצלמה","gui.extension.videosensing.description":"זיהוי תנועה באמצעות המצלמה","gui.extension.text2speech.name":"טקסט לדיבור","gui.extension.text2speech.description":"גרמו לפרויקט שלכם לדבר","gui.extension.translate.name":"תרגום","gui.extension.translate.description":"תרגום טקסט להרבה שפות","gui.extension.makeymakey.description":"הפוך כל דבר לקליד","gui.extension.microbit.description":"חברו את הפרויקטים שלכם לעולם","gui.extension.microbit.connectingMessage":"מתחבר","gui.extension.ev3.description":"בנה רובוטים אינטראקטיביים ועוד.","gui.extension.ev3.connectingMessage":"מתחבר. וודאו שקוד ה־PIN שמוגדר ב־EV3 הוא 1234","gui.extension.boost.description":"תנו חיים ליצירות רובוטיות","gui.extension.boost.connectingMessage":"מתחבר","gui.extension.wedo2.description":"בנו עם מנועים וחיישנים","gui.extension.wedo2.connectingMessage":"מתחבר","gui.extension.gdxfor.description":"הרגש דחיפה, משיכה, תנועה וסיבוב","gui.extension.gdxfor.connectingMessage":"מתחבר","gui.libraryTags.all":"הכול","gui.libraryTags.animals":"חיות","gui.libraryTags.dance":"ריקוד","gui.libraryTags.effects":"אפקטים","gui.libraryTags.fantasy":"פנטסיה","gui.libraryTags.fashion":"אופנה","gui.libraryTags.food":"אוכל","gui.libraryTags.indoors":"בפנים","gui.libraryTags.loops":"לולאות","gui.libraryTags.music":"מוזיקה","gui.libraryTags.notes":"רשימות","gui.libraryTags.outdoors":"בחוץ","gui.libraryTags.patterns":"תבניות","gui.libraryTags.people":"אנשים","gui.libraryTags.percussion":"כלי הקשה","gui.libraryTags.space":"חלל","gui.libraryTags.sports":"ספורט","gui.libraryTags.underwater":"תת-מימי","gui.libraryTags.voice":"קול","gui.libraryTags.wacky":"משוגע","gui.libraryTags.animation":"הנפשה","gui.libraryTags.art":"אומנות","gui.libraryTags.games":"משחקים","gui.libraryTags.stories":"סיפורים","gui.libraryTags.letters":"אותיות","gui.opcodeLabels.direction":"כיוון","gui.opcodeLabels.xposition":"מיקום על ציר x","gui.opcodeLabels.yposition":"מיקום על ציר y","gui.opcodeLabels.size":"גודל","gui.opcodeLabels.costumename":"שם תלבושת","gui.opcodeLabels.costumenumber":"מספר תלבושת","gui.opcodeLabels.backdropname":"שם רקע","gui.opcodeLabels.backdropnumber":"מספר רקע","gui.opcodeLabels.volume":"עוצמה","gui.opcodeLabels.tempo":"קצב","gui.opcodeLabels.answer":"תשובה","gui.opcodeLabels.loudness":"קולניות","gui.opcodeLabels.username":"שם משתמש","gui.opcodeLabels.year":"שנה","gui.opcodeLabels.month":"חודש","gui.opcodeLabels.date":"תאריך","gui.opcodeLabels.dayofweek":"יום בשבוע","gui.opcodeLabels.hour":"שעה","gui.opcodeLabels.minute":"דקה","gui.opcodeLabels.second":"שניה","gui.opcodeLabels.timer":"שעון עצר","gui.sharedMessages.backdrop":"רקע{index}","gui.sharedMessages.costume":"תלבושת{index}","gui.sharedMessages.sprite":"דמות{index}","gui.sharedMessages.pop":"פופ","gui.sharedMessages.replaceProjectWarning":"להחליף את תוכן הפרויקט הנוכחי?","gui.sharedMessages.loadFromComputerTitle":"טעינה מהמחשב שלך","boost.color.any":"צבע כלשהו","boost.color.black":"שחור","boost.color.blue":"כחול","boost.color.green":"ירוק","boost.color.red":"אדום","boost.color.white":"לבן","boost.color.yellow":"צהוב","boost.getMotorPosition":"מיקום מנוע [MOTOR_REPORTER_ID]","boost.getTiltAngle":"זווית הטיה [TILT_DIRECTION]","boost.motorDirection.backward":"בדרך ההיא","boost.motorDirection.forward":"בדרך הזאת","boost.motorDirection.reverse":"הפוך","boost.motorOff":"כבה את מנוע [MOTOR_ID]","boost.motorOn":"הדלק את מנוע [MOTOR_ID]","boost.motorOnFor":"הדלקת [MOTOR_ID] למשך [DURATION] שניות","boost.motorOnForRotation":"הדלק מנוע [MOTOR_ID] למשך [ROTATION] סיבובים","boost.seeingColor":"רואים לבנה בצבע [COLOR]?","boost.setLightHue":"קבע צבע אור ל [HUE]","boost.setMotorDirection":"קבע כיוון [MOTOR_ID] ל[MOTOR_DIRECTION]","boost.setMotorPower":"קבע מהירות של [MOTOR_ID] ל[POWER] %","boost.tiltDirection.any":"הכל","boost.tiltDirection.down":"למטה","boost.tiltDirection.left":"שמאלה","boost.tiltDirection.right":"ימינה","boost.tiltDirection.up":"למעלה","boost.whenColor":"כאשר רואים לבנה בצבע [COLOR]","boost.whenTilted":"כאשר מוטה [TILT_DIRECTION_ANY]","ev3.beepNote":"צפצף תו [NOTE]ל[TIME]שניות","ev3.buttonPressed":"כפתור [PORT] נלחץ?","ev3.getBrightness":"בהירות","ev3.getDistance":"מרחק","ev3.getMotorPosition":"מצב מנוע ב[PORT] ","ev3.motorSetPower":"קבע מנוע[PORT] להספק של [POWER] %","ev3.motorTurnClockwise":"סובב את מנוע[PORT] בכיוון זה במשך [TIME] שניות","ev3.motorTurnCounterClockwise":"סובב את מנוע [PORT] בכיוון ההוא במשך [TIME] שניות","ev3.whenBrightnessLessThan":"כאשר בהירות <[DISTANCE]","ev3.whenButtonPressed":"כאשר לוחצים על כפתור [PORT]","ev3.whenDistanceLessThan":"כאשר מרחק < [DISTANCE]","gdxfor.getAcceleration":"תאוצה [DIRECTION]","gdxfor.getForce":"כוח","gdxfor.getSpin":"מהירות סיבוב [DIRECTION]","gdxfor.getTilt":"זווית הטיה [TILT]","gdxfor.isFreeFalling":"נופל?","gdxfor.isTilted":"מוטה [TILT]","gdxfor.pulled":"נמשך","gdxfor.pushed":"נדחף","gdxfor.shaken":"נוער","gdxfor.startedFalling":"החל ליפול","gdxfor.tiltDirectionMenu.any":"הכל","gdxfor.tiltDirectionMenu.back":"לאחור","gdxfor.tiltDirectionMenu.front":"קדימה","gdxfor.tiltDirectionMenu.left":"שמאלה","gdxfor.tiltDirectionMenu.right":"ימינה","gdxfor.turnedFaceDown":"פונה כלפי מטה","gdxfor.turnedFaceUp":"פונה כלפי מעלה","gdxfor.whenForcePushedOrPulled":"כאשר חיישן הכוח [PUSH_PULL]","gdxfor.whenGesture":"כאשר [GESTURE]","gdxfor.whenTilted":"כאשר מוטה [TILT]","makeymakey.downArrow":"חץ מטה","makeymakey.downArrowShort":"מטה","makeymakey.leftArrow":"חץ שמאלי","makeymakey.leftArrowShort":"שמאלה","makeymakey.rightArrow":"חץ ימני","makeymakey.rightArrowShort":"ימינה","makeymakey.spaceKey":"רווח","makeymakey.upArrow":"חץ מעלה","makeymakey.upArrowShort":"מעלה","makeymakey.whenKeyPressed":"כאשר לוחצים על מקש [KEY]","makeymakey.whenKeysPressedInOrder":"כאשר מקישים את הרצף [SEQUENCE] ","microbit.buttonsMenu.any":"כל","microbit.clearDisplay":"נקה תצוגה","microbit.defaultTextToDisplay":"שלום!","microbit.displaySymbol":"הצג [MATRIX]","microbit.displayText":"הצגת טקסט [TEXT]","microbit.gesturesMenu.jumped":"קפץ","microbit.gesturesMenu.moved":"זז","microbit.gesturesMenu.shaken":"רעד","microbit.isButtonPressed":"לחצו על כפתור [BTN]‏ ?","microbit.isTilted":"נוטה[DIRECTION]?","microbit.pinStateMenu.off":"כבה","microbit.pinStateMenu.on":"הפעל","microbit.tiltAngle":"זווית הטיה [DIRECTION]","microbit.tiltDirectionMenu.any":"כל","microbit.tiltDirectionMenu.back":"אחורית","microbit.tiltDirectionMenu.front":"קדמית","microbit.tiltDirectionMenu.left":"שמאלה","microbit.tiltDirectionMenu.right":"ימינה","microbit.whenButtonPressed":"כאשר לוחצים על כפתור [BTN]","microbit.whenGesture":"כאשר [GESTURE]","microbit.whenPinConnected":"כאשר פין [PIN] מחובר","microbit.whenTilted":"כאשר מוטה [DIRECTION]","music.categoryName":"מוזיקה","music.changeTempo":"שנה קצב ב [TEMPO]","music.drumBass":"(2) תוף בס","music.drumBongo":"(13) בונגו","music.drumCabasa":"(15) קבסה","music.drumClaves":"(9) מקלות הקשה","music.drumClosedHiHat":"(6) מצילה סגורה","music.drumConga":"(14) קונגה","music.drumCowbell":"(11) פעמון פרה","music.drumCrashCymbal":"(4) מצילתיים","music.drumCuica":"(18) קויקה","music.drumGuiro":"(16) גווירו","music.drumHandClap":"(8) מחיאת כף","music.drumOpenHiHat":"(5) מצילה פתוחה","music.drumSideStick":"(3) מקל על צד התוף","music.drumSnare":"(1) תוף סנר","music.drumTambourine":"(7) תוף מרים","music.drumTriangle":"(12) משולש","music.drumVibraslap":"(17) ויברסלאפ","music.drumWoodBlock":"(10) לבנת עץ","music.getTempo":"קצב","music.instrumentBass":"(6) בס","music.instrumentBassoon":"(14) בסון","music.instrumentCello":"(8) צ\'לו","music.instrumentChoir":"(15) מקהלה","music.instrumentClarinet":"(10) קלרינט","music.instrumentElectricGuitar":"(5) גיטרה חשמלית","music.instrumentElectricPiano":"(2) פסנתר חשמלי","music.instrumentFlute":"(12) חליל","music.instrumentGuitar":"(4) גיטרה","music.instrumentMarimba":"(19) מרימבה","music.instrumentMusicBox":"(17) תיבת נגינה ","music.instrumentOrgan":"(3) אורגן","music.instrumentPiano":"(1) פסנתר","music.instrumentPizzicato":"(7) פיציקטו","music.instrumentSaxophone":"(11) סקסופון","music.instrumentSteelDrum":"(18) תוף פלדה","music.instrumentSynthLead":"(20) סינתיסייזר לד","music.instrumentSynthPad":"(21) סינתיסייזר פאד","music.instrumentTrombone":"(9) טרומבון","music.instrumentVibraphone":"(16) ויברפון","music.instrumentWoodenFlute":"(13) חליל עץ","music.midiPlayDrumForBeats":"נגן בתוף [DRUM] למשך [BEATS] פעימות","music.midiSetInstrument":"קביעת כלי נגינה ל[INSTRUMENT]","music.playDrumForBeats":"נגן בתוף [DRUM] למשך [BEATS] פעימות","music.playNoteForBeats":"נגן תו [NOTE] במשך [BEATS] פעימות","music.restForBeats":"נוח למשך [BEATS] פעימות","music.setInstrument":"קבע כלי נגינה ל [INSTRUMENT]","music.setTempo":"קבע קצב ל [TEMPO]","pen.categoryName":"עט","pen.changeColorParam":"שנה [COLOR_PARAM] עט ב[VALUE]","pen.changeHue":"שנה צבע עט ב[HUE]","pen.changeShade":"שנה הצללת עט ב[SHADE]","pen.changeSize":"שנה גודל עט ב[SIZE]","pen.clear":"מחק הכול","pen.colorMenu.brightness":"בהירות","pen.colorMenu.color":"צבע","pen.colorMenu.saturation":"רווי צבע","pen.colorMenu.transparency":"שקיפות","pen.penDown":"עט מטה","pen.penUp":"עט מעלה","pen.setColor":"קבע צבע עט ל[COLOR]","pen.setColorParam":"קבע [COLOR_PARAM] עט ל[VALUE]","pen.setHue":"קבע צבע עט ל[HUE]","pen.setShade":"קבע הצללת עט ל[SHADE]","pen.setSize":"קבע גודל עט ל[SIZE]","pen.stamp":"חתום","text2speech.alto":"אלט","text2speech.categoryName":"טקסט לדיבור","text2speech.defaultTextToSpeak":"שלום","text2speech.giant":"ענק","text2speech.kitten":"חתלתול","text2speech.setLanguageBlock":"קבע שפה ל[LANGUAGE]","text2speech.setVoiceBlock":"קבע קול ל [VOICE]","text2speech.speakAndWaitBlock":"הקרא [WORDS]","text2speech.squeak":"ציוץ","text2speech.tenor":"טנור","translate.categoryName":"תרגום","translate.defaultTextToTranslate":"שלום","translate.translateBlock":"תרגם[WORDS] ל[LANGUAGE]","translate.viewerLanguage":"שפה","videoSensing.categoryName":"חיישן מצלמה","videoSensing.direction":"כיוון","videoSensing.motion":"תנועה","videoSensing.off":"כבה","videoSensing.on":"הפעל","videoSensing.onFlipped":"הפעל כתמונת ראי","videoSensing.setVideoTransparency":"קבע שקיפות מצלמה ל [TRANSPARENCY]","videoSensing.sprite":"דמות","videoSensing.stage":"במה","videoSensing.videoOn":"[ATTRIBUTE] של המצלמה על [SUBJECT]","videoSensing.videoToggle":"[VIDEO_STATE] את המצלמה","videoSensing.whenMotionGreaterThan":"כאשר התנועה במצלמה > [REFERENCE]","wedo2.getDistance":"מרחק","wedo2.getTiltAngle":"זווית הטיה [TILT_DIRECTION]","wedo2.isTilted":"מוטה[TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"בדרך ההיא","wedo2.motorDirection.forward":"בדרך הזאת","wedo2.motorDirection.reverse":"הפוך","wedo2.motorId.a":"מנוע A","wedo2.motorId.all":"כל המנועים","wedo2.motorId.b":"מנוע B","wedo2.motorId.default":"מנוע","wedo2.motorOff":"כיבוי [MOTOR_ID]","wedo2.motorOn":"הדלקת [MOTOR_ID]","wedo2.motorOnFor":"הדלקת[MOTOR_ID] למשך [DURATION] שניות","wedo2.playNoteFor":"ניגון תו [NOTE] למשך [DURATION] שניות","wedo2.setLightHue":"קבע צבע אור ל [HUE]","wedo2.setMotorDirection":"קבע כיוון[MOTOR_ID] ל [MOTOR_DIRECTION]","wedo2.startMotorPower":"קבע הספק של[MOTOR_ID] ל [POWER]","wedo2.tiltDirection.any":"כל","wedo2.tiltDirection.down":"מטה","wedo2.tiltDirection.left":"שמאלה","wedo2.tiltDirection.right":"ימינה","wedo2.tiltDirection.up":"מעלה","wedo2.whenDistance":"כאשר מרחק [OP] [REFERENCE]","wedo2.whenTilted":"כאשר מוטה [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"צבע","paint.paintEditor.saturation":"רוויה","paint.paintEditor.brightness":"בהירות","paint.paintEditor.costume":"תלבושת","paint.paintEditor.group":"קבץ","paint.paintEditor.ungroup":"בטל קיבוץ","paint.paintEditor.undo":"בטל","paint.paintEditor.redo":"בצע שוב","paint.paintEditor.forward":"קדימה","paint.paintEditor.backward":"אחורה","paint.paintEditor.front":"העבר לקידמה","paint.paintEditor.back":"העבר לרקע","paint.paintEditor.more":"עוד","paint.modeTools.brushSize":"גודל","paint.modeTools.eraserSize":"גודל מחק","paint.modeTools.copy":"העתק","paint.modeTools.paste":"הדבק","paint.modeTools.delete":"מחק","paint.modeTools.curved":"מעוקל","paint.modeTools.pointed":"מחודד","paint.modeTools.thickness":"עובי","paint.modeTools.flipHorizontal":"הפוך אופקית","paint.modeTools.flipVertical":"הפוך אנכית","paint.modeTools.filled":"מלא","paint.modeTools.outlined":"מסורטט","paint.paintEditor.bitmap":"המרה למפת סיביות","paint.paintEditor.vector":"המרה לוקטור","paint.paintEditor.fill":"מילוי","paint.paintEditor.stroke":"מסגרת","paint.brushMode.brush":"מברשת","paint.eraserMode.eraser":"מחק","paint.fillMode.fill":"מילוי","paint.lineMode.line":"קו","paint.ovalMode.oval":"עיגול","paint.rectMode.rect":"מלבן","paint.reshapeMode.reshape":"שנה צורה","paint.roundedRectMode.roundedRect":"מלבן מעוגל","paint.selectMode.select":"בחר","paint.textMode.text":"טקסט","paint.colorPicker.swap":"החלף","tw.usernameModal.reset":"אִתחוּל"},"hr":{"gui.alerts.tryAgain":"Pokušajte ponovo","gui.alerts.download":"Preuzmi","gui.connection.reconnect":"Ponovno povezivanje","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Ruksak","gui.backpack.errorBackpack":"Pogreška pri učitavanju","gui.backpack.loadingBackpack":"Učitavanje...","gui.backpack.more":"Više","gui.backpack.emptyBackpack":"Ruksak je prazan","gui.unsupportedBrowser.label":"Preglednik nije podržan","gui.cards.all-tutorials":"Tutoriali","gui.cards.shrink":"Shrink","gui.cards.expand":"Expand","gui.cards.close":"Zatvori","gui.cards.more-things-to-try":"Isprobaj i ovo!","gui.cards.see-more":"Vidi više","gui.comingSoon.message1":"Ne brini, radimo na tome{emoji}","gui.comingSoon.message2":"Uskoro...","gui.comingSoon.message3":"Radimo na tome{emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Nije pronađen nijedan uređaj","gui.connection.auto-scanning.prescan":"Neka Vaš uređaj bude u blizini, a zatim započnite s pretraživanjem.","gui.connection.auto-scanning.pressbutton":"Pritisnite gumb na uređaju.","gui.connection.auto-scanning.start-search":"Počnite tražiti","gui.connection.connecting-searchbutton":"Traženje...","gui.connection.auto-scanning.try-again":"Pokušajte ponovo","gui.connection.connected":"Povezan","gui.connection.disconnect":"Isključiti","gui.connection.go-to-editor":"Idite na uređivač","gui.connection.connecting-cancelbutton":"Povezivanje...","gui.connection.error.errorMessage":"Ups! Nešto je pošlo po krivom.","gui.connection.error.tryagainbutton":"Pokušajte ponovo","gui.connection.error.helpbutton":"Pomoć","gui.connection.peripheral-name-label":"Naziv uređaja","gui.connection.connect":"Poveži","gui.connection.scanning.lookingforperipherals":"Tražim uređaje","gui.connection.scanning.noPeripheralsFound":"Nema uređaja","gui.connection.scanning.instructions":"Odaberite svoj uređaj na gornjem popisu.","gui.connection.search":"Osvježi","gui.connection.unavailable.installscratchlink":"Provjerite jeste li instalirali i pokrenuli Scratch Link","gui.connection.unavailable.enablebluetooth":"Provjerite je li Bluetooth omogućen","gui.connection.unavailable.tryagainbutton":"Pokušajte ponovo","gui.connection.unavailable.helpbutton":"Pomoć","gui.controls.go":"Počni","gui.controls.stop":"Zaustavi","gui.crashMessage.label":"Ups! Nešto je pošlo po krivom.","gui.crashMessage.errorNumber":"Your error was logged with id {errorId}","gui.crashMessage.reload":"Ponovno učitaj","gui.customProcedures.myblockModalTitle":"Napravi blok","gui.customProcedures.addAnInputNumberText":"Dodaj ulaz","gui.customProcedures.numberTextType":"broj ili tekst","gui.customProcedures.addAnInputBoolean":"Dodaj ulaz","gui.customProcedures.booleanType":"bulov izraz","gui.customProcedures.addALabel":"Dodajte natpis","gui.customProcedures.runWithoutScreenRefresh":"Izvršite bez osvježavanja zaslona","gui.customProcedures.cancel":"Otkaži","gui.customProcedures.ok":"U redu","gui.SpriteInfo.direction":"Smjer","gui.directionPicker.rotationStyles.allAround":"Na sve strane","gui.directionPicker.rotationStyles.leftRight":"Lijevo/Desno","gui.directionPicker.rotationStyles.dontRotate":"Bez okretanja","gui.gui.addExtension":"Dodaj proširenje","gui.gui.codeTab":"Skripte","gui.gui.backdropsTab":"Pozadine","gui.gui.costumesTab":"Kostimi","gui.gui.soundsTab":"Zvukovi","gui.extensionLibrary.comingSoon":"Dolazi uskoro","gui.extensionLibrary.requires":"Potrebno","gui.extensionLibrary.collaboration":"Suradnja s","gui.library.filterPlaceholder":"Traži","gui.library.allTag":"Sve","gui.loader.headline":"Učitavanje projekta","gui.loader.creating":"Kreiranje projekta","gui.authorInfo.byUser":"od {username}","gui.menuBar.seeProjectPage":"Pogledaj stranicu projekta","gui.menuBar.LanguageSelector":"izbornik jezika","gui.menuBar.tutorialsLibrary":"Tutoriali","gui.menuBar.restoreSprite":"Vrati lika","gui.menuBar.restoreSound":"Vrati zvuk","gui.menuBar.restoreCostume":"Vrati kostim","gui.menuBar.restore":"Vrati obrisano","gui.menuBar.saveNow":"Spremi sada","gui.menuBar.saveAsCopy":"Spremi kao kopiju","gui.menuBar.remix":"Obrada","gui.menuBar.new":"Novo","gui.menuBar.file":"Datoteka","gui.menuBar.downloadToComputer":"Spremi na računalo","gui.menuBar.edit":"Uredi","gui.menuBar.turboModeOff":"Isključite turbo način rada","gui.menuBar.turboModeOn":"Uključite turbo način rada","gui.gui.projectTitlePlaceholder":"Naslov projekta ","gui.menuBar.isShared":"Dijeljeno","gui.menuBar.share":"Dijeli","gui.modal.help":"Pomoć","gui.modal.back":"Nazad","gui.monitor.listMonitor.empty":"(prazno)","gui.monitor.listMonitor.listLength":"dužina{length}","gui.monitor.contextMenu.default":"normalni prikaz","gui.monitor.contextMenu.large":"veliki prikaz","gui.monitor.contextMenu.slider":"klizač","gui.monitor.contextMenu.sliderRange":"change slider range","gui.monitor.contextMenu.import":"import","gui.monitor.contextMenu.export":"export","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Play","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"Za sve likove","gui.gui.variableScopeOptionSpriteOnly":"Samo za ovaj lik","gui.gui.cloudVariableOption":"Varijabla na poslužitelju","gui.gui.variablePromptAllSpritesMessage":"Ova će varijabla biti dostupna svim likovima.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Otkaži","gui.prompt.ok":"U redu","gui.playbackStep.stopMsg":"Zaustavi","gui.playbackStep.playMsg":"Pokreni","gui.playbackStep.loadingMsg":"Učitavam...","gui.playbackStep.saveMsg":"Spremi","gui.playbackStep.reRecordMsg":"Snimi ponovno","gui.recordModal.title":"Snimi zvuk","gui.recordingStep.beginRecord":"Započnite snimanje klikom na gumb u nastavku","gui.recordingStep.permission":"{arrow}Trebamo vašu dozvolu za korištenje mikrofona","gui.recordingStep.stop":"Zaustavi snimanje","gui.recordingStep.record":"Snimi","gui.sliderModal.min":"Minimum value","gui.sliderModal.max":"Maximum value","gui.sliderModal.title":"Change slider range","gui.sliderPrompt.cancel":"Cancel","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Zvuk","gui.soundEditor.play":"Pokreni","gui.soundEditor.stop":"Zaustavi","gui.soundEditor.copy":"Copy","gui.soundEditor.paste":"Paste","gui.soundEditor.copyToNew":"Copy to New","gui.soundEditor.delete":"Delete","gui.soundEditor.save":"Spremi","gui.soundEditor.undo":"Poništi","gui.soundEditor.redo":"Ponovi","gui.soundEditor.faster":"Brže","gui.soundEditor.slower":"Sporije","gui.soundEditor.echo":"Jeka","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Glasnije","gui.soundEditor.softer":"Blaže","gui.soundEditor.reverse":"Obrnuto","gui.soundEditor.fadeOut":"Fade out","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Mute","gui.SpriteInfo.spritePlaceholder":"Ime","gui.SpriteInfo.sprite":"Lik","gui.SpriteInfo.show":"Prikaži","gui.SpriteInfo.size":"Veličina","gui.spriteSelectorItem.contextMenuDuplicate":"Dupliciraj","gui.spriteSelectorItem.contextMenuExport":"izvoz","gui.spriteSelectorItem.contextMenuDelete":"obriši","gui.spriteSelector.addSpriteFromLibrary":"Odaberi lik","gui.spriteSelector.addSpriteFromPaint":"Naslikaj","gui.spriteSelector.addSpriteFromSurprise":"Iznenađenje","gui.spriteSelector.addSpriteFromFile":"Učitaj lik","gui.stageHeader.stageSizeLarge":"Prijeđi na veliku pozornicu","gui.stageHeader.stageSizeSmall":"Prijeđi na malu pozornicu","gui.stageHeader.stageSizeFull":"Rad preko cijelog zaslona","gui.stageHeader.stageSizeUnFull":"Izađite iz cijelog zaslona","gui.stageHeader.fullscreenControl":"Kontrola cijelog zaslona","gui.spriteSelector.addBackdropFromLibrary":"Odaberi pozadinu","gui.stageSelector.addBackdropFromPaint":"Naslikaj","gui.stageSelector.addBackdropFromSurprise":"Iznenađenje","gui.stageSelector.addBackdropFromFile":"Učitaj pozadinu","gui.stageSelector.stage":"Pozornica","gui.stageSelector.backdrops":"Pozadine","gui.telemetryOptIn.label":"Report statistics to improve Scratch","gui.telemetryOptIn.body1":"The Scratch Team is always looking to better understand how Scratch is used around the world. To help support this effort, you can allow Scratch to automatically send usage information to the Scratch Team.","gui.telemetryOptIn.body2":"The information we collect includes language selection, blocks usage, and some events like saving, loading, and uploading a project. We DO NOT collect any personal information. Please see our {privacyPolicyLink} for more information.","gui.telemetryOptIn.privacyPolicyLink":"Privacy Policy","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Turbo način","gui.webglModal.label":"Preglednik ne podržava WebGL","gui.webglModal.webgllink":"ne podržava WebGL","gui.costumeLibrary.chooseABackdrop":"Odaberi pozadinu","gui.costumeLibrary.chooseACostume":"Odaberi kostim","gui.costumeTab.addBackdropFromLibrary":"Odaberi pozadinu","gui.costumeTab.addCostumeFromLibrary":"Odaberi kostim","gui.costumeTab.addBlankCostume":"Naslikaj","gui.costumeTab.addSurpriseCostume":"Iznenađenje","gui.costumeTab.addFileBackdrop":"Učitaj pozadinu","gui.costumeTab.addFileCostume":"Prenesi kostim","gui.extensionLibrary.chooseAnExtension":"Odaberi proširenje","gui.extensionLibrary.extensionUrl":"Unesi URL proširenja","gui.monitors.importListColumnPrompt":"Which column should be used (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Nije moguće započeti snimanje","gui.soundLibrary.chooseASound":"Odaberi zvuk","gui.soundTab.fileUploadSound":"Učitaj zvuk","gui.soundTab.surpriseSound":"Iznenađenje","gui.soundTab.recordSound":"Snimi","gui.soundTab.addSoundFromLibrary":"Odaberi zvuk","gui.spriteLibrary.chooseASprite":"Odaberi lik","gui.tipsLibrary.tutorials":"Odaberi vodič","gui.alerts.createsuccess":"Novi projekt kreiran.","gui.alerts.createcopysuccess":"Projekt je spremljen kao kopija","gui.alerts.createremixsuccess":"Projekt je spremljen kao remix.","gui.alerts.creating":"Stvaram novi...","gui.alerts.creatingCopy":"Kopiram projekt...","gui.alerts.creatingRemix":"Remixam projekt...","gui.alerts.creatingError":"Projekt nije bilo moguće kreirati. Molimo pokušaj ponovo!","gui.alerts.savingError":"Projekt nije bilo moguće spremiti.","gui.alerts.savesuccess":"Projekt je spremljen.","gui.alerts.saving":"Spremam projekt...","gui.alerts.cloudInfo":"Imaj na umu da varijable oblaka podržavaju samo brojeve, a ne slova ili simbole. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Nauči više.","gui.alerts.importing":"Importing…","gui.defaultProject.variable":"moja varijabla","gui.extension.music.name":"Glazba","gui.extension.music.description":"Sviraj na instrumentima i bubnjevima.","gui.extension.pen.name":"Olovka","gui.extension.pen.description":"Crtaj pomoću likova.","gui.extension.videosensing.name":"Video","gui.extension.videosensing.description":"Osjećaj pokreta s kamerom.","gui.extension.text2speech.name":"Tekst u govor","gui.extension.text2speech.description":"Likovi u projektima govore.","gui.extension.translate.name":"Prevedi","gui.extension.translate.description":"Prevedi tekst na puno jezika.","gui.extension.makeymakey.description":"Pretvori bilo što u tipku.","gui.extension.microbit.description":"Poveži svoj projekt sa svijetom.","gui.extension.microbit.connectingMessage":"Povezivanje","gui.extension.ev3.description":"Izgradi interaktivne robote i još mnogo toga.","gui.extension.ev3.connectingMessage":"Spajanje. Provjeri je li pin na EV3 postavljen na 1234.","gui.extension.boost.description":"Bring robotic creations to life.","gui.extension.boost.connectingMessage":"Connecting","gui.extension.wedo2.description":"Gradi s motorima i senzorima.","gui.extension.wedo2.connectingMessage":"Povezivanje","gui.extension.gdxfor.description":"Sense push, pull, motion, and spin.","gui.extension.gdxfor.connectingMessage":"Connecting","gui.libraryTags.all":"Sve","gui.libraryTags.animals":"Životinje","gui.libraryTags.dance":"Ples","gui.libraryTags.effects":"Efekti","gui.libraryTags.fantasy":"Fantazija","gui.libraryTags.fashion":"Moda","gui.libraryTags.food":"Hrana","gui.libraryTags.indoors":"Unutra","gui.libraryTags.loops":"Petlje","gui.libraryTags.music":"Glazba","gui.libraryTags.notes":"Bilješke","gui.libraryTags.outdoors":"Vani","gui.libraryTags.patterns":"Uzorak","gui.libraryTags.people":"Ljudi","gui.libraryTags.percussion":"Udaraljke","gui.libraryTags.space":"Prostor","gui.libraryTags.sports":"Sport","gui.libraryTags.underwater":"Podvodni","gui.libraryTags.voice":"Glas","gui.libraryTags.wacky":"Ćaknut","gui.libraryTags.animation":"Animacija","gui.libraryTags.art":"Umjetnost","gui.libraryTags.games":"Igre","gui.libraryTags.stories":"Priče","gui.libraryTags.letters":"Slova","gui.opcodeLabels.direction":"smjer","gui.opcodeLabels.xposition":"x položaj","gui.opcodeLabels.yposition":"y položaj","gui.opcodeLabels.size":"veličina","gui.opcodeLabels.costumename":"naziv kostima","gui.opcodeLabels.costumenumber":"Broj kostima","gui.opcodeLabels.backdropname":"naziv pozadine","gui.opcodeLabels.backdropnumber":"Broj pozadine","gui.opcodeLabels.volume":"jačina zvuka","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"odgovor","gui.opcodeLabels.loudness":"glasnoća","gui.opcodeLabels.username":"nadimak","gui.opcodeLabels.year":"godina","gui.opcodeLabels.month":"mjesec","gui.opcodeLabels.date":"dan","gui.opcodeLabels.dayofweek":"dan u tjednu","gui.opcodeLabels.hour":"sat","gui.opcodeLabels.minute":"minuta","gui.opcodeLabels.second":"sekunda","gui.opcodeLabels.timer":"štoperica","gui.sharedMessages.backdrop":"pozadina{index}","gui.sharedMessages.costume":"kostim{index}","gui.sharedMessages.sprite":"Lik{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Replace contents of the current project?","gui.sharedMessages.loadFromComputerTitle":"Load from your computer","boost.color.any":"bilo koja boja","boost.color.black":"crna","boost.color.blue":"plava","boost.color.green":"zelena","boost.color.red":"crvena","boost.color.white":"bijela","boost.color.yellow":"yellow","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] position","boost.getTiltAngle":"kut nagiba [TILT_DIRECTION]","boost.motorDirection.backward":"smjer kazaljke na satu","boost.motorDirection.forward":"suprotno kazaljke na satu","boost.motorDirection.reverse":"obrnuto","boost.motorOff":"turn motor [MOTOR_ID] off","boost.motorOn":"turn motor [MOTOR_ID] on","boost.motorOnFor":"turn motor [MOTOR_ID] for [DURATION] seconds","boost.motorOnForRotation":"turn motor [MOTOR_ID] for [ROTATION] rotations","boost.seeingColor":"seeing [COLOR] brick?","boost.setLightHue":"set light color to [HUE]","boost.setMotorDirection":"set motor [MOTOR_ID] direction [MOTOR_DIRECTION]","boost.setMotorPower":"set motor [MOTOR_ID] speed to [POWER] %","boost.tiltDirection.any":"bilo koja","boost.tiltDirection.down":"dolje","boost.tiltDirection.left":"lijevo","boost.tiltDirection.right":"desno","boost.tiltDirection.up":"gore","boost.whenColor":"when [COLOR] brick seen","boost.whenTilted":"kada je nagnuto [TILT_DIRECTION_ANY]","ev3.beepNote":"sviraj ton [NOTE] [TIME] sekundi","ev3.buttonPressed":"gumb [PORT] pritisnut?","ev3.getBrightness":"osvjetljenje","ev3.getDistance":"udaljenost","ev3.getMotorPosition":"motor [PORT] pozicija","ev3.motorSetPower":"motor [PORT] postavi snagu na [POWER] %","ev3.motorTurnClockwise":"motor [PORT] okreni ovako na [TIME] sekundi","ev3.motorTurnCounterClockwise":"motor [PORT] okreni suprotno od kazaljke na satu na [TIME] sekunde","ev3.whenBrightnessLessThan":"kada je osvjeteljnje < [DISTANCE]","ev3.whenButtonPressed":"kada je tipka [PORT] pritisnuta","ev3.whenDistanceLessThan":"kada je udaljenost < [DISTANCE]","gdxfor.getAcceleration":"ubrzanje [DIRECTION]","gdxfor.getForce":"force","gdxfor.getSpin":"spin speed [DIRECTION]","gdxfor.getTilt":"tilt angle [TILT]","gdxfor.isFreeFalling":"falling?","gdxfor.isTilted":"tilted [TILT]?","gdxfor.pulled":"pulled","gdxfor.pushed":"pushed","gdxfor.shaken":"shaken","gdxfor.startedFalling":"started falling","gdxfor.tiltDirectionMenu.any":"any","gdxfor.tiltDirectionMenu.back":"back","gdxfor.tiltDirectionMenu.front":"front","gdxfor.tiltDirectionMenu.left":"left","gdxfor.tiltDirectionMenu.right":"right","gdxfor.turnedFaceDown":"turned face down","gdxfor.turnedFaceUp":"turned face up","gdxfor.whenForcePushedOrPulled":"when force sensor [PUSH_PULL]","gdxfor.whenGesture":"when [GESTURE]","gdxfor.whenTilted":"when tilted [TILT]","makeymakey.downArrow":"strelica dolje","makeymakey.downArrowShort":"dolje","makeymakey.leftArrow":"strelica lijevo","makeymakey.leftArrowShort":"lijevo","makeymakey.rightArrow":"strelica desno","makeymakey.rightArrowShort":"desno","makeymakey.spaceKey":"razmaknica","makeymakey.upArrow":"strelica gore","makeymakey.upArrowShort":"gore","makeymakey.whenKeyPressed":"when [KEY] key pressed","makeymakey.whenKeysPressedInOrder":"when [SEQUENCE] pressed in order","microbit.buttonsMenu.any":"bilo koja","microbit.clearDisplay":"očisti ekran","microbit.defaultTextToDisplay":"Bok!","microbit.displaySymbol":"prikaži [MATRIX]","microbit.displayText":"prikaži tekst [TEXT]","microbit.gesturesMenu.jumped":"skok","microbit.gesturesMenu.moved":"pomaknuto","microbit.gesturesMenu.shaken":"protresen","microbit.isButtonPressed":"gumb [BTN] pritisnut?","microbit.isTilted":"nagnuto [DIRECTION]?","microbit.pinStateMenu.off":"isključeno","microbit.pinStateMenu.on":"uključeno","microbit.tiltAngle":"kut nagiba [DIRECTION]","microbit.tiltDirectionMenu.any":"bilo koja","microbit.tiltDirectionMenu.back":"nazad","microbit.tiltDirectionMenu.front":"naprijed","microbit.tiltDirectionMenu.left":"lijevo","microbit.tiltDirectionMenu.right":"desno","microbit.whenButtonPressed":"kada je gumb [BTN] pritisnut","microbit.whenGesture":"kada je [GESTURE]","microbit.whenPinConnected":"kada je pin [PIN] spojen","microbit.whenTilted":"kada je nagnuto [DIRECTION]","music.categoryName":"Glazba","music.changeTempo":"promijeni tempo za [TEMPO]","music.drumBass":"(2) Bass bubanj","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Drveni štapići","music.drumClosedHiHat":"(6) Zatvorene činele","music.drumConga":"(14) Konga","music.drumCowbell":"(11) Kravlje zvonce","music.drumCrashCymbal":"(4) Crash činele","music.drumCuica":"(18) Cuica bubanj","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Pljesak","music.drumOpenHiHat":"(5) Otvorene činele","music.drumSideStick":"(3) Side Stick zvuk","music.drumSnare":"(1) Mali bubanj","music.drumTambourine":"(7) Tamburin","music.drumTriangle":"(12) Triangl","music.drumVibraslap":"(17) Vibrafon","music.drumWoodBlock":"(10) Drveni block","music.getTempo":"tempo","music.instrumentBass":"(6) Bas","music.instrumentBassoon":"(14) Fagot","music.instrumentCello":"(8) Violončelo","music.instrumentChoir":"(15) Zbor","music.instrumentClarinet":"(10) Klarinet","music.instrumentElectricGuitar":"(5) Električna gitara","music.instrumentElectricPiano":"(2) Električni piano","music.instrumentFlute":"(12) Flauta","music.instrumentGuitar":"(4) Gitara","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Muzička kutijica","music.instrumentOrgan":"(3) Orgulje","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saksofon","music.instrumentSteelDrum":"(18) Čelični bubanj","music.instrumentSynthLead":"(20) Synth Lead","music.instrumentSynthPad":"(21) Synth Pad","music.instrumentTrombone":"(9) Trombon","music.instrumentVibraphone":"(16) Vibrafon","music.instrumentWoodenFlute":"(13) Drvena flauta","music.midiPlayDrumForBeats":"bubnjaj [DRUM] [BEATS] puta","music.midiSetInstrument":"postavi instrument na [INSTRUMENT]","music.playDrumForBeats":"bubnjaj [DRUM] [BEATS] puta","music.playNoteForBeats":"sviraj ton [NOTE] [BEATS] puta","music.restForBeats":"preskoči [BEATS] puta","music.setInstrument":"postavi instrument na [INSTRUMENT]","music.setTempo":"postavi tempo na [TEMPO]","pen.categoryName":"Olovka","pen.changeColorParam":"promijeni [COLOR_PARAM] olovke za [VALUE]","pen.changeHue":"promijeni boju olovke za [HUE]","pen.changeShade":"promjeni sjenu olovke za [SHADE]","pen.changeSize":"promijeni debljinu olovke za [SIZE]","pen.clear":"izbriši sve","pen.colorMenu.brightness":"osvjetljenje","pen.colorMenu.color":"boja","pen.colorMenu.saturation":"saturacija","pen.colorMenu.transparency":"providnost","pen.penDown":"spusti olovku","pen.penUp":"podigni olovku","pen.setColor":"postavi boju olovke na [COLOR]","pen.setColorParam":"postavi [COLOR_PARAM] olovke na [VALUE]","pen.setHue":"postavi boju olovke na [HUE]","pen.setShade":"postavi sjenu olovke na [SHADE]","pen.setSize":"postavi debljinu olovke na [SIZE]","pen.stamp":"žig","text2speech.alto":"alt","text2speech.categoryName":"Text to Speech","text2speech.defaultTextToSpeak":"hello","text2speech.giant":"div","text2speech.kitten":"mačić","text2speech.setLanguageBlock":"postavi jezik na [LANGUAGE]","text2speech.setVoiceBlock":"postavi glas na [VOICE]","text2speech.speakAndWaitBlock":"govori [WORDS]","text2speech.squeak":"cviljenje","text2speech.tenor":"tenor","translate.categoryName":"Prevedi","translate.defaultTextToTranslate":"Bok","translate.translateBlock":"prevedi [WORDS] na [LANGUAGE]","translate.viewerLanguage":"jezik","videoSensing.categoryName":"Video","videoSensing.direction":"smjer","videoSensing.motion":"gibanje","videoSensing.off":"isključeno","videoSensing.on":"uključeno","videoSensing.onFlipped":"uključeno zrcaljenje","videoSensing.setVideoTransparency":"postavi providnost videa na [TRANSPARENCY]","videoSensing.sprite":"lik","videoSensing.stage":"pozornica","videoSensing.videoOn":"video [ATTRIBUTE] na [SUBJECT]","videoSensing.videoToggle":"postavi video [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"kada je gibanje videa > [REFERENCE]","wedo2.getDistance":"udaljenost","wedo2.getTiltAngle":"kut nagiba [TILT_DIRECTION]","wedo2.isTilted":"nagnuto [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"smjer kazaljke na satu","wedo2.motorDirection.forward":"suprotno kazaljke na satu","wedo2.motorDirection.reverse":"obrnuto","wedo2.motorId.a":"motor A","wedo2.motorId.all":"svi motori","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"isključi [MOTOR_ID]","wedo2.motorOn":"uključi [MOTOR_ID]","wedo2.motorOnFor":"uključi [MOTOR_ID] na [DURATION] sekundi","wedo2.playNoteFor":"sviraj ton [NOTE] [DURATION] sekundi","wedo2.setLightHue":"postavi boju svjetla na [HUE]","wedo2.setMotorDirection":"postavi smjer [MOTOR_ID] na [MOTOR_DIRECTION]","wedo2.startMotorPower":"postavi snagu [MOTOR_ID] na [POWER]","wedo2.tiltDirection.any":"bilo koja","wedo2.tiltDirection.down":"dolje","wedo2.tiltDirection.left":"lijevo","wedo2.tiltDirection.right":"desno","wedo2.tiltDirection.up":"gore","wedo2.whenDistance":"kada je udaljenost [OP] [REFERENCE]","wedo2.whenTilted":"kada je nagnuto [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Boja","paint.paintEditor.saturation":"Saturacija","paint.paintEditor.brightness":"Osvjetljenje","paint.paintEditor.costume":"Kostim","paint.paintEditor.group":"Grupiraj","paint.paintEditor.ungroup":"Razgrupiraj","paint.paintEditor.undo":"Poništi","paint.paintEditor.redo":"Ponovi","paint.paintEditor.forward":"Naprijed","paint.paintEditor.backward":"Natrag","paint.paintEditor.front":"prednji","paint.paintEditor.back":"Stražnji","paint.paintEditor.more":"Više","paint.modeTools.brushSize":"Veličina","paint.modeTools.eraserSize":"Debljina gumice","paint.modeTools.copy":"Kopiraj","paint.modeTools.paste":"Zalijepi","paint.modeTools.delete":"Izbriši","paint.modeTools.curved":"Zaobljen","paint.modeTools.pointed":"Šiljast","paint.modeTools.thickness":"Debljina","paint.modeTools.flipHorizontal":"Obrni vodoravno","paint.modeTools.flipVertical":"Obrni okomito","paint.modeTools.filled":"Ispunjeno","paint.modeTools.outlined":"Obrubljeno","paint.paintEditor.bitmap":"Pretvori u mapu bitova","paint.paintEditor.vector":"Pretvori u vektor","paint.paintEditor.fill":"Ispuna","paint.paintEditor.stroke":"Obrub","paint.brushMode.brush":"Kist","paint.eraserMode.eraser":"Gumica","paint.fillMode.fill":"Ispuna","paint.lineMode.line":"Linija","paint.ovalMode.oval":"Kružnica","paint.rectMode.rect":"Pravokutnik","paint.reshapeMode.reshape":"Preoblikuj","paint.roundedRectMode.roundedRect":"Pravokutnik","paint.selectMode.select":"Označi","paint.textMode.text":"Tekst","paint.colorPicker.swap":"Zamijeni"},"xh":{"gui.alerts.tryAgain":"Zama kwakhona","gui.alerts.download":"Khuphela","gui.connection.reconnect":"Qhagamshelana kwakhona","gui.backpack.costumeLabel":"isinxibo","gui.backpack.soundLabel":"isandi","gui.backpack.scriptLabel":"Iskriphth","gui.backpack.spriteLabel":"i-sprite","gui.backpack.header":"Ubhaka","gui.backpack.errorBackpack":"Kubekho ingxaki ekulaysheni ubhaka ","gui.backpack.loadingBackpack":"Iyalaysha","gui.backpack.more":"Ngaphezulu","gui.backpack.emptyBackpack":"Ubhaka akaqulathanga nto","gui.unsupportedBrowser.label":"Isikhangeli asixhaswanga","gui.cards.all-tutorials":"Izifundo","gui.cards.shrink":"Nciphisa","gui.cards.expand":"Yandisa","gui.cards.close":"Vala","gui.cards.more-things-to-try":"Izinto ezingaphezulu onokuzizama!","gui.cards.see-more":"Bona nangakumbi","gui.comingSoon.message1":"Ungakhathazeki, siphezu kwayo {emoji}","gui.comingSoon.message2":"Iyeza kamsinyane...","gui.comingSoon.message3":"Sisebenza kuyo{emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Akukho zixhobo zifunyenweyo","gui.connection.auto-scanning.prescan":"Yiba nezixhobo zakho, ze uqalise ukukhangela.","gui.connection.auto-scanning.pressbutton":"Cofa iqhosha kwisixhobo sakho.","gui.connection.auto-scanning.start-search":"Qalisa Ukhangela","gui.connection.connecting-searchbutton":"Iyahangela...","gui.connection.auto-scanning.try-again":"Zama kwakhona","gui.connection.connected":"Ziqhagamshelene","gui.connection.disconnect":"Qhawula uqhagamshelwano","gui.connection.go-to-editor":"Yiya ku- Editor","gui.connection.connecting-cancelbutton":"Iyaqhagamshelana...","gui.connection.error.errorMessage":"Yhoo, kubonakala ngathi ikhona into engahambanga kakuhle.","gui.connection.error.tryagainbutton":"Zama kwakhona","gui.connection.error.helpbutton":"Nceda","gui.connection.peripheral-name-label":"Igama lesixhobo","gui.connection.connect":"Qhagamshelanisa","gui.connection.scanning.lookingforperipherals":"Ukukhangela izixhobo","gui.connection.scanning.noPeripheralsFound":"Akukho zixhobo zifunyenweyo","gui.connection.scanning.instructions":"Khangela isixhobo sakho kuluhlu olungasentla","gui.connection.search":"Yenza ntsha","gui.connection.unavailable.installscratchlink":"Qinisekisa ukuba ukuba u- Scratch Link ufakelwe kwaye uyasebenza","gui.connection.unavailable.enablebluetooth":"Jonga ukuba iBluetooth ivuliwe","gui.connection.unavailable.tryagainbutton":"Zama kwakhona","gui.connection.unavailable.helpbutton":"Nceda","gui.controls.go":"Hamba","gui.controls.stop":"Yima","gui.crashMessage.label":"Yhoo! Ikhona into engahambanga kakuhle.","gui.crashMessage.errorNumber":"Ingxaki yakho ingeniswe ngala ngale id {errorId}","gui.crashMessage.reload":"Phinda uyilayshe","gui.customProcedures.myblockModalTitle":"Yenza ibhloko kwakhona","gui.customProcedures.addAnInputNumberText":"Faka igalelo","gui.customProcedures.numberTextType":"inani okanye umbhalo","gui.customProcedures.addAnInputBoolean":"Faka igalelo","gui.customProcedures.booleanType":"I-boolean","gui.customProcedures.addALabel":"Faka uphawu","gui.customProcedures.runWithoutScreenRefresh":"Sebenza ngaphandle ngokwenziwa ntsha kwe -screen","gui.customProcedures.cancel":"Rhoxisa","gui.customProcedures.ok":"Kulungile","gui.SpriteInfo.direction":"Isalathiso","gui.directionPicker.rotationStyles.allAround":"Kuzo Zonke","gui.directionPicker.rotationStyles.leftRight":"Ekhohlo/Ekunene","gui.directionPicker.rotationStyles.dontRotate":"Sukujikelezisa","gui.gui.addExtension":"Faka Ulwandiso","gui.gui.codeTab":"Ikhowdi","gui.gui.backdropsTab":"Imiva","gui.gui.costumesTab":"ikhostyum","gui.gui.soundsTab":"Izandi","gui.extensionLibrary.comingSoon":"iyeza kamsinyame","gui.extensionLibrary.requires":"Ifuna","gui.extensionLibrary.collaboration":"Intsebenziswano no","gui.library.filterPlaceholder":"Khangela","gui.library.allTag":"Konke","gui.loader.headline":"Ukulaysha Iprojekhth","gui.loader.creating":"Ukwensza Iprpjekhth","gui.authorInfo.byUser":"ngu {username}","gui.menuBar.seeProjectPage":"Jonga Iphepha leprojekhth","gui.menuBar.LanguageSelector":"Isikhethi lwimi","gui.menuBar.tutorialsLibrary":"Izifundo","gui.menuBar.restoreSprite":"Buyisela i-Sprite","gui.menuBar.restoreSound":"Buyisela Isandi","gui.menuBar.restoreCostume":"Buyisa Ikhostyum","gui.menuBar.restore":"Buyisela","gui.menuBar.saveNow":"Gcina ngoku","gui.menuBar.saveAsCopy":"Gcina njenge kopi","gui.menuBar.remix":"Xuba kwakhona","gui.menuBar.new":"Entsha","gui.menuBar.file":"Ifayl","gui.menuBar.downloadToComputer":"Gcina ekhomputeni yakho","gui.menuBar.edit":"Hlela","gui.menuBar.turboModeOff":"Cima i - Turbo Mode","gui.menuBar.turboModeOn":"Vula i - Turbo Mode","gui.gui.projectTitlePlaceholder":"Igama leprojekhth apha","gui.menuBar.isShared":"Wabelene","gui.menuBar.share":"Yabelana","gui.modal.help":"Nceda","gui.modal.back":"Emva","gui.monitor.listMonitor.empty":"(ayiqulathanga nto)","gui.monitor.listMonitor.listLength":"ubude{length}","gui.monitor.contextMenu.default":"indlela yokufunda yesiqhelo","gui.monitor.contextMenu.large":"ukufunda okukhulu","gui.monitor.contextMenu.slider":"umtyibilikisi","gui.monitor.contextMenu.sliderRange":"guqula umgama womtyibilikisi","gui.monitor.contextMenu.import":"ivela ngaphandle","gui.monitor.contextMenu.export":"ithunyelwa ngaphandle","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Dlala","gui.playButton.stop":"Yima","gui.gui.variableScopeOptionAllSprites":"Yazo zonke ii-Sprite","gui.gui.variableScopeOptionSpriteOnly":"Yeyesi-Sprite sodwa","gui.gui.cloudVariableOption":"I - variable ye -Cloud (igcinwe kwi - server ))","gui.gui.variablePromptAllSpritesMessage":"Le - variable izawufumaneka kuzo zonke ii-sprites.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Rhoxisa","gui.prompt.ok":"Kulungille","gui.playbackStep.stopMsg":"Yima","gui.playbackStep.playMsg":"Dlala","gui.playbackStep.loadingMsg":"Iyalaysha...","gui.playbackStep.saveMsg":"Gcina","gui.playbackStep.reRecordMsg":"Shicilela kwakhona","gui.recordModal.title":"Shicilela isandi","gui.recordingStep.beginRecord":"Qalisa ukushicilela ngokucofa iqhosha elingezantsi","gui.recordingStep.permission":"{arrow} Sidinga imvume yakho ukusebenzisa umboko wakho.","gui.recordingStep.stop":"Pheza ukushicilela","gui.recordingStep.record":"Shicilelea","gui.sliderModal.min":"Elona xabiso lincinci","gui.sliderModal.max":"Elona xabiso liphezulu","gui.sliderModal.title":"Guqula ubungakanani bomtyibilizisi ","gui.sliderPrompt.cancel":"Rhoxisa","gui.sliderPrompt.ok":"Kulungile","gui.soundEditor.sound":"Isandi","gui.soundEditor.play":"Dlala","gui.soundEditor.stop":"Yima","gui.soundEditor.copy":"Khuphela","gui.soundEditor.paste":"Ncamathisela","gui.soundEditor.copyToNew":"Khuphela kwentsha","gui.soundEditor.delete":"Cima","gui.soundEditor.save":"Gcina","gui.soundEditor.undo":"Susa","gui.soundEditor.redo":"Phinda wenze","gui.soundEditor.faster":"Ngokukhawuleza okuthe chatha","gui.soundEditor.slower":"Ngokucotha okuthe kratya","gui.soundEditor.echo":"Isandi esilinganisayo","gui.soundEditor.robot":"i-Roboth","gui.soundEditor.louder":"Khwaza nangaphezulu","gui.soundEditor.softer":"Ngokuthambe nangaphezulu","gui.soundEditor.reverse":"Buya umva","gui.soundEditor.fadeOut":"Mbatsha","gui.soundEditor.fadeIn":"Gqama","gui.soundEditor.mute":"Thula","gui.SpriteInfo.spritePlaceholder":"Igama","gui.SpriteInfo.sprite":"i-Sprite","gui.SpriteInfo.show":"Bonisa","gui.SpriteInfo.size":"Ubungakanani","gui.spriteSelectorItem.contextMenuDuplicate":"Phinda","gui.spriteSelectorItem.contextMenuExport":"thumela ngaphandle","gui.spriteSelectorItem.contextMenuDelete":"cima","gui.spriteSelector.addSpriteFromLibrary":"Khetha i - Sprite","gui.spriteSelector.addSpriteFromPaint":"Peynta","gui.spriteSelector.addSpriteFromSurprise":"Mangalisa","gui.spriteSelector.addSpriteFromFile":"Faka i-Sprite","gui.stageHeader.stageSizeLarge":"Guqulela kwiqonga elikhulu","gui.stageHeader.stageSizeSmall":"Guqulela kwelincinci iqonga","gui.stageHeader.stageSizeFull":"Ngena kwimo yeskrin esikhulu","gui.stageHeader.stageSizeUnFull":"Phuma kwimo yeskrin esikhulu","gui.stageHeader.fullscreenControl":"Ulawulo Leskrini Esigcweleyo","gui.spriteSelector.addBackdropFromLibrary":"Zikhethele Umva","gui.stageSelector.addBackdropFromPaint":"Peynta","gui.stageSelector.addBackdropFromSurprise":"Mangalisa","gui.stageSelector.addBackdropFromFile":"Faka Umva","gui.stageSelector.stage":"iqonga","gui.stageSelector.backdrops":"Imiva","gui.telemetryOptIn.label":"Xela iinkcukacha zophucula u-Scratch","gui.telemetryOptIn.body1":"Iqela le-Scratch lihlala likhangela iindlela zokuqonda ukuba u - scratch usetyenziswa njani ehlabathini jikelelele. Ukuzama ukuxhasa ezi nzame ungavumela u-Scratch ukuba athumele ngokuzenzekelayo zokusetyenziswa zakho kwiqela le - Scratch.","gui.telemetryOptIn.body2":"Iinkcukhankca esiziqokelelayo zibandakanya ukukhethwa kolwimi, ukusetyenziswa kweebhloko, kwaneziganeko ezifana nokonga, kwanokufaka iprojekhth. ASIQOKELELI naziphi na iinkcukhakca ezingomntu. Nceda jonga eyethu i {privacyPolicyLink} ngolwazi oluthe vetshe.","gui.telemetryOptIn.privacyPolicyLink":"Imigaqo - siseko yabucala","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Ubume be - Turbo","gui.webglModal.label":"Isikhangeli sakho asiyixhasi i - WebGL","gui.webglModal.webgllink":"asiyixhasi i - WebGL","gui.costumeLibrary.chooseABackdrop":"Khetha Umva","gui.costumeLibrary.chooseACostume":"Khetha Ikhostyum","gui.costumeTab.addBackdropFromLibrary":"Khetha Umva","gui.costumeTab.addCostumeFromLibrary":"Khetha Ikhostyum","gui.costumeTab.addBlankCostume":"Peynta","gui.costumeTab.addSurpriseCostume":"Mangalisa","gui.costumeTab.addFileBackdrop":"Faka Umva","gui.costumeTab.addFileCostume":"Faka Ikhostyum","gui.extensionLibrary.chooseAnExtension":"Khetha Ulwandiso","gui.extensionLibrary.extensionUrl":"Ngena kulwandiso lwe URL","gui.monitors.importListColumnPrompt":"Loluphi uluhlu ekufuneka lusetyenzisiwe (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Asikwazanga ukuqalisa ukushicilela","gui.soundLibrary.chooseASound":"Khetha Isandi","gui.soundTab.fileUploadSound":"Faka Isandi","gui.soundTab.surpriseSound":"Mangalisa","gui.soundTab.recordSound":"Shicilela","gui.soundTab.addSoundFromLibrary":"Khetha Isandi","gui.spriteLibrary.chooseASprite":"Khetha i-Sprite","gui.tipsLibrary.tutorials":"Khetha isifundo","gui.alerts.createsuccess":"Iprojekhth entsha yenziwe","gui.alerts.createcopysuccess":"Iprojekhth igcinwe wayikopi","gui.alerts.createremixsuccess":"Iprojekhth igcinwe ngokuxutywa ngokutsha","gui.alerts.creating":"Qala entsha...","gui.alerts.creatingCopy":"Ukukhuphela iprojekhth","gui.alerts.creatingRemix":"Xuba iprojekhth okutsha...","gui.alerts.creatingError":"Iprojekhth ayenzekanga. Nceda uzame kwakhona","gui.alerts.savingError":"Iprojekhth ayikeazanga ukugcineka.","gui.alerts.savesuccess":"Iprojekhth igcinekile","gui.alerts.saving":"Sigcina iprojekhth","gui.alerts.cloudInfo":"Nceda qaphela, icloud variable ixhasa amani kuphela, hayi amagama neempawu.{learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Funda nangakumbi","gui.alerts.importing":"sithatha ngaphandle...","gui.defaultProject.variable":"i-variable yam","gui.extension.music.name":"Umculo","gui.extension.music.description":"Dlala izixhobo kunye namagubu","gui.extension.pen.name":"Usiba","gui.extension.pen.description":"Zoba nge-Sprites zakho","gui.extension.videosensing.name":"Ukuva Ividyo","gui.extension.videosensing.description":"Yiva intshukumo ngekhamera","gui.extension.text2speech.name":"Umbhalo ukuya Kwintetho","gui.extension.text2speech.description":"Yenza Iiprojekhth zakho zithethe","gui.extension.translate.name":"Tolika","gui.extension.translate.description":"Tolukela umbhalo kwiilwimi ezininzi","gui.extension.makeymakey.description":"Yenza nantonina ibe sisitshixo","gui.extension.microbit.description":"Qhagamshelanisa iiprojekhth zakho nehlabathi.","gui.extension.microbit.connectingMessage":"Ukudibanisa","gui.extension.ev3.description":"Yakha iirobhothi ezisebenzisanayo nangaphezulu","gui.extension.ev3.connectingMessage":"Iyaqhagamshelana. Qinisekisa ukuba i-pini ekwi-EV3 yakho ilundiselelwe ukuba ibe ngu-1234.","gui.extension.boost.description":"Zisa izidalwa zeerobhothi ebomini","gui.extension.boost.connectingMessage":"Ukuqhagamshelana","gui.extension.wedo2.description":"Yakha ngemooto mezixhobo zokuva","gui.extension.wedo2.connectingMessage":"Ukuqhagamshelana","gui.extension.gdxfor.description":"Yiva, tyhala, tsala, intshukumo, uze ujikelezise","gui.extension.gdxfor.connectingMessage":"Ukuqhagamshelana","gui.libraryTags.all":"Konke","gui.libraryTags.animals":"Izilwanyana","gui.libraryTags.dance":"Danisa","gui.libraryTags.effects":"Ifuthe","gui.libraryTags.fantasy":"Umbono","gui.libraryTags.fashion":"Imfashoni","gui.libraryTags.food":"Ukutya","gui.libraryTags.indoors":"Ngaphakathi","gui.libraryTags.loops":"Isikroba","gui.libraryTags.music":"Umculo","gui.libraryTags.notes":"Imibhalo","gui.libraryTags.outdoors":"Ngaphandle","gui.libraryTags.patterns":"Iipateni","gui.libraryTags.people":"Abantu","gui.libraryTags.percussion":"Isixhobo Somculo Esihlokomayo","gui.libraryTags.space":"Isithuba","gui.libraryTags.sports":"Imidlalo","gui.libraryTags.underwater":"Ngaphantsi Kwamanzi","gui.libraryTags.voice":"Ilizwi","gui.libraryTags.wacky":"Ehlekisayo","gui.libraryTags.animation":"Ukufakela Ubomi","gui.libraryTags.art":"Ubugcisa","gui.libraryTags.games":"Imidlalo","gui.libraryTags.stories":"Amabali","gui.libraryTags.letters":"Oonobumba","gui.opcodeLabels.direction":"Isalathisi","gui.opcodeLabels.xposition":"indawo ka x","gui.opcodeLabels.yposition":"indawo ka y","gui.opcodeLabels.size":"Ubungakanani","gui.opcodeLabels.costumename":"Igama Lekhostyum","gui.opcodeLabels.costumenumber":"Inani lekhostyum","gui.opcodeLabels.backdropname":"igama lomva","gui.opcodeLabels.backdropnumber":"inani lomva","gui.opcodeLabels.volume":"umlinganiselo wesandi","gui.opcodeLabels.tempo":"isantya","gui.opcodeLabels.answer":"impendulo","gui.opcodeLabels.loudness":"ingxolo","gui.opcodeLabels.username":"igama lomsebenzisi","gui.opcodeLabels.year":"unyaka","gui.opcodeLabels.month":"inyanaga","gui.opcodeLabels.date":"usuku","gui.opcodeLabels.dayofweek":"usuku lweveki","gui.opcodeLabels.hour":"iyure","gui.opcodeLabels.minute":"umzuzu","gui.opcodeLabels.second":"umzuzwana","gui.opcodeLabels.timer":"isibali xesha","gui.sharedMessages.backdrop":"Umva {index}","gui.sharedMessages.costume":"ikhostyum{index}","gui.sharedMessages.sprite":"i-Sprite{index}","gui.sharedMessages.pop":"Gqabhuza","gui.sharedMessages.replaceProjectWarning":"Faka okunye endaweni yoku okuqulethwe yiprojekhth yalo mzuzu?","gui.sharedMessages.loadFromComputerTitle":"Thata ekhompyutheni yakho","boost.color.any":"Nawuphina umbala","boost.color.black":"mnyama","boost.color.blue":"luhlaza okwesibhakabhaka","boost.color.green":"luhlaza","boost.color.red":"bomvu","boost.color.white":"mhlophe","boost.color.yellow":"mthubi","boost.getMotorPosition":"imoto [MOTOR_REPORTER_ID] indawo","boost.getTiltAngle":"kekelisaa iengile [TILT_DIRECTION]","boost.motorDirection.backward":"la ndlela","boost.motorDirection.forward":"le ndlela","boost.motorDirection.reverse":"buya umva","boost.motorOff":"jika imoto [MOTOR_ID] icime","boost.motorOn":"jika imoto [MOTOR_ID] idume","boost.motorOnFor":"cima imoto [MOTOR_ID] idume [DURATION] yemizuzwana","boost.motorOnForRotation":"guqula motor [MOTOR_ID] eyenzelwe [ROTATION] ijikeleze","boost.seeingColor":"ubona [COLOR] isitena?","boost.setLightHue":"lungiselela umbala wokukhanya [HUE]","boost.setMotorDirection":"lungiselela motor [MOTOR_ID] isalathiso [MOTOR_DIRECTION]","boost.setMotorPower":"lungiselela motor [MOTOR_ID] isatya sibe [POWER] %","boost.tiltDirection.any":"nayiphi","boost.tiltDirection.down":"phantsi","boost.tiltDirection.left":"ekhohlo","boost.tiltDirection.right":"ekunene","boost.tiltDirection.up":"phezulu","boost.whenColor":"xa [COLOR] isitena siboniwe","boost.whenTilted":"xa ikekelisiwe [TILT_DIRECTION_ANY] ","ev3.beepNote":"ukuqaphle iBEEP [NOTE] kanga [TIME] mizuzwana","ev3.buttonPressed":"iqosha [PORT] lIcofiwe?","ev3.getBrightness":"Ukuqaqamba","ev3.getDistance":"umgama","ev3.getMotorPosition":"imoto [PORT] indawo","ev3.motorSetPower":"imoto [PORT] lungiselela amadla [POWER] %","ev3.motorTurnClockwise":"imoto [PORT] jonga ngapha [TIME] imizuzwana","ev3.motorTurnCounterClockwise":"imoto [PORT] jongisa ngaphaya [TIME] mizuzwana","ev3.whenBrightnessLessThan":"xa ukuqaqamba < [DISTANCE]","ev3.whenButtonPressed":"xa iqosha [PORT] licofiwe","ev3.whenDistanceLessThan":"xa umgama < [DISTANCE]","gdxfor.getAcceleration":"ukwanda kwesantya [DIRECTION]","gdxfor.getForce":"nyanzelisa","gdxfor.getSpin":"jikelezisa isantya [DIRECTION]","gdxfor.getTilt":"kekelisa iengile [TILT]","gdxfor.isFreeFalling":"iyawa?","gdxfor.isTilted":"kekele [TILT]?","gdxfor.pulled":"tsalile","gdxfor.pushed":"tyhalile","gdxfor.shaken":"shukumiswe","gdxfor.startedFalling":"qalise ukuwa","gdxfor.tiltDirectionMenu.any":"nayiphi","gdxfor.tiltDirectionMenu.back":"emva","gdxfor.tiltDirectionMenu.front":"phambili","gdxfor.tiltDirectionMenu.left":"ekhohlo","gdxfor.tiltDirectionMenu.right":"ekunene","gdxfor.turnedFaceDown":"jongise ubuso phantsi","gdxfor.turnedFaceUp":"jongise ubuso phezulu","gdxfor.whenForcePushedOrPulled":"xa isivo sinyanzeliso [PUSH_PULL]","gdxfor.whenGesture":"xa [GESTURE]","gdxfor.whenTilted":"xa ikekelisiwe [TILT]","makeymakey.downArrow":"utolo oluphantsi","makeymakey.downArrowShort":"phantsi","makeymakey.leftArrow":"utolo olusekhohlo","makeymakey.leftArrowShort":"ekhohlo","makeymakey.rightArrow":"utolo olusekunene","makeymakey.rightArrowShort":"ekunene","makeymakey.spaceKey":"isithuba","makeymakey.upArrow":"utolo oluphezulu","makeymakey.upArrowShort":"phezulu","makeymakey.whenKeyPressed":"xa [KEY] licofiwe","makeymakey.whenKeysPressedInOrder":"xa [SEQUENCE] licofwe ngendlela","microbit.buttonsMenu.any":"nayiphi","microbit.clearDisplay":"ukubonisa okucacileyo","microbit.defaultTextToDisplay":"Mholo","microbit.displaySymbol":"Bonisa [MATRIX]","microbit.displayText":"bonisa umbhalo [TEXT]","microbit.gesturesMenu.jumped":"yatsiba","microbit.gesturesMenu.moved":"isuile","microbit.gesturesMenu.shaken":"shukunyisiwe","microbit.isButtonPressed":"[BTN] qhosha licofiwe?","microbit.isTilted":"kekele [DIRECTION]?","microbit.pinStateMenu.off":"cimile","microbit.pinStateMenu.on":"iyasebenza","microbit.tiltAngle":"kekele i-engile [DIRECTION]","microbit.tiltDirectionMenu.any":"nayiphi","microbit.tiltDirectionMenu.back":"emva","microbit.tiltDirectionMenu.front":"phambili","microbit.tiltDirectionMenu.left":"ekhohlo","microbit.tiltDirectionMenu.right":"ekunene","microbit.whenButtonPressed":"xa [BTN] iqhosha licofiwe","microbit.whenGesture":"xa [GESTURE]","microbit.whenPinConnected":"xa i-pini [PIN] Iqhagashelanisiwe","microbit.whenTilted":"xa ikekele [DIRECTION]","music.categoryName":"Umculo","music.changeTempo":"guqula isantya nge [TEMPO]","music.drumBass":"(2) Igubu lebass","music.drumBongo":"(13) i-Bongo","music.drumCabasa":"(15) i-Cabasa","music.drumClaves":"(9) ii-claves","music.drumClosedHiHat":"(6) Evaliweyo i-Hit-Hat","music.drumConga":"(14) igubu","music.drumCowbell":"(11) intsimbi yenkomo","music.drumCrashCymbal":"(4) ngquba i-nkcenkce","music.drumCuica":"(18) i-Cuica","music.drumGuiro":"(16) i-Guiro","music.drumHandClap":"(8) Ukuqhwatywa kwezandla","music.drumOpenHiHat":"(5) Vula i-Hit-Hat","music.drumSideStick":"(3) Ukhuni lwasecaleni ","music.drumSnare":"(1) igubu le-snare","music.drumTambourine":"(7) i-Tambourine","music.drumTriangle":"(12) Unxantathu","music.drumVibraslap":"(17) i-Vibraslap","music.drumWoodBlock":"(10) istena seplanga","music.getTempo":"isantya","music.instrumentBass":"(6) i-Bass","music.instrumentBassoon":"(14) i-Basson","music.instrumentCello":"(8) i-Cello","music.instrumentChoir":"(15) ikwayara","music.instrumentClarinet":"(10) i-Clarinet","music.instrumentElectricGuitar":"(5) ikatara yombane","music.instrumentElectricPiano":"(2) ipiyano yombane","music.instrumentFlute":"(12) ifluthi","music.instrumentGuitar":"(4) Ikatara","music.instrumentMarimba":"(19) Imarimba","music.instrumentMusicBox":"(17) Ibhokisi yomculo","music.instrumentOrgan":"(3) Iogan","music.instrumentPiano":"(1) Ipiyano","music.instrumentPizzicato":"(7) i-Pizzicato","music.instrumentSaxophone":"(11) Ixilongo","music.instrumentSteelDrum":"(18) igubu lentsimbi","music.instrumentSynthLead":"(20) i-Synth ekhokelayo","music.instrumentSynthPad":"(21) incwadana ye-Synth ","music.instrumentTrombone":"(9) i-Trombone","music.instrumentVibraphone":"(16) I-vibraphone","music.instrumentWoodenFlute":"(13) i-flute yeplanga","music.midiPlayDrumForBeats":"dlala igubu [DRUM] kule [BEATS] ","music.midiSetInstrument":"lungiselela isixhobo ku [INSTRUMENT]","music.playDrumForBeats":"dlala igubu [DRUM] kule [BEATS] ","music.playNoteForBeats":"dlala isandi [NOTE] kule [BEATS] ","music.restForBeats":"phumza i [BEATS] ","music.setInstrument":"lungiselela isixhobo kwi [INSTRUMENT]","music.setTempo":"lungiselela isantya [TEMPO]","pen.categoryName":"Usiba","pen.changeColorParam":"guqula usiba [COLOR_PARAM] nge [VALUE]","pen.changeHue":"guqula umbala wesiba nge [HUE]","pen.changeShade":"guqula usiba ngesithunzi [SHADE]","pen.changeSize":"guqula usiba ngobungakanani [SIZE]","pen.clear":"cima konke","pen.colorMenu.brightness":"ukuqaqamba","pen.colorMenu.color":"umbala","pen.colorMenu.saturation":"izele","pen.colorMenu.transparency":"ukubonakalisa kwelinye icala","pen.penDown":"usiba phantsi","pen.penUp":"usiba phezulu","pen.setColor":"lungiselela umbala wosiba ube [COLOR]","pen.setColorParam":"lungiselela usiba [COLOR_PARAM] ku [VALUE]","pen.setHue":"lungiselela umbala wosiba ube [HUE]","pen.setShade":"lungiselela isithinzi sosiba sibe [SHADE]","pen.setSize":"lungiselela ubungakanani bosiba bube [SIZE]","pen.stamp":"ngqisha","text2speech.alto":"i-alto","text2speech.categoryName":"umbhalo ubeyintetho","text2speech.defaultTextToSpeak":"Mholo","text2speech.giant":"isigebenga","text2speech.kitten":"intshontsho lekati","text2speech.setLanguageBlock":"lungisa ulwimi lube [LANGUAGE]","text2speech.setVoiceBlock":"lungiselela ilizwi libe [VOICE]","text2speech.speakAndWaitBlock":"thetha [WORDS]","text2speech.squeak":"tswina","text2speech.tenor":"i-tenor","translate.categoryName":"Tolika","translate.defaultTextToTranslate":"Mholo","translate.translateBlock":"tolika [WORDS] abe [LANGUAGE]","translate.viewerLanguage":"ulwimi","videoSensing.categoryName":"Ukuva ividyo","videoSensing.direction":"isalathiso","videoSensing.motion":"intshukumo","videoSensing.off":"icimile","videoSensing.on":"iyasebenza","videoSensing.onFlipped":"iguqulwe","videoSensing.setVideoTransparency":"lungiselela ukubonisa kwelinye icala kwevidyo [TRANSPARENCY]","videoSensing.sprite":"i-sprite","videoSensing.stage":"iqonga","videoSensing.videoOn":"ividiyo [ATTRIBUTE] malunga ne [SUBJECT]","videoSensing.videoToggle":"guqula ividyo [VIDEO_STATE] ","videoSensing.whenMotionGreaterThan":"xa ukushukuma kwevidyo > [REFERENCE]","wedo2.getDistance":"umgama","wedo2.getTiltAngle":"kwekelisa i-engile [TILT_DIRECTION]","wedo2.isTilted":"ikekele [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"la ndlela","wedo2.motorDirection.forward":"le ndlela","wedo2.motorDirection.reverse":"buya umva","wedo2.motorId.a":"imoto A","wedo2.motorId.all":"zonke iimoto","wedo2.motorId.b":"moto B","wedo2.motorId.default":"imoto","wedo2.motorOff":"jija [MOTOR_ID] icime","wedo2.motorOn":"jija [MOTOR_ID] idume","wedo2.motorOnFor":"jijaa [MOTOR_ID] idume [DURATION] yemizuzwana","wedo2.playNoteFor":"dlala isandi [NOTE] ixesha [DURATION] mizuzwana","wedo2.setLightHue":"lungiselela ukukhanya kombala kube [HUE]","wedo2.setMotorDirection":"lungiselela i [MOTOR_ID] isalathiso sibe [MOTOR_DIRECTION]","wedo2.startMotorPower":"lungiselela i [MOTOR_ID] amandla abe [POWER]","wedo2.tiltDirection.any":"nayiphi","wedo2.tiltDirection.down":"phantsi","wedo2.tiltDirection.left":"ekhohlo","wedo2.tiltDirection.right":"ekunene","wedo2.tiltDirection.up":"phezulu","wedo2.whenDistance":"xa umgama [OP] [REFERENCE]","wedo2.whenTilted":"xa ikekele [TILT_DIRECTION_ANY] ","paint.paintEditor.hue":"Umbala","paint.paintEditor.saturation":"Ukugcwala","paint.paintEditor.brightness":"Ukuqaqamba","paint.paintEditor.costume":"Ikhostyum","paint.paintEditor.group":"Iqela","paint.paintEditor.ungroup":"Phasalakisa","paint.paintEditor.undo":"Qhaqha","paint.paintEditor.redo":"Yenza kwakhona","paint.paintEditor.forward":"Phambili","paint.paintEditor.backward":"Emva","paint.paintEditor.front":"Ngaphambili","paint.paintEditor.back":"emva","paint.paintEditor.more":"Ngaphezulu","paint.modeTools.brushSize":"Ubungakanani","paint.modeTools.eraserSize":"Ubungakanani besicimi","paint.modeTools.copy":"Khuphela","paint.modeTools.paste":"Ncamathisela","paint.modeTools.delete":"Cima","paint.modeTools.curved":"Inamagophe","paint.modeTools.pointed":"Yolathe","paint.modeTools.thickness":"Ubungqindilili","paint.modeTools.flipHorizontal":"Guqula ububanzi","paint.modeTools.flipVertical":"Guqula ubunzulu","paint.modeTools.filled":"Ugcwalise","paint.modeTools.outlined":"Uyicacise nzulu","paint.paintEditor.bitmap":"Qhagamshela ku-Bitmap","paint.paintEditor.vector":"Guqula ibe yi- Vector","paint.paintEditor.fill":"Gcwalisa","paint.paintEditor.stroke":"Cacisa nzulu","paint.brushMode.brush":"Phulula","paint.eraserMode.eraser":"Isixhobo sokucima","paint.fillMode.fill":"Gcwalisa","paint.lineMode.line":"Umgca","paint.ovalMode.oval":"Isangqa","paint.rectMode.rect":"Ixande","paint.reshapeMode.reshape":"Milisa okutsha","paint.roundedRectMode.roundedRect":"Unxantathu owenziwe ronte","paint.selectMode.select":"Khetha","paint.textMode.text":"Umbhalo","paint.colorPicker.swap":"Tshintsha"},"zu":{"gui.alerts.tryAgain":"Zama futhi","gui.alerts.download":"Downloda gcina manje","gui.connection.reconnect":"Hlanganisa kabusha","gui.backpack.costumeLabel":"imvunulo","gui.backpack.soundLabel":"umsindo","gui.backpack.scriptLabel":"umbhalo","gui.backpack.spriteLabel":"umlingisi","gui.backpack.header":"Isikhwama","gui.backpack.errorBackpack":"Kukhona okungalungile ekufakeni ibackpack","gui.backpack.loadingBackpack":"Kusangena...","gui.backpack.more":"Okunye","gui.backpack.emptyBackpack":"iBackpack ayinalutho","gui.unsupportedBrowser.label":"Ibrowza ayisekeliwe","gui.cards.all-tutorials":"AmaTutorials","gui.cards.shrink":"Nciphisa","gui.cards.expand":"Kwandise ","gui.cards.close":"Vala","gui.cards.more-things-to-try":"Okunye okuningi eningakuzama","gui.cards.see-more":"Buka okunye","gui.comingSoon.message1":"Sisebenza kona kuyimanje {emoji}","gui.comingSoon.message2":"Kuyeza Maduzane...","gui.comingSoon.message3":"Sisebenza kona kuyimanje {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Akukho maDevice atholiwe","gui.connection.auto-scanning.prescan":"Idevice ayibeseduza ukuqala ukusesha.","gui.connection.auto-scanning.pressbutton":"Cindezela inkinombo kwi device yakho","gui.connection.auto-scanning.start-search":"Qala useshe","gui.connection.connecting-searchbutton":"Sisasesha...","gui.connection.auto-scanning.try-again":"Phinda uzame","gui.connection.connected":"Sekuxhumekile","gui.connection.disconnect":"Akuxhumekile","gui.connection.go-to-editor":"Hamba uye Kumhleli","gui.connection.connecting-cancelbutton":"Siyayixhuma...","gui.connection.error.errorMessage":"Oops, kubukeka kungathi khona okungalungile.","gui.connection.error.tryagainbutton":"Phinda uzame","gui.connection.error.helpbutton":"Usizo","gui.connection.peripheral-name-label":"Igama leDevice","gui.connection.connect":"Xhuma","gui.connection.scanning.lookingforperipherals":"Sibheka amaDevices","gui.connection.scanning.noPeripheralsFound":"Akukho maDevice atholiwe","gui.connection.scanning.instructions":"Khetha iDevice kulawa akhona","gui.connection.search":"Lungisa kabusha","gui.connection.unavailable.installscratchlink":"Yenza isiqiniseko ukuthi iScratch Link ifakiwe futhi iyasebenza","gui.connection.unavailable.enablebluetooth":"Bheka iBluetooth ukuthi ivumelekile","gui.connection.unavailable.tryagainbutton":"Phinda uzame","gui.connection.unavailable.helpbutton":"Usizo","gui.controls.go":"Hamba","gui.controls.stop":"Ima","gui.crashMessage.label":"Oops! Khona okungalungile","gui.crashMessage.errorNumber":"Iphutha lakho lingeniswe kuID {errorId}","gui.crashMessage.reload":"Asiphinde sigcwalise","gui.customProcedures.myblockModalTitle":"Enza amabhulokisi","gui.customProcedures.addAnInputNumberText":"Faka ngegalelo","gui.customProcedures.numberTextType":"Inamba noma umbhalo","gui.customProcedures.addAnInputBoolean":"Faka ngegalelo","gui.customProcedures.booleanType":"boolean","gui.customProcedures.addALabel":"Faka i-label","gui.customProcedures.runWithoutScreenRefresh":"Baleka ngaphandle kokuvuselela isikrini","gui.customProcedures.cancel":"Cima","gui.customProcedures.ok":"Kulungile","gui.SpriteInfo.direction":"Indlela","gui.directionPicker.rotationStyles.allAround":"Yonke indawo","gui.directionPicker.rotationStyles.leftRight":"isinxele-nangakwesokudla","gui.directionPicker.rotationStyles.dontRotate":"Ungayiphenduli","gui.gui.addExtension":"Faka okokunezelela ","gui.gui.codeTab":"Ikhodi","gui.gui.backdropsTab":"Izindawo","gui.gui.costumesTab":"Izimpahla","gui.gui.soundsTab":"Imisindo","gui.extensionLibrary.comingSoon":"Kuyeza Maduzane...","gui.extensionLibrary.requires":"Okudingekayo","gui.extensionLibrary.collaboration":"Ngokuhambisana ne","gui.library.filterPlaceholder":"Cinga","gui.library.allTag":"Yonke","gui.loader.headline":"Kungena iProject","gui.loader.creating":"Akha iprojekthi","gui.authorInfo.byUser":"yenziwe ngu {username}","gui.menuBar.seeProjectPage":"Bona ikhasi leprojekthi","gui.menuBar.LanguageSelector":"umkhethi wezolimu","gui.menuBar.tutorialsLibrary":"AmaTutorials","gui.menuBar.restoreSprite":"Buyisela Umlingisi","gui.menuBar.restoreSound":"Buyisela Umsindo","gui.menuBar.restoreCostume":"Buyisela Impahla","gui.menuBar.restore":"Buyisela","gui.menuBar.saveNow":"Gcina manje","gui.menuBar.saveAsCopy":"Gcina njenge khophi","gui.menuBar.remix":"Ingxube","gui.menuBar.new":"Entsha","gui.menuBar.file":"Ifayela","gui.menuBar.downloadToComputer":"Gcina kweyakho ikhomputha","gui.menuBar.edit":"Lungisa","gui.menuBar.turboModeOff":"Vala ithebho modi","gui.menuBar.turboModeOn":"Vula ithebho modi","gui.gui.projectTitlePlaceholder":"Isihloko se-Projecti lana","gui.menuBar.isShared":"uPhiwe","gui.menuBar.share":"Yipha","gui.modal.help":"Usizo","gui.modal.back":"Emuva","gui.monitor.listMonitor.empty":"(akukho)","gui.monitor.listMonitor.listLength":"ubude {length}","gui.monitor.contextMenu.default":"okujwayelekile bomphumelo","gui.monitor.contextMenu.large":"ubukhulu bomphumelo","gui.monitor.contextMenu.slider":"shibilika","gui.monitor.contextMenu.sliderRange":"Shitsha iSlider ukuyaphansi/ukuyaphezulu ","gui.monitor.contextMenu.import":"ngenisa","gui.monitor.contextMenu.export":"isithumela","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Dlala","gui.playButton.stop":"Ima","gui.gui.variableScopeOptionAllSprites":"Ngabo bonke omlingisi","gui.gui.variableScopeOptionSpriteOnly":"Ngalomlingsi kuphela","gui.gui.cloudVariableOption":"I-khlawudi variyabhulI (ibekwe kwiseva )","gui.gui.variablePromptAllSpritesMessage":"Lokuguquka kwenzeke kubo bonke","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Cima","gui.prompt.ok":"Kulungile","gui.playbackStep.stopMsg":"Ima","gui.playbackStep.playMsg":"Dlala","gui.playbackStep.loadingMsg":"Kusangena...","gui.playbackStep.saveMsg":"Gcina","gui.playbackStep.reRecordMsg":"Phinda urekhode","gui.recordModal.title":"Rekhoda umsindo","gui.recordingStep.beginRecord":"Qala ukuqoda ngokuchofoza inkinobho","gui.recordingStep.permission":"{arrow} Sidinga imvume yakho ukusebenzisa imicrophone yakho","gui.recordingStep.stop":"Ima ukurekhoda","gui.recordingStep.record":"Qopha","gui.sliderModal.min":"Ivelu engaphansi ","gui.sliderModal.max":"Ivelu engaphezulu ","gui.sliderModal.title":"Shitsha Islider ukuyaphansi/ukuyaphezulu","gui.sliderPrompt.cancel":"Cima","gui.sliderPrompt.ok":"Kulungile","gui.soundEditor.sound":"Umsindo","gui.soundEditor.play":"Dlala","gui.soundEditor.stop":"Ima","gui.soundEditor.copy":"Khopisha","gui.soundEditor.paste":"Namathisela","gui.soundEditor.copyToNew":"Kopisha kuyekokusha ","gui.soundEditor.delete":"Susa","gui.soundEditor.save":"Gcina","gui.soundEditor.undo":"Yenza kabusha","gui.soundEditor.redo":"Ukwenzakabusha","gui.soundEditor.faster":"Shesha","gui.soundEditor.slower":"Kacane","gui.soundEditor.echo":"Ukunanela","gui.soundEditor.robot":"Robhothi","gui.soundEditor.louder":"Kakhulu","gui.soundEditor.softer":"Kuthambile","gui.soundEditor.reverse":"Hlehlisa emumva","gui.soundEditor.fadeOut":"Ukuwehlisa umsindo ","gui.soundEditor.fadeIn":"Ukukhuphula umsindo","gui.soundEditor.mute":"Awuthule umsindo ","gui.SpriteInfo.spritePlaceholder":"Igama","gui.SpriteInfo.sprite":"Umlingisi","gui.SpriteInfo.show":"Khombisa","gui.SpriteInfo.size":"Isisindo","gui.spriteSelectorItem.contextMenuDuplicate":"fanisa","gui.spriteSelectorItem.contextMenuExport":"isithumela","gui.spriteSelectorItem.contextMenuDelete":"khipha","gui.spriteSelector.addSpriteFromLibrary":"Khetha Umlingisi","gui.spriteSelector.addSpriteFromPaint":"Penda","gui.spriteSelector.addSpriteFromSurprise":"Isimanga","gui.spriteSelector.addSpriteFromFile":"Faka Umlingisi","gui.stageHeader.stageSizeLarge":"Shintshela kwinkundla enkulu","gui.stageHeader.stageSizeSmall":"Shintshela kwinkundla encane","gui.stageHeader.stageSizeFull":"Ngena kwindlela ezolula isikhrini sibe sikhula","gui.stageHeader.stageSizeUnFull":"Phma kwindlela elula iskhrini sibe sikhulu","gui.stageHeader.fullscreenControl":"Indlela egcwele yokulawula isinkrini","gui.spriteSelector.addBackdropFromLibrary":"Khetha Indawo","gui.stageSelector.addBackdropFromPaint":"Penda","gui.stageSelector.addBackdropFromSurprise":"Isimanga","gui.stageSelector.addBackdropFromFile":"Faka Indawo","gui.stageSelector.stage":"Isiteji","gui.stageSelector.backdrops":"Izindawo","gui.telemetryOptIn.label":"Sitshele ngemiphumela ukuze uthuthukise ukusebenzisa kwakho uScratch ","gui.telemetryOptIn.body1":"Ithimu Scratch ihlale ifuna izindlela ezingcono zokufundisa ukuthi uScratch usetshenziswa kanjani emhlabeni wonke. Ukubalekelela emfuthweni abanawo, Ungakwazi ukuvumela uScratch ukuthi uthumele imilayezo ngimeninigwane yakho ngokusebenzisa uScratch kuyo iScratch Thimu ","gui.telemetryOptIn.body2":"Ulwazi esiluqoqile liphethe lapho ongakhetha khona uhlobo lolwimi, ukusentshenziswa kwamabhulokisi nokunye okwenzakalayo njengoku beka ukufaka iPhrojethi. ASIVUMI Ukuqoqa ulwazi lwangasese lomuntu. Sicela ubone {privacyPolicyLink} ukuthola eminye imininigwane ","gui.telemetryOptIn.privacyPolicyLink":"Ngasese umgomo","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Sheshisa Indlela","gui.webglModal.label":"iBrowser yakho ayisekeli iWebGL","gui.webglModal.webgllink":"Ayisekeli iWebGL","gui.costumeLibrary.chooseABackdrop":"Khetha Indawo","gui.costumeLibrary.chooseACostume":"Khetha impahla","gui.costumeTab.addBackdropFromLibrary":"Khetha Indawo","gui.costumeTab.addCostumeFromLibrary":"Khetha impahla","gui.costumeTab.addBlankCostume":"Penda","gui.costumeTab.addSurpriseCostume":"Isimanga","gui.costumeTab.addFileBackdrop":"Faka Indawo","gui.costumeTab.addFileCostume":"Faka Impahla","gui.extensionLibrary.chooseAnExtension":"Khetha Isiluli","gui.extensionLibrary.extensionUrl":"Faka iURL yokulula","gui.monitors.importListColumnPrompt":"Iyiphi ikholumu ekufanele isentshenziswe (1-{numberOfColumns})? ","gui.recordingStep.alertMsg":"Ayikwazi ukuqola ukuqopha","gui.soundLibrary.chooseASound":"Khetha Umsindo","gui.soundTab.fileUploadSound":"Faka Umsindo","gui.soundTab.surpriseSound":"Isimanga","gui.soundTab.recordSound":"Qopha","gui.soundTab.addSoundFromLibrary":"Khetha Umsindo","gui.spriteLibrary.chooseASprite":"Khetha Umlingisi","gui.tipsLibrary.tutorials":"Khetha iTutorial","gui.alerts.createsuccess":"Iprojekthi entsha yakhiwe","gui.alerts.createcopysuccess":"Iprojekthi igcinwe njengkhophi","gui.alerts.createremixsuccess":"Iprojekthi igcinwe njengomxubo","gui.alerts.creating":"Akha entsha...","gui.alerts.creatingCopy":"Kopisha iprojekthi...","gui.alerts.creatingRemix":"Ukuxutshwa kweprojekthi","gui.alerts.creatingError":"Akukwazanga ukwakha iprojekthi. Cela uzama futhi!","gui.alerts.savingError":"iprojekthi ayigcinekanga","gui.alerts.savesuccess":"Iyagcina iprojekthi.","gui.alerts.saving":"Gcina umsebenzi...","gui.alerts.cloudInfo":"Cela wazi, uluthi i-cloud variable isekela izinombolo, hhayi izinhlamvu noma amasimbholi {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Funda kabanzi.","gui.alerts.importing":"Ukungenisa...","gui.defaultProject.variable":"i-variable yami","gui.extension.music.name":"uMculo","gui.extension.music.description":"Dlala isikhali kanye nam dilamu","gui.extension.pen.name":"Ipeni","gui.extension.pen.description":"Dweba nabalingisibakho","gui.extension.videosensing.name":"Ukubona ividiyo","gui.extension.videosensing.description":"Izwa ukunyakaza ngeKhamera","gui.extension.text2speech.name":"Bhala kwinkulumo","gui.extension.text2speech.description":"Yenza iProject yakho ikhulume","gui.extension.translate.name":"Humusha","gui.extension.translate.description":"Shintsela umbhalo kwezinye izilimu","gui.extension.makeymakey.description":"Yenza noma yini ibe ukhiye.","gui.extension.microbit.description":"Xhumanisa amaProject akho nomhlaba","gui.extension.microbit.connectingMessage":"Siyayixhuma","gui.extension.ev3.description":"Yakha amaRobhothi akwaziyo ukukhuluma nokunye","gui.extension.ev3.connectingMessage":"Isaxhumanisa. Qinisekisa ukuthi ipin ekuEV3 isethiwe ku1234.","gui.extension.boost.description":"Ukuletha izakhiwo zama ROBOTS empilweni ","gui.extension.boost.connectingMessage":"Kuyaxhumana","gui.extension.wedo2.description":"Yakha ngemishini kanye nezinhloli","gui.extension.wedo2.connectingMessage":"Kuyaxhumana","gui.extension.gdxfor.description":"Sensa ukuphusha, ukudonsa, ukunyakaza noku spina ","gui.extension.gdxfor.connectingMessage":"Kuyaxhumana","gui.libraryTags.all":"Yonke","gui.libraryTags.animals":"Izilwane","gui.libraryTags.dance":"Dansa","gui.libraryTags.effects":"Imithelela","gui.libraryTags.fantasy":"Uphupha/Ubuhle","gui.libraryTags.fashion":"Imfashini","gui.libraryTags.food":"Ukudla","gui.libraryTags.indoors":"Ngaphakathi","gui.libraryTags.loops":"Amaluphu","gui.libraryTags.music":"uMculo","gui.libraryTags.notes":"Amanothi","gui.libraryTags.outdoors":"Ngaphandle","gui.libraryTags.patterns":"Iphethini","gui.libraryTags.people":"Abantu","gui.libraryTags.percussion":"Idilamu Lomculo","gui.libraryTags.space":"Isikhala","gui.libraryTags.sports":"Imidlalo","gui.libraryTags.underwater":"Ngaphansi kwamanzi","gui.libraryTags.voice":"Izwi","gui.libraryTags.wacky":"Engasile ","gui.libraryTags.animation":"Khathuni","gui.libraryTags.art":"Imidwebo","gui.libraryTags.games":"Umdlalo","gui.libraryTags.stories":"Izindaba","gui.libraryTags.letters":"Izinhlamvu","gui.opcodeLabels.direction":"indlela","gui.opcodeLabels.xposition":"x indlela yokuma","gui.opcodeLabels.yposition":"y indlela yokuma","gui.opcodeLabels.size":"isisindo","gui.opcodeLabels.costumename":"igama lempahla","gui.opcodeLabels.costumenumber":"Inamba yempahla","gui.opcodeLabels.backdropname":"igama lendawo","gui.opcodeLabels.backdropnumber":"Inamba indawo","gui.opcodeLabels.volume":"umsindo","gui.opcodeLabels.tempo":"izinsimbi","gui.opcodeLabels.answer":"phendula","gui.opcodeLabels.loudness":"umsindo omkhulu","gui.opcodeLabels.username":"igama elisebenzile","gui.opcodeLabels.year":"unyaka","gui.opcodeLabels.month":"inyanga","gui.opcodeLabels.date":"usuku","gui.opcodeLabels.dayofweek":"usuku lwesonto","gui.opcodeLabels.hour":"ihora","gui.opcodeLabels.minute":"umzuzu","gui.opcodeLabels.second":"umzuzwana","gui.opcodeLabels.timer":"iwashi elicushiwe","gui.sharedMessages.backdrop":"Indawo{index}","gui.sharedMessages.costume":"Impahla{index}","gui.sharedMessages.sprite":"Umlingisi{index}","gui.sharedMessages.pop":"qhumisa","gui.sharedMessages.replaceProjectWarning":"Buyisela imininingwane yeprojekthi yamanje?","gui.sharedMessages.loadFromComputerTitle":"Thathela kweyakho ikhomputha","boost.color.any":"Noma imuphi umbala","boost.color.black":"okumnyama","boost.color.blue":"oluhlaza","boost.color.green":"oluhlaza kwatshani ","boost.color.red":"okubomvu ","boost.color.white":"okumhlophe ","boost.color.yellow":"Okuphuzi ","boost.getMotorPosition":"Moto [MOTOR_REPORTER_ID] indawo ","boost.getTiltAngle":"tshekisa engeli [TILT_DIRECTION]","boost.motorDirection.backward":"leyandlela","boost.motorDirection.forward":"lendlela","boost.motorDirection.reverse":"buyelemumva ","boost.motorOff":"Jikisa imoto [MOTOR_ID] Uyivale ","boost.motorOn":"Jikisa imoto [MOTOR_ID] uyivule ","boost.motorOnFor":"Jikisa imoto [MOTOR_ID] isikhathi [DURATION] imizuzwana ","boost.motorOnForRotation":"Jikisa imoto[MOTOR_ID] Uku [ROTATION] Ukuphendukisa ","boost.seeingColor":"Ukubona [COLOR] Brick? ","boost.setLightHue":"hlela ukhanya kombala ukuyise [HUE]","boost.setMotorDirection":"lungisa imoto [MOTOR_ID] indlela [MOTOR_DIRECTION] ","boost.setMotorPower":"Lungisa imotor [MOTOR_ID] ijubane uliyise [POWER] ","boost.tiltDirection.any":"noma ikuphi","boost.tiltDirection.down":"ezansi","boost.tiltDirection.left":"Kwesobunxele ","boost.tiltDirection.right":"Kwesokudla ","boost.tiltDirection.up":"phezulu","boost.whenColor":"Uma [COLOR] ukubonakala kwe brick ","boost.whenTilted":"Umakutshekisiwe [TILT_DIRECTION_ANY]","ev3.beepNote":"Inothi beep [NOTE] isikhathi [TIME] imizuzwana","ev3.buttonPressed":"inkinobho [PORT] ecindezeliwe?","ev3.getBrightness":"ukukhanya","ev3.getDistance":"ibanga","ev3.getMotorPosition":"indawo yemotho [PORT]","ev3.motorSetPower":"hlela amandla [POWER]% eMotho [PORT]","ev3.motorTurnClockwise":"Imotho [PORT] ayijike ngalendlela isikhathi [TIME]Imizuzwana  ","ev3.motorTurnCounterClockwise":"imotho [PORT] ayijike ngaleyandlela isikhathi [TIME] imizuzwana","ev3.whenBrightnessLessThan":"uma ukukhanya <[DISTANCE]","ev3.whenButtonPressed":"Inkinobho [PORT] mayicindezeliwe","ev3.whenDistanceLessThan":"uma ibanga < [DISTANCE]","gdxfor.getAcceleration":"Ukusheshisa [DIRECTION]","gdxfor.getForce":"Ngamandla ","gdxfor.getSpin":"ukuphenduka ngejubane [DIRECTION]","gdxfor.getTilt":"Tshekisa engeli [TILT]","gdxfor.isFreeFalling":"Kuyawa ? ","gdxfor.isTilted":"Kutshekisiwe [TILT]?","gdxfor.pulled":"Kudonsekile ","gdxfor.pushed":"Kuphushekile ","gdxfor.shaken":"ukunyakaziswa ","gdxfor.startedFalling":"Sekuqalile kuyawa ","gdxfor.tiltDirectionMenu.any":"noma ikuphi","gdxfor.tiltDirectionMenu.back":"emuva","gdxfor.tiltDirectionMenu.front":"phambili","gdxfor.tiltDirectionMenu.left":"inxele","gdxfor.tiltDirectionMenu.right":"sokudla","gdxfor.turnedFaceDown":"Jika ubuso buyephansi ","gdxfor.turnedFaceUp":"Jika ubuso buyephezulu ","gdxfor.whenForcePushedOrPulled":"Uma kuphushwe isensor [PUSH_PULL]","gdxfor.whenGesture":"uma [GESTURE]","gdxfor.whenTilted":"Makutshekisiwe [TILT]","makeymakey.downArrow":"umcibisholo ophansi","makeymakey.downArrowShort":"ngezansi","makeymakey.leftArrow":"umcibisholo kwesobunxele","makeymakey.leftArrowShort":"inxele","makeymakey.rightArrow":"umcibilisholo kwesokudla","makeymakey.rightArrowShort":"sokudla","makeymakey.spaceKey":"isikhala","makeymakey.upArrow":"umcibilisholo phezulu","makeymakey.upArrowShort":"phezulu","makeymakey.whenKeyPressed":"Uma [KEY]kucindezeliwe ","makeymakey.whenKeysPressedInOrder":"Uma [SEQUENCE]kucindezeliwe ngendlela ","microbit.buttonsMenu.any":"noma ikuphi","microbit.clearDisplay":"isiboniso esicacile","microbit.defaultTextToDisplay":"Sawubona!","microbit.displaySymbol":"Isibonisi [MATRIX]","microbit.displayText":"Isibonisi samagama abhaliwe [TEXT]","microbit.gesturesMenu.jumped":"gxumile","microbit.gesturesMenu.moved":"nyakazile","microbit.gesturesMenu.shaken":"ukunyakaziswa ","microbit.isButtonPressed":"[BTN] inkinobho icindezelwe?","microbit.isTilted":"Itshekile [DIRECTION]?","microbit.pinStateMenu.off":"cisha","microbit.pinStateMenu.on":"khanyile","microbit.tiltAngle":"tshekisa engeli [DIRECTION]","microbit.tiltDirectionMenu.any":"noma ikuphi","microbit.tiltDirectionMenu.back":"emuva","microbit.tiltDirectionMenu.front":"phambili","microbit.tiltDirectionMenu.left":"inxele","microbit.tiltDirectionMenu.right":"sokudla","microbit.whenButtonPressed":"Inkinobho [BTN] mayicindezeliwe ","microbit.whenGesture":"uma [GESTURE]","microbit.whenPinConnected":"uma uphini [PIN] uxhunyiwe ","microbit.whenTilted":"uma kutshesiwe [DIRECTION]","music.categoryName":"uMculo","music.changeTempo":"shintsha iThempo nge [TEMPO]","music.drumBass":"(2) Isigubhu esi nebhesi","music.drumBongo":"(13) Bhongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Zinduku","music.drumClosedHiHat":"(6) Ihi-Hat Evaliwe","music.drumConga":"(14) Ikhonga","music.drumCowbell":"(11) Insimbi yenkomo","music.drumCrashCymbal":"(4) Crash Cymbal","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Ihlombe","music.drumOpenHiHat":"(5) Vula Hi-Hat","music.drumSideStick":"(3) Induku eseceleni","music.drumSnare":"(1) Idilamu Snare","music.drumTambourine":"(7) Tambourine","music.drumTriangle":"(12) Nxantathu","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Ikhuni amabhulokisi","music.getTempo":"izinsimbi","music.instrumentBass":"(6) Bhesi","music.instrumentBassoon":"(14) Icilongo","music.instrumentCello":"(8) Cello","music.instrumentChoir":"(15) Ikwaya","music.instrumentClarinet":"(10) Clarinet","music.instrumentElectricGuitar":"(5) Isigingci sagesi","music.instrumentElectricPiano":"(2) Upiyano wagesi","music.instrumentFlute":"(12) Flute","music.instrumentGuitar":"(4) Isiginci","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Ibhokisi lomculo","music.instrumentOrgan":"(3) Organ","music.instrumentPiano":"(1) Upiyano","music.instrumentPizzicato":"(7) Umculo osheshayo","music.instrumentSaxophone":"(11) Saxophone","music.instrumentSteelDrum":"(18) Isigubhu Sensimbi","music.instrumentSynthLead":"(20) Synth Lead","music.instrumentSynthPad":"(21) Synth Pad","music.instrumentTrombone":"(9) Trombone","music.instrumentVibraphone":"(16) Vibraphone","music.instrumentWoodenFlute":"(13) Ikhwela Flute","music.midiPlayDrumForBeats":"dlala idilamu [DRUM] le [BEATS] ibhithi","music.midiSetInstrument":"hlela isikhali sokusebenza [INSTRUMENT]","music.playDrumForBeats":"dlala idilamu [DRUM] le [BEATS] ibhithi","music.playNoteForBeats":"dlala inothi [NOTE] le [BEATS] bhithi","music.restForBeats":"okuseleyo nge [BEATS] bhithi ","music.setInstrument":"hlela isikhali sokusebenza [INSTRUMENT]","music.setTempo":"hlela ithempo ku [TEMPO]","pen.categoryName":"Ipeni","pen.changeColorParam":"shintsha ipeni [COLOR_PARAM] nge [VALUE]","pen.changeHue":"shintsha umbala wepeni nge [HUE]","pen.changeShade":"shintsha ipeni usithe nge [SHADE]","pen.changeSize":"shintsha usayizi wepeni ngo [SIZE]","pen.clear":"kususe konke ","pen.colorMenu.brightness":"ukukhanya","pen.colorMenu.color":"umbala","pen.colorMenu.saturation":"ukukhanya kombala ","pen.colorMenu.transparency":"obala","pen.penDown":"ipeni phansi","pen.penUp":"ipeni phezulu","pen.setColor":"hlela umbala wepeni [COLOR]","pen.setColorParam":"hlela ipeni [COLOR_PARAM] uliyise kwi [VALUE]","pen.setHue":"hlela umbala wepeni uwuyise [HUE]","pen.setShade":"hlela ukusitha ngepeni ukuyise [SHADE]","pen.setSize":"hlela ubukhulu bepeni ubuyise [SIZE]","pen.stamp":"isitembu","text2speech.alto":"I -altho","text2speech.categoryName":"Bhala kwinkulumo","text2speech.defaultTextToSpeak":"sawubona","text2speech.giant":"isiqhwaga ","text2speech.kitten":"Ingane yekati","text2speech.setLanguageBlock":"hlela ulimi uliyise [LANGUAGE]","text2speech.setVoiceBlock":"hlela izwi uliyise [VOICE]","text2speech.speakAndWaitBlock":"khuluma [WORDS]","text2speech.squeak":"Tswininiza","text2speech.tenor":"I-thena","translate.categoryName":"Humusha ","translate.defaultTextToTranslate":"sawubona","translate.translateBlock":"humusha [WORDS] uyise [LANGUAGE]","translate.viewerLanguage":"ulimi","videoSensing.categoryName":"Ukubona ividiyo","videoSensing.direction":"indlela","videoSensing.motion":"ukunyakaza","videoSensing.off":"cisha","videoSensing.on":"ivulekile","videoSensing.onFlipped":"kuphenyiwe ","videoSensing.setVideoTransparency":"hlela ukubonakala kweVidiyo ukuyise [TRANSPARENCY]","videoSensing.sprite":"umlingisi","videoSensing.stage":"isiteji","videoSensing.videoOn":"vidiyo [ATTRIBUTE] ku [SUBJECT]","videoSensing.videoToggle":"phendula ividiyo [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"umakunyakaza ividiyo > [REFERENCE]","wedo2.getDistance":"ibanga","wedo2.getTiltAngle":"tshekisa engeli [TILT_DIRECTION]","wedo2.isTilted":"itshekile [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"leyandlela","wedo2.motorDirection.forward":"lendlela","wedo2.motorDirection.reverse":"buyelemunva","wedo2.motorId.a":"imotho A ","wedo2.motorId.all":"wonke amamotho ","wedo2.motorId.b":"imotho B","wedo2.motorId.default":"imotho","wedo2.motorOff":"yicishe [MOTOR_ID]","wedo2.motorOn":"yivule [MOTOR_ID]","wedo2.motorOnFor":"yivule [MOTOR_ID] isikhathi [DURATION] imizuzwana","wedo2.playNoteFor":"dlala inothi [NOTE] isikathi [DURATION] imizuzwana ","wedo2.setLightHue":"hlela ukhanya kombala ukuyise [HUE]","wedo2.setMotorDirection":"hlela indlela ye [MOTOR_ID] ukuyise [MOTOR_DIRECTION] ","wedo2.startMotorPower":"hlela [MOTOR_ID] amandla uwayise [POWER]","wedo2.tiltDirection.any":"noma ikuphi","wedo2.tiltDirection.down":"ngezansi","wedo2.tiltDirection.left":"inxele","wedo2.tiltDirection.right":"sokudla","wedo2.tiltDirection.up":"phezulu","wedo2.whenDistance":"uma ibanga [OP] [REFERENCE]","wedo2.whenTilted":"Umakutshekisiwe [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Umbala","paint.paintEditor.saturation":"Ukukhanya kombala","paint.paintEditor.brightness":"Ukukhanya","paint.paintEditor.costume":"Impahla","paint.paintEditor.group":"Iqembu","paint.paintEditor.ungroup":"Hlukanisa","paint.paintEditor.undo":"Yenza kabusha","paint.paintEditor.redo":"Ukwenzakabusha","paint.paintEditor.forward":"Phambili","paint.paintEditor.backward":"Emuva","paint.paintEditor.front":"Phambili","paint.paintEditor.back":"Emuva","paint.paintEditor.more":"Okunye","paint.modeTools.brushSize":"Isisindo","paint.modeTools.eraserSize":"Irabha ubude","paint.modeTools.copy":"Khopisha","paint.modeTools.paste":"Namathisela","paint.modeTools.delete":"Susa","paint.modeTools.curved":"Lugobile ","paint.modeTools.pointed":"Iphoyinti","paint.modeTools.thickness":"Ugqinsi","paint.modeTools.flipHorizontal":"Phendula ngokuya emaceleni","paint.modeTools.flipVertical":"Phendula ngokuya phansi naphezulu","paint.modeTools.filled":"Kugcwele","paint.modeTools.outlined":"Kugqamile","paint.paintEditor.bitmap":"Shitsela kuBitmap","paint.paintEditor.vector":"Shitsela kuVector","paint.paintEditor.fill":"Gcwalisa","paint.paintEditor.stroke":"Kugqamise","paint.brushMode.brush":"Ibhrashi","paint.eraserMode.eraser":"Irabha","paint.fillMode.fill":"Gcwalisa","paint.lineMode.line":"Umugqa","paint.ovalMode.oval":"Indingiliza","paint.rectMode.rect":"Irectangle","paint.reshapeMode.reshape":"Ukubuyisele esimeni","paint.roundedRectMode.roundedRect":"Indingiliza yerectangle","paint.selectMode.select":"Khetha","paint.textMode.text":"Umbhalo","paint.colorPicker.swap":"Shitsha "},"is":{"gui.alerts.tryAgain":"Try Again","gui.alerts.download":"Download","gui.connection.reconnect":"Reconnect","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Bakpoki","gui.backpack.errorBackpack":"Villa kom upp þegar reynt var að sækja bakpokann","gui.backpack.loadingBackpack":"Hleð inn ...","gui.backpack.more":"More","gui.backpack.emptyBackpack":"Bakpokinn er tómur","gui.unsupportedBrowser.label":"Styður ekki vafra","gui.cards.all-tutorials":"Kennsluefni","gui.cards.shrink":"Shrink","gui.cards.expand":"Expand","gui.cards.close":"Close","gui.cards.more-things-to-try":"Fleiri hlutir til að prófa!","gui.cards.see-more":"Sjá fleiri","gui.comingSoon.message1":"Ekki hafa áhyggjur, við erum að vinna í þessu {emoji}","gui.comingSoon.message2":"Kemur bráðlega...","gui.comingSoon.message3":"Við erum að vinna í þessu {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"No devices found","gui.connection.auto-scanning.prescan":"Have your device nearby, then begin searching.","gui.connection.auto-scanning.pressbutton":"Press the button on your device.","gui.connection.auto-scanning.start-search":"Start Searching","gui.connection.connecting-searchbutton":"Searching...","gui.connection.auto-scanning.try-again":"Try again","gui.connection.connected":"Tengt","gui.connection.disconnect":"Aftengja","gui.connection.go-to-editor":"Fara til baka í ritil","gui.connection.connecting-cancelbutton":"Að tengjast...","gui.connection.error.errorMessage":"Úps, eitthvað fór úrskeiðis","gui.connection.error.tryagainbutton":"Reyna aftur","gui.connection.error.helpbutton":"Hjálp","gui.connection.peripheral-name-label":"Device name","gui.connection.connect":"Tengjast","gui.connection.scanning.lookingforperipherals":"Looking for devices","gui.connection.scanning.noPeripheralsFound":"No devices found","gui.connection.scanning.instructions":"Veldu tækið þitt í listanum að ofan.","gui.connection.search":"Endurhlaða","gui.connection.unavailable.installscratchlink":"Vertu viss um að hafa sett upp Scratch Link og það sé í gangi","gui.connection.unavailable.enablebluetooth":"Athugaðu hvort að það sé kveikt á Bluetooth","gui.connection.unavailable.tryagainbutton":"Reyna aftur","gui.connection.unavailable.helpbutton":"Hjálp","gui.controls.go":"Keyra","gui.controls.stop":"Stopp","gui.crashMessage.label":"Oops! Something went wrong.","gui.crashMessage.errorNumber":"Your error was logged with id {errorId}","gui.crashMessage.reload":"Reload","gui.customProcedures.myblockModalTitle":"Búa til kubb","gui.customProcedures.addAnInputNumberText":"Bæta við inntaki","gui.customProcedures.numberTextType":"Tala eða texti","gui.customProcedures.addAnInputBoolean":"Bæta við inntaki","gui.customProcedures.booleanType":"boolean","gui.customProcedures.addALabel":"Bæta við merki","gui.customProcedures.runWithoutScreenRefresh":"Keyra án þess að uppfæra skjámynd","gui.customProcedures.cancel":"Hætta við","gui.customProcedures.ok":"Í lagi","gui.SpriteInfo.direction":"Átt","gui.directionPicker.rotationStyles.allAround":"Allt í kring","gui.directionPicker.rotationStyles.leftRight":"Vinstri/hægri","gui.directionPicker.rotationStyles.dontRotate":"Ekki snúast","gui.gui.addExtension":"Bæta við viðbót","gui.gui.codeTab":"Kóði","gui.gui.backdropsTab":"Bakgrunnar","gui.gui.costumesTab":"Búningar","gui.gui.soundsTab":"Hljóð","gui.extensionLibrary.comingSoon":"Kemur bráðlega","gui.extensionLibrary.requires":"Requires","gui.extensionLibrary.collaboration":"Collaboration with","gui.library.filterPlaceholder":"Leita","gui.library.allTag":"All","gui.loader.headline":"Hleð inn verkefni ","gui.loader.creating":"Creating Project","gui.authorInfo.byUser":"by {username}","gui.menuBar.seeProjectPage":"See Project Page","gui.menuBar.LanguageSelector":"velja tungumál","gui.menuBar.tutorialsLibrary":"Kennsluefni","gui.menuBar.restoreSprite":"Restore Sprite","gui.menuBar.restoreSound":"Restore Sound","gui.menuBar.restoreCostume":"Restore Costume","gui.menuBar.restore":"Restore","gui.menuBar.saveNow":"Vista núna","gui.menuBar.saveAsCopy":"Vista sem afrit","gui.menuBar.remix":"Remix","gui.menuBar.new":"Ný","gui.menuBar.file":"Skrá","gui.menuBar.downloadToComputer":"Vista á tölvuna þína","gui.menuBar.edit":"Breyta","gui.menuBar.turboModeOff":"Slökkva á snöggham","gui.menuBar.turboModeOn":"Kveikja á snöggham","gui.gui.projectTitlePlaceholder":"Project title here","gui.menuBar.isShared":"Shared","gui.menuBar.share":"Deila","gui.modal.help":"Hjálp","gui.modal.back":"Til baka","gui.monitor.listMonitor.empty":"(empty)","gui.monitor.listMonitor.listLength":"length {length}","gui.monitor.contextMenu.default":"venjuleg leturgerð","gui.monitor.contextMenu.large":"Stór leturgerð","gui.monitor.contextMenu.slider":"renna","gui.monitor.contextMenu.sliderRange":"change slider range","gui.monitor.contextMenu.import":"import","gui.monitor.contextMenu.export":"export","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Play","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"Fyrir allar teikningar","gui.gui.variableScopeOptionSpriteOnly":"Aðeins fyrir þessa teikningu","gui.gui.cloudVariableOption":"Cloud variable (stored on server)","gui.gui.variablePromptAllSpritesMessage":"Þessi breyta verður aðgengileg öllum teikningunum.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Hætta við","gui.prompt.ok":"Í lagi","gui.playbackStep.stopMsg":"Stopp","gui.playbackStep.playMsg":"Spila","gui.playbackStep.loadingMsg":"Hleð inn ...","gui.playbackStep.saveMsg":"Vista","gui.playbackStep.reRecordMsg":"Taka upp aftur","gui.recordModal.title":"Taka upp hljóð","gui.recordingStep.beginRecord":"Begin recording by clicking the button below","gui.recordingStep.permission":"{arrow}We need your permission to use your microphone","gui.recordingStep.stop":"Stop recording","gui.recordingStep.record":"Record","gui.sliderModal.min":"Minimum value","gui.sliderModal.max":"Maximum value","gui.sliderModal.title":"Change slider range","gui.sliderPrompt.cancel":"Cancel","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Hljóð","gui.soundEditor.play":"Spila","gui.soundEditor.stop":"Stopp","gui.soundEditor.copy":"Copy","gui.soundEditor.paste":"Paste","gui.soundEditor.copyToNew":"Copy to New","gui.soundEditor.delete":"Delete","gui.soundEditor.save":"Vista","gui.soundEditor.undo":"Afgera","gui.soundEditor.redo":"Endurgera","gui.soundEditor.faster":"Hraðar","gui.soundEditor.slower":"Hægar","gui.soundEditor.echo":"Bergmál","gui.soundEditor.robot":"Vélmenni","gui.soundEditor.louder":"Hærra","gui.soundEditor.softer":"Mýkja","gui.soundEditor.reverse":"Snúa við","gui.soundEditor.fadeOut":"Fade out","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Mute","gui.SpriteInfo.spritePlaceholder":"Nafn","gui.SpriteInfo.sprite":"Teikning","gui.SpriteInfo.show":"Sýna","gui.SpriteInfo.size":"Stærð","gui.spriteSelectorItem.contextMenuDuplicate":"tvöfalda","gui.spriteSelectorItem.contextMenuExport":"flytja út","gui.spriteSelectorItem.contextMenuDelete":"eyða","gui.spriteSelector.addSpriteFromLibrary":"Veldu teikningu","gui.spriteSelector.addSpriteFromPaint":"Mála","gui.spriteSelector.addSpriteFromSurprise":"Koma á óvart","gui.spriteSelector.addSpriteFromFile":"Sækja teikningu","gui.stageHeader.stageSizeLarge":"Skipta yfir á stórt svið","gui.stageHeader.stageSizeSmall":"Skipta yfir á lítið svið","gui.stageHeader.stageSizeFull":"Fylla í skjáinn","gui.stageHeader.stageSizeUnFull":"Minnka skjáinn","gui.stageHeader.fullscreenControl":"Fylla í skjá stýring","gui.spriteSelector.addBackdropFromLibrary":"Veldu bakgrunn","gui.stageSelector.addBackdropFromPaint":"Málning","gui.stageSelector.addBackdropFromSurprise":"Koma á óvart","gui.stageSelector.addBackdropFromFile":"Sækja bakgrunn","gui.stageSelector.stage":"Svið","gui.stageSelector.backdrops":"Bakgrunnar","gui.telemetryOptIn.label":"Report statistics to improve Scratch","gui.telemetryOptIn.body1":"The Scratch Team is always looking to better understand how Scratch is used around the world. To help support this effort, you can allow Scratch to automatically send usage information to the Scratch Team.","gui.telemetryOptIn.body2":"The information we collect includes language selection, blocks usage, and some events like saving, loading, and uploading a project. We DO NOT collect any personal information. Please see our {privacyPolicyLink} for more information.","gui.telemetryOptIn.privacyPolicyLink":"Privacy Policy","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Snögghamur","gui.webglModal.label":"Vafrinn þinn styður ekki WebGL","gui.webglModal.webgllink":"styður ekki WebGL","gui.costumeLibrary.chooseABackdrop":"Veldu bakgrunn","gui.costumeLibrary.chooseACostume":"Velja búning","gui.costumeTab.addBackdropFromLibrary":"Veldu bakgrunn","gui.costumeTab.addCostumeFromLibrary":"Velja búning","gui.costumeTab.addBlankCostume":"Málning","gui.costumeTab.addSurpriseCostume":"Koma á óvart","gui.costumeTab.addFileBackdrop":"Sækja bakgrunn","gui.costumeTab.addFileCostume":"Sækja búning","gui.extensionLibrary.chooseAnExtension":"Veldu viðbót","gui.extensionLibrary.extensionUrl":"Sett inn hlekk á viðbótinni","gui.monitors.importListColumnPrompt":"Which column should be used (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Gat ekki hafið upptöku","gui.soundLibrary.chooseASound":"Veldu hljóð","gui.soundTab.fileUploadSound":"Sækja hljóð","gui.soundTab.surpriseSound":"Koma á óvart","gui.soundTab.recordSound":"Taka upp","gui.soundTab.addSoundFromLibrary":"Veldu hljóð","gui.spriteLibrary.chooseASprite":"Veldu teikningu","gui.tipsLibrary.tutorials":"Veldu kennsuefni","gui.alerts.createsuccess":"New project created.","gui.alerts.createcopysuccess":"Project saved as a copy.","gui.alerts.createremixsuccess":"Project saved as a remix.","gui.alerts.creating":"Creating new…","gui.alerts.creatingCopy":"Copying project…","gui.alerts.creatingRemix":"Remixing project…","gui.alerts.creatingError":"Could not create the project. Please try again!","gui.alerts.savingError":"Project could not save.","gui.alerts.savesuccess":"Project saved.","gui.alerts.saving":"Saving project…","gui.alerts.cloudInfo":"Please note, cloud variables only support numbers, not letters or symbols. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Learn more.","gui.alerts.importing":"Importing…","gui.defaultProject.variable":"my variable","gui.extension.music.name":"Tónlist","gui.extension.music.description":"Spila hljóðfæri og trommur. ","gui.extension.pen.name":"Penni","gui.extension.pen.description":"Teiknaðu með teikningunum þínum. ","gui.extension.videosensing.name":"Vídeó mæling","gui.extension.videosensing.description":"Skynja hreyfingu með myndavélinni","gui.extension.text2speech.name":"Text to Speech","gui.extension.text2speech.description":"Make your projects talk.","gui.extension.translate.name":"Translate","gui.extension.translate.description":"Translate text into many languages.","gui.extension.makeymakey.description":"Make anything into a key.","gui.extension.microbit.description":"Tengdu verkefnin þín við heiminn. ","gui.extension.microbit.connectingMessage":"Tengjast","gui.extension.ev3.description":"Búðu til gagnvirk vélmenni og fleira. ","gui.extension.ev3.connectingMessage":"Tengist. Passaðu að pinnið í EV3 sé 1234.","gui.extension.boost.description":"Bring robotic creations to life.","gui.extension.boost.connectingMessage":"Connecting","gui.extension.wedo2.description":"Byggt með mótorum og skynjurum.","gui.extension.wedo2.connectingMessage":"Connecting","gui.extension.gdxfor.description":"Sense push, pull, motion, and spin.","gui.extension.gdxfor.connectingMessage":"Connecting","gui.libraryTags.all":"All","gui.libraryTags.animals":"Animals","gui.libraryTags.dance":"Dance","gui.libraryTags.effects":"Effects","gui.libraryTags.fantasy":"Fantasy","gui.libraryTags.fashion":"Fashion","gui.libraryTags.food":"Food","gui.libraryTags.indoors":"Indoors","gui.libraryTags.loops":"Loops","gui.libraryTags.music":"Music","gui.libraryTags.notes":"Notes","gui.libraryTags.outdoors":"Outdoors","gui.libraryTags.patterns":"Patterns","gui.libraryTags.people":"People","gui.libraryTags.percussion":"Percussion","gui.libraryTags.space":"Space","gui.libraryTags.sports":"Sports","gui.libraryTags.underwater":"Underwater","gui.libraryTags.voice":"Voice","gui.libraryTags.wacky":"Wacky","gui.libraryTags.animation":"Animation","gui.libraryTags.art":"Art","gui.libraryTags.games":"Games","gui.libraryTags.stories":"Stories","gui.libraryTags.letters":"Letters","gui.opcodeLabels.direction":"direction","gui.opcodeLabels.xposition":"x position","gui.opcodeLabels.yposition":"y position","gui.opcodeLabels.size":"size","gui.opcodeLabels.costumename":"costume name","gui.opcodeLabels.costumenumber":"costume number","gui.opcodeLabels.backdropname":"backdrop name","gui.opcodeLabels.backdropnumber":"backdrop number","gui.opcodeLabels.volume":"volume","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"answer","gui.opcodeLabels.loudness":"loudness","gui.opcodeLabels.username":"username","gui.opcodeLabels.year":"year","gui.opcodeLabels.month":"month","gui.opcodeLabels.date":"date","gui.opcodeLabels.dayofweek":"day of week","gui.opcodeLabels.hour":"hour","gui.opcodeLabels.minute":"minute","gui.opcodeLabels.second":"second","gui.opcodeLabels.timer":"timer","gui.sharedMessages.backdrop":"backdrop{index}","gui.sharedMessages.costume":"costume{index}","gui.sharedMessages.sprite":"Sprite{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Replace contents of the current project?","gui.sharedMessages.loadFromComputerTitle":"Load from your computer","boost.color.any":"any color","boost.color.black":"black","boost.color.blue":"blue","boost.color.green":"green","boost.color.red":"red","boost.color.white":"white","boost.color.yellow":"yellow","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] position","boost.getTiltAngle":"tilt angle [TILT_DIRECTION]","boost.motorDirection.backward":"that way","boost.motorDirection.forward":"this way","boost.motorDirection.reverse":"reverse","boost.motorOff":"turn motor [MOTOR_ID] off","boost.motorOn":"turn motor [MOTOR_ID] on","boost.motorOnFor":"turn motor [MOTOR_ID] for [DURATION] seconds","boost.motorOnForRotation":"turn motor [MOTOR_ID] for [ROTATION] rotations","boost.seeingColor":"seeing [COLOR] brick?","boost.setLightHue":"set light color to [HUE]","boost.setMotorDirection":"set motor [MOTOR_ID] direction [MOTOR_DIRECTION]","boost.setMotorPower":"set motor [MOTOR_ID] speed to [POWER] %","boost.tiltDirection.any":"any","boost.tiltDirection.down":"down","boost.tiltDirection.left":"left","boost.tiltDirection.right":"right","boost.tiltDirection.up":"up","boost.whenColor":"when [COLOR] brick seen","boost.whenTilted":"when tilted [TILT_DIRECTION_ANY]","ev3.beepNote":"beep note [NOTE] for [TIME] secs","ev3.buttonPressed":"button [PORT] pressed?","ev3.getBrightness":"brightness","ev3.getDistance":"distance","ev3.getMotorPosition":"motor [PORT] position","ev3.motorSetPower":"motor [PORT] set power [POWER] %","ev3.motorTurnClockwise":"motor [PORT] turn this way for [TIME] seconds","ev3.motorTurnCounterClockwise":"motor [PORT] turn that way for [TIME] seconds","ev3.whenBrightnessLessThan":"when brightness < [DISTANCE]","ev3.whenButtonPressed":"when button [PORT] pressed","ev3.whenDistanceLessThan":"when distance < [DISTANCE]","gdxfor.getAcceleration":"acceleration [DIRECTION]","gdxfor.getForce":"force","gdxfor.getSpin":"spin speed [DIRECTION]","gdxfor.getTilt":"tilt angle [TILT]","gdxfor.isFreeFalling":"falling?","gdxfor.isTilted":"tilted [TILT]?","gdxfor.pulled":"pulled","gdxfor.pushed":"pushed","gdxfor.shaken":"shaken","gdxfor.startedFalling":"started falling","gdxfor.tiltDirectionMenu.any":"any","gdxfor.tiltDirectionMenu.back":"back","gdxfor.tiltDirectionMenu.front":"front","gdxfor.tiltDirectionMenu.left":"left","gdxfor.tiltDirectionMenu.right":"right","gdxfor.turnedFaceDown":"turned face down","gdxfor.turnedFaceUp":"turned face up","gdxfor.whenForcePushedOrPulled":"when force sensor [PUSH_PULL]","gdxfor.whenGesture":"when [GESTURE]","gdxfor.whenTilted":"when tilted [TILT]","makeymakey.downArrow":"down arrow","makeymakey.downArrowShort":"down","makeymakey.leftArrow":"left arrow","makeymakey.leftArrowShort":"left","makeymakey.rightArrow":"right arrow","makeymakey.rightArrowShort":"right","makeymakey.spaceKey":"space","makeymakey.upArrow":"up arrow","makeymakey.upArrowShort":"up","makeymakey.whenKeyPressed":"when [KEY] key pressed","makeymakey.whenKeysPressedInOrder":"when [SEQUENCE] pressed in order","microbit.buttonsMenu.any":"any","microbit.clearDisplay":"clear display","microbit.defaultTextToDisplay":"Hello!","microbit.displaySymbol":"display [MATRIX]","microbit.displayText":"display text [TEXT]","microbit.gesturesMenu.jumped":"jumped","microbit.gesturesMenu.moved":"moved","microbit.gesturesMenu.shaken":"shaken","microbit.isButtonPressed":"[BTN] button pressed?","microbit.isTilted":"tilted [DIRECTION]?","microbit.pinStateMenu.off":"off","microbit.pinStateMenu.on":"on","microbit.tiltAngle":"tilt angle [DIRECTION]","microbit.tiltDirectionMenu.any":"any","microbit.tiltDirectionMenu.back":"back","microbit.tiltDirectionMenu.front":"front","microbit.tiltDirectionMenu.left":"left","microbit.tiltDirectionMenu.right":"right","microbit.whenButtonPressed":"when [BTN] button pressed","microbit.whenGesture":"when [GESTURE]","microbit.whenPinConnected":"when pin [PIN] connected","microbit.whenTilted":"when tilted [DIRECTION]","music.categoryName":"Tónlist","music.changeTempo":"breyta hraða um [TEMPO]","music.drumBass":"(2) Bassa tromma","music.drumBongo":"(13) Bongo tromma","music.drumCabasa":"(15) Hrista","music.drumClaves":"(9) Taktstangir","music.drumClosedHiHat":"(6) Lokaður Hi-Hat","music.drumConga":"(14) Konga tromma","music.drumCowbell":"(11) Kúabjalla","music.drumCrashCymbal":"(4) Glamrandi simball","music.drumCuica":"(18) Cuica tromma","music.drumGuiro":"(16) Guíró","music.drumHandClap":"(8) Klapp","music.drumOpenHiHat":"(5) Opinn Hi-Hat","music.drumSideStick":"(3) Hliðar prik","music.drumSnare":"(1) Sneriltromma","music.drumTambourine":"(7) Tambúrína","music.drumTriangle":"(12) Þríhyrningur","music.drumVibraslap":"(17) Víbrastrengur","music.drumWoodBlock":"(10) Viðarblokk","music.getTempo":"taktur","music.instrumentBass":"(6) Bassi","music.instrumentBassoon":"(14) Fagott","music.instrumentCello":"(8) Selló","music.instrumentChoir":"(15) Kór","music.instrumentClarinet":"(10) Klarinet","music.instrumentElectricGuitar":"(5) Rafmagnsgítar","music.instrumentElectricPiano":"(2) Rafmagnspíanó","music.instrumentFlute":"(12) Flauta","music.instrumentGuitar":"(4) Gítar","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Spiladós","music.instrumentOrgan":"(3) Orgel","music.instrumentPiano":"(1) Píanó","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxófónn","music.instrumentSteelDrum":"(18) Stál tromma","music.instrumentSynthLead":"(20) Aðal hljóðgervill","music.instrumentSynthPad":"(21) Hljóðgervill ","music.instrumentTrombone":"(9) Básúna","music.instrumentVibraphone":"(16) Víbrafónn","music.instrumentWoodenFlute":"(13) Viðar flauta","music.midiPlayDrumForBeats":"play drum [DRUM] for [BEATS] beats","music.midiSetInstrument":"set instrument to [INSTRUMENT]","music.playDrumForBeats":"spila trommu [DRUM] í [BEATS] slög","music.playNoteForBeats":"spila nótu [NOTE] í [BEATS] slög","music.restForBeats":"bíða í [BEATS] slög","music.setInstrument":"setja hljóðfæri sem [INSTRUMENT]","music.setTempo":"setja hraða sem [TEMPO]","pen.categoryName":"Penni","pen.changeColorParam":"breyta lit penna [COLOR_PARAM] í [VALUE]","pen.changeHue":"breyta lit penna um [HUE]","pen.changeShade":"breyta litbrigði penna um [SHADE]","pen.changeSize":"breyta stærð penna um [SIZE]","pen.clear":"hreinsa allt","pen.colorMenu.brightness":"birtustig","pen.colorMenu.color":"litur","pen.colorMenu.saturation":"mettun","pen.colorMenu.transparency":"gegnsæi","pen.penDown":"penni niður","pen.penUp":"penni upp","pen.setColor":"setja lit penna sem [COLOR]","pen.setColorParam":"setja lit penna [COLOR_PARAM]í [VALUE]","pen.setHue":"setja lit penna sem [HUE]","pen.setShade":"setja skugga penna í [SHADE]","pen.setSize":"setja stærð penna í [SIZE]","pen.stamp":"stimpla","text2speech.alto":"alto","text2speech.categoryName":"Text to Speech","text2speech.defaultTextToSpeak":"hello","text2speech.giant":"giant","text2speech.kitten":"kettlingur","text2speech.setLanguageBlock":"set language to [LANGUAGE]","text2speech.setVoiceBlock":"setja rödd sem [VOICE]","text2speech.speakAndWaitBlock":"tala [WORDS]","text2speech.squeak":"tíst","text2speech.tenor":"tenor","translate.categoryName":"Translate","translate.defaultTextToTranslate":"halló","translate.translateBlock":"þýða [WORDS] á [LANGUAGE]","translate.viewerLanguage":"tungumál","videoSensing.categoryName":"Vídeó mæling","videoSensing.direction":"átt","videoSensing.motion":"hreyfing","videoSensing.off":"af","videoSensing.on":"á","videoSensing.onFlipped":"á flippi","videoSensing.setVideoTransparency":"setja gegnsæi hreyfimyndar í [TRANSPARENCY]","videoSensing.sprite":"teikning","videoSensing.stage":"svið","videoSensing.videoOn":"vídeó [ATTRIBUTE] á [SUBJECT]","videoSensing.videoToggle":"breyta vídeó [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"þegar hreyfing í vídeó > [REFERENCE]","wedo2.getDistance":"distance","wedo2.getTiltAngle":"tilt angle [TILT_DIRECTION]","wedo2.isTilted":"tilted [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"that way","wedo2.motorDirection.forward":"this way","wedo2.motorDirection.reverse":"reverse","wedo2.motorId.a":"motor A","wedo2.motorId.all":"all motors","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"turn [MOTOR_ID] off","wedo2.motorOn":"turn [MOTOR_ID] on","wedo2.motorOnFor":"turn [MOTOR_ID] on for [DURATION] seconds","wedo2.playNoteFor":"play note [NOTE] for [DURATION] seconds","wedo2.setLightHue":"set light color to [HUE]","wedo2.setMotorDirection":"set [MOTOR_ID] direction to [MOTOR_DIRECTION]","wedo2.startMotorPower":"set [MOTOR_ID] power to [POWER]","wedo2.tiltDirection.any":"any","wedo2.tiltDirection.down":"down","wedo2.tiltDirection.left":"left","wedo2.tiltDirection.right":"right","wedo2.tiltDirection.up":"up","wedo2.whenDistance":"when distance [OP] [REFERENCE]","wedo2.whenTilted":"when tilted [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Litur","paint.paintEditor.saturation":"mettun","paint.paintEditor.brightness":"Birtustig","paint.paintEditor.costume":"Búningur","paint.paintEditor.group":"Hópur","paint.paintEditor.ungroup":"Leysa upp hóp","paint.paintEditor.undo":"Afgera","paint.paintEditor.redo":"Endurgera","paint.paintEditor.forward":"Áfram","paint.paintEditor.backward":"Aftur á bak","paint.paintEditor.front":"Fremst","paint.paintEditor.back":"Til baka","paint.paintEditor.more":"Meira","paint.modeTools.brushSize":"Stærð","paint.modeTools.eraserSize":"Stærð strokleðurs","paint.modeTools.copy":"Afrita","paint.modeTools.paste":"Líma","paint.modeTools.delete":"Eyða","paint.modeTools.curved":"Sveigja","paint.modeTools.pointed":"Oddmjótt","paint.modeTools.thickness":"Þykkt","paint.modeTools.flipHorizontal":"Flippa lárétt","paint.modeTools.flipVertical":"Flippa lóðrétt","paint.modeTools.filled":"Fylla","paint.modeTools.outlined":"Útlína","paint.paintEditor.bitmap":"Umbreyta í Bitmap","paint.paintEditor.vector":"Umbreyta í vektor","paint.paintEditor.fill":"Fylla","paint.paintEditor.stroke":"Útlína","paint.brushMode.brush":"Bursti","paint.eraserMode.eraser":"Strokleður","paint.fillMode.fill":"Fylla","paint.lineMode.line":"Lína","paint.ovalMode.oval":"Hringur","paint.rectMode.rect":"Ferhyrningur","paint.reshapeMode.reshape":"Ummynda","paint.roundedRectMode.roundedRect":"Rúnaður ferhyrningur","paint.selectMode.select":"Velja","paint.textMode.text":"Texti","paint.colorPicker.swap":"Skipta"},"it":{"gui.alerts.tryAgain":"Prova di Nuovo","gui.alerts.download":"Salva sul tuo computer","gui.connection.reconnect":"Ricollega","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"suono","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Valigetta","gui.backpack.errorBackpack":"Errore nel caricamento dello zaino","gui.backpack.loadingBackpack":"Caricamento in corso...","gui.backpack.more":"Altro","gui.backpack.emptyBackpack":"Lo zaino è vuoto","gui.unsupportedBrowser.label":"Browser non supportato","gui.cards.all-tutorials":"Tutorial","gui.cards.shrink":"Riduci","gui.cards.expand":"Espandi","gui.cards.close":"Chiudi","gui.cards.more-things-to-try":"Altre cose da provare!","gui.cards.see-more":"Ulteriori informazioni","gui.comingSoon.message1":"Non preoccuparti, ci stiamo lavorando {emoji}","gui.comingSoon.message2":"Disponibile a breve...","gui.comingSoon.message3":"Ci stiamo lavorando {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Nessun dispositivo trovato","gui.connection.auto-scanning.prescan":"Tieni il tuo dispositivo a portata, quindi inizia la ricerca.","gui.connection.auto-scanning.pressbutton":"Premi il pulsante sul tuo dispositivo.","gui.connection.auto-scanning.start-search":"Inizio Ricerca","gui.connection.connecting-searchbutton":"Ricerca in corso...","gui.connection.auto-scanning.try-again":"Prova ancora","gui.connection.connected":"Connesso","gui.connection.disconnect":"Scollega","gui.connection.go-to-editor":"Torna all\'Editor","gui.connection.connecting-cancelbutton":"Collegamento in corso...","gui.connection.error.errorMessage":"Ops, sembra che qualcosa non abbia funzionato.","gui.connection.error.tryagainbutton":"Prova ancora","gui.connection.error.helpbutton":"Aiuto","gui.connection.peripheral-name-label":"Nome del dispositivo","gui.connection.connect":"Collega","gui.connection.scanning.lookingforperipherals":"Ricerca dispositivi in corso","gui.connection.scanning.noPeripheralsFound":"Nessun dispositivo trovato","gui.connection.scanning.instructions":"Seleziona il dispositivo nella lista.","gui.connection.search":"Aggiorna","gui.connection.unavailable.installscratchlink":"Assicurati che Scratch Link sia installato e correttamente funzionante","gui.connection.unavailable.enablebluetooth":"Accertati che il Bluetooth sia attivato","gui.connection.unavailable.tryagainbutton":"Prova ancora","gui.connection.unavailable.helpbutton":"Aiuto","gui.controls.go":"Vai","gui.controls.stop":"Ferma tutto","gui.crashMessage.label":"Ops! Qualcosa non ha funzionato.","gui.crashMessage.errorNumber":"L\'errore è stato loggato con id {errorId}","gui.crashMessage.reload":"Ricarica","gui.customProcedures.myblockModalTitle":"Crea un Blocco","gui.customProcedures.addAnInputNumberText":"Aggiungi un argomento","gui.customProcedures.numberTextType":"numero o testo","gui.customProcedures.addAnInputBoolean":"Aggiungi un argomento","gui.customProcedures.booleanType":"booleano","gui.customProcedures.addALabel":"Aggiungi una scritta","gui.customProcedures.runWithoutScreenRefresh":"Esegui senza aggiornare lo schermo","gui.customProcedures.cancel":"Annulla","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Direzione","gui.directionPicker.rotationStyles.allAround":"Può Ruotare","gui.directionPicker.rotationStyles.leftRight":"Sinistra-Destra","gui.directionPicker.rotationStyles.dontRotate":"Non ruotare","gui.gui.addExtension":"Aggiungi un\'Estensione","gui.gui.codeTab":"Codice","gui.gui.backdropsTab":"Sfondi","gui.gui.costumesTab":"Costumi","gui.gui.soundsTab":"Suoni","gui.extensionLibrary.comingSoon":"Disponibile a Breve","gui.extensionLibrary.requires":"Richiede","gui.extensionLibrary.collaboration":"In collaborazione con","gui.library.filterPlaceholder":"Cerca","gui.library.allTag":"Tutti","gui.loader.headline":"Caricamento del Progetto in corso","gui.loader.creating":"Creazione del progetto in corso...","gui.authorInfo.byUser":"di {username}","gui.menuBar.seeProjectPage":"Vai alla Pagina del Progetto","gui.menuBar.LanguageSelector":"selezione lingua","gui.menuBar.tutorialsLibrary":"Tutorial","gui.menuBar.restoreSprite":"Ripristina lo Sprite","gui.menuBar.restoreSound":"Annulla rimozione Suono","gui.menuBar.restoreCostume":"Annulla rimozione Costume","gui.menuBar.restore":"Ripristina","gui.menuBar.saveNow":"Salva ora","gui.menuBar.saveAsCopy":"Salva una copia","gui.menuBar.remix":"Remix","gui.menuBar.new":"Nuovo","gui.menuBar.file":"File","gui.menuBar.downloadToComputer":"Salva sul tuo computer","gui.menuBar.edit":"Modifica","gui.menuBar.turboModeOff":"Disattiva Modalità Turbo","gui.menuBar.turboModeOn":"Attiva Modalità Turbo","gui.gui.projectTitlePlaceholder":"Inserisci il titolo del progetto","gui.menuBar.isShared":"Condiviso","gui.menuBar.share":"Condividi","gui.modal.help":"Aiuto","gui.modal.back":"Indietro","gui.monitor.listMonitor.empty":"(vuota)","gui.monitor.listMonitor.listLength":"lunghezza {length}","gui.monitor.contextMenu.default":"normale","gui.monitor.contextMenu.large":"grande","gui.monitor.contextMenu.slider":"cursore","gui.monitor.contextMenu.sliderRange":"scegli min e max del cursore","gui.monitor.contextMenu.import":"importa","gui.monitor.contextMenu.export":"esporta","gui.monitor.contextMenu.hide":"nascondi","gui.playButton.play":"Riproduci","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"Per tutti gli sprite","gui.gui.variableScopeOptionSpriteOnly":"Solo per questo sprite","gui.gui.cloudVariableOption":"Variabile cloud (salvata sul server)","gui.gui.variablePromptAllSpritesMessage":"Questa variabile potrà essere letta e modificata da tutti gli sprite.","gui.gui.listPromptAllSpritesMessage":"Questa lista potrà essere letta e modificata da tutti gli sprite.","gui.prompt.cancel":"Annulla","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Stop","gui.playbackStep.playMsg":"Riproduci","gui.playbackStep.loadingMsg":"Caricamento in corso...","gui.playbackStep.saveMsg":"Salva","gui.playbackStep.reRecordMsg":"Ripeti la registrazione","gui.recordModal.title":"Registra Suono","gui.recordingStep.beginRecord":"Inizia a registrare cliccando il pulsante qui sotto","gui.recordingStep.permission":"{arrow}Ci occorre il tuo permesso per poter usare il microfono","gui.recordingStep.stop":"Arresta la registrazione","gui.recordingStep.record":"Registra","gui.sliderModal.min":"Valore minimo","gui.sliderModal.max":"Valore massimo","gui.sliderModal.title":"Intervallo del cursore","gui.sliderPrompt.cancel":"Annulla","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Suono","gui.soundEditor.play":"Riproduci","gui.soundEditor.stop":"Arresta","gui.soundEditor.copy":"Copia","gui.soundEditor.paste":"Incolla","gui.soundEditor.copyToNew":"Copialo come Nuovo Suono","gui.soundEditor.delete":"Cancella","gui.soundEditor.save":"Salva","gui.soundEditor.undo":"Annulla","gui.soundEditor.redo":"Ripristina","gui.soundEditor.faster":"Accelera","gui.soundEditor.slower":"Rallenta","gui.soundEditor.echo":"Eco","gui.soundEditor.robot":"Effetto Robot","gui.soundEditor.louder":"Aumenta volume","gui.soundEditor.softer":"Diminuisci volume","gui.soundEditor.reverse":"Inverti","gui.soundEditor.fadeOut":"Fade out","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Muto","gui.SpriteInfo.spritePlaceholder":"Nome","gui.SpriteInfo.sprite":"Sprite","gui.SpriteInfo.show":"Mostra","gui.SpriteInfo.size":"Dimensione","gui.spriteSelectorItem.contextMenuDuplicate":"duplica","gui.spriteSelectorItem.contextMenuExport":"esporta","gui.spriteSelectorItem.contextMenuDelete":"cancella","gui.spriteSelector.addSpriteFromLibrary":"Scegli uno Sprite","gui.spriteSelector.addSpriteFromPaint":"Disegna un nuovo sprite","gui.spriteSelector.addSpriteFromSurprise":"Aggiungi uno sprite a Sorpresa","gui.spriteSelector.addSpriteFromFile":"Importa Sprite","gui.stageHeader.stageSizeLarge":"Passa alla visualizzazione con Stage grande","gui.stageHeader.stageSizeSmall":"Passa alla visualizzazione con Stage ridotto","gui.stageHeader.stageSizeFull":"Passa alla modalità presentazione","gui.stageHeader.stageSizeUnFull":"Esci dalla modalità presentazione","gui.stageHeader.fullscreenControl":"Pulsante modalità presentazione","gui.spriteSelector.addBackdropFromLibrary":"Scegli uno Sfondo","gui.stageSelector.addBackdropFromPaint":"Disegna un nuovo sfondo","gui.stageSelector.addBackdropFromSurprise":"Aggiungi uno sfondo a Sorpresa","gui.stageSelector.addBackdropFromFile":"Importa Sfondo","gui.stageSelector.stage":"Stage","gui.stageSelector.backdrops":"Sfondi","gui.telemetryOptIn.label":"Trasmetti statistiche per migliorare Scratch","gui.telemetryOptIn.body1":"Il Team di Scratch cerca continuamente di capire in che modo Scratch viene usato in tutto il mondo. Per supportare questo sforzo puoi permettere a Scratch di inviare automaticamente al Team di Scratch informazioni sul modo in cui lo usi.","gui.telemetryOptIn.body2":"Le informazioni che raccogliamo includono il linguaggio selezionato, l\'uso dei diversi blocchi e alcuni eventi come salvare, aprire e caricare un progetto. NON raccogliamo informazioni personali. Ti invitiamo a visitare la pagina della nostra {privacyPolicyLink} per ulteriori informazioni.","gui.telemetryOptIn.privacyPolicyLink":"Politica della Privacy","gui.telemetryOptIn.optInText":"Condividi le mie statistiche di uso con lo Scratch Team","gui.telemetryOptIn.optInTooltip":"Abilita telemetria","gui.telemetryOptIn.optOutText":"Non condividere le mie statistiche di uso con lo Scratch Team ","gui.telemetryOptIn.optOutTooltip":"Disabilita telemetria","gui.telemetryOptIn.settingWasUpdated":"Le impostazioni sono state aggiornate.","gui.telemetryOptIn.buttonClose":"Chiudi","gui.turboMode.active":"Modalità Turbo","gui.webglModal.label":"Il Tuo Browser Non Supporta WebGL","gui.webglModal.webgllink":"non supporta WebGL","gui.costumeLibrary.chooseABackdrop":"Scegli uno Sfondo","gui.costumeLibrary.chooseACostume":"Scegli un Costume","gui.costumeTab.addBackdropFromLibrary":"Scegli uno Sfondo","gui.costumeTab.addCostumeFromLibrary":"Scegli un Costume","gui.costumeTab.addBlankCostume":"Disegna un nuovo costume","gui.costumeTab.addSurpriseCostume":"Scegli un costume a Sorpresa","gui.costumeTab.addFileBackdrop":"Importa Sfondo","gui.costumeTab.addFileCostume":"Importa Costume","gui.extensionLibrary.chooseAnExtension":"Scegli una Estensione","gui.extensionLibrary.extensionUrl":"Inserisci l\'URL dell\'estensione","gui.monitors.importListColumnPrompt":"Quale colonna vuoi che venga usata (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Impossibile iniziare la registrazione","gui.soundLibrary.chooseASound":"Scegli un Suono","gui.soundTab.fileUploadSound":"Carica un Suono","gui.soundTab.surpriseSound":"Aggiungi un suono a Sorpresa","gui.soundTab.recordSound":"Registra","gui.soundTab.addSoundFromLibrary":"Scegli un Suono","gui.spriteLibrary.chooseASprite":"Scegli uno Sprite","gui.tipsLibrary.tutorials":"Scegli un Tutorial.","gui.alerts.createsuccess":"Creato nuovo progetto.","gui.alerts.createcopysuccess":"Salvata una copia del progetto.","gui.alerts.createremixsuccess":"Salvato un remix del progetto.","gui.alerts.creating":"Creazione di un nuovo progetto in corso...","gui.alerts.creatingCopy":"Copia del progetto in corso...","gui.alerts.creatingRemix":"Remix del progetto in corso...","gui.alerts.creatingError":"Impossibile creare il progetto. Prova di nuovo!","gui.alerts.savingError":"Non è possibile salvare il progetto.","gui.alerts.savesuccess":"Progetto salvato.","gui.alerts.saving":"Salvataggio del progetto in corso...","gui.alerts.cloudInfo":"Ricorda che le variabili cloud supportano solo numeri, non supportano lettere o simboli. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Per saperne di più.","gui.alerts.importing":"Importazione in corso...","gui.defaultProject.variable":"la mia variabile","gui.extension.music.name":"Musica","gui.extension.music.description":"Suona strumenti e percussioni.","gui.extension.pen.name":"Penna","gui.extension.pen.description":"Disegna usando gli sprite.","gui.extension.videosensing.name":"Movimento Webcam","gui.extension.videosensing.description":"Rileva il movimento con la tua webcam.","gui.extension.text2speech.name":"Da Testo a Voce","gui.extension.text2speech.description":"Fai parlare i tuoi progetti","gui.extension.translate.name":"Traduci","gui.extension.translate.description":"Traduci un testo in molte altre lingue.","gui.extension.makeymakey.description":"Trasforma qualunque cosa in un pulsante","gui.extension.microbit.description":"Collega il tuo progetto con il mondo che ti circonda","gui.extension.microbit.connectingMessage":"Collegamento in corso","gui.extension.ev3.description":"Costruisci robot interattivi e altro ancora.","gui.extension.ev3.connectingMessage":"Connessione in corso. Assicurati che il pin sul tuo EV3 sia 1234.","gui.extension.boost.description":"Dai vita alle tue creazione robotiche.","gui.extension.boost.connectingMessage":"Collegamento in corso","gui.extension.wedo2.description":"Costruisci qualcosa usando motori e sensori.","gui.extension.wedo2.connectingMessage":"Collegamento in corso","gui.extension.gdxfor.description":"Rileva spinte, trazioni, movimenti e rotazioni.","gui.extension.gdxfor.connectingMessage":"Collegamento in corso","gui.libraryTags.all":"Tutti","gui.libraryTags.animals":"Animali","gui.libraryTags.dance":"Danza","gui.libraryTags.effects":"Effetti","gui.libraryTags.fantasy":"Fantasia","gui.libraryTags.fashion":"Moda","gui.libraryTags.food":"Cibi","gui.libraryTags.indoors":"Interni","gui.libraryTags.loops":"Loop","gui.libraryTags.music":"Musica","gui.libraryTags.notes":"Note","gui.libraryTags.outdoors":"Esterni","gui.libraryTags.patterns":"Pattern","gui.libraryTags.people":"Persone","gui.libraryTags.percussion":"Percussioni","gui.libraryTags.space":"Spazio","gui.libraryTags.sports":"Sport","gui.libraryTags.underwater":"Fondo del mare","gui.libraryTags.voice":"Voce","gui.libraryTags.wacky":"Strani","gui.libraryTags.animation":"Animazioni","gui.libraryTags.art":"Arte","gui.libraryTags.games":"Giochi","gui.libraryTags.stories":"Storie","gui.libraryTags.letters":"Lettere","gui.opcodeLabels.direction":"direzione","gui.opcodeLabels.xposition":"posizione x","gui.opcodeLabels.yposition":"posizione y","gui.opcodeLabels.size":"dimensione","gui.opcodeLabels.costumename":"nome del costume","gui.opcodeLabels.costumenumber":"numero del costume","gui.opcodeLabels.backdropname":"nome dello sfondo","gui.opcodeLabels.backdropnumber":"numero dello sfondo","gui.opcodeLabels.volume":"volume","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"risposta","gui.opcodeLabels.loudness":"volume microfono","gui.opcodeLabels.username":"username","gui.opcodeLabels.year":"anno","gui.opcodeLabels.month":"mese","gui.opcodeLabels.date":"data","gui.opcodeLabels.dayofweek":"giorno della settimana","gui.opcodeLabels.hour":"ora","gui.opcodeLabels.minute":"minuti","gui.opcodeLabels.second":"secondi","gui.opcodeLabels.timer":"cronometro","gui.sharedMessages.backdrop":"sfondo{index}","gui.sharedMessages.costume":"costume{index}","gui.sharedMessages.sprite":"Sprite{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Vuoi rimpiazzare il contenuto del progetto corrente?","gui.sharedMessages.loadFromComputerTitle":"Carica dal computer","boost.color.any":"colore qualunque","boost.color.black":"nero","boost.color.blue":"blu","boost.color.green":"verde","boost.color.red":"rosso","boost.color.white":"bianco","boost.color.yellow":"giallo","boost.getMotorPosition":"posizione motore [MOTOR_REPORTER_ID]","boost.getTiltAngle":"angolo inclinazione [TILT_DIRECTION]","boost.motorDirection.backward":"da quella parte","boost.motorDirection.forward":"da questa parte","boost.motorDirection.reverse":"inversa","boost.motorOff":"spegni motore [MOTOR_ID]","boost.motorOn":"accendi motore [MOTOR_ID]","boost.motorOnFor":"accendi motore [MOTOR_ID] per [DURATION] secondi","boost.motorOnForRotation":"accendi motore [MOTOR_ID] per [ROTATION] rotazioni","boost.seeingColor":"vedo mattoncino [COLOR]","boost.setLightHue":"porta colore luci a [HUE]","boost.setMotorDirection":"porta direzione motore [MOTOR_ID] a [MOTOR_DIRECTION]","boost.setMotorPower":"porta potenza [MOTOR_ID] a [POWER]","boost.tiltDirection.any":"in direzione qualunque","boost.tiltDirection.down":"in giù","boost.tiltDirection.left":"a sinistra","boost.tiltDirection.right":"a destra","boost.tiltDirection.up":"in su","boost.whenColor":"quando vedo mattoncino [COLOR]","boost.whenTilted":"quando inclinato [TILT_DIRECTION_ANY]","ev3.beepNote":"emetti nota [NOTE] per [TIME] secondi","ev3.buttonPressed":"pulsante [PORT] premuto","ev3.getBrightness":"luminosità","ev3.getDistance":"distanza","ev3.getMotorPosition":"posizione motore [PORT]","ev3.motorSetPower":"porta potenza motore [PORT] a [POWER] %","ev3.motorTurnClockwise":"aziona il motore [PORT] in questa direzione per [TIME] secondi","ev3.motorTurnCounterClockwise":"azione il motore [PORT] nell\'altra direzione per [TIME] secondi","ev3.whenBrightnessLessThan":"quando luminosità < [DISTANCE]","ev3.whenButtonPressed":"quando pulsante [PORT] premuto","ev3.whenDistanceLessThan":"quando distanza < [DISTANCE]","gdxfor.getAcceleration":"accelerazione [DIRECTION]","gdxfor.getForce":"forza","gdxfor.getSpin":"velocità di rotazione [DIRECTION]","gdxfor.getTilt":"angolo inclinazione [TILT]","gdxfor.isFreeFalling":"sto cadendo","gdxfor.isTilted":"inclinato [TILT]","gdxfor.pulled":"vengo tirato","gdxfor.pushed":"sono spinto","gdxfor.shaken":"è scosso","gdxfor.startedFalling":"inizia a cadere","gdxfor.tiltDirectionMenu.any":"in direzione qualunque","gdxfor.tiltDirectionMenu.back":"indietro","gdxfor.tiltDirectionMenu.front":"in avanti","gdxfor.tiltDirectionMenu.left":"a sinistra","gdxfor.tiltDirectionMenu.right":"a destra","gdxfor.turnedFaceDown":"è a faccia in giù","gdxfor.turnedFaceUp":"è a faccia in su","gdxfor.whenForcePushedOrPulled":"quando il sensore di forza rileva che [PUSH_PULL]","gdxfor.whenGesture":"quando [GESTURE]","gdxfor.whenTilted":"quando inclinato [TILT]","makeymakey.downArrow":"freccia giù","makeymakey.downArrowShort":"giù","makeymakey.leftArrow":"freccia sinistra","makeymakey.leftArrowShort":"a sinistra","makeymakey.rightArrow":"freccia destra","makeymakey.rightArrowShort":"a destra","makeymakey.spaceKey":"spazio","makeymakey.upArrow":"freccia su","makeymakey.upArrowShort":"su","makeymakey.whenKeyPressed":"quando si preme il tasto [KEY]","makeymakey.whenKeysPressedInOrder":"quando si preme la sequenza di tasti [SEQUENCE]","microbit.buttonsMenu.any":"in direzione qualunque","microbit.clearDisplay":"cancella display","microbit.defaultTextToDisplay":"Ciao!","microbit.displaySymbol":"mostra [MATRIX] su display","microbit.displayText":"mostra testo [TEXT]","microbit.gesturesMenu.jumped":"salta","microbit.gesturesMenu.moved":"si muove","microbit.gesturesMenu.shaken":"si scuote","microbit.isButtonPressed":"pulsante [BTN] premuto","microbit.isTilted":"inclinato [DIRECTION]","microbit.pinStateMenu.off":"spento","microbit.pinStateMenu.on":"acceso","microbit.tiltAngle":"angolo inclinazione [DIRECTION]","microbit.tiltDirectionMenu.any":"in direzione qualunque","microbit.tiltDirectionMenu.back":"indietro","microbit.tiltDirectionMenu.front":"in avanti","microbit.tiltDirectionMenu.left":"a sinistra","microbit.tiltDirectionMenu.right":"a destra","microbit.whenButtonPressed":"quando pulsante [BTN] premuto","microbit.whenGesture":"quando [GESTURE]","microbit.whenPinConnected":"quando il pin [PIN] è collegato","microbit.whenTilted":"quando inclinato [DIRECTION]","music.categoryName":"Musica","music.changeTempo":"cambia tempo di [TEMPO]","music.drumBass":"(2) Grancassa","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabassa","music.drumClaves":"(9) Legnetti","music.drumClosedHiHat":"(6) Charleston","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Campanaccio","music.drumCrashCymbal":"(4) Piatto Crash","music.drumCuica":"(18) Cuíca","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Battimano","music.drumOpenHiHat":"(5) Hi-Hat aperto","music.drumSideStick":"(3) Bacchette","music.drumSnare":"(1) Rullante","music.drumTambourine":"(7) Tamburello","music.drumTriangle":"(12) Triangolo","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Blocchetto di legno","music.getTempo":"tempo","music.instrumentBass":"(6) Basso elettrico","music.instrumentBassoon":"(14) Fagotto","music.instrumentCello":"(8) Violoncello","music.instrumentChoir":"(15) Coro","music.instrumentClarinet":"(10) Clarinetto","music.instrumentElectricGuitar":"(5) Chitarra elettrica","music.instrumentElectricPiano":"(2) Piano elettrico","music.instrumentFlute":"(12) Flauto","music.instrumentGuitar":"(4) Chitarra","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Carillon","music.instrumentOrgan":"(3) Organo","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Sassofono","music.instrumentSteelDrum":"(18) Steel Drum","music.instrumentSynthLead":"(20) Sintetizzatore","music.instrumentSynthPad":"(21) Sintetizzatore (suoni di sottofondo)","music.instrumentTrombone":"(9) Trombone","music.instrumentVibraphone":"(16) Vibrafono","music.instrumentWoodenFlute":"(13) Flauto di legno","music.midiPlayDrumForBeats":"suona tamburo [DRUM] per [BEATS] battute","music.midiSetInstrument":"passa a strumento [INSTRUMENT]","music.playDrumForBeats":"suona il tamburo [DRUM] per [BEATS] battute","music.playNoteForBeats":"suona la nota [NOTE] per [BEATS] battute","music.restForBeats":"pausa di [BEATS] battute","music.setInstrument":"passa a strumento [INSTRUMENT]","music.setTempo":"imposta tempo a [TEMPO] bpm","pen.categoryName":"Penna","pen.changeColorParam":"cambia [COLOR_PARAM] penna di [VALUE]","pen.changeHue":"cambia colore penna di [HUE]","pen.changeShade":"cambia luminosità penna di [SHADE]","pen.changeSize":"cambia spessore penna di [SIZE]","pen.clear":"pulisci","pen.colorMenu.brightness":"luminosità","pen.colorMenu.color":"colore","pen.colorMenu.saturation":"intensità colore","pen.colorMenu.transparency":"trasparenza","pen.penDown":"penna giù","pen.penUp":"penna su","pen.setColor":"usa penna di colore [COLOR]","pen.setColorParam":"porta [COLOR_PARAM] penna a [VALUE]","pen.setHue":"usa penna di colore [HUE]","pen.setShade":"porta luminosità penna a [SHADE]","pen.setSize":"usa penna di spessore [SIZE]","pen.stamp":"timbra","text2speech.alto":"da contralto","text2speech.categoryName":"Da Testo a Voce","text2speech.defaultTextToSpeak":"ciao","text2speech.giant":"da gigante","text2speech.kitten":"da gattino","text2speech.setLanguageBlock":"usa lingua [LANGUAGE]","text2speech.setVoiceBlock":"usa voce [VOICE]","text2speech.speakAndWaitBlock":"pronuncia [WORDS]","text2speech.squeak":"stridula","text2speech.tenor":"da tenore","translate.categoryName":"Traduci","translate.defaultTextToTranslate":"ciao","translate.translateBlock":"traduci [WORDS] in [LANGUAGE]","translate.viewerLanguage":"lingua","videoSensing.categoryName":"Movimento Webcam","videoSensing.direction":"direzione","videoSensing.motion":"movimento","videoSensing.off":"spegni","videoSensing.on":"accendi","videoSensing.onFlipped":"accendi e inverti orizzontalmente","videoSensing.setVideoTransparency":"porta trasparenza webcam a [TRANSPARENCY]","videoSensing.sprite":"sprite","videoSensing.stage":"stage","videoSensing.videoOn":"[ATTRIBUTE] del video su [SUBJECT]","videoSensing.videoToggle":"[VIDEO_STATE] il video della webcam","videoSensing.whenMotionGreaterThan":"quando movimento video è > [REFERENCE]","wedo2.getDistance":"distanza","wedo2.getTiltAngle":"angolo inclinazione [TILT_DIRECTION]","wedo2.isTilted":"inclinato [TILT_DIRECTION_ANY]","wedo2.motorDirection.backward":"da quella parte","wedo2.motorDirection.forward":"da questa parte","wedo2.motorDirection.reverse":"inversa","wedo2.motorId.a":"motore A","wedo2.motorId.all":"tutti i motori","wedo2.motorId.b":"motore B","wedo2.motorId.default":"motore","wedo2.motorOff":"spegni [MOTOR_ID]","wedo2.motorOn":"accendi [MOTOR_ID]","wedo2.motorOnFor":"accendi [MOTOR_ID] per [DURATION] secondi","wedo2.playNoteFor":"suona nota [NOTE] per [DURATION] secondi","wedo2.setLightHue":"porta colore luci a [HUE]","wedo2.setMotorDirection":"porta direzione [MOTOR_ID] a [MOTOR_DIRECTION]","wedo2.startMotorPower":"porta potenza [MOTOR_ID] a [POWER]","wedo2.tiltDirection.any":"in direzione qualunque","wedo2.tiltDirection.down":"in giù","wedo2.tiltDirection.left":"a sinistra","wedo2.tiltDirection.right":"a destra","wedo2.tiltDirection.up":"in su","wedo2.whenDistance":"quando distanza [OP] [REFERENCE]","wedo2.whenTilted":"quando inclinato [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Colore","paint.paintEditor.saturation":"Saturazione","paint.paintEditor.brightness":"Luminosità","paint.paintEditor.costume":"Costume","paint.paintEditor.group":"Raggruppa","paint.paintEditor.ungroup":"Separa","paint.paintEditor.undo":"Annulla","paint.paintEditor.redo":"Ripristina","paint.paintEditor.forward":"Porta avanti","paint.paintEditor.backward":"Porta indietro","paint.paintEditor.front":"Primo piano","paint.paintEditor.back":"Secondo piano","paint.paintEditor.more":"Altro","paint.modeTools.brushSize":"Dimensione","paint.modeTools.eraserSize":"Dimensione gomma","paint.modeTools.copy":"Copia","paint.modeTools.paste":"Incolla","paint.modeTools.delete":"Cancella","paint.modeTools.curved":"Curva","paint.modeTools.pointed":"Angolo","paint.modeTools.thickness":"Spessore","paint.modeTools.flipHorizontal":"Rifletti in Orizzontale","paint.modeTools.flipVertical":"Capovolgi","paint.modeTools.filled":"Riempito","paint.modeTools.outlined":"Contorno","paint.paintEditor.bitmap":"Converti in Bitmap","paint.paintEditor.vector":"Converti in Vettoriale","paint.paintEditor.fill":"Riempimento","paint.paintEditor.stroke":"Contorno","paint.brushMode.brush":"Pennello","paint.eraserMode.eraser":"Gomma","paint.fillMode.fill":"Riempimento","paint.lineMode.line":"Linea","paint.ovalMode.oval":"Cerchio","paint.rectMode.rect":"Rettangolo","paint.reshapeMode.reshape":"Modifica contorno","paint.roundedRectMode.roundedRect":"Rettangolo Arrotondato","paint.selectMode.select":"Seleziona","paint.textMode.text":"Testo","paint.colorPicker.swap":"Scambia","tw.alerts.autosaving":"Creazione del punto di ripristino...","tw.alerts.lostPeripheralConnection":"Persa la connessione a {extensionName}.","tw.alerts.savedToDisk":"Salvato sul computer.","tw.backpack.rename":"Nuovo nome:","tw.browserModal.desc":"Assicurati di usare una versione recente di Google Chrome, Mozilla Firefox, Microsoft Edge o Apple Safari.","tw.cantUseCloud":"Sebbene tu possa creare variabili cloud, queste funzioneranno solo quando il progetto sarà stato caricato sul sito di Scratch o sarà stato convertito usando un tool come {packager}.","tw.changeUsername.cannotChangeWhileRunning":"Non è possibile cambiare lo username mentre il progetto è in esecuzione.","tw.cloudVariableBadge":"Questo progetto usa le variabili cloud. TurboWarp usa un proprio server di variabili cloud indipendente da Scratch. Nota che gli utenti potrebbero non essere chi detto dal loro username in quanto chiunque può cambiare il proprio username in quello che preferisce. {learnMore}","tw.code":"Codice Sorgente","tw.confirmIncompatibleExtension":"Questa estensione non è compatibile con Scratch. I progetti che vengono creati con essa non possono essere caricati sul sito di Scratch. Sei sicuro di volerla attivare?","tw.customExtension.description":"Carica le estensioni personalizzate usando Il loro URL. Per sviluppatori. Sperimentale.","tw.customExtension.name":"Estensioni Personalizzate","tw.featuredProjectsStudio":"Vai alla galleria sul sito di Scratch.","tw.feedback":"Feedback & Bug","tw.feedbackButton":"Feedback per TurboWarp","tw.footer.credits":"Crediti","tw.footer.disclaimer":"TurboWarp non è affiliato a Scratch, allo Scratch Team o alla Scratch Foundation.","tw.footer.donate":"Dona","tw.footer.embed":"Inclusione","tw.footer.fosshost":"Hosting fornito da Fosshost","tw.footer.parameters":"Parametri URL","tw.footer.translate":"Aiuta a Tradurre TurboWarp","tw.gui.crashMessage.description":"Ci dispiace, sembra che la pagina abbia avuto un arresto anomalo. Aggiorna la pagina per riprovare.","tw.gui.defaultProjectTitle":"Progetto","tw.guiDefaultTitle":"Esegue i progetti Scratch più velocemente","tw.home.credit":"Note e Crediti","tw.home.description":"TurboWarp è una Modifica di Scratch che compila i progetti in JavaScript per renderli molto più veloci. Provalo, inserisci qui sopra un ID di un progetto o una URL o scegli uno dei progetti in primo piano che trovi qui sotto.","tw.home.instructions":"Istruzioni","tw.input.tooltip":"Copia e incolla il link di un progetto Scratch qui!","tw.interpolationEnabled":"Interpolazione","tw.invalidParameters.clones":"Il parametro URL \\"clone\\" non è valido","tw.invalidParameters.fps":"Il parametro URL \\"fps\\" non è valido","tw.loadError":"Errore nel caricamento del progetto: {error}","tw.loader.assets.known":"Scaricamento risorse in corso ({complete}/{total}) ...","tw.loader.assets.unknown":"Scaricamento risorse in corso ...","tw.loader.data":"Scaricamento dati del progetto in corso...","tw.loader.generic":"Caricamento del progetto in corso …","tw.menuBar.60off":"Disabilita modalità 60 FPS","tw.menuBar.60on":"Abilita modalità 60 FPS","tw.menuBar.addons":"Addon","tw.menuBar.advanced":"Impostazioni Avanzate","tw.menuBar.changeUsername":"Cambia Username","tw.menuBar.cloudOff":"Disabilita Variabili Cloud","tw.menuBar.cloudOn":"Abilita Variabili Cloud","tw.menuBar.cloudUnavailable":"Le Variabili Cloud non sono Disponibili","tw.menuBar.cloudUnavailableAlert":"Impossibile usare le variabili cloud, probabilmente perché è stato aperto l\'editor.","tw.menuBar.loadRestorePoint":"Carica il punto di ripristino","tw.menuBar.moreSettings":"Impostazioni Avanzate","tw.menuBar.newFramerate":"Nuovo framerate:","tw.menuBar.package":"Crea pacchetto","tw.menuBar.reportError1":"Non è stato possibile compilare tutti gli script.","tw.menuBar.reportError2":"Si è verificato un problema. Ti invitiamo a segnalarlo.","tw.menuBar.saveAs":"Salva come {file}","tw.menuBar.seeInside":"Guarda dentro","tw.oldDownload":"Salve in un file separato...","tw.openAdvanced":"Apri impostazioni avanzate","tw.paint.alpha":"Opacità","tw.privacy":"Politica della Privacy","tw.restorePoint.confirm":"L\'editor memorizza un punto di ripristino automatico in caso qualcosa non vada per il verso giusto e tu abbia dimenticato di salvare. Non dovresti fare affidamento su questa funzionalità e non possiamo garantirti che potrai recuperare il tuo progetto. Vuoi provare a caricarlo?","tw.restorePoint.loadFail":"Impossibile caricare il punto di ripristino: {error}","tw.saveAs":"Salva come...","tw.saveTo":"Salva come {file}","tw.scratchUnsafeCloud":"Se crei questa variabile cloud, il progetto supererà il limite massimo di {number} variabili previsto da Scratch e alcune variabili non funzioneranno se caricerai il progetto sul sito di Scratch.","tw.settingsModal.customStageSize":"Dimensioni Stage Personalizzate:","tw.settingsModal.customStageSizeHelp":"Cambia la dimensione dello stage di Scratch da 480x360 a un altro valore. Prova 640x360 per rendere lo stage widescreen. Pochi progetti potranno gestire questa proprietà.","tw.settingsModal.dangerZone":"Zona Pericolosa","tw.settingsModal.disableCompiler":"Disabilita Compilatore","tw.settingsModal.disableCompilerHelp":"Disabilita il compilatore di TurboWarp. E\' un\'opzione utile soltanto quando si modificano i progetti, in modo che gli script si aggiornino immediatamente. Si sconsiglia di usare questa opzione in altri casi.","tw.settingsModal.featured":"In Evidenza","tw.settingsModal.fps":"60 FPS (FPS personalizzato)","tw.settingsModal.fpsHelp":"Esegue gli script 60 volte al secondo invece di 30. Alcuni progetti potrebbero non funzionare correttamente con questa impostazione abilitata. In questo caso puoi provare ad abilitare l\'interpolazione senza abilitare la modalità 60 FPS. {customFramerate}.","tw.settingsModal.fpsHelp.customFramerate":"Clicca qui per usare un framerate diverso da 30 o 60","tw.settingsModal.help":"Clicca per aiuto","tw.settingsModal.highQualityPen":"Penna Alta Qualità","tw.settingsModal.highQualityPenHelp":"Permette ai progetti di essere visualizzati ad una risoluzione maggiore e disabilita l\'arrotondamento delle coordinate fatto dall\'editor. Non tutti i progetti si giovano di questa impostazione che può avere impatto sulla performance del progetto.","tw.settingsModal.infiniteClones":"Cloni Infiniti","tw.settingsModal.infiniteClonesHelp":"Disabilita il limite di Scratch di 300 cloni.","tw.settingsModal.interpolation":"Interpolazione","tw.settingsModal.interpolationHelp":"Fa apparire i progetti più fluidi interpolando il movimento degli sprite. L\'interpolazione non dovrebbe essere usata nei progetti 3D, nei raytracer, nei progetti basati sull\'uso della penna e nei progetti che laggano in quanto l\'interpolazione li farebbe eseguire più lentamente senza farli apparire più fluidi.","tw.settingsModal.largeStageWarning":"L\'uso di uno stage personalizzato così grande non è raccomandato! Ti suggeriamo di usare una dimensione inferiore con le stesse proporzioni e usare poi il fullscreen per portarlo alle dimensioni dello schermo dell\'utente.","tw.settingsModal.removeFencing":"Rimozione Recinto","tw.settingsModal.removeFencingHelp":"Permette agli sprite di muoversi completamente fuori dallo Stage e di diventare grandi o piccoli quando si desidera e permette ai blocchi sensori che verificano il contatto di funzionare anche quando gli sprite sono completamente fuori dallo Stage.","tw.settingsModal.removeLimits":"Rimozione Limiti","tw.settingsModal.removeMiscLimits":"Rimozione Limiti Vari","tw.settingsModal.removeMiscLimitsHelp":"Rimuove i limiti agli effetti sonori e alla dimensione della penna.","tw.settingsModal.storeProjectOptions":"Memorizza le impostazioni nel progetto","tw.settingsModal.storeProjectOptionsHelp":"Memorizza nel progetto le impostazioni selezionate in modo che siano applicate automaticamente quando il progetto viene caricato in TurboWarp. Il warp timer e la disabilitazione del compilatore non verranno memorizzati.","tw.settingsModal.title":"Impostazioni Avanzate","tw.settingsModal.warpTimerHelp":"Permette ai progetti di verificare se sono bloccati in un loop molto lungo o infinito e di essere quindi eseguiti ad un framerate più basso invece di apparire bloccati fino a che il loop non termina. Questa opzione risolve molte cause di blocco ma ha un impatto significativo sulla performance, quindi è abilitata come impostazione predeterminata solo all\'interno dell\'editor.","tw.spriteSelectorItem.rename":"rinomina","tw.stereoAlert":"Modificando questo suono stereo verrà convertito in modo in maniera irreversibile. ","tw.studioview.authorAttribution":"di {author}","tw.studioview.error":"Si è verificato un errore nel caricamento della pagina di progetti successiva.","tw.studioview.hoverText":"{title} di {author}","tw.tooLarge":"Questo suono potrebbe essere troppo pesante per essere caricato su Scratch.","tw.twExtension.description":"Nuovi blocchi strani. Non compatibile con Scratch.","tw.twExtension.name":"Blocchi TurboWarp","tw.unshared.1":"I progetti non convidisi non saranno più accessibili in futuro tramite il loro ID a causa di cambiamenti alla API di Scratch.","tw.unshared.2":"Per ulteriori informazioni vai a {link}","tw.unshared.cache":"Se il progetto è stato condiviso di recente questo messaggio può apparire erroneamente per alcuni minuti.","tw.usernameModal.help":"Questo valore verrà archiviato nello spazio di archiviazione del tuo browser. Potrebbe essere loggato quando interagisci con progetti che usano le variabili cloud.","tw.usernameModal.help2":"Valori che non corrispondono ad un account Scratch valido saranno di solito rifiutati dal server delle variabili cloud. Raccomandiamo di lasciarli così come sono o cambiandolo nel tuo username Scratch.","tw.usernameModal.mustChange":"Il server delle variabili cloud pensa che il tuo username possa non essere sicuro. Ti preghiamo di cambiarlo con qualcos\'altro o di {resetIt}","tw.usernameModal.mustChange.resetIt":"resettarlo (raccomandato)","tw.usernameModal.reset":"Resetta","tw.usernameModal.title":"Cambia Username","tw.viewFeaturedProjects":"Clicca per vedere i progetti in primo piano.","tw.viewOnScratch":"Mostra il progetto nel sito di Scratch","tw.webglModal.description":"Sembra che il tuo browser o il tuo computer non siano compatibili con {webGlLink}. Questa tecnologia è necessaria per poter usare questo sito. Prova ad aggiornare il tuo browser e i tuoi driver video o a riavviare il tuo computer."},"ka":{"gui.alerts.tryAgain":"კიდევ სცადე","gui.alerts.download":"ჩამოტვირთვა","gui.connection.reconnect":"ხელახლა დაკავშირება","gui.backpack.costumeLabel":"კოსტიუმი","gui.backpack.soundLabel":"ხმა","gui.backpack.scriptLabel":"სკრიპტი","gui.backpack.spriteLabel":"სპრაიტი","gui.backpack.header":"ზურგჩანთა","gui.backpack.errorBackpack":"შეცდომა ზურგჩანთის ჩატვირთვისას","gui.backpack.loadingBackpack":"იტვირთება...","gui.backpack.more":"სხვა","gui.backpack.emptyBackpack":"ზურგჩანთა ცარიელია","gui.unsupportedBrowser.label":"ბრაუზერის მხარდაჭერა არ არის","gui.cards.all-tutorials":"გაკვეთილები","gui.cards.shrink":"აკეცვა","gui.cards.expand":"გაშლა","gui.cards.close":"დახურვა","gui.cards.more-things-to-try":"სცადე უფრო მეტი!","gui.cards.see-more":"მეტის ნახვა","gui.comingSoon.message1":"ნუ ღელავ, ჩვენ ვმუშაობთ ამ პრობლემაზე {emoji}","gui.comingSoon.message2":"მალე იქნება...","gui.comingSoon.message3":"ჩვენ ვმუშაობთ ამ პრობლემაზე {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"მოწყობილობა ვერ მოიძებნა","gui.connection.auto-scanning.prescan":"თან იქონიეთ თქვენი მოწყობილობა, შემდეგ დაიწყეთ ძებნა.","gui.connection.auto-scanning.pressbutton":"დააჭირეთ თქვენი მოწყობილობის ღილაკზე.","gui.connection.auto-scanning.start-search":"ძებნის დაწყება","gui.connection.connecting-searchbutton":"იძებნება...","gui.connection.auto-scanning.try-again":"კიდევ სცადე","gui.connection.connected":"დაკავშირებულია","gui.connection.disconnect":"კავშირის გაწყვეტა","gui.connection.go-to-editor":"რედაქტორზე გადასვლა","gui.connection.connecting-cancelbutton":"კავშირი მყარდება...","gui.connection.error.errorMessage":"უკაცრავად, როგორც ჩანს შეცდომა მოხდა.","gui.connection.error.tryagainbutton":"კიდევ სცადე","gui.connection.error.helpbutton":"დახმარება","gui.connection.peripheral-name-label":"მოწყობილობის სახელი","gui.connection.connect":"დაკავშირება","gui.connection.scanning.lookingforperipherals":"მიმდინარეობს მოწყობილობის ძებნა","gui.connection.scanning.noPeripheralsFound":"მოწყობილობა ვერ მოიძებნა","gui.connection.scanning.instructions":"აირჩიე შენი მოწყობილობა ამ სიიდან","gui.connection.search":"განახლება","gui.connection.unavailable.installscratchlink":"დარწმუნდი, რომ Scratch Link დაყენებულია და მუშაობს","gui.connection.unavailable.enablebluetooth":"დარწმუნდი, რომ Bluetooth ჩართულია","gui.connection.unavailable.tryagainbutton":"კიდევ სცადე","gui.connection.unavailable.helpbutton":"დახმარება","gui.controls.go":"გადასვლა","gui.controls.stop":"გაჩერება","gui.crashMessage.label":"უკაცრავად, შეცდომა მოხდა.","gui.crashMessage.errorNumber":"თქვენი შეცდომა აღრიცხულია იდენტიფიკატორით {errorId}","gui.crashMessage.reload":"ხელახლა ჩატვირთვა","gui.customProcedures.myblockModalTitle":"შექმენი ბლოკი","gui.customProcedures.addAnInputNumberText":"დაამატე შესაყვანი","gui.customProcedures.numberTextType":"რიცხვი ან ტექსტი","gui.customProcedures.addAnInputBoolean":"დაამატე შესაყვანი","gui.customProcedures.booleanType":"ლოგიკური","gui.customProcedures.addALabel":"დაამატე იარლიყი","gui.customProcedures.runWithoutScreenRefresh":"მუშაობა ეკრანის განახლების გარეშე","gui.customProcedures.cancel":"გააუქმება","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"მიმართულება","gui.directionPicker.rotationStyles.allAround":"გარშემო","gui.directionPicker.rotationStyles.leftRight":"მარცხენა/მარჯვენა","gui.directionPicker.rotationStyles.dontRotate":"ტრიალის გარეშე","gui.gui.addExtension":"გაფართოების დამატება","gui.gui.codeTab":"კოდი","gui.gui.backdropsTab":"ფონები","gui.gui.costumesTab":"კოსტიუმები","gui.gui.soundsTab":"ხმები","gui.extensionLibrary.comingSoon":"მალე იქნება","gui.extensionLibrary.requires":"მოითხოვს","gui.extensionLibrary.collaboration":"თანამშრომლობაში","gui.library.filterPlaceholder":"ძიება","gui.library.allTag":"ყველა","gui.loader.headline":"პროექტი იტვირთება","gui.loader.creating":"იქმნება პროექტი","gui.authorInfo.byUser":"{username} მიერ","gui.menuBar.seeProjectPage":"იხილე პროექტის გვერდი","gui.menuBar.LanguageSelector":"ენის ასარჩევი","gui.menuBar.tutorialsLibrary":"გაკვეთილები","gui.menuBar.restoreSprite":"სპრაიტის აღდგენა ","gui.menuBar.restoreSound":"ხმის აღდგენა","gui.menuBar.restoreCostume":"კოსტიუმის აღდგენა","gui.menuBar.restore":"აღდგენა","gui.menuBar.saveNow":"შეინახე ახლა","gui.menuBar.saveAsCopy":"შეინახე როგორც ასლი","gui.menuBar.remix":"რემიქსი","gui.menuBar.new":"ახალი","gui.menuBar.file":"ფაილი","gui.menuBar.downloadToComputer":"შეინახე შენს კომპიუტერზე","gui.menuBar.edit":"რედაქტირება","gui.menuBar.turboModeOff":"გამორთე ტურბო რეჟიმი","gui.menuBar.turboModeOn":"ჩართე ტურბო რეჟიმი","gui.gui.projectTitlePlaceholder":"პროექტის სახელი აქ","gui.menuBar.isShared":"ზიარი","gui.menuBar.share":"გააზიარე","gui.modal.help":"დახმარება","gui.modal.back":"უკან","gui.monitor.listMonitor.empty":"(ცარიელი)","gui.monitor.listMonitor.listLength":"სიგრძე {length}","gui.monitor.contextMenu.default":"ჩვეულებრივი წასაკითხი ხედი","gui.monitor.contextMenu.large":"დიდი წასაკითხი ხედი","gui.monitor.contextMenu.slider":"ცოცია","gui.monitor.contextMenu.sliderRange":"ცოციას დიაპაზონის შეცვლა","gui.monitor.contextMenu.import":"იმპორტი","gui.monitor.contextMenu.export":"ექსპორტი","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"დაკვრა","gui.playButton.stop":"გაჩერება","gui.gui.variableScopeOptionAllSprites":"ყველა სპრაიტისთვის","gui.gui.variableScopeOptionSpriteOnly":"მხოლოდ ამ სპრაიტისთვის","gui.gui.cloudVariableOption":"ღრუბლის ცვლადი (ინახება სერვერზე)","gui.gui.variablePromptAllSpritesMessage":"ეს ცვლადი მისაწვდომი იქნება ყველა სპრაიტისთვის.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"გაუქმება","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"გაჩერება","gui.playbackStep.playMsg":"დაკვრა","gui.playbackStep.loadingMsg":"იტვირთება...","gui.playbackStep.saveMsg":"შენახვა","gui.playbackStep.reRecordMsg":"ხელახლა ჩაწერა","gui.recordModal.title":"ხმის ჩაწერა","gui.recordingStep.beginRecord":"დაიწყე ჩაწერა ქვემო ღილაკის დაჭერით","gui.recordingStep.permission":"{arrow} საჭიროა თქვენი ნებართვა მიკროფონის გამოსაყენებლად","gui.recordingStep.stop":"ჩაწერის შეწყვეტა","gui.recordingStep.record":"ჩაწერა","gui.sliderModal.min":"მინიმალური მნიშვნელობა","gui.sliderModal.max":"მაქსიმალური მნიშვნელობა","gui.sliderModal.title":"ცოციას დიაპაზონის შეცვლა","gui.sliderPrompt.cancel":"გაუქმება","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"ხმა","gui.soundEditor.play":"დაკვრა","gui.soundEditor.stop":"გაჩერება","gui.soundEditor.copy":"კოპირება","gui.soundEditor.paste":"ჩასმა","gui.soundEditor.copyToNew":"კოპირება ახალში","gui.soundEditor.delete":"წაშლა","gui.soundEditor.save":"შენახვა","gui.soundEditor.undo":"გაუქმება","gui.soundEditor.redo":"აღდგენა","gui.soundEditor.faster":"აჩქარება","gui.soundEditor.slower":"შენელება","gui.soundEditor.echo":"ექო","gui.soundEditor.robot":"რობოტი","gui.soundEditor.louder":"ხმის ამაღლება","gui.soundEditor.softer":"დარბილება","gui.soundEditor.reverse":"უკან მიბრუნება","gui.soundEditor.fadeOut":"თანდათან გაყუჩება","gui.soundEditor.fadeIn":"თანდათან მომატება","gui.soundEditor.mute":"უხმოდ","gui.SpriteInfo.spritePlaceholder":"სახელი","gui.SpriteInfo.sprite":"სპრაიტი","gui.SpriteInfo.show":"ჩვენება","gui.SpriteInfo.size":"ზომა","gui.spriteSelectorItem.contextMenuDuplicate":"დუბლირება","gui.spriteSelectorItem.contextMenuExport":"ექსპორტი","gui.spriteSelectorItem.contextMenuDelete":"წაშლა","gui.spriteSelector.addSpriteFromLibrary":"აირჩიე სპრაიტი","gui.spriteSelector.addSpriteFromPaint":"დახატვა","gui.spriteSelector.addSpriteFromSurprise":"სიურპრიზი","gui.spriteSelector.addSpriteFromFile":"ატვირთე სპრაიტი","gui.stageHeader.stageSizeLarge":"გადაერთე დიდ სცენაზე","gui.stageHeader.stageSizeSmall":"გადაერთე პატარა სცენაზე","gui.stageHeader.stageSizeFull":"გადაერთე სრული ეკრანის რეჟიმზე","gui.stageHeader.stageSizeUnFull":"გამოდი სრული ეკრანის რეჟიმიდან","gui.stageHeader.fullscreenControl":"სრული ეკრანის კონტროლი","gui.spriteSelector.addBackdropFromLibrary":"აირჩიე ფონი","gui.stageSelector.addBackdropFromPaint":"დახატვა","gui.stageSelector.addBackdropFromSurprise":"სიურპრიზი","gui.stageSelector.addBackdropFromFile":"ატვირთე ფონი","gui.stageSelector.stage":"სცენა","gui.stageSelector.backdrops":"ფონები","gui.telemetryOptIn.label":"გააგზავნე სტატისტიკა Scratch-ის გასაუმჯობესებლად","gui.telemetryOptIn.body1":"Scratch-ის გუნდი მუდმივად დაინტერესებულია უკეთესად ესმოდეს, თუ როგორ გამოიყენაბა Scratch-ი მსოფლიოში. ამ ძალისხმევის მხარდასაჭერად შეგიძლია ნება დართო Scratch-ს ავტომატურად გაუგზავნოს გამოყენების ინფორმაცია Scratch-ის გუნდს.","gui.telemetryOptIn.body2":"ინფორმაცია, რომელსაც ჩვენ ვაგროვებთ, მოიცავს ენის არჩევანს, ბლოკების გამოყენებას და ზოგიერთ მოვლენებს, როგორიცაა პროექტის შენახვა, ჩამოტვირთვა და ატვირთვა. ჩვენ არ ვაგროვებთ არავითარ პერსონალურ ინფორმაციას. იხილე ჩვენი {privacyPolicyLink} დამატებითი ინფორმაციისთვის.","gui.telemetryOptIn.privacyPolicyLink":"კონფიდენციალურობის პოლიტიკა","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"ტურბო რეჟიმი","gui.webglModal.label":"თქვენი ბრაუზერი არაა თავსებადი WebGL-თან","gui.webglModal.webgllink":" არაა თავსებადი WebGL-თან","gui.costumeLibrary.chooseABackdrop":"აირჩიე ფონი","gui.costumeLibrary.chooseACostume":"აირჩიე კოსტიუმი","gui.costumeTab.addBackdropFromLibrary":"აირჩიე ფონი","gui.costumeTab.addCostumeFromLibrary":"აირჩიე კოსტიუმი","gui.costumeTab.addBlankCostume":"დახატვა","gui.costumeTab.addSurpriseCostume":"სიურპრიზი","gui.costumeTab.addFileBackdrop":"ფონის ატვირთვა","gui.costumeTab.addFileCostume":"კოსტიუმის ატვირთვა","gui.extensionLibrary.chooseAnExtension":"აირჩიე გაფართოება","gui.extensionLibrary.extensionUrl":"შეიყვანე გაფართოების URL","gui.monitors.importListColumnPrompt":"რომელი სვეტი უნდა გამოიყენოს (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"შეუძლებელია ჩაწერის დაწყება","gui.soundLibrary.chooseASound":"ხმის არჩევა","gui.soundTab.fileUploadSound":"ხმის ატვირთვა","gui.soundTab.surpriseSound":"სიურპრიზი","gui.soundTab.recordSound":"ჩაწერა","gui.soundTab.addSoundFromLibrary":"ხმის არჩევა","gui.spriteLibrary.chooseASprite":"სპრაიტის არჩევა","gui.tipsLibrary.tutorials":"გაკვეთილის არჩევა","gui.alerts.createsuccess":"ახალი პროექტი შექმნილია.","gui.alerts.createcopysuccess":"პროექტი შენახულია როგორც ასლი.","gui.alerts.createremixsuccess":"პროექტი შენახულია როგორც რემიქსი.","gui.alerts.creating":"იქმნება ახალი...","gui.alerts.creatingCopy":"იქმნება პროექტის ასლი...","gui.alerts.creatingRemix":"იქმნება პროექტის რემიქსი...","gui.alerts.creatingError":"პროექტის შექმნა ვერ მოხერხდა. გთხოვთ კიდევ სცადოთ!\\n","gui.alerts.savingError":"პროექტის შენახვა ვერ მოხერხდა.","gui.alerts.savesuccess":"პროექტი შენახულია.","gui.alerts.saving":"პროექტი ინახება...","gui.alerts.cloudInfo":"გთხოვთ გაითვალისწინოთ, რომ ღრუბლოვანი ცვლადები წარმოადგენენ მხოლოდ რიცხვებს და არა ასოებსა და სიმბოლოებს. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"გაიგე მეტი.","gui.alerts.importing":"წარმოებს იმპორტი...","gui.defaultProject.variable":"ჩემი ცვლადი","gui.extension.music.name":"მუსიკა","gui.extension.music.description":"დაუკარი ინსტრუმენტებზე და დოლებზე.","gui.extension.pen.name":"კალამი","gui.extension.pen.description":"ხატე სპრაიტებით.","gui.extension.videosensing.name":"ვიდეო მგრძნობელობა ","gui.extension.videosensing.description":"იგრძენი მოძრაობა კამერის საშუალებით.","gui.extension.text2speech.name":"ტექსტის ამეტყველება","gui.extension.text2speech.description":"აამეტყველე შენი პროექტები.","gui.extension.translate.name":"თარგმნე","gui.extension.translate.description":"თარგმნე ტექსტი სხვადასხვა ენებზე.","gui.extension.makeymakey.description":"გადააქციე ნებისმიერი რამ გასაღებად.","gui.extension.microbit.description":"დაუკავშირდი მსოფლიოს შენი პროექტებით.","gui.extension.microbit.connectingMessage":"კავშირის დამყარება","gui.extension.ev3.description":"ააგე ინტერაქტიული რობოტები და ბევრი სხვა რამ.","gui.extension.ev3.connectingMessage":"კავშირის დამყარება. დარწმუნდი, რომ შენს EV3-ზე დაყენებულია პინის მნიშვნელობა 1234.","gui.extension.boost.description":"შთანერგე რობოტებს სიცოცხლე.","gui.extension.boost.connectingMessage":"კავშირის დამყარება","gui.extension.wedo2.description":"ააგე ძრავების და სენსორების საშუალებით.","gui.extension.wedo2.connectingMessage":"კავშირის დამყარება","gui.extension.gdxfor.description":"იგრძენი დაწოლა, გაწევა, მოძრაობა და ბრუნვა.","gui.extension.gdxfor.connectingMessage":"კავშირის დამყარება","gui.libraryTags.all":"ყველა","gui.libraryTags.animals":"ცხოველები","gui.libraryTags.dance":"ცეკვა","gui.libraryTags.effects":"ეფექტები","gui.libraryTags.fantasy":"ფანტაზია","gui.libraryTags.fashion":"მოდა","gui.libraryTags.food":"საკვები","gui.libraryTags.indoors":"შენობაში","gui.libraryTags.loops":"ციკლები","gui.libraryTags.music":"მუსიკა","gui.libraryTags.notes":"ნოტები","gui.libraryTags.outdoors":"ღია ცის ქვეშ","gui.libraryTags.patterns":"მოხატულობა","gui.libraryTags.people":"ადამიანები","gui.libraryTags.percussion":"დამრტყმელები","gui.libraryTags.space":"კოსმოსი","gui.libraryTags.sports":"სპორტი","gui.libraryTags.underwater":"წყალქვეშ","gui.libraryTags.voice":"ხმა","gui.libraryTags.wacky":"უცნაური","gui.libraryTags.animation":"ანიმაცია","gui.libraryTags.art":"ხელოვნება","gui.libraryTags.games":"თამაშები","gui.libraryTags.stories":"ამბები","gui.libraryTags.letters":"ასოები","gui.opcodeLabels.direction":"მიმართულება","gui.opcodeLabels.xposition":"x მდებარეობა","gui.opcodeLabels.yposition":"y მდებარეობა","gui.opcodeLabels.size":"ზომა","gui.opcodeLabels.costumename":"კოსტიუმის სახელი","gui.opcodeLabels.costumenumber":"კოსტიუმის ნომერი","gui.opcodeLabels.backdropname":"ფონის სახელი","gui.opcodeLabels.backdropnumber":"ფონის ნომერი","gui.opcodeLabels.volume":"ხმის სიმაღლე","gui.opcodeLabels.tempo":"ტემპი","gui.opcodeLabels.answer":"პასუხი","gui.opcodeLabels.loudness":"მაღალი ხმა","gui.opcodeLabels.username":"მომხმარებელი","gui.opcodeLabels.year":"წელი","gui.opcodeLabels.month":"თვე","gui.opcodeLabels.date":"თარიღი","gui.opcodeLabels.dayofweek":"კვირის დღე","gui.opcodeLabels.hour":"საათი","gui.opcodeLabels.minute":"წუთი","gui.opcodeLabels.second":"წამი","gui.opcodeLabels.timer":"წამზომი","gui.sharedMessages.backdrop":"ზურგჩანთა{index}","gui.sharedMessages.costume":"კოსტიუმი{index}","gui.sharedMessages.sprite":"სპრაიტი{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"შევანაცვლო მიმდინარე პროექტის შიგთავსი?","gui.sharedMessages.loadFromComputerTitle":"ატვირთე შენი კომპიუტერიდან","boost.color.any":"ნებისმიერი ფერი","boost.color.black":"შავი","boost.color.blue":"ლურჯი","boost.color.green":"მწვანე","boost.color.red":"წითელი","boost.color.white":"თეთრი","boost.color.yellow":"ყვითელი","boost.getMotorPosition":"ძრავის [MOTOR_REPORTER_ID] მდგომარეობა","boost.getTiltAngle":"დახრის კუთხე [TILT_DIRECTION]","boost.motorDirection.backward":"აქეთ","boost.motorDirection.forward":"იქით","boost.motorDirection.reverse":"უკუსვლა","boost.motorOff":"გამორთე ძრავა [MOTOR_ID]","boost.motorOn":"ჩართე ძრავა [MOTOR_ID]","boost.motorOnFor":"ჩართე ძრავა [MOTOR_ID] [DURATION] წამით","boost.motorOnForRotation":"ჩართე ძრავა [MOTOR_ID] [ROTATION] ბრუნით","boost.seeingColor":"ხედავ [COLOR] აგურს?","boost.setLightHue":"დააყენე ნათურის ფერი [HUE]","boost.setMotorDirection":"დააყენე ძრავის [MOTOR_ID] მიმართულება [MOTOR_DIRECTION]","boost.setMotorPower":"დააყენე ძრავის [MOTOR_ID] სიჩქარე [POWER] %","boost.tiltDirection.any":"ნებისმიერი","boost.tiltDirection.down":"ქვევით","boost.tiltDirection.left":"მარცხნივ","boost.tiltDirection.right":"მარჯვნივ","boost.tiltDirection.up":"ზევით","boost.whenColor":"როდესაც ხედავ [COLOR] აგურს","boost.whenTilted":"როდესაც დახრილია [TILT_DIRECTION_ANY]","ev3.beepNote":"დაუკარი ნოტა [NOTE] [TIME] წამი","ev3.buttonPressed":"ღილაკი [PORT] დაჭერილია?","ev3.getBrightness":"სიკაშკაშე","ev3.getDistance":"მანძილი","ev3.getMotorPosition":"ძრავის მდგომარეობა [PORT]","ev3.motorSetPower":"ძრავას [PORT] დაუყენე სიმძლავრე [POWER] %","ev3.motorTurnClockwise":"ძრავა [PORT] აბრუნე აქეთ [TIME] წამი","ev3.motorTurnCounterClockwise":"ძრავა [PORT] აბრუნე იქით [TIME] წამი","ev3.whenBrightnessLessThan":"როდესაც სიკაშკაშე < [DISTANCE]","ev3.whenButtonPressed":"როდესაც ღილაკი [PORT] დაჭერილია","ev3.whenDistanceLessThan":"როდესაც მანძილი < [DISTANCE]","gdxfor.getAcceleration":"აჩქარება [DIRECTION]","gdxfor.getForce":"ძალა","gdxfor.getSpin":"ბრუნვის სიჩქარე [DIRECTION]","gdxfor.getTilt":"დახრის კუთხე [TILT]","gdxfor.isFreeFalling":"ვარდება?","gdxfor.isTilted":"დახრილია [TILT]?","gdxfor.pulled":"გამოწეულია","gdxfor.pushed":"დაჭერილია","gdxfor.shaken":"შერხეულია","gdxfor.startedFalling":"ვარდნა დაიწყო","gdxfor.tiltDirectionMenu.any":"ნებისმიერი","gdxfor.tiltDirectionMenu.back":"უკან","gdxfor.tiltDirectionMenu.front":"წინ","gdxfor.tiltDirectionMenu.left":"მარცხნივ","gdxfor.tiltDirectionMenu.right":"მარჯვნივ","gdxfor.turnedFaceDown":"მოტრიალებულია პირით ქვევით","gdxfor.turnedFaceUp":"მოტრიალებულია პირით ზევით","gdxfor.whenForcePushedOrPulled":"როდესაც ძალის სენსორი [PUSH_PULL]","gdxfor.whenGesture":"როდესაც [GESTURE]","gdxfor.whenTilted":"როდესაც დახრილია [TILT]","makeymakey.downArrow":"ისარი ქვევით","makeymakey.downArrowShort":"ქვევით","makeymakey.leftArrow":"ისარი მარცხნივ","makeymakey.leftArrowShort":"მარცხნივ","makeymakey.rightArrow":"ისარი მარჯვნივ","makeymakey.rightArrowShort":"მარჯვნივ","makeymakey.spaceKey":"დაშორება","makeymakey.upArrow":"ისარი ზევით","makeymakey.upArrowShort":"ზევით","makeymakey.whenKeyPressed":"როდესაც [KEY] ღილაკი დაჭერილია","makeymakey.whenKeysPressedInOrder":"როდესაც [SEQUENCE] რიგითაა დაჭერილი","microbit.buttonsMenu.any":"ნებისმიერი","microbit.clearDisplay":"გაწმინდე ეკრანი","microbit.defaultTextToDisplay":"გამარჯობა!","microbit.displaySymbol":"ეკრანი [MATRIX]","microbit.displayText":"აჩვენე ტექსტი [TEXT]","microbit.gesturesMenu.jumped":"გადახტა","microbit.gesturesMenu.moved":"გადაადგილდა","microbit.gesturesMenu.shaken":"შეირხა","microbit.isButtonPressed":"[BTN] ღილაკი დაჭერილია?","microbit.isTilted":"გადაიხარა [DIRECTION]?","microbit.pinStateMenu.off":"გამორთვა","microbit.pinStateMenu.on":"ჩართვა","microbit.tiltAngle":"დახრის კუთხე [DIRECTION]","microbit.tiltDirectionMenu.any":"ნებისმიერი","microbit.tiltDirectionMenu.back":"უკან","microbit.tiltDirectionMenu.front":"წინ","microbit.tiltDirectionMenu.left":"მარცხნივ","microbit.tiltDirectionMenu.right":"მარჯვნივ","microbit.whenButtonPressed":"როდესაც [BTN] ღილაკი დაჭერილია","microbit.whenGesture":"როდესაც [GESTURE]","microbit.whenPinConnected":"როდესაც კონტაქტი [PIN] ჩართულია","microbit.whenTilted":"როდესაც დახრილია [DIRECTION]","music.categoryName":"მუსიკა","music.changeTempo":"შეცვალე ტემპი [TEMPO]-ით","music.drumBass":"(2) ბას დოლი","music.drumBongo":"(13) ბონგო","music.drumCabasa":"(15) კაბასა","music.drumClaves":"(9) კლავე","music.drumClosedHiHat":"(6) დახურული ჰაი-ჰეთი","music.drumConga":"(14) კონგა","music.drumCowbell":"(11) კაუბელი","music.drumCrashCymbal":"(4) კრეშ თეფშები","music.drumCuica":"(18) კუიკა","music.drumGuiro":"(16) გუირო","music.drumHandClap":"(98) ტაში","music.drumOpenHiHat":"(5) ღია ჰაი-ჰეთი","music.drumSideStick":"(3) გვერდითი დასარტყამი","music.drumSnare":"(1) ზამბარიანი დოლი","music.drumTambourine":"(7) დაირა","music.drumTriangle":"(12) სამკუთხედი","music.drumVibraslap":"(17) ვიბრასლეფი","music.drumWoodBlock":"(10) ხის ბლოკი","music.getTempo":"ტემპი","music.instrumentBass":"(6) ბასი","music.instrumentBassoon":"(14) ფაგოტი","music.instrumentCello":"(8) ჩელო","music.instrumentChoir":"(15) გუნდი","music.instrumentClarinet":"(10) კლარნეტი","music.instrumentElectricGuitar":"(5) ელექტრო გიტარა","music.instrumentElectricPiano":"(2) ელექტრო პიანინო","music.instrumentFlute":"(12) ფლეიტა","music.instrumentGuitar":"(4) გიტარა","music.instrumentMarimba":"(19) მარიმბა","music.instrumentMusicBox":"(17) მუსიკალური ყუთი","music.instrumentOrgan":"(3) ორღანი","music.instrumentPiano":"(1) ფორტეპიანო","music.instrumentPizzicato":"(7) პიციკატო","music.instrumentSaxophone":"(11) საქსაფონი","music.instrumentSteelDrum":"(18) ფოლადის დოლი","music.instrumentSynthLead":"(20) წამყვანი სინთეზატორი","music.instrumentSynthPad":"(21) ფონის სინთეზატორი","music.instrumentTrombone":"(9) ტრომბონი","music.instrumentVibraphone":"(16) ვიბრაფონი","music.instrumentWoodenFlute":"(13) ხის ფლეიტა","music.midiPlayDrumForBeats":"დაუკარი დოლი [DRUM] [BEATS] ბიტით","music.midiSetInstrument":"აირჩიე ინსტრუმენტი [INSTRUMENT]","music.playDrumForBeats":"დაუკარი დოლი [DRUM] [BEATS] ბიტით","music.playNoteForBeats":"დაუკარი ნოტა [NOTE] [BEATS] ბიტით","music.restForBeats":"პაუზა [BEATS] ბიტით","music.setInstrument":"აირჩიე ინსტრუმენტი [INSTRUMENT]","music.setTempo":"დააყენე ტემპი [TEMPO]","pen.categoryName":"კალამი","pen.changeColorParam":"შეცვალე კალმის [COLOR_PARAM] [VALUE]-ით","pen.changeHue":"შეცვალე კალმის ფერი [HUE]-თი","pen.changeShade":"შეცვალე კალმის ელფერი [SHADE]-ით","pen.changeSize":"შეცვალე კალმის ზომა [SIZE]-ით","pen.clear":"წაშალე ყველაფერი","pen.colorMenu.brightness":"სიკაშკაშე","pen.colorMenu.color":"ფერი","pen.colorMenu.saturation":"გაჯერება","pen.colorMenu.transparency":"გამჭვირვალობა","pen.penDown":"კალამი ქვევით","pen.penUp":"კალამი ზევით","pen.setColor":"დააყენე კალმის ფერი [COLOR]","pen.setColorParam":"დააყენე კალმის [COLOR_PARAM] [VALUE]","pen.setHue":"დააყენე კალმის ფერი [HUE]","pen.setShade":"დააყენე კალმის ელფერი [SHADE]","pen.setSize":"დააყენე კალმის ზომა [SIZE]","pen.stamp":"ბეჭდვა","text2speech.alto":"ალტი","text2speech.categoryName":"ტექსტის ამეტყველება","text2speech.defaultTextToSpeak":"გამარჯობა","text2speech.giant":"გიგანტი","text2speech.kitten":"კნუტი","text2speech.setLanguageBlock":"აირჩიე ენა [LANGUAGE]","text2speech.setVoiceBlock":"აირჩიე ხმა [VOICE]","text2speech.speakAndWaitBlock":"თქვი [WORDS]","text2speech.squeak":"წრიპინი","text2speech.tenor":"ტენორი","translate.categoryName":"თარგმნე","translate.defaultTextToTranslate":"სალამი","translate.translateBlock":"თარგმნე [WORDS] [LANGUAGE]-ად","translate.viewerLanguage":"ენა","videoSensing.categoryName":"ვიდეო სენსორი","videoSensing.direction":"მიმართულება","videoSensing.motion":"მოძრაობა","videoSensing.off":"გამორთვა","videoSensing.on":"ჩართვა","videoSensing.onFlipped":"ჩართვა პირიქით","videoSensing.setVideoTransparency":"დააყენე ვიდეოს გამჭვირვალობა [TRANSPARENCY]","videoSensing.sprite":"სპრაიტი","videoSensing.stage":"სცენა","videoSensing.videoOn":"ვიდეო [ATTRIBUTE] [SUBJECT]","videoSensing.videoToggle":"ჩართე ვიდეო [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"როდესაც ვიდეო მოძრაობა > [REFERENCE]","wedo2.getDistance":"მანძილი","wedo2.getTiltAngle":"დახრის კუთხე [TILT_DIRECTION]","wedo2.isTilted":"დახრილია [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"აქეთ","wedo2.motorDirection.forward":"იქით","wedo2.motorDirection.reverse":"უკუსვლა","wedo2.motorId.a":"ძრავა A","wedo2.motorId.all":"ყველა ძრავა","wedo2.motorId.b":"ძრავა B","wedo2.motorId.default":"ძრავა","wedo2.motorOff":"გამორთე [MOTOR_ID]","wedo2.motorOn":"ჩართე [MOTOR_ID]","wedo2.motorOnFor":"ჩართე ძრავა [MOTOR_ID] [DURATION] წამით","wedo2.playNoteFor":"დაუკარი ნოტა [NOTE] [DURATION] წამი","wedo2.setLightHue":"დააყენე ნათურის ფერი [HUE]","wedo2.setMotorDirection":"დააყენე [MOTOR_ID]-ის მიმართულება [MOTOR_DIRECTION]","wedo2.startMotorPower":"დააყენე [MOTOR_ID]-ის ძალა [POWER]","wedo2.tiltDirection.any":"ნებისმიერი","wedo2.tiltDirection.down":"ქვევით","wedo2.tiltDirection.left":"მარცხნივ","wedo2.tiltDirection.right":"მარჯვნივ","wedo2.tiltDirection.up":"ზევით","wedo2.whenDistance":"როდესაც მანძილი [OP] [REFERENCE]","wedo2.whenTilted":"როდესაც დახრილია [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"ფერი","paint.paintEditor.saturation":"გაჯერება","paint.paintEditor.brightness":"სიკაშკაშე","paint.paintEditor.costume":"კოსტიუმი","paint.paintEditor.group":"დაჯგუფება","paint.paintEditor.ungroup":"ჯგუფის დაშლა ","paint.paintEditor.undo":"გაუქმება","paint.paintEditor.redo":"აღდგენა","paint.paintEditor.forward":"წინ","paint.paintEditor.backward":"უკან","paint.paintEditor.front":"წინა პლანზე","paint.paintEditor.back":"უკანა პლანზე","paint.paintEditor.more":"სხვა","paint.modeTools.brushSize":"ზომა","paint.modeTools.eraserSize":"საშლელის ზომა","paint.modeTools.copy":"კოპირება","paint.modeTools.paste":"ჩასმა","paint.modeTools.delete":"წაშლა","paint.modeTools.curved":"გამრუდებული","paint.modeTools.pointed":"მიმართული","paint.modeTools.thickness":"სისქე","paint.modeTools.flipHorizontal":"ჰორიზონტალურად არეკვლა","paint.modeTools.flipVertical":"ვერტიკალურად არეკვლა","paint.modeTools.filled":"შევსებული","paint.modeTools.outlined":"შემოხაზული","paint.paintEditor.bitmap":"რასტრულ გამოსახულებად გარდაქმნა","paint.paintEditor.vector":"ვექტორულ გამოსახულებად გარდაქმნა","paint.paintEditor.fill":"შევსება","paint.paintEditor.stroke":"გამოკვეთე","paint.brushMode.brush":"ფუნჯი","paint.eraserMode.eraser":"საშლელი","paint.fillMode.fill":"შევსება","paint.lineMode.line":"ხაზი","paint.ovalMode.oval":"წრე","paint.rectMode.rect":"მართკუთხედი","paint.reshapeMode.reshape":"ფორმის შეცვლა","paint.roundedRectMode.roundedRect":"დამრგვალებული მართკუთხედი","paint.selectMode.select":"არჩევა","paint.textMode.text":"ტექსტი","paint.colorPicker.swap":"შეცვლა"},"kk":{"gui.alerts.tryAgain":"Қайта жасап көр","gui.alerts.download":"Жүктеп алу","gui.connection.reconnect":"Байланысты қайта орнату","gui.backpack.costumeLabel":"Спрайт","gui.backpack.soundLabel":"дыбыс","gui.backpack.scriptLabel":"скрипт","gui.backpack.spriteLabel":"спрайт","gui.backpack.header":"Рюкзак","gui.backpack.errorBackpack":"Қателер жиналатын иыққап","gui.backpack.loadingBackpack":"Жүктелуде...","gui.backpack.more":"Көбірек","gui.backpack.emptyBackpack":"Иыққап бос","gui.unsupportedBrowser.label":"Браузер қолданылмайды","gui.cards.all-tutorials":"Оқулықтар","gui.cards.shrink":"Кішірейту","gui.cards.expand":"Кеңейту","gui.cards.close":"Жабу","gui.cards.more-things-to-try":"Тағы бір нәрсе көріңіз!","gui.cards.see-more":"Толығырақ","gui.comingSoon.message1":"Уайымдамаңыз, біз оған дайынбыз{emoji}\\n ","gui.comingSoon.message2":"Жуырда...","gui.comingSoon.message3":"Біз бұнымен жұмыс істеп жатырмыз{emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Құрылғылар табылмады","gui.connection.auto-scanning.prescan":"Құрылғыны жақындатыңыз да, іздеуді бастаңыз","gui.connection.auto-scanning.pressbutton":"Құрылғыдағы батырманы басыңыз","gui.connection.auto-scanning.start-search":"Іздеуді бастау","gui.connection.connecting-searchbutton":"Іздеу...","gui.connection.auto-scanning.try-again":"Қайта байқап көру","gui.connection.connected":"Қосылды","gui.connection.disconnect":"Ажыратылды","gui.connection.go-to-editor":"Редакторға өту","gui.connection.connecting-cancelbutton":"Қосылуда...","gui.connection.error.errorMessage":"Упс, бірнәрсе жұрыс емес сияқты.","gui.connection.error.tryagainbutton":"Қайта байқап көру","gui.connection.error.helpbutton":"Көмек","gui.connection.peripheral-name-label":"Құрылғының атауы","gui.connection.connect":"Қосылу","gui.connection.scanning.lookingforperipherals":"Құрылғыларды іздеу","gui.connection.scanning.noPeripheralsFound":"Құрылғылар табылмады","gui.connection.scanning.instructions":"Жоғарыдағы тізімнен өз құрылғыңды таңда","gui.connection.search":"Жаңарту","gui.connection.unavailable.installscratchlink":"Сізде Scratch Link орнатылып, іске қосылғанына көз жеткізіңіз","gui.connection.unavailable.enablebluetooth":"Bluetooth-дің қосылғанына көз жеткізіңіз","gui.connection.unavailable.tryagainbutton":"Қайта байқап көру","gui.connection.unavailable.helpbutton":"Көмек","gui.controls.go":"Кеттік","gui.controls.stop":"Стоп","gui.crashMessage.label":"Упс! Бір нәрсе дұрыс емес.","gui.crashMessage.errorNumber":"Бұл қате {errorId}идентификаторымен тіркелді","gui.crashMessage.reload":"Қайта жүктеу","gui.customProcedures.myblockModalTitle":"Блок жасау","gui.customProcedures.addAnInputNumberText":"Енгізуді қосу","gui.customProcedures.numberTextType":"сан немесе текст","gui.customProcedures.addAnInputBoolean":"Енгізуді қосу","gui.customProcedures.booleanType":"логикалық","gui.customProcedures.addALabel":"Жапсырма қосу","gui.customProcedures.runWithoutScreenRefresh":"Экранды жаңартусыз іске қосу","gui.customProcedures.cancel":"Болдырмау","gui.customProcedures.ok":"Жақсы","gui.SpriteInfo.direction":"Бағыты","gui.directionPicker.rotationStyles.allAround":"Айналада","gui.directionPicker.rotationStyles.leftRight":"Сол/Оң","gui.directionPicker.rotationStyles.dontRotate":"Айналдырмау","gui.gui.addExtension":"Қосымша қосу","gui.gui.codeTab":"Код","gui.gui.backdropsTab":"Фондар","gui.gui.costumesTab":"Костюмдер","gui.gui.soundsTab":"Дыбыстар","gui.extensionLibrary.comingSoon":"Жуырда...","gui.extensionLibrary.requires":"Талап етеді","gui.extensionLibrary.collaboration":"бірлесу","gui.library.filterPlaceholder":"Іздеу","gui.library.allTag":"Барлығы","gui.loader.headline":"Проектті жүктеу","gui.loader.creating":"Проектті ашу","gui.authorInfo.byUser":"{username}","gui.menuBar.seeProjectPage":"Проект парақшасын көру","gui.menuBar.LanguageSelector":"тілді таңдау","gui.menuBar.tutorialsLibrary":"Оқулықтар","gui.menuBar.restoreSprite":"Спрайтты қайтару","gui.menuBar.restoreSound":"Дыбысты қайтару","gui.menuBar.restoreCostume":"Костюмді қайтару","gui.menuBar.restore":"Қайтару","gui.menuBar.saveNow":"Қазір сақтау","gui.menuBar.saveAsCopy":"Көшірме ретінде сақтау","gui.menuBar.remix":"Ремикс","gui.menuBar.new":"Жаңа","gui.menuBar.file":"Файл","gui.menuBar.downloadToComputer":"Компьютерге сақтау","gui.menuBar.edit":"Түзету","gui.menuBar.turboModeOff":"Турбо режимін өшіру","gui.menuBar.turboModeOn":"Турбо режимін қосу","gui.gui.projectTitlePlaceholder":"Проекттің атауы осы жерде","gui.menuBar.isShared":"Бөлісті","gui.menuBar.share":"Бөлісу","gui.modal.help":"Көмек","gui.modal.back":"Артқа","gui.monitor.listMonitor.empty":"(бос)","gui.monitor.listMonitor.listLength":"ұзындығы{length}","gui.monitor.contextMenu.default":"қалыпты көрсеткіш","gui.monitor.contextMenu.large":"үлкен көрсеткіш","gui.monitor.contextMenu.slider":"тетікше","gui.monitor.contextMenu.sliderRange":"жүгірткінің диапазонын өзгерту","gui.monitor.contextMenu.import":"импорттау","gui.monitor.contextMenu.export":"экспорттау","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Ойнау","gui.playButton.stop":"Стоп","gui.gui.variableScopeOptionAllSprites":"Барлық спрайтар үшін","gui.gui.variableScopeOptionSpriteOnly":"Тек осы спрайт үшін","gui.gui.cloudVariableOption":"Бұлттық айнымалы (серверде сақталады)","gui.gui.variablePromptAllSpritesMessage":"Бұл айнымалы барлық спрайттар үшін қол жетімді","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Болдырмау","gui.prompt.ok":"Жақсы","gui.playbackStep.stopMsg":"Стоп","gui.playbackStep.playMsg":"Ойнау","gui.playbackStep.loadingMsg":"Жүктелуде...","gui.playbackStep.saveMsg":"Сақтау","gui.playbackStep.reRecordMsg":"Қайта жазу","gui.recordModal.title":"Дауысты жазу","gui.recordingStep.beginRecord":"Жазу үшін төменде орналасқан батырманы басыңыз","gui.recordingStep.permission":"{arrow}Микрофонды қолдану үшін бізге сіздің рұқсатыңыз керек","gui.recordingStep.stop":"Жазуды тоқтату","gui.recordingStep.record":"Жазу","gui.sliderModal.min":"Мимималды мән","gui.sliderModal.max":"Максималды мән","gui.sliderModal.title":"Жүгірткінің диапазонын өзгерту","gui.sliderPrompt.cancel":"Болдырмау","gui.sliderPrompt.ok":"Жақсы","gui.soundEditor.sound":"Дыбыс","gui.soundEditor.play":"Ойнау","gui.soundEditor.stop":"Стоп","gui.soundEditor.copy":"Көшіру","gui.soundEditor.paste":"Қою","gui.soundEditor.copyToNew":"Жаңаға көшіру","gui.soundEditor.delete":"Жою","gui.soundEditor.save":"Сақтау","gui.soundEditor.undo":"Болдырмау","gui.soundEditor.redo":"Қайталау","gui.soundEditor.faster":"Жылдамырақ","gui.soundEditor.slower":"Баяуырақ","gui.soundEditor.echo":"Жаңғырық","gui.soundEditor.robot":"Робот","gui.soundEditor.louder":"Қаттырақ","gui.soundEditor.softer":"Жұмсағырақ","gui.soundEditor.reverse":"Кері","gui.soundEditor.fadeOut":"Жоғалу","gui.soundEditor.fadeIn":"Пайда болу","gui.soundEditor.mute":"Дыбысын өшіру","gui.SpriteInfo.spritePlaceholder":"Есімі","gui.SpriteInfo.sprite":"Спрайт","gui.SpriteInfo.show":"Көрсету","gui.SpriteInfo.size":"өлшем","gui.spriteSelectorItem.contextMenuDuplicate":"көшірмесін жасау","gui.spriteSelectorItem.contextMenuExport":"экспорттау","gui.spriteSelectorItem.contextMenuDelete":"жою","gui.spriteSelector.addSpriteFromLibrary":"Спрайтты таңдаңыз","gui.spriteSelector.addSpriteFromPaint":"Бояу","gui.spriteSelector.addSpriteFromSurprise":"Тосын сый","gui.spriteSelector.addSpriteFromFile":"Спрайтты жүктеу","gui.stageHeader.stageSizeLarge":"Үлкен сахнаға ауысу","gui.stageHeader.stageSizeSmall":"Кіші сахнаға ауысу","gui.stageHeader.stageSizeFull":"Толық экран режиміне өту","gui.stageHeader.stageSizeUnFull":"Толық экран режимінен шығу","gui.stageHeader.fullscreenControl":"Толық экранды басқару","gui.spriteSelector.addBackdropFromLibrary":"Фонды таңдаңыз","gui.stageSelector.addBackdropFromPaint":"Бояу","gui.stageSelector.addBackdropFromSurprise":"Тосын сый","gui.stageSelector.addBackdropFromFile":"Фонды жүктеу","gui.stageSelector.stage":"Сахна","gui.stageSelector.backdrops":"фондар","gui.telemetryOptIn.label":"Скретчті жақсарту үшін статистика туралы есеп беру","gui.telemetryOptIn.body1":"Scratch Командасы әрдайым «Scratch»-ті бүкіл әлемде қалай қолданылатындығы туралы жақсы түсінуге тырысады. Бұл әрекетті қолдауға көмектесу үшін, Сіз Scratch бағдарламасына қолдану туралы ақпаратын автоматты түрде Scratch Командасына жіберуге рұқсат етуіңізге болады.","gui.telemetryOptIn.body2":"Біз жинаған ақпарат тіл таңдауды, блоктарды пайдалануды және жобаны сақтау, жүктеу және шығару сияқты кейбір оқиғаларды қамтиды. Біз ешқандай жеке ақпаратты жинамаймыз. Қосымша ақпарат алу үшін біздің Құпиялылық саясатымызды {privacyPolicyLink}қараңыз.","gui.telemetryOptIn.privacyPolicyLink":"Құпиялылық саясаты","gui.telemetryOptIn.optInText":"Қолданыс материалын Скратч командасымен бөліс","gui.telemetryOptIn.optInTooltip":"Телеметрияны қосу","gui.telemetryOptIn.optOutText":"Қолданыс материалымен Скратч командасымен бөліспеу ","gui.telemetryOptIn.optOutTooltip":"Телеметрияны өшіру","gui.telemetryOptIn.settingWasUpdated":"Сіздің баптауларыңыз жаңартылды.","gui.telemetryOptIn.buttonClose":"Жабу","gui.turboMode.active":"Турбо режим","gui.webglModal.label":"Сіздің браузеріңіз WebGL-ді қолдамайды","gui.webglModal.webgllink":"WebGL қолдамайды","gui.costumeLibrary.chooseABackdrop":"Фонды таңдаңыз","gui.costumeLibrary.chooseACostume":"Костюмді таңдау","gui.costumeTab.addBackdropFromLibrary":"Фонды таңдаңыз","gui.costumeTab.addCostumeFromLibrary":"Костюмді таңдау","gui.costumeTab.addBlankCostume":"Бояу","gui.costumeTab.addSurpriseCostume":"Тосын сый","gui.costumeTab.addFileBackdrop":"Фонды жүктеу","gui.costumeTab.addFileCostume":"Костюмді жүктеу","gui.extensionLibrary.chooseAnExtension":"Қосмшаны таңдау","gui.extensionLibrary.extensionUrl":"Қосымшаның URL-ін енгізіңіз","gui.monitors.importListColumnPrompt":"Қай баған қолданылуы керек (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Жазу мүмкін емес","gui.soundLibrary.chooseASound":"Дыбысты таңдау","gui.soundTab.fileUploadSound":"Дыбысты жүктеу","gui.soundTab.surpriseSound":"Тосын сый","gui.soundTab.recordSound":"Жазу","gui.soundTab.addSoundFromLibrary":"Дыбысты таңдау","gui.spriteLibrary.chooseASprite":"Спрайтты таңдаңыз","gui.tipsLibrary.tutorials":"Туториалды таңдау","gui.alerts.createsuccess":"Жаңа проект құрылды.","gui.alerts.createcopysuccess":"Проект көшірме ретінде сақталды.","gui.alerts.createremixsuccess":"Проект ремикс ретінде сақталды.","gui.alerts.creating":"Жаңасын құру...","gui.alerts.creatingCopy":"Проектті көшіру...","gui.alerts.creatingRemix":"Проектті ремикстеу...","gui.alerts.creatingError":"Проектті құру мүмкін емес. Қайта көріңіз!","gui.alerts.savingError":"Проект сақталмады.","gui.alerts.savesuccess":"Проект сақталды.","gui.alerts.saving":"Проект сақталуда...","gui.alerts.cloudInfo":"Назар аударыңыз, бұлтты айнымалылар символдар мен әріптерді емес, тек сандарды ғана қолдайды{learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Толығырақ.","gui.alerts.importing":"Импорттау...","gui.defaultProject.variable":"менің айнымалым","gui.extension.music.name":"Музыка","gui.extension.music.description":"Аспаптарда және дабылда ойнау","gui.extension.pen.name":"Қалам","gui.extension.pen.description":"Өз спрайтыңды салу","gui.extension.videosensing.name":"Бейнебақылау","gui.extension.videosensing.description":"Қозғалысты камера арқылы сезу","gui.extension.text2speech.name":"Текстті дауысқа айналдыру","gui.extension.text2speech.description":"Өз проектіңді сөйлету","gui.extension.translate.name":"Аудару","gui.extension.translate.description":"Текстті көптеген тілдерге аудару","gui.extension.makeymakey.description":"Кілтке Бірнәрсе Жасау","gui.extension.microbit.description":"Өз проектіңді әлеммен байланыстыр","gui.extension.microbit.connectingMessage":"Қосылуда...","gui.extension.ev3.description":"Интерактивті Роботтарды Құрастыру","gui.extension.ev3.connectingMessage":"Қосылуда. Өз EV3-де 1234 пині орнатылғанын көз жеткізіңіз.","gui.extension.boost.description":"Роботтандырылған туындыларды өмірге енгізіңіз","gui.extension.boost.connectingMessage":"Қосылуда...","gui.extension.wedo2.description":"Қозғалтқыштар мен датчиктермен құрастырыңыз","gui.extension.wedo2.connectingMessage":"Қосылуда...","gui.extension.gdxfor.description":"Итеруді, тартуды, қозғалысты және айналуды сезініңіз","gui.extension.gdxfor.connectingMessage":"Қосылуда...","gui.libraryTags.all":"Барлығы","gui.libraryTags.animals":"Жануарлар","gui.libraryTags.dance":"Би","gui.libraryTags.effects":"Эффекттер","gui.libraryTags.fantasy":"Қиял","gui.libraryTags.fashion":"Сән","gui.libraryTags.food":"Тағам","gui.libraryTags.indoors":"Ғимарат ішінде","gui.libraryTags.loops":"Түйіндер","gui.libraryTags.music":"Музыка","gui.libraryTags.notes":"Нота","gui.libraryTags.outdoors":"Ашық ауада","gui.libraryTags.patterns":"Өрнектер","gui.libraryTags.people":"Адамдар","gui.libraryTags.percussion":"Перкуссия","gui.libraryTags.space":"Пробел","gui.libraryTags.sports":"Спорт","gui.libraryTags.underwater":"Су асты әлемі","gui.libraryTags.voice":"Дауыс","gui.libraryTags.wacky":"Тентек","gui.libraryTags.animation":"Анимация","gui.libraryTags.art":"Өнер","gui.libraryTags.games":"Ойындар","gui.libraryTags.stories":"Әңгімелер","gui.libraryTags.letters":"Әріптер","gui.opcodeLabels.direction":"бағыт","gui.opcodeLabels.xposition":"x қалпында","gui.opcodeLabels.yposition":"y қалпында","gui.opcodeLabels.size":"өлшем","gui.opcodeLabels.costumename":"костюм аты","gui.opcodeLabels.costumenumber":"костюм нөмірі","gui.opcodeLabels.backdropname":"фонның атауы","gui.opcodeLabels.backdropnumber":"фон нөмірі","gui.opcodeLabels.volume":"дыбыс","gui.opcodeLabels.tempo":"қарқын","gui.opcodeLabels.answer":"жауап","gui.opcodeLabels.loudness":"дыбыс деңгейі","gui.opcodeLabels.username":"пайдаланушының аты","gui.opcodeLabels.year":"жыл","gui.opcodeLabels.month":"ай","gui.opcodeLabels.date":"күні","gui.opcodeLabels.dayofweek":"апта күні","gui.opcodeLabels.hour":"сағат","gui.opcodeLabels.minute":"минут","gui.opcodeLabels.second":"секунд","gui.opcodeLabels.timer":"таймер","gui.sharedMessages.backdrop":"фон{index}","gui.sharedMessages.costume":"костюм{index}","gui.sharedMessages.sprite":"Спрайт{index}","gui.sharedMessages.pop":"поп","gui.sharedMessages.replaceProjectWarning":"Ағымдағы проекттің мазмұнын ауыстыру керек пе?","gui.sharedMessages.loadFromComputerTitle":"Компьютерден жүктеу","boost.color.any":"кез келген түс","boost.color.black":"қара","boost.color.blue":"көк","boost.color.green":"жасыл","boost.color.red":"қызыл","boost.color.white":"ақ","boost.color.yellow":"сары","boost.getMotorPosition":"[MOTOR_REPORTER_ID] моторының орны","boost.getTiltAngle":"[TILT_DIRECTION] еңкею бұрышы ","boost.motorDirection.backward":"осы жолмен","boost.motorDirection.forward":"осылайша","boost.motorDirection.reverse":"қайту","boost.motorOff":" [MOTOR_ID] моторын өшір","boost.motorOn":" [MOTOR_ID] моторын іске қос","boost.motorOnFor":"[MOTOR_ID] моторын [DURATION] секундқа қос","boost.motorOnForRotation":"[MOTOR_ID] моторын [ROTATION] рет айналуға қос","boost.seeingColor":" [COLOR] кірпіші көрініп тұр ма?","boost.setLightHue":"жарық түсін [HUE] орнат","boost.setMotorDirection":"[MOTOR_ID] моторын [MOTOR_DIRECTION] бағытында орнат","boost.setMotorPower":"[MOTOR_ID] моторының жылдамдығын [POWER] % орнат","boost.tiltDirection.any":"кез келген","boost.tiltDirection.down":"төмен","boost.tiltDirection.left":"солға","boost.tiltDirection.right":"оңға","boost.tiltDirection.up":"жоғары","boost.whenColor":" [COLOR] кірпіші көрінгенде","boost.whenTilted":" [TILT_DIRECTION_ANY] еңкейгенде","ev3.beepNote":"[NOTE] жазбасының [TIME] секундқа дыбысын қос","ev3.buttonPressed":"[PORT] пернесі басылды ма?","ev3.getBrightness":"жарықтық","ev3.getDistance":"арақашықтық","ev3.getMotorPosition":" [PORT] моторының орны","ev3.motorSetPower":" [PORT] моторына [POWER] % қуатын орнату","ev3.motorTurnClockwise":" [PORT] моторын осы бағытта [TIME] секунд бойы бұру","ev3.motorTurnCounterClockwise":" [PORT] моторын осы бағытта [TIME] секунд бойы бұр","ev3.whenBrightnessLessThan":"жарықтығы < [DISTANCE] болғанда","ev3.whenButtonPressed":" [PORT] пернесі басылғанда","ev3.whenDistanceLessThan":"қашықтыңы < [DISTANCE] болғанда","gdxfor.getAcceleration":" [DIRECTION] үдеу","gdxfor.getForce":"күш","gdxfor.getSpin":"айналу жылдамдығы [DIRECTION]","gdxfor.getTilt":"еңкею бұрышы [TILT]","gdxfor.isFreeFalling":"құлап бара жатыр ма?","gdxfor.isTilted":"[TILT] еңкейді ме?","gdxfor.pulled":"тартылды","gdxfor.pushed":"итерілді","gdxfor.shaken":"шайқалды","gdxfor.startedFalling":"құлай бастады","gdxfor.tiltDirectionMenu.any":"кез келген","gdxfor.tiltDirectionMenu.back":"арты","gdxfor.tiltDirectionMenu.front":"алды","gdxfor.tiltDirectionMenu.left":"солға","gdxfor.tiltDirectionMenu.right":"оңға","gdxfor.turnedFaceDown":"беті тқмен қарады","gdxfor.turnedFaceUp":"беті жоғары қарады","gdxfor.whenForcePushedOrPulled":"сенсорда [PUSH_PULL] әрекеті болғанда","gdxfor.whenGesture":"[GESTURE] болғанда","gdxfor.whenTilted":"[TILT] еңкейгенде","makeymakey.downArrow":"нұсқары төмен","makeymakey.downArrowShort":"төмен","makeymakey.leftArrow":"нұсқары солға","makeymakey.leftArrowShort":"солға","makeymakey.rightArrow":"нұсқары оңға","makeymakey.rightArrowShort":"оңға","makeymakey.spaceKey":"пробел","makeymakey.upArrow":"нұсқары жоғары","makeymakey.upArrowShort":"жоғары","makeymakey.whenKeyPressed":"[KEY] пернесі басылғанда","makeymakey.whenKeysPressedInOrder":"[SEQUENCE] ретпен басылғанда","microbit.buttonsMenu.any":"кез келген","microbit.clearDisplay":"дисплейді тазалау","microbit.defaultTextToDisplay":"Сәлем!","microbit.displaySymbol":"[MATRIX] көрсету","microbit.displayText":"[TEXT] мәтінін көрсету","microbit.gesturesMenu.jumped":"секірді","microbit.gesturesMenu.moved":"қозғалды","microbit.gesturesMenu.shaken":"шайқалды","microbit.isButtonPressed":"[BTN] пернесі басылды ма?","microbit.isTilted":"[DIRECTION] еңкейді ме?","microbit.pinStateMenu.off":"өшіру","microbit.pinStateMenu.on":"қосу","microbit.tiltAngle":"еңкею бұрышы [DIRECTION]","microbit.tiltDirectionMenu.any":"кез келген","microbit.tiltDirectionMenu.back":"арты","microbit.tiltDirectionMenu.front":"алды","microbit.tiltDirectionMenu.left":"солға","microbit.tiltDirectionMenu.right":"оңға","microbit.whenButtonPressed":"[BTN] пернесі басылғанда","microbit.whenGesture":"[GESTURE] болғанда","microbit.whenPinConnected":"[PIN] істігі қосылғанда","microbit.whenTilted":"[DIRECTION] бағытында еңкейгенде","music.categoryName":"Музыка","music.changeTempo":"темпті [TEMPO] өзгерткенде","music.drumBass":"(2) бас дабылы","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"Клавес","music.drumClosedHiHat":"Жабық хай-хэт","music.drumConga":"(14) Conga","music.drumCowbell":" Cowbell","music.drumCrashCymbal":"Табақшалардың соғылуы","music.drumCuica":"Куика","music.drumGuiro":"Гуиро","music.drumHandClap":"Шапалақтау","music.drumOpenHiHat":"Ашық хай-хэт","music.drumSideStick":"Бүйір қалам","music.drumSnare":"Дабыл","music.drumTambourine":"Тамбурин","music.drumTriangle":"Үшбұрыш","music.drumVibraslap":"Вибраслэп","music.drumWoodBlock":"Ағаш қорапша","music.getTempo":"Дыбыс ырғағы","music.instrumentBass":"Бас","music.instrumentBassoon":"Фагот","music.instrumentCello":"Виолончель","music.instrumentChoir":"Хор","music.instrumentClarinet":"Кларнет","music.instrumentElectricGuitar":"Электрлік гитара","music.instrumentElectricPiano":"Электрлік пианино","music.instrumentFlute":"Флейта","music.instrumentGuitar":"Гитара","music.instrumentMarimba":"Маримба","music.instrumentMusicBox":"Музыкалық сандық","music.instrumentOrgan":"Орган","music.instrumentPiano":"Пианино","music.instrumentPizzicato":"Пиццикато","music.instrumentSaxophone":"Саксофон","music.instrumentSteelDrum":"Болат дабыл","music.instrumentSynthLead":"Жетекші синтезатор","music.instrumentSynthPad":"Pad синтезаторі","music.instrumentTrombone":"Тромбон","music.instrumentVibraphone":"Вибрафон","music.instrumentWoodenFlute":"Ағаш флейта","music.midiPlayDrumForBeats":"[DRUM] дабылында [BEATS] такт ойнау","music.midiSetInstrument":"[INSTRUMENT] аспабын орнату","music.playDrumForBeats":"[DRUM] дабылында [BEATS] такт ойнау","music.playNoteForBeats":"[NOTE] нотасында [BEATS] такт ойнау","music.restForBeats":" [BEATS] такт күту","music.setInstrument":"[INSTRUMENT] аспабын орнату","music.setTempo":"Ырғақты [TEMPO] орнатыңыз","pen.categoryName":"Қалам","pen.changeColorParam":"[COLOR_PARAM]  қаламның түсін [VALUE] бойынша өзгерту","pen.changeHue":"қаламның түсін [HUE]  өзгерту ","pen.changeShade":"қалам реңін [SHADE] өзгерту","pen.changeSize":"қаламның өлшемін [SIZE] өзгерту ","pen.clear":"Бәрін өшіру","pen.colorMenu.brightness":"жарықтық","pen.colorMenu.color":"түс","pen.colorMenu.saturation":"Қанықтылық","pen.colorMenu.transparency":"мөлдірлік","pen.penDown":"қауырсынды түсіру","pen.penUp":"қауырсынды көтеру","pen.setColor":"қаламның түсін [COLOR] орнату","pen.setColorParam":"[COLOR_PARAM] қаламның түсін [VALUE] бойынша орнату","pen.setHue":"қаламның түсін [HUE] орнату","pen.setShade":"қалам реңін [SHADE] өзгерту","pen.setSize":"қаламның өлшемін [SIZE] орнату","pen.stamp":"марка","text2speech.alto":"альт","text2speech.categoryName":"Текстті дауысқа айналдыру","text2speech.defaultTextToSpeak":"сәлем","text2speech.giant":"алып","text2speech.kitten":"марғау","text2speech.setLanguageBlock":"тілді [LANGUAGE] орнату","text2speech.setVoiceBlock":"дауысты [VOICE] орнату","text2speech.speakAndWaitBlock":"[WORDS] айту","text2speech.squeak":"сықырлау","text2speech.tenor":"тенор","translate.categoryName":"Аудару","translate.defaultTextToTranslate":"сәлем","translate.translateBlock":"[WORDS] [LANGUAGE] тіліне аудару","translate.viewerLanguage":"тіл","videoSensing.categoryName":"Бейнебақылау","videoSensing.direction":"бағыт","videoSensing.motion":"қозғалыс","videoSensing.off":"өшіру","videoSensing.on":"қосу","videoSensing.onFlipped":"төңкерілген","videoSensing.setVideoTransparency":"бейне ашықтығын [TRANSPARENCY] орнату","videoSensing.sprite":"спрайт","videoSensing.stage":"stage","videoSensing.videoOn":"[SUBJECT]-тегі видео [ATTRIBUTE] ","videoSensing.videoToggle":"[VIDEO_STATE] видеоны іске қосу","videoSensing.whenMotionGreaterThan":"видео қозғалысы > [REFERENCE]","wedo2.getDistance":"арақашықтық","wedo2.getTiltAngle":"[TILT_DIRECTION] еңкею бұрышы ","wedo2.isTilted":" [TILT_DIRECTION_ANY] еңкейген бе?","wedo2.motorDirection.backward":"осы жолмен","wedo2.motorDirection.forward":"осылайша","wedo2.motorDirection.reverse":"қайту","wedo2.motorId.a":"А моторы","wedo2.motorId.all":"барлық моторлар","wedo2.motorId.b":"Б моторы","wedo2.motorId.default":"мотор","wedo2.motorOff":" [MOTOR_ID] моторын өшір","wedo2.motorOn":" [MOTOR_ID] моторын іске қос","wedo2.motorOnFor":"[MOTOR_ID] моторын [DURATION] секундқа қос","wedo2.playNoteFor":"[NOTE] нотасын [DURATION] секунд ойнату","wedo2.setLightHue":"жарық түсін [HUE] орнат","wedo2.setMotorDirection":"[MOTOR_ID] моторын [MOTOR_DIRECTION] бағытында орнат","wedo2.startMotorPower":"[MOTOR_ID] қуатын [POWER] орнату","wedo2.tiltDirection.any":"кез келген","wedo2.tiltDirection.down":"төмен","wedo2.tiltDirection.left":"солға","wedo2.tiltDirection.right":"оңға","wedo2.tiltDirection.up":"жоғары","wedo2.whenDistance":"арақашықтық [OP] [REFERENCE] болған кезде","wedo2.whenTilted":" [TILT_DIRECTION_ANY] еңкейгенде","paint.paintEditor.hue":"Түс","paint.paintEditor.saturation":"Қанықтылық","paint.paintEditor.brightness":"Жарықтығы","paint.paintEditor.costume":"Костюм","paint.paintEditor.group":"Топтау","paint.paintEditor.ungroup":"топтан шығару","paint.paintEditor.undo":"Болдырмау","paint.paintEditor.redo":"Қайталау","paint.paintEditor.forward":"Алға","paint.paintEditor.backward":"Артқа","paint.paintEditor.front":"Фронт","paint.paintEditor.back":"Артқа","paint.paintEditor.more":"Көбірек","paint.modeTools.brushSize":"өлшем","paint.modeTools.eraserSize":"Өшіргіштің өлшемі","paint.modeTools.copy":"Көшіру","paint.modeTools.paste":"Қою","paint.modeTools.delete":"Жою","paint.modeTools.curved":"Қисық","paint.modeTools.pointed":"Көрсетілген\\n","paint.modeTools.thickness":"Қалыңдығы","paint.modeTools.flipHorizontal":"Көлденеңінен аудару","paint.modeTools.flipVertical":"Тігінен аудару","paint.modeTools.filled":"Толтырылған","paint.modeTools.outlined":"Сызылған","paint.paintEditor.bitmap":"Растрлық графикаға ауыстыру","paint.paintEditor.vector":"Векторлық графикаға ауыстыру","paint.paintEditor.fill":"Толтыру","paint.paintEditor.stroke":"контур","paint.brushMode.brush":"Қылқалам","paint.eraserMode.eraser":"Өшіргіш","paint.fillMode.fill":"Толтыру","paint.lineMode.line":"Сызық","paint.ovalMode.oval":"Шеңбер","paint.rectMode.rect":"Тікбұрыш","paint.reshapeMode.reshape":"Форманы өзгерту","paint.roundedRectMode.roundedRect":"Дөңгелек бұрышты төртбұрыш","paint.selectMode.select":"Таңдау","paint.textMode.text":"Мәтін","paint.colorPicker.swap":"Ауыстыру"},"qu":{"gui.alerts.tryAgain":"Yapamanta Ruray","gui.alerts.download":"Hurquy","gui.connection.reconnect":"Yapamanta Qallariy","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Qipina","gui.backpack.errorBackpack":"Mana allinchu llamkay","gui.backpack.loadingBackpack":"Llamkachkan...","gui.backpack.more":"aswan","gui.backpack.emptyBackpack":"Mana imayuq qipina","gui.unsupportedBrowser.label":"maskaynin manam allinchu kaywan","gui.cards.all-tutorials":"Yanapawansunchik","gui.cards.shrink":"Qintikuchkan","gui.cards.expand":"Hatunyachiy","gui.cards.close":"Wichqay","gui.cards.more-things-to-try":"Ancha Yanapay Qawanapaq!","gui.cards.see-more":"Acha Qaway","gui.comingSoon.message1":"ama llakikuychu chanipunim {emoji}","gui.comingSoon.message2":"Hukninkama...","gui.comingSoon.message3":"chay punim llamkachkaniku {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Manan Ima Llamkaynin Tarikunchu","gui.connection.auto-scanning.prescan":"Ima lamkaynikita kuskapuni churay, chaymanta Qallariy Maskariyta.","gui.connection.auto-scanning.pressbutton":"llamkaynikipi butunta ñipuy","gui.connection.auto-scanning.start-search":"Maskay Qallariq","gui.connection.connecting-searchbutton":"Maskariy","gui.connection.auto-scanning.try-again":"Yapamanta Ruray","gui.connection.connected":"Kuskachasqa","gui.connection.disconnect":"Wañuchina","gui.connection.go-to-editor":"Maukachinapaq","gui.connection.connecting-cancelbutton":"Kuskachasqa","gui.connection.error.errorMessage":"Karay, manam allintachus Lluqsichkan.","gui.connection.error.tryagainbutton":"Yapamanta Ruray","gui.connection.error.helpbutton":"yanapay","gui.connection.peripheral-name-label":"Llamkaynikipa Sutin","gui.connection.connect":"Kuskasqa","gui.connection.scanning.lookingforperipherals":"Llamkaynikita Maskariy","gui.connection.scanning.noPeripheralsFound":"Manan Ima Llamkaynin Tarikunchu","gui.connection.scanning.instructions":"Akllay ima llamkayniki Tarikusqanta. ","gui.connection.search":"Musuqyachi","gui.connection.unavailable.installscratchlink":"Yuyari Scratch Link tupachisqa kanqa allin llamkanaykipaq","gui.connection.unavailable.enablebluetooth":"Chiqanchay Bluetooth kuyurichisqa kachun","gui.connection.unavailable.tryagainbutton":"Yapamanta Ruray","gui.connection.unavailable.helpbutton":"yanapay","gui.controls.go":"Riy","gui.controls.stop":"Sayay","gui.crashMessage.label":"Ay! Mana allintachu lluqsirun","gui.crashMessage.errorNumber":"pantasqaykiqa churakurqun kay id-wan {errorId}","gui.crashMessage.reload":"Yapamanta qallariy","gui.customProcedures.myblockModalTitle":"ruray huk champata","gui.customProcedures.addAnInputNumberText":"Yapay huk yaykuqta","gui.customProcedures.numberTextType":"yupaychay qillqanata","gui.customProcedures.addAnInputBoolean":"Yapay huk Yaykuqta","gui.customProcedures.booleanType":"buulianu","gui.customProcedures.addALabel":"yapay huk itikitata","gui.customProcedures.runWithoutScreenRefresh":"Llamkariy mana yapamanta qallarichispa","gui.customProcedures.cancel":"Manaña llamkaychu","gui.customProcedures.ok":"ARI","gui.SpriteInfo.direction":"Maypi","gui.directionPicker.rotationStyles.allAround":"Maymanpas Muyuq","gui.directionPicker.rotationStyles.leftRight":"Ichuq - Alliq","gui.directionPicker.rotationStyles.dontRotate":"Mana Muyuq","gui.gui.addExtension":"Yapay qawanata","gui.gui.codeTab":"kudiqu","gui.gui.backdropsTab":"Hipayninkuna","gui.gui.costumesTab":"Pachakuna","gui.gui.soundsTab":"Uyarikusqan","gui.extensionLibrary.comingSoon":"Hukninkama","gui.extensionLibrary.requires":"Munariy","gui.extensionLibrary.collaboration":"Yanapakuykuy","gui.library.filterPlaceholder":"Maskay","gui.library.allTag":"Llapan","gui.loader.headline":"Llamkay Qallarichkan","gui.loader.creating":"Llamkayta Ruray","gui.authorInfo.byUser":"llamkay sutinrayku {username}","gui.menuBar.seeProjectPage":"Qaway Rapi Ruwasqaykita","gui.menuBar.LanguageSelector":"simi akllay","gui.menuBar.tutorialsLibrary":"Yanapawansunchik","gui.menuBar.restoreSprite":"iqiqom allichachkan","gui.menuBar.restoreSound":"qapariqnin Allichachkan","gui.menuBar.restoreCostume":"pacha alichachkan","gui.menuBar.restore":"Allichay","gui.menuBar.saveNow":"waqaychay kunan","gui.menuBar.saveAsCopy":"Waqaychay huk kupiyapi","gui.menuBar.remix":"Kambiyay","gui.menuBar.new":"Musuq","gui.menuBar.file":"Qillqasqa","gui.menuBar.downloadToComputer":"Kumputaduraykiman waqaychay","gui.menuBar.edit":"Allichay","gui.menuBar.turboModeOff":"wañuchiy turbu muduta","gui.menuBar.turboModeOn":"Turbupi Qallariy Hina","gui.gui.projectTitlePlaceholder":"Llamkaynikipa sutin","gui.menuBar.isShared":"Rakisqa","gui.menuBar.share":"Rakiy","gui.modal.help":"yanapay","gui.modal.back":"hipaman","gui.monitor.listMonitor.empty":"(Mana imayuq)","gui.monitor.listMonitor.listLength":"sunin {length}","gui.monitor.contextMenu.default":"liyiy-kuy","gui.monitor.contextMenu.large":"Hatun qaway","gui.monitor.contextMenu.slider":"lluchkay","gui.monitor.contextMenu.sliderRange":"tikray lluchkay Hatunyariqta","gui.monitor.contextMenu.import":"impurtay","gui.monitor.contextMenu.export":"ixpurtay","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Pukllay","gui.playButton.stop":"Sayay","gui.gui.variableScopeOptionAllSprites":"llapan sprites-kunapaq","gui.gui.variableScopeOptionSpriteOnly":"sprite kunallapaq","gui.gui.cloudVariableOption":"puyu redpi Variabli (sirvidurllapi waqaychasqa)","gui.gui.variablePromptAllSpritesMessage":"Kay variabliqa llapam sprites-paqmi.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Manaña llamkaychu","gui.prompt.ok":"ARI","gui.playbackStep.stopMsg":"Sayay","gui.playbackStep.playMsg":"Pukllay","gui.playbackStep.loadingMsg":"Llamkachkan...","gui.playbackStep.saveMsg":"Waqaychay","gui.playbackStep.reRecordMsg":"yapamanta qrabay","gui.recordModal.title":"Luqyariqta Grabay","gui.recordingStep.beginRecord":"Qallari qrabayta butun uraypi klikyaykuspa ","gui.recordingStep.permission":"{arrow}munaniku pirmisuykita mikruphuno usanaykupaq. ","gui.recordingStep.stop":"Qrabayta sayay","gui.recordingStep.record":"Qrabay","gui.sliderModal.min":"Pisi balurlla","gui.sliderModal.max":"Ancha balur","gui.sliderModal.title":"tikray lluchkay Hatunyariqta","gui.sliderPrompt.cancel":"Manaña llamkanchu","gui.sliderPrompt.ok":"ARI","gui.soundEditor.sound":"qapariqnin","gui.soundEditor.play":"Pukllay","gui.soundEditor.stop":"Sayay","gui.soundEditor.copy":"kupyay","gui.soundEditor.paste":"Laqay","gui.soundEditor.copyToNew":"Musuqman Kupyay","gui.soundEditor.delete":"Pichay","gui.soundEditor.save":"Waqaychay","gui.soundEditor.undo":"ruraray","gui.soundEditor.redo":"kutipay","gui.soundEditor.faster":"Utqayllaman","gui.soundEditor.slower":"Allillamanta","gui.soundEditor.echo":"Ruwasqa","gui.soundEditor.robot":"Rubut","gui.soundEditor.louder":"Hatunkaray","gui.soundEditor.softer":"Llampulla","gui.soundEditor.reverse":"Qipaman puriy","gui.soundEditor.fadeOut":"Chinkarichiy","gui.soundEditor.fadeIn":"Hichay","gui.soundEditor.mute":"Upallay","gui.SpriteInfo.spritePlaceholder":"Suti","gui.SpriteInfo.sprite":"Spriti","gui.SpriteInfo.show":"qawanapaq","gui.SpriteInfo.size":"Hatun","gui.spriteSelectorItem.contextMenuDuplicate":"iskaychay","gui.spriteSelectorItem.contextMenuExport":"ixpurtay","gui.spriteSelectorItem.contextMenuDelete":"pichay","gui.spriteSelector.addSpriteFromLibrary":"Akllay huk Spritiyta","gui.spriteSelector.addSpriteFromPaint":"Llimpiy","gui.spriteSelector.addSpriteFromSurprise":"Muspay","gui.spriteSelector.addSpriteFromFile":"Sprite Qispinan","gui.stageHeader.stageSizeLarge":"Tikray hatun Qawarinaman","gui.stageHeader.stageSizeSmall":"Tikray uchuy Qawarinaman","gui.stageHeader.stageSizeFull":"Yaykuy qawana Intiruman","gui.stageHeader.stageSizeUnFull":"Lluqsiy qawana Intirumanta","gui.stageHeader.fullscreenControl":"Kamachiy qawanata","gui.spriteSelector.addBackdropFromLibrary":"Warkunata Akllay hipayninmanta ","gui.stageSelector.addBackdropFromPaint":"Llimpiy","gui.stageSelector.addBackdropFromSurprise":"Muspay","gui.stageSelector.addBackdropFromFile":"Warkunata Huqariy hipayninmanta ","gui.stageSelector.stage":"chimpa qaway","gui.stageSelector.backdrops":"Hipayninkuna","gui.telemetryOptIn.label":"niykuy hayka punitaq allichana Scratch-ta","gui.telemetryOptIn.body1":"Scratch ikipunmi maskanku allin llamkayta scratchwan llapan pachapi. yanapanampaq llapa rurayninpi, icha Scratchmi apachin utqallaman willakuyta scratch ikipunam.","gui.telemetryOptIn.body2":"willakuyta hapisqanchik kanmi simikunata, churay champakunata hinaspapas huk iwintukunta waqaychanapaqpas, churay hinaspa llamkay churaypas. manam pallanchikchu willakuy pirsunalnikita. ama hina kaspalla qaway{privacyPolicyLink} willakuykunata.","gui.telemetryOptIn.privacyPolicyLink":"Chiqanchikkuna Kikillanchikpaq","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Turbu Mudu","gui.webglModal.label":"maskasqaykipi manam kallparinchu WebGL nisgan","gui.webglModal.webgllink":"manan allinchu WebGL","gui.costumeLibrary.chooseABackdrop":"Warkunata Akllay hipayninmanta ","gui.costumeLibrary.chooseACostume":"Akllay huk Pachata","gui.costumeTab.addBackdropFromLibrary":"Warkunata Akllay hipayninmanta ","gui.costumeTab.addCostumeFromLibrary":"Akllay huk Pachata","gui.costumeTab.addBlankCostume":"Llimpiy","gui.costumeTab.addSurpriseCostume":"Achalaw","gui.costumeTab.addFileBackdrop":"Warkunata Huqariy hipayninmanta ","gui.costumeTab.addFileCostume":"Pacha Qispiy","gui.extensionLibrary.chooseAnExtension":"Akllaykuy hatuyninta","gui.extensionLibrary.extensionUrl":"churaykuy URL intirnitmanta.","gui.monitors.importListColumnPrompt":"Ima munasqaykita churanki (1-{numberOfColumns} )?","gui.recordingStep.alertMsg":"Qrabasion manan qallariyta atinchu.","gui.soundLibrary.chooseASound":"Akllay Luqyariqta","gui.soundTab.fileUploadSound":"Qispiriy Luqyariqta","gui.soundTab.surpriseSound":"Muspay","gui.soundTab.recordSound":"Qrabay","gui.soundTab.addSoundFromLibrary":"Akllay Luqyariqta","gui.spriteLibrary.chooseASprite":"Akllay huk Spritiyta","gui.tipsLibrary.tutorials":"Akllay Yanapaykunata","gui.alerts.createsuccess":"Musuq llamkay rurasqa.","gui.alerts.createcopysuccess":"Llakayqa waqaychakun huk kupiyapi","gui.alerts.createremixsuccess":"llamkay waqaychasqa takiqhina.","gui.alerts.creating":"Musuq ruray ...","gui.alerts.creatingCopy":"kupiyay llamkaynikita ...","gui.alerts.creatingRemix":"Kambiyasqa llamkay...","gui.alerts.creatingError":"llamkay manam ruwarinchu. ama hina kaspalla yapamanta qallariy!","gui.alerts.savingError":"llamkay manam waqaychakurqachu","gui.alerts.savesuccess":"llamkay qispichiy.","gui.alerts.saving":"Waqaychay llamkay ...","gui.alerts.cloudInfo":"Yuyariy kay puyu wariabliqa manam munanchu yupata,qillqata ni simbulutapas. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Anchay yachaykuy","gui.alerts.importing":"impurtay...","gui.defaultProject.variable":"hukniraqni","gui.extension.music.name":"Taki","gui.extension.music.description":"tukay instumintuta tanburtapas.","gui.extension.pen.name":"qillqay kaspi","gui.extension.pen.description":"Spritwam llimpiy.","gui.extension.videosensing.name":"Tarisqa Qawana","gui.extension.videosensing.description":"Kamarawan kuyuyta sintiy.","gui.extension.text2speech.name":"Qillqa Rimay ","gui.extension.text2speech.description":"Ruway Llamkasqaykikuna rimarinampaq","gui.extension.translate.name":"Tikray","gui.extension.translate.description":"Tikray Qillqaykunata Llapam Simiman","gui.extension.makeymakey.description":"Munasqaykita rurachun llawipi","gui.extension.microbit.description":"Tupachiy llamkaykikunata llapam hatun aylluman.","gui.extension.microbit.connectingMessage":"Kuskachasqa","gui.extension.ev3.description":"ruray rubut puririnanta himatas.","gui.extension.ev3.connectingMessage":"tupachkan qawariy EV3 nikipi pinnin 1234 kunfiqurasqa tarikuchun.","gui.extension.boost.description":"Kawsariyninta rubutkunaman churaykuy.","gui.extension.boost.connectingMessage":"Kuskachasqa","gui.extension.wedo2.description":"ruray mutur musyaqkunawan.","gui.extension.wedo2.connectingMessage":"Kuskachasqa","gui.extension.gdxfor.description":"musyay, tanqay, chutay, kuyuy hinaspa muyuy","gui.extension.gdxfor.connectingMessage":"Kuskachasqa","gui.libraryTags.all":"Llapan","gui.libraryTags.animals":"Uywakunata","gui.libraryTags.dance":"Tusuykuna","gui.libraryTags.effects":"Iphictukuna","gui.libraryTags.fantasy":"Fantasiyakuna","gui.libraryTags.fashion":"Pacha","gui.libraryTags.food":"mikuna","gui.libraryTags.indoors":"Hukupi","gui.libraryTags.loops":"Kutimanta","gui.libraryTags.music":"Taki","gui.libraryTags.notes":"Qillqaykuna","gui.libraryTags.outdoors":"Wayra kachasqa","gui.libraryTags.patterns":"Patrunkuna","gui.libraryTags.people":"Runa","gui.libraryTags.percussion":"Pirkusionkuna","gui.libraryTags.space":"Chimpa","gui.libraryTags.sports":"Pukllaykuna","gui.libraryTags.underwater":"Yaku-ukunpi puriq","gui.libraryTags.voice":"Rimaq","gui.libraryTags.wacky":"Upa","gui.libraryTags.animation":"Kawsachina","gui.libraryTags.art":"Rakiri","gui.libraryTags.games":"Pukllaykuna","gui.libraryTags.stories":"Willakuy","gui.libraryTags.letters":"Qillqakuna","gui.opcodeLabels.direction":"maypi","gui.opcodeLabels.xposition":"x sayay","gui.opcodeLabels.yposition":"y sayay","gui.opcodeLabels.size":"hatunin","gui.opcodeLabels.costumename":"pachapa sutin","gui.opcodeLabels.costumenumber":"pachapa yupaynin","gui.opcodeLabels.backdropname":"hipaynin sutin","gui.opcodeLabels.backdropnumber":"yupa hipaynin ","gui.opcodeLabels.volume":"ancha uyarina","gui.opcodeLabels.tempo":"pacha","gui.opcodeLabels.answer":"kutichiy rimayta","gui.opcodeLabels.loudness":"qapariknin","gui.opcodeLabels.username":"sutiyki","gui.opcodeLabels.year":"wata","gui.opcodeLabels.month":"killa","gui.opcodeLabels.date":"pacha","gui.opcodeLabels.dayofweek":"punchawkuna","gui.opcodeLabels.hour":"pacha","gui.opcodeLabels.minute":"minutu","gui.opcodeLabels.second":"wawa pacha","gui.opcodeLabels.timer":"yupachaq","gui.sharedMessages.backdrop":"hipaynin{index}","gui.sharedMessages.costume":"pacha {index}","gui.sharedMessages.sprite":"Sprit {index}","gui.sharedMessages.pop":"pup","gui.sharedMessages.replaceProjectWarning":"Musuqmanta ruray Llamkasqaykita?","gui.sharedMessages.loadFromComputerTitle":"Kumputaduraykimanta Llamkariy","boost.color.any":"mayqin kulurpas","boost.color.black":"yana","boost.color.blue":"anqas","boost.color.green":"qumir","boost.color.red":"puka","boost.color.white":"yuraq","boost.color.yellow":"qellu","boost.getMotorPosition":"kallpanchaq churasqa [MOTOR_REPORTER_ID]","boost.getTiltAngle":"Kuchuq kinraychasqa [TILT_DIRECTION]","boost.motorDirection.backward":"chayna puniy","boost.motorDirection.forward":"kayna puniy","boost.motorDirection.reverse":"qipaman puriy","boost.motorOff":"mutur wañuchisqa [MOTOR_ID]","boost.motorOn":"Kallpanchaq qallarichisqa [MOTOR_ID]","boost.motorOnFor":"mutur muyuq [MOTOR_ID] icha [DURATION] siqundupi","boost.motorOnForRotation":"mutur muyuq [MOTOR_ID] icha [ROTATION] muyuriqnin","boost.seeingColor":"qawaspa [COLOR] champa?","boost.setLightHue":"akchiqpa llimpinta churay [HUE]","boost.setMotorDirection":"muturta churaykuy [MOTOR_ID] riqman [MOTOR_DIRECTION]","boost.setMotorPower":"utqayllaman churay [MOTOR_ID] muturpa [POWER]%","boost.tiltDirection.any":"mayqimpas","boost.tiltDirection.down":"urayman","boost.tiltDirection.left":"ichuq","boost.tiltDirection.right":"alliq","boost.tiltDirection.up":"hawampi","boost.whenColor":" imayna [COLOR] champa qawakuptin","boost.whenTilted":"kinraykachisqa kaptin [TILT_DIRECTION_ANY]","ev3.beepNote":"tukachi [NOTE] kaywan [TIME] wawa pachawan","ev3.buttonPressed":"butun [PORT] nitisqa?","ev3.getBrightness":"kanchiq","ev3.getDistance":"karuchan","ev3.getMotorPosition":"Kallpanchachiq [PORT] churay","ev3.motorSetPower":"Kallpanchaq [PORT] churay kallpachaykuy [POWER] %","ev3.motorTurnClockwise":"Kallpanchaq [PORT] muyurichi waklawman [TIME] wawa pachapi","ev3.motorTurnCounterClockwise":"Kallpanchaq [PORT] muyurichi kaylawman [TIME] wawa pachapi","ev3.whenBrightnessLessThan":"akchiriq kaptin < [DISTANCE]","ev3.whenButtonPressed":"butun [PORT] ñitisqa kaptin","ev3.whenDistanceLessThan":"karu kaptin < [DISTANCE]","gdxfor.getAcceleration":"utqallaman [DIRECTION]","gdxfor.getForce":"kallpa","gdxfor.getSpin":"utqayman muyuq [DIRECTION]","gdxfor.getTilt":"kuchusta chinruri [TILT]","gdxfor.isFreeFalling":"imam wichin?","gdxfor.isTilted":"chinrusqachu [TILT]?","gdxfor.pulled":"wikapasqa","gdxfor.pushed":"tamqarisqa","gdxfor.shaken":"tapsiy","gdxfor.startedFalling":"wichiyta qallarichkan","gdxfor.tiltDirectionMenu.any":"mayqimpas","gdxfor.tiltDirectionMenu.back":"hipa","gdxfor.tiltDirectionMenu.front":"chimpa","gdxfor.tiltDirectionMenu.left":"ichuq","gdxfor.tiltDirectionMenu.right":"alliq","gdxfor.turnedFaceDown":"urayman tikrasqa","gdxfor.turnedFaceUp":"anayman tikrasqa","gdxfor.whenForcePushedOrPulled":"kallpachaq musiaq kaptin [PUSH_PULL]","gdxfor.whenGesture":"imay [GESTURE]","gdxfor.whenTilted":"chinrusqa kaptin [TILT]","makeymakey.downArrow":"urayman qillqana","makeymakey.downArrowShort":"urayman","makeymakey.leftArrow":"lluqiman qillqana","makeymakey.leftArrowShort":"ichuq","makeymakey.rightArrow":"alliqman qillqana","makeymakey.rightArrowShort":"alliq","makeymakey.spaceKey":"chimpa","makeymakey.upArrow":"hanayman qillqana","makeymakey.upArrowShort":"hawampi","makeymakey.whenKeyPressed":"imayna [KEY] tikla ñitisqa","makeymakey.whenKeysPressedInOrder":"Hayka [SEQUENCE] nitisqa hukllamanta","microbit.buttonsMenu.any":"mayqimpas","microbit.clearDisplay":"picahay qawanata","microbit.defaultTextToDisplay":"Rimaykullayki!","microbit.displaySymbol":"qawana [MATRIX]","microbit.displayText":"qillqata qawarina [TEXT]","microbit.gesturesMenu.jumped":"pawarqun","microbit.gesturesMenu.moved":"musuqmi","microbit.gesturesMenu.shaken":"tapsiy","microbit.isButtonPressed":"[BTN] butun ñitisqa?","microbit.isTilted":"chinrusqa [DIRECTION]?","microbit.pinStateMenu.off":"wañuy","microbit.pinStateMenu.on":"rikchari","microbit.tiltAngle":"kuchusta chinru [DIRECTION]","microbit.tiltDirectionMenu.any":"mayqimpas","microbit.tiltDirectionMenu.back":"kutiy","microbit.tiltDirectionMenu.front":"chimpa","microbit.tiltDirectionMenu.left":"ichuq","microbit.tiltDirectionMenu.right":"alliq","microbit.whenButtonPressed":"imayna [BTN] butun ñitisqa","microbit.whenGesture":"imay [GESTURE]","microbit.whenPinConnected":"imayna tipi [PIN] tupachisqa","microbit.whenTilted":"chinrusqa kaptin [DIRECTION]","music.categoryName":"Taki","music.changeTempo":"tikray pachata [TEMPO]","music.drumBass":"(2) tinya","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) Hit-Hat wichkasqa","music.drumConga":"(14) Konqa","music.drumCowbell":"(11) Kowbell","music.drumCrashCymbal":"(4) Platillo Tupachisqa ","music.drumCuica":"(18) Kuika","music.drumGuiro":"(16) Quiru","music.drumHandClap":"(8) Maqui Taqllay","music.drumOpenHiHat":"(5) Hit-Hat Kichasqa","music.drumSideStick":"(3) tamburpa waqtan takasqa","music.drumSnare":"(1) Tambur","music.drumTambourine":"(7) Sunaha","music.drumTriangle":"(12) Chinisku","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10)Kullu tuqyaq","music.getTempo":"pacha","music.instrumentBass":"(6) Bahu","music.instrumentBassoon":"(14) Bassuun","music.instrumentCello":"(8) Cello","music.instrumentChoir":"(15) Takiri","music.instrumentClarinet":"(10) Klariniti","music.instrumentElectricGuitar":"(5) Qitarra iliktriku","music.instrumentElectricPiano":"(2) Piyanu iliktriku","music.instrumentFlute":"(12)Pinkuyllu","music.instrumentGuitar":"(4)Quitarra","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17)kahita Takiq","music.instrumentOrgan":"(3) Urqanu","music.instrumentPiano":"(1)piyanu","music.instrumentPizzicato":"(7) Pisikato","music.instrumentSaxophone":"(11) Sakso","music.instrumentSteelDrum":"(18) tinya latamanta","music.instrumentSynthLead":"(20) Synth Lead nisqan","music.instrumentSynthPad":"(21) Synth Pad nisqan","music.instrumentTrombone":"(9) Trumbun","music.instrumentVibraphone":"(16)wibraphuni","music.instrumentWoodenFlute":"(13) Qina","music.midiPlayDrumForBeats":"tukay tambur [DRUM] chaypaq [BEATS] luqluqyaqkuna","music.midiSetInstrument":"tiquy inkilltupa [INSTRUMENT] ","music.playDrumForBeats":"tukay tambur [DRUM] chaypaq [BEATS] luqluqyaqkuna","music.playNoteForBeats":"pukllayta tukay [NOTE] chayman [BEATS] luqluqyaqkuna","music.restForBeats":" samachiy [BEATS] luqluqyaqkuna","music.setInstrument":"tiquy inkilltupa [INSTRUMENT] ","music.setTempo":"churay pachata [TEMPO]","pen.categoryName":"qillqay kaspi","pen.changeColorParam":"tikray qillqay kaspi [COLOR_PARAM] rayku [VALUE]","pen.changeHue":"tikray qillqay kaspi kulur-rayku [HUE]","pen.changeShade":"tikray qillqay llantunninta [SHADE]","pen.changeSize":"tikray qillqay hatunninta [SIZE]","pen.clear":"llapanta pichay","pen.colorMenu.brightness":"kanchiq","pen.colorMenu.color":"kulur","pen.colorMenu.saturation":"Llimpi yuraqchay","pen.colorMenu.transparency":"chuyarayaq","pen.penDown":"qillqana uraypi","pen.penUp":"qillqay hanaypi","pen.setColor":"tikray qillqay kaspi Llimpiy-rayku [COLOR]","pen.setColorParam":"churay qillqay kaspita [COLOR_PARAM] rayku [VALUE]","pen.setHue":"churaykuy llimpinman qillqaq kaspita [HUE]","pen.setShade":"churaykuy qillqapa llantuyninta [SHADE]","pen.setSize":"churay qillqay kaspipa hatuyninta [SIZE]","pen.stamp":"sello nisqan","text2speech.alto":"Sayachiy","text2speech.categoryName":"Qillqa Rimay ","text2speech.defaultTextToSpeak":"imaynalla ","text2speech.giant":"hatunkaray","text2speech.kitten":"misicha","text2speech.setLanguageBlock":"churay simiman [LANGUAGE] ","text2speech.setVoiceBlock":"churay Rimaqman [VOICE]","text2speech.speakAndWaitBlock":"rimay [WORDS]","text2speech.squeak":"qapariy","text2speech.tenor":"tinur","translate.categoryName":"Tikray","translate.defaultTextToTranslate":"imaynalla ","translate.translateBlock":"tikray [WORDS] chaymanta [LANGUAGE]","translate.viewerLanguage":"Simi","videoSensing.categoryName":"Tarisqa Qawana","videoSensing.direction":"maypi","videoSensing.motion":"kuyuchiy","videoSensing.off":"wañuy","videoSensing.on":"rikchari","videoSensing.onFlipped":"tikray","videoSensing.setVideoTransparency":"churay vidio chhuyaqniman [TRANSPARENCY]","videoSensing.sprite":"Sprite","videoSensing.stage":"Chimpa qaway","videoSensing.videoOn":"widiu [ATTRIBUTE] in [SUBJECT]","videoSensing.videoToggle":"muyuchiy widiuta [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"hayka widiu muyuptin > [REFERENCE]","wedo2.getDistance":"karuchan","wedo2.getTiltAngle":"Kuchuq kinraychasqa [TILT_DIRECTION]","wedo2.isTilted":"kinray [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"chayna puniy","wedo2.motorDirection.forward":"kayna puniy","wedo2.motorDirection.reverse":"qipaman puriy","wedo2.motorId.a":"kallpachaq A","wedo2.motorId.all":"llapan kallpachaqkuna","wedo2.motorId.b":"kallpachaq B","wedo2.motorId.default":"kallpanchachiq","wedo2.motorOff":"muyuq [MOTOR_ID] wañuchisqa","wedo2.motorOn":"qallarichiy [MOTOR_ID]","wedo2.motorOnFor":"qallariy [MOTOR_ID] icha [DURATION] siqundupi","wedo2.playNoteFor":"qillqay luqyay [NOTE] icha [DURATION] siqundupi","wedo2.setLightHue":"akchiqpa llimpinta churay [HUE]","wedo2.setMotorDirection":"rinayta churaykuy [MOTOR_ID] inpi [MOTOR_DIRECTION]","wedo2.startMotorPower":"churaykuy [MOTOR_ID] kallapachiqninta [POWER]","wedo2.tiltDirection.any":"mayqimpas","wedo2.tiltDirection.down":"urayman","wedo2.tiltDirection.left":"ichuq","wedo2.tiltDirection.right":"alliq","wedo2.tiltDirection.up":"hawampi","wedo2.whenDistance":"karu kaptin [OP] [REFERENCE]","wedo2.whenTilted":"kinraykachisqa kaptin [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"kulur","paint.paintEditor.saturation":"Llimpi yuraqchay","paint.paintEditor.brightness":"kanchiq","paint.paintEditor.costume":"Pacha","paint.paintEditor.group":"Huñusqa","paint.paintEditor.ungroup":"Rakisqa","paint.paintEditor.undo":"ruraray","paint.paintEditor.redo":"kutipay","paint.paintEditor.forward":"Ñawpaqman","paint.paintEditor.backward":"Qipaman","paint.paintEditor.front":"Chimpa","paint.paintEditor.back":"Hipaman","paint.paintEditor.more":"aswan","paint.modeTools.brushSize":"Hatun","paint.modeTools.eraserSize":"Hatun Pichana","paint.modeTools.copy":"kupyay","paint.modeTools.paste":"Laqay","paint.modeTools.delete":"Pichay","paint.modeTools.curved":"Muyo","paint.modeTools.pointed":"Tupsuyaq","paint.modeTools.thickness":"Rakuqnin","paint.modeTools.flipHorizontal":"Kinrayman Tikrasqa","paint.modeTools.flipVertical":"Sayaqman Tikrasqa","paint.modeTools.filled":"Huntasqa","paint.modeTools.outlined":"Sikwiy","paint.paintEditor.bitmap":"Tikrayay MapaBitman","paint.paintEditor.vector":"Tikray Vikturman","paint.paintEditor.fill":"huntay","paint.paintEditor.stroke":"Muyuriqnin","paint.brushMode.brush":"Llimpinapaq","paint.eraserMode.eraser":"Pichana","paint.fillMode.fill":"Huntasqa","paint.lineMode.line":"Sikwi","paint.ovalMode.oval":"Muyu","paint.rectMode.rect":"Tawa Kuchuyuq","paint.reshapeMode.reshape":"Allichana","paint.roundedRectMode.roundedRect":"Muyuq hina Tawa Kuchu","paint.selectMode.select":"Akllasqa","paint.textMode.text":"Qillqay","paint.colorPicker.swap":"Hukniraqchay"},"sw":{"gui.alerts.tryAgain":"Jaribu Tena","gui.alerts.download":"Pakua","gui.connection.reconnect":"Jaribu Tena Kuunganisha","gui.backpack.costumeLabel":"mtindo","gui.backpack.soundLabel":"sauti","gui.backpack.scriptLabel":"hati","gui.backpack.spriteLabel":"kihusika","gui.backpack.header":"Mkoba","gui.backpack.errorBackpack":"Kosa limetokea kupakia mkoba","gui.backpack.loadingBackpack":"Inapakia...","gui.backpack.more":"Zaidi","gui.backpack.emptyBackpack":"Hakuna kitu kwenye mkoba","gui.unsupportedBrowser.label":"Kivinjari hakikubaliwi","gui.cards.all-tutorials":"Mafunzo","gui.cards.shrink":"Punguza Ukubwa","gui.cards.expand":"Panua","gui.cards.close":"Funga","gui.cards.more-things-to-try":"Vitu zaidi vya kujaribu!","gui.cards.see-more":"Tazama zaidi","gui.comingSoon.message1":"Tunaishughulikia {emoji}","gui.comingSoon.message2":"Inakuja hivi karibuni...","gui.comingSoon.message3":"Tunaishughulikia {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Hakuna vifaa vilivyopatikana","gui.connection.auto-scanning.prescan":"Kuwa na kifaa chako karibu, kisha anza kutafuta.","gui.connection.auto-scanning.pressbutton":"Bonyeza kitufe kwenye kifaa chako.","gui.connection.auto-scanning.start-search":"Anza Kutafuta","gui.connection.connecting-searchbutton":"Inatafuta...","gui.connection.auto-scanning.try-again":"Jaribu tena","gui.connection.connected":"Imeunganishwa","gui.connection.disconnect":"Tenganisha","gui.connection.go-to-editor":"Enda kwa Kihariri","gui.connection.connecting-cancelbutton":"Inaunganisha...","gui.connection.error.errorMessage":"Inaonekana kama kuna kitu kimeenda vibaya.","gui.connection.error.tryagainbutton":"Jaribu tena","gui.connection.error.helpbutton":"Usaidizi","gui.connection.peripheral-name-label":"Jina la kifaa","gui.connection.connect":"Unganisha","gui.connection.scanning.lookingforperipherals":"Inatafuta vifaa","gui.connection.scanning.noPeripheralsFound":"Hakuna vifaa vilivyopatikana","gui.connection.scanning.instructions":"Chagua kifaa chako kwenye orodha hapo juu.","gui.connection.search":"Pakia Mpya","gui.connection.unavailable.installscratchlink":"Hakikisha umesakinisha Scratch Link na inaendesha","gui.connection.unavailable.enablebluetooth":"Angalia kuwa muunganisho wa Bluetooth umewezeshwa","gui.connection.unavailable.tryagainbutton":"Jaribu tena","gui.connection.unavailable.helpbutton":"Usaidizi","gui.controls.go":"Anza","gui.controls.stop":"Komesha","gui.crashMessage.label":"Kuna kitu kimeenda vibaya.","gui.crashMessage.errorNumber":"Kosa lako lilihifadhiwa kutumia kitambulisho {errorId}","gui.crashMessage.reload":"Pakia tena","gui.customProcedures.myblockModalTitle":"Unda Bloku","gui.customProcedures.addAnInputNumberText":"Ongeza uingizaji","gui.customProcedures.numberTextType":"nambari ama maandishi","gui.customProcedures.addAnInputBoolean":"Ongeza uingizaji","gui.customProcedures.booleanType":"boolean","gui.customProcedures.addALabel":"Ongeza lebo","gui.customProcedures.runWithoutScreenRefresh":"Endesha bila kupakia skrini","gui.customProcedures.cancel":"Katisha","gui.customProcedures.ok":"Sawa","gui.SpriteInfo.direction":"Mwelekeo","gui.directionPicker.rotationStyles.allAround":"Pande Zote","gui.directionPicker.rotationStyles.leftRight":"Kushoto/Kulia","gui.directionPicker.rotationStyles.dontRotate":"Isizunguke","gui.gui.addExtension":"Ongeza Kiendelezi","gui.gui.codeTab":"Msimbo","gui.gui.backdropsTab":"Mandhari Za Nyuma","gui.gui.costumesTab":"Mitindo","gui.gui.soundsTab":"Sauti","gui.extensionLibrary.comingSoon":"Inakuja Hivi Karibuni","gui.extensionLibrary.requires":"Mahitaji","gui.extensionLibrary.collaboration":"Kushirikiana na","gui.library.filterPlaceholder":"Tafuta","gui.library.allTag":"Kila kitu","gui.loader.headline":"Inapakia Mradi","gui.loader.creating":"Inaunda Mradi","gui.authorInfo.byUser":"ni mradi wa {username}","gui.menuBar.seeProjectPage":"Tazama Ukurasa Wa Mradi","gui.menuBar.LanguageSelector":"kichaguzi cha lugha","gui.menuBar.tutorialsLibrary":"Mafunzo","gui.menuBar.restoreSprite":"Rejesha Kihusika","gui.menuBar.restoreSound":"Rejesha Sauti","gui.menuBar.restoreCostume":"Rejesha Mtindo","gui.menuBar.restore":"Rejesha","gui.menuBar.saveNow":"Hifadhi sasa","gui.menuBar.saveAsCopy":"Hifadhi kama nakala","gui.menuBar.remix":"Geuza","gui.menuBar.new":"Mpya","gui.menuBar.file":"Faili","gui.menuBar.downloadToComputer":"Hifadhi kwa kompyuta yako","gui.menuBar.edit":"Hariri","gui.menuBar.turboModeOff":"Zima Uharaka","gui.menuBar.turboModeOn":"Washa Uharaka","gui.gui.projectTitlePlaceholder":"Kichwa cha mradi hapa","gui.menuBar.isShared":"Imesambazwa","gui.menuBar.share":"Sambaza","gui.modal.help":"Usaidizi","gui.modal.back":"Rudi","gui.monitor.listMonitor.empty":"(tupu)","gui.monitor.listMonitor.listLength":"urefu {length}","gui.monitor.contextMenu.default":"maonyesho ya kawaida","gui.monitor.contextMenu.large":"maonyesho kubwa","gui.monitor.contextMenu.slider":"kitelezi","gui.monitor.contextMenu.sliderRange":"badilisha kiwango cha kitelezi","gui.monitor.contextMenu.import":"ingiza","gui.monitor.contextMenu.export":"hamisha","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Cheza","gui.playButton.stop":"Komesha","gui.gui.variableScopeOptionAllSprites":"Kwa vihusika vyote","gui.gui.variableScopeOptionSpriteOnly":"Kwa kihusika hiki pekee","gui.gui.cloudVariableOption":"Kibadilika cha mtandaoni (kinachohifadhiwa kwa seva)","gui.gui.variablePromptAllSpritesMessage":"Kibadilika hiki kitapatikana kwa vihusika vyote.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Katisha","gui.prompt.ok":"Sawa","gui.playbackStep.stopMsg":"Komesha","gui.playbackStep.playMsg":"Cheza","gui.playbackStep.loadingMsg":"Inapakia...","gui.playbackStep.saveMsg":"Hifadhi","gui.playbackStep.reRecordMsg":"Rekodi tena","gui.recordModal.title":"Rekodi Sauti","gui.recordingStep.beginRecord":"Anza kurekodi kwa kubonyeza kitufe hapa chini","gui.recordingStep.permission":"{arrow}Tunahitaji ruhusa yako kutumia maikrofoni yako","gui.recordingStep.stop":"Komesha kurekodi","gui.recordingStep.record":"Rekodi","gui.sliderModal.min":"Thamani ya chini","gui.sliderModal.max":"Thamani ya juu","gui.sliderModal.title":"Badilisha kiwango cha kitelezi","gui.sliderPrompt.cancel":"Katisha","gui.sliderPrompt.ok":"Sawa","gui.soundEditor.sound":"Sauti","gui.soundEditor.play":"Cheza","gui.soundEditor.stop":"Komesha","gui.soundEditor.copy":"Nakala","gui.soundEditor.paste":"Bandika","gui.soundEditor.copyToNew":"Nakili Kama Mpya","gui.soundEditor.delete":"Futa","gui.soundEditor.save":"Hifadhi","gui.soundEditor.undo":"Ondoa","gui.soundEditor.redo":"Rudia","gui.soundEditor.faster":"Haraka","gui.soundEditor.slower":"Polepole","gui.soundEditor.echo":"Mwangwi","gui.soundEditor.robot":"Roboti","gui.soundEditor.louder":"Ongeza Kiasi ya Sauti","gui.soundEditor.softer":"Punguza Kiasi ya Sauti","gui.soundEditor.reverse":"Upande Mwingine","gui.soundEditor.fadeOut":"Fifia Sauti","gui.soundEditor.fadeIn":"Fufua Sauti","gui.soundEditor.mute":"Zima Sauti","gui.SpriteInfo.spritePlaceholder":"Jina","gui.SpriteInfo.sprite":"Kihusika","gui.SpriteInfo.show":"Onyesha","gui.SpriteInfo.size":"Ukubwa","gui.spriteSelectorItem.contextMenuDuplicate":"nakili bloku","gui.spriteSelectorItem.contextMenuExport":"hamisha","gui.spriteSelectorItem.contextMenuDelete":"futa","gui.spriteSelector.addSpriteFromLibrary":"Chagua Kihusika","gui.spriteSelector.addSpriteFromPaint":"Chora","gui.spriteSelector.addSpriteFromSurprise":"Kihusika Chochote","gui.spriteSelector.addSpriteFromFile":"Pakia Kihusika","gui.stageHeader.stageSizeLarge":"Badilisha kwa jukwaa kubwa","gui.stageHeader.stageSizeSmall":"Badilisha kwa jukwaa ndogo","gui.stageHeader.stageSizeFull":"Ingiza hali kamili ya skrini","gui.stageHeader.stageSizeUnFull":"Toka hali kamili ya skrini","gui.stageHeader.fullscreenControl":"Udhibiti Kamili Wa Skrini","gui.spriteSelector.addBackdropFromLibrary":"Chagua Mandhari Ya Nyuma","gui.stageSelector.addBackdropFromPaint":"Chora","gui.stageSelector.addBackdropFromSurprise":"Jukwaa Lolote","gui.stageSelector.addBackdropFromFile":"Pakia Mandhari Ya Nyuma","gui.stageSelector.stage":"Jukwaa","gui.stageSelector.backdrops":"Mandhari Za Nyuma","gui.telemetryOptIn.label":"Ripoti takwimu za kuboresha Scratch","gui.telemetryOptIn.body1":"Timu ya Scratch inataka kuelewa jinsi Scratch inayotumika duniani kote. Ili kusaidia msaada huu, unaweza kuruhusu Scratch kutuma habari ya utumiaji kwa Timu ya Scratch.","gui.telemetryOptIn.body2":"Habari tunayokusanya ni pamoja na uteuzi wa lugha, utumiaji wa bloku, na matukio kadhaa kama kuhifadhi, kupakia, na kupakua mradi. Hatukusanyi habari yoyote ya kibinafsi. Tafadhali tazama {privacyPolicyLink} yetu kwa habari zaidi.","gui.telemetryOptIn.privacyPolicyLink":"Sera ya Faragha","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Harakisha","gui.webglModal.label":"Kivinjari chako hakikubali WebGL","gui.webglModal.webgllink":"haikubali WebGL","gui.costumeLibrary.chooseABackdrop":"Chagua Mandhari Ya Nyuma","gui.costumeLibrary.chooseACostume":"Chagua Mtindo","gui.costumeTab.addBackdropFromLibrary":"Chagua Mandhari Ya Nyuma","gui.costumeTab.addCostumeFromLibrary":"Chagua Mtindo","gui.costumeTab.addBlankCostume":"Chora","gui.costumeTab.addSurpriseCostume":"Mtindo Wowote","gui.costumeTab.addFileBackdrop":"Pakia Mandhari Ya Nyuma","gui.costumeTab.addFileCostume":"Pakia Mtindo","gui.extensionLibrary.chooseAnExtension":"Chagua Kiendelezi","gui.extensionLibrary.extensionUrl":"Ingiza kiungo cha kiendelezi","gui.monitors.importListColumnPrompt":"Safu gani inapaswa kutumika (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Haikuweza kuanza kurekodi","gui.soundLibrary.chooseASound":"Chagua Sauti","gui.soundTab.fileUploadSound":"Pakia Sauti","gui.soundTab.surpriseSound":"Sauti Yoyote","gui.soundTab.recordSound":"Rekodi","gui.soundTab.addSoundFromLibrary":"Chagua Sauti","gui.spriteLibrary.chooseASprite":"Chagua Kihusika","gui.tipsLibrary.tutorials":"Chagua Funzo","gui.alerts.createsuccess":"Mradi mpya umeundwa.","gui.alerts.createcopysuccess":"Mradi umehifadhiwa kama nakala.","gui.alerts.createremixsuccess":"Mradi umehifadhiwa kama kigeuzi.","gui.alerts.creating":"Inaunda mradi mpya...","gui.alerts.creatingCopy":"Inanakili mradi…","gui.alerts.creatingRemix":"Inatengeneza kigeuzi cha mradi...","gui.alerts.creatingError":"Haikuweza kuunda mradi. Tafadhali jaribu tena!","gui.alerts.savingError":"Mradi hauwezi kuhifadhiwa","gui.alerts.savesuccess":"Mradi umehifadhiwa.","gui.alerts.saving":"Mradi unahifadhiwa...","gui.alerts.cloudInfo":"Tafadhali kumbuka, vibadilika vya mtandaoni vinakubali nambari tu, sio herufi au alama. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Pata maelezo zaidi.","gui.alerts.importing":"Unaingizwa...","gui.defaultProject.variable":"kibadilika changu","gui.extension.music.name":"Muziki","gui.extension.music.description":"Cheza vyombo vya muziki na ngoma.","gui.extension.pen.name":"Kalamu","gui.extension.pen.description":"Chora kutumia vihusika vyako.","gui.extension.videosensing.name":"Uhisi Wa Video","gui.extension.videosensing.description":"Hisi mwendo kutumia kamera.","gui.extension.text2speech.name":"Maandishi kwa Matamshi","gui.extension.text2speech.description":"Fanya miradi yako izungumze.","gui.extension.translate.name":"Tafsiri","gui.extension.translate.description":"Tafsiri maandishi katika lugha nyingi.","gui.extension.makeymakey.description":"Badilisha kitu chochote kuwa kitufe","gui.extension.microbit.description":"Unganisha miradi yako na dunia.","gui.extension.microbit.connectingMessage":"Inaunganisha","gui.extension.ev3.description":"Jenga roboti inayounganika na mambo mengineyo.","gui.extension.ev3.connectingMessage":"Inaunganisha. Hakikisha kuwa pini kwenye EV3 yako ni 1234.","gui.extension.boost.description":"Fufua roboti.","gui.extension.boost.connectingMessage":"Inaunganisha","gui.extension.wedo2.description":"Jenga kutumia mota na vihisia.","gui.extension.wedo2.connectingMessage":"Inaunganisha","gui.extension.gdxfor.description":"Hisi msukumo, mvuto, mwendo na mzunguko.","gui.extension.gdxfor.connectingMessage":"Inaunganisha","gui.libraryTags.all":"Kila Kitu","gui.libraryTags.animals":"Wanyama","gui.libraryTags.dance":"Dansi","gui.libraryTags.effects":"Athari","gui.libraryTags.fantasy":"Fantasia","gui.libraryTags.fashion":"Mtindo","gui.libraryTags.food":"Chakula","gui.libraryTags.indoors":"Ndani Ya Nyumba","gui.libraryTags.loops":"Vitanzi","gui.libraryTags.music":"Muziki","gui.libraryTags.notes":"Noti","gui.libraryTags.outdoors":"Nje","gui.libraryTags.patterns":"Ruwaza","gui.libraryTags.people":"Watu","gui.libraryTags.percussion":"Vyombo Vya Kugongwa","gui.libraryTags.space":"Angani","gui.libraryTags.sports":"Spoti","gui.libraryTags.underwater":"Chini Ya Maji","gui.libraryTags.voice":"Sauti","gui.libraryTags.wacky":"Kuchekesha","gui.libraryTags.animation":"Kibonzo","gui.libraryTags.art":"Sanaa","gui.libraryTags.games":"Michezo","gui.libraryTags.stories":"Hadithi","gui.libraryTags.letters":"Herufi","gui.opcodeLabels.direction":"mwelekeo","gui.opcodeLabels.xposition":"Nafasi ya x","gui.opcodeLabels.yposition":"Nafasi ya y","gui.opcodeLabels.size":"ukubwa","gui.opcodeLabels.costumename":"jina la mtindo","gui.opcodeLabels.costumenumber":"nambari ya mtindo","gui.opcodeLabels.backdropname":"jina la mandhari ya nyuma","gui.opcodeLabels.backdropnumber":"nambari ya mandhari ya nyuma","gui.opcodeLabels.volume":"kiasi ya sauti","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"jibu","gui.opcodeLabels.loudness":"ukubwa wa sauti","gui.opcodeLabels.username":"jina la mtumiaji","gui.opcodeLabels.year":"mwaka","gui.opcodeLabels.month":"mwezi","gui.opcodeLabels.date":"tarehe","gui.opcodeLabels.dayofweek":"siku ya wiki","gui.opcodeLabels.hour":"saa","gui.opcodeLabels.minute":"dakika","gui.opcodeLabels.second":"sekunde","gui.opcodeLabels.timer":"kipima muda","gui.sharedMessages.backdrop":"mandhari ya nyuma{index}","gui.sharedMessages.costume":"mtindo{index}","gui.sharedMessages.sprite":"Kihusika{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Badilisha yaliyomo kwenye mradi wa sasa?","gui.sharedMessages.loadFromComputerTitle":"Pakisha kutoka kwa kompyuta yako","boost.color.any":"rangi yoyote","boost.color.black":"nyeusi","boost.color.blue":"buluu","boost.color.green":"kijani","boost.color.red":"nyekundu","boost.color.white":"nyeupe","boost.color.yellow":"manjano","boost.getMotorPosition":"nafasi ya mota [MOTOR_REPORTER_ID]","boost.getTiltAngle":"pembe ya mwinamo [TILT_DIRECTION]","boost.motorDirection.backward":"njia hiyo","boost.motorDirection.forward":"njia hii","boost.motorDirection.reverse":"pindua","boost.motorOff":"zima mota [MOTOR_ID]","boost.motorOn":"washa mota [MOTOR_ID]","boost.motorOnFor":"washa mota [MOTOR_ID] kwa sekunde [DURATION]","boost.motorOnForRotation":"washa mota [MOTOR_ID] kwa mizunguko [ROTATION]","boost.seeingColor":"tofali la [COLOR] inaonekana?","boost.setLightHue":"weka rangi ya mwangaza kuwa [HUE]","boost.setMotorDirection":"weka mwelekeo wa mota [MOTOR_ID] kuwa [MOTOR_DIRECTION]","boost.setMotorPower":"weka kasi ya mota [MOTOR_ID] kuwa [POWER] %","boost.tiltDirection.any":"mwelekeo wowote","boost.tiltDirection.down":"chini","boost.tiltDirection.left":"kushoto","boost.tiltDirection.right":"kulia","boost.tiltDirection.up":"juu","boost.whenColor":"tofali la [COLOR] linapoonekana","boost.whenTilted":"inapoinamishwa [TILT_DIRECTION_ANY]","ev3.beepNote":"cheza noti [NOTE] kwa sekunde [TIME]","ev3.buttonPressed":"kitufe cha [PORT] kimebonyezwa?","ev3.getBrightness":"mng\'aro","ev3.getDistance":"umbali","ev3.getMotorPosition":"nafasi ya mota [PORT]","ev3.motorSetPower":"weka nguvu ya mota [PORT] kuwa [POWER] %","ev3.motorTurnClockwise":"mota [PORT] kuzunguka hivi kwa sekunde [TIME]","ev3.motorTurnCounterClockwise":"mota [PORT] kuzunguka hivyo kwa sekunde [TIME]","ev3.whenBrightnessLessThan":"wakati mng\'aro < [DISTANCE]","ev3.whenButtonPressed":"kitufe [PORT] kinapobonyezwa","ev3.whenDistanceLessThan":"mwelekeo unapokuwa < [DISTANCE]","gdxfor.getAcceleration":"kasi [DIRECTION]","gdxfor.getForce":"nguvu","gdxfor.getSpin":"kasi ya mzunguko [DIRECTION]","gdxfor.getTilt":"pembe ya mwinamo [TILT]","gdxfor.isFreeFalling":"inaanguka?","gdxfor.isTilted":"imeinamishwa [TILT]?","gdxfor.pulled":"kinapovutwa","gdxfor.pushed":"kinaposukumwa","gdxfor.shaken":"kutikiswa","gdxfor.startedFalling":"kuanza kuanguka","gdxfor.tiltDirectionMenu.any":"mwelekeo wowote","gdxfor.tiltDirectionMenu.back":"nyuma","gdxfor.tiltDirectionMenu.front":"mbele","gdxfor.tiltDirectionMenu.left":"kushoto","gdxfor.tiltDirectionMenu.right":"kulia","gdxfor.turnedFaceDown":"kupinduka juu chini","gdxfor.turnedFaceUp":"kupinduka mbele juu","gdxfor.whenForcePushedOrPulled":"kihisia cha nguvu [PUSH_PULL]","gdxfor.whenGesture":"wakati [GESTURE]","gdxfor.whenTilted":"inapoinamishwa [TILT]","makeymakey.downArrow":"kishale cha chini","makeymakey.downArrowShort":"chini","makeymakey.leftArrow":"kishale cha kushoto","makeymakey.leftArrowShort":"kushoto","makeymakey.rightArrow":"kishale cha kulia","makeymakey.rightArrowShort":"kulia","makeymakey.spaceKey":"nafasi","makeymakey.upArrow":"kishale cha juu","makeymakey.upArrowShort":"juu","makeymakey.whenKeyPressed":"kitufe [KEY] kinapobonyezwa","makeymakey.whenKeysPressedInOrder":"vitufe vinapobonyezwa kwa utaratibu wa [SEQUENCE]","microbit.buttonsMenu.any":"mwelekeo wowote","microbit.clearDisplay":"futa skrini","microbit.defaultTextToDisplay":"Hello!","microbit.displaySymbol":"onyesha [MATRIX]","microbit.displayText":"onyesha maandishi [TEXT]","microbit.gesturesMenu.jumped":"inaporushwa","microbit.gesturesMenu.moved":"inaposongwa","microbit.gesturesMenu.shaken":"inapotikiswa","microbit.isButtonPressed":"kitufe [BTN] kimebonyezwa?","microbit.isTilted":"imeinamishwa [DIRECTION]?","microbit.pinStateMenu.off":"zima","microbit.pinStateMenu.on":"washa","microbit.tiltAngle":"pembe ya mwinamo [DIRECTION]","microbit.tiltDirectionMenu.any":"mwelekeo wowote","microbit.tiltDirectionMenu.back":"nyuma","microbit.tiltDirectionMenu.front":"mbele","microbit.tiltDirectionMenu.left":"kushoto","microbit.tiltDirectionMenu.right":"kulia","microbit.whenButtonPressed":"kitufe [BTN] kinapobonyezwa","microbit.whenGesture":"wakati [GESTURE]","microbit.whenPinConnected":"pini [PIN] inapounganishwa","microbit.whenTilted":"inapoinamishwa [DIRECTION]","music.categoryName":"Muziki","music.changeTempo":"badilisha tempo kwa [TEMPO]","music.drumBass":"(2) Ngoma Ya Bass","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) Closed Hi-Hat","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Cowbell","music.drumCrashCymbal":"(4) Crash Cymbal","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Makofi","music.drumOpenHiHat":"(5) Open Hi-Hat","music.drumSideStick":"(3) Vijiti Vya Ngoma","music.drumSnare":"(1) Ngoma ya Snare","music.drumTambourine":"(7) Manyanga","music.drumTriangle":"(12) Ala ya Pembetatu","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Mbao","music.getTempo":"tempo","music.instrumentBass":"(6) Bass","music.instrumentBassoon":"(14) Basuni","music.instrumentCello":"(8) Cello","music.instrumentChoir":"(15) Kwaya","music.instrumentClarinet":"(10) Klarineti","music.instrumentElectricGuitar":"(5) Gitaa La Umeme","music.instrumentElectricPiano":"(2) Piano Ya Umeme","music.instrumentFlute":"(12) Filimbi","music.instrumentGuitar":"(4) Gitaa","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Sanduku La Muziki","music.instrumentOrgan":"(3) Kinanda Cha Filimbi","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Fidla","music.instrumentSaxophone":"(11) Saksafoni","music.instrumentSteelDrum":"(18) Ngoma Ya Chuma","music.instrumentSynthLead":"(20) Synth Lead","music.instrumentSynthPad":"(21) Synth Pad","music.instrumentTrombone":"(9) Tromboni","music.instrumentVibraphone":"(16) Vibraphone","music.instrumentWoodenFlute":"(13) Zumari","music.midiPlayDrumForBeats":"cheza ngoma [DRUM] kwa midundo [BEATS]","music.midiSetInstrument":"weka ala ya muziki kuwa [INSTRUMENT]","music.playDrumForBeats":"cheza ngoma [DRUM] kwa midundo [BEATS]","music.playNoteForBeats":"cheza noti [NOTE] kwa midundo [BEATS]","music.restForBeats":"pumzika kwa midundo [BEATS]","music.setInstrument":"weka ala ya muziki kuwa [INSTRUMENT]","music.setTempo":"weka tempo kuwa [TEMPO]","pen.categoryName":"Kalamu","pen.changeColorParam":"badilisha [COLOR_PARAM] kwa [VALUE]","pen.changeHue":"badilisha rangi ya kalamu kwa [HUE]","pen.changeShade":"badilisha namna ya rangi ya kalamu kwa [SHADE]","pen.changeSize":"badilisha ukubwa wa kalamu kwa [SIZE]","pen.clear":"futa yote","pen.colorMenu.brightness":"mng\'aro","pen.colorMenu.color":"rangi","pen.colorMenu.saturation":"kiasi ya rangi","pen.colorMenu.transparency":"upenyeko wa nuru","pen.penDown":"kalamu chini","pen.penUp":"kalamu juu","pen.setColor":"weka rangi ya kalamu kuwa [COLOR]","pen.setColorParam":"weka [COLOR_PARAM] kuwa [VALUE]","pen.setHue":"weka rangi ya kalamu kuwa [HUE]","pen.setShade":"weka namna ya rangi ya kalamu kuwa [SHADE]","pen.setSize":"weka ukubwa wa kalamu kuwa [SIZE]","pen.stamp":"muhuri","text2speech.alto":"alto","text2speech.categoryName":"Maandishi kwa Matamshi","text2speech.defaultTextToSpeak":"habari","text2speech.giant":"jitu","text2speech.kitten":"paka","text2speech.setLanguageBlock":"weka lugha kuwa [LANGUAGE]","text2speech.setVoiceBlock":"weka sauti kuwa [VOICE]","text2speech.speakAndWaitBlock":"sema [WORDS]","text2speech.squeak":"squeak","text2speech.tenor":"tenor","translate.categoryName":"Tafsiri","translate.defaultTextToTranslate":"habari","translate.translateBlock":"tafsiri [WORDS] hadi [LANGUAGE]","translate.viewerLanguage":"lugha","videoSensing.categoryName":"Uhisi Wa Video","videoSensing.direction":"mwelekeo","videoSensing.motion":"mwendo","videoSensing.off":"zima","videoSensing.on":"washa","videoSensing.onFlipped":"ikipinduliwa","videoSensing.setVideoTransparency":"weka upenyeko wa nuru kuwa [TRANSPARENCY]","videoSensing.sprite":"kihusika","videoSensing.stage":"jukwaa","videoSensing.videoOn":"[ATTRIBUTE] wa video uwe kwa [SUBJECT]","videoSensing.videoToggle":"video [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"wakati mwendo wa video > [REFERENCE]","wedo2.getDistance":"umbali","wedo2.getTiltAngle":"pembe ya mwinamo [TILT_DIRECTION]","wedo2.isTilted":"imeinamishwa [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"hivyo","wedo2.motorDirection.forward":"hivi","wedo2.motorDirection.reverse":"upande mwingine","wedo2.motorId.a":"mota A","wedo2.motorId.all":"mota zote","wedo2.motorId.b":"mota B","wedo2.motorId.default":"mota","wedo2.motorOff":"zima [MOTOR_ID]","wedo2.motorOn":"washa [MOTOR_ID]","wedo2.motorOnFor":"washa [MOTOR_ID] kwa sekunde [DURATION]","wedo2.playNoteFor":"cheza noti [NOTE] kwa sekunde [DURATION]","wedo2.setLightHue":"weka rangi ya mwangaza kuwa [HUE]","wedo2.setMotorDirection":"weka mwelekeo wa [MOTOR_ID] kuwa [MOTOR_DIRECTION]","wedo2.startMotorPower":"weka nguvu ya [MOTOR_ID] kuwa [POWER]","wedo2.tiltDirection.any":"mwelekeo wowote","wedo2.tiltDirection.down":"chini","wedo2.tiltDirection.left":"kushoto","wedo2.tiltDirection.right":"kulia","wedo2.tiltDirection.up":"juu","wedo2.whenDistance":"wakati mwelekeo [OP] [REFERENCE]","wedo2.whenTilted":"inapoinamishwa [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Rangi","paint.paintEditor.saturation":"Kiasi Ya Rangi","paint.paintEditor.brightness":"Mng\'aro","paint.paintEditor.costume":"Mtindo","paint.paintEditor.group":"Kusanya","paint.paintEditor.ungroup":"Toa Kwenye Kundi","paint.paintEditor.undo":"Ondoa","paint.paintEditor.redo":"Rudia","paint.paintEditor.forward":"Enda Mbele","paint.paintEditor.backward":"Rudi Nyuma","paint.paintEditor.front":"Mbele","paint.paintEditor.back":"Nyuma","paint.paintEditor.more":"Zaidi","paint.modeTools.brushSize":"Ukubwa ","paint.modeTools.eraserSize":"Ukubwa wa kifutio","paint.modeTools.copy":"Nakala","paint.modeTools.paste":"Bandika","paint.modeTools.delete":"Futa","paint.modeTools.curved":"Fanya Mzingo","paint.modeTools.pointed":"Fanya Kipeo","paint.modeTools.thickness":"Unene","paint.modeTools.flipHorizontal":"Zungusha Kwa Mlalo","paint.modeTools.flipVertical":"Zungusha Kwa Wima","paint.modeTools.filled":"Iliyojazwa","paint.modeTools.outlined":"Mstari Uliozungukwa","paint.paintEditor.bitmap":"Badilisha kuwa Bitmap","paint.paintEditor.vector":"Badilisha kuwa Vector","paint.paintEditor.fill":"Jaza Rangi","paint.paintEditor.stroke":"Mstari Wa Kuzunguka","paint.brushMode.brush":"Brashi","paint.eraserMode.eraser":"Kifutio","paint.fillMode.fill":"Jaza Rangi","paint.lineMode.line":"Mstari","paint.ovalMode.oval":"Duara","paint.rectMode.rect":"Mstatili","paint.reshapeMode.reshape":"Badilisha Umbo","paint.roundedRectMode.roundedRect":"Mstatili Uilo Na Pembe Za Mviringo","paint.selectMode.select":"Chagua","paint.textMode.text":"Maandishi","paint.colorPicker.swap":"Badilisha"},"ht":{"gui.alerts.tryAgain":"Eseye ankò","gui.alerts.download":"Telechaje","gui.connection.reconnect":"Rekonekte","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"aktè","gui.backpack.header":"Valiz lekòl","gui.backpack.errorBackpack":"Erè chajman valiz lekòl","gui.backpack.loadingBackpack":"Chajman...","gui.backpack.more":"Plis","gui.backpack.emptyBackpack":"Valiz lekòl la vid","gui.unsupportedBrowser.label":"Pa gen sipò pou navigatè sa a","gui.cards.all-tutorials":"Leson","gui.cards.shrink":"Ratresi","gui.cards.expand":"Elaji","gui.cards.close":"Fèmen","gui.cards.more-things-to-try":"Plis bagay pou w eseye !","gui.cards.see-more":"Gade plis","gui.comingSoon.message1":"Pa enkyete w, n ap travay sou li{emoji}","gui.comingSoon.message2":"Disponib Talè","gui.comingSoon.message3":"N ap travay sou li{emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Nou pa jwenn okenn aparèy","gui.connection.auto-scanning.prescan":"Mete aparèy ou la tou pre, epi kòmanse chèche","gui.connection.auto-scanning.pressbutton":"Peze bouton nan aparèy ou an.","gui.connection.auto-scanning.start-search":"Kòmanse Chèche","gui.connection.connecting-searchbutton":"L ap chèche...","gui.connection.auto-scanning.try-again":"Eseye ankò","gui.connection.connected":"Konekte","gui.connection.disconnect":"Dekonekte","gui.connection.go-to-editor":"Ale nan Editè","gui.connection.connecting-cancelbutton":"L ap konekte...","gui.connection.error.errorMessage":"Wouch, sanble yon bagay mal pase.","gui.connection.error.tryagainbutton":"Eseye ankò","gui.connection.error.helpbutton":"Èd","gui.connection.peripheral-name-label":"Non aparèy ","gui.connection.connect":"Konekte","gui.connection.scanning.lookingforperipherals":"L ap chèche aparèy","gui.connection.scanning.noPeripheralsFound":"Nou pa jwenn okenn aparèy","gui.connection.scanning.instructions":"Chwazi aparèy ou la nan lis ki an wo a.","gui.connection.search":"Chaje ankò","gui.connection.unavailable.installscratchlink":"Asire Lyen Scratch la enstale epi l ap mache","gui.connection.unavailable.enablebluetooth":"Tcheke Bluetooth aktive","gui.connection.unavailable.tryagainbutton":"Eseye ankò","gui.connection.unavailable.helpbutton":"Èd","gui.controls.go":"Ale","gui.controls.stop":"Kanpe","gui.crashMessage.label":"Wouch! Gen yon bagay ki te mal pase. ","gui.crashMessage.errorNumber":"Pwoblèm ou lan anrejistre ak idantite{errorId}","gui.crashMessage.reload":"Rechaje","gui.customProcedures.myblockModalTitle":"Fè yon blòk ","gui.customProcedures.addAnInputNumberText":"Ajoute yon antre","gui.customProcedures.numberTextType":"chif oubyen tèks","gui.customProcedures.addAnInputBoolean":"Ajoute yon antre","gui.customProcedures.booleanType":"bouleyen","gui.customProcedures.addALabel":"Ajoute yon etikèt","gui.customProcedures.runWithoutScreenRefresh":"Fè mache san chaje ekran an ankò","gui.customProcedures.cancel":"Anile","gui.customProcedures.ok":"Oke","gui.SpriteInfo.direction":"Direksyon","gui.directionPicker.rotationStyles.allAround":"Toutotou","gui.directionPicker.rotationStyles.leftRight":"Goch/Dwat","gui.directionPicker.rotationStyles.dontRotate":"Pa vire ","gui.gui.addExtension":"Ajoute ekstansyon","gui.gui.codeTab":"Kòd","gui.gui.backdropsTab":"Fon ","gui.gui.costumesTab":"Kostim","gui.gui.soundsTab":"Son","gui.extensionLibrary.comingSoon":"Disponib Talè","gui.extensionLibrary.requires":"Egzije","gui.extensionLibrary.collaboration":"Kolaborasyon ak","gui.library.filterPlaceholder":"Chèche","gui.library.allTag":"Tout","gui.loader.headline":"Chajman pwojè","gui.loader.creating":"Kreye pwojè","gui.authorInfo.byUser":"Otè : {username}","gui.menuBar.seeProjectPage":"Gade paj pwojè a","gui.menuBar.LanguageSelector":"seleksyonè lang","gui.menuBar.tutorialsLibrary":"Leson","gui.menuBar.restoreSprite":"Fè aktè la retounen","gui.menuBar.restoreSound":"Fè son an retounen","gui.menuBar.restoreCostume":"Fè kostim lan retounen","gui.menuBar.restore":"Fè l retounen","gui.menuBar.saveNow":"Sovgade kounye a","gui.menuBar.saveAsCopy":"Sovgade kòm yon kopi","gui.menuBar.remix":"Remikse","gui.menuBar.new":"Nouvo","gui.menuBar.file":"Fichye","gui.menuBar.downloadToComputer":"Sovgade sou òdinatè w a","gui.menuBar.edit":"Modifye","gui.menuBar.turboModeOff":"Fèmen Mòd Turbo a","gui.menuBar.turboModeOn":"Ouvri Mòd Turbo a","gui.gui.projectTitlePlaceholder":"Tit Pwojè isi","gui.menuBar.isShared":"Pataje","gui.menuBar.share":"Pataje","gui.modal.help":"Èd","gui.modal.back":"Retounen","gui.monitor.listMonitor.empty":"(vid)","gui.monitor.listMonitor.listLength":"longè{length}","gui.monitor.contextMenu.default":"lekti nòmal","gui.monitor.contextMenu.large":"gran lekti","gui.monitor.contextMenu.slider":"kisè","gui.monitor.contextMenu.sliderRange":"Chanje zòn kisè ","gui.monitor.contextMenu.import":"enpòte","gui.monitor.contextMenu.export":"espòte","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Jwe","gui.playButton.stop":"Koupe","gui.gui.variableScopeOptionAllSprites":"Pou tout aktè","gui.gui.variableScopeOptionSpriteOnly":"Pou aktè sa a sèlman","gui.gui.cloudVariableOption":"Varyab nyaj (estoke sou sèvè a)","gui.gui.variablePromptAllSpritesMessage":"Varyab sa ap disponib pou tout aktè.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Anile","gui.prompt.ok":"Oke","gui.playbackStep.stopMsg":"Kanpe","gui.playbackStep.playMsg":"Jwe","gui.playbackStep.loadingMsg":"Chajman...","gui.playbackStep.saveMsg":"Sovgade","gui.playbackStep.reRecordMsg":"Anrejistre ankò","gui.recordModal.title":"Anrejistre son","gui.recordingStep.beginRecord":"Kòmanse anrejistre nan klike sou bouton an ba a","gui.recordingStep.permission":"{arrow}Nou bezwen pèmisyon w pou n itilize mikwofòn ou nan","gui.recordingStep.stop":"Sispann anrejistre","gui.recordingStep.record":"Anrejistre","gui.sliderModal.min":"Nonm minimòm","gui.sliderModal.max":"Nonm maksimòm","gui.sliderModal.title":"Chanje zòn kisè","gui.sliderPrompt.cancel":"Anile","gui.sliderPrompt.ok":"Oke","gui.soundEditor.sound":"Son","gui.soundEditor.play":"Jwe","gui.soundEditor.stop":"Kanpe","gui.soundEditor.copy":"Kopye","gui.soundEditor.paste":"Kole","gui.soundEditor.copyToNew":"Kopye nan Nouvo","gui.soundEditor.delete":"Efase","gui.soundEditor.save":"Sovgade","gui.soundEditor.undo":"Defèt","gui.soundEditor.redo":"Refè","gui.soundEditor.faster":"Pi rapid","gui.soundEditor.slower":"Pi dousman","gui.soundEditor.echo":"Eko","gui.soundEditor.robot":"Wobo","gui.soundEditor.louder":"Pi fò","gui.soundEditor.softer":"Pi ba","gui.soundEditor.reverse":"Ranvèse","gui.soundEditor.fadeOut":"Disparèt gradyèlman","gui.soundEditor.fadeIn":"Antre gradyèlman","gui.soundEditor.mute":"Sou silans","gui.SpriteInfo.spritePlaceholder":"Non","gui.SpriteInfo.sprite":"Aktè","gui.SpriteInfo.show":"Montre","gui.SpriteInfo.size":"Tay","gui.spriteSelectorItem.contextMenuDuplicate":"kopye","gui.spriteSelectorItem.contextMenuExport":"espòte","gui.spriteSelectorItem.contextMenuDelete":"efase","gui.spriteSelector.addSpriteFromLibrary":"Chwazi yon aktè","gui.spriteSelector.addSpriteFromPaint":"Pentire","gui.spriteSelector.addSpriteFromSurprise":"Sipriz","gui.spriteSelector.addSpriteFromFile":"Ajoute aktè","gui.stageHeader.stageSizeLarge":"Chanje sèn lan ak yon gwo sèn","gui.stageHeader.stageSizeSmall":"Chanje sèn lan ak yon ti sèn","gui.stageHeader.stageSizeFull":"Antre nan mòd ekran plen","gui.stageHeader.stageSizeUnFull":"Sòti nan mòd ekran plen","gui.stageHeader.fullscreenControl":"Kontwòl ekran plen","gui.spriteSelector.addBackdropFromLibrary":"Chwazi yon fon ","gui.stageSelector.addBackdropFromPaint":"Pentire","gui.stageSelector.addBackdropFromSurprise":"Sipriz","gui.stageSelector.addBackdropFromFile":"Ajoute yon fon ","gui.stageSelector.stage":"Sèn","gui.stageSelector.backdrops":"Fon ","gui.telemetryOptIn.label":"Voye estatistik ou pou ede Scratch vin pi bon","gui.telemetryOptIn.body1":"Ekip Scratch la toujou ap chèche pou l pi byen konprann ki jan moun itilize Scratch tou pa tou sou latè. Pou sipòte efò sa a, ou ka pèmèt Scratch voye enfòmasyon itilizasyon w bay Ekip Scratch la otomatikman","gui.telemetryOptIn.body2":"Enfòmasyon nou kolekte yo gen ladan seleksyon lang, itilizasyon blòk yo, ak kèk evènman tankou sovgade, chajman, ak ajoute yon pwojè. Nou PA kolekte OKENN enfòmasyon pèsonèl. Tanpri gade{privacyPolicyLink} pou plis enfòmasyon.","gui.telemetryOptIn.privacyPolicyLink":"Règleman sou enfòmasyon ki dwe rete prive","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Mòd Turbo","gui.webglModal.label":"Navigatè w a pa sipòte WebGL","gui.webglModal.webgllink":"pa sipòte WebGL","gui.costumeLibrary.chooseABackdrop":"Chwazi yon fon ","gui.costumeLibrary.chooseACostume":"Chwazi yon kostim","gui.costumeTab.addBackdropFromLibrary":"Chwazi yon fon ","gui.costumeTab.addCostumeFromLibrary":"Chwazi yon kostim","gui.costumeTab.addBlankCostume":"Pentire","gui.costumeTab.addSurpriseCostume":"Sipriz","gui.costumeTab.addFileBackdrop":"Ajoute yon fon","gui.costumeTab.addFileCostume":"Ajoute yon kostim","gui.extensionLibrary.chooseAnExtension":"Chwazi yon ekstansyon","gui.extensionLibrary.extensionUrl":"Antre URL ekstansyon an","gui.monitors.importListColumnPrompt":"Ki kolòn pou n itilize (1-{numberOfColumns}) ?","gui.recordingStep.alertMsg":"Nou pa t kapab kòmanse anrejistreman","gui.soundLibrary.chooseASound":"Chwazi yon son","gui.soundTab.fileUploadSound":"Ajoute yon Son","gui.soundTab.surpriseSound":"Sipriz","gui.soundTab.recordSound":"Anrejistre","gui.soundTab.addSoundFromLibrary":"Chwazi yon son","gui.spriteLibrary.chooseASprite":"Chwazi yon aktè","gui.tipsLibrary.tutorials":"Chwazi yon leson","gui.alerts.createsuccess":"Nou kreye yon nouvo pwojè. ","gui.alerts.createcopysuccess":"Nou sovgade pwojè a kòm yon kopi. ","gui.alerts.createremixsuccess":"Nou sovgade pwojè a kòm yon remiks.","gui.alerts.creating":"Kreye nouvo ...","gui.alerts.creatingCopy":"Kopye pwojè ...","gui.alerts.creatingRemix":"Remikse pwojè ...","gui.alerts.creatingError":"Nou pa t ka kreye pwojè a. Tanpri eseye ankò !","gui.alerts.savingError":"Nou pa t ka sovgade pwojè a.","gui.alerts.savesuccess":"Nou sovgade pwojè a","gui.alerts.saving":"Sovgade pwojè...","gui.alerts.cloudInfo":"Tanpri sonje, varyab nyaj yo sèlman sipòte chif, pa lèt ak senbòl.{learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Aprann plis.","gui.alerts.importing":"Enpòte...","gui.defaultProject.variable":"varyab mwen la","gui.extension.music.name":"Mizik","gui.extension.music.description":"Jwe enstriman ak tanbou. ","gui.extension.pen.name":"Plim","gui.extension.pen.description":"Desinen ak aktè ou yo.","gui.extension.videosensing.name":"Deteksyon videyo","gui.extension.videosensing.description":"Detekte mouvman avèk kamera a.","gui.extension.text2speech.name":"Tèks an Vwa","gui.extension.text2speech.description":"Fè pwojè w yo pale.","gui.extension.translate.name":"Tradwi","gui.extension.translate.description":"Tradwi tèks nan plizyè lang. ","gui.extension.makeymakey.description":"Fè nenpòt bagay tounen yon kle. ","gui.extension.microbit.description":"Konekte pwojè ou yo ak anviwònman w. ","gui.extension.microbit.connectingMessage":"L ap konekte","gui.extension.ev3.description":"Konstwi wobo entèraktif e plis toujou","gui.extension.ev3.connectingMessage":"L ap konekte. Asire PIN EV3 ou a se 1234 li ye.","gui.extension.boost.description":"Fè kreyasyon wobotik ou yo tounen vivan","gui.extension.boost.connectingMessage":"L ap konekte","gui.extension.wedo2.description":"Konstwi ak motè epi detektè.","gui.extension.wedo2.connectingMessage":"L ap konekte","gui.extension.gdxfor.description":"Detekte pouse, rale, mouvman, ak vire.","gui.extension.gdxfor.connectingMessage":"L ap konekte","gui.libraryTags.all":"Tout","gui.libraryTags.animals":"Bèt","gui.libraryTags.dance":"Danse","gui.libraryTags.effects":"Efè","gui.libraryTags.fantasy":"Imajinè","gui.libraryTags.fashion":"Rad","gui.libraryTags.food":"Manje","gui.libraryTags.indoors":"An dedan kay","gui.libraryTags.loops":"Bouk ","gui.libraryTags.music":"Mizik","gui.libraryTags.notes":"Nòt","gui.libraryTags.outdoors":"Deyò","gui.libraryTags.patterns":"Modèl ","gui.libraryTags.people":"Moun","gui.libraryTags.percussion":"Batri","gui.libraryTags.space":"Espas","gui.libraryTags.sports":"Espò","gui.libraryTags.underwater":"An ba dlo","gui.libraryTags.voice":"Vwa","gui.libraryTags.wacky":"Biza","gui.libraryTags.animation":"Animasyon","gui.libraryTags.art":"Atizay","gui.libraryTags.games":"Jwèt ","gui.libraryTags.stories":"Istwa ","gui.libraryTags.letters":"Lèt ","gui.opcodeLabels.direction":"direksyon","gui.opcodeLabels.xposition":"pozisyon x","gui.opcodeLabels.yposition":"pozisyon y","gui.opcodeLabels.size":"gwosè","gui.opcodeLabels.costumename":"non kostim","gui.opcodeLabels.costumenumber":"nimewo kostim","gui.opcodeLabels.backdropname":"non twal fon an","gui.opcodeLabels.backdropnumber":"mimewo twal fon","gui.opcodeLabels.volume":"volim","gui.opcodeLabels.tempo":"tenmpo","gui.opcodeLabels.answer":"repons","gui.opcodeLabels.loudness":"volim ","gui.opcodeLabels.username":"non itilizatè","gui.opcodeLabels.year":"ane","gui.opcodeLabels.month":"mwa","gui.opcodeLabels.date":"jou","gui.opcodeLabels.dayofweek":"jou nan semenn lan","gui.opcodeLabels.hour":"lè","gui.opcodeLabels.minute":"minit","gui.opcodeLabels.second":"segond","gui.opcodeLabels.timer":"kwonomèt","gui.sharedMessages.backdrop":"Twal fon{index}","gui.sharedMessages.costume":"Kostim{index}","gui.sharedMessages.sprite":"Aktè{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Ranplase kontni pwojè aktyèl la ?","gui.sharedMessages.loadFromComputerTitle":"Chaje yon pwojè sou òdinatè w ","boost.color.any":"nenpòt koulè","boost.color.black":"nwa","boost.color.blue":"ble","boost.color.green":"vèt","boost.color.red":"wouj","boost.color.white":"blan","boost.color.yellow":"jòn","boost.getMotorPosition":"pozisyon motè [MOTOR_REPORTER_ID]","boost.getTiltAngle":"ang li panche [TILT_DIRECTION]","boost.motorDirection.backward":"lòt direksyon an","boost.motorDirection.forward":"direksyon sa a","boost.motorDirection.reverse":"fè bak","boost.motorOff":"rete motè [MOTOR_ID]","boost.motorOn":"mete motè [MOTOR_ID] an mach","boost.motorOnFor":"fè motè a woule [MOTOR_ID] pandan [DURATION] segond","boost.motorOnForRotation":"fè motè woule [MOTOR_ID] pandan [ROTATION] rotasyon","boost.seeingColor":"èske l wè brik [COLOR] ?","boost.setLightHue":"mete koulè limyè sou [HUE]","boost.setMotorDirection":"fikse direksyon motè [MOTOR_ID] a [MOTOR_DIRECTION]","boost.setMotorPower":"fikse vitès motè [MOTOR_ID] a [POWER] %","boost.tiltDirection.any":"nenpòt","boost.tiltDirection.down":"an ba","boost.tiltDirection.left":"goch","boost.tiltDirection.right":"dwat","boost.tiltDirection.up":"an wo","boost.whenColor":"lè l wè brik [COLOR] ","boost.whenTilted":"lè l panche [TILT_DIRECTION_ANY]","ev3.beepNote":"bipe ton [NOTE] pandan [TIME] segond","ev3.buttonPressed":"èske bouton [PORT] an peze ?","ev3.getBrightness":"ekleraj","ev3.getDistance":"distans","ev3.getMotorPosition":"Pozisyon motè [PORT]","ev3.motorSetPower":"fikse fòs motè [PORT] a [POWER] %","ev3.motorTurnClockwise":"motè [PORT] pran direksyon sa a pandan [TIME] segond","ev3.motorTurnCounterClockwise":"motè [PORT] pran lòt direksyon an pandan [TIME] segond","ev3.whenBrightnessLessThan":"lè ekleraj < [DISTANCE]","ev3.whenButtonPressed":"lè bouton [PORT] peze","ev3.whenDistanceLessThan":"lè distans < [DISTANCE]","gdxfor.getAcceleration":"akselere an [DIRECTION]","gdxfor.getForce":"fòs","gdxfor.getSpin":"vitès rotasyon [DIRECTION]","gdxfor.getTilt":"ang l ap panche [TILT]","gdxfor.isFreeFalling":"èske l ap tonbe ?","gdxfor.isTilted":"èske l ap panche [TILT] ?","gdxfor.pulled":"rale","gdxfor.pushed":"pouse","gdxfor.shaken":"te souke","gdxfor.startedFalling":"kòmanse tonbe","gdxfor.tiltDirectionMenu.any":"nenpòt","gdxfor.tiltDirectionMenu.back":"dèyè","gdxfor.tiltDirectionMenu.front":"devan","gdxfor.tiltDirectionMenu.left":"goch","gdxfor.tiltDirectionMenu.right":"dwat","gdxfor.turnedFaceDown":"vire tèt an ba","gdxfor.turnedFaceUp":"vire tèt an lè","gdxfor.whenForcePushedOrPulled":"lè kaptè fòs [PUSH_PULL]","gdxfor.whenGesture":"lè [GESTURE]","gdxfor.whenTilted":"lè l panche [TILT]","makeymakey.downArrow":"flèch an ba","makeymakey.downArrowShort":"an ba","makeymakey.leftArrow":"flèch goch","makeymakey.leftArrowShort":"goch","makeymakey.rightArrow":"flèch dwat","makeymakey.rightArrowShort":"dwat","makeymakey.spaceKey":"espas","makeymakey.upArrow":"flèch an wo","makeymakey.upArrowShort":"anwo","makeymakey.whenKeyPressed":"lè [KEY] touch peze","makeymakey.whenKeysPressedInOrder":"lè [SEQUENCE] peze nan lòd","microbit.buttonsMenu.any":"nenpòt","microbit.clearDisplay":"netwaye ekran","microbit.defaultTextToDisplay":"Alo !","microbit.displaySymbol":"afiche [MATRIX]","microbit.displayText":"afiche tèks [TEXT]","microbit.gesturesMenu.jumped":"sote","microbit.gesturesMenu.moved":"deplase","microbit.gesturesMenu.shaken":"te souke","microbit.isButtonPressed":"èske bouton [BTN] peze ?","microbit.isTilted":"èske l panche a [DIRECTION] ?","microbit.pinStateMenu.off":"fèmen","microbit.pinStateMenu.on":"limen","microbit.tiltAngle":"ang li panche an [DIRECTION]","microbit.tiltDirectionMenu.any":"nenpòt","microbit.tiltDirectionMenu.back":"dèyè","microbit.tiltDirectionMenu.front":"devan","microbit.tiltDirectionMenu.left":"goch","microbit.tiltDirectionMenu.right":"dwat","microbit.whenButtonPressed":"lè bouton [BTN] peze","microbit.whenGesture":"lè [GESTURE]","microbit.whenPinConnected":"lè zepeng [PIN] konekte","microbit.whenTilted":"lè l panche an [DIRECTION]","music.categoryName":"Mizik","music.changeTempo":"chanje tenmpo pa [TEMPO]","music.drumBass":"(2) Gwo kès","music.drumBongo":"(13) Tanbou marasa","music.drumCabasa":"(15) Kalbas (Cabasa Amerik Latin, Shekere afriken)","music.drumClaves":"(9) Clave kiben","music.drumClosedHiHat":"(6) Senbal sali-chapo femèn","music.drumConga":"(14) Batri petwo (Konga kiben)","music.drumCowbell":"(11) Klochèt","music.drumCrashCymbal":"(4) Woule mazon sou yon senbal","music.drumCuica":"(18) Tanbou samba (Cuica brezilyen)","music.drumGuiro":"(16) Enstriman salsa (Guiro Amerik Latin)","music.drumHandClap":"(8) Bat bravo","music.drumOpenHiHat":"(5) Senbal sali-chapo tou louvri","music.drumSideStick":"(3) Manch tanbou","music.drumSnare":"(1) Tanbou kès","music.drumTambourine":"(7) Tanbouren","music.drumTriangle":"(12) Triyang","music.drumVibraslap":"(17) Zo machwè (Kiyada Amerik Latin, Vibraslap)","music.drumWoodBlock":"(10) Blòk bwa","music.getTempo":"tenmpo","music.instrumentBass":"(6) Kontrebas","music.instrumentBassoon":"(14) Bason","music.instrumentCello":"(8) vyolonsèl","music.instrumentChoir":"(15) Koral","music.instrumentClarinet":"(10) Klarinèt","music.instrumentElectricGuitar":"(5) Gita elektrik","music.instrumentElectricPiano":"(2) Pyano elektrik","music.instrumentFlute":"(12) Flit","music.instrumentGuitar":"(4) Gita","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Kariyon","music.instrumentOrgan":"(3) Òg","music.instrumentPiano":"(1) Pyano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saksofòn","music.instrumentSteelDrum":"(18) Tanbou Asye (Trinidad ak Tobago)","music.instrumentSynthLead":"(20) Sentetizè pou melodi (lead)","music.instrumentSynthPad":"(21) Sentetizè pou mikse (pad)","music.instrumentTrombone":"(9) Twonbòn","music.instrumentVibraphone":"(16) Vibrafòn (djaz)","music.instrumentWoodenFlute":"(13) Flit an bwa","music.midiPlayDrumForBeats":"jwe tanbou [DRUM] pandan [BEATS] batman","music.midiSetInstrument":"chwazi enstriman [INSTRUMENT]","music.playDrumForBeats":"jwe tanbou [DRUM] pandan [BEATS] batman","music.playNoteForBeats":"jwe ton [NOTE] pandan [BEATS] batman","music.restForBeats":"repoze pandan [BEATS] batman","music.setInstrument":"chwazi enstriman [INSTRUMENT]","music.setTempo":"fikse tenmpo a [TEMPO]","pen.categoryName":"Plim","pen.changeColorParam":"chanje plim [COLOR_PARAM] pa [VALUE]","pen.changeHue":"chanje koulè plim pa [HUE]","pen.changeShade":"chanje lonbraj plim pa [SHADE]","pen.changeSize":"chanje tay plim pa [SIZE]","pen.clear":"efase tout","pen.colorMenu.brightness":"ekleraj","pen.colorMenu.color":"koulè","pen.colorMenu.saturation":"satirasyon","pen.colorMenu.transparency":"transparans","pen.penDown":"bese plim la","pen.penUp":"leve plim la","pen.setColor":"fikse koulè plim nan [COLOR]","pen.setColorParam":"fikse plim [COLOR_PARAM] sou [VALUE]","pen.setHue":"fikse koulè plim sou [HUE]","pen.setShade":"fikse lonbraj plim a [SHADE]","pen.setSize":"fikse tay plim sou [SIZE]","pen.stamp":"mete so","text2speech.alto":"alto","text2speech.categoryName":"Tèks an Vwa","text2speech.defaultTextToSpeak":"bonjou","text2speech.giant":"gran","text2speech.kitten":"ti chat","text2speech.setLanguageBlock":"chwazi lang [LANGUAGE]","text2speech.setVoiceBlock":"fikse vwa a [VOICE]","text2speech.speakAndWaitBlock":"pale [WORDS]","text2speech.squeak":"kriye","text2speech.tenor":"tenò","translate.categoryName":"Tradwi","translate.defaultTextToTranslate":"bonjou","translate.translateBlock":"tradwi [WORDS] an [LANGUAGE]","translate.viewerLanguage":"lang","videoSensing.categoryName":"Deteksyon videyo","videoSensing.direction":"direksyon","videoSensing.motion":"mouvman","videoSensing.off":"rete","videoSensing.on":"jwe","videoSensing.onFlipped":"sou ranvèse","videoSensing.setVideoTransparency":"fikse transparans videyo a [TRANSPARENCY]","videoSensing.sprite":"aktè","videoSensing.stage":"sèn","videoSensing.videoOn":"videyo [ATTRIBUTE] sou [SUBJECT]","videoSensing.videoToggle":"fè videyo [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"lè mouvman videyo > [REFERENCE]","wedo2.getDistance":"distans","wedo2.getTiltAngle":"ang li panche [TILT_DIRECTION]","wedo2.isTilted":"èske li panche [TILT_DIRECTION_ANY] ?","wedo2.motorDirection.backward":"lòt direksyon an","wedo2.motorDirection.forward":"direksyon sa a","wedo2.motorDirection.reverse":"fè bak","wedo2.motorId.a":"motè A","wedo2.motorId.all":"tout motè ","wedo2.motorId.b":"motè B","wedo2.motorId.default":"motè","wedo2.motorOff":"rete [MOTOR_ID] ","wedo2.motorOn":"mete [MOTOR_ID] an mach","wedo2.motorOnFor":"fè [MOTOR_ID] woule pandan [DURATION] segond","wedo2.playNoteFor":"jwe ton [NOTE] pandan [DURATION] segond","wedo2.setLightHue":"mete koulè limyè sou [HUE]","wedo2.setMotorDirection":"mete [MOTOR_ID] sou direksyon [MOTOR_DIRECTION]","wedo2.startMotorPower":"fikse fòs [MOTOR_ID] a [POWER]","wedo2.tiltDirection.any":"nenpòt","wedo2.tiltDirection.down":"an ba","wedo2.tiltDirection.left":"goch","wedo2.tiltDirection.right":"dwat","wedo2.tiltDirection.up":"an wo","wedo2.whenDistance":"lè distans [OP] [REFERENCE]","wedo2.whenTilted":"lè l panche [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Koulè","paint.paintEditor.saturation":"Satirasyon","paint.paintEditor.brightness":"Ekleraj","paint.paintEditor.costume":"Kostim","paint.paintEditor.group":"Gwoup","paint.paintEditor.ungroup":"Degwoupe","paint.paintEditor.undo":"Anile","paint.paintEditor.redo":"Fè ankò","paint.paintEditor.forward":"Avanse","paint.paintEditor.backward":"Bak","paint.paintEditor.front":"Douvan","paint.paintEditor.back":"Dèyè","paint.paintEditor.more":"Plis","paint.modeTools.brushSize":"Tay","paint.modeTools.eraserSize":"Tay gòm","paint.modeTools.copy":"Kopye","paint.modeTools.paste":"Kole","paint.modeTools.delete":"Efase","paint.modeTools.curved":"Koube","paint.modeTools.pointed":"Pwenti","paint.modeTools.thickness":"Epesè","paint.modeTools.flipHorizontal":"Ranvèse orizontalman","paint.modeTools.flipVertical":"Ranvèse vètikalman","paint.modeTools.filled":"Ranpli","paint.modeTools.outlined":"An kontou","paint.paintEditor.bitmap":"Konvèti an Bitmap","paint.paintEditor.vector":"Konvèti an vektè","paint.paintEditor.fill":"Ranpli","paint.paintEditor.stroke":"Kontou","paint.brushMode.brush":"Penso","paint.eraserMode.eraser":"Gòm","paint.fillMode.fill":"Ranpli","paint.lineMode.line":"Liy","paint.ovalMode.oval":"Sèk","paint.rectMode.rect":"Rektang","paint.reshapeMode.reshape":"Refòme","paint.roundedRectMode.roundedRect":"Rektang Awondi","paint.selectMode.select":"Seleksyone","paint.textMode.text":"Tèks","paint.colorPicker.swap":"Echanje"},"ku":{"gui.alerts.tryAgain":"Dîsa Biceribîne","gui.alerts.download":"Daxîne","gui.connection.reconnect":"Dîsa girêde","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Çenteyê Piştê","gui.backpack.errorBackpack":"Di barkirina çenteyê pişte de çewtî çêbû","gui.backpack.loadingBackpack":"Tê barkirin...","gui.backpack.more":"Zêdetir","gui.backpack.emptyBackpack":"Çenteyê Piştê vala ye","gui.unsupportedBrowser.label":"Gerok nayê piştgirîkirin","gui.cards.all-tutorials":"Fêrgeh","gui.cards.shrink":"Biçûk bike","gui.cards.expand":"Fireh bike","gui.cards.close":"Bigire","gui.cards.more-things-to-try":"Ji bo ceribandinê tiştên zêdetir!","gui.cards.see-more":"Zêdetir Bibîne","gui.comingSoon.message1":"Xemgîn nebe, em hene {emoji}","gui.comingSoon.message2":"Pir Nêz de...","gui.comingSoon.message3":"Em li ser dixebitin {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Cîhaz nehatin dîtin","gui.connection.auto-scanning.prescan":"Cîhaza xwe li nêzîka xwe bihêle, paşê dest bi lêgerînê bike.","gui.connection.auto-scanning.pressbutton":"Pêlî bişkoka li ser cîhaza xwe bike.","gui.connection.auto-scanning.start-search":"Dest bi Lêgerînê Bike","gui.connection.connecting-searchbutton":"Tê gerîn...","gui.connection.auto-scanning.try-again":"Dîsa biceribîne","gui.connection.connected":"Hate girêdan","gui.connection.disconnect":"Girêdanê Qut Bike","gui.connection.go-to-editor":"Biçe Edîtorê","gui.connection.connecting-cancelbutton":"Tê girêdan...","gui.connection.error.errorMessage":"Weyy, wiha dixuye ku hinek tişt berevajî çûn.","gui.connection.error.tryagainbutton":"Dîsa biceribîne","gui.connection.error.helpbutton":"Alîkarî","gui.connection.peripheral-name-label":"Navê cîhazê","gui.connection.connect":"Girê bide","gui.connection.scanning.lookingforperipherals":"Li cîhazan tê gerîn","gui.connection.scanning.noPeripheralsFound":"Cîhaz nehatin dîtin","gui.connection.scanning.instructions":"Ji lîsteya jorîn cîhaza xwe hilbijêre.","gui.connection.search":"Nû bike","gui.connection.unavailable.installscratchlink":"Ji sazbûn û xebitandina Scratch Linkê piştrast be","gui.connection.unavailable.enablebluetooth":"Çalakbûna Bluetoothê kontrol bike","gui.connection.unavailable.tryagainbutton":"Dîsa biceribîne","gui.connection.unavailable.helpbutton":"Alîkarî","gui.controls.go":"Here","gui.controls.stop":"Rawestîne","gui.crashMessage.label":"Weyy, Hinek tişt çewt çûn.","gui.crashMessage.errorNumber":"Çewtiyek bi hejmara {errorId} hate tomarkirin","gui.crashMessage.reload":"Dîsa bar bike","gui.customProcedures.myblockModalTitle":"Blokekê Çê Bike","gui.customProcedures.addAnInputNumberText":"Têketanekê tevlî bike","gui.customProcedures.numberTextType":"hejmar an jî nivîs","gui.customProcedures.addAnInputBoolean":"Têketanekê tevlî bike","gui.customProcedures.booleanType":"mantiqî","gui.customProcedures.addALabel":"Etîketekê tevlî bike","gui.customProcedures.runWithoutScreenRefresh":"Bila beyî nûkirina ekranê bixebite","gui.customProcedures.cancel":"Betal","gui.customProcedures.ok":"Baş e","gui.SpriteInfo.direction":"Hêl","gui.directionPicker.rotationStyles.allAround":"Bi Hemû Hêla ve","gui.directionPicker.rotationStyles.leftRight":"Rastê/Çepê","gui.directionPicker.rotationStyles.dontRotate":"Ne zîvirîne","gui.gui.addExtension":"Pêvek Tevlî Bike","gui.gui.codeTab":"Kod","gui.gui.backdropsTab":"Dekor","gui.gui.costumesTab":"Kostum","gui.gui.soundsTab":"Deng","gui.extensionLibrary.comingSoon":"Pir Nêz de...","gui.extensionLibrary.requires":"Hewceyî","gui.extensionLibrary.collaboration":"Bi hevkarî","gui.library.filterPlaceholder":"Lêgerîn","gui.library.allTag":"Hemû","gui.loader.headline":"Proje Tê Barkirin","gui.loader.creating":"Proje Tê Afirandin","gui.authorInfo.byUser":"Ji aliye {username} ve","gui.menuBar.seeProjectPage":"Rûpela Projeyê Bibîne","gui.menuBar.LanguageSelector":"hilbijarkera ziman","gui.menuBar.tutorialsLibrary":"Fêrgeh","gui.menuBar.restoreSprite":"Pêlîstikê Vegerîne","gui.menuBar.restoreSound":"Deng Vegerîne","gui.menuBar.restoreCostume":"Kostumê Vegerîne","gui.menuBar.restore":"Vegerîne","gui.menuBar.saveNow":"Aniha tomar bike","gui.menuBar.saveAsCopy":"Wekî kopî tomar bike","gui.menuBar.remix":"Remîks","gui.menuBar.new":"Nû","gui.menuBar.file":"Pelge","gui.menuBar.downloadToComputer":"Li kombersa xwe tomar bike","gui.menuBar.edit":"Sererast bike","gui.menuBar.turboModeOff":"Moda Turboyê bigire","gui.menuBar.turboModeOn":"Moda Turboyê veke","gui.gui.projectTitlePlaceholder":"Li vira serika projeyê","gui.menuBar.isShared":"Parvekirî","gui.menuBar.share":"Parve bike","gui.modal.help":"Alîkarî","gui.modal.back":"Paşve","gui.monitor.listMonitor.empty":"(vala)","gui.monitor.listMonitor.listLength":"dirêjî {length}","gui.monitor.contextMenu.default":"xuyanga normal","gui.monitor.contextMenu.large":"xuyanga fireh","gui.monitor.contextMenu.slider":"pêşeker","gui.monitor.contextMenu.sliderRange":"rêjeya şemitandinê biguherîne","gui.monitor.contextMenu.import":"têxîne nav","gui.monitor.contextMenu.export":"derxîne","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Lêxe","gui.playButton.stop":"Rawestîne","gui.gui.variableScopeOptionAllSprites":"Ji bo hemû pêlîstikan","gui.gui.variableScopeOptionSpriteOnly":"Tenê ji bo vê pêlîstikê","gui.gui.cloudVariableOption":"Guheroka Ewr (li ser serverê hatiye hilanîn)","gui.gui.variablePromptAllSpritesMessage":"Ev guherok dê ji bo hemû pêlîstikan derbasdar be.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Betal","gui.prompt.ok":"Baş e","gui.playbackStep.stopMsg":"Rawestîne","gui.playbackStep.playMsg":"Lêxe","gui.playbackStep.loadingMsg":"Tê barkirin...","gui.playbackStep.saveMsg":"Tomar bike","gui.playbackStep.reRecordMsg":"Dîsa tomar bike","gui.recordModal.title":"Deng Tomar Bike","gui.recordingStep.beginRecord":"Bi pêlîkirina bişkoka jêrîn ve dest bi tomarkirinê bike","gui.recordingStep.permission":"Ji bo {arrow} mikrofona te bi kar bîne pêwîstiya wê bi destûra te heye","gui.recordingStep.stop":"Tomarkirinê rawestîne","gui.recordingStep.record":"Tomar bike","gui.sliderModal.min":"Nirxê herî nizm","gui.sliderModal.max":"Nirxê herî bilind","gui.sliderModal.title":"Rêjeya şemitandinê biguherîne","gui.sliderPrompt.cancel":"Betal","gui.sliderPrompt.ok":"Baş e","gui.soundEditor.sound":"Deng","gui.soundEditor.play":"Lêxe","gui.soundEditor.stop":"Rawestîne","gui.soundEditor.copy":"Kopî bike","gui.soundEditor.paste":"Bizeliqîne","gui.soundEditor.copyToNew":"Li ya Nû kopî bike","gui.soundEditor.delete":"Jê bibe","gui.soundEditor.save":"Tomar bike","gui.soundEditor.undo":"Vegerîne","gui.soundEditor.redo":"Dîsa pêşve","gui.soundEditor.faster":"Zûtir","gui.soundEditor.slower":"Hêdîtir","gui.soundEditor.echo":"Dengvedan","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Dengê bilindtir","gui.soundEditor.softer":"Nermtir","gui.soundEditor.reverse":"Berevajî","gui.soundEditor.fadeOut":"Tarî bike","gui.soundEditor.fadeIn":"Ronî bike","gui.soundEditor.mute":"Bêdeng bike","gui.SpriteInfo.spritePlaceholder":"Nav","gui.SpriteInfo.sprite":"Pêlîstik","gui.SpriteInfo.show":"Nîşan bide","gui.SpriteInfo.size":"Mezinahî","gui.spriteSelectorItem.contextMenuDuplicate":"kopiya wê derxe","gui.spriteSelectorItem.contextMenuExport":"derxîne","gui.spriteSelectorItem.contextMenuDelete":"jê bibe","gui.spriteSelector.addSpriteFromLibrary":"Pêlîstikekê Hilbijêre","gui.spriteSelector.addSpriteFromPaint":"Rengandin","gui.spriteSelector.addSpriteFromSurprise":"Surprîz","gui.spriteSelector.addSpriteFromFile":"Pêlîstikê Hilbixîne","gui.stageHeader.stageSizeLarge":"Derbasî dika fireh bibe","gui.stageHeader.stageSizeSmall":"Derbasî dika biçûk bibe","gui.stageHeader.stageSizeFull":"Derbasî moda ekrana tije bibe","gui.stageHeader.stageSizeUnFull":"Ji moda ekrana tije derkeve","gui.stageHeader.fullscreenControl":"Kontrola Ekrana Tije","gui.spriteSelector.addBackdropFromLibrary":"Dekorekê Hilbijêre","gui.stageSelector.addBackdropFromPaint":"Rengandin","gui.stageSelector.addBackdropFromSurprise":"Surprîz","gui.stageSelector.addBackdropFromFile":"Dekorê Hilbixîne","gui.stageSelector.stage":"Dik","gui.stageSelector.backdrops":"Dekor","gui.telemetryOptIn.label":"Ji bo pêşxistina Scratchê rêjejimaran ragihîne","gui.telemetryOptIn.body1":"Ji bo bi awayekî baştir were fêhmkirin ku Scratch li seranserê dinyayê çawa tê bikaranîn Tîma Scratchê her dem di nav hewldanan de ye. Ji bo ku piştgiriya van hewldanan bikî, tu dikare destûrê bide ku Scratch bixweberî agahdariyên bikaranînê ji Tîma Scratchê re bişîne.","gui.telemetryOptIn.body2":"Agahiyên em berhev dikin ev in; hilbijartina ziman, bikaranîna blokan, barkirin û hilxistina projeyan û hinek çalakiyên wekî din. Em agahiyên kesane hîç berhev NAKIN. Ji kerema xwe ji bo zanyariyên zêdetir here rûpela {privacyPolicyLink}ê.","gui.telemetryOptIn.privacyPolicyLink":"Polîtîkaya Nihêniyê","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Moda Turboyê","gui.webglModal.label":"Geroka Te Piştgiriya WebGLê Nake","gui.webglModal.webgllink":"WebGL nayê piştgirîkirin","gui.costumeLibrary.chooseABackdrop":"Dekorekê Hilbijêre","gui.costumeLibrary.chooseACostume":"Kostumekê Hilbijêre","gui.costumeTab.addBackdropFromLibrary":"Dekorekê Hilbijêre","gui.costumeTab.addCostumeFromLibrary":"Kostumekê Hilbijêre","gui.costumeTab.addBlankCostume":"Rengandin","gui.costumeTab.addSurpriseCostume":"Surprîz","gui.costumeTab.addFileBackdrop":"Dekor Hilbixîne","gui.costumeTab.addFileCostume":"Kostum Hilbixîne","gui.extensionLibrary.chooseAnExtension":"Pêvekekê Hilbijêre","gui.extensionLibrary.extensionUrl":"URLa pêvekê têxîne","gui.monitors.importListColumnPrompt":"Divê kîjan stûn were bi kar anîn(1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Tomarkirina deng nayê destpêkirin","gui.soundLibrary.chooseASound":"Dengekî Hilbijêre","gui.soundTab.fileUploadSound":"Deng Hilbixîne","gui.soundTab.surpriseSound":"Surprîz","gui.soundTab.recordSound":"Tomarkirin","gui.soundTab.addSoundFromLibrary":"Dengekî Hilbijêre","gui.spriteLibrary.chooseASprite":"Pêlîstikekê Hilbijêre","gui.tipsLibrary.tutorials":"Derseke Fêrbûnê Hilbijêre","gui.alerts.createsuccess":"Projeya nû hate afirandin.","gui.alerts.createcopysuccess":"Proje wekî kopî hate tomarkirin.","gui.alerts.createremixsuccess":"Proje wekî remîkskirî hate tomarkirin.","gui.alerts.creating":"Nû tê afirandin...","gui.alerts.creatingCopy":"Proje tê kopîkirin...","gui.alerts.creatingRemix":"Proje tê remîkskirin...","gui.alerts.creatingError":"Proje nehate afirandin. Ji kerema xwe dîsa biceribîne!","gui.alerts.savingError":"Proje tomar nebû.","gui.alerts.savesuccess":"Proje tomar bû.","gui.alerts.saving":"Proje tê tomarkirin...","gui.alerts.cloudInfo":"Ji kerema xwe hişyar be, guherokên ewrê tenê piştgiriya hejmaran dike, piştgiriya herf û sembolan nake. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Zêdetir bizane.","gui.alerts.importing":"Têxistinî nav dibe...","gui.defaultProject.variable":"guheroka min","gui.extension.music.name":"Muzîk","gui.extension.music.description":"Amûran û daholê lêxe.","gui.extension.pen.name":"Pênûs","gui.extension.pen.description":"Bi pêlîstika xwe xêz bike.","gui.extension.videosensing.name":"Pêhisîna Vîdyoyê","gui.extension.videosensing.description":"Bi kamerayê li tevgerê bihise.","gui.extension.text2speech.name":"Ji Nivîsê bo Deng","gui.extension.text2speech.description":"Projeyên xwe biaxivîne.","gui.extension.translate.name":"Werger","gui.extension.translate.description":"Nivîsê li gelek zimanan wergerîne.","gui.extension.makeymakey.description":"Her tiştî bi bişkokekê çêke.","gui.extension.microbit.description":"Projeyên xwe bi dinyayê re parve bike.","gui.extension.microbit.connectingMessage":"Tê girêdan","gui.extension.ev3.description":"Robotên înteraktîv û zêdetirî wan ava bike.","gui.extension.ev3.connectingMessage":"Tê girêdan. Ji sazbûna pîna EV3ê wekî 1234 piştrast be.","gui.extension.boost.description":"Kreasyonên robotîk tevlî jiyanê bike.","gui.extension.boost.connectingMessage":"Tê girêdan","gui.extension.wedo2.description":"Bi motor û sensoran ava bike.","gui.extension.wedo2.connectingMessage":"Tê girêdan","gui.extension.gdxfor.description":"Bi dehfdan, kişandin, tevger û zîvirandinê bihise.","gui.extension.gdxfor.connectingMessage":"Tê girêdan","gui.libraryTags.all":"Hemû","gui.libraryTags.animals":"Ajel/Heywan","gui.libraryTags.dance":"Dans","gui.libraryTags.effects":"Efekt","gui.libraryTags.fantasy":"Fantazî","gui.libraryTags.fashion":"Moda","gui.libraryTags.food":"Xurek","gui.libraryTags.indoors":"Hundir","gui.libraryTags.loops":"Zîvir","gui.libraryTags.music":"Muzîk","gui.libraryTags.notes":"Nota","gui.libraryTags.outdoors":"Derveyî","gui.libraryTags.patterns":"Nexş","gui.libraryTags.people":"Mirov","gui.libraryTags.percussion":"Amûrên Lêdanê","gui.libraryTags.space":"Feza","gui.libraryTags.sports":"Werzîş","gui.libraryTags.underwater":"Jêrav","gui.libraryTags.voice":"Deng","gui.libraryTags.wacky":"Ecêb","gui.libraryTags.animation":"Anîmasyon","gui.libraryTags.art":"Huner","gui.libraryTags.games":"Lîstok","gui.libraryTags.stories":"Serpêhatî","gui.libraryTags.letters":"Herf","gui.opcodeLabels.direction":"hêl","gui.opcodeLabels.xposition":"cîgeha x\'ê","gui.opcodeLabels.yposition":"cîgeha y\'yê","gui.opcodeLabels.size":"mezinahî","gui.opcodeLabels.costumename":"navê kostumê","gui.opcodeLabels.costumenumber":"hejmara kostumê","gui.opcodeLabels.backdropname":"navê dekorê","gui.opcodeLabels.backdropnumber":"hejmara dekorê","gui.opcodeLabels.volume":"deng","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"bersiv","gui.opcodeLabels.loudness":"bilindahiya deng","gui.opcodeLabels.username":"navê bikarhêner","gui.opcodeLabels.year":"sal","gui.opcodeLabels.month":"meh","gui.opcodeLabels.date":"dîrok","gui.opcodeLabels.dayofweek":"roja hefteyê","gui.opcodeLabels.hour":"demjimêr","gui.opcodeLabels.minute":"xulek","gui.opcodeLabels.second":"çirke","gui.opcodeLabels.timer":"demsazker","gui.sharedMessages.backdrop":"dekor{index}","gui.sharedMessages.costume":"kostum {index}","gui.sharedMessages.sprite":"Pêlîstik {index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Bila naveroka projeya heyî were guhertin?","gui.sharedMessages.loadFromComputerTitle":"Ji kombersa xwe bar bike","boost.color.any":"her çi rengek","boost.color.black":"reş","boost.color.blue":"şîn","boost.color.green":"kesk","boost.color.red":"sor","boost.color.white":"spî","boost.color.yellow":"zer","boost.getMotorPosition":"cîgeha motora [MOTOR_REPORTER_ID]ê","boost.getTiltAngle":"pîvana xwarbûnê [TILT_DIRECTION]","boost.motorDirection.backward":"wê hêla","boost.motorDirection.forward":"vê hêla","boost.motorDirection.reverse":"berevajî wê","boost.motorOff":"motora [MOTOR_ID]ê bigire","boost.motorOn":"motora [MOTOR_ID]ê veke","boost.motorOnFor":"motora [MOTOR_ID]ê [DURATION] çirkeyan bixebitîne","boost.motorOnForRotation":"motora [MOTOR_ID]ê [ROTATION] cara bizîvirîne","boost.seeingColor":"parçeyê [COLOR] dibînî?","boost.setLightHue":"rengê ronahiyê bike [HUE]","boost.setMotorDirection":"berê motora [MOTOR_ID]ê wekî [MOTOR_DIRECTION] saz bike","boost.setMotorPower":"hêza motora [MOTOR_ID]ê wekî % [POWER] saz bike","boost.tiltDirection.any":"her çi yek","boost.tiltDirection.down":"jêr","boost.tiltDirection.left":"çep","boost.tiltDirection.right":"rast","boost.tiltDirection.up":"jor","boost.whenColor":"dema ku parçeyê bi rengê [COLOR] hat dîtin","boost.whenTilted":"dema ku [TILT_DIRECTION_ANY] xwar bû","ev3.beepNote":"notaya [NOTE]ê [TIME] çirkeyan lêxe","ev3.buttonPressed":"pêlî bişkoka [PORT]ê hate kirin?","ev3.getBrightness":"ronahî","ev3.getDistance":"mesafe","ev3.getMotorPosition":"cîgeha motora [PORT]ê","ev3.motorSetPower":"hêza motora [PORT]ê wekî % [POWER] saz bike","ev3.motorTurnClockwise":"motora [PORT]ê bi vê hêlê ( > ) ve [TIME] çirkeyan bizîvirîne","ev3.motorTurnCounterClockwise":"motora [PORT]ê bi vê hêla ( < ) [TIME] çirkeyan bizîvirîne","ev3.whenBrightnessLessThan":"dema ku ronahî bû < [DISTANCE]","ev3.whenButtonPressed":"dema ku pêlî bişkoka [PORT]ê hate kirin","ev3.whenDistanceLessThan":"dema ku mesafe bû < [DISTANCE]","gdxfor.getAcceleration":"lezîn [DIRECTION]","gdxfor.getForce":"hêz","gdxfor.getSpin":"leza zîvirînê [DIRECTION]","gdxfor.getTilt":"pîvana xwarbûnê [TILT]","gdxfor.isFreeFalling":"dikeve?","gdxfor.isTilted":" ma [TILT] xwar e?","gdxfor.pulled":"kişandî","gdxfor.pushed":"dehfdandî","gdxfor.shaken":"hejandî","gdxfor.startedFalling":"dest bi ketinê kiriye","gdxfor.tiltDirectionMenu.any":"her çi yek","gdxfor.tiltDirectionMenu.back":"paşve","gdxfor.tiltDirectionMenu.front":"pêşve","gdxfor.tiltDirectionMenu.left":"çepê","gdxfor.tiltDirectionMenu.right":"rastê","gdxfor.turnedFaceDown":"berê wê bi jêr ve","gdxfor.turnedFaceUp":"berê wê bi jor ve","gdxfor.whenForcePushedOrPulled":"dema ku hêza sensorê bû [PUSH_PULL]","gdxfor.whenGesture":"dema ku bû [GESTURE]","gdxfor.whenTilted":"dema ku xwarbûn bibe [TILT]","makeymakey.downArrow":"tîra jêr","makeymakey.downArrowShort":"jêr","makeymakey.leftArrow":"tîra çepê","makeymakey.leftArrowShort":"çep","makeymakey.rightArrow":"tîra rastê","makeymakey.rightArrowShort":"rast","makeymakey.spaceKey":"valahî","makeymakey.upArrow":"tîra jor","makeymakey.upArrowShort":"jor","makeymakey.whenKeyPressed":"dema ku pêlî bişkoka [KEY]ê hate kirin","makeymakey.whenKeysPressedInOrder":"dema ku bi rêzê pêlî [SEQUENCE]ê hate kirin","microbit.buttonsMenu.any":"her çi yek","microbit.clearDisplay":"ekranê paqij bike","microbit.defaultTextToDisplay":"Silav!","microbit.displaySymbol":"[MATRIX]ê nîşan bide","microbit.displayText":"nivîsa [TEXT]ê nîşan bide","microbit.gesturesMenu.jumped":"gavkirî","microbit.gesturesMenu.moved":"veguheztî","microbit.gesturesMenu.shaken":"hejandî","microbit.isButtonPressed":"pêlî bişkoka [BTN]ê hatiye kirin?","microbit.isTilted":"[DIRECTION] hatiye xwarkirin?","microbit.pinStateMenu.off":"girtî","microbit.pinStateMenu.on":"vekirî","microbit.tiltAngle":"pîvana xwarbûnê [DIRECTION]","microbit.tiltDirectionMenu.any":"her çi yek","microbit.tiltDirectionMenu.back":"paşve","microbit.tiltDirectionMenu.front":"pêşî","microbit.tiltDirectionMenu.left":"çep","microbit.tiltDirectionMenu.right":"rast","microbit.whenButtonPressed":"dema ku pêlî bişkoka [BTN]ê hate kirin","microbit.whenGesture":"dema ku bû [GESTURE]","microbit.whenPinConnected":"dema ku pîn [PIN]ê hate girêdan","microbit.whenTilted":"dema ku [DIRECTION] hate xwarkirin","music.categoryName":"Muzîk","music.changeTempo":"tempoyê bike [TEMPO]","music.drumBass":"(2) Bas Dahol","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Kabasa","music.drumClaves":"(9) Klaves","music.drumClosedHiHat":"(6) Hi-Hata Girtî","music.drumConga":"(14) Konga","music.drumCowbell":"(11) Zingil","music.drumCrashCymbal":"(4) Sentûr","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Çepik","music.drumOpenHiHat":"(5) Zengila Vekirî","music.drumSideStick":"(3) Darikê Kêlekê","music.drumSnare":"(1) Trampet","music.drumTambourine":"(7) Def","music.drumTriangle":"(12) Sêgoşe","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Bloka Text","music.getTempo":"tempo","music.instrumentBass":"(6) Bas","music.instrumentBassoon":"(14) Bassoon","music.instrumentCello":"(8) Selo","music.instrumentChoir":"(15) Koro","music.instrumentClarinet":"(10) Klarnet","music.instrumentElectricGuitar":"(5) Elektro Gîtar","music.instrumentElectricPiano":"(2) Elektro Piyano","music.instrumentFlute":"(12) Flut","music.instrumentGuitar":"(4) Gîtar","music.instrumentMarimba":"(19) Marîmba","music.instrumentMusicBox":"(17) Qutiya Muzîkê","music.instrumentOrgan":"(3) Org","music.instrumentPiano":"(1) Piyano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saksafon","music.instrumentSteelDrum":"(18) Dahola Polayê","music.instrumentSynthLead":"(20) Syntha Gulle","music.instrumentSynthPad":"(21) Synth Pad","music.instrumentTrombone":"(9) Trombon","music.instrumentVibraphone":"(16) Vîbrafon","music.instrumentWoodenFlute":"(13) Bilûr","music.midiPlayDrumForBeats":"dahola [DRUM]ê [BEATS] lêdana lêxe","music.midiSetInstrument":"amûrê bike [INSTRUMENT]","music.playDrumForBeats":"dahola [DRUM]ê [BEATS] lêdana lêxe","music.playNoteForBeats":"notaya [NOTE]ê [BEATS] lêdana lêxe","music.restForBeats":"[BEATS] lêdana bisekine","music.setInstrument":"amûrê bike [INSTRUMENT]","music.setTempo":"tempoyê bike [TEMPO]","pen.categoryName":"Pênûs","pen.changeColorParam":"pênûsa [COLOR_PARAM]ê bi [VALUE] re biguherîne","pen.changeHue":"rengê pênûsê bi qasî [HUE] zêde bike","pen.changeShade":"sîbera pênûsê bi qasî [SHADE] zêde bike","pen.changeSize":"mezinahiya pênûsê bi qasî [SIZE] zêde bike","pen.clear":"hemûyan jê bibe","pen.colorMenu.brightness":"ronahî","pen.colorMenu.color":"reng","pen.colorMenu.saturation":"têrbûn","pen.colorMenu.transparency":"zelalî","pen.penDown":"pênûsê pêxîne","pen.penUp":"pênûsê bilind bike","pen.setColor":"rengê pênûsê bike [COLOR]","pen.setColorParam":"pênûsa [COLOR_PARAM]ê bike [VALUE]","pen.setHue":"rengê pênûsê bike [HUE]","pen.setShade":"sîbera pênûsê bike [SHADE]","pen.setSize":"mezinahiya pênûsê bike [SIZE]","pen.stamp":"mohr bike","text2speech.alto":"alto","text2speech.categoryName":"Ji Nivîsê bo Deng","text2speech.defaultTextToSpeak":"silav","text2speech.giant":"dêw(hût)","text2speech.kitten":"çêlika pisîkê","text2speech.setLanguageBlock":"ziman bike [LANGUAGE]","text2speech.setVoiceBlock":"deng bike [VOICE]","text2speech.speakAndWaitBlock":"bipeyive [WORDS]","text2speech.squeak":"hawar","text2speech.tenor":"tenor","translate.categoryName":"Werger","translate.defaultTextToTranslate":"silav","translate.translateBlock":"nivîsa [WORDS]ê wergerîne zimanê [LANGUAGE]","translate.viewerLanguage":"ziman","videoSensing.categoryName":"Pêhisîna Vîdyoyê","videoSensing.direction":"hêla","videoSensing.motion":"tevgera","videoSensing.off":"bigire","videoSensing.on":"veke","videoSensing.onFlipped":"berevajîkirî","videoSensing.setVideoTransparency":"zelalbûna vîdyoyê bike [TRANSPARENCY]","videoSensing.sprite":"pêlîstik","videoSensing.stage":"dik","videoSensing.videoOn":"vîdyoya [ATTRIBUTE]ê ya li ser [SUBJECT]ê","videoSensing.videoToggle":"vîdyoyê [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"dema ku tevgera vîdyoyê bû > [REFERENCE]","wedo2.getDistance":"mesafe","wedo2.getTiltAngle":"pîvana xwarbûnê [TILT_DIRECTION]","wedo2.isTilted":"[TILT_DIRECTION_ANY] xwar bûye?","wedo2.motorDirection.backward":"wê hêla","wedo2.motorDirection.forward":"vê hêla","wedo2.motorDirection.reverse":"berevajî","wedo2.motorId.a":"motora A","wedo2.motorId.all":"tevahiya motoran","wedo2.motorId.b":"motora B","wedo2.motorId.default":"motor","wedo2.motorOff":"[MOTOR_ID]ê bigire","wedo2.motorOn":"[MOTOR_ID]ê veke","wedo2.motorOnFor":"[MOTOR_ID]ê [DURATION] çirkeyan bixebitîne","wedo2.playNoteFor":"notaya [NOTE]ê [DURATION] çirkeyan lêxe","wedo2.setLightHue":"rengê ronahiyê wekî [HUE] saz bike","wedo2.setMotorDirection":"berê motora [MOTOR_ID]ê bide [MOTOR_DIRECTION]ê","wedo2.startMotorPower":"hêza motora [MOTOR_ID]ê bike % [POWER]","wedo2.tiltDirection.any":"her çi yek","wedo2.tiltDirection.down":"jêr","wedo2.tiltDirection.left":"çep","wedo2.tiltDirection.right":"rast","wedo2.tiltDirection.up":"jor","wedo2.whenDistance":"dema ku mesafe bû [OP] [REFERENCE]","wedo2.whenTilted":"dema ku [TILT_DIRECTION_ANY] xwar bû","paint.paintEditor.hue":"Reng","paint.paintEditor.saturation":"Têrbûna Reng","paint.paintEditor.brightness":"Ronahî","paint.paintEditor.costume":"Kostum","paint.paintEditor.group":"Kom","paint.paintEditor.ungroup":"Komê belav bike","paint.paintEditor.undo":"Vegerîne","paint.paintEditor.redo":"Dîsa pêşve","paint.paintEditor.forward":"Pêşve","paint.paintEditor.backward":"Paşve","paint.paintEditor.front":"Herî Pêşî","paint.paintEditor.back":"Herî Paşî","paint.paintEditor.more":"Zêdetir","paint.modeTools.brushSize":"Mezinahî","paint.modeTools.eraserSize":"Mezinahiya jêbirkê","paint.modeTools.copy":"Kopî bike","paint.modeTools.paste":"Bizeliqîne","paint.modeTools.delete":"Jê bibe","paint.modeTools.curved":"Badayî","paint.modeTools.pointed":"Nîşankirî","paint.modeTools.thickness":"Qalindbûn","paint.modeTools.flipHorizontal":"Vexistî Bizîvirîne","paint.modeTools.flipVertical":"Stûnî Bizîvirîne","paint.modeTools.filled":"Tijebûyî","paint.modeTools.outlined":"Kurte","paint.paintEditor.bitmap":"Veguherîne Bitmapê","paint.paintEditor.vector":"Veguherîne Vektorê","paint.paintEditor.fill":"Tije bike","paint.paintEditor.stroke":"Puxte","paint.brushMode.brush":"Firçe","paint.eraserMode.eraser":"Jêbirk","paint.fillMode.fill":"Tije bike","paint.lineMode.line":"Çixêz","paint.ovalMode.oval":"Çember","paint.rectMode.rect":"Çarqozî","paint.reshapeMode.reshape":"Şêweyê biguherîne","paint.roundedRectMode.roundedRect":"Çarqoziya Çerxkirî","paint.selectMode.select":"Hilbijêre","paint.textMode.text":"Nivîs","paint.colorPicker.swap":"Pev Biguherîne"},"ckb":{"gui.alerts.tryAgain":"دوبارە هەوڵدەوە","gui.alerts.download":"داگرتن","gui.connection.reconnect":"پێکەوەبەستنەوە","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"کۆڵەپشت","gui.backpack.errorBackpack":"لە ئامادەکردنی کۆڵەپشت هەڵەڕوویدا","gui.backpack.loadingBackpack":"ئامادەکردن...","gui.backpack.more":"زیاتر","gui.backpack.emptyBackpack":"کۆڵەپشت بەتاڵە","gui.unsupportedBrowser.label":"وێبگەڕ پاڵپشتی نەکراوە","gui.cards.all-tutorials":"فێرکارییەکان","gui.cards.shrink":"وێک هاتن","gui.cards.expand":"فراوان کردن","gui.cards.close":"داخستن","gui.cards.more-things-to-try":"شتی زیاتر بۆ تاقیکردنەوە!","gui.cards.see-more":"زیاتر ببینە","gui.comingSoon.message1":"نیگەران مەبە، ئێمە خەریکین {emoji}","gui.comingSoon.message2":"بەم زووانە...","gui.comingSoon.message3":"ئێمە کاری لەسەر دەکەین {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"هیچ ئامێرێک نەدۆزرایەوە","gui.connection.auto-scanning.prescan":"ئامێرەکەت لەم نزیکانەیە، دواتر دەست بکە بە گەران.","gui.connection.auto-scanning.pressbutton":"دوگمەکە داگرە لەسەر ئامێرەکەت.","gui.connection.auto-scanning.start-search":"دەستپێکردنی گەڕان","gui.connection.connecting-searchbutton":"گەڕان...","gui.connection.auto-scanning.try-again":"دوبارە هەوڵدەوە","gui.connection.connected":"پێکەوەبەستراو","gui.connection.disconnect":"پچڕانی پەیوەندی","gui.connection.go-to-editor":"بڕۆ بۆ سەرنووسەر","gui.connection.connecting-cancelbutton":"پێکەوەبەستن...","gui.connection.error.errorMessage":"ئۆو، پێدەچێت هەڵەیەک ڕویدابێت.","gui.connection.error.tryagainbutton":"دوبارە هەوڵدەوە","gui.connection.error.helpbutton":"یارمەتی","gui.connection.peripheral-name-label":"ناوی ئامێر","gui.connection.connect":"پێکەوەبەستن","gui.connection.scanning.lookingforperipherals":"گەڕان بۆ ئامێرەکان","gui.connection.scanning.noPeripheralsFound":"هیچ ئامێرێک نەدۆزرایەوە","gui.connection.scanning.instructions":"ئامێرەکەت لە لیستەکەی سەرەوە دیاری بکە.","gui.connection.search":"تازەکردنەوە","gui.connection.unavailable.installscratchlink":"دڵنیابە لەوەی کە بەستەری سکڕاچ دامەزراوە و لە جێبەجێکردندایە","gui.connection.unavailable.enablebluetooth":"پشکنین بکە کە بلوتووس چالاککراوە","gui.connection.unavailable.tryagainbutton":"دوبارە هەوڵدەوە","gui.connection.unavailable.helpbutton":"یارمەتی","gui.controls.go":"بڕۆ","gui.controls.stop":"وەستان","gui.crashMessage.label":"ئۆو! هەڵەیەک ڕوویدا.","gui.crashMessage.errorNumber":"هەڵەکەت تۆمارکرا بە ژمارەی {errorId}","gui.crashMessage.reload":"ئامادەکردن","gui.customProcedures.myblockModalTitle":"دروستکردنی بلۆکێک","gui.customProcedures.addAnInputNumberText":"زیادکردنی تێخستەیەک","gui.customProcedures.numberTextType":"ژمارە یان دەق","gui.customProcedures.addAnInputBoolean":"زیادکردنی تێخستەیەک","gui.customProcedures.booleanType":"بوولی","gui.customProcedures.addALabel":"زیادکردنی ناونیشان","gui.customProcedures.runWithoutScreenRefresh":"جێبەجێی بکە بەبێ نوێبوونەوەی شاشە","gui.customProcedures.cancel":"پاشگەزبوونەوە","gui.customProcedures.ok":"باشە","gui.SpriteInfo.direction":"ئاڕاستە","gui.directionPicker.rotationStyles.allAround":"بەدەوری","gui.directionPicker.rotationStyles.leftRight":"چەپ/ڕاست","gui.directionPicker.rotationStyles.dontRotate":"مەیسوڕێنە","gui.gui.addExtension":"زیادکردنی زیادکراوە","gui.gui.codeTab":"کۆد","gui.gui.backdropsTab":"پاشبنه‌ماکان","gui.gui.costumesTab":"بەرگەکان","gui.gui.soundsTab":"دەنگەکان","gui.extensionLibrary.comingSoon":"بەم زووانە","gui.extensionLibrary.requires":"پێویستییەکان","gui.extensionLibrary.collaboration":"هاوکاریکردن لەگەڵ","gui.library.filterPlaceholder":"گەڕان","gui.library.allTag":"هەموو","gui.loader.headline":"ئامادەکردنی پڕۆژە","gui.loader.creating":"دروستکردنی پڕۆژە","gui.authorInfo.byUser":"لەلایەن {username}","gui.menuBar.seeProjectPage":"بینینی پەڕەی پڕۆژە","gui.menuBar.LanguageSelector":"هەڵبژێرەری زمان","gui.menuBar.tutorialsLibrary":"فێرکارییەکان","gui.menuBar.restoreSprite":"گەڕاندنەوەی تەن","gui.menuBar.restoreSound":"گەڕاندنەوەی دەنگ","gui.menuBar.restoreCostume":"گەڕاندنەوەی بەرگ","gui.menuBar.restore":"گەڕاندنەوە","gui.menuBar.saveNow":"ئێستا پاشەکەوتی بکە","gui.menuBar.saveAsCopy":"پاشەکەوتکردن وەک لەبەرگیراوەیەک","gui.menuBar.remix":"تێکەڵاوکردنەوە","gui.menuBar.new":"نوێ","gui.menuBar.file":"پەڕگە","gui.menuBar.downloadToComputer":"پاشەکەوتکردن لە کۆمپیوتەرەکەت","gui.menuBar.edit":"دەستکاری","gui.menuBar.turboModeOff":"کوژانەوەی دۆخی توربۆ","gui.menuBar.turboModeOn":"هەڵکردنی دۆخی توربۆ","gui.gui.projectTitlePlaceholder":"ناونیشانی پڕۆژە لێرە","gui.menuBar.isShared":"هاوبەش کراو","gui.menuBar.share":"هاوبەشی کردن","gui.modal.help":"یارمەتی","gui.modal.back":"دواوە","gui.monitor.listMonitor.empty":"(بەتاڵ)","gui.monitor.listMonitor.listLength":"درێژی {length}","gui.monitor.contextMenu.default":"پیشاندانی ئاسایی","gui.monitor.contextMenu.large":"پیشاندانی گەورە","gui.monitor.contextMenu.slider":"خلیسکێنەر","gui.monitor.contextMenu.sliderRange":"گۆڕینی ڕادەی خلیسکێنەر","gui.monitor.contextMenu.import":"هێنان","gui.monitor.contextMenu.export":"ناردنەدەرەوە","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"لێدان","gui.playButton.stop":"وەستان","gui.gui.variableScopeOptionAllSprites":"بۆ هەموو تەنەکان","gui.gui.variableScopeOptionSpriteOnly":"تەنها بۆ ئەم تەنە","gui.gui.cloudVariableOption":"گۆڕاوی هەور (پاشەکەوتکرا لەسەر ڕاژە)","gui.gui.variablePromptAllSpritesMessage":"ئەم گۆڕاوە بەردەستە بۆ هەموو تەنەکان.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"پاشگەزبوونەوە","gui.prompt.ok":"باشە","gui.playbackStep.stopMsg":"وەستان","gui.playbackStep.playMsg":"لێدان","gui.playbackStep.loadingMsg":"ئامادەکردن...","gui.playbackStep.saveMsg":"پاشەکەوتکردن","gui.playbackStep.reRecordMsg":"تۆمارکردنەوە","gui.recordModal.title":"تۆمارکردنی دەنگ","gui.recordingStep.beginRecord":"دەستپێکردنی تۆمارکردن بە کرتەکردن لەسەر دوگمەی خوارەوە","gui.recordingStep.permission":"{arrow}پێویستمان بە مۆڵەتی تۆیە بۆ بەکارهێنانی کامێڕاکەت","gui.recordingStep.stop":"وەستانی تۆمارکردن","gui.recordingStep.record":"تۆمارکردن","gui.sliderModal.min":"نزمترین نرخ","gui.sliderModal.max":"بەرزترین نرخ","gui.sliderModal.title":"گۆڕینی ڕادەی خلیسکێنەر","gui.sliderPrompt.cancel":"پاشگەزبوونەوە","gui.sliderPrompt.ok":"باشە","gui.soundEditor.sound":"دەنگ","gui.soundEditor.play":"لێدان","gui.soundEditor.stop":"وەستان","gui.soundEditor.copy":"لەبەرگرتنەوە","gui.soundEditor.paste":"لکاندن","gui.soundEditor.copyToNew":"لەبەرگرتنەوە بۆ نوێ","gui.soundEditor.delete":"سڕینەوە","gui.soundEditor.save":"پاشەکەوتکردن","gui.soundEditor.undo":"هه‌ڵوه‌شاندنه‌وه‌","gui.soundEditor.redo":"کردنەوە","gui.soundEditor.faster":"خێراتر","gui.soundEditor.slower":"هێواشتر","gui.soundEditor.echo":"دەنگ دانەوە","gui.soundEditor.robot":"ڕۆبۆت","gui.soundEditor.louder":"بەرزتر","gui.soundEditor.softer":"نەرمتر","gui.soundEditor.reverse":"پێچەوانە","gui.soundEditor.fadeOut":"کاڵبوونەوە","gui.soundEditor.fadeIn":"چڕبوون","gui.soundEditor.mute":"بێدەنگکردن","gui.SpriteInfo.spritePlaceholder":"ناو","gui.SpriteInfo.sprite":"تەن","gui.SpriteInfo.show":"بینین","gui.SpriteInfo.size":"قەبارە","gui.spriteSelectorItem.contextMenuDuplicate":"هاوشێوەکردنەوە","gui.spriteSelectorItem.contextMenuExport":"ناردنەدەرەوە","gui.spriteSelectorItem.contextMenuDelete":"سڕینەوە","gui.spriteSelector.addSpriteFromLibrary":"هەڵبژاردنی تەن","gui.spriteSelector.addSpriteFromPaint":"وێنەکێشان","gui.spriteSelector.addSpriteFromSurprise":"سەرسام بوون","gui.spriteSelector.addSpriteFromFile":"بارکردنی تەن","gui.stageHeader.stageSizeLarge":"گۆڕین بۆ سەکۆی گەورە","gui.stageHeader.stageSizeSmall":"گۆڕین بۆ سەکۆی بچووک","gui.stageHeader.stageSizeFull":"چوونە شێوازی پڕ بەشاشە","gui.stageHeader.stageSizeUnFull":"دەرچوون لە شێوازی پڕ بەشاشە","gui.stageHeader.fullscreenControl":"کۆنتڕۆڵی پڕ بەشاشە","gui.spriteSelector.addBackdropFromLibrary":"هەڵبژاردنی پاشبنەمایەک","gui.stageSelector.addBackdropFromPaint":"وێنەکێشان","gui.stageSelector.addBackdropFromSurprise":"سەرسام بوون","gui.stageSelector.addBackdropFromFile":"بارکردنی پاشبنەما","gui.stageSelector.stage":"سەکۆ","gui.stageSelector.backdrops":"پاشبنه‌ماکان","gui.telemetryOptIn.label":"ڕاپۆرت کردنی ئامارەکان بۆ پێشخستنی سکڕاچ","gui.telemetryOptIn.body1":"تیمی سكڕاچ هەردەم بە هیوان بۆ تێگەیشتنی باشتر کە چۆن سکڕاچ بەکاردێت لە هەموو دونیا. بۆ یارمەتی ئەم ئەرکە، تۆ دەتوانیت ڕێگە بدەیت سکڕاچ خۆکارانە زانیاری بەکارهاتوو بنێرێت بۆ تیمی سکڕاچ.","gui.telemetryOptIn.body2":"ئەو زانیارییانەی کە ئێمە کۆی دەکەینەوە بریتین لە هەڵبژاردەی زمان، بەکارهێنانەکانی بلۆک و هەندێک کرداری وەک پاشەکەوتکردن، ئامادەکردن و بارکردنی پڕۆژەیەک. ئێمە هیچ زانیارییەکی کەسی کۆ ناکەینەوە. تکایە {privacyPolicyLink} ئێمە ببینە بۆ زانیاری زیاتر.","gui.telemetryOptIn.privacyPolicyLink":"ڕێسای تایبەتمەندێتی","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"دۆخی توربۆ","gui.webglModal.label":"وێبگەڕەکەت پاڵپشتی WebGL ناکات","gui.webglModal.webgllink":"پاڵپشتی WebGL ناکات","gui.costumeLibrary.chooseABackdrop":"هەڵبژاردنی پاشبنەمایەک","gui.costumeLibrary.chooseACostume":"هەڵبژاردنی بەرگێک","gui.costumeTab.addBackdropFromLibrary":"هەڵبژاردنی پاشبنەمایەک","gui.costumeTab.addCostumeFromLibrary":"هەڵبژاردنی بەرگێک","gui.costumeTab.addBlankCostume":"وێنەکێشان","gui.costumeTab.addSurpriseCostume":"سەرسام بوون","gui.costumeTab.addFileBackdrop":"بارکردنی پاشبنەما","gui.costumeTab.addFileCostume":"بارکردنی بەرگ","gui.extensionLibrary.chooseAnExtension":"زیادکراوەیەک هەڵبژێرە","gui.extensionLibrary.extensionUrl":"بەستەری زیادکراوە داخڵ بکە","gui.monitors.importListColumnPrompt":"کام ستوون پێویستە بەکاربێت (1-{numberOfColumns})؟","gui.recordingStep.alertMsg":"تۆمارکردن نەتوانرا دەست پێبکرێت","gui.soundLibrary.chooseASound":"هەڵبژاردنی دەنگێک","gui.soundTab.fileUploadSound":"بارکردنی دەنگ","gui.soundTab.surpriseSound":"سەرسام بوون","gui.soundTab.recordSound":"تۆمارکردن","gui.soundTab.addSoundFromLibrary":"هەڵبژاردنی دەنگێک","gui.spriteLibrary.chooseASprite":"هەڵبژاردنی تەنێک","gui.tipsLibrary.tutorials":"فێرکارییەک هەڵبژێرە","gui.alerts.createsuccess":"پڕۆژەی نوێ دروستکرا.","gui.alerts.createcopysuccess":"پڕۆژە پاشەکەوتکرا وەک لەبەرگیراوەیەک.","gui.alerts.createremixsuccess":"پڕۆژەکە پاشەکەوت وەک تێکەڵاوییەک.","gui.alerts.creating":"دروستکردنی نوێ...","gui.alerts.creatingCopy":"لەبەرگرتنەوەی پڕۆژە...","gui.alerts.creatingRemix":"تێکەڵاوکردنی پڕۆژە...","gui.alerts.creatingError":"پڕۆژەکە نەتوانرا دروست بکرێت. تکایە دوبارە هەوڵبدەوە!","gui.alerts.savingError":"پڕۆژەکە نەتوانرا پاشەکەوت بکرێت.","gui.alerts.savesuccess":"پڕۆژە پاشەکەوتکرا.","gui.alerts.saving":"پڕۆژە پاشەکەوتدەکرێت...","gui.alerts.cloudInfo":"تکایە بزانە، گۆڕاوەکانی هەور تەنها پاڵپشتی ژمارە دەکەن، نەک پیتەکان و هێماکان. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"زیاتر فێربە.","gui.alerts.importing":"هێنان...","gui.defaultProject.variable":"گۆڕاوەکەم","gui.extension.music.name":"میوزیک","gui.extension.music.description":"لێدانی ئامرازەکان و تەپڵەکان.","gui.extension.pen.name":"پێنووس","gui.extension.pen.description":"بکێشە لەگەڵ تەنەکانت.","gui.extension.videosensing.name":"هەستی ڤیدیۆیی","gui.extension.videosensing.description":"هەستی جوڵان لەگەڵ کامێڕا.","gui.extension.text2speech.name":"دەق بۆ قسە","gui.extension.text2speech.description":"پڕۆژەکانت بە قسە بێنە.","gui.extension.translate.name":"وەرگێڕان","gui.extension.translate.description":"وەرگێڕانی دەق بۆ زۆر زمان.","gui.extension.makeymakey.description":"هەموو شتێک بخە سەر دوگمە.","gui.extension.microbit.description":"پڕۆژەکانت ببەستەوە لەگەڵ جیهان.","gui.extension.microbit.connectingMessage":"پێکەوەبەستن...","gui.extension.ev3.description":"ڕۆبۆتی بە کاردانەوە دروست بکە و زیاتر.","gui.extension.ev3.connectingMessage":"پەیوەندیکردن. دڵنیابە کە نێرکی EV3ەکەت داناوە بە 1234.","gui.extension.boost.description":"هێنانی دروستکراوی ڕۆبۆتی بۆ ژیان.","gui.extension.boost.connectingMessage":"پێکەوەبەستن...","gui.extension.wedo2.description":"لەگەڵ ماتۆڕ و هەستەوەرەکان دروست بکە.","gui.extension.wedo2.connectingMessage":"پێکەوەبەستن...","gui.extension.gdxfor.description":"هەستی پاڵنان، ڕاکێشان، جوڵان و سوڕان.","gui.extension.gdxfor.connectingMessage":"پێکەوەبەستن...","gui.libraryTags.all":"هەموو","gui.libraryTags.animals":"ئاژەڵەکان","gui.libraryTags.dance":"سەما","gui.libraryTags.effects":"کاریگەرییەکان","gui.libraryTags.fantasy":"خەیاڵاوی","gui.libraryTags.fashion":"مۆدە","gui.libraryTags.food":"خواردن","gui.libraryTags.indoors":"ناوەوە","gui.libraryTags.loops":"دووبارەبوونەوەکان","gui.libraryTags.music":"میوزیک","gui.libraryTags.notes":"تێبینییەکان","gui.libraryTags.outdoors":"دەرەوە","gui.libraryTags.patterns":"شێوەکان","gui.libraryTags.people":"خەڵک","gui.libraryTags.percussion":"ئاواز","gui.libraryTags.space":"بۆشایی","gui.libraryTags.sports":"یارییەکان","gui.libraryTags.underwater":"لەژێر ئاو","gui.libraryTags.voice":"دەنگ","gui.libraryTags.wacky":"سەیر","gui.libraryTags.animation":"وێنەی جوڵاو","gui.libraryTags.art":"هونەر","gui.libraryTags.games":"یارییەکان","gui.libraryTags.stories":"چیرۆکەکان","gui.libraryTags.letters":"پیتەکان","gui.opcodeLabels.direction":"ئاڕاستە","gui.opcodeLabels.xposition":"شوێنی x","gui.opcodeLabels.yposition":"شوێنی y","gui.opcodeLabels.size":"قەبارە","gui.opcodeLabels.costumename":"ناوی بەرگ","gui.opcodeLabels.costumenumber":"ژمارەی بەرگ","gui.opcodeLabels.backdropname":"ناوی پاشبنەما","gui.opcodeLabels.backdropnumber":"ژمارەی پاشبنەما","gui.opcodeLabels.volume":"قەبارە","gui.opcodeLabels.tempo":"خێرایی","gui.opcodeLabels.answer":"وەڵام","gui.opcodeLabels.loudness":"دەنگەدەنگ","gui.opcodeLabels.username":"ناوی بەکارهێنەر","gui.opcodeLabels.year":"ساڵ","gui.opcodeLabels.month":"مانگ","gui.opcodeLabels.date":"بەروار","gui.opcodeLabels.dayofweek":"ڕۆژی هەفتە","gui.opcodeLabels.hour":"کاتژمێر","gui.opcodeLabels.minute":"خولەک","gui.opcodeLabels.second":"چرکە","gui.opcodeLabels.timer":"کاتێنەر","gui.sharedMessages.backdrop":"پاشبنەما{index}","gui.sharedMessages.costume":"بەرگ{index}","gui.sharedMessages.sprite":"تەن{index}","gui.sharedMessages.pop":"پۆپ","gui.sharedMessages.replaceProjectWarning":"گۆڕینەوەی ناوەڕۆکی پڕۆژەی ئێستا؟","gui.sharedMessages.loadFromComputerTitle":"هێنان لە کۆمپیوتەرەکەت","boost.color.any":"هەر ڕەنگێک","boost.color.black":"ڕەش","boost.color.blue":"شین","boost.color.green":"سەوز","boost.color.red":"سور","boost.color.white":"سپی","boost.color.yellow":"زەرد","boost.getMotorPosition":"ماتۆڕ [MOTOR_REPORTER_ID] شوێن","boost.getTiltAngle":"گۆشەی لاری [TILT_DIRECTION]","boost.motorDirection.backward":"بەم ڕێگەیە","boost.motorDirection.forward":"بەو ڕێگەیە","boost.motorDirection.reverse":"پێچەوانە","boost.motorOff":"ماتۆڕی [MOTOR_ID] بکوژێنەوە","boost.motorOn":"ماتۆڕی [MOTOR_ID] پێبکە","boost.motorOnFor":"ماتۆڕی [MOTOR_ID] پێبکە بۆ [DURATION] چرکە","boost.motorOnForRotation":"ماتۆڕی [MOTOR_ID] پێبکە بۆ [ROTATION] سوڕان","boost.seeingColor":"بینینی خشتی [COLOR]؟","boost.setLightHue":"دانانی ڕووناکی ڕەنگ بە [HUE]","boost.setMotorDirection":"دانانی ئاڕاستەی ماتۆڕی [MOTOR_ID] بە [MOTOR_DIRECTION]","boost.setMotorPower":"دانانی خێرایی ماتۆڕی [MOTOR_ID] بە [POWER] %","boost.tiltDirection.any":"هەر کام","boost.tiltDirection.down":"ژێرەوە","boost.tiltDirection.left":"چەپ","boost.tiltDirection.right":"ڕاست","boost.tiltDirection.up":"سەرەوە","boost.whenColor":"کاتێک خشتی [COLOR] بینرا","boost.whenTilted":"کاتێک لارکرا [TILT_DIRECTION_ANY]","ev3.beepNote":"ئاماژەی بیپ [NOTE] بۆ [TIME] چرکە","ev3.buttonPressed":"دوگمەی [PORT] کرتەکرا؟","ev3.getBrightness":"ڕووناکی","ev3.getDistance":"دووری","ev3.getMotorPosition":"ماتۆڕ [PORT] شوێن","ev3.motorSetPower":"ماتۆڕ [PORT] دانانی هێز [POWER] ٪","ev3.motorTurnClockwise":"ماتۆڕ [PORT] ئەم ڕێگایە بگرە بۆ [TIME] چرکە","ev3.motorTurnCounterClockwise":"ماتۆڕ [PORT] ئەو ڕێگایە بگرە بۆ [TIME] چرکە","ev3.whenBrightnessLessThan":"کاتێک ڕووناکی < [DISTANCE]","ev3.whenButtonPressed":"کاتێک دوگمەی [PORT] کرتەکرا","ev3.whenDistanceLessThan":"کاتێک دووری < [DISTANCE]","gdxfor.getAcceleration":"گوڕ [DIRECTION]","gdxfor.getForce":"هێز","gdxfor.getSpin":"خێرایی خولانەوە [DIRECTION]","gdxfor.getTilt":"گۆشەی لارکردنەوە [TILT]","gdxfor.isFreeFalling":"دەکەوێت؟","gdxfor.isTilted":"لارکراو [TILT]؟","gdxfor.pulled":"ڕاکێشراو","gdxfor.pushed":"پاڵنراو","gdxfor.shaken":"هەژاو","gdxfor.startedFalling":"دەستی بە کەوتن کرد","gdxfor.tiltDirectionMenu.any":"هەر کام","gdxfor.tiltDirectionMenu.back":"دواوە","gdxfor.tiltDirectionMenu.front":"پێشەوە","gdxfor.tiltDirectionMenu.left":"چەپ","gdxfor.tiltDirectionMenu.right":"ڕاست","gdxfor.turnedFaceDown":"خوارکردنەوەی ڕوو","gdxfor.turnedFaceUp":"بەرزکردنەوەی ڕوو","gdxfor.whenForcePushedOrPulled":"کاتێک هەستەوەری هێز [PUSH_PULL]","gdxfor.whenGesture":"کاتێک [GESTURE]","gdxfor.whenTilted":"کاتێک لارکرا [TILT]","makeymakey.downArrow":"تیری خواروو","makeymakey.downArrowShort":"ژێرەوە","makeymakey.leftArrow":"تیری چەپ","makeymakey.leftArrowShort":"چەپ","makeymakey.rightArrow":"تیری ڕاست","makeymakey.rightArrowShort":"ڕاست","makeymakey.spaceKey":"بۆشایی","makeymakey.upArrow":"تیری سەروو","makeymakey.upArrowShort":"سەرەوە","makeymakey.whenKeyPressed":"کاتێک دوگمەی [KEY] کرتەکرا","makeymakey.whenKeysPressedInOrder":"کاتێک [SEQUENCE] کرتەکرا بە ڕیزبەندی","microbit.buttonsMenu.any":"هەر کام","microbit.clearDisplay":"سڕینەوەی شاشە","microbit.defaultTextToDisplay":"سڵاو!","microbit.displaySymbol":"پیشاندانی [MATRIX]","microbit.displayText":"پیشاندانی دەق [TEXT]","microbit.gesturesMenu.jumped":"بازدراو","microbit.gesturesMenu.moved":"جوڵاو","microbit.gesturesMenu.shaken":"هەژاو","microbit.isButtonPressed":"دوگمەی [BTN] کرتەکرا؟","microbit.isTilted":"لارکراو [DIRECTION]؟","microbit.pinStateMenu.off":"ناکارا","microbit.pinStateMenu.on":"کارا","microbit.tiltAngle":"گۆشەی لاری [DIRECTION]","microbit.tiltDirectionMenu.any":"هەر کام","microbit.tiltDirectionMenu.back":"دواوە","microbit.tiltDirectionMenu.front":"پێشەوە","microbit.tiltDirectionMenu.left":"چەپ","microbit.tiltDirectionMenu.right":"ڕاست","microbit.whenButtonPressed":"کاتێک دوگمەی [BTN] کرتەکرا","microbit.whenGesture":"کاتێک [GESTURE]","microbit.whenPinConnected":"کاتێک نێرکی [PIN] بەسترابوو","microbit.whenTilted":"کاتێک لارکرا [DIRECTION]","music.categoryName":"میوزیک","music.changeTempo":"گۆڕینی خێرایی بە [TEMPO]","music.drumBass":"(2) تەپڵی دەنگ قووڵ","music.drumBongo":"(13) بۆنگۆ","music.drumCabasa":"(15) کاباسا","music.drumClaves":"(9) کڵاڤیس","music.drumClosedHiHat":"(6) داخستنی Hi-Hat","music.drumConga":"(14) کۆنگا","music.drumCowbell":"(11) زەنگوڵە","music.drumCrashCymbal":"(4) سنج لێدان","music.drumCuica":"(18) کویکا","music.drumGuiro":"(16) گویڕۆ","music.drumHandClap":"(8) چەپڵە لێدان","music.drumOpenHiHat":"(5) کردنەوەی Hi-Hat","music.drumSideStick":"داری لا","music.drumSnare":"(1) تەپڵی داو","music.drumTambourine":"(7) تەپل","music.drumTriangle":"(12) سێگۆشە","music.drumVibraslap":"(17) ڤیبراسلاپ","music.drumWoodBlock":"(10) بلۆکی تەختە","music.getTempo":"خێرایی","music.instrumentBass":"(6) دەنگ قووڵ","music.instrumentBassoon":"(14) دووزەلە","music.instrumentCello":"(8) چەلۆ","music.instrumentChoir":"(15) دەستەی گۆرانی","music.instrumentClarinet":"(10) کلارنێت","music.instrumentElectricGuitar":"(5) گیتاری ئەلیکترۆنی","music.instrumentElectricPiano":"(2) پیانۆی ئەلیکترۆنی","music.instrumentFlute":"(12) فلوت","music.instrumentGuitar":"(4) گیتار","music.instrumentMarimba":"(19) ماريمبا","music.instrumentMusicBox":"(17) قوتوی میوزیک","music.instrumentOrgan":"(3) ئەندام","music.instrumentPiano":"(1) پیانۆ","music.instrumentPizzicato":"(7) پیزەکاتۆ","music.instrumentSaxophone":"(11) ساکسۆفۆن","music.instrumentSteelDrum":"(18) تەپڵی ئاسن","music.instrumentSynthLead":"(20) ژەنینی پێشەنگ","music.instrumentSynthPad":"(21) ژەنینی ناوەندی","music.instrumentTrombone":"(9) ترۆمبۆن","music.instrumentVibraphone":"(16) ڤیبرافۆن","music.instrumentWoodenFlute":"(13) فلوتی دار","music.midiPlayDrumForBeats":"لێدانی تەپڵ [DRUM] بۆ [BEATS] لێدان","music.midiSetInstrument":"دانانی ئامێر بە [INSTRUMENT]","music.playDrumForBeats":"لێدانی تەپڵ [DRUM] بۆ [BEATS] لیدان","music.playNoteForBeats":"لێدانی ئاماژەی [NOTE] بۆ [BEATS] لێدان","music.restForBeats":"پشوو بۆ [BEATS] لێدان","music.setInstrument":"دانانی ئامێر بە [INSTRUMENT]","music.setTempo":"دانانی خێرایی بە [TEMPO]","pen.categoryName":"پێنووس","pen.changeColorParam":"گۆڕینی پێنووس [COLOR_PARAM] بە [VALUE]","pen.changeHue":"گۆڕینی ڕەنگی پێنووس بە [HUE]","pen.changeShade":"گۆڕینی سێبەری پێنووس بە [SHADE]","pen.changeSize":"گۆڕینی قەبارەی پێنووس بە [SIZE]","pen.clear":"سڕینەوەی هەموو","pen.colorMenu.brightness":"ڕووناکی","pen.colorMenu.color":"ڕەنگ","pen.colorMenu.saturation":"تێری","pen.colorMenu.transparency":"ڕۆشنایی","pen.penDown":"پێنووس داگرتن","pen.penUp":"پێنووس بەرزکردن","pen.setColor":"دانانی ڕەنگی پێنووس بە [COLOR]","pen.setColorParam":"دانانی پێنووس [COLOR_PARAM] بە [VALUE]","pen.setHue":"دانانی ڕەنگی پێنووس بە [HUE]","pen.setShade":"دانانی سێبەری پێنووس بە [SHADE]","pen.setSize":"دانانی قەبارەی پێنووس بە [SIZE]","pen.stamp":"مۆر","text2speech.alto":"دەنگی مامناوەند","text2speech.categoryName":"دەق بۆ قسە","text2speech.defaultTextToSpeak":"سڵاو","text2speech.giant":"زل","text2speech.kitten":"بێچوه پشیله","text2speech.setLanguageBlock":"دانانی زمان بە [LANGUAGE]","text2speech.setVoiceBlock":"دانانی دەنگ بە [VOICE]","text2speech.speakAndWaitBlock":"قسە بکە [WORDS]","text2speech.squeak":"قیڕە","text2speech.tenor":"دەنگی مامناوەند","translate.categoryName":"وەرگێڕان","translate.defaultTextToTranslate":"سڵاو","translate.translateBlock":"وەرگێڕانی [WORDS] بۆ [LANGUAGE]","translate.viewerLanguage":"زمان","videoSensing.categoryName":"هەستی ڤیدیۆیی","videoSensing.direction":"ئاڕاستە","videoSensing.motion":"جوڵان","videoSensing.off":"ناکارا","videoSensing.on":"کارا","videoSensing.onFlipped":"لە هەڵگەڕانەوە","videoSensing.setVideoTransparency":"دانانی ڕۆشنایی ڤیدیۆ بە [TRANSPARENCY]","videoSensing.sprite":"تەن","videoSensing.stage":"سەکۆ","videoSensing.videoOn":"ڤیدیۆ [ATTRIBUTE] لەسەر [SUBJECT]","videoSensing.videoToggle":"ڤیدیۆ بکە بە [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"کاتێک جوڵەی ڤیدیۆ > [REFERENCE]","wedo2.getDistance":"دووری","wedo2.getTiltAngle":"گۆشەی لاری [TILT_DIRECTION]","wedo2.isTilted":"لارکراو [TILT_DIRECTION_ANY]؟","wedo2.motorDirection.backward":"بەم ڕێگەیە","wedo2.motorDirection.forward":"بەو ڕێگەیە","wedo2.motorDirection.reverse":"پێچەوانە","wedo2.motorId.a":"ماتۆڕ A","wedo2.motorId.all":"هەموو ماتۆڕەکان","wedo2.motorId.b":"ماتۆڕ B","wedo2.motorId.default":"ماتۆڕ","wedo2.motorOff":"[MOTOR_ID] بکوژێنەوە","wedo2.motorOn":"[MOTOR_ID] پێبکە","wedo2.motorOnFor":"[MOTOR_ID] پێبکە بۆ [DURATION] چرکە","wedo2.playNoteFor":"لێدانی ئاماژەی [NOTE] بۆ [DURATION] چرکە","wedo2.setLightHue":"دانانی ڕووناکی ڕەنگ بە [HUE]","wedo2.setMotorDirection":"دانانی ئاڕاستەی [MOTOR_ID] بە [MOTOR_DIRECTION]","wedo2.startMotorPower":"دانانی هێزی [MOTOR_ID] بە [POWER]","wedo2.tiltDirection.any":"هەر کام","wedo2.tiltDirection.down":"ژێرەوە","wedo2.tiltDirection.left":"چەپ","wedo2.tiltDirection.right":"ڕاست","wedo2.tiltDirection.up":"سەرەوە","wedo2.whenDistance":"کاتێک دووری [OP] [REFERENCE]","wedo2.whenTilted":"کاتێک لارکرا [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"ڕەنگ","paint.paintEditor.saturation":"تێری","paint.paintEditor.brightness":"ڕووناکی","paint.paintEditor.costume":"بەرگ","paint.paintEditor.group":"گروپ کردن","paint.paintEditor.ungroup":"نا گروپ کردن","paint.paintEditor.undo":"هه‌ڵوه‌شاندنه‌وه‌","paint.paintEditor.redo":"کردنەوە","paint.paintEditor.forward":"بۆ پێشەوە","paint.paintEditor.backward":"بۆ دواوە","paint.paintEditor.front":"پێشەوە","paint.paintEditor.back":"دواوە","paint.paintEditor.more":"زیاتر","paint.modeTools.brushSize":"قەبارە","paint.modeTools.eraserSize":"قەبارەی سڕەوە","paint.modeTools.copy":"لەبەرگرتنەوە","paint.modeTools.paste":"لکاندن","paint.modeTools.delete":"سڕینەوە","paint.modeTools.curved":"چەماوە","paint.modeTools.pointed":"ئاماژە بۆکراو","paint.modeTools.thickness":"ئەستوورایی","paint.modeTools.flipHorizontal":"هەڵگەڕانەوەی ئاسۆیی","paint.modeTools.flipVertical":"هەڵگەڕانەوەی ستوونی","paint.modeTools.filled":"پڕکراوە","paint.modeTools.outlined":"چوارچێوەکراو","paint.paintEditor.bitmap":"گۆڕینی بۆ Bitmap","paint.paintEditor.vector":"گۆڕینی بۆ Vector","paint.paintEditor.fill":"پڕکردنەوە","paint.paintEditor.stroke":"چوارچێوە","paint.brushMode.brush":"فڵچە","paint.eraserMode.eraser":"سڕەوە","paint.fillMode.fill":"پڕکردنەوە","paint.lineMode.line":"هێڵ","paint.ovalMode.oval":"بازنە","paint.rectMode.rect":"لاکێشە","paint.reshapeMode.reshape":"شێوەکردنەوە","paint.roundedRectMode.roundedRect":"لاکێشەی خڕ","paint.selectMode.select":"دیاریکردن","paint.textMode.text":"دەق","paint.colorPicker.swap":"ئاڵوگۆڕ"},"lv":{"gui.alerts.tryAgain":"Mēģini vēlreiz","gui.alerts.download":"Lejupielādēt","gui.connection.reconnect":"Savienot vēlreiz","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Mugursoma","gui.backpack.errorBackpack":"Kļūda ielādējot mugursomu","gui.backpack.loadingBackpack":"Ielādē ...","gui.backpack.more":"Vairāk","gui.backpack.emptyBackpack":"Mugursoma tukša","gui.unsupportedBrowser.label":"Pārlūks netiek atbalstīts","gui.cards.all-tutorials":"Apmācības","gui.cards.shrink":"Shrink","gui.cards.expand":"Expand","gui.cards.close":"Aizvērt","gui.cards.more-things-to-try":"Izmēģināt citas lietas!","gui.cards.see-more":"Skatīt vairāk","gui.comingSoon.message1":"Neuztraucies, mēs pie tā strādājam {emoji}","gui.comingSoon.message2":"Drīzumā...","gui.comingSoon.message3":"Mēs pie tā strādājam {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Nav atrasta neviena ierīce","gui.connection.auto-scanning.prescan":"Pārliecinies, ka ierīce ir tuvumā, tad sāc meklēšanu.","gui.connection.auto-scanning.pressbutton":"Spied pogu uz savas ierīces.","gui.connection.auto-scanning.start-search":"Sākt meklēšanu","gui.connection.connecting-searchbutton":"Meklē...","gui.connection.auto-scanning.try-again":"Mēģināt vēlreiz","gui.connection.connected":"Savienots","gui.connection.disconnect":"Atvienot","gui.connection.go-to-editor":"Doties uz redaktoru","gui.connection.connecting-cancelbutton":"Savienojas...","gui.connection.error.errorMessage":"Kaut kas nogāja greizi...","gui.connection.error.tryagainbutton":"Mēģināt vēlreiz","gui.connection.error.helpbutton":"Palīdzība","gui.connection.peripheral-name-label":"Ierīces nosaukums","gui.connection.connect":"Savienot","gui.connection.scanning.lookingforperipherals":"Meklē ierīces","gui.connection.scanning.noPeripheralsFound":"Nav atrasta neviena ierīce","gui.connection.scanning.instructions":"Izvēlies ierīci augšējā sarakstā.","gui.connection.search":"Atsvaidzināt","gui.connection.unavailable.installscratchlink":"Pārliecinies, ka Scratch Link ir instalēts un darbojas","gui.connection.unavailable.enablebluetooth":"Pārliecinies, ka Bluetooth ir iespējots","gui.connection.unavailable.tryagainbutton":"Mēģināt vēlreiz","gui.connection.unavailable.helpbutton":"Palīdzība","gui.controls.go":"Palaist","gui.controls.stop":"Apturēt","gui.crashMessage.label":"Kaut kas nogāja greizi...","gui.crashMessage.errorNumber":"Jūsu kļūda tika reģistrēta ar id {errorId}","gui.crashMessage.reload":"Pārlādēt","gui.customProcedures.myblockModalTitle":"Izveidot bloku","gui.customProcedures.addAnInputNumberText":"Pievienot ievadi","gui.customProcedures.numberTextType":"skaitlis vai teksts","gui.customProcedures.addAnInputBoolean":"Pievienot ievadi","gui.customProcedures.booleanType":"loģiskais lauks - jā/nē","gui.customProcedures.addALabel":"Pievienot etiķeti","gui.customProcedures.runWithoutScreenRefresh":"Palaist bez ekrāna atsvaidzināšanas","gui.customProcedures.cancel":"Atcelt","gui.customProcedures.ok":"Labi","gui.SpriteInfo.direction":"Virziens","gui.directionPicker.rotationStyles.allAround":"Jebkurā virzienā","gui.directionPicker.rotationStyles.leftRight":"Pa labi/Pa kreisi","gui.directionPicker.rotationStyles.dontRotate":"Nerotēt","gui.gui.addExtension":"Pievienot paplašinājumu","gui.gui.codeTab":"Kods","gui.gui.backdropsTab":"Foni","gui.gui.costumesTab":"Tērpi","gui.gui.soundsTab":"Skaņas","gui.extensionLibrary.comingSoon":"Drīzumā","gui.extensionLibrary.requires":"Nepieciešams","gui.extensionLibrary.collaboration":"Sadarbībā ar","gui.library.filterPlaceholder":"Meklēt","gui.library.allTag":"Viss","gui.loader.headline":"Ielādē projektu","gui.loader.creating":"Veido projektu","gui.authorInfo.byUser":"autors {username}","gui.menuBar.seeProjectPage":"Skatīt projekta lapu","gui.menuBar.LanguageSelector":"valodas izvēle","gui.menuBar.tutorialsLibrary":"Apmācības","gui.menuBar.restoreSprite":"Atjaunot gariņu","gui.menuBar.restoreSound":"Atjaunot skaņu","gui.menuBar.restoreCostume":"Atjaunot tērpu","gui.menuBar.restore":"Atjaunot","gui.menuBar.saveNow":"Saglabāt tagad","gui.menuBar.saveAsCopy":"Saglabāt kā kopiju","gui.menuBar.remix":"Remikss","gui.menuBar.new":"Jauns","gui.menuBar.file":"Fails","gui.menuBar.downloadToComputer":"Saglabāt šajā datorā","gui.menuBar.edit":"Rediģēt","gui.menuBar.turboModeOff":"Izslēgt turbo režīmu","gui.menuBar.turboModeOn":"Ieslēgt turbo režīmu","gui.gui.projectTitlePlaceholder":"Projekta virsraksts","gui.menuBar.isShared":"Kopīgotie","gui.menuBar.share":"Kopīgot","gui.modal.help":"Palīdzība","gui.modal.back":"Atpakaļ","gui.monitor.listMonitor.empty":"(tukšs)","gui.monitor.listMonitor.listLength":"garums {length}","gui.monitor.contextMenu.default":"normāls rādījums","gui.monitor.contextMenu.large":"liels rādījums","gui.monitor.contextMenu.slider":"slīdnis","gui.monitor.contextMenu.sliderRange":"change slider range","gui.monitor.contextMenu.import":"importēt","gui.monitor.contextMenu.export":"eksportēt","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Play","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"Visiem gariņiem","gui.gui.variableScopeOptionSpriteOnly":"Tikai šim gariņam","gui.gui.cloudVariableOption":"Mākoņmainīgais (saglabāts serverī)","gui.gui.variablePromptAllSpritesMessage":"Šis mainīgais būs pieejams visiem gariņiem.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Atcelt","gui.prompt.ok":"Labi","gui.playbackStep.stopMsg":"Apturēt","gui.playbackStep.playMsg":"Atskaņot","gui.playbackStep.loadingMsg":"Ielādē ...","gui.playbackStep.saveMsg":"Saglabāt","gui.playbackStep.reRecordMsg":"Atkārtoti ierakstīt","gui.recordModal.title":"Ierakstīt skaņu","gui.recordingStep.beginRecord":"Sāc ierakstīšanu, spiežot pogu zemāk","gui.recordingStep.permission":"{arrow}Mums nepieciešama tava atļauja, lai izmantotu mikrofonu","gui.recordingStep.stop":"Beigt ierakstīšanu","gui.recordingStep.record":"Ierakstīt","gui.sliderModal.min":"Minimum value","gui.sliderModal.max":"Maximum value","gui.sliderModal.title":"Change slider range","gui.sliderPrompt.cancel":"Cancel","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Skaņa","gui.soundEditor.play":"Atskaņot","gui.soundEditor.stop":"Apturēt","gui.soundEditor.copy":"Copy","gui.soundEditor.paste":"Paste","gui.soundEditor.copyToNew":"Copy to New","gui.soundEditor.delete":"Delete","gui.soundEditor.save":"Saglabāt","gui.soundEditor.undo":"Atsaukt","gui.soundEditor.redo":"Atcelt atsaukšanu","gui.soundEditor.faster":"Ātrāk","gui.soundEditor.slower":"Lēnāk","gui.soundEditor.echo":"Atbalss","gui.soundEditor.robot":"Robots","gui.soundEditor.louder":"Skaļāk","gui.soundEditor.softer":"Klusāk","gui.soundEditor.reverse":"Atpakaļgaitā","gui.soundEditor.fadeOut":"Fade out","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Mute","gui.SpriteInfo.spritePlaceholder":"Nosaukums","gui.SpriteInfo.sprite":"Gariņš","gui.SpriteInfo.show":"Rādīt","gui.SpriteInfo.size":"Izmērs","gui.spriteSelectorItem.contextMenuDuplicate":"dublēt","gui.spriteSelectorItem.contextMenuExport":"eksportēt","gui.spriteSelectorItem.contextMenuDelete":"dzēst","gui.spriteSelector.addSpriteFromLibrary":"Izvēlēties gariņu","gui.spriteSelector.addSpriteFromPaint":"Zīmēt","gui.spriteSelector.addSpriteFromSurprise":"Pārsteigums","gui.spriteSelector.addSpriteFromFile":"Augšupielādēt gariņu","gui.stageHeader.stageSizeLarge":"Pārslēgties uz lielu skatuvi","gui.stageHeader.stageSizeSmall":"Pārslēgties uz mazu skatuvi","gui.stageHeader.stageSizeFull":"Ieiet pilnekrāna režīmā","gui.stageHeader.stageSizeUnFull":"Iziet no pilnekrāna režīma","gui.stageHeader.fullscreenControl":"Pilnekrāna kontrole","gui.spriteSelector.addBackdropFromLibrary":"Izvēlēties Fonu","gui.stageSelector.addBackdropFromPaint":"Zīmēt","gui.stageSelector.addBackdropFromSurprise":"Pārsteigums","gui.stageSelector.addBackdropFromFile":"Augšupielādēt fonu","gui.stageSelector.stage":"Skatuve","gui.stageSelector.backdrops":"Foni","gui.telemetryOptIn.label":"Report statistics to improve Scratch","gui.telemetryOptIn.body1":"The Scratch Team is always looking to better understand how Scratch is used around the world. To help support this effort, you can allow Scratch to automatically send usage information to the Scratch Team.","gui.telemetryOptIn.body2":"The information we collect includes language selection, blocks usage, and some events like saving, loading, and uploading a project. We DO NOT collect any personal information. Please see our {privacyPolicyLink} for more information.","gui.telemetryOptIn.privacyPolicyLink":"Privātuma politika","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Turbo režīms","gui.webglModal.label":"Tavs Pārlūks Neatbalsta WebGL","gui.webglModal.webgllink":"neatbalsta WebGL","gui.costumeLibrary.chooseABackdrop":"Izvēlēties Fonu","gui.costumeLibrary.chooseACostume":"Izvēlēties tērpu","gui.costumeTab.addBackdropFromLibrary":"Izvēlēties Fonu","gui.costumeTab.addCostumeFromLibrary":"Izvēlēties tērpu","gui.costumeTab.addBlankCostume":"Zīmēt","gui.costumeTab.addSurpriseCostume":"Pārsteigums","gui.costumeTab.addFileBackdrop":"Augšupielādēt fonu","gui.costumeTab.addFileCostume":"Augšupielādēt tērpu","gui.extensionLibrary.chooseAnExtension":"Izvēlēties paplašinājumu","gui.extensionLibrary.extensionUrl":"Ievadīt URL paplašinājumam","gui.monitors.importListColumnPrompt":"Kura kolonna jāizmanto (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Nevar sākt ierakstīšanu","gui.soundLibrary.chooseASound":"Izvēlēties skaņu","gui.soundTab.fileUploadSound":"Augšupielādēt skaņu","gui.soundTab.surpriseSound":"Pārsteigums","gui.soundTab.recordSound":"Ierakstīt","gui.soundTab.addSoundFromLibrary":"Izvēlēties skaņu","gui.spriteLibrary.chooseASprite":"Izvēlēties gariņu","gui.tipsLibrary.tutorials":"Izvēlēties apmācību","gui.alerts.createsuccess":"Jauns projekts izveidots.","gui.alerts.createcopysuccess":"Projekts saglabāts kā kopija.","gui.alerts.createremixsuccess":"Projekts saglabāts kā remikss.","gui.alerts.creating":"Veido jaunu...","gui.alerts.creatingCopy":"Kopē projektu...","gui.alerts.creatingRemix":"Remiksē projektu...","gui.alerts.creatingError":"Nevar izveidot projektu. Mēģini vēlreiz!","gui.alerts.savingError":"Projektu nevar saglabāt.","gui.alerts.savesuccess":"Projekts saglabāts.","gui.alerts.saving":"Saglabā projektu...","gui.alerts.cloudInfo":"Lūdzu ievērojiet, ka mākoņmainīgie atbalsta tikai ciparus, nevis burtus vai simbolus. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Uzzināt vairāk.","gui.alerts.importing":"Importing…","gui.defaultProject.variable":"mans mainīgais","gui.extension.music.name":"Mūzika","gui.extension.music.description":"Spēlē instrumentus un bungas.","gui.extension.pen.name":"Zīmulis","gui.extension.pen.description":"Zīmē ar saviem gariņiem.","gui.extension.videosensing.name":"Video uztveršana","gui.extension.videosensing.description":"Uztver kustības ar kameru.","gui.extension.text2speech.name":"Teksta pārvēršana runā","gui.extension.text2speech.description":"Liec saviem projektiem runāt.","gui.extension.translate.name":"Tulkot","gui.extension.translate.description":"Pārtulko tekstu vairākās valodās.","gui.extension.makeymakey.description":"Pārveido jebkuru lietu par taustiņu.","gui.extension.microbit.description":"Savieno savus projektus ar pasauli.","gui.extension.microbit.connectingMessage":"Savienojas","gui.extension.ev3.description":"Būvē interaktīvus robotus un daudz ko citu.","gui.extension.ev3.connectingMessage":"Savienojas. Pārliecinies, ka tava EV3 pin kods ir 1234.","gui.extension.boost.description":"Bring robotic creations to life.","gui.extension.boost.connectingMessage":"Connecting","gui.extension.wedo2.description":"Būvēt ar motoriem un sensoriem.","gui.extension.wedo2.connectingMessage":"Savienojas","gui.extension.gdxfor.description":"Sense push, pull, motion, and spin.","gui.extension.gdxfor.connectingMessage":"Connecting","gui.libraryTags.all":"Viss","gui.libraryTags.animals":"Dzīvnieki","gui.libraryTags.dance":"Dejas","gui.libraryTags.effects":"Efekti","gui.libraryTags.fantasy":"Fantāzija","gui.libraryTags.fashion":"Mode","gui.libraryTags.food":"Ēdiens","gui.libraryTags.indoors":"Iekštelpas","gui.libraryTags.loops":"Loops","gui.libraryTags.music":"Mūzika","gui.libraryTags.notes":"Notis","gui.libraryTags.outdoors":"Brīvā daba","gui.libraryTags.patterns":"Patterns","gui.libraryTags.people":"Cilvēki","gui.libraryTags.percussion":"Perkusijas","gui.libraryTags.space":"Kosmoss","gui.libraryTags.sports":"Sports","gui.libraryTags.underwater":"Zemūdens","gui.libraryTags.voice":"Balss","gui.libraryTags.wacky":"Wacky","gui.libraryTags.animation":"Animācijas","gui.libraryTags.art":"Māksla","gui.libraryTags.games":"Spēles","gui.libraryTags.stories":"Stāsti","gui.libraryTags.letters":"Burti","gui.opcodeLabels.direction":"virziens","gui.opcodeLabels.xposition":"x pozīcija","gui.opcodeLabels.yposition":"y pozīcija","gui.opcodeLabels.size":"izmērs","gui.opcodeLabels.costumename":"tērpa nosaukums","gui.opcodeLabels.costumenumber":"tērpa numurs","gui.opcodeLabels.backdropname":"fona nosaukums","gui.opcodeLabels.backdropnumber":"fona numurs","gui.opcodeLabels.volume":"skaļums","gui.opcodeLabels.tempo":"temps","gui.opcodeLabels.answer":"atbilde","gui.opcodeLabels.loudness":"skaļums","gui.opcodeLabels.username":"lietotājvārds","gui.opcodeLabels.year":"gads","gui.opcodeLabels.month":"mēnesis","gui.opcodeLabels.date":"datums","gui.opcodeLabels.dayofweek":"nedēļas diena","gui.opcodeLabels.hour":"stunda","gui.opcodeLabels.minute":"minūte","gui.opcodeLabels.second":"sekunde","gui.opcodeLabels.timer":"taimeris","gui.sharedMessages.backdrop":"fons{index}","gui.sharedMessages.costume":"tērps{index}","gui.sharedMessages.sprite":"Gariņš{index}","gui.sharedMessages.pop":"paukšķis","gui.sharedMessages.replaceProjectWarning":"Replace contents of the current project?","gui.sharedMessages.loadFromComputerTitle":"Load from your computer","boost.color.any":"any color","boost.color.black":"black","boost.color.blue":"blue","boost.color.green":"green","boost.color.red":"red","boost.color.white":"white","boost.color.yellow":"yellow","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] position","boost.getTiltAngle":"tilt angle [TILT_DIRECTION]","boost.motorDirection.backward":"that way","boost.motorDirection.forward":"this way","boost.motorDirection.reverse":"reverse","boost.motorOff":"turn motor [MOTOR_ID] off","boost.motorOn":"turn motor [MOTOR_ID] on","boost.motorOnFor":"turn motor [MOTOR_ID] for [DURATION] seconds","boost.motorOnForRotation":"turn motor [MOTOR_ID] for [ROTATION] rotations","boost.seeingColor":"seeing [COLOR] brick?","boost.setLightHue":"set light color to [HUE]","boost.setMotorDirection":"set motor [MOTOR_ID] direction [MOTOR_DIRECTION]","boost.setMotorPower":"set motor [MOTOR_ID] speed to [POWER] %","boost.tiltDirection.any":"any","boost.tiltDirection.down":"down","boost.tiltDirection.left":"left","boost.tiltDirection.right":"right","boost.tiltDirection.up":"up","boost.whenColor":"when [COLOR] brick seen","boost.whenTilted":"when tilted [TILT_DIRECTION_ANY]","ev3.beepNote":"pīkstināt noti [NOTE] [TIME] sekundes","ev3.buttonPressed":"poga [PORT] piespiesta?","ev3.getBrightness":"gaišums","ev3.getDistance":"attālums","ev3.getMotorPosition":"motora [PORT] pozīcija","ev3.motorSetPower":"motoram [PORT] iestatīt enerģiju uz [POWER] %","ev3.motorTurnClockwise":"motoru [PORT] pagriezt šajā virzienā [TIME] sekundes","ev3.motorTurnCounterClockwise":"motoru [PORT] pagriezt tajā virzienā [TIME] sekundes","ev3.whenBrightnessLessThan":"kad gaišums < [DISTANCE]","ev3.whenButtonPressed":"kad poga [PORT] piespiesta","ev3.whenDistanceLessThan":"kad attālums < [DISTANCE]","gdxfor.getAcceleration":"paātrinājums [DIRECTION]","gdxfor.getForce":"spēks","gdxfor.getSpin":"spin speed [DIRECTION]","gdxfor.getTilt":"tilt angle [TILT]","gdxfor.isFreeFalling":"falling?","gdxfor.isTilted":"tilted [TILT]?","gdxfor.pulled":"pulled","gdxfor.pushed":"pushed","gdxfor.shaken":"shaken","gdxfor.startedFalling":"started falling","gdxfor.tiltDirectionMenu.any":"any","gdxfor.tiltDirectionMenu.back":"back","gdxfor.tiltDirectionMenu.front":"front","gdxfor.tiltDirectionMenu.left":"left","gdxfor.tiltDirectionMenu.right":"right","gdxfor.turnedFaceDown":"turned face down","gdxfor.turnedFaceUp":"turned face up","gdxfor.whenForcePushedOrPulled":"when force sensor [PUSH_PULL]","gdxfor.whenGesture":"when [GESTURE]","gdxfor.whenTilted":"when tilted [TILT]","makeymakey.downArrow":"lejuptaustiņš","makeymakey.downArrowShort":"uz leju","makeymakey.leftArrow":"kreisais bulttaustiņš","makeymakey.leftArrowShort":"pa kreisi","makeymakey.rightArrow":"labais bulttaustiņš","makeymakey.rightArrowShort":"pa labi","makeymakey.spaceKey":"atstarpe","makeymakey.upArrow":"augšuptaustiņš","makeymakey.upArrowShort":"uz augšu","makeymakey.whenKeyPressed":"when [KEY] key pressed","makeymakey.whenKeysPressedInOrder":"when [SEQUENCE] pressed in order","microbit.buttonsMenu.any":"jebkāds","microbit.clearDisplay":"notīrīt ekrānu","microbit.defaultTextToDisplay":"Sveiki!","microbit.displaySymbol":"rādīt [MATRIX]","microbit.displayText":"rādīt tekstu [TEXT]","microbit.gesturesMenu.jumped":"palēcās","microbit.gesturesMenu.moved":"pārvietojās","microbit.gesturesMenu.shaken":"pakratījās","microbit.isButtonPressed":"[BTN] poga piespiesta?","microbit.isTilted":"noliekts [DIRECTION]?","microbit.pinStateMenu.off":"izslēgts","microbit.pinStateMenu.on":"ieslēgts","microbit.tiltAngle":"noliekt leņķī [DIRECTION]","microbit.tiltDirectionMenu.any":"jebkur","microbit.tiltDirectionMenu.back":"uz aizmuguri","microbit.tiltDirectionMenu.front":"uz priekšu","microbit.tiltDirectionMenu.left":"pa kreisi","microbit.tiltDirectionMenu.right":"pa labi","microbit.whenButtonPressed":"kad poga [BTN] piespiesta","microbit.whenGesture":"kad [GESTURE]","microbit.whenPinConnected":"kad spraudnis [PIN] savienots","microbit.whenTilted":"kad noliekts [DIRECTION]","music.categoryName":"Mūzika","music.changeTempo":"mainīt tempu par [TEMPO]","music.drumBass":"(2) Basa bungas","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Kabasa","music.drumClaves":"(9) Klaves","music.drumClosedHiHat":"(6) Slēgtais Hi-Hat šķīvis","music.drumConga":"(14) Konga","music.drumCowbell":"(11) Zvans","music.drumCrashCymbal":"(4) Crash šķīvji","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Roku plaukšķis","music.drumOpenHiHat":"(5) Atvērts Hi-Hat šķīvis","music.drumSideStick":"(3) Bungu malas piesitiens","music.drumSnare":"(1) Solo bungas","music.drumTambourine":"(7) Tamburīns","music.drumTriangle":"(12) Trijstūris","music.drumVibraslap":"(17) Vibra slaperis","music.drumWoodBlock":"(10) Koka bloks","music.getTempo":"temps","music.instrumentBass":"(6) Bass","music.instrumentBassoon":"(14) Fagots","music.instrumentCello":"(8) Čells","music.instrumentChoir":"(15) Koris","music.instrumentClarinet":"(10) Klarnete","music.instrumentElectricGuitar":"(5) Elektriskā ģitāra","music.instrumentElectricPiano":"(2) Elektriskās klavieres","music.instrumentFlute":"(12) Flauta","music.instrumentGuitar":"(4) Ģitāra","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Mūzikas lādīte","music.instrumentOrgan":"(3) Ērģeles","music.instrumentPiano":"(1) Klavieres","music.instrumentPizzicato":"(7) Pičkato","music.instrumentSaxophone":"(11) Saksofons","music.instrumentSteelDrum":"(18) Metāla bungas","music.instrumentSynthLead":"(20) Galvenais sintezators","music.instrumentSynthPad":"(21) Pavadošais sintezators","music.instrumentTrombone":"(9) Trombons","music.instrumentVibraphone":"(16) Ksilofons","music.instrumentWoodenFlute":"(13) Koka flauta","music.midiPlayDrumForBeats":"spēlēt bungas [DRUM] [BEATS] sitienus","music.midiSetInstrument":"iestatīt instrumentu uz [INSTRUMENT]","music.playDrumForBeats":"spēlēt bungas [DRUM] [BEATS] sitienus","music.playNoteForBeats":"spēlēt noti [NOTE] [BEATS] sitienus","music.restForBeats":"pauze [BEATS] sitienus","music.setInstrument":"iestatīt instrumentu uz [INSTRUMENT]","music.setTempo":"iestatīt tempu uz [TEMPO]","pen.categoryName":"Zīmulis","pen.changeColorParam":"mainīt zīmuļa [COLOR_PARAM] par [VALUE]","pen.changeHue":"mainīt zīmuļa krāsu par [HUE]","pen.changeShade":"mainīt zīmuļa tumšumu par [SHADE]","pen.changeSize":"mainīt zīmuļa izmēru par [SIZE]","pen.clear":"notīrīt visu","pen.colorMenu.brightness":"gaišums","pen.colorMenu.color":"krāsa","pen.colorMenu.saturation":"piesātinājums","pen.colorMenu.transparency":"caurspīdīgums","pen.penDown":"zīmulis piespiests","pen.penUp":"zīmulis pacelts","pen.setColor":"iestatīt zīmuļa krāsu uz [COLOR]","pen.setColorParam":"iestatīt zīmuļa [COLOR_PARAM] uz [VALUE]","pen.setHue":"iestatīt zīmuļa krāsu uz [HUE]","pen.setShade":"iestatīt zīmuļa tumšumu uz [SHADE]","pen.setSize":"iestatīt zīmuļa izmēru uz [SIZE]","pen.stamp":"zīmogs","text2speech.alto":"alts","text2speech.categoryName":"Text to Speech","text2speech.defaultTextToSpeak":"hello","text2speech.giant":"milzis","text2speech.kitten":"kaķēns","text2speech.setLanguageBlock":"iestatīt valodu uz [LANGUAGE]","text2speech.setVoiceBlock":"iestatīt balsi uz [VOICE]","text2speech.speakAndWaitBlock":"teikt [WORDS]","text2speech.squeak":"pīkstiens","text2speech.tenor":"tenors","translate.categoryName":"Tulkot","translate.defaultTextToTranslate":"sveiki","translate.translateBlock":"tulkot [WORDS] uz [LANGUAGE]","translate.viewerLanguage":"valoda","videoSensing.categoryName":"Video uztveršana","videoSensing.direction":"virziens","videoSensing.motion":"kustība","videoSensing.off":"izslēgt","videoSensing.on":"ieslēgt","videoSensing.onFlipped":"ieslēgt apgrieztu","videoSensing.setVideoTransparency":"iestatīt video caurspīdīgumu uz [TRANSPARENCY]","videoSensing.sprite":"gariņš","videoSensing.stage":"skatuve","videoSensing.videoOn":"video [ATTRIBUTE] uz [SUBJECT]","videoSensing.videoToggle":"[VIDEO_STATE]video","videoSensing.whenMotionGreaterThan":"kad video kustība > [REFERENCE]","wedo2.getDistance":"attālums","wedo2.getTiltAngle":"noliekt leņķī [TILT_DIRECTION]","wedo2.isTilted":"noliekts [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"uz otru pusi","wedo2.motorDirection.forward":"uz šo pusi","wedo2.motorDirection.reverse":"apgriezt pretējā virzienā","wedo2.motorId.a":"motors A","wedo2.motorId.all":"visi motori","wedo2.motorId.b":"motors B","wedo2.motorId.default":"motors","wedo2.motorOff":"izslēgt [MOTOR_ID]","wedo2.motorOn":"ieslēgt [MOTOR_ID]","wedo2.motorOnFor":"ieslēgt [MOTOR_ID] [DURATION] sekundes","wedo2.playNoteFor":"spēlēt noti [NOTE] [DURATION] sekundes","wedo2.setLightHue":"iestatīt gaismas krāsu uz [HUE]","wedo2.setMotorDirection":"iestatīt [MOTOR_ID] virzienu uz [MOTOR_DIRECTION]","wedo2.startMotorPower":"iestatīt [MOTOR_ID] enerģiju uz [POWER]","wedo2.tiltDirection.any":"jebkādā virzienā","wedo2.tiltDirection.down":"uz leju","wedo2.tiltDirection.left":"pa kreisi","wedo2.tiltDirection.right":"pa labi","wedo2.tiltDirection.up":"uz augšu","wedo2.whenDistance":"kad attālums [OP][REFERENCE]","wedo2.whenTilted":"kad noliekts [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Krāsa","paint.paintEditor.saturation":"Piesātinājums","paint.paintEditor.brightness":"Gaišums","paint.paintEditor.costume":"Tērps","paint.paintEditor.group":"Grupēt","paint.paintEditor.ungroup":"Atgrupēt","paint.paintEditor.undo":"Atsaukt","paint.paintEditor.redo":"Atcelt atsaukšanu","paint.paintEditor.forward":"Uz priekšu","paint.paintEditor.backward":"Atpakaļ","paint.paintEditor.front":"Uz priekšpusi","paint.paintEditor.back":"Uz aizmuguri","paint.paintEditor.more":"Vairāk","paint.modeTools.brushSize":"Izmērs","paint.modeTools.eraserSize":"Dzēšgumijas izmērs","paint.modeTools.copy":"Kopēt","paint.modeTools.paste":"Ielīmēt","paint.modeTools.delete":"Dzēst","paint.modeTools.curved":"Izliekts","paint.modeTools.pointed":"Lauzts","paint.modeTools.thickness":"Biezums","paint.modeTools.flipHorizontal":"Apmest horizontāli","paint.modeTools.flipVertical":"Apmest vertikāli","paint.modeTools.filled":"Aizpildīts","paint.modeTools.outlined":"Neaizpildīts","paint.paintEditor.bitmap":"Pārvērst rastra grafikā","paint.paintEditor.vector":"Pārvērst vektorgrafikā","paint.paintEditor.fill":"Aizpildīt","paint.paintEditor.stroke":"Kontūra","paint.brushMode.brush":"Ota","paint.eraserMode.eraser":"Dzēšgumija","paint.fillMode.fill":"Aizpildīt","paint.lineMode.line":"Līnija","paint.ovalMode.oval":"Aplis","paint.rectMode.rect":"Taisnstūris","paint.reshapeMode.reshape":"Pārveidot","paint.roundedRectMode.roundedRect":"Noapaļots taisnstūris","paint.selectMode.select":"Atlasīt","paint.textMode.text":"Teksts","paint.colorPicker.swap":"Mainīt"},"lt":{"gui.alerts.tryAgain":"Pabandyk dar kartą","gui.alerts.download":"Atsisiųsti","gui.connection.reconnect":"Prisijungti iš naujo","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Kopijavimo aplankas","gui.backpack.errorBackpack":"Klaida įkeliant iš kopijavimo aplanko","gui.backpack.loadingBackpack":"Kraunasi...","gui.backpack.more":"Daugiau","gui.backpack.emptyBackpack":"Kopijavimo aplankas tuščias","gui.unsupportedBrowser.label":"Naršyklė nepalaikoma","gui.cards.all-tutorials":"Pamokos","gui.cards.shrink":"Sumažinti","gui.cards.expand":"Išskleisti","gui.cards.close":"Uždaryti","gui.cards.more-things-to-try":"Išbandyk daugiau dalykų!","gui.cards.see-more":"Žiūrėti daugiau","gui.comingSoon.message1":"Nesijaudink, mes tobuliname {emoji}","gui.comingSoon.message2":"Netrukus...","gui.comingSoon.message3":"Mes stengiamės ir tobuliname {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Nerasta jokių įrenginių","gui.connection.auto-scanning.prescan":"Pasiimk įrenginį prie savęs ir pradėk paiešką.","gui.connection.auto-scanning.pressbutton":"Nuspauskite mygtuką savo įrenginyje.","gui.connection.auto-scanning.start-search":"Pradėti paiešką","gui.connection.connecting-searchbutton":"Ieškoma...","gui.connection.auto-scanning.try-again":"Bandyti iš naujo","gui.connection.connected":"Prisijungta","gui.connection.disconnect":"Atsijungti","gui.connection.go-to-editor":"Grįžti į Redaktorių","gui.connection.connecting-cancelbutton":"Jungiamasi...","gui.connection.error.errorMessage":"Oi, atrodo kažkas ne taip.","gui.connection.error.tryagainbutton":"Bandyti iš naujo","gui.connection.error.helpbutton":"Pagalba","gui.connection.peripheral-name-label":"Įrenginio pavadinimas","gui.connection.connect":"Prisijungti","gui.connection.scanning.lookingforperipherals":"Ieškoma įrenginių","gui.connection.scanning.noPeripheralsFound":"Nerasta jokių įrenginių","gui.connection.scanning.instructions":"Pasirink įrenginį iš aukščiau esančio sąrašo.","gui.connection.search":"Atnaujinti","gui.connection.unavailable.installscratchlink":"Įsitikinkite, kad įdiegta ir veikia Scratch Link","gui.connection.unavailable.enablebluetooth":"Patikrinkite, ar Bluetooth funkcija įjungta","gui.connection.unavailable.tryagainbutton":"Bandyti iš naujo","gui.connection.unavailable.helpbutton":"Pagalba","gui.controls.go":"Pradėti","gui.controls.stop":"Stop","gui.crashMessage.label":"Oi, atrodo kažkas ne taip.","gui.crashMessage.errorNumber":"Klaida buvo užregistruota su ID {errorId}","gui.crashMessage.reload":"Atnaujinti","gui.customProcedures.myblockModalTitle":"Sukurti bloką","gui.customProcedures.addAnInputNumberText":"Pridėti įvestį","gui.customProcedures.numberTextType":"skaičius arba tekstas","gui.customProcedures.addAnInputBoolean":"Pridėti įvestį","gui.customProcedures.booleanType":"loginis tipas","gui.customProcedures.addALabel":"Pridėti etiketę","gui.customProcedures.runWithoutScreenRefresh":"Vykdyti be ekrano atnaujinimo","gui.customProcedures.cancel":"Atšaukti","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Kryptis","gui.directionPicker.rotationStyles.allAround":"Aplinkui","gui.directionPicker.rotationStyles.leftRight":"kairėn/dešinėn","gui.directionPicker.rotationStyles.dontRotate":"Nesisukti","gui.gui.addExtension":"Pridėti plėtinį","gui.gui.codeTab":"Programos kodas","gui.gui.backdropsTab":"Fonai","gui.gui.costumesTab":"Kaukės","gui.gui.soundsTab":"Garsai","gui.extensionLibrary.comingSoon":"Netrukus","gui.extensionLibrary.requires":"Reikalavimai","gui.extensionLibrary.collaboration":"Bendradarbiaujant su","gui.library.filterPlaceholder":"Paieška","gui.library.allTag":"Viskas","gui.loader.headline":"Kraunamas projektas","gui.loader.creating":"Projektas kuriamas","gui.authorInfo.byUser":"sukūrė {username}","gui.menuBar.seeProjectPage":"Į projekto puslapį","gui.menuBar.LanguageSelector":"kalbos pasirinkimas","gui.menuBar.tutorialsLibrary":"Pamokos","gui.menuBar.restoreSprite":"Atstatyti veikėją","gui.menuBar.restoreSound":"Atstatyti garsą","gui.menuBar.restoreCostume":"Atstatyti kaukę","gui.menuBar.restore":"Atstatyti","gui.menuBar.saveNow":"Išsaugoti dabar","gui.menuBar.saveAsCopy":"Išsaugoti kopiją","gui.menuBar.remix":"Perdaroma kūryba (remiksas)","gui.menuBar.new":"Naujas","gui.menuBar.file":"Failas","gui.menuBar.downloadToComputer":"Išsaugoti savo kompiuteryje","gui.menuBar.edit":"Taisyti","gui.menuBar.turboModeOff":"Išjungti Turbo režimą","gui.menuBar.turboModeOn":"Įjungti Turbo režimą","gui.gui.projectTitlePlaceholder":"Vieta projekto pavadinimui","gui.menuBar.isShared":"Dalinamasi","gui.menuBar.share":"Dalintis","gui.modal.help":"Pagalba","gui.modal.back":"Atgal","gui.monitor.listMonitor.empty":"(tuščia)","gui.monitor.listMonitor.listLength":"ilgis {length}","gui.monitor.contextMenu.default":"rodyti įprastai","gui.monitor.contextMenu.large":"rodyti didesnį","gui.monitor.contextMenu.slider":"slinktis","gui.monitor.contextMenu.sliderRange":"pakeisti slankiklio diapazoną","gui.monitor.contextMenu.import":"įkelti","gui.monitor.contextMenu.export":"eksportuoti","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Paleisti","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"Visiems veikėjams","gui.gui.variableScopeOptionSpriteOnly":"Tik šiam veikėjui","gui.gui.cloudVariableOption":"Kintamasis debesyje (išsaugotas serveryje)","gui.gui.variablePromptAllSpritesMessage":"Šis kintamasis bus prieinamas visiems veikėjams","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Atšaukti","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Stop","gui.playbackStep.playMsg":"Paleisti","gui.playbackStep.loadingMsg":"Kraunasi...","gui.playbackStep.saveMsg":"Išsaugoti","gui.playbackStep.reRecordMsg":"Įrašyti iš naujo","gui.recordModal.title":"Įrašyti garsą","gui.recordingStep.beginRecord":"Įrašui pradėti paspausk žemiau esantį mygtuką","gui.recordingStep.permission":"{arrow}Reikia tavo leidimo naudoti mikrofoną","gui.recordingStep.stop":"Baigti įrašymą","gui.recordingStep.record":"Įrašyti","gui.sliderModal.min":"Minimalus dydis","gui.sliderModal.max":"Maksimalus dydis","gui.sliderModal.title":"pakeisti slankiklio diapazoną","gui.sliderPrompt.cancel":"Atšaukti","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Garsas","gui.soundEditor.play":"Paleisti","gui.soundEditor.stop":"Stop","gui.soundEditor.copy":"Kopijuoti","gui.soundEditor.paste":"Įklijuoti","gui.soundEditor.copyToNew":"Kopijuoti kaip naują","gui.soundEditor.delete":"Ištrinti","gui.soundEditor.save":"Išsaugoti","gui.soundEditor.undo":"Atšaukti","gui.soundEditor.redo":"Grąžinti","gui.soundEditor.faster":"Greičiau","gui.soundEditor.slower":"Lėčiau","gui.soundEditor.echo":"Aidas","gui.soundEditor.robot":"Robotas","gui.soundEditor.louder":"Garsiau","gui.soundEditor.softer":"Tyliau","gui.soundEditor.reverse":"Atbulai","gui.soundEditor.fadeOut":"Išnykti","gui.soundEditor.fadeIn":"Išnyks","gui.soundEditor.mute":"Nutildyti","gui.SpriteInfo.spritePlaceholder":"Pavadinimas","gui.SpriteInfo.sprite":"Veikėjas","gui.SpriteInfo.show":"Rodyti","gui.SpriteInfo.size":"Dydis","gui.spriteSelectorItem.contextMenuDuplicate":"padaryti kopiją","gui.spriteSelectorItem.contextMenuExport":"eksportuoti","gui.spriteSelectorItem.contextMenuDelete":"šalinti","gui.spriteSelector.addSpriteFromLibrary":"Pasirink veikėją","gui.spriteSelector.addSpriteFromPaint":"Piešti","gui.spriteSelector.addSpriteFromSurprise":"Siurprizas","gui.spriteSelector.addSpriteFromFile":"Įkelti veikėją","gui.stageHeader.stageSizeLarge":"Pakeisti į didelę sceną","gui.stageHeader.stageSizeSmall":"Pakeisti į mažą sceną","gui.stageHeader.stageSizeFull":"Rodyti per visą ekraną","gui.stageHeader.stageSizeUnFull":"Išjungti rodymą per visą ekraną","gui.stageHeader.fullscreenControl":"Per visą ekraną","gui.spriteSelector.addBackdropFromLibrary":"Pasirink foną","gui.stageSelector.addBackdropFromPaint":"Piešti","gui.stageSelector.addBackdropFromSurprise":"Siurprizas","gui.stageSelector.addBackdropFromFile":"Įkelti foną","gui.stageSelector.stage":"Scena","gui.stageSelector.backdrops":"Fonai","gui.telemetryOptIn.label":"Dalinkis naudojimo statistika ir padėk mums tobulinti Scratch.","gui.telemetryOptIn.body1":"„Scratch“ komanda visada siekia geriau suprasti, kaip „Scratch“ naudojama visame pasaulyje. Norėdami padėti palaikyti šias pastangas, galite leisti „Scratch“ automatiškai siųsti naudojimo informaciją „Scratch“ komandai.","gui.telemetryOptIn.body2":"Mūsų renkama informacija apima kalbos pasirinkimą, blokų (komandų) naudojimą ir kai kuriuos įvykius, tokius kaip projekto išsaugojimas, įkėlimas ir pasidalijimas su kitais vartotojais. Mes nerenkame jokios asmeninės informacijos. Norėdami gauti daugiau informacijos, skaitykite mūsų {privacyPolicyLink}.","gui.telemetryOptIn.privacyPolicyLink":"Privatumo politika","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Turbo režimas","gui.webglModal.label":"Ši naršyklė nepalaiko WebGL","gui.webglModal.webgllink":"nepalaiko WebGL","gui.costumeLibrary.chooseABackdrop":"Pasirink foną","gui.costumeLibrary.chooseACostume":"Pasirink kaukę","gui.costumeTab.addBackdropFromLibrary":"Pasirink foną","gui.costumeTab.addCostumeFromLibrary":"Pasirink kaukę","gui.costumeTab.addBlankCostume":"Piešti","gui.costumeTab.addSurpriseCostume":"Siurprizas","gui.costumeTab.addFileBackdrop":"Įkelti foną","gui.costumeTab.addFileCostume":"Įkelti kaukę","gui.extensionLibrary.chooseAnExtension":"Pasirink plėtinį","gui.extensionLibrary.extensionUrl":"Įveskite plėtinio URL","gui.monitors.importListColumnPrompt":"Kuris stulpelis turėtų būti naudojamas (1- {numberOfColumns})?","gui.recordingStep.alertMsg":"Nepavyko pradėti įrašo","gui.soundLibrary.chooseASound":"Pasirink garsą","gui.soundTab.fileUploadSound":"Įkelti garsą","gui.soundTab.surpriseSound":"Siurprizas","gui.soundTab.recordSound":"Įrašyti","gui.soundTab.addSoundFromLibrary":"Pasirink garsą","gui.spriteLibrary.chooseASprite":"Pasirink veikėją","gui.tipsLibrary.tutorials":"Pasirink pamoką","gui.alerts.createsuccess":"Sukurta sėkmingai.","gui.alerts.createcopysuccess":"Projektas išsaugotas kaip kopija","gui.alerts.createremixsuccess":"Projektas išsaugotas kaip remiksas.","gui.alerts.creating":"Kuriamas naujas...","gui.alerts.creatingCopy":"Projektas kopijuojamas...","gui.alerts.creatingRemix":"Remiktuojamas projektas ...","gui.alerts.creatingError":"Nepavyko sukurti projekto. Pabandykite iš naujo!","gui.alerts.savingError":"Projekto išsaugoti nepavyko.","gui.alerts.savesuccess":"Projektas išsaugotas.","gui.alerts.saving":"Išsaugoma...","gui.alerts.cloudInfo":"Atminkite, kad debesų kintamieji palaiko tik skaičius, o ne raides ar simbolius. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Sužinok daugiau.","gui.alerts.importing":"Importuoti","gui.defaultProject.variable":"mano kintamasis","gui.extension.music.name":"Muzika","gui.extension.music.description":"Groti instrumentais ir būgnais.","gui.extension.pen.name":"Pieštukas","gui.extension.pen.description":"Piešti savo veikėjus.","gui.extension.videosensing.name":"Vaizdo jutikliai","gui.extension.videosensing.description":"Aptikti judesį naudojant kamerą.","gui.extension.text2speech.name":"Skaityti tekstą","gui.extension.text2speech.description":"Tavo projektai galės kalbėti.","gui.extension.translate.name":"Išversti","gui.extension.translate.description":"Versti tekstą į kitas kalbas.","gui.extension.makeymakey.description":"Iš bet ko padaryk klavišą.","gui.extension.microbit.description":"Jungti projektus su visu pasauliu.","gui.extension.microbit.connectingMessage":"Jungiamasi","gui.extension.ev3.description":"Sukurkite interaktyvius robotus ir dar daugiau.","gui.extension.ev3.connectingMessage":"Prisijungimas. Įsitikinkite, kad jūsų EV3 PIN kodas yra 1234.","gui.extension.boost.description":"Suteikite robotui gyvenimiškų bruožų","gui.extension.boost.connectingMessage":"Jungiamasi","gui.extension.wedo2.description":"Kurkite su motorais ir jutikliais.","gui.extension.wedo2.connectingMessage":"Jungiamasi","gui.extension.gdxfor.description":"Juskite traukimą, stūmimą, judesį ir sukimąsi","gui.extension.gdxfor.connectingMessage":"Jungiamasi","gui.libraryTags.all":"Viskas","gui.libraryTags.animals":"Gyvūnai","gui.libraryTags.dance":"Šokis","gui.libraryTags.effects":"Efektai","gui.libraryTags.fantasy":"Fantazija","gui.libraryTags.fashion":"Mada","gui.libraryTags.food":"Maistas","gui.libraryTags.indoors":"Viduje","gui.libraryTags.loops":"Ciklai","gui.libraryTags.music":"Muzika","gui.libraryTags.notes":"Natos","gui.libraryTags.outdoors":"Lauke","gui.libraryTags.patterns":"Raštai","gui.libraryTags.people":"Žmonės","gui.libraryTags.percussion":"Mušamieji","gui.libraryTags.space":"Kosmosas","gui.libraryTags.sports":"Sportas","gui.libraryTags.underwater":"Povandeninis pasaulis","gui.libraryTags.voice":"Balsas","gui.libraryTags.wacky":"Pašėlę","gui.libraryTags.animation":"Animacija","gui.libraryTags.art":"Menas","gui.libraryTags.games":"Žaidimai","gui.libraryTags.stories":"Pasakojimai","gui.libraryTags.letters":"Raidės","gui.opcodeLabels.direction":"kryptis","gui.opcodeLabels.xposition":"x koordinatė","gui.opcodeLabels.yposition":"y koordinatė","gui.opcodeLabels.size":"dydis","gui.opcodeLabels.costumename":"kaukės pavadinimas","gui.opcodeLabels.costumenumber":"kaukės numeris","gui.opcodeLabels.backdropname":"fono pavadinimas","gui.opcodeLabels.backdropnumber":"fono numeris","gui.opcodeLabels.volume":"garsas","gui.opcodeLabels.tempo":"tempas","gui.opcodeLabels.answer":"atsakymas","gui.opcodeLabels.loudness":"garsumas","gui.opcodeLabels.username":"vartotojo vardas","gui.opcodeLabels.year":"metai","gui.opcodeLabels.month":"mėnuo","gui.opcodeLabels.date":"data","gui.opcodeLabels.dayofweek":"savaitės diena","gui.opcodeLabels.hour":"valanda","gui.opcodeLabels.minute":"minutė","gui.opcodeLabels.second":"sekundė","gui.opcodeLabels.timer":"laikmatis","gui.sharedMessages.backdrop":"fonas{index}","gui.sharedMessages.costume":"kaukė{index}","gui.sharedMessages.sprite":"Veikėjas{index}","gui.sharedMessages.pop":"pokšt","gui.sharedMessages.replaceProjectWarning":"Ar nori pakeisti šio projekto turinį?","gui.sharedMessages.loadFromComputerTitle":"Įkelti iš kompiuterio","boost.color.any":"bet kuri spalva","boost.color.black":"juoda","boost.color.blue":"mėlyna","boost.color.green":"žalia","boost.color.red":"raudona","boost.color.white":"balta","boost.color.yellow":"geltona","boost.getMotorPosition":"variklio [MOTOR_REPORTER_ID] pozicija","boost.getTiltAngle":"paversk kryptimi [TILT_DIRECTION]","boost.motorDirection.backward":"šen","boost.motorDirection.forward":"ten","boost.motorDirection.reverse":"atvirkščiai","boost.motorOff":"išjunk variklį [MOTOR_ID] ","boost.motorOn":"įjunk variklį [MOTOR_ID] ","boost.motorOnFor":"suk variklį [MOTOR_ID] [DURATION] sekundes","boost.motorOnForRotation":"suk variklį [MOTOR_ID] [ROTATION] apsukas","boost.seeingColor":"matoma [COLOR] blokų?","boost.setLightHue":"keisti šviesos spalvą į [HUE]","boost.setMotorDirection":"nustatyti variklio [MOTOR_ID] kryptį [MOTOR_DIRECTION]","boost.setMotorPower":"nustatyti variklio [MOTOR_ID] greitį į [POWER] %","boost.tiltDirection.any":"bet kur","boost.tiltDirection.down":"žemyn","boost.tiltDirection.left":"kairėn","boost.tiltDirection.right":"dešinėn","boost.tiltDirection.up":"aukštyn","boost.whenColor":"kai [COLOR] bloko matoma ","boost.whenTilted":"kai paversta [TILT_DIRECTION_ANY]","ev3.beepNote":"groti natą [NOTE]tiek sekundžių: [TIME]","ev3.buttonPressed":"ar mygtukas [PORT] nuspaustas?","ev3.getBrightness":"šviesumas","ev3.getDistance":"atstumas","ev3.getMotorPosition":"[PORT] variklio pozicija","ev3.motorSetPower":"[PORT] varikliui nustatyti jėgą [POWER] %","ev3.motorTurnClockwise":"[PORT] variklį sukti šia kryptimi tiek sekundžių: [TIME]","ev3.motorTurnCounterClockwise":"[PORT] variklį sukti šia kryptimi tiek sekundžių: [TIME]","ev3.whenBrightnessLessThan":"kai šviesumas < [DISTANCE]","ev3.whenButtonPressed":"kai nuspaudžiamas mygtukas [PORT]","ev3.whenDistanceLessThan":"kai atstumas < [DISTANCE]","gdxfor.getAcceleration":"pagreitis [DIRECTION]","gdxfor.getForce":"jėga","gdxfor.getSpin":"sukimosi greitis [DIRECTION]]","gdxfor.getTilt":"pasvirk kampu [TILT]","gdxfor.isFreeFalling":"krenta?","gdxfor.isTilted":"Pasukta [TILT]?","gdxfor.pulled":"traukiama","gdxfor.pushed":"stumiama","gdxfor.shaken":"papurtyta","gdxfor.startedFalling":"pradėjo kristi","gdxfor.tiltDirectionMenu.any":"bet kur","gdxfor.tiltDirectionMenu.back":"atgal","gdxfor.tiltDirectionMenu.front":"priekin","gdxfor.tiltDirectionMenu.left":"kairėn","gdxfor.tiltDirectionMenu.right":"dešinėn","gdxfor.turnedFaceDown":"pasukti veidu žemyn","gdxfor.turnedFaceUp":"pasukti veidu aukštyn","gdxfor.whenForcePushedOrPulled":"kai jėgos jutiklis [PUSH_PULL]","gdxfor.whenGesture":"kai [GESTURE]","gdxfor.whenTilted":"pakreipus [TILT]","makeymakey.downArrow":"rodyklė žemyn","makeymakey.downArrowShort":"žemyn","makeymakey.leftArrow":"rodyklė kairėn","makeymakey.leftArrowShort":"kairėn","makeymakey.rightArrow":"rodyklė dešinėn","makeymakey.rightArrowShort":"dešinėn","makeymakey.spaceKey":"tarpas","makeymakey.upArrow":"rodyklė aukštyn","makeymakey.upArrowShort":"aukštyn","makeymakey.whenKeyPressed":"Kai [KEY] paspaustas","makeymakey.whenKeysPressedInOrder":"Kai seka [SEQUENCE] suvesta","microbit.buttonsMenu.any":"bet kuris","microbit.clearDisplay":"išvalyti ekraną","microbit.defaultTextToDisplay":"Sveiki!","microbit.displaySymbol":"rodyti [MATRIX]","microbit.displayText":"rodyti tekstą [TEXT]","microbit.gesturesMenu.jumped":"šuolis","microbit.gesturesMenu.moved":"pajudinta","microbit.gesturesMenu.shaken":"papurtyta","microbit.isButtonPressed":"ar nuspaustas mygtukas [BTN]?","microbit.isTilted":"ar paversta [DIRECTION]?","microbit.pinStateMenu.off":"išjungti","microbit.pinStateMenu.on":"įjungti","microbit.tiltAngle":"paversta kampu [DIRECTION]","microbit.tiltDirectionMenu.any":"bet kuris","microbit.tiltDirectionMenu.back":"atgal","microbit.tiltDirectionMenu.front":"pirmyn","microbit.tiltDirectionMenu.left":"kairėn","microbit.tiltDirectionMenu.right":"dešinėn","microbit.whenButtonPressed":"kai paspaudi mygtuką [BTN]","microbit.whenGesture":"kai [GESTURE]","microbit.whenPinConnected":"kai prijungtas kištukas [PIN]","microbit.whenTilted":"kai paversta [DIRECTION]","music.categoryName":"Muzika","music.changeTempo":"tempą padidink [TEMPO]","music.drumBass":"(2) Bosinis būgnas","music.drumBongo":"(13) Bongo būgnas","music.drumCabasa":"(15) Kabasa","music.drumClaves":"(9) Strypeliai","music.drumClosedHiHat":"(6) Uždaras haihetas","music.drumConga":"(14) Konga","music.drumCowbell":"(11) Skrabalas","music.drumCrashCymbal":"(4) „Crash“ lėkštės","music.drumCuica":"(18) Kuika","music.drumGuiro":"(16) Giras","music.drumHandClap":"(8) Pliaukštelėjimas delnais","music.drumOpenHiHat":"(5) Atviras haihetas","music.drumSideStick":"(3) Side Stick","music.drumSnare":"(1) Mažasis būgnas","music.drumTambourine":"(7) Tambūrinas","music.drumTriangle":"(12) Trikampis","music.drumVibraslap":"(17) Vibraslapis","music.drumWoodBlock":"(10) Trinkelė","music.getTempo":"tempas","music.instrumentBass":"(6) Bosas","music.instrumentBassoon":"(14) Fagotas","music.instrumentCello":"(8) Violončelė","music.instrumentChoir":"(15) Choras","music.instrumentClarinet":"(10) Klarnetas","music.instrumentElectricGuitar":"(5) Elektrinė gitara","music.instrumentElectricPiano":"(2) Sintezatorius","music.instrumentFlute":"(12) Fleita","music.instrumentGuitar":"(4) Gitara","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Muzikinė dėžutė","music.instrumentOrgan":"(3) Vargonai","music.instrumentPiano":"(1) Pianinas","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saksofonas","music.instrumentSteelDrum":"(18) Plieno būgnas","music.instrumentSynthLead":"(20) Solinis sintezatorius","music.instrumentSynthPad":"(21) Sintezatorius","music.instrumentTrombone":"(9) Trombonas","music.instrumentVibraphone":"(16) Vibrafonas","music.instrumentWoodenFlute":"(13) Medinė fleita","music.midiPlayDrumForBeats":"groti būgnu [DRUM] tiek taktų: [BEATS]","music.midiSetInstrument":"nustatyti instrumentą į [INSTRUMENT]","music.playDrumForBeats":"groti būgnu [DRUM] tiek taktų: [BEATS]","music.playNoteForBeats":"groti natą [NOTE] tiek taktų: [BEATS]","music.restForBeats":"pauzė tiek taktų: [BEATS]","music.setInstrument":"instrumentą nustatyti į [INSTRUMENT]","music.setTempo":"keisti tempą į [TEMPO] ","pen.categoryName":"Pieštukas","pen.changeColorParam":"keisk pieštuko [COLOR_PARAM]per[VALUE]","pen.changeHue":"keisk pieštuko spalvą per [HUE]","pen.changeShade":"keisk pieštuko atspalvį per [SHADE]","pen.changeSize":"keisk pieštuko dydį per [SIZE]","pen.clear":"ištrinti viską","pen.colorMenu.brightness":"šviesumas","pen.colorMenu.color":"spalva","pen.colorMenu.saturation":"sodrumas","pen.colorMenu.transparency":"permatomumas","pen.penDown":"pieštukas pieš","pen.penUp":"pieštukas nebepieš","pen.setColor":"keisti pieštuko spalvą į [COLOR]","pen.setColorParam":"piešimo [COLOR_PARAM] = [VALUE]","pen.setHue":"piešimo atspalvis = [HUE]","pen.setShade":"keisti pieštuko atspalvį į [SHADE]","pen.setSize":"keisti pieštuko dydį į [SIZE]","pen.stamp":"antspaudas","text2speech.alto":"alto balsas","text2speech.categoryName":"Skaityti tekstą","text2speech.defaultTextToSpeak":"sveiki","text2speech.giant":"milžino balsas","text2speech.kitten":"kačiukas","text2speech.setLanguageBlock":"keisti kalbą į [LANGUAGE]","text2speech.setVoiceBlock":"keisti balsą į [VOICE]","text2speech.speakAndWaitBlock":"sakyti [WORDS]","text2speech.squeak":"cyptelėjimas","text2speech.tenor":"tenoro balsas","translate.categoryName":"Išversti","translate.defaultTextToTranslate":"sveiki","translate.translateBlock":"išversti [WORDS] į [LANGUAGE]","translate.viewerLanguage":"kalba","videoSensing.categoryName":"Vaizdo jutikliai","videoSensing.direction":"kryptis","videoSensing.motion":"judesys","videoSensing.off":"Išjungti","videoSensing.on":"Įjungti","videoSensing.onFlipped":"kai apverčiama","videoSensing.setVideoTransparency":"nustatyk video permatomumą į[TRANSPARENCY]","videoSensing.sprite":"veikėjas","videoSensing.stage":"scena","videoSensing.videoOn":"video [ATTRIBUTE]iš[SUBJECT]","videoSensing.videoToggle":"perjungti video į [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"kai judesio vaizde > [REFERENCE]","wedo2.getDistance":"atstumas","wedo2.getTiltAngle":"paversta kryptimi [TILT_DIRECTION]","wedo2.isTilted":"ar paversta [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"šen","wedo2.motorDirection.forward":"ten","wedo2.motorDirection.reverse":"atbulai","wedo2.motorId.a":"variklis A","wedo2.motorId.all":"visi varikliai","wedo2.motorId.b":"variklis B","wedo2.motorId.default":"variklis","wedo2.motorOff":"išjungti [MOTOR_ID]","wedo2.motorOn":"įjungti [MOTOR_ID]","wedo2.motorOnFor":"įjungti [MOTOR_ID] [DURATION] sekundžių","wedo2.playNoteFor":"groti natą [NOTE] [DURATION] s.","wedo2.setLightHue":"spalvos tonas = [HUE]","wedo2.setMotorDirection":"[MOTOR_ID] kryptis = [MOTOR_DIRECTION]","wedo2.startMotorPower":"[MOTOR_ID] galia = [POWER]","wedo2.tiltDirection.any":"bet kuris","wedo2.tiltDirection.down":"žemyn","wedo2.tiltDirection.left":"kairėn","wedo2.tiltDirection.right":"dešinėn","wedo2.tiltDirection.up":"aukštyn","wedo2.whenDistance":"kai atstumas [OP] [REFERENCE]","wedo2.whenTilted":"kai paversta [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Spalva","paint.paintEditor.saturation":"Sodrumas","paint.paintEditor.brightness":"Šviesumas","paint.paintEditor.costume":"Kaukė","paint.paintEditor.group":"Grupuoti","paint.paintEditor.ungroup":"Išgrupuoti","paint.paintEditor.undo":"Atšaukti","paint.paintEditor.redo":"Grąžinti","paint.paintEditor.forward":"Artyn","paint.paintEditor.backward":"Tolyn","paint.paintEditor.front":"Į priekį","paint.paintEditor.back":"Atgal","paint.paintEditor.more":"Daugiau","paint.modeTools.brushSize":"Dydis","paint.modeTools.eraserSize":"Trintuko dydis","paint.modeTools.copy":"Kopijuoti","paint.modeTools.paste":"Įklijuoti","paint.modeTools.delete":"Šalinti","paint.modeTools.curved":"Lenktas","paint.modeTools.pointed":"Tiesus","paint.modeTools.thickness":"Storis","paint.modeTools.flipHorizontal":"Apversti horizontaliai","paint.modeTools.flipVertical":"Apversti vertikaliai","paint.modeTools.filled":"Užpildyta","paint.modeTools.outlined":"Su kontūru","paint.paintEditor.bitmap":"Keisti į piešinį taškais","paint.paintEditor.vector":"Keisti į piešinį linijomis","paint.paintEditor.fill":"Užpildymas","paint.paintEditor.stroke":"Kontūrai","paint.brushMode.brush":"Teptukas","paint.eraserMode.eraser":"Trintukas","paint.fillMode.fill":"Užpildyti","paint.lineMode.line":"Linija","paint.ovalMode.oval":"Apskritimas","paint.rectMode.rect":"Stačiakampis","paint.reshapeMode.reshape":"Pakeisti formą","paint.roundedRectMode.roundedRect":"Užapvalintas stačiakampis","paint.selectMode.select":"Pažymėti","paint.textMode.text":"Tekstas","paint.colorPicker.swap":"Sukeisti","tw.alerts.autosaving":"Atkuriamas atkūrimo taškas...","tw.alerts.lostPeripheralConnection":"Prarastas {extensionName} ryšys.","tw.alerts.savedToDisk":"Išsaugota į jūsų kompiuterį.","tw.backpack.rename":"Naujas vardas:","tw.browserModal.desc":"Įsitikinkite kad naudojate naujausią Google Chrome, Mozilla Firefox, Microsoft Edge, ar Apple Safari.","tw.changeUsername.cannotChangeWhileRunning":"Naudotojo vardas negali būti pakeistas kol projektas yra paleistas.","tw.cloudVariableBadge":"Šis projektas naudojasi debesies kintamaisiais. TurboWarp naudojasi savo atskiru debesies kintamųjų serveriu nepriklausomu nuo Scratch. Saugokitės apsimetinėjimo, nes bet kas gali pakeisti savo naudotojo vardą į bet kokį. {learnMore}","tw.code":"Šaltinio kodas","tw.confirmIncompatibleExtension":"Šis papildinys nėra suderinamas su Scratch. Projektai sukurti su šiuo papildiniu negali būti įkelti į Scratch svetainę. Ar jūs tikri kad norite jį įjungti?","tw.customExtension.description":"Užkrauti pasirinktinius papildinius iš URL. Kurėjams. Eksperimentinė funkcija.","tw.customExtension.name":"Pasirinktinis papildinys","tw.featuredProjectsStudio":"Peržiurėti studiją per Scratch.","tw.feedback":"Atsiliepimai ir Klaidos","tw.feedbackButton":"TurboWarp atsiliepimas","tw.footer.credits":"Padėkos","tw.footer.disclaimer":"TurboWarp nėra susietas su Scratch, the Scratch Team ar su the Scratch Foundation.","tw.footer.donate":"Paaukoti","tw.footer.embed":"Įterpimas","tw.footer.fosshost":"Hosting\'as suteiktas Fosshost","tw.footer.parameters":"URL Parametrai","tw.footer.translate":"Padėkite išversti TurboWarp","tw.gui.crashMessage.description":"Labai atsiprašome, bet atrodo, kad puslapis užstrigo. Prašome perkrauti puslapį ir pabandyti dar kartą.","tw.gui.defaultProjectTitle":"Projektas","tw.guiDefaultTitle":"Paleisk Scratch projektus greičiau","tw.home.credit":"Pastabos ir Padėkos","tw.home.description":"TurboWarp yra Scratch modifikacija, kuria projektai kompiliuojami į JavaScript, kad veiktų labai greitai. Išbandykite tai įvesdami projekto ID arba URL viršuje arba pasirinkdami rekomenduojamą projektą apačioje.","tw.home.instructions":"Instrukcijos","tw.input.tooltip":"Nukopijuokite ir įklijuokite Scratch projekto nuorodą čia!","tw.interpolationEnabled":"Interpoliacija","tw.invalidParameters.clones":"\\"klono\\" URL parametras yra neteisingas","tw.invalidParameters.fps":"\\"fps\\" URL parametras yra neteisingas","tw.loadError":"Nepavyksta įkelti projekto: {error}","tw.loader.assets.known":"atsisiunčiami duomenys ({complete}/{total}) ...","tw.loader.assets.unknown":"Duomenys įdiegiami.","tw.loader.data":"Projekto duomenys atsisiunčia...","tw.loader.generic":"Projektas kraunamas...","tw.menuBar.60off":"Išjungti 60 FPS režimą","tw.menuBar.60on":"Įjungti 60 FPS režimą","tw.menuBar.addons":"Įskiepiai","tw.menuBar.advanced":"Išplėstiniai","tw.menuBar.changeUsername":"Pakeisti Naudotojo vardą","tw.menuBar.cloudOff":"Išjungti Debesies kintamuosius","tw.menuBar.cloudOn":"Įjungti debesies kintamuosius","tw.menuBar.cloudUnavailable":"Debesies kintamieji nepasiekiami","tw.menuBar.cloudUnavailableAlert":"Negalite naudotis debesies kintamaisiais, tikriausia kad jūs įjungėte redaguotoją.","tw.menuBar.loadRestorePoint":"Užkrauti atkurimo tašką","tw.menuBar.moreSettings":"Išplėstiniai nustatymai","tw.menuBar.newFramerate":"Naujas kadrų per sekundę greitis:","tw.menuBar.package":"Supakuoti projektą","tw.menuBar.reportError1":"Kai kurie veikėjai negali būti sukompiliuoti.","tw.menuBar.reportError2":"Tai klaida. Prašau mums apie ją reportuoti.","tw.menuBar.saveAs":"Išsaugoti kaip {file}","tw.menuBar.seeInside":"Peržiurėti vidų","tw.oldDownload":"Išsaugoti į atskirą failą...","tw.paint.alpha":"Nepermatomumas","tw.privacy":"Privatumo politika","tw.restorePoint.confirm":"TurboWarp įrašo vieną automatinio atkūrimo tašką, jei kas nors nutiko ir pamiršote išsaugoti projektą. Tačiau negalime garantuoti, kad tai padės atkurti jūsų projektą. Pabandyti jį įkelti?","tw.restorePoint.loadFail":"Negalima užkrauti atkūrimo taško: {error}","tw.saveAs":"Išsaugoti kaip...","tw.saveTo":"Išsaugoti į {file}","tw.settingsModal.customStageSize":"Pasirinktinis Scenos dydis:","tw.settingsModal.customStageSizeHelp":"Pakeičia Scratch scenos dydį iš 480x360 į kitą. Išbandykite 640x360, kad scena būtų plačiaekranė. Tik nedaugelis projektų su tuo susidoros tinkamai.","tw.settingsModal.dangerZone":"Pavojinga zona","tw.settingsModal.disableCompiler":"Išjungti kompiliatorių","tw.settingsModal.disableCompilerHelp":"Išjungia TurboWarp kompiliatorių. Redaguodami projektus galite norėti įjungti šią funkciją, kad scenarijai būtų nedelsiant atnaujinami. Priešingu atveju niekada neturėtumėte įjungti šios funkcijos.","tw.settingsModal.featured":"Rekomenduojama","tw.settingsModal.fps":"60 FPS (Pasirinktiniai FPS)","tw.settingsModal.fpsHelp":"Paleidžia kodus 60 kadrų per sekundę greičiu užuot paleidus 30. Daugiausia projektų neveiks su šiuo nustatymu įjungtu. Pabandykite Interpoliaciją su 60 FPS režimu išjungtu jei tai priežastis. {customFramerate}.","tw.settingsModal.fpsHelp.customFramerate":"Spustelėkite kito nei 30 ar 60 kadrų per sekundę nustatymui","tw.settingsModal.help":"Spustėlkite dėl pagalbos","tw.settingsModal.highQualityPen":"Aukštos kokybės pieštukas","tw.settingsModal.highQualityPenHelp":"Leidžia pieštuko projektams veikti didesne skiriamąja geba ir išjungia kai kurių koordinačių apvalinimą redaktoriuje. Šis nustatymas nėra naudingas visiems projektams ir gali turėti įtakos našumui.","tw.settingsModal.infiniteClones":"Begaliniai Klonai","tw.settingsModal.infiniteClonesHelp":"Panaikina Scratch 300 klonų limitą.","tw.settingsModal.interpolation":"Interpoliacija","tw.settingsModal.interpolationHelp":"Projektai atrodo sklandžiau, nes interpoliuojamas personažų udėjimas. Interpoliacija neturėtų būti naudojama 3D projektuose, \\"Raytracer\\" projektuose, piešimo projektuose ir stringančiuose projektuose, nes dėl interpoliacijos jie veiks lėčiau, bet neatrodys sklandžiau.","tw.settingsModal.largeStageWarning":"Nerekomenduojama naudoti tokio dydžio pasirinktinio scenos dydžio! Vietoj to naudokite mažesnį dydį su tuo pačiu kraštinių santykiu ir leiskite viso ekrano režimui padidinti jo mastelį, kad jis atitiktų naudotojo ekraną.","tw.settingsModal.removeFencing":"Panaikinti scenos aptvarus","tw.settingsModal.removeFencingHelp":"Suteikia galimybę personažams judėti už ekrano ribų, tapti tokiais dideliais arba mažais, kokiais jie nori, ir leidžia liesti blokus už ekrano ribų.","tw.settingsModal.removeLimits":"Pašalinti limitus","tw.settingsModal.removeMiscLimits":"Pašalinti įvairius limitus.","tw.settingsModal.removeMiscLimitsHelp":"Pašalina garso efektų limitus bei pieštuko dydžio limitus.","tw.settingsModal.storeProjectOptions":"Išsaugoti nustatymus projekte.","tw.settingsModal.storeProjectOptionsHelp":"Įrašo pasirinktus nustatymus į projektą, kad jie būtų automatiškai taikomi, kai TurboWarp įkelia šį projektą. \\"Nukreipimo laikmatis\\" ir \\"išjungti kompiliatorių\\" nebus išsaugoti.","tw.settingsModal.title":"Išplėstiniai nustatymai","tw.settingsModal.warpTimer":"Nukreipimo laikmatis","tw.settingsModal.warpTimerHelp":"Kodai tikrina, ar jie nėra įstrigę ilgoje arba begalinėje kilpoje, ir veikia nedideliu kadrų dažniu, užuot įstrigę, kol kilpa baigsis. Tai išsprendžia daugumą gedimų, tačiau turi didelį poveikį našumui, todėl pagal numatytuosius nustatymus ši funkcija įjungta tik redaktoriuje.","tw.spriteSelectorItem.rename":"pervardinti","tw.studioview.authorAttribution":"Sukurta {author}","tw.studioview.error":"Kraunant kitą projektų puslapį įvyko klaida.","tw.studioview.hoverText":"{title} sukurta {author}","tw.twExtension.description":"Keisti nauji blokai. Nesuderinami su Scratch.","tw.twExtension.name":"TurboWarp Blokai","tw.unshared.1":"Dėl būsimų Scratch API pakeitimų ateityje nebegalėsite pasiekti nesidalijamų projektų naudodami tik jų projekto ID.","tw.unshared.2":"Dėl daugiau informacijos, aplankykite: {link}","tw.usernameModal.help":"Ši vertė bus išsaugota jūsų naršyklės saugykloje. Ji turėtų būti prijungta kai naudojates projektais kurie turi debesies kintamuosius.","tw.usernameModal.help2":"Vertes, kurios neatitinka galiojančios Scratch paskyros, debesies kintamųjų serveris paprastai atmeta. Rekomenduojame palikti jį tokį, koks yra, arba pakeisti į Scratch naudotojo vardą.","tw.usernameModal.mustChange":"Atsiprašome, bet debesies kintamųjų serveris mano kad jūsų naudotojo vardas gali būti nesaugus. Prašome jį pakeisti arba {resetIt}.","tw.usernameModal.mustChange.resetIt":"Iš naujo nustatyti jį (rekomenduojama)","tw.usernameModal.reset":"nustatyti iš naujo","tw.usernameModal.title":"Pakeisti Naudotojo vardą","tw.viewFeaturedProjects":"Spustelkite kad pažiurėtumėte rekomenduojamus projektus.","tw.viewOnScratch":"Peržiurėti projektą per Scratch","tw.webglModal.description":"Deja, atrodo, kad jūsų naršyklė arba kompiuteris nepalaiko {webGlLink}. Ši technologija reikalinga, kad ši svetainė veiktų. Pabandykite atnaujinti naršyklę ir grafikos tvarkykles arba iš naujo paleiskite kompiuterį."},"hu":{"gui.alerts.tryAgain":"Próbáld újra","gui.alerts.download":"Letöltés","gui.connection.reconnect":"Csatlakozz újra","gui.backpack.costumeLabel":"jelmez","gui.backpack.soundLabel":"hang","gui.backpack.scriptLabel":"kód","gui.backpack.spriteLabel":"szereplő","gui.backpack.header":"Tálca","gui.backpack.errorBackpack":"Hiba a tálca betöltésekor","gui.backpack.loadingBackpack":"Betöltés...","gui.backpack.more":"Több","gui.backpack.emptyBackpack":"A tálca üres","gui.unsupportedBrowser.label":"A böngésző nem támogatott","gui.cards.all-tutorials":"Gyakorlatok","gui.cards.shrink":"Kicsinyítés","gui.cards.expand":"Kibont","gui.cards.close":"Bezár","gui.cards.more-things-to-try":"Még több minden kipróbálható!","gui.cards.see-more":"Még több","gui.comingSoon.message1":"Ne aggódj, rajta vagyunk {emoji}","gui.comingSoon.message2":"Hamarosan...","gui.comingSoon.message3":"Dolgozunk rajta {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Nem találtunk eszközöket","gui.connection.auto-scanning.prescan":"Legyen a készüléked a közelben, majd kezd meg a keresést.","gui.connection.auto-scanning.pressbutton":"Nyomd meg a gombot az eszközödön.","gui.connection.auto-scanning.start-search":"Keresés indítása","gui.connection.connecting-searchbutton":"Keresés...","gui.connection.auto-scanning.try-again":"Próbáld újra","gui.connection.connected":"Csatlakoztatva","gui.connection.disconnect":"Szétkapcsolás","gui.connection.go-to-editor":"Menj a szerkesztőbe","gui.connection.connecting-cancelbutton":"Csatlakozás…","gui.connection.error.errorMessage":"Hoppá, úgy tűnik valami rosszul sikerült.","gui.connection.error.tryagainbutton":"Próbáld újra","gui.connection.error.helpbutton":"Súgó","gui.connection.peripheral-name-label":"Eszköz neve","gui.connection.connect":"Csatlakozás","gui.connection.scanning.lookingforperipherals":"Készülékek keresése","gui.connection.scanning.noPeripheralsFound":"Nem találtunk eszközöket","gui.connection.scanning.instructions":"Válaszd ki az eszközödet a fenti listából.","gui.connection.search":"Frissítés","gui.connection.unavailable.installscratchlink":"Győződj meg róla, hogy a Scratch Link telepítve van és fut","gui.connection.unavailable.enablebluetooth":"Ellenőrizd, hogy a Bluetooth engedélyezve van-e","gui.connection.unavailable.tryagainbutton":"Próbáld újra","gui.connection.unavailable.helpbutton":"Súgó","gui.controls.go":"Indulás","gui.controls.stop":"Állj","gui.crashMessage.label":"Hoppá! Valami rosszul sikerült.","gui.crashMessage.errorNumber":"A hibádat ezzel az azonosítóval naplóztuk: {errorId}","gui.crashMessage.reload":"Újratöltés","gui.customProcedures.myblockModalTitle":"Blokk létrehozása","gui.customProcedures.addAnInputNumberText":"Bemenet hozzáadása","gui.customProcedures.numberTextType":"szám vagy szöveg","gui.customProcedures.addAnInputBoolean":"Bemenet hozzáadása","gui.customProcedures.booleanType":"logikai","gui.customProcedures.addALabel":"Címke hozzáadás","gui.customProcedures.runWithoutScreenRefresh":"Futtatás képernyőfrissítés nélkül","gui.customProcedures.cancel":"Mégsem","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Irány","gui.directionPicker.rotationStyles.allAround":"Mindenfelé","gui.directionPicker.rotationStyles.leftRight":"Balra-jobbra","gui.directionPicker.rotationStyles.dontRotate":"Nem foroghat","gui.gui.addExtension":"Bővítmény hozzáadása","gui.gui.codeTab":"Kód","gui.gui.backdropsTab":"Hátterek","gui.gui.costumesTab":"Jelmezek","gui.gui.soundsTab":"Hangok","gui.extensionLibrary.comingSoon":"Hamarosan","gui.extensionLibrary.requires":"Igények","gui.extensionLibrary.collaboration":"Együttműködés","gui.library.filterPlaceholder":"Keresés","gui.library.allTag":"Minden","gui.loader.headline":"Projekt betöltése","gui.loader.creating":"Projekt létrehozása","gui.authorInfo.byUser":"{username} által","gui.menuBar.seeProjectPage":"Vissza a projekt oldalára","gui.menuBar.LanguageSelector":"nyelvválasztó","gui.menuBar.tutorialsLibrary":"Gyakorlatok","gui.menuBar.restoreSprite":"Szereplő helyreállítása","gui.menuBar.restoreSound":"Hang visszaállítása","gui.menuBar.restoreCostume":"Jelmez visszaállítása","gui.menuBar.restore":"Helyreállítás","gui.menuBar.saveNow":"Mentés most","gui.menuBar.saveAsCopy":"Mentés másolatként","gui.menuBar.remix":"Remixelés","gui.menuBar.new":"Új","gui.menuBar.file":"Fájl","gui.menuBar.downloadToComputer":"Letöltés saját gépre","gui.menuBar.edit":"Szerkesztés","gui.menuBar.turboModeOff":"Turbó mód kikapcsolása","gui.menuBar.turboModeOn":"Turbó mód bekapcsolása","gui.gui.projectTitlePlaceholder":"Project címe","gui.menuBar.isShared":"Megosztva","gui.menuBar.share":"Megosztás","gui.modal.help":"Súgó","gui.modal.back":"Vissza","gui.monitor.listMonitor.empty":"(üres)","gui.monitor.listMonitor.listLength":"hosszúság {length}","gui.monitor.contextMenu.default":"normál kijelző","gui.monitor.contextMenu.large":"nagy kijelző","gui.monitor.contextMenu.slider":"csúszka","gui.monitor.contextMenu.sliderRange":"csúszka tartomány megváltoztatása","gui.monitor.contextMenu.import":"importálás","gui.monitor.contextMenu.export":"exportálás","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Lejátszás","gui.playButton.stop":"Állj","gui.gui.variableScopeOptionAllSprites":"Minden szereplőé","gui.gui.variableScopeOptionSpriteOnly":"A kiválasztott szereplőé","gui.gui.cloudVariableOption":"Megosztott változó (szerveren tárolt)","gui.gui.variablePromptAllSpritesMessage":"Ez a változó minden szereplőek elérhető lesz","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Mégsem","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Állj","gui.playbackStep.playMsg":"Lejátszás","gui.playbackStep.loadingMsg":"Betöltés...","gui.playbackStep.saveMsg":"Mentés","gui.playbackStep.reRecordMsg":"Újrafelvétel","gui.recordModal.title":"Hang felvétele","gui.recordingStep.beginRecord":"Az alábbi gombra kattintva kezdheted a felvételt","gui.recordingStep.permission":"{arrow}Az engedélyedre van szükségünk a mikrofonod használatához ","gui.recordingStep.stop":"Felvétel leállítása","gui.recordingStep.record":"Felvétel","gui.sliderModal.min":"Minimum érték","gui.sliderModal.max":"Maximum érték","gui.sliderModal.title":"Csúszka tartomány megváltoztatása","gui.sliderPrompt.cancel":"Mégsem","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Hang","gui.soundEditor.play":"Lejátszás","gui.soundEditor.stop":"Állj","gui.soundEditor.copy":"Másolás","gui.soundEditor.paste":"Beillesztés","gui.soundEditor.copyToNew":"Copy to New","gui.soundEditor.delete":"Törlés","gui.soundEditor.save":"Mentés","gui.soundEditor.undo":"Visszavonás","gui.soundEditor.redo":"Mégis","gui.soundEditor.faster":"Gyorsabban","gui.soundEditor.slower":"Lassabban","gui.soundEditor.echo":"Visszhang","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Hangosabban","gui.soundEditor.softer":"Lágyabban","gui.soundEditor.reverse":"Visszafelé","gui.soundEditor.fadeOut":"Fade out","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Lenémítás","gui.SpriteInfo.spritePlaceholder":"Név","gui.SpriteInfo.sprite":"Szereplő","gui.SpriteInfo.show":"Megjelenítés","gui.SpriteInfo.size":"Méret","gui.spriteSelectorItem.contextMenuDuplicate":"duplikálás","gui.spriteSelectorItem.contextMenuExport":"exportálás","gui.spriteSelectorItem.contextMenuDelete":"törlés","gui.spriteSelector.addSpriteFromLibrary":"Válassz szereplőt","gui.spriteSelector.addSpriteFromPaint":"Festés","gui.spriteSelector.addSpriteFromSurprise":"Meglepetés","gui.spriteSelector.addSpriteFromFile":"Szereplő feltöltés","gui.stageHeader.stageSizeLarge":"Váltás nagy színpadra","gui.stageHeader.stageSizeSmall":"Váltás kicsi színpadra","gui.stageHeader.stageSizeFull":"Lépj be teljes képernyős üzemmódba","gui.stageHeader.stageSizeUnFull":"Teljes képernyős üzemmód elhagyása","gui.stageHeader.fullscreenControl":"A teljes képernyő szabályozása","gui.spriteSelector.addBackdropFromLibrary":"Válassz hátteret","gui.stageSelector.addBackdropFromPaint":"Festés","gui.stageSelector.addBackdropFromSurprise":"Meglepetés","gui.stageSelector.addBackdropFromFile":"Háttér feltöltése","gui.stageSelector.stage":"Színpad","gui.stageSelector.backdrops":"Hátterek","gui.telemetryOptIn.label":"Statisztikák jelentése a Scratch javításához","gui.telemetryOptIn.body1":"A Scratch Team mindig arra törekszik, hogy jobban megértse, hogyan használják a Scratch-et a világban. Az erőfeszítés támogatása érdekében engedélyezheti a Scratch számára, hogy automatikusan küldjön használati adatokat a Scratch Teamnek.","gui.telemetryOptIn.body2":"Az általunk gyűjtött információk magukban foglalják a nyelvválasztást, a blokkok használatát és bizonyos eseményeket, mint például a mentés, a betöltés és egy projekt feltöltése. NEM gyűjtünk személyes adatokat. További információért olvasd el {privacyPolicyLink}adatvédelmi szabályzatunkat.","gui.telemetryOptIn.privacyPolicyLink":"Adatvédelem","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Bezár","gui.turboMode.active":"Turbó mód","gui.webglModal.label":"A böngésződ nem támogatja a WebGL-t","gui.webglModal.webgllink":"WebGL nem támogatott","gui.costumeLibrary.chooseABackdrop":"Válassz hátteret","gui.costumeLibrary.chooseACostume":"Válassz jelmezt","gui.costumeTab.addBackdropFromLibrary":"Válassz hátteret","gui.costumeTab.addCostumeFromLibrary":"Válassz jelmezt","gui.costumeTab.addBlankCostume":"Festés","gui.costumeTab.addSurpriseCostume":"Meglepetés","gui.costumeTab.addFileBackdrop":"Háttér feltöltése","gui.costumeTab.addFileCostume":"Jelmez feltöltése","gui.extensionLibrary.chooseAnExtension":"Válassz bővítményt","gui.extensionLibrary.extensionUrl":"Írd be a bővítmény URL-jét","gui.monitors.importListColumnPrompt":"Melyik oszlopot használjuk (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Nem lehet elkezdeni a felvételt","gui.soundLibrary.chooseASound":"Válassz hangot","gui.soundTab.fileUploadSound":"Hang feltöltése","gui.soundTab.surpriseSound":"Meglepetés","gui.soundTab.recordSound":"Felvétel","gui.soundTab.addSoundFromLibrary":"Válassz hangot","gui.spriteLibrary.chooseASprite":"Válassz szereplőt","gui.tipsLibrary.tutorials":"Válassz gyakorlatot","gui.alerts.createsuccess":"Új projekt létrehozva.","gui.alerts.createcopysuccess":"Projekt elmentve másolatként.","gui.alerts.createremixsuccess":"Projekt elmentve remixként.","gui.alerts.creating":"Új létrehozása...","gui.alerts.creatingCopy":"Projekt másolása...","gui.alerts.creatingRemix":"Projekt remixelése...","gui.alerts.creatingError":"Nem lehetett létrehozni a projektet. Kérlek próbáld újra!","gui.alerts.savingError":"A projektet nem lehet elmenteni.","gui.alerts.savesuccess":"Projekt elmentve.","gui.alerts.saving":"Projekt mentése...","gui.alerts.cloudInfo":"Kérjük, vedd figyelembe, hogy a megosztott változó csak számot tárolhat, betűt vagy szimbólumot nem. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"További információ.","gui.alerts.importing":"Importálás...","gui.defaultProject.variable":"az én változóm","gui.extension.music.name":"Zene","gui.extension.music.description":"Játssz a hangszereken és a dobokon.","gui.extension.pen.name":"Toll","gui.extension.pen.description":"Rajzolj a szereplőkkel","gui.extension.videosensing.name":"Videóérzékelés","gui.extension.videosensing.description":"Érzékeld a mozgást a kamerával.","gui.extension.text2speech.name":"Text to Speech","gui.extension.text2speech.description":"Készíts beszélő projekteket","gui.extension.translate.name":"Fordítás","gui.extension.translate.description":"Fordítsd le a szöveget sok nyelvre.","gui.extension.makeymakey.description":"Változtass mindent kulcssá.","gui.extension.microbit.description":"Kapcsold össze a programjaidat a világgal.","gui.extension.microbit.connectingMessage":"Kapcsolódás","gui.extension.ev3.description":"Építs interaktív robotokat és sok mást.","gui.extension.ev3.connectingMessage":"Csatlakozás. Győződj meg róla, hogy az EV3-ban lévő tű 1234-re van állítva.","gui.extension.boost.description":"Keltsd életre robot alkotásaidat.","gui.extension.boost.connectingMessage":"Kapcsolódás","gui.extension.wedo2.description":"Építs motorokkal és érzékelőkkel.","gui.extension.wedo2.connectingMessage":"Kapcsolódás","gui.extension.gdxfor.description":"Nyomás, húzás, mozgás és forgás érzékelése.","gui.extension.gdxfor.connectingMessage":"Kapcsolódás","gui.libraryTags.all":"Minden","gui.libraryTags.animals":"Állatok","gui.libraryTags.dance":"Tánc","gui.libraryTags.effects":"Hatások","gui.libraryTags.fantasy":"Fantázia","gui.libraryTags.fashion":"Divat","gui.libraryTags.food":"Étel","gui.libraryTags.indoors":"Beltér","gui.libraryTags.loops":"Ciklusok","gui.libraryTags.music":"Zene","gui.libraryTags.notes":"Hangjegyek","gui.libraryTags.outdoors":"Kültér","gui.libraryTags.patterns":"Minták","gui.libraryTags.people":"Emberek","gui.libraryTags.percussion":"Ütőhangszerek","gui.libraryTags.space":"Űr","gui.libraryTags.sports":"Sport","gui.libraryTags.underwater":"Vízalatt","gui.libraryTags.voice":"Hang","gui.libraryTags.wacky":"Hóbortos","gui.libraryTags.animation":"Animáció","gui.libraryTags.art":"Művészet","gui.libraryTags.games":"Játékok","gui.libraryTags.stories":"Történetek","gui.libraryTags.letters":"Betűk","gui.opcodeLabels.direction":"iránya","gui.opcodeLabels.xposition":"x helyzete","gui.opcodeLabels.yposition":"y helyzete","gui.opcodeLabels.size":"mérete","gui.opcodeLabels.costumename":"jelmez neve","gui.opcodeLabels.costumenumber":"jelmez száma","gui.opcodeLabels.backdropname":"háttér neve","gui.opcodeLabels.backdropnumber":"háttér száma","gui.opcodeLabels.volume":"hangereje","gui.opcodeLabels.tempo":"tempó","gui.opcodeLabels.answer":"válasz","gui.opcodeLabels.loudness":"hangerő","gui.opcodeLabels.username":"felhasználó","gui.opcodeLabels.year":"év","gui.opcodeLabels.month":"hónap","gui.opcodeLabels.date":"nap","gui.opcodeLabels.dayofweek":"hét napja","gui.opcodeLabels.hour":"óra","gui.opcodeLabels.minute":"perc","gui.opcodeLabels.second":"másodperc","gui.opcodeLabels.timer":"időmérő","gui.sharedMessages.backdrop":"háttér{index}","gui.sharedMessages.costume":"jelmez{index}","gui.sharedMessages.sprite":"szereplő{index}","gui.sharedMessages.pop":"pukk","gui.sharedMessages.replaceProjectWarning":"Meglévő projekt tartalmának felülírása?","gui.sharedMessages.loadFromComputerTitle":"Feltöltés saját gépről","boost.color.any":"bármely szín","boost.color.black":"fekete","boost.color.blue":"kék","boost.color.green":"zöld","boost.color.red":"piros","boost.color.white":"fehér","boost.color.yellow":"sárga","boost.getMotorPosition":"[MOTOR_REPORTER_ID] motor pozíciója","boost.getTiltAngle":"[TILT_DIRECTION] billenési szög","boost.motorDirection.backward":"arra","boost.motorDirection.forward":"erre","boost.motorDirection.reverse":"visszafelé","boost.motorOff":"[MOTOR_ID] motor kikapcsolása","boost.motorOn":"[MOTOR_ID] motor bekapcsolása","boost.motorOnFor":"[MOTOR_ID] motor bekapcsolása [DURATION] másodpercig","boost.motorOnForRotation":"[MOTOR_ID] motor bekapcsolása [ROTATION] fordulatra","boost.seeingColor":"látsz [COLOR] téglát?","boost.setLightHue":"lámpa színe legyen [HUE]","boost.setMotorDirection":"[MOTOR_ID] motor beállítása [MOTOR_DIRECTION] irányba","boost.setMotorPower":"[MOTOR_ID] motor sebessége legyen [POWER]%","boost.tiltDirection.any":"bármelyik","boost.tiltDirection.down":"le","boost.tiltDirection.left":"balra","boost.tiltDirection.right":"jobbra","boost.tiltDirection.up":"fel","boost.whenColor":"ha [COLOR] téglát látsz","boost.whenTilted":"amikor [TILT_DIRECTION_ANY] irányba billentve","ev3.beepNote":"[NOTE] hangjelzés lejátszása [TIME] másodpercig","ev3.buttonPressed":"[PORT] gomb lenyomva?","ev3.getBrightness":"fényerő","ev3.getDistance":"távolság","ev3.getMotorPosition":"[PORT] motor pozíciója","ev3.motorSetPower":"[PORT] motor teljesítménye legyen [POWER] %","ev3.motorTurnClockwise":"[PORT] motor forduljon erre [TIME] másodpercig","ev3.motorTurnCounterClockwise":"[PORT] motor forduljon arra [TIME] másodpercig","ev3.whenBrightnessLessThan":"amikor a fényerő < [DISTANCE]","ev3.whenButtonPressed":"amikor [PORT] gomb lenyomva","ev3.whenDistanceLessThan":"amikor a távolság < [DISTANCE]","gdxfor.getAcceleration":"gyorsulás [DIRECTION] irányban","gdxfor.getForce":"erő","gdxfor.getSpin":"forgási sebesség [DIRECTION] irányban","gdxfor.getTilt":"billenés szög [TILT]","gdxfor.isFreeFalling":"zuhan?","gdxfor.isTilted":"billen [TILT]?","gdxfor.pulled":"meghúzva","gdxfor.pushed":"benyomva","gdxfor.shaken":"megrázva","gdxfor.startedFalling":"zuhanni kezdett","gdxfor.tiltDirectionMenu.any":"bármelyik","gdxfor.tiltDirectionMenu.back":"leghátra","gdxfor.tiltDirectionMenu.front":"legelőre","gdxfor.tiltDirectionMenu.left":"balra","gdxfor.tiltDirectionMenu.right":"jobbra","gdxfor.turnedFaceDown":"lefelé fordítva","gdxfor.turnedFaceUp":"felfelé fordítva","gdxfor.whenForcePushedOrPulled":"amikor az erő-szenzor [PUSH_PULL]","gdxfor.whenGesture":"amikor [GESTURE]","gdxfor.whenTilted":"amikor billen [TILT]","makeymakey.downArrow":"lefele nyíl","makeymakey.downArrowShort":"le","makeymakey.leftArrow":"balra nyíl","makeymakey.leftArrowShort":"balra","makeymakey.rightArrow":"jobbra nyíl","makeymakey.rightArrowShort":"jobbra","makeymakey.spaceKey":"szóköz","makeymakey.upArrow":"felfele nyíl","makeymakey.upArrowShort":"fel","makeymakey.whenKeyPressed":"amikor [KEY] gomb lenyomva","makeymakey.whenKeysPressedInOrder":"amikor [SEQUENCE] sorban lenyomva","microbit.buttonsMenu.any":"bármelyik","microbit.clearDisplay":"kijelző törlése","microbit.defaultTextToDisplay":"Hello!","microbit.displaySymbol":"[MATRIX] megjelenítése","microbit.displayText":"[TEXT] szöveg megjelenítése","microbit.gesturesMenu.jumped":"átugrott","microbit.gesturesMenu.moved":"elmozdult","microbit.gesturesMenu.shaken":"megrázva","microbit.isButtonPressed":"[BTN] gomb megnyomva?","microbit.isTilted":"[DIRECTION] irányba billentve ?","microbit.pinStateMenu.off":"ki","microbit.pinStateMenu.on":"be","microbit.tiltAngle":"[DIRECTION] billenési szög","microbit.tiltDirectionMenu.any":"bármelyik","microbit.tiltDirectionMenu.back":"hátul","microbit.tiltDirectionMenu.front":"elöl","microbit.tiltDirectionMenu.left":"balra","microbit.tiltDirectionMenu.right":"jobbra","microbit.whenButtonPressed":"amikor [BTN] gomb megnyomva","microbit.whenGesture":"amikor [GESTURE]","microbit.whenPinConnected":"amikor pin [PIN] csatlakoztatva","microbit.whenTilted":"amikor [DIRECTION] irányba billentve","music.categoryName":"Zene","music.changeTempo":"tempó változzon [TEMPO]","music.drumBass":"(2) Nagydob","music.drumBongo":"(13) Bongó","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Kasztanyetta","music.drumClosedHiHat":"(6) Zárt Hi-Hat","music.drumConga":"(14) Konga","music.drumCowbell":"(11) Kolomp","music.drumCrashCymbal":"(4) Cintányér","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Taps","music.drumOpenHiHat":"(5) Nyitott Hi-Hat","music.drumSideStick":"(3) Dob pereme","music.drumSnare":"(1) Pergődob","music.drumTambourine":"(7) Tamburin","music.drumTriangle":"(12) Triangulum","music.drumVibraslap":"(17) Kereplő","music.drumWoodBlock":"(10) Fa kocka","music.getTempo":"tempó","music.instrumentBass":"(6) Basszus","music.instrumentBassoon":"(14) Basszuskürt","music.instrumentCello":"(8) Cselló","music.instrumentChoir":"(15) Kórus","music.instrumentClarinet":"(10) Klarinét","music.instrumentElectricGuitar":"(5) Elektromos gitár","music.instrumentElectricPiano":"(2) Elektromos zongora","music.instrumentFlute":"(12) Furulya","music.instrumentGuitar":"(4) Gitár","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Zenélő doboz","music.instrumentOrgan":"(3) Orgona","music.instrumentPiano":"(1) Zongora","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxofon","music.instrumentSteelDrum":"(18) Acél dob","music.instrumentSynthLead":"(20) Szóló szintetizátor","music.instrumentSynthPad":"(21) Szintetizátor érintőlap","music.instrumentTrombone":"(9) Harsona","music.instrumentVibraphone":"(16) Vibrafon","music.instrumentWoodenFlute":"(13) Fa furulya","music.midiPlayDrumForBeats":"játssz [DRUM] dobon [BEATS] ütemig","music.midiSetInstrument":"hangszer legyen [INSTRUMENT]","music.playDrumForBeats":"játssz [DRUM] dobon [BEATS] ütemig","music.playNoteForBeats":"játszd le [NOTE] hangjegyet [BEATS] ütemig","music.restForBeats":"szünetelj [BEATS] ütemig","music.setInstrument":"hangszer legyen [INSTRUMENT]","music.setTempo":"tempó legyen [TEMPO]","pen.categoryName":"Toll","pen.changeColorParam":"toll [COLOR_PARAM] változzon [VALUE]","pen.changeHue":"toll színe változzon [HUE]","pen.changeShade":"toll árnyalata változzon [SHADE]","pen.changeSize":"toll mérete változzon [SIZE]","pen.clear":"töröld a rajzokat","pen.colorMenu.brightness":"fényerő","pen.colorMenu.color":"szín","pen.colorMenu.saturation":"telítettség","pen.colorMenu.transparency":"átlátszóság","pen.penDown":"tollat tedd le","pen.penUp":"tollat emeld fel","pen.setColor":"toll színe legyen [COLOR]","pen.setColorParam":"toll [COLOR_PARAM] legyen [VALUE]","pen.setHue":"toll színe legyen [HUE]","pen.setShade":"toll árnyalata legyen [SHADE]","pen.setSize":"toll mérete legyen [SIZE]","pen.stamp":"készíts lenyomatot","text2speech.alto":"alt","text2speech.categoryName":"Text to Speech","text2speech.defaultTextToSpeak":"üdv","text2speech.giant":"óriás","text2speech.kitten":"cica","text2speech.setLanguageBlock":"nyelv legyen [LANGUAGE]","text2speech.setVoiceBlock":"hang legyen [VOICE]","text2speech.speakAndWaitBlock":"mondd [WORDS]","text2speech.squeak":"vinnyogás","text2speech.tenor":"tenor","translate.categoryName":"Fordítás","translate.defaultTextToTranslate":"üdv","translate.translateBlock":"fordítsd le azt, hogy [WORDS] erre a nyelvre:[LANGUAGE]","translate.viewerLanguage":"nyelv","videoSensing.categoryName":"Videóérzékelés","videoSensing.direction":"irány","videoSensing.motion":"mozgás","videoSensing.off":"ki","videoSensing.on":"be","videoSensing.onFlipped":"felpattintott","videoSensing.setVideoTransparency":"videó átlátszósága legyen [TRANSPARENCY]","videoSensing.sprite":"szereplő","videoSensing.stage":"színpad","videoSensing.videoOn":"video attribútum [ATTRIBUTE] [SUBJECT] tárgyban","videoSensing.videoToggle":"videó kapcsolása [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"amikor a videó mozgása > [REFERENCE]","wedo2.getDistance":"távolság","wedo2.getTiltAngle":"[TILT_DIRECTION] billenési szög","wedo2.isTilted":"[TILT_DIRECTION_ANY] irányba billenve?","wedo2.motorDirection.backward":"arra","wedo2.motorDirection.forward":"erre","wedo2.motorDirection.reverse":"visszafelé","wedo2.motorId.a":"A motor","wedo2.motorId.all":"minden motor","wedo2.motorId.b":"B motor","wedo2.motorId.default":"motor","wedo2.motorOff":"[MOTOR_ID] kikapcsolása","wedo2.motorOn":"[MOTOR_ID] bekapcsolása","wedo2.motorOnFor":"[MOTOR_ID] bekapcsolása [DURATION] másodpercig","wedo2.playNoteFor":"[NOTE] hang lejátszása [DURATION] másodpercig","wedo2.setLightHue":"lámpa színének beállítása erre: [HUE]","wedo2.setMotorDirection":"[MOTOR_ID] beállítása [MOTOR_DIRECTION] irányba","wedo2.startMotorPower":"[MOTOR_ID] teljesítménye legyen [POWER]","wedo2.tiltDirection.any":"bármelyik","wedo2.tiltDirection.down":"le","wedo2.tiltDirection.left":"balra","wedo2.tiltDirection.right":"jobbra","wedo2.tiltDirection.up":"fel","wedo2.whenDistance":"amikor [OP] távolság [REFERENCE]","wedo2.whenTilted":"amikor [TILT_DIRECTION_ANY] irányba billentve","paint.paintEditor.hue":"Szín","paint.paintEditor.saturation":"Telítettség","paint.paintEditor.brightness":"Fényerő","paint.paintEditor.costume":"Jelmez","paint.paintEditor.group":"Csoportosítás","paint.paintEditor.ungroup":"Csoport bontása","paint.paintEditor.undo":"Visszavonás","paint.paintEditor.redo":"Mégis","paint.paintEditor.forward":"Előreküld","paint.paintEditor.backward":"Hátraküld","paint.paintEditor.front":"Legelőre","paint.paintEditor.back":"Leghátra","paint.paintEditor.more":"Több","paint.modeTools.brushSize":"Méret","paint.modeTools.eraserSize":"Radír méret","paint.modeTools.copy":"Másolás","paint.modeTools.paste":"Beillesztés","paint.modeTools.delete":"Törlés","paint.modeTools.curved":"Ívelt","paint.modeTools.pointed":"Csúcsos","paint.modeTools.thickness":"Vastagság","paint.modeTools.flipHorizontal":"Vízszintes tükrözés","paint.modeTools.flipVertical":"Függőleges tükrözés","paint.modeTools.filled":"Kitöltött","paint.modeTools.outlined":"Körvonalazott","paint.paintEditor.bitmap":"Konvertálás Bitképpé","paint.paintEditor.vector":"Konvertálás Vektorképpe","paint.paintEditor.fill":"Kitöltés","paint.paintEditor.stroke":"Körvonal","paint.brushMode.brush":"Ecset","paint.eraserMode.eraser":"Radír","paint.fillMode.fill":"Kitöltés","paint.lineMode.line":"Vonal","paint.ovalMode.oval":"Kör","paint.rectMode.rect":"Téglalap","paint.reshapeMode.reshape":"Újraformálás","paint.roundedRectMode.roundedRect":"Kerekített téglalap","paint.selectMode.select":"Kijelölés","paint.textMode.text":"Szöveg","paint.colorPicker.swap":"Csere","tw.alerts.autosaving":"Helyreállítási pont készítése...","tw.alerts.savedToDisk":"Mentve a számítógépre.","tw.backpack.rename":"Új név:","tw.browserModal.desc":"Győződj meg róla, hogy egy friss verzióját használod a Google Chrome-nak, Mozilla Firefoxnak, Microsoft Edge-nek vagy Apple Safarinak.","tw.changeUsername.cannotChangeWhileRunning":"A felhasználónév nem változtatható meg a projekt futása alatt.","tw.cloudVariableBadge":"Ez a projekt megosztott változókat használ. A TurboWarp sajátot használ belőlük, ami teljesen független a Scratchtől. Figyeljen az ál-megszemélyesítésre, hiszen bárki bármire beállíthatja a felhasználónevét. {learnMore}","tw.code":"Forráskód","tw.confirmIncompatibleExtension":"Ez a kiegészítés nem kompatibilis a Scratchhel. Ezzel készített projekteket nem lehet feltölteni a Scratch weboldalára. Biztos, hogy mégis engedélyezni szeretnéd őket?","tw.customExtension.description":"Betölthetsz egyéni kiegészítőket URL-ekből. Fejlesztőknek. Kísérleti.","tw.customExtension.name":"Egyéni Kiegészítő","tw.featuredProjectsStudio":"Műhely megtekintése a Scratchen.","tw.feedback":"Visszajelzés és Hibák","tw.feedbackButton":"Visszajelzés a TurboWarpról","tw.footer.credits":"Stáblista","tw.footer.disclaimer":"A TurboWarp nem tagja, vagy leányvállalata a Scratchnek, a Scratch Csapatnak vagy a Scratch Alapítványnak.","tw.footer.embed":"Beágyazás","tw.footer.fosshost":"A megosztást a Fosshost biztosítja.","tw.footer.parameters":"URL Paraméterek","tw.footer.translate":"Segíts lefordítani a TurboWarpot","tw.gui.crashMessage.description":"Nagyon sajnáljuk, de úgy tűnik, hogy a projekt összeomlott. Kérjük frissítsd az oldalt, és próbáld újra.","tw.gui.defaultProjectTitle":"Projekt","tw.guiDefaultTitle":"Scratch projektek futtatása gyorsabban","tw.home.credit":"Megjegyzések és stáblista","tw.home.description":"A TurboWarp egy Scratch-modifikáció, ami átfordítja a projekteket JavaScriptbe, így igazán gyorsan lefuttatva őket. Próbálja ki egy projekt azonosítójával (ID), vagy URL-jével a fenti mezőbe beillesztve, illetve egy kiemelt projekt választásával lentről.","tw.home.instructions":"Utasítások","tw.input.tooltip":"Másolj, majd illessz be Scratch-projekt linkeket ide!","tw.interpolationEnabled":"Interpoláció","tw.invalidParameters.clones":"A \\"clone\\" URL paraméter érvénytelen","tw.invalidParameters.fps":"Az \\"fps\\" URL paraméter nem érvényes","tw.loader.assets.known":"Tartozékok letöltése ({complete}/{total}) …","tw.loader.assets.unknown":"Eszközök betöltése ...","tw.loader.data":"Projektadatok letöltése ...","tw.loader.generic":"Projekt betöltése ...","tw.menuBar.60off":"A 60 FPS mód kikapcsolása","tw.menuBar.60on":"60 FPS Mód bekapcsolása","tw.menuBar.addons":"Kiegészítők","tw.menuBar.advanced":"Haladó","tw.menuBar.changeUsername":"Felhasználónév Megváltoztatása","tw.menuBar.cloudOff":"Megosztott változók kikapcsolása","tw.menuBar.cloudOn":"Megosztott Változók engedélyezése","tw.menuBar.cloudUnavailable":"Nem érhetőek el a Megosztott Változók","tw.menuBar.cloudUnavailableAlert":"Nem használhatóak a megosztott változók, legvalószínűbben azért, mert megnyitottad a szerkesztőt.","tw.menuBar.loadRestorePoint":"Helyreállítási pont visszatöltése","tw.menuBar.moreSettings":"Haladó Beállítások","tw.menuBar.newFramerate":"Új képkockaarány:","tw.menuBar.reportError1":"Néhány szkriptet nem sikerült lefordítani.","tw.menuBar.reportError2":"Ez egy hiba. Kérjük jelentsd.","tw.menuBar.saveAs":"Mentés {file}-ként","tw.menuBar.seeInside":"Megnézem belülről","tw.paint.alpha":"Áttetszőség","tw.privacy":"Adatvédelmi Irányelvek","tw.restorePoint.confirm":"A szerkesztő automatikusan rögzít egy helyreállítási pontot, abból az okból, hogyha bármi baj történne és elfelejtene a felhasználó menteni... Ennek ellenére nem lenne jó csak erre támaszkodni, és nem tudjuk garantálni, hogy teljesen vissza fogja nyerni a projektedet. Próbáljuk meg azért betölteni?","tw.restorePoint.loadFail":"Nem lehetett betölteni a helyreállítási pontot: {error}","tw.settingsModal.customStageSize":"Egyedi Színpadméret:","tw.settingsModal.customStageSizeHelp":"Megváltoztatja a méretét a Scratch színpadnak 480×360-ról valami másra. Próbálja ki a 640×360-t, hogy a színpad képernyő méretű legyen. Csak nagyon kevés projekt kezeli ezt megfelelően.","tw.settingsModal.dangerZone":"Veszélyzóna","tw.settingsModal.disableCompiler":"Fordítóprogram kikapcsolása","tw.settingsModal.disableCompilerHelp":"Letiltja a TurboWarp fordítóprogramját. Projektek szerkesztése közben elképzelhető, hogy szüksége lehet rá a szkriptek azonnali frissítése végett. Egyéb helyzetekben sose kapcsolja be ezt!","tw.settingsModal.featured":"Kiemelt","tw.settingsModal.fps":"60 FPS (Egyéni FPS)","tw.settingsModal.fpsHelp":"Az utasításokat 30 helyett 60-szor futtatja le másodpercenként. A legtöbb projekt nem fog megfelelően működni ezzel. Ki kell próbálnod az Interpolációt 60 FPS nélkül, ha ez a helyzet. {customFramerate}.","tw.settingsModal.fpsHelp.customFramerate":"Kattintson 30, vagy 60-tól eltérő képkockaarány használatához","tw.settingsModal.help":"Kattintson segítségért","tw.settingsModal.highQualityPen":"Magas Minőségű Toll","tw.settingsModal.highQualityPenHelp":"Lehetővé teszi a tollal készített projekteket, hogy magasabb felbontásban fussanak, valamint letilt bizonyos koordinátakerekítést is a szerkesztőben. Nem minden projektnek előnyös ez a beállítás, valamint lehet, hogy a teljesítményre is hatással van.","tw.settingsModal.infiniteClones":"Végtelen másolatszám","tw.settingsModal.infiniteClonesHelp":"Letiltja a Scratch 300-as másolatkorlátját","tw.settingsModal.interpolation":"Interpoláció","tw.settingsModal.interpolationHelp":"Simábban jeleníti meg a projekteket azáltal, hogy interpolálja a szereplők mozgását. Az interpolációt nem szabad 3D projektekre, \\"raytracer\\"-ekre, tollat használó projektekre és laggolós projektekre alkalmazni, hiszen az interpoláció csak lassabbá fogja tenni a lefuttatásukat, viszont a megjelenésükön nem fog igazítani.","tw.settingsModal.largeStageWarning":"Egyéni színpadméret használatánál nem ajánlott ilyen nagyot alkalmazni. Helyette használj egy kisebb méretet, de megegyező aránnyal, és bízd rá a teljes képernyőre, hogy felnagyítsa a felhasználó lejátszójának méretéhez.","tw.settingsModal.removeFencing":"Lekerítés eltávolítása","tw.settingsModal.removeFencingHelp":"Lehetővé teszi a szereplőket, hogy a színpadon kívülre menjenek, olyan nagyok, vagy kicsik legyenek, amilyenek csak akarnak, valamint az érzékelős blokkokat is működőképessé teszi színpadon kívül is.","tw.settingsModal.removeLimits":"Korlátok eltávolítása","tw.settingsModal.removeMiscLimits":"Egyéb Korlátok Eltávolítása","tw.settingsModal.removeMiscLimitsHelp":"Eltávolítja a hangeffekt limiteket, és a tollméret korlátozottságait.","tw.settingsModal.storeProjectOptions":"Beállítások eltárolása a projektben.","tw.settingsModal.storeProjectOptionsHelp":"Eltárolja a kiválasztott beállításokat a projektben, így azonnal alkalmazhatja a TurboWarp őket betöltésnél. A Warp Időzítő és a Fordítóprogram Kikapcsolása nem lesz elmentve.","tw.settingsModal.title":"Haladó Beállítások","tw.settingsModal.warpTimer":"Warp Időzítő","tw.settingsModal.warpTimerHelp":"Leellenőrzi a szkripteket, hogy nem-e ragadtak bele egy hosszú- vagy végtelen-ciklusba, és alacsony képkockaarányban futtatja őket, ahelyett hogy leragadjanak, amíg a ciklus véget ér. Ez tehát megjavítja a legtöbb összeomlást, de cserébe van egy jelentős teljesítménybehatása is, így csak a szerkesztőben van automatikusan bekapcsolva.","tw.spriteSelectorItem.rename":"átnevezés","tw.studioview.authorAttribution":"{author} által","tw.studioview.error":"Hiba történt a projektek következő oldalának betöltése közben.","tw.studioview.hoverText":"{title}, {author} által","tw.twExtension.description":"Furcsa új blokkok. Nem kompatibilisek a Scratchel.","tw.twExtension.name":"TurboWarp Blokkok","tw.usernameModal.help":"Ez az érték a böngésződ tárában fog eltárolódni. Lehet, hogy naplózva lesz amikor olyan projektekkel lépsz kapcsolatba, amik tartalmaznak megosztott változókat.","tw.usernameModal.help2":"Olyan értékeket, amik nem egyeznek meg egy érvényes Scratch fiókkal sem, a megosztott változók szervere elutasít jellemzően. Azt javasoljuk, hogy hagyd, ahogy van, vagy állítsd a Scratch felhasználónevedre.","tw.usernameModal.mustChange":"Bocsánat, a megosztott változók szervere szerint a felhasználóneved nem lehet föltétlenül biztonságos. Kérjük változtasd meg valami másra, vagy {resetIt}.","tw.usernameModal.mustChange.resetIt":"állítsd vissza (ajánlott)","tw.usernameModal.reset":"Visszaállítás","tw.usernameModal.title":"Felhasználónév Megváltoztatása","tw.viewFeaturedProjects":"Egy kattintás a kiemelt projektek megtekintéséhez.","tw.viewOnScratch":"Projekt megtekintése a Scratchen.","tw.webglModal.description":"Sajnos úgy tűnik, hogy a böngészője vagy számítógépe {webGlLink}. Ez a technológia szükséges ezenaz oldal lefutásához."},"mi":{"gui.alerts.tryAgain":"Whakamātauria Anō","gui.alerts.download":"Tikiaketia","gui.connection.reconnect":"Tūhonoa anōtia","gui.backpack.costumeLabel":"kākahu","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Pīkau","gui.backpack.errorBackpack":"Kua raru te tāuta pīkau","gui.backpack.loadingBackpack":"Kei te utaina...","gui.backpack.more":"Anō","gui.backpack.emptyBackpack":"Kua kautahanga te Pīkau","gui.unsupportedBrowser.label":"Kāore e tautokona te pūtirotiro","gui.cards.all-tutorials":"Ngā Akoranga","gui.cards.shrink":"Shrink","gui.cards.expand":"Expand","gui.cards.close":"Katia","gui.cards.more-things-to-try":"Ētahi mahinga kē kia whakamātauria!","gui.cards.see-more":"Tirohia anōtia","gui.comingSoon.message1":"Kaua e māharahara, kei te ū tonu mātou {emoji}","gui.comingSoon.message2":"Ākuanei kei konei...","gui.comingSoon.message3":"Kei te hanga tonu mātou i tēnei {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Kāore i kitea te pūrere","gui.connection.auto-scanning.prescan":"Whakatata mai tō pūrere, kātahi tīmatahia te rapu.","gui.connection.auto-scanning.pressbutton":"Panaia te pātene o tō pūrere.","gui.connection.auto-scanning.start-search":"Tīmatahia te Rapu","gui.connection.connecting-searchbutton":"Kei te rapu...","gui.connection.auto-scanning.try-again":"Whakamātauria anōtia","gui.connection.connected":"Kua honoa","gui.connection.disconnect":"Kua motukia","gui.connection.go-to-editor":"Haere ki te Taupānga Whakatika","gui.connection.connecting-cancelbutton":"Kei te hono...","gui.connection.error.errorMessage":"Auē! Kua puta mai he raru.","gui.connection.error.tryagainbutton":"Whakamātauria anōtia","gui.connection.error.helpbutton":"Āwhina","gui.connection.peripheral-name-label":"Ingoa pūrere","gui.connection.connect":"Honoa","gui.connection.scanning.lookingforperipherals":"Kei te rapu i ngā pūrere","gui.connection.scanning.noPeripheralsFound":"Kāore i kitea te pūrere","gui.connection.scanning.instructions":"Tīpakongia tō pūrere i te rārangi kei runga nei.","gui.connection.search":"Whakahoua","gui.connection.unavailable.installscratchlink":"Āta titiro mēnā kua tāutahia te Scratch Link, kua whakahaerehia hoki.","gui.connection.unavailable.enablebluetooth":"Kātahi, Whakakā i a Nihokikorangi","gui.connection.unavailable.tryagainbutton":"Whakamātauria anōtia","gui.connection.unavailable.helpbutton":"Āwhina","gui.controls.go":"Haere","gui.controls.stop":"Katia","gui.crashMessage.label":"Auē! Kua puta mai he raru.","gui.crashMessage.errorNumber":"Kua tukuna tō hapa ki te rangitaki me te tautuhinga {errorId}","gui.crashMessage.reload":"Whakahou","gui.customProcedures.myblockModalTitle":"Hangaia tētahi Paraka","gui.customProcedures.addAnInputNumberText":"Tāpirihia tētahi tāuru","gui.customProcedures.numberTextType":"he nama, he kupu rānei","gui.customProcedures.addAnInputBoolean":"Whakaurua tētahi tāuru","gui.customProcedures.booleanType":"boolean","gui.customProcedures.addALabel":"Tāpirihia tētahi kupu tapanga:","gui.customProcedures.runWithoutScreenRefresh":"Whakahaeretia, kāore he whakahounga o te mata","gui.customProcedures.cancel":"Whakakore","gui.customProcedures.ok":"Ka pai","gui.SpriteInfo.direction":"Ahunga","gui.directionPicker.rotationStyles.allAround":"Huri Noa","gui.directionPicker.rotationStyles.leftRight":"Mauī/Katau","gui.directionPicker.rotationStyles.dontRotate":"Kaua e takahuri","gui.gui.addExtension":"Tāpirihia tētahi Torohanga","gui.gui.codeTab":"Waehere","gui.gui.backdropsTab":"Ngā Ārai Tuarongo","gui.gui.costumesTab":"Ngā Kākahu","gui.gui.soundsTab":"Ngā oro","gui.extensionLibrary.comingSoon":"Ākuanei kei konei","gui.extensionLibrary.requires":"Herenga","gui.extensionLibrary.collaboration":"Tuituinga mahi","gui.library.filterPlaceholder":"Rapua","gui.library.allTag":"Te Katoa","gui.loader.headline":"Kei te Utaina te Kaupapa","gui.loader.creating":"Kei te Waihanga i te Kaupapa","gui.authorInfo.byUser":"nā{username}","gui.menuBar.seeProjectPage":"Tirohia te Whārangi Kaupapa","gui.menuBar.LanguageSelector":"kōwhiringa reo","gui.menuBar.tutorialsLibrary":"Ngā Akoranga","gui.menuBar.restoreSprite":"Whakaora Parehe","gui.menuBar.restoreSound":"Whakaora Oro","gui.menuBar.restoreCostume":"Whakaora Kākahu","gui.menuBar.restore":"Whakaora","gui.menuBar.saveNow":"Tiakina ināianei","gui.menuBar.saveAsCopy":"Tiakina hei tārua","gui.menuBar.remix":"Whakarākeitia","gui.menuBar.new":"Hou","gui.menuBar.file":"Kōnae","gui.menuBar.downloadToComputer":"Tiakina ki tō rorohiko","gui.menuBar.edit":"Whakatikaina","gui.menuBar.turboModeOff":"Wetohia te Aratau Kapongao","gui.menuBar.turboModeOn":"Whakakāngia te Aratau Kapongao","gui.gui.projectTitlePlaceholder":"Ingoa kaupapa ki konei","gui.menuBar.isShared":"Kua tuaritia","gui.menuBar.share":"Tuaritia","gui.modal.help":"Āwhina","gui.modal.back":"Hoki atu","gui.monitor.listMonitor.empty":"(kāore he mea kei roto)","gui.monitor.listMonitor.listLength":"roanga {length}","gui.monitor.contextMenu.default":"pānui māori","gui.monitor.contextMenu.large":"pānui rahi","gui.monitor.contextMenu.slider":"rēreti","gui.monitor.contextMenu.sliderRange":"change slider range","gui.monitor.contextMenu.import":"kaweake","gui.monitor.contextMenu.export":"kaweake","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Play","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"Mō ngā parehe katoa","gui.gui.variableScopeOptionSpriteOnly":"Mō tēnei parehe anake","gui.gui.cloudVariableOption":"Taurangi Raraunga Kapua (kei te tūmau)","gui.gui.variablePromptAllSpritesMessage":"Ka wātea tēnei taurangi mō ngā parehe katoa.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Whakakore","gui.prompt.ok":"Ka pai","gui.playbackStep.stopMsg":"Katia","gui.playbackStep.playMsg":"Whakatangihia","gui.playbackStep.loadingMsg":"Kei te utaina...","gui.playbackStep.saveMsg":"Tiakina","gui.playbackStep.reRecordMsg":"Hopukina anōtia","gui.recordModal.title":"Hopu Oro","gui.recordingStep.beginRecord":"Tīmatahia te hopuoro mā te pāwhiri i te pātene kei raro nei","gui.recordingStep.permission":"{arrow}Me whai whakaaetanga mātou i a koe kia whakamahia tō hopuoro","gui.recordingStep.stop":"Katia te hopuoro","gui.recordingStep.record":"Hopukina","gui.sliderModal.min":"Minimum value","gui.sliderModal.max":"Maximum value","gui.sliderModal.title":"Change slider range","gui.sliderPrompt.cancel":"Cancel","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Oro","gui.soundEditor.play":"Whakatangihia","gui.soundEditor.stop":"Katia","gui.soundEditor.copy":"Copy","gui.soundEditor.paste":"Paste","gui.soundEditor.copyToNew":"Copy to New","gui.soundEditor.delete":"Delete","gui.soundEditor.save":"Tiakina","gui.soundEditor.undo":"Wetekia","gui.soundEditor.redo":"Mahia anōtia","gui.soundEditor.faster":"Tere ake","gui.soundEditor.slower":"Pōturi ake","gui.soundEditor.echo":"Pāorooro","gui.soundEditor.robot":"Karetao","gui.soundEditor.louder":"Whakakaha i te oro","gui.soundEditor.softer":"Ririki","gui.soundEditor.reverse":"Hurikōaro","gui.soundEditor.fadeOut":"Fade out","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Mute","gui.SpriteInfo.spritePlaceholder":"Ingoa","gui.SpriteInfo.sprite":"Parehe","gui.SpriteInfo.show":"Whakaaturia","gui.SpriteInfo.size":"Rahi","gui.spriteSelectorItem.contextMenuDuplicate":"tāruatia","gui.spriteSelectorItem.contextMenuExport":"kaweake","gui.spriteSelectorItem.contextMenuDelete":"mukua","gui.spriteSelector.addSpriteFromLibrary":"Kōwhiria tētahi Parehe","gui.spriteSelector.addSpriteFromPaint":"Peita","gui.spriteSelector.addSpriteFromSurprise":"Ohorere","gui.spriteSelector.addSpriteFromFile":"Tukuatu Parehe","gui.stageHeader.stageSizeLarge":"Panoni ki te atamira nui","gui.stageHeader.stageSizeSmall":"Panoni ki te atamira iti","gui.stageHeader.stageSizeFull":"Panoni ki te aratau mata katoa","gui.stageHeader.stageSizeUnFull":"Puta atu i te aratau mata katoa","gui.stageHeader.fullscreenControl":"Whakatina Mata Katoa","gui.spriteSelector.addBackdropFromLibrary":"Kōwhiria tētahi Ārai Tuarongo","gui.stageSelector.addBackdropFromPaint":"Peita","gui.stageSelector.addBackdropFromSurprise":"Ohorere","gui.stageSelector.addBackdropFromFile":"Tukuatu Ārai Tuarongo","gui.stageSelector.stage":"Atamira","gui.stageSelector.backdrops":"Ngā Ārai Tuarongo","gui.telemetryOptIn.label":"Tukuna tauanga kia whakawhanake i te Scratch","gui.telemetryOptIn.body1":"Ko te whāinga o te Tīma Scratch i ngā wā katoa kia mārama ake ka pēhea te Scratch ka whakamahia huri noa i te Ao. Hei āwhina i ēnei mahi, ka āhei koe te whakaae atu kia tuku aunoa te Scratch i ngā raraunga whakamahi ki te Tīma Scratch. ","gui.telemetryOptIn.body2":"Ko te momo mōhiohio e kohia nei e mātou, ko te kōwhiringa reo, ngā paraka kua whakamahia, me ētahi o ngā takahanga pērā ki te tāuta, te tiaki me te tukuatu i ngā kaupapa. KA KORE mātou e kohi i ngā mōhiohio whaiaro. Tirohia tā mātou {privacyPolicyLink} ki te ako anō.","gui.telemetryOptIn.privacyPolicyLink":"Kaupapa Here mō te Tūmataitinga","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Te Aratau Kapongao","gui.webglModal.label":"Kāore a WebGL i te tautokona e tō pūtirotiro","gui.webglModal.webgllink":"kāore e tautokona te WebGL","gui.costumeLibrary.chooseABackdrop":"Kōwhiria tētahi Ārai Tuarongo","gui.costumeLibrary.chooseACostume":"Kōwhiria he Kākahu","gui.costumeTab.addBackdropFromLibrary":"Kōwhiria tētahi Ārai Tuarongo","gui.costumeTab.addCostumeFromLibrary":"Kōwhiria he Kākahu","gui.costumeTab.addBlankCostume":"Peita","gui.costumeTab.addSurpriseCostume":"Ohorere","gui.costumeTab.addFileBackdrop":"Tukuatu Ārai Tuarongo","gui.costumeTab.addFileCostume":"Tukuatu Kākahu","gui.extensionLibrary.chooseAnExtension":"Kōwhiria tētahi Torohanga","gui.extensionLibrary.extensionUrl":"Tāurutia te URL mō te torohanga","gui.monitors.importListColumnPrompt":"Ko tēhea te tīwae hei whakamahi (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Kāore i taea te tīmata i te hopu oro","gui.soundLibrary.chooseASound":"Kōwhiria tētahi Oro","gui.soundTab.fileUploadSound":"Tukuatu oro","gui.soundTab.surpriseSound":"Ohorere","gui.soundTab.recordSound":"Rēkoata","gui.soundTab.addSoundFromLibrary":"Kōwhiria tētahi Oro","gui.spriteLibrary.chooseASprite":"Kōwhiria tētahi Parehe","gui.tipsLibrary.tutorials":"Kōwhiria he Akoranga","gui.alerts.createsuccess":"Kua Waihangatia te Kaupapa Hou","gui.alerts.createcopysuccess":"Kua tiakina te kaupapa hei tārua.","gui.alerts.createremixsuccess":"Kua tiakina te kaupapa hei whakarākei.","gui.alerts.creating":"Kei te waihanga mea hou...","gui.alerts.creatingCopy":"Kei te tārua i te kaupapa...","gui.alerts.creatingRemix":"Kei te whakarākei i te kaupapa...","gui.alerts.creatingError":"Kāore i taea te waihanga kaupapa, whakamātauria anōtia!","gui.alerts.savingError":"Kāore i taea te tiaki i te kaupapa.","gui.alerts.savesuccess":"Kua tiakina te kaupapa.","gui.alerts.saving":"Kei te tiaki i te kaupapa...","gui.alerts.cloudInfo":"Kia mārama koe, ka taea ngā nama anake i ngā taurangi ā-ipurangi, kāore e tautokona ngā pūreta, ngā pūāhua rānei. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Kia ako kōrero anō.","gui.alerts.importing":"Importing…","gui.defaultProject.variable":"taku taurangi","gui.extension.music.name":"Puoro","gui.extension.music.description":"Whakatangi i ngā tāonga puoro me ngā pahū.","gui.extension.pen.name":"Pene","gui.extension.pen.description":"Mā te parehe e tuhi.","gui.extension.videosensing.name":"He Paerongo Ataata","gui.extension.videosensing.description":"Mā te kāmera te mahi paerongo nekenekehanga.","gui.extension.text2speech.name":"Kuputuhi ki te Kōrero ","gui.extension.text2speech.description":"Whakakōrerotia tō kaupapa.","gui.extension.translate.name":"Whakawhitiwhiti Reo Ā-tuhi","gui.extension.translate.description":"Whakahuri ngā tuhinga ki ngā reo maha.","gui.extension.makeymakey.description":"Whakamahia te aha noa hei pātuhi.","gui.extension.microbit.description":"Honohonoa ō kaupapa ki te ao.","gui.extension.microbit.connectingMessage":"Kei te hono","gui.extension.ev3.description":"Hangaia he karetao tauwhitiwhiti, te aha rānei.","gui.extension.ev3.connectingMessage":"Kei te hono. Kia tika te tautuhi i te pine EV3 ki te 1234.","gui.extension.boost.description":"Bring robotic creations to life.","gui.extension.boost.connectingMessage":"Connecting","gui.extension.wedo2.description":"Hanga me ngā pūkaha me ngā paerongo.","gui.extension.wedo2.connectingMessage":"Kei te hono","gui.extension.gdxfor.description":"Sense push, pull, motion, and spin.","gui.extension.gdxfor.connectingMessage":"Connecting","gui.libraryTags.all":"Te Katoa","gui.libraryTags.animals":"Ngā Kararehe","gui.libraryTags.dance":"Kanikani","gui.libraryTags.effects":"Ngā pānga","gui.libraryTags.fantasy":"Wawata","gui.libraryTags.fashion":"Kākahu","gui.libraryTags.food":"Kai","gui.libraryTags.indoors":"Rō-whare","gui.libraryTags.loops":"Koromeke","gui.libraryTags.music":"Puoro","gui.libraryTags.notes":"Tuhipoka","gui.libraryTags.outdoors":"O Waho","gui.libraryTags.patterns":"Tauira","gui.libraryTags.people":"Tāngata","gui.libraryTags.percussion":"Taonga papā","gui.libraryTags.space":"Ātea","gui.libraryTags.sports":"Hākinakina","gui.libraryTags.underwater":"Raro wai","gui.libraryTags.voice":"Reo","gui.libraryTags.wacky":"Pukuhohe","gui.libraryTags.animation":"Hākoritanga","gui.libraryTags.art":"Toi","gui.libraryTags.games":"Ngā Kēmu","gui.libraryTags.stories":"Ngā Pakiwaitara","gui.libraryTags.letters":"Ngā reta","gui.opcodeLabels.direction":"ahunga","gui.opcodeLabels.xposition":"tūnga x","gui.opcodeLabels.yposition":"tūnga y","gui.opcodeLabels.size":"rahi","gui.opcodeLabels.costumename":"ingoa kākahu","gui.opcodeLabels.costumenumber":"nama kākahu","gui.opcodeLabels.backdropname":"ingoa ārai tuarongo","gui.opcodeLabels.backdropnumber":"nama ārai tuarongo","gui.opcodeLabels.volume":"kahaoro","gui.opcodeLabels.tempo":"tere","gui.opcodeLabels.answer":"whakautu","gui.opcodeLabels.loudness":"hoihoi","gui.opcodeLabels.username":"ingoa kaiwhakamahi","gui.opcodeLabels.year":"tau","gui.opcodeLabels.month":"marama","gui.opcodeLabels.date":"te rā","gui.opcodeLabels.dayofweek":"te rangi o te wiki","gui.opcodeLabels.hour":"haora","gui.opcodeLabels.minute":"miniti","gui.opcodeLabels.second":"hēkona","gui.opcodeLabels.timer":"taima","gui.sharedMessages.backdrop":"ārai tuarongo{index}","gui.sharedMessages.costume":"kākahu{index}","gui.sharedMessages.sprite":"Parehe{index}","gui.sharedMessages.pop":"pakō","gui.sharedMessages.replaceProjectWarning":"Replace contents of the current project?","gui.sharedMessages.loadFromComputerTitle":"Load from your computer","boost.color.any":"any color","boost.color.black":"black","boost.color.blue":"blue","boost.color.green":"green","boost.color.red":"red","boost.color.white":"white","boost.color.yellow":"yellow","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] position","boost.getTiltAngle":"tilt angle [TILT_DIRECTION]","boost.motorDirection.backward":"that way","boost.motorDirection.forward":"this way","boost.motorDirection.reverse":"reverse","boost.motorOff":"turn motor [MOTOR_ID] off","boost.motorOn":"turn motor [MOTOR_ID] on","boost.motorOnFor":"turn motor [MOTOR_ID] for [DURATION] seconds","boost.motorOnForRotation":"turn motor [MOTOR_ID] for [ROTATION] rotations","boost.seeingColor":"seeing [COLOR] brick?","boost.setLightHue":"set light color to [HUE]","boost.setMotorDirection":"set motor [MOTOR_ID] direction [MOTOR_DIRECTION]","boost.setMotorPower":"set motor [MOTOR_ID] speed to [POWER] %","boost.tiltDirection.any":"any","boost.tiltDirection.down":"down","boost.tiltDirection.left":"left","boost.tiltDirection.right":"right","boost.tiltDirection.up":"up","boost.whenColor":"when [COLOR] brick seen","boost.whenTilted":"when tilted [TILT_DIRECTION_ANY]","ev3.beepNote":"whakatangihia te oro [NOTE] mō ngā hēkona [TIME]","ev3.buttonPressed":"kua pēhia te pātuhi [PORT]?","ev3.getBrightness":"pīataata","ev3.getDistance":"tawhiti","ev3.getMotorPosition":"ahunga pūkaha[PORT]","ev3.motorSetPower":"pūkaha[PORT] tautuhia te kaha ki[POWER] %","ev3.motorTurnClockwise":"pūkaha [PORT] huri pēnei mō ngā hēkona [TIME]","ev3.motorTurnCounterClockwise":"pūkaha [PORT]huri pērā mō ngā hēkona [TIME]","ev3.whenBrightnessLessThan":"ina pīataata < [DISTANCE]","ev3.whenButtonPressed":"inā pāwhiria te pātene [PORT]","ev3.whenDistanceLessThan":"ina tawhiti < [DISTANCE]","gdxfor.getAcceleration":"acceleration [DIRECTION]","gdxfor.getForce":"force","gdxfor.getSpin":"spin speed [DIRECTION]","gdxfor.getTilt":"tilt angle [TILT]","gdxfor.isFreeFalling":"falling?","gdxfor.isTilted":"tilted [TILT]?","gdxfor.pulled":"pulled","gdxfor.pushed":"pushed","gdxfor.shaken":"shaken","gdxfor.startedFalling":"started falling","gdxfor.tiltDirectionMenu.any":"any","gdxfor.tiltDirectionMenu.back":"back","gdxfor.tiltDirectionMenu.front":"front","gdxfor.tiltDirectionMenu.left":"left","gdxfor.tiltDirectionMenu.right":"right","gdxfor.turnedFaceDown":"turned face down","gdxfor.turnedFaceUp":"turned face up","gdxfor.whenForcePushedOrPulled":"when force sensor [PUSH_PULL]","gdxfor.whenGesture":"when [GESTURE]","gdxfor.whenTilted":"when tilted [TILT]","makeymakey.downArrow":"pere whakararo","makeymakey.downArrowShort":"ki raro","makeymakey.leftArrow":"pere mauī","makeymakey.leftArrowShort":"mauī","makeymakey.rightArrow":"pere katau","makeymakey.rightArrowShort":"katau","makeymakey.spaceKey":"mokowā","makeymakey.upArrow":"pere whakarunga","makeymakey.upArrowShort":"ki runga","makeymakey.whenKeyPressed":"when [KEY] key pressed","makeymakey.whenKeysPressedInOrder":"when [SEQUENCE] pressed in order","microbit.buttonsMenu.any":"noa","microbit.clearDisplay":"ūkuia te mata","microbit.defaultTextToDisplay":"Tēnā koe!","microbit.displaySymbol":"whakaaturia [MATRIX]","microbit.displayText":"whakaaturia [TEXT]","microbit.gesturesMenu.jumped":"i peke","microbit.gesturesMenu.moved":"i neke","microbit.gesturesMenu.shaken":"i rūrū","microbit.isButtonPressed":"[BTN] pātene i pēhia?","microbit.isTilted":"kua tītaha ki[DIRECTION]?","microbit.pinStateMenu.off":"weto","microbit.pinStateMenu.on":"kā","microbit.tiltAngle":"koki tītaha [DIRECTION]","microbit.tiltDirectionMenu.any":"noa","microbit.tiltDirectionMenu.back":"muri","microbit.tiltDirectionMenu.front":"mua","microbit.tiltDirectionMenu.left":"mauī","microbit.tiltDirectionMenu.right":"katau","microbit.whenButtonPressed":"ina pēhia pātene [BTN] ","microbit.whenGesture":"ina [GESTURE]","microbit.whenPinConnected":"whakamātautau, ina honoa ki te pine [PIN]","microbit.whenTilted":"ina tītaha ki [DIRECTION]","music.categoryName":"Puoro","music.changeTempo":"panonitia te tere mā te [TEMPO]","music.drumBass":"(2) Pahū Nguru","music.drumBongo":"(13) Pahū tamarua","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Poro rākau","music.drumClosedHiHat":"(6) Hi-Hat kua Katia","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Pere-kau","music.drumCrashCymbal":"(4) Tīwēwē Wheoro","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Pakipaki-ā-ringa","music.drumOpenHiHat":"(5) Hi-Hat kua Huakina","music.drumSideStick":"(3) Rākau Taha Pahū","music.drumSnare":"(1) Pahū Rarā","music.drumTambourine":"(7) Tatangi","music.drumTriangle":"(12) Tapatoru","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Paraka Rākau","music.getTempo":"tere","music.instrumentBass":"(6) Reo Nguru","music.instrumentBassoon":"(14) Pūhoru","music.instrumentCello":"(8) Whiranui","music.instrumentChoir":"(15) Tira Waiata","music.instrumentClarinet":"(10) Rehu Matangi","music.instrumentElectricGuitar":"(5) Kitā Hiko","music.instrumentElectricPiano":"(2) Piana Hiko","music.instrumentFlute":"(12) Pūtōrino","music.instrumentGuitar":"(4) Kitā","music.instrumentMarimba":"(19) Pakakau","music.instrumentMusicBox":"(17) Pouaka Puoro","music.instrumentOrgan":"(3) Ōkena","music.instrumentPiano":"(1) Piana","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Pūtohe","music.instrumentSteelDrum":"(18) Pahū Rino","music.instrumentSynthLead":"(20) Kōtui Arataki","music.instrumentSynthPad":"(21) Kōtui Papatū","music.instrumentTrombone":"(9) Pūkumekume","music.instrumentVibraphone":"(16) Vibraphone","music.instrumentWoodenFlute":"(13) Pūtorino","music.midiPlayDrumForBeats":"whakatangihia te pahū [DRUM] mō ngā taki [BEATS] ","music.midiSetInstrument":"tautuhia te taonga puoro ki te [INSTRUMENT]","music.playDrumForBeats":"whakatangihia te pahū [DRUM] mō ngā taki [BEATS] ","music.playNoteForBeats":"whakatangihia te oro [NOTE] mō ngā taki [BEATS]","music.restForBeats":"tatari mō ngā taki [BEATS]","music.setInstrument":"tautuhia te taonga puoro ki te [INSTRUMENT]","music.setTempo":"tautuhia te tere kia [TEMPO]","pen.categoryName":"Pene","pen.changeColorParam":"panonitia te [COLOR_PARAM] o te pene mā te [VALUE]","pen.changeHue":"panonitia te tae o te pene mā te [HUE]","pen.changeShade":"panonitia te kauruku o te pene mā te [SHADE]","pen.changeSize":"panonitia te nui o te pene mā te [SIZE]","pen.clear":"Kōmurutia te katoa","pen.colorMenu.brightness":"pīataata","pen.colorMenu.color":"tae","pen.colorMenu.saturation":"waiwai","pen.colorMenu.transparency":"pūatatata","pen.penDown":"pene ki raro","pen.penUp":"pene ki runga","pen.setColor":"tautuhia te tae o te pene kia [COLOR]","pen.setColorParam":"tautuhia te [COLOR_PARAM] o te pene kia [VALUE]","pen.setHue":"tautuhia te tae o te pene kia [HUE]","pen.setShade":"tautuhia te kauruku o te pene kia [SHADE]","pen.setSize":"tautuhia te nui o te pene kia [SIZE]","pen.stamp":"waitohu","text2speech.alto":"reo pekerangi","text2speech.categoryName":"Text to Speech","text2speech.defaultTextToSpeak":"hello","text2speech.giant":"kākarepō","text2speech.kitten":"punua ngeru","text2speech.setLanguageBlock":"tautuhia te reo kia[LANGUAGE]","text2speech.setVoiceBlock":"tautuhia te reo ki [VOICE]","text2speech.speakAndWaitBlock":"kīia [WORDS]","text2speech.squeak":"koekoe","text2speech.tenor":"reo iere","translate.categoryName":"Google Translate","translate.defaultTextToTranslate":"kia ora","translate.translateBlock":"whakawhitiwhitia [WORDS] ki te reo [LANGUAGE]","translate.viewerLanguage":"reo","videoSensing.categoryName":"He Tairongo Ataata","videoSensing.direction":"ahunga","videoSensing.motion":"nekenekehanga","videoSensing.off":"weto","videoSensing.on":"kā","videoSensing.onFlipped":"ina whakawhitia","videoSensing.setVideoTransparency":"tautuhia te pūatatata o te ataata kia [TRANSPARENCY]","videoSensing.sprite":"parehe","videoSensing.stage":"atamira","videoSensing.videoOn":"ataata [ATTRIBUTE] kei [SUBJECT]","videoSensing.videoToggle":"hurihia te ataata kia [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"ina te nekenekehanga o te ataata > [REFERENCE]","wedo2.getDistance":"tawhiti","wedo2.getTiltAngle":"koki tītaha [TILT_DIRECTION]","wedo2.isTilted":"kua tītaha ki [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"tērā ahunga","wedo2.motorDirection.forward":"tēnei ahunga","wedo2.motorDirection.reverse":"ahu whakamuri","wedo2.motorId.a":"pūkaha A","wedo2.motorId.all":"ngā pūkaha katoa","wedo2.motorId.b":"pūkaha B","wedo2.motorId.default":"pūkaha","wedo2.motorOff":"whakaweto [MOTOR_ID]","wedo2.motorOn":"whakakā [MOTOR_ID]","wedo2.motorOnFor":"whakakā[MOTOR_ID] mō ngā hēkona [DURATION]","wedo2.playNoteFor":"whakatangihia te oro [NOTE] mō ngā hēkona[DURATION]","wedo2.setLightHue":"tautuhia te tae māmā ki te [HUE]","wedo2.setMotorDirection":"tautuhia te pūkaha [MOTOR_ID] kia huri [MOTOR_DIRECTION]","wedo2.startMotorPower":"tautuhia te pūkaha [MOTOR_ID] kia [POWER] te kaha","wedo2.tiltDirection.any":"noa","wedo2.tiltDirection.down":"ki raro","wedo2.tiltDirection.left":"mauī","wedo2.tiltDirection.right":"katau","wedo2.tiltDirection.up":"ki runga","wedo2.whenDistance":"ina tawhiti [OP] [REFERENCE]","wedo2.whenTilted":"ina tītaha [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Tae","paint.paintEditor.saturation":"Waiwai","paint.paintEditor.brightness":"Pīataata","paint.paintEditor.costume":"Kākahu","paint.paintEditor.group":"Whakarōpūngia","paint.paintEditor.ungroup":"Wehea","paint.paintEditor.undo":"Wetekia","paint.paintEditor.redo":"Mahia anōtia","paint.paintEditor.forward":"Ki mua","paint.paintEditor.backward":"Ki muri","paint.paintEditor.front":"Mua","paint.paintEditor.back":"Hoki atu","paint.paintEditor.more":"Anō","paint.modeTools.brushSize":"Rahi","paint.modeTools.eraserSize":"Te rahi kōmuru","paint.modeTools.copy":"Tāruatia","paint.modeTools.paste":"Whakapiri","paint.modeTools.delete":"Mukua","paint.modeTools.curved":"Ānau","paint.modeTools.pointed":"Koi","paint.modeTools.thickness":"Mātotoru","paint.modeTools.flipHorizontal":"Pore whakapae","paint.modeTools.flipVertical":"Pore poutū","paint.modeTools.filled":"Kua kī","paint.modeTools.outlined":"Kua whakahuahuatia","paint.paintEditor.bitmap":"Whakawhitia hei Maheremoka","paint.paintEditor.vector":"Whakawhitia hei Pere","paint.paintEditor.fill":"Whakakīia","paint.paintEditor.stroke":"Whakahuahua","paint.brushMode.brush":"Paraihe","paint.eraserMode.eraser":"Kōmuru","paint.fillMode.fill":"Whakakīia","paint.lineMode.line":"Rārangi","paint.ovalMode.oval":"Porowhita","paint.rectMode.rect":"Tapawhā Roa","paint.reshapeMode.reshape":"Tāraia anōtia","paint.roundedRectMode.roundedRect":"Tapawhā Roa Tōpuku","paint.selectMode.select":"Kōwhiria","paint.textMode.text":"Kuputuhi","paint.colorPicker.swap":"Whakawhitia"},"mn":{"gui.alerts.tryAgain":"Дахин оролдох","gui.alerts.download":"Татах","gui.connection.reconnect":"Дахин холбогд","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"дуу","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"дүрс","gui.backpack.header":"Үүргэвч","gui.backpack.errorBackpack":"Үүргэвчний алдаа","gui.backpack.loadingBackpack":"Ачаалж байна","gui.backpack.more":"Цааш...","gui.backpack.emptyBackpack":"Үүргэвч хоосон байна","gui.unsupportedBrowser.label":"Энэ хөтөвч дээр ажиллуулах боломжгүй","gui.cards.all-tutorials":"Дадлага хичээл","gui.cards.shrink":"Жижигрүүлэх","gui.cards.expand":"Томруулах","gui.cards.close":"Хаах","gui.cards.more-things-to-try":"Илүү их туршиж үзэх зүйлс","gui.cards.see-more":"Илүү ихийг харах","gui.comingSoon.message1":"Битгий санаа зовоорой, бид энийг сайжруулахаар ажиллаж байна {emoji}","gui.comingSoon.message2":"Тун удахгүй...","gui.comingSoon.message3":"Бид энийг сайжруулахаар ажиллаж байна {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Төхөөрөмж олдсонгүй","gui.connection.auto-scanning.prescan":"Төхөөрөмжийг ойрхон байршуулаад, хайж эхлэнэ үү.","gui.connection.auto-scanning.pressbutton":"Төхөөрөмж дээрх товчлуурыг дарна уу","gui.connection.auto-scanning.start-search":"Хайж эхлэх","gui.connection.connecting-searchbutton":"Хайж байна","gui.connection.auto-scanning.try-again":"Дахин оролдох","gui.connection.connected":"Холбогдсон","gui.connection.disconnect":"Салгах","gui.connection.go-to-editor":"Editor руу орох","gui.connection.connecting-cancelbutton":"Холбогдож байна...","gui.connection.error.errorMessage":"Яанаа, ямар нэг асуудал гарлаа.","gui.connection.error.tryagainbutton":"Дахин оролдох","gui.connection.error.helpbutton":"Тусламж","gui.connection.peripheral-name-label":"Төхөөрөмжийн нэр","gui.connection.connect":"Холбогд","gui.connection.scanning.lookingforperipherals":"Төхөөрөмжүүд хайж байна","gui.connection.scanning.noPeripheralsFound":"Төхөөрөмж олдсонгүй","gui.connection.scanning.instructions":"Дээрх жагсаалтаас төхөөрөмжөө сонгоно уу.","gui.connection.search":"Дахин хайх","gui.connection.unavailable.installscratchlink":"Scratch Link-г компьютер дээрээ суулгаж, ажиллуулж байгаа эсэхийг шалгана уу.","gui.connection.unavailable.enablebluetooth":"Bluetooth асаалттай эсэхийг шалгана уу.","gui.connection.unavailable.tryagainbutton":"Дахин оролдох","gui.connection.unavailable.helpbutton":"Тусламж","gui.controls.go":"Эхэл","gui.controls.stop":"Зогс","gui.crashMessage.label":"Яанаа. Алдаа гарчихлаа.","gui.crashMessage.errorNumber":"Алдааг {errorId}дугаартай бүртгэлээ.","gui.crashMessage.reload":"Дахин ачаалла","gui.customProcedures.myblockModalTitle":"Блок зохиох","gui.customProcedures.addAnInputNumberText":"Оролт нэмэх","gui.customProcedures.numberTextType":"тоо эсвэл эх","gui.customProcedures.addAnInputBoolean":"Оролт нэмэх","gui.customProcedures.booleanType":"булийн","gui.customProcedures.addALabel":"Тэмдэглэгээ нэмэх","gui.customProcedures.runWithoutScreenRefresh":"Дэлгэцийг шинээр сэргээлгүйгээр ажиллах","gui.customProcedures.cancel":"Цуцлах","gui.customProcedures.ok":"Тийм","gui.SpriteInfo.direction":"Чиглэл","gui.directionPicker.rotationStyles.allAround":"Эргэн тойронд","gui.directionPicker.rotationStyles.leftRight":"Зүүн/Баруун","gui.directionPicker.rotationStyles.dontRotate":"Битгий эргүүл","gui.gui.addExtension":"Өргөтгөл нэмэх","gui.gui.codeTab":"Код","gui.gui.backdropsTab":"Дэвсгэрүүд","gui.gui.costumesTab":"Өмсгөлүүд","gui.gui.soundsTab":"Дуунууд","gui.extensionLibrary.comingSoon":"Мөд удахгүй","gui.extensionLibrary.requires":"Шаардлага","gui.extensionLibrary.collaboration":" хамтран ажиллах","gui.library.filterPlaceholder":"Хайх","gui.library.allTag":"Бүх","gui.loader.headline":"Төслийг уншиж байна","gui.loader.creating":"Төсөл үүсгэж байна","gui.authorInfo.byUser":"төслийг бүтээгч{username}","gui.menuBar.seeProjectPage":"Төслийн хуудсаар зочлох","gui.menuBar.LanguageSelector":"хэлний сонголт","gui.menuBar.tutorialsLibrary":"Дасгал хичээл","gui.menuBar.restoreSprite":"Устгасан дүрсийг буцаах","gui.menuBar.restoreSound":"Устгасан дууг буцаах","gui.menuBar.restoreCostume":"Устгасан өмсгөлийг буцаах","gui.menuBar.restore":"Устгах үйлдлийг буцаах","gui.menuBar.saveNow":"Одоо хадгалах","gui.menuBar.saveAsCopy":"Хуулбарлаж хадгалах","gui.menuBar.remix":"Холих","gui.menuBar.new":"Шинэ","gui.menuBar.file":"Файл","gui.menuBar.downloadToComputer":"Өөрийнхөө компьютерт хадгалах","gui.menuBar.edit":"Засах","gui.menuBar.turboModeOff":"Хурдасгах горимыг болиулах","gui.menuBar.turboModeOn":"Хурдасгах горимыг ажиллуулах","gui.gui.projectTitlePlaceholder":"Төслийн нэр бичих","gui.menuBar.isShared":"Хуваалцсан төсөл","gui.menuBar.share":"Хуваалцах","gui.modal.help":"Тусламж","gui.modal.back":"Буцах","gui.monitor.listMonitor.empty":"(хоосон)","gui.monitor.listMonitor.listLength":"урт {length}","gui.monitor.contextMenu.default":"жижигрүүлэх","gui.monitor.contextMenu.large":"томруулах","gui.monitor.contextMenu.slider":"хөшүүрэг","gui.monitor.contextMenu.sliderRange":"хөшүүргийн хязгаарыг өөрчлөх","gui.monitor.contextMenu.import":"оруулах","gui.monitor.contextMenu.export":"гаргах","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Тоглуулах","gui.playButton.stop":"Зогсоох","gui.gui.variableScopeOptionAllSprites":"Бүх дүрсэнд","gui.gui.variableScopeOptionSpriteOnly":"Зөвхөн энэ дүрсэнд","gui.gui.cloudVariableOption":"үүлэн хувьсагч (сервер дээр хадгалсан)","gui.gui.variablePromptAllSpritesMessage":"Энэ хувьсагчийн бүх дүрсэнд ашиглана.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Цуцлах","gui.prompt.ok":"Тийм","gui.playbackStep.stopMsg":"Зогсоох","gui.playbackStep.playMsg":"Тоглуулах","gui.playbackStep.loadingMsg":"Уншиж байна...","gui.playbackStep.saveMsg":"Хадгалах","gui.playbackStep.reRecordMsg":"Шинээр бичих","gui.recordModal.title":"Дуу бичих","gui.recordingStep.beginRecord":"\\"Бичих\\" товчийг дармагц дууг бичиж эхлэнэ","gui.recordingStep.permission":"{arrow}Микрофон ашиглах эрх олгоно уу","gui.recordingStep.stop":"Дуу бичихийг зогсоох","gui.recordingStep.record":"Дуу бичих","gui.sliderModal.min":"Хамгийн бага утга","gui.sliderModal.max":"Хамгийн их утга","gui.sliderModal.title":"Хөшүүрэгний цар хүрээг өөрчлөх ","gui.sliderPrompt.cancel":"Цуцлах","gui.sliderPrompt.ok":"Тийм","gui.soundEditor.sound":"Дуу","gui.soundEditor.play":"Тоглуулах","gui.soundEditor.stop":"Зогсоох","gui.soundEditor.copy":"Хуулбарлах","gui.soundEditor.paste":"Шилжүүлэх","gui.soundEditor.copyToNew":"Сонгосон дууг шинэ дуу руу хуулах","gui.soundEditor.delete":"Устгах","gui.soundEditor.save":"Хадгалах","gui.soundEditor.undo":"Буцаах","gui.soundEditor.redo":"Буцаасан үйлдлийг сэргээх","gui.soundEditor.faster":"Хурдасгах","gui.soundEditor.slower":"Удаашруулах","gui.soundEditor.echo":"Цуурайтуулах","gui.soundEditor.robot":"Робот эффект оруулах","gui.soundEditor.louder":"Чангалах","gui.soundEditor.softer":"Зөөлрүүлэх","gui.soundEditor.reverse":"Эргүүлэх","gui.soundEditor.fadeOut":"Аажмаар султгах","gui.soundEditor.fadeIn":"Аажмаар чангалах","gui.soundEditor.mute":"Дүүгүй болгох","gui.SpriteInfo.spritePlaceholder":"Нэр","gui.SpriteInfo.sprite":"Дүрс","gui.SpriteInfo.show":"Харуулах","gui.SpriteInfo.size":"Хэмжээ","gui.spriteSelectorItem.contextMenuDuplicate":"хувилах","gui.spriteSelectorItem.contextMenuExport":"компьютерт хадгалах","gui.spriteSelectorItem.contextMenuDelete":"устгах","gui.spriteSelector.addSpriteFromLibrary":"Дүрс сонгох","gui.spriteSelector.addSpriteFromPaint":"Дүрс зурах","gui.spriteSelector.addSpriteFromSurprise":"Дүрсийг санамсаргүйгээр сонго","gui.spriteSelector.addSpriteFromFile":"Дүрс компьютероос оруулах","gui.stageHeader.stageSizeLarge":"Тайзыг томруулах","gui.stageHeader.stageSizeSmall":"Тайзыг жижигрүүлэх","gui.stageHeader.stageSizeFull":"Дэлгэцийг томруулах","gui.stageHeader.stageSizeUnFull":"Дэлгэцийг жижигрүүлэх","gui.stageHeader.fullscreenControl":"Дэлгэцийг томруулах/жижигрүүлэх","gui.spriteSelector.addBackdropFromLibrary":"Дэвсгэр сонгох","gui.stageSelector.addBackdropFromPaint":"Тайз зурах","gui.stageSelector.addBackdropFromSurprise":"Тайзыг санамсаргүйгээр сонго","gui.stageSelector.addBackdropFromFile":"Дэвсгэрийг файлаас оруулах","gui.stageSelector.stage":"Тайз","gui.stageSelector.backdrops":"Дэвсгэрүүд","gui.telemetryOptIn.label":"Scratch-г сайжруулах зорилгоор статистик мэдээг явуулах","gui.telemetryOptIn.body1":"Scratch баг хүмүүс дэлхий даяар Scratch-г хэрхэн ашиглаж буйг мэдэж, хэрхэн сайжруулах хэрэгтэйг тогтмол судалж байдаг. Та бидний ажлыг дэмжин, Scratch баг руу автоматаар хэрэглээний мэдээллийг явуулах зөвшөөрлийг олгоорой.","gui.telemetryOptIn.body2":"Бид хэлний сонголт, блокын хэрэглээ, төсөл хадгалах, төсөл нээх, интернэтэд байршуулах зэрэг үйлдлүүдийн мэдэллийг цуглуулдаг болно. Бид хэрэглэгчийн ямарваа хувийн мэдээллийг цуглуулдаггүй. {privacyPolicyLink}руу хандаж манай мэдээлэл авах журамтай танилцана уу.","gui.telemetryOptIn.privacyPolicyLink":"Хувийн мэдээлэл хадгалах журам","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Алсаас хэмжих төхөөрөмжийг идэвхжүүлэх","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Алсаас хэмжих төхөөрөмжийг идэвхгүй болгох","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Хаах","gui.turboMode.active":"Турбо горим","gui.webglModal.label":"Таны интернэт хөтөч WebGL дэмждэггүй тул хандах боломжгүй байна","gui.webglModal.webgllink":"WebGL дэмждэггүй","gui.costumeLibrary.chooseABackdrop":"Дэвсгэр сонгох","gui.costumeLibrary.chooseACostume":"Өмсгөл сонгох","gui.costumeTab.addBackdropFromLibrary":"Дэвсгэр сонгох","gui.costumeTab.addCostumeFromLibrary":"Өмсгөл сонгох","gui.costumeTab.addBlankCostume":"Өмсгөл зурах","gui.costumeTab.addSurpriseCostume":"Өмсгөлийг санамсаргүйгээр сонго","gui.costumeTab.addFileBackdrop":"Дэвсгэрийг файлаас оруулах","gui.costumeTab.addFileCostume":"Файлаас өмсгөл оруулах","gui.extensionLibrary.chooseAnExtension":"Нэмэлт өргөтгөлүүд","gui.extensionLibrary.extensionUrl":"Өргөтгөлийн URL-г оруулна уу","gui.monitors.importListColumnPrompt":"Аль баганыг ашиглах вэ (1-{numberOfColumns}-с сонгоно уу)? ","gui.recordingStep.alertMsg":"Дуу бичиж чадсангүй","gui.soundLibrary.chooseASound":"Дуу сонгох","gui.soundTab.fileUploadSound":"Дууг компьютероос оруулах","gui.soundTab.surpriseSound":"Дууг санамсаргүйгээр сонгох","gui.soundTab.recordSound":"Дуу бичих","gui.soundTab.addSoundFromLibrary":"Дуу сонгох","gui.spriteLibrary.chooseASprite":"Дүрс сонгох","gui.tipsLibrary.tutorials":"Заавар сонгох","gui.alerts.createsuccess":"Шинэ төслийг үүсгэлээ.","gui.alerts.createcopysuccess":"Төслийг хуулбарлаж хадгаллаа.","gui.alerts.createremixsuccess":"Төслийг өөрчлөн хадгаллаа.","gui.alerts.creating":"Шинээр үүсгэж байна...","gui.alerts.creatingCopy":"Төслийг хуулбарлаж байна...","gui.alerts.creatingRemix":"Төслийг өөрчлөн нээж байна...","gui.alerts.creatingError":"Төсөл үүсгэж чадсангүй. Дахин оролдоорой!","gui.alerts.savingError":"Төслийг хадгалж чадсангүй.","gui.alerts.savesuccess":"Төслийг хадгаллаа.","gui.alerts.saving":"Төслийг хадгалж байна...","gui.alerts.cloudInfo":"Үүлэн хувьсагчид зөвхөн тоо хадгалж болох бөгөөд үсэг, дүрс хадгалахгүйг санаарай. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Илүү ихийг судлах.","gui.alerts.importing":"Төслийг оруулж байна","gui.defaultProject.variable":"миний хувьсагч","gui.extension.music.name":"Хөгжим","gui.extension.music.description":"Хөгжмийн зэмсэг, бөмбөр тоглуулах","gui.extension.pen.name":"Үзэг","gui.extension.pen.description":"Дүрсээрээ зурах","gui.extension.videosensing.name":"Бичлэг мэдрэгч","gui.extension.videosensing.description":"Камераар хөдөлгөөн мэдрэх","gui.extension.text2speech.name":"Бичмэл эхээс яриа рүү хөрвүүлэх","gui.extension.text2speech.description":"Төслүүдээ ярьдаг болгох","gui.extension.translate.name":"Орчуулах","gui.extension.translate.description":"Эхийг олон хэл рүү хөрвүүлэх","gui.extension.makeymakey.description":"Ямарваа зүйлийг товч болгон ашиглах","gui.extension.microbit.description":"Төслөө бусадтай хуваалцъя","gui.extension.microbit.connectingMessage":"Холбогдож байна","gui.extension.ev3.description":"Хөдөлгөөнт робот зэргийг барих ","gui.extension.ev3.connectingMessage":"Холбогдож байна. EV3 дээрх хөлийг 1234 болгож тохируулсанг эсэхийг нягтлаарай.","gui.extension.boost.description":"Роботуудад амь оруулцгаая.","gui.extension.boost.connectingMessage":"Холбогдож байна","gui.extension.wedo2.description":"Мотор, мэдрэгч ашиглах","gui.extension.wedo2.connectingMessage":"Холбогдож байна","gui.extension.gdxfor.description":"Түлхэх, татах, хөдлөх, эргэлдэх хөдөлгөөнүүдийг мэдрэх","gui.extension.gdxfor.connectingMessage":"Холбогдож байна","gui.libraryTags.all":"Бүгд","gui.libraryTags.animals":"Амьтад","gui.libraryTags.dance":"Бүжиг","gui.libraryTags.effects":"Эффект","gui.libraryTags.fantasy":"Уран зөгнөлт","gui.libraryTags.fashion":"Хувцас загвар","gui.libraryTags.food":"Хоол","gui.libraryTags.indoors":"Дотоод","gui.libraryTags.loops":"Давталтууд","gui.libraryTags.music":"Хөгжим","gui.libraryTags.notes":"Нотууд","gui.libraryTags.outdoors":"Гадаад","gui.libraryTags.patterns":"Зураг хээ","gui.libraryTags.people":"Хүмүүс","gui.libraryTags.percussion":"Цохиур хөгжим","gui.libraryTags.space":"Сансар огторгүй","gui.libraryTags.sports":"Спорт","gui.libraryTags.underwater":"Усан доорх","gui.libraryTags.voice":"Дуу, хоолой","gui.libraryTags.wacky":"Өвөрмөц","gui.libraryTags.animation":"Анимэйшн","gui.libraryTags.art":"Урлаг","gui.libraryTags.games":"Тоглоомнууд","gui.libraryTags.stories":"Үлгэрүүд","gui.libraryTags.letters":"Үсгүүд","gui.opcodeLabels.direction":"чиглэл","gui.opcodeLabels.xposition":"x - утга","gui.opcodeLabels.yposition":"y - утга","gui.opcodeLabels.size":"хэмжээ","gui.opcodeLabels.costumename":"өмсгөлийн нэр","gui.opcodeLabels.costumenumber":"өмсгөлийн дугаар","gui.opcodeLabels.backdropname":"дэвсгэрийн нэр","gui.opcodeLabels.backdropnumber":"дэвсгэрийн дугаар","gui.opcodeLabels.volume":"дууны эрч","gui.opcodeLabels.tempo":"хэм","gui.opcodeLabels.answer":"хариулт","gui.opcodeLabels.loudness":"дууны эрч","gui.opcodeLabels.username":"хэрэглэгчийн нэр","gui.opcodeLabels.year":"жил","gui.opcodeLabels.month":"сар","gui.opcodeLabels.date":"огноо","gui.opcodeLabels.dayofweek":"долоо хоногийн өдөр","gui.opcodeLabels.hour":"цаг","gui.opcodeLabels.minute":"минут","gui.opcodeLabels.second":"секунд","gui.opcodeLabels.timer":"тоолуур","gui.sharedMessages.backdrop":"дэвсгэр {index}","gui.sharedMessages.costume":"өмсгөл {index}","gui.sharedMessages.sprite":"Дүрс {index}","gui.sharedMessages.pop":"поп","gui.sharedMessages.replaceProjectWarning":"Одоо хөгжүүлж буй төслийг устган, шинийг нээх үү?","gui.sharedMessages.loadFromComputerTitle":"Компьютероос төсөл оруулах","boost.color.any":"ямар нэг өнгө","boost.color.black":"хар","boost.color.blue":"цэнхэр","boost.color.green":"ногоон","boost.color.red":"улаан","boost.color.white":"цагаан","boost.color.yellow":"шар","boost.getMotorPosition":"[MOTOR_REPORTER_ID] моторын байршил","boost.getTiltAngle":"[TILT_DIRECTION] өнцгөөр хазайлга","boost.motorDirection.backward":"тэрүүгээр","boost.motorDirection.forward":"энүүгээр","boost.motorDirection.reverse":"гэдрэг","boost.motorOff":"[MOTOR_ID] мотор-г унтраа","boost.motorOn":"[MOTOR_ID] моторыг асаа","boost.motorOnFor":"[MOTOR_ID] моторыг [DURATION] секунд асаа","boost.motorOnForRotation":"мотор [MOTOR_ID]-г [ROTATION] эргүүлэхээр асаа","boost.seeingColor":"[COLOR] тоосгыг харж байна уу?","boost.setLightHue":"гэрлийн өнгийг [HUE] болго","boost.setMotorDirection":"[MOTOR_ID] моторын чиглэлийг [MOTOR_DIRECTION] болго","boost.setMotorPower":"[MOTOR_ID] моторын хурдыг [POWER] % болго","boost.tiltDirection.any":"аливаа","boost.tiltDirection.down":"доошоо","boost.tiltDirection.left":"зүүн","boost.tiltDirection.right":"баруун","boost.tiltDirection.up":"дээшээ","boost.whenColor":"[COLOR] тоосгыг харсан бол","boost.whenTilted":"[TILT_DIRECTION_ANY] чигт хазайсан бол","ev3.beepNote":"[NOTE] нот-г [TIME] секундын турш дуугарга","ev3.buttonPressed":"[PORT] товчлуурыг дарсан уу?","ev3.getBrightness":"цайруулалт","ev3.getDistance":"зай","ev3.getMotorPosition":"моторын [PORT] -ын байрлал","ev3.motorSetPower":"моторын [PORT] -ын хүчийг [POWER] болго","ev3.motorTurnClockwise":"моторын [PORT] -г цагийн зүүний дагуу [TIME] секунд хөдөлгө","ev3.motorTurnCounterClockwise":"моторын [PORT] -г цагийн зүүний эсрэг тийш [TIME] секунд хөдөлгө","ev3.whenBrightnessLessThan":"цайруулалт < [DISTANCE] үед","ev3.whenButtonPressed":"[PORT] товчлуурыг дарсан үед","ev3.whenDistanceLessThan":"зай < [DISTANCE] үед","gdxfor.getAcceleration":"[DIRECTION] зүгт хурдал","gdxfor.getForce":"хүч","gdxfor.getSpin":"[DIRECTION] хурдаар эргэлд","gdxfor.getTilt":"өнцгийг [TILT] -р хазайлга","gdxfor.isFreeFalling":"унаж байна уу?","gdxfor.isTilted":"[TILT] өнцгөөр хазайсан байна уу?","gdxfor.pulled":"гадагш татагдсан","gdxfor.pushed":"дотогш түлхэгдсэн","gdxfor.shaken":"сэгсрэгдсэн","gdxfor.startedFalling":"унаж эхэлсэн","gdxfor.tiltDirectionMenu.any":"аливаа","gdxfor.tiltDirectionMenu.back":"ар тал","gdxfor.tiltDirectionMenu.front":"нүүр тал","gdxfor.tiltDirectionMenu.left":"зүүн","gdxfor.tiltDirectionMenu.right":"баруун","gdxfor.turnedFaceDown":"нүүр тал нь доош харсан","gdxfor.turnedFaceUp":"нүүр тал нь дээш харсан","gdxfor.whenForcePushedOrPulled":"хүч мэдрэгч [PUSH_PULL] мэдрэх үед","gdxfor.whenGesture":"[GESTURE] мэдрэгдэх үед","gdxfor.whenTilted":"[TILT] өнцгөөр хазайсан байхад","makeymakey.downArrow":"доошоо сум","makeymakey.downArrowShort":"доошоо","makeymakey.leftArrow":"зүүн сум","makeymakey.leftArrowShort":"зүүн","makeymakey.rightArrow":"баруун сум","makeymakey.rightArrowShort":"баруун","makeymakey.spaceKey":"спейс товчлуур","makeymakey.upArrow":"дээш сум","makeymakey.upArrowShort":"дээш","makeymakey.whenKeyPressed":"товчлуур [KEY] дарагдах үед","makeymakey.whenKeysPressedInOrder":"[SEQUENCE] дарааллыг дарах үед","microbit.buttonsMenu.any":"аливаа","microbit.clearDisplay":"дэлгэцийг цэвэрлэ","microbit.defaultTextToDisplay":"Sain uu!","microbit.displaySymbol":"[MATRIX] -г дэлгэцээр гарга","microbit.displayText":"[TEXT] -г дэлгэцээр гарга","microbit.gesturesMenu.jumped":"үсэрсэн","microbit.gesturesMenu.moved":"хөдөлсөн","microbit.gesturesMenu.shaken":"сэгсрэгдсэн","microbit.isButtonPressed":"[BTN] товчлуур дарагдсан уу?","microbit.isTilted":"[DIRECTION] зүг рүү хазайсан байна уу?","microbit.pinStateMenu.off":"Унтраа","microbit.pinStateMenu.on":"Асаа","microbit.tiltAngle":"өнцгийг [DIRECTION] -р хазайлга","microbit.tiltDirectionMenu.any":"аливаа","microbit.tiltDirectionMenu.back":"ар тал","microbit.tiltDirectionMenu.front":"урд тал","microbit.tiltDirectionMenu.left":"зүүн","microbit.tiltDirectionMenu.right":"баруун","microbit.whenButtonPressed":"[BTN] товчлуурыг дарсан үед","microbit.whenGesture":"[GESTURE] мэдрэгдэх үед","microbit.whenPinConnected":"[PIN] хөл холбогдсон үед","microbit.whenTilted":"[DIRECTION] чигт хазайсан бол","music.categoryName":"Хөгжим","music.changeTempo":"эрчмийг [TEMPO]-р соль","music.drumBass":"(2) том бөмбөр","music.drumBongo":"(13) Бонго","music.drumCabasa":"(15) Кабаса хөгжмийн зэмсэг","music.drumClaves":"(9) Цохиурт хөгжмийн зэмсэг","music.drumClosedHiHat":"(6) Хаалттай товшлуур хөгжим","music.drumConga":"(14) Конга","music.drumCowbell":"(11) Хонх","music.drumCrashCymbal":"(4) Жингэнэх цан","music.drumCuica":"(18) Күика бөмбөр","music.drumGuiro":"(16) Гуйро","music.drumHandClap":"(8) Алга ташилтын дуу","music.drumOpenHiHat":"(5) Хаалттай товшлуур хөгжим","music.drumSideStick":"(3) Давхар бөмбөрдөх","music.drumSnare":"(18) Жижиг бөмбөр","music.drumTambourine":"(7) Тамбурин","music.drumTriangle":"(12) Гурвалжин","music.drumVibraslap":"(17) Вибро слэп","music.drumWoodBlock":"(10) Модон блок","music.getTempo":"хэм","music.instrumentBass":"(6) Басс","music.instrumentBassoon":"(14) Үелэх бишгүүр","music.instrumentCello":"(8) Том хуур","music.instrumentChoir":"(15) Найрал дуу","music.instrumentClarinet":"(10) Кларинет бишгүүр","music.instrumentElectricGuitar":"(5) Цахилгаан гитар","music.instrumentElectricPiano":"(2) Цахилгаан төгөлдөр хуур","music.instrumentFlute":"(12) Лимбэ","music.instrumentGuitar":"(4) Гитар","music.instrumentMarimba":"(19) Маримба хөгжим","music.instrumentMusicBox":"(17) Хөгжмийн хайрцаг","music.instrumentOrgan":"(3) Орган хөгжим","music.instrumentPiano":"(1) Төгөлдөр хуур","music.instrumentPizzicato":"(7) Пиццикато","music.instrumentSaxophone":"(11) Сакфофон","music.instrumentSteelDrum":"(18) Ган бөмбөр","music.instrumentSynthLead":"(20) Синтетик хөгжим","music.instrumentSynthPad":"(21) Синтетик даралт","music.instrumentTrombone":"(9) Тромбон үлээвэр хөгжим","music.instrumentVibraphone":"(16) Вибрафон","music.instrumentWoodenFlute":"(13) Модон бишгүүр","music.midiPlayDrumForBeats":"[DRUM] бөмбөрийг [BEATS] хэмнэл тогло","music.midiSetInstrument":"хөгжмийн зэмсгийг [INSTRUMENT] болго","music.playDrumForBeats":"[DRUM] бөмбөрийг [BEATS] хэмнэл тогло","music.playNoteForBeats":"[NOTE] нотыг [BEATS] хэмнэл тогло","music.restForBeats":"[BEATS] хэмнэл завсарла","music.setInstrument":"хөгжмийн зэмсгийг [INSTRUMENT] болго","music.setTempo":"темпийг [TEMPO] болго","pen.categoryName":"Үзэг","pen.changeColorParam":"үзгийн [COLOR_PARAM] -г [VALUE] -р соль","pen.changeHue":"үзэгний өнгийг [HUE] болго","pen.changeShade":"үзэгний сүүдрийг [SHADE] болго","pen.changeSize":"үзэгний хэмжээг [SIZE]-р өөрчил","pen.clear":"бүгдийг арилга","pen.colorMenu.brightness":"гэрэлтэлт","pen.colorMenu.color":"өнгө","pen.colorMenu.saturation":"нэвчилт","pen.colorMenu.transparency":"тунгалагжилт","pen.penDown":"зур","pen.penUp":"зурахаа боль","pen.setColor":"[COLOR] өнгийн үзэг","pen.setColorParam":"үзэгний [COLOR_PARAM] -г [VALUE] болго","pen.setHue":"үзэгний өнгийг [HUE] болго","pen.setShade":"үзэгний сүүдрийг [SHADE] болго","pen.setSize":"үзэгний хэмжээг [SIZE] болго","pen.stamp":"дардас","text2speech.alto":"алто","text2speech.categoryName":"Бичмэл эхээс яриа рүү","text2speech.defaultTextToSpeak":"Сайн уу","text2speech.giant":"аврага","text2speech.kitten":"муужгай","text2speech.setLanguageBlock":"хэлийг [LANGUAGE] хэл болго","text2speech.setVoiceBlock":"авиаг [VOICE] болго","text2speech.speakAndWaitBlock":"[WORDS] үгийг хэл","text2speech.squeak":"чахрах","text2speech.tenor":"тенор хоолой","translate.categoryName":"Орчуулах","translate.defaultTextToTranslate":"Сайн уу","translate.translateBlock":"[WORDS] -г [LANGUAGE] хэл лүү орчуул","translate.viewerLanguage":"хэл","videoSensing.categoryName":"Бичлэг мэдрэгч","videoSensing.direction":"чиглэл","videoSensing.motion":"хөдөлгөөн","videoSensing.off":"Салга","videoSensing.on":"Залга","videoSensing.onFlipped":"эргүүлсэн","videoSensing.setVideoTransparency":"бичлэгийн тунгалагжилтыг [TRANSPARENCY] болго","videoSensing.sprite":"дүрс","videoSensing.stage":"тайз","videoSensing.videoOn":"[SUBJECT] -д оногдох нийт [ATTRIBUTE] -н тоо","videoSensing.videoToggle":"бичлэгийг [VIDEO_STATE] болго","videoSensing.whenMotionGreaterThan":"бичлэгийн хөдөлгөөн > [REFERENCE] үед","wedo2.getDistance":"зай","wedo2.getTiltAngle":"өнцгийг [TILT_DIRECTION] -р хазайлга","wedo2.isTilted":"[TILT_DIRECTION_ANY] чигт хазайсан байна уу?","wedo2.motorDirection.backward":"тэрүүгээр","wedo2.motorDirection.forward":"тэр зам","wedo2.motorDirection.reverse":"гэдрэг","wedo2.motorId.a":"мотор A","wedo2.motorId.all":"бүх моторууд","wedo2.motorId.b":"мотор B","wedo2.motorId.default":"мотор","wedo2.motorOff":"мотор [MOTOR_ID] -г унтраа","wedo2.motorOn":"мотор [MOTOR_ID] -г асаа","wedo2.motorOnFor":"мотор [MOTOR_ID] -г [DURATION] секунд асаа","wedo2.playNoteFor":"[NOTE] нотыг [DURATION] секунд тогло ","wedo2.setLightHue":"гэрлийн өнгийг [HUE] болго","wedo2.setMotorDirection":"мотор [MOTOR_ID] -н чиглэлийг [MOTOR_DIRECTION] болго","wedo2.startMotorPower":"моторын [MOTOR_ID] -ын хүчийг [POWER] болго","wedo2.tiltDirection.any":"аливаа","wedo2.tiltDirection.down":"доошоо","wedo2.tiltDirection.left":"зүүн","wedo2.tiltDirection.right":"баруун","wedo2.tiltDirection.up":"дээшээ","wedo2.whenDistance":"зай [OP][REFERENCE] үед","wedo2.whenTilted":"[TILT_DIRECTION_ANY] чигт хазайсан бол","paint.paintEditor.hue":"Өнгө","paint.paintEditor.saturation":"Нэвчилт","paint.paintEditor.brightness":"Цайруулалт","paint.paintEditor.costume":"Өмсгөл","paint.paintEditor.group":"Бүлэг","paint.paintEditor.ungroup":"Бүлэглэлт болиулах","paint.paintEditor.undo":"Үйлдлийг буцаах","paint.paintEditor.redo":"Буцаалтыг сэргээх","paint.paintEditor.forward":"Урагшаа","paint.paintEditor.backward":"Арагшаа","paint.paintEditor.front":"Урд","paint.paintEditor.back":"Ард","paint.paintEditor.more":"Цааш...","paint.modeTools.brushSize":"Хэмжээ","paint.modeTools.eraserSize":"Баллуурын хэмжээ","paint.modeTools.copy":"Хуулбарлах","paint.modeTools.paste":"Хуулбарыг буулгах","paint.modeTools.delete":"Устгах","paint.modeTools.curved":"Мохой","paint.modeTools.pointed":"Хурц","paint.modeTools.thickness":"Зузаан","paint.modeTools.flipHorizontal":"Хэвтээ тэнхлэгийн дагуу тонгоруулах","paint.modeTools.flipVertical":"Босоо тэнхлэгийн дагуу тонгоруулах","paint.modeTools.filled":"Дүүрсэн","paint.modeTools.outlined":"Хүрээлсэн зураастай","paint.paintEditor.bitmap":"Битмап-руу шилжүүлэх","paint.paintEditor.vector":"Вектор-т шилжүүл","paint.paintEditor.fill":"Дүүргэх","paint.paintEditor.stroke":"Хүрээ зураас","paint.brushMode.brush":"Бийр","paint.eraserMode.eraser":"Баллуур","paint.fillMode.fill":"Дүүргэх","paint.lineMode.line":"Шугам","paint.ovalMode.oval":"Тойрог","paint.rectMode.rect":"Тэгш өнцөгт","paint.reshapeMode.reshape":"Дүрсийг өөрчлөх","paint.roundedRectMode.roundedRect":"Мөлгөр дөрвөлжин","paint.selectMode.select":"Сонгох","paint.textMode.text":"Текст","paint.colorPicker.swap":"Сэлгэх"},"nl":{"gui.alerts.tryAgain":"Probeer opnieuw","gui.alerts.download":"Downloaden","gui.connection.reconnect":"Opnieuw verbinden","gui.backpack.costumeLabel":"uiterlijk","gui.backpack.soundLabel":"geluid","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Rugzak","gui.backpack.errorBackpack":"Fout bij laden van de rugzak","gui.backpack.loadingBackpack":"Laden ...","gui.backpack.more":"Meer","gui.backpack.emptyBackpack":"Rugzak is leeg","gui.unsupportedBrowser.label":"Browser wordt niet ondersteund","gui.cards.all-tutorials":"Lessen","gui.cards.shrink":"Verklein","gui.cards.expand":"Vergroot","gui.cards.close":"Sluiten","gui.cards.more-things-to-try":"Meer dingen om te proberen!","gui.cards.see-more":"Bekijk meer","gui.comingSoon.message1":"Geen zorgen, wij zijn ermee bezig {emoji}","gui.comingSoon.message2":"Binnenkort beschikbaar","gui.comingSoon.message3":"Wordt aan gewerkt {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Geen apparaten gevonden","gui.connection.auto-scanning.prescan":"Houd je apparaat in de buurt, begin dan met zoeken","gui.connection.auto-scanning.pressbutton":"Druk op de knop op je apparaat","gui.connection.auto-scanning.start-search":"Start met zoeken","gui.connection.connecting-searchbutton":"Zoeken ...","gui.connection.auto-scanning.try-again":"Probeer opnieuw","gui.connection.connected":"Verbonden","gui.connection.disconnect":"Verbinding verbreken","gui.connection.go-to-editor":"Ga naar de editor","gui.connection.connecting-cancelbutton":"Bezig te verbinden ...","gui.connection.error.errorMessage":"Oeps, het lijkt dat er iets mis gegaan is.","gui.connection.error.tryagainbutton":"Probeer opnieuw","gui.connection.error.helpbutton":"Help","gui.connection.peripheral-name-label":"Apparaatnaam","gui.connection.connect":"Verbind","gui.connection.scanning.lookingforperipherals":"Zoeken naar apparaten","gui.connection.scanning.noPeripheralsFound":"Geen apparaten gevonden","gui.connection.scanning.instructions":"Kies je apparaat in de lijst hierboven.","gui.connection.search":"Ververs","gui.connection.unavailable.installscratchlink":"Zorg ervoor Scratch Link geïnstalleerd is en draait.","gui.connection.unavailable.enablebluetooth":"Controleer dat Bluetooth aan staat","gui.connection.unavailable.tryagainbutton":"Probeer opnieuw","gui.connection.unavailable.helpbutton":"Help","gui.controls.go":"Ga","gui.controls.stop":"Stop","gui.crashMessage.label":"Oeps! Er is iets fout gegaan.","gui.crashMessage.errorNumber":"Je pagina is vastgelopen, en dat is geregistreerd met ID{errorId}","gui.crashMessage.reload":"Herladen","gui.customProcedures.myblockModalTitle":"Maak een blok","gui.customProcedures.addAnInputNumberText":"Voeg een invoer toe","gui.customProcedures.numberTextType":"getal of tekst","gui.customProcedures.addAnInputBoolean":"Voeg een invoer toe","gui.customProcedures.booleanType":"booleaan","gui.customProcedures.addALabel":"Voeg een label toe","gui.customProcedures.runWithoutScreenRefresh":"Voer uit zonder het scherm te verversen","gui.customProcedures.cancel":" Annuleren","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Richting","gui.directionPicker.rotationStyles.allAround":"Helemaal meedraaien","gui.directionPicker.rotationStyles.leftRight":"Links/rechts","gui.directionPicker.rotationStyles.dontRotate":"Niet meedraaien","gui.gui.addExtension":"Voeg een uitbreiding toe","gui.gui.codeTab":"Code","gui.gui.backdropsTab":"Achtergronden","gui.gui.costumesTab":"Uiterlijken","gui.gui.soundsTab":"Geluiden","gui.extensionLibrary.comingSoon":"Binnenkort beschikbaar","gui.extensionLibrary.requires":"Vereist","gui.extensionLibrary.collaboration":"Samenwerking met","gui.library.filterPlaceholder":"Zoek","gui.library.allTag":"Alles","gui.loader.headline":"Project laden...","gui.loader.creating":"Bezig een project te maken","gui.authorInfo.byUser":"door {username}","gui.menuBar.seeProjectPage":"Bekijk de project pagina","gui.menuBar.LanguageSelector":"taalkiezer","gui.menuBar.tutorialsLibrary":"Lessen","gui.menuBar.restoreSprite":"Herstel sprite","gui.menuBar.restoreSound":"Herstel geluid","gui.menuBar.restoreCostume":"Herstel uiterlijk","gui.menuBar.restore":"Herstel","gui.menuBar.saveNow":"Nu opslaan","gui.menuBar.saveAsCopy":"Opslaan als","gui.menuBar.remix":"Remix","gui.menuBar.new":"Nieuw","gui.menuBar.file":"Bestand","gui.menuBar.downloadToComputer":"Opslaan op je computer","gui.menuBar.edit":"Bewerk","gui.menuBar.turboModeOff":"Zet turbo modus uit","gui.menuBar.turboModeOn":"Zet turbo modus aan","gui.gui.projectTitlePlaceholder":"Project titel hier","gui.menuBar.isShared":"Gedeeld","gui.menuBar.share":"Delen","gui.modal.help":"Help","gui.modal.back":"Terug","gui.monitor.listMonitor.empty":"(leeg)","gui.monitor.listMonitor.listLength":"lengte {length}","gui.monitor.contextMenu.default":"normaal uitlezen","gui.monitor.contextMenu.large":"groot uitlezen","gui.monitor.contextMenu.slider":"schuif","gui.monitor.contextMenu.sliderRange":"verander schuifbereik","gui.monitor.contextMenu.import":"importeren","gui.monitor.contextMenu.export":"exporteren","gui.monitor.contextMenu.hide":"verdwijn","gui.playButton.play":"Spelen","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"Voor alle sprites","gui.gui.variableScopeOptionSpriteOnly":"Alleen voor deze sprite","gui.gui.cloudVariableOption":"Cloud variabele (opgeslagen op de server)","gui.gui.variablePromptAllSpritesMessage":"Deze variabele is beschikbaar in alle sprites.","gui.gui.listPromptAllSpritesMessage":"Deze lijst zal beschikbaar zijn voor alle sprites.","gui.prompt.cancel":" Annuleren","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Stop","gui.playbackStep.playMsg":"Spelen","gui.playbackStep.loadingMsg":"Laden ...","gui.playbackStep.saveMsg":"Bewaar","gui.playbackStep.reRecordMsg":"Opnieuw opnemen","gui.recordModal.title":"Geluid opnemen","gui.recordingStep.beginRecord":"Begin met opnemen door op de onderstaande knop te klikken","gui.recordingStep.permission":"{arrow}We hebben je toestemming nodig om je microfoon te gebruiken","gui.recordingStep.stop":"Stop met opnemen","gui.recordingStep.record":"Opnemen","gui.sliderModal.min":"Minimum waarde","gui.sliderModal.max":"Maximum waarde","gui.sliderModal.title":"Verander schuifbereik","gui.sliderPrompt.cancel":"Annuleren","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Geluid","gui.soundEditor.play":"Spelen","gui.soundEditor.stop":"Stop","gui.soundEditor.copy":"Kopie maken ","gui.soundEditor.paste":"Plakken","gui.soundEditor.copyToNew":"Kopieer naar nieuw","gui.soundEditor.delete":"Verwijder","gui.soundEditor.save":"Opslaan","gui.soundEditor.undo":"Ongedaan maken","gui.soundEditor.redo":"Opnieuw","gui.soundEditor.faster":"Sneller","gui.soundEditor.slower":"Trager","gui.soundEditor.echo":"Echo","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Luider","gui.soundEditor.softer":"Zachter","gui.soundEditor.reverse":"Keer om","gui.soundEditor.fadeOut":"Fade uit","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Stil","gui.SpriteInfo.spritePlaceholder":"Naam","gui.SpriteInfo.sprite":"Sprite","gui.SpriteInfo.show":"Toon","gui.SpriteInfo.size":"Grootte","gui.spriteSelectorItem.contextMenuDuplicate":"dupliceren","gui.spriteSelectorItem.contextMenuExport":"exporteren","gui.spriteSelectorItem.contextMenuDelete":"verwijderen","gui.spriteSelector.addSpriteFromLibrary":"Kies een sprite","gui.spriteSelector.addSpriteFromPaint":"Teken","gui.spriteSelector.addSpriteFromSurprise":"Verrassing","gui.spriteSelector.addSpriteFromFile":"Upload sprite","gui.stageHeader.stageSizeLarge":"Schakel naar groot speelveld","gui.stageHeader.stageSizeSmall":"Schakel naar klein speelveld","gui.stageHeader.stageSizeFull":"Ga naar volledig scherm","gui.stageHeader.stageSizeUnFull":"Verlaat full screen mode","gui.stageHeader.fullscreenControl":"Volledig scherm besturing","gui.spriteSelector.addBackdropFromLibrary":"Kies een achtergrond","gui.stageSelector.addBackdropFromPaint":"Tekenen","gui.stageSelector.addBackdropFromSurprise":"Verrassing","gui.stageSelector.addBackdropFromFile":"Upload achtergrond","gui.stageSelector.stage":"Speelveld","gui.stageSelector.backdrops":"Achtergronden","gui.telemetryOptIn.label":"Deel statistieken om Scratch te verbeteren","gui.telemetryOptIn.body1":"Het Scratch-team is constant bezig om beter te begrijpen hoe Scratch wereldwijd gebruikt wordt. Om dit streven te ondersteunen, kun je Scratch toestaan om automatisch gebruiksgegevens te versturen naar het Scratch-team.","gui.telemetryOptIn.body2":"De informatie die we verzamelen omvat taalkeuze, gebruik van blokken en een aantal acties zoals opslaan, laden en uploaden van een project. We verzamelen GEEN persoonlijke informatie. Zie ons {privacyPolicyLink} voor meer informatie.","gui.telemetryOptIn.privacyPolicyLink":"Privacybeleid","gui.telemetryOptIn.optInText":"Deel mijn gebruikersgegevens met het Scratch Team","gui.telemetryOptIn.optInTooltip":"Schakel telemetrie in","gui.telemetryOptIn.optOutText":"Deel mijn gebruikersgegevens niet met het Scratch Team","gui.telemetryOptIn.optOutTooltip":"Schakel telemetrie uit","gui.telemetryOptIn.settingWasUpdated":"Je keuze is bijgewerkt.","gui.telemetryOptIn.buttonClose":"Sluiten","gui.turboMode.active":"Turbomodus","gui.webglModal.label":"WebGL wordt niet door jouw browser ondersteund","gui.webglModal.webgllink":"ondersteunt geen WebGL","gui.costumeLibrary.chooseABackdrop":"Kies een achtergrond","gui.costumeLibrary.chooseACostume":"Kies een uiterlijk","gui.costumeTab.addBackdropFromLibrary":"Kies een achtergrond","gui.costumeTab.addCostumeFromLibrary":"Kies een uiterlijk","gui.costumeTab.addBlankCostume":"Tekenen","gui.costumeTab.addSurpriseCostume":"Verrassing","gui.costumeTab.addFileBackdrop":"Upload achtergrond","gui.costumeTab.addFileCostume":"Upload uiterlijk","gui.extensionLibrary.chooseAnExtension":"Kies een uitbreiding","gui.extensionLibrary.extensionUrl":"Geef de URL van de uitbreiding","gui.monitors.importListColumnPrompt":"Welke kolom moet gebruikt worden (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Kon opname niet starten","gui.soundLibrary.chooseASound":"Kies een geluid","gui.soundTab.fileUploadSound":"Upload geluid","gui.soundTab.surpriseSound":"Verrassing","gui.soundTab.recordSound":"Opnemen","gui.soundTab.addSoundFromLibrary":"Kies een geluid","gui.spriteLibrary.chooseASprite":"Kies een sprite","gui.tipsLibrary.tutorials":"Kies een handleiding","gui.alerts.createsuccess":"Nieuw project gemaakt.","gui.alerts.createcopysuccess":"Kopie van het project bewaard.","gui.alerts.createremixsuccess":"Project bewaard als een remix.","gui.alerts.creating":"Bezig met nieuw te maken ...","gui.alerts.creatingCopy":"Project wordt gekopieerd ...","gui.alerts.creatingRemix":"Project wordt geremixed","gui.alerts.creatingError":"Kon het project niet maken. Probeer opnieuw!","gui.alerts.savingError":"Project kon niet opgeslagen worden.","gui.alerts.savesuccess":"Project is bewaard.","gui.alerts.saving":"Project wordt bewaard ...","gui.alerts.cloudInfo":"Let op, cloud variabelen kunnen alleen worden gebruikt voor getallen, niet voor tekst of symbolen. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Meer weten.","gui.alerts.importing":"Bezig met importeren ...","gui.defaultProject.variable":"mijn variabele","gui.extension.music.name":"Muziek","gui.extension.music.description":"Speel instrumenten en drums.","gui.extension.pen.name":"Pen","gui.extension.pen.description":"Teken met je sprites.","gui.extension.videosensing.name":"Video","gui.extension.videosensing.description":"Neem beweging waar met de camera","gui.extension.text2speech.name":"Tekst naar spraak","gui.extension.text2speech.description":"Laat je projecten praten","gui.extension.translate.name":"Vertaal","gui.extension.translate.description":"Vertaal tekst naar vele talen.","gui.extension.makeymakey.description":"Verander alles in een knop","gui.extension.microbit.description":"Verbind je projecten met de wereld.","gui.extension.microbit.connectingMessage":"Bezig te verbinden","gui.extension.ev3.description":"Bouw interactieve robots en meer.","gui.extension.ev3.connectingMessage":"Bezig te verbinden. Zorg dat de pin op je EV3 op 1234 gezet is.","gui.extension.boost.description":"Breng robotcreaties tot leven.","gui.extension.boost.connectingMessage":"Bezig te verbinden","gui.extension.wedo2.description":"Bouw met motoren en sensoren.","gui.extension.wedo2.connectingMessage":"Bezig te verbinden","gui.extension.gdxfor.description":"Waarnemen van duwen, trekken, bewegen en draaien","gui.extension.gdxfor.connectingMessage":"Bezig te verbinden","gui.libraryTags.all":"Alles","gui.libraryTags.animals":"Dieren","gui.libraryTags.dance":"Dansen","gui.libraryTags.effects":"Effecten","gui.libraryTags.fantasy":"Fantasie","gui.libraryTags.fashion":"Mode","gui.libraryTags.food":"Voedsel","gui.libraryTags.indoors":"Binnen","gui.libraryTags.loops":"Lussen","gui.libraryTags.music":"Muziek","gui.libraryTags.notes":"Noten","gui.libraryTags.outdoors":"Buiten","gui.libraryTags.patterns":"Patronen","gui.libraryTags.people":"Mensen","gui.libraryTags.percussion":"Slagwerk","gui.libraryTags.space":"Ruimte","gui.libraryTags.sports":"Sport","gui.libraryTags.underwater":"Onder water","gui.libraryTags.voice":"Stem","gui.libraryTags.wacky":"Gek","gui.libraryTags.animation":"Animatie","gui.libraryTags.art":"Kunst","gui.libraryTags.games":"Spelletjes","gui.libraryTags.stories":"Verhalen","gui.libraryTags.letters":"Letters","gui.opcodeLabels.direction":"richting","gui.opcodeLabels.xposition":"x-positie","gui.opcodeLabels.yposition":"y-positie","gui.opcodeLabels.size":"grootte","gui.opcodeLabels.costumename":"uiterlijk naam","gui.opcodeLabels.costumenumber":"uiterlijk nummer","gui.opcodeLabels.backdropname":"achtergrond naam","gui.opcodeLabels.backdropnumber":"achtergrond nummer","gui.opcodeLabels.volume":"volume","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"antwoord","gui.opcodeLabels.loudness":"volume","gui.opcodeLabels.username":"gebruikersnaam","gui.opcodeLabels.year":"jaar","gui.opcodeLabels.month":"maand","gui.opcodeLabels.date":"datum","gui.opcodeLabels.dayofweek":"dag van de week","gui.opcodeLabels.hour":"uur","gui.opcodeLabels.minute":"minuut","gui.opcodeLabels.second":"seconde","gui.opcodeLabels.timer":"klok","gui.sharedMessages.backdrop":"achtergrond{index}","gui.sharedMessages.costume":"uiterlijk{index}","gui.sharedMessages.sprite":"Sprite{index}","gui.sharedMessages.pop":"plop","gui.sharedMessages.replaceProjectWarning":"Huidige project vervangen?","gui.sharedMessages.loadFromComputerTitle":"Uploaden vanaf je computer","boost.color.any":"willekeurige kleur","boost.color.black":"zwart","boost.color.blue":"blauw","boost.color.green":"groen","boost.color.red":"rood","boost.color.white":"wit","boost.color.yellow":"geel","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] positie","boost.getTiltAngle":"kantelhoek [TILT_DIRECTION]","boost.motorDirection.backward":"daarheen","boost.motorDirection.forward":"hierheen","boost.motorDirection.reverse":"omkeren","boost.motorOff":"zet motor [MOTOR_ID] uit","boost.motorOn":"zet motor [MOTOR_ID] aan","boost.motorOnFor":"zet motor [MOTOR_ID][DURATION] seconde aan","boost.motorOnForRotation":"zet motor [MOTOR_ID] aan voor [ROTATION] omwentelingen","boost.seeingColor":"is steen [COLOR]?","boost.setLightHue":"zet lichtkleur op [HUE]","boost.setMotorDirection":"zet motor [MOTOR_ID] richting op [MOTOR_DIRECTION]","boost.setMotorPower":"zet motor [MOTOR_ID] snelheid op [POWER]%","boost.tiltDirection.any":"willekeurig","boost.tiltDirection.down":"omlaag","boost.tiltDirection.left":"links","boost.tiltDirection.right":"rechts","boost.tiltDirection.up":"omhoog","boost.whenColor":"als [COLOR] steen gezien","boost.whenTilted":"als gekanteld naar [TILT_DIRECTION_ANY]","ev3.beepNote":"speel noot [NOTE][TIME]seconde","ev3.buttonPressed":"knop [PORT]ingedrukt?","ev3.getBrightness":"helderheid","ev3.getDistance":"afstand","ev3.getMotorPosition":"motor [PORT]positie","ev3.motorSetPower":"zet motor [PORT]op [POWER]%","ev3.motorTurnClockwise":"draai motor [PORT][TIME] seconde hierheen","ev3.motorTurnCounterClockwise":"draai motor [PORT][TIME]seconde daarheen","ev3.whenBrightnessLessThan":"als helderheid < [DISTANCE]","ev3.whenButtonPressed":"als knop [PORT]ingedrukt is","ev3.whenDistanceLessThan":"als afstand < [DISTANCE]","gdxfor.getAcceleration":"versnelling [DIRECTION]","gdxfor.getForce":"kracht","gdxfor.getSpin":"draaisnelheid [DIRECTION]","gdxfor.getTilt":"kantelhoek [TILT]","gdxfor.isFreeFalling":"vallend?","gdxfor.isTilted":"gekanteld [TILT]","gdxfor.pulled":"getrokken","gdxfor.pushed":"gedrukt","gdxfor.shaken":"geschud","gdxfor.startedFalling":"begonnen te vallen","gdxfor.tiltDirectionMenu.any":"willekeurig","gdxfor.tiltDirectionMenu.back":"achter","gdxfor.tiltDirectionMenu.front":"voor","gdxfor.tiltDirectionMenu.left":"links","gdxfor.tiltDirectionMenu.right":"rechts","gdxfor.turnedFaceDown":"gericht naar beneden","gdxfor.turnedFaceUp":"gericht naar boven","gdxfor.whenForcePushedOrPulled":"wanneer krachtsensor [PUSH_PULL]","gdxfor.whenGesture":"wanneer [GESTURE]","gdxfor.whenTilted":"als [TILT]gekanteld","makeymakey.downArrow":"pijltje omlaag","makeymakey.downArrowShort":"omlaag","makeymakey.leftArrow":"pijltje links","makeymakey.leftArrowShort":"links","makeymakey.rightArrow":"pijltje rechts","makeymakey.rightArrowShort":"rechts","makeymakey.spaceKey":"spatie","makeymakey.upArrow":"pijltje omhoog","makeymakey.upArrowShort":"omhoog","makeymakey.whenKeyPressed":"wanneer [KEY]toets ingedrukt wordt","makeymakey.whenKeysPressedInOrder":"wanneer [SEQUENCE]in deze volgorde wordt ingedrukt","microbit.buttonsMenu.any":"willekeurig","microbit.clearDisplay":"wis het display","microbit.defaultTextToDisplay":"Hallo!","microbit.displaySymbol":"display [MATRIX]","microbit.displayText":"toon tekst [TEXT]","microbit.gesturesMenu.jumped":"gesprongen","microbit.gesturesMenu.moved":"bewogen","microbit.gesturesMenu.shaken":"geschud","microbit.isButtonPressed":"knop [BTN]ingedrukt?","microbit.isTilted":"gekanteld naar[DIRECTION]?","microbit.pinStateMenu.off":"uit","microbit.pinStateMenu.on":"aan","microbit.tiltAngle":"kantelhoek [DIRECTION]","microbit.tiltDirectionMenu.any":"willekeurig","microbit.tiltDirectionMenu.back":"achter","microbit.tiltDirectionMenu.front":"voor","microbit.tiltDirectionMenu.left":"links","microbit.tiltDirectionMenu.right":"rechts","microbit.whenButtonPressed":"als knop [BTN]ingedrukt is","microbit.whenGesture":"als [GESTURE]","microbit.whenPinConnected":"wanneer pin [PIN] is verbonden","microbit.whenTilted":"als gekanteld naar [DIRECTION]","music.categoryName":"Muziek","music.changeTempo":"verander tempo met [TEMPO]","music.drumBass":"(2) Basdrum","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Kabassa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) Gesloten Hihat","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Koebel","music.drumCrashCymbal":"(4) Crashbekken","music.drumCuica":"(18) Cuíca","music.drumGuiro":"(16) Güiro","music.drumHandClap":"(8) Handklap","music.drumOpenHiHat":"(5) Open Hihat","music.drumSideStick":"(3) Side Stick","music.drumSnare":"(1) Snarentrom","music.drumTambourine":"(7) Tamboerijn","music.drumTriangle":"(12) Triangel","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Wood Block","music.getTempo":"tempo","music.instrumentBass":"(6) Bas","music.instrumentBassoon":"(14) Fagot","music.instrumentCello":"(8) Cello","music.instrumentChoir":"(15) Koor","music.instrumentClarinet":"(10) Klarinet","music.instrumentElectricGuitar":"(5) Elektrische Gitaar","music.instrumentElectricPiano":"(2) Elektrische Piano","music.instrumentFlute":"(12) Fluit","music.instrumentGuitar":"(4) Gitaar","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Speeldoos","music.instrumentOrgan":"(3) Orgel","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxofoon","music.instrumentSteelDrum":"(18) Steeldrum","music.instrumentSynthLead":"(20) Synth Lead","music.instrumentSynthPad":"(21) Synth Pad","music.instrumentTrombone":"(9) Trombone","music.instrumentVibraphone":"(16) Vibrafoon","music.instrumentWoodenFlute":"(13) Blokfluit","music.midiPlayDrumForBeats":"speel drum [DRUM]gedurende[BEATS] maten","music.midiSetInstrument":"maak instrument [INSTRUMENT]","music.playDrumForBeats":"speel drum [DRUM]gedurende[BEATS] maten","music.playNoteForBeats":"speel noot [NOTE] gedurende [BEATS]maten","music.restForBeats":"[BEATS]maten rust","music.setInstrument":"maak instrument [INSTRUMENT]","music.setTempo":"maak tempo [TEMPO]","pen.categoryName":"Pen","pen.changeColorParam":"verander pen [COLOR_PARAM]met [VALUE]","pen.changeHue":"verander penkleur met [HUE]","pen.changeShade":"verander penhelderheid met [SHADE]","pen.changeSize":"verander pendikte met [SIZE]","pen.clear":"wis alles","pen.colorMenu.brightness":"helderheid","pen.colorMenu.color":"kleur","pen.colorMenu.saturation":"verzadiging","pen.colorMenu.transparency":"doorzichtigheid","pen.penDown":"pen neer","pen.penUp":"pen op","pen.setColor":"maak penkleur [COLOR]","pen.setColorParam":"maak pen [COLOR_PARAM] [VALUE]","pen.setHue":"maak penkleur [HUE]","pen.setShade":"maak penhelderheid [SHADE]","pen.setSize":"maak pendikte [SIZE]","pen.stamp":"stempel","text2speech.alto":"alt","text2speech.categoryName":"Tekst naar spraak","text2speech.defaultTextToSpeak":"hallo","text2speech.giant":"reus","text2speech.kitten":"katje","text2speech.setLanguageBlock":"stel de taal in op [LANGUAGE]","text2speech.setVoiceBlock":"zet stem op [VOICE]","text2speech.speakAndWaitBlock":"zeg [WORDS]","text2speech.squeak":"piep","text2speech.tenor":"tenor","translate.categoryName":"Vertaal","translate.defaultTextToTranslate":"hallo","translate.translateBlock":"vertaal [WORDS] naar [LANGUAGE]","translate.viewerLanguage":"taal","videoSensing.categoryName":"Video","videoSensing.direction":"richting","videoSensing.motion":"beweging","videoSensing.off":"uit","videoSensing.on":"aan","videoSensing.onFlipped":"aan gespiegeld","videoSensing.setVideoTransparency":"zet video transparantie op [TRANSPARENCY]","videoSensing.sprite":"sprite","videoSensing.stage":"speelveld","videoSensing.videoOn":"video [ATTRIBUTE]van[SUBJECT]","videoSensing.videoToggle":"zet video [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"wanneer video beweging > [REFERENCE]","wedo2.getDistance":"afstand","wedo2.getTiltAngle":"kantelhoek [TILT_DIRECTION]","wedo2.isTilted":"gekanteld [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"daarheen","wedo2.motorDirection.forward":"hierheen","wedo2.motorDirection.reverse":"omkeren","wedo2.motorId.a":"motor A","wedo2.motorId.all":"alle motoren","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"zet [MOTOR_ID]uit","wedo2.motorOn":"zet [MOTOR_ID]aan","wedo2.motorOnFor":"zet [MOTOR_ID][DURATION]seconde aan","wedo2.playNoteFor":"speel noot [NOTE][DURATION]seconde","wedo2.setLightHue":"zet lichtkleur op [HUE]","wedo2.setMotorDirection":"zet [MOTOR_ID]richting op [MOTOR_DIRECTION]","wedo2.startMotorPower":"zet [MOTOR_ID]kracht op [POWER]","wedo2.tiltDirection.any":"willekeurig","wedo2.tiltDirection.down":"omlaag","wedo2.tiltDirection.left":"links","wedo2.tiltDirection.right":"rechts","wedo2.tiltDirection.up":"omhoog","wedo2.whenDistance":"als afstand [OP][REFERENCE]","wedo2.whenTilted":"als gekanteld naar [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Kleur","paint.paintEditor.saturation":"Verzadiging","paint.paintEditor.brightness":"Helderheid","paint.paintEditor.costume":"Uiterlijk","paint.paintEditor.group":"Groeperen","paint.paintEditor.ungroup":"Groep opheffen","paint.paintEditor.undo":"Ongedaan maken","paint.paintEditor.redo":"Opnieuw","paint.paintEditor.forward":"Naar voren","paint.paintEditor.backward":"Naar achteren","paint.paintEditor.front":"Naar voorgrond","paint.paintEditor.back":"Naar achtergrond","paint.paintEditor.more":"Meer","paint.modeTools.brushSize":"Grootte","paint.modeTools.eraserSize":"Gum-breedte","paint.modeTools.copy":"Kopie maken ","paint.modeTools.paste":"Plakken","paint.modeTools.delete":"Verwijder","paint.modeTools.curved":"Gebogen","paint.modeTools.pointed":"Puntig","paint.modeTools.thickness":"Dikte","paint.modeTools.flipHorizontal":"Links-rechts omdraaien","paint.modeTools.flipVertical":"Boven-onder omdraaien","paint.modeTools.filled":"Gevuld","paint.modeTools.outlined":"Omtrek","paint.paintEditor.bitmap":"Zet om naar bitmap","paint.paintEditor.vector":"Zet om naar vector","paint.paintEditor.fill":"Vulling","paint.paintEditor.stroke":"Omtrek","paint.brushMode.brush":"Kwast","paint.eraserMode.eraser":"Gum","paint.fillMode.fill":"Vulling","paint.lineMode.line":"Lijn","paint.ovalMode.oval":"Cirkel","paint.rectMode.rect":"Rechthoek","paint.reshapeMode.reshape":"Opnieuw vormen","paint.roundedRectMode.roundedRect":"Afgeronde rechthoek","paint.selectMode.select":"Selecteren","paint.textMode.text":"Tekst","paint.colorPicker.swap":"Wissel","tw.alerts.autosaving":"Herstelpunt aan het maken...","tw.alerts.lostPeripheralConnection":"Verbinding verloren met {extensionName}.","tw.alerts.savedToDisk":"Opgeslagen op je computer.","tw.backpack.rename":"Nieuwe naam:","tw.browserModal.desc":"Gebruik een recente versie van Google Chrome, Mozilla Firefox, Microsoft Edge, of Apple Safari","tw.cantUseCloud":"Hoewel je cloudvariabelen kunt maken, zullen ze niet werken behalve als dit project is geüpload naar Scratch of geconverteerd d.m.v. een tool zoals de {packager}.","tw.changeUsername.cannotChangeWhileRunning":"Gebruikersnaam kan niet worden veranderd terwijl het project bezig is.","tw.cloudVariableBadge":"Dit project gebruikt cloudvariabelen. TurboWarp gebruikt een eigen server voor cloudvariabelen, onafhankelijk van Scratch. Wees bewust van imitatie omdat iedereen zijn/haar gebruikersnaam kan veranderen in wat ze maar willen. {learnMore}","tw.code":"Broncode","tw.confirmIncompatibleExtension":"Deze extensie is incompatibel met Scratch. Projecten die het gebruiken kunnen niet worden geüpload naar de Scratch-website. Weet je zeker dat je het in wilt schakelen?","tw.customExtension.description":"Laad aangepaste extensies van URL\'s. Voor ontwikkelaars. Experimenteel.","tw.customExtension.name":"Aangepaste Extensie","tw.featuredProjectsStudio":"Deze studio op Scratch laten zien.","tw.feedbackButton":"TurboWarp-Feedback","tw.footer.disclaimer":"TurboWarp is niet aangesloten bij Scratch, het Scratch-Team, of de Scratch-organisatie.","tw.footer.donate":"Doneren","tw.footer.embed":"Invoeging","tw.footer.fosshost":"Hosting aangeboden door Fosshost","tw.footer.parameters":"URL-Parameters","tw.footer.translate":"Help met TurboWarp Vertalen","tw.gui.crashMessage.description":"Het spijt ons, maar het lijkt erop dat de pagina is gecrasht. Ververs je pagina om het opnieuw te proberen.","tw.guiDefaultTitle":"Speel Scratch-projecten sneller af","tw.home.credit":"Opmerkingen en credits","tw.home.description":"TurboWarp is een Scratch-modificatie die projecten compileert naar JavaScript om ze heel snel te laten werken. Probeer het door hierboven een project-ID of URL in te voeren of hieronder een uitgelicht project te kiezen.","tw.home.instructions":"Instructies","tw.input.tooltip":"Kopieer en plak hier een link naar een Scratch-project!","tw.interpolationEnabled":"Interpolatie","tw.invalidParameters.clones":"\\"clone\\" URL parameter is ongeldig","tw.invalidParameters.fps":"\\"fps\\" URL parameter is ongeldig","tw.loadError":"Kon project niet laden: {error}","tw.loader.assets.known":"Onderdelen aan het downloaden ({complete}/{total}) ...","tw.loader.assets.unknown":"Onderdelen aan het downloaden …","tw.loader.data":"Projectgegevens aan het downloaden …","tw.loader.generic":"Project aan het laden ...","tw.menuBar.60off":"60 FPS-Modus Uitzetten","tw.menuBar.60on":"60 FPS-Modus Aanzetten","tw.menuBar.advanced":"Geavanceerd","tw.menuBar.changeUsername":"Gebruikersnaam Veranderen","tw.menuBar.cloudOff":"Cloudvariabelen Uitschakelen","tw.menuBar.cloudOn":"Cloudvariabelen Inschakelen","tw.menuBar.cloudUnavailable":"Cloudvariabelen zijn niet Beschikbaar","tw.menuBar.cloudUnavailableAlert":"Kan geen cloudvariabelen gebruiken, waarschijnlijk omdat je de editor hebt geopend.","tw.menuBar.loadRestorePoint":"Herstelpunt laden","tw.menuBar.moreSettings":"Geavanceerde Instellingen","tw.menuBar.newFramerate":"Nieuwe framerate:","tw.menuBar.package":"Project packagen","tw.menuBar.reportError1":"Sommige scripts konden niet worden gecompileerd.","tw.menuBar.reportError2":"Dit is een bug. Rapporteer het alsjeblieft.","tw.menuBar.saveAs":"Opslaan als {file}","tw.menuBar.seeInside":"Bekijk van binnen","tw.oldDownload":"Opslaan naar apart bestand...","tw.openAdvanced":"Geavanceerde instellingen openen","tw.paint.alpha":"Doorzichtigheid","tw.privacy":"Privacybeleid","tw.restorePoint.confirm":"De editor slaat automatisch één herstelpunt op voor het geval dat er iets misgaat en je vergeet op te slaan. Je moet hier niet altijd op vertrouwen en we kunnen niet garanderen dat het je project herstelt. Wil je proberen om het te laden?","tw.restorePoint.loadFail":"Kon herstelpunt niet laden: {error}","tw.saveAs":"Opslaan als...","tw.saveTo":"Opslaan in {file}","tw.scratchUnsafeCloud":"Als je deze cloudvariabele maakt, zal het project het limiet van {number} variabelen overschrijden, en sommige variabelen zullen niet goed werken als je het project uploadt naar Scratch.","tw.settingsModal.customStageSize":"Aangepaste Speelveldgrootte:","tw.settingsModal.customStageSizeHelp":"Verandert de grootte van het Scratch-speelveld van 480x360 naar iets anders. Probeer 640x360 voor een breed beeld. Dit werkt goed met maar heel weinig projecten.","tw.settingsModal.dangerZone":"Gevarenzone","tw.settingsModal.disableCompiler":"Compiler Uitschakelen","tw.settingsModal.disableCompilerHelp":"Schakelt de TurboWarp-compiler uit. Je zou dit aan willen zetten tijdens het bewerken van projecten zodat scripts gelijk updaten. Anders zou je dit nooit aan moeten zetten.","tw.settingsModal.featured":"Uitgelicht","tw.settingsModal.fps":"60 FPS (Aangepaste FPS)","tw.settingsModal.fpsHelp":"Voert scripts 60 keer per seconde uit in plaats van 30. De meeste projecten zullen niet goed werken met deze instelling. Probeer Interpolatie zonder 60 FPS als dit het geval is. {customFramerate}.","tw.settingsModal.fpsHelp.customFramerate":"Klik voor een andere framerate dan 30 of 60","tw.settingsModal.help":"Klik voor hulp","tw.settingsModal.highQualityPen":"Hoge Kwaliteit-Pen","tw.settingsModal.highQualityPenHelp":"Tekent projecten met de pen in hogere resoluties en verbetert de pen in de editor. Niet alle projecten hebben voordeel van deze instelling en het kan prestaties verslechteren.","tw.settingsModal.infiniteClones":"Oneindig Veel Klonen","tw.settingsModal.infiniteClonesHelp":"Schakelt het 300-klonenlimiet van Scratch uit.","tw.settingsModal.interpolation":"Interpolatie","tw.settingsModal.interpolationHelp":"Laat projecten er gladder uitzien door spritebewegingen te interpoleren. Interpolatie zou niet moeten worden gebruikt in 3D-projecten, raytracers, penprojecten, en trage projecten, omdat interpolatie ze juist trager maakt.","tw.settingsModal.largeStageWarning":"Het gebruiken van een speelveld van deze grootte is niet aangeraden! Gebruik in plaats daarvan een kleinere grootte met dezelfde beeldverhouding en laat het volledig scherm-modus het vergroten om het op de weergave van de gebruiker af te stemmen.","tw.settingsModal.removeFencing":"Waardelimieten Weghalen","tw.settingsModal.removeFencingHelp":"Geeft sprites de mogelijkheid om van het scherm af bewegen, zo groot of klein te worden als ze maar willen, en laat blokken voor aanrakingen zelfs buiten het scherm werken.","tw.settingsModal.removeLimits":"Limieten Weghalen","tw.settingsModal.removeMiscLimits":"Diverse Limieten Weghalen","tw.settingsModal.removeMiscLimitsHelp":"Haalt geluidseffectlimieten en pengroottelimieten weg.","tw.settingsModal.storeProjectOptions":"Instellingen opslaan in project","tw.settingsModal.storeProjectOptionsHelp":"Slaat de geselecteerde instellingen op in het project zodat ze automatisch zullen worden toegepast wanneer TurboWarp dit project laadt. Warp-stopwatch en compiler uitschakelen worden niet opgeslagen.","tw.settingsModal.title":"Geavanceerde Instellingen","tw.settingsModal.warpTimer":"Warp-Stopwatch","tw.settingsModal.warpTimerHelp":"Controleert of scripts vastzitten in een lange of oneindige lus en voor een lage framerate zorgen in plaats van vastzitten tot de lus eindigt. Dit lost de meeste crashes op maar heeft een grote invloed op prestaties, dus het is alleen standaard ingeschakeld in de editor.","tw.spriteSelectorItem.rename":"hernoemen","tw.stereoAlert":"Het bewerken van dit stereogeluid zal het onomkeerbaar veranderen naar mono.","tw.studioview.authorAttribution":"door {author}","tw.studioview.error":"Er is een fout opgetreden tijdens het laden van de volgende pagina van projecten.","tw.studioview.hoverText":"{title} door {author}","tw.tooLarge":"Dit geluidsbestand is mogelijk te groot om te uploaden naar Scratch.","tw.twExtension.description":"Rare nieuwe blokken. Niet compatibel met Scratch.","tw.twExtension.name":"TurboWarp-Blokken","tw.unshared.1":"Niet-gedeelde projecten worden ooit niet meer toegankelijk door alleen hun project-ID\'s te gebruiken wegens aanstaande veranderingen in de API van Scratch.","tw.unshared.2":"Voor meer informatie, bezoek: {link}","tw.unshared.cache":"Als dit project recentelijk is gedeeld, kan het zijn dat dit bericht een paar minuten lang verkeerd wordt weergegeven.","tw.usernameModal.help":"Deze waarde wordt opgeslagen in de opslag van je browser. Het kan worden gelogd wanneer je iets doet met projecten met cloudvariabelen.","tw.usernameModal.help2":"Waarden die niet corresponderen met een geldig Scratch-account worden normaal geweigerd door de cloudvariabelenserver. We raden je aan het zo te laten of het te veranderen naar je Scratch-gebruikersnaam.","tw.usernameModal.mustChange":"Het spijt ons, maar de cloudvariabelenserver vermoedt dat je gebruikersnaam onveilig is. Verander het alsjeblieft naar iets anders of {resetIt}.","tw.usernameModal.mustChange.resetIt":"reset het (aanbevolen)","tw.usernameModal.reset":"Resetten","tw.usernameModal.title":"Gebruikersnaam Veranderen","tw.viewFeaturedProjects":"Klik om uitgelichte projecten te zien.","tw.viewOnScratch":"Dit project op Scratch laten zien","tw.webglModal.description":"Het ziet er helaas uit dat je browser of computer {webGlLink}. Deze technologie is vereist voor deze site om goed te werken. Probeer je browser en grafische stuurprogramma\'s te updaten of start je computer opnieuw op."},"ja":{"gui.alerts.tryAgain":"もう一度試す ","gui.alerts.download":"ダウンロード","gui.connection.reconnect":"再接続","gui.backpack.costumeLabel":"コスチューム","gui.backpack.soundLabel":"音","gui.backpack.scriptLabel":"スクリプト","gui.backpack.spriteLabel":"スプライト","gui.backpack.header":"バックパック","gui.backpack.errorBackpack":"バックパックの読み込み時にエラーが発生しました","gui.backpack.loadingBackpack":"読み込み中...","gui.backpack.more":"もっと","gui.backpack.emptyBackpack":"バックパックは空です","gui.unsupportedBrowser.label":" ブラウザーはサポートされていません","gui.cards.all-tutorials":"チュートリアル","gui.cards.shrink":"縮小","gui.cards.expand":"拡大","gui.cards.close":"閉じる","gui.cards.more-things-to-try":"これも試してみよう!","gui.cards.see-more":"もっと見る","gui.comingSoon.message1":"ご安心下さい。開発中です {emoji}","gui.comingSoon.message2":"近日公開","gui.comingSoon.message3":"開発中です {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"デバイスが見つかりませんでした","gui.connection.auto-scanning.prescan":"デバイスを近くに置いて、検索を開始する","gui.connection.auto-scanning.pressbutton":"デバイスのボタンを押す","gui.connection.auto-scanning.start-search":"検索を開始","gui.connection.connecting-searchbutton":"検索中...","gui.connection.auto-scanning.try-again":"もう一度試す","gui.connection.connected":"接続されました","gui.connection.disconnect":"切断する","gui.connection.go-to-editor":"エディターへ行く","gui.connection.connecting-cancelbutton":"接続中です...","gui.connection.error.errorMessage":"うわっ! 何か問題が発生したようです。","gui.connection.error.tryagainbutton":"もう一度試す","gui.connection.error.helpbutton":"ヘルプ","gui.connection.peripheral-name-label":"デバイス名","gui.connection.connect":"接続する","gui.connection.scanning.lookingforperipherals":"デバイスを探索中","gui.connection.scanning.noPeripheralsFound":"デバイスが見つかりませんでした","gui.connection.scanning.instructions":"上のリストからデバイスを選んでください。","gui.connection.search":"更新","gui.connection.unavailable.installscratchlink":"Scratch Linkがインストールされ、実行中であることを確認してください","gui.connection.unavailable.enablebluetooth":"Bluetoothが有効になっていることを確認してください","gui.connection.unavailable.tryagainbutton":"もう一度試す","gui.connection.unavailable.helpbutton":"ヘルプ","gui.controls.go":"実行","gui.controls.stop":"止める","gui.crashMessage.label":"うわっ! 何か問題が発生しました。","gui.crashMessage.errorNumber":"エラーはID {errorId}として記録されました。","gui.crashMessage.reload":"再読み込み","gui.customProcedures.myblockModalTitle":"ブロックを作る","gui.customProcedures.addAnInputNumberText":"引数を追加","gui.customProcedures.numberTextType":"数値またはテキスト","gui.customProcedures.addAnInputBoolean":"引数を追加","gui.customProcedures.booleanType":"真偽値","gui.customProcedures.addALabel":"ラベルのテキストを追加","gui.customProcedures.runWithoutScreenRefresh":"画面を再描画せずに実行する","gui.customProcedures.cancel":"キャンセル","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"向き","gui.directionPicker.rotationStyles.allAround":"自由に回転","gui.directionPicker.rotationStyles.leftRight":"左右のみ","gui.directionPicker.rotationStyles.dontRotate":"回転しない","gui.gui.addExtension":"拡張機能を追加","gui.gui.codeTab":"コード","gui.gui.backdropsTab":"背景","gui.gui.costumesTab":"コスチューム","gui.gui.soundsTab":"音","gui.extensionLibrary.comingSoon":"近日公開","gui.extensionLibrary.requires":"必要なもの","gui.extensionLibrary.collaboration":"協力","gui.library.filterPlaceholder":"検索","gui.library.allTag":"すべて","gui.loader.headline":"プロジェクトを読み込み中…","gui.loader.creating":"プロジェクトを作る","gui.authorInfo.byUser":"{username}作","gui.menuBar.seeProjectPage":"プロジェクトページを見る","gui.menuBar.LanguageSelector":"言語の選択","gui.menuBar.tutorialsLibrary":"チュートリアル","gui.menuBar.restoreSprite":"削除の取り消し(スプライト)","gui.menuBar.restoreSound":"削除の取り消し(音)","gui.menuBar.restoreCostume":"削除の取り消し(コスチューム)","gui.menuBar.restore":"削除の取り消し","gui.menuBar.saveNow":"直ちに保存","gui.menuBar.saveAsCopy":"コピーを保存","gui.menuBar.remix":"リミックス","gui.menuBar.new":"新規","gui.menuBar.file":"ファイル","gui.menuBar.downloadToComputer":"コンピューターに保存する","gui.menuBar.edit":"編集","gui.menuBar.turboModeOff":"ターボモードを解除する","gui.menuBar.turboModeOn":"ターボモードにする","gui.gui.projectTitlePlaceholder":"プロジェクトのタイトルを入力","gui.menuBar.isShared":"共有されたもの","gui.menuBar.share":"共有する","gui.modal.help":"ヘルプ","gui.modal.back":"戻る","gui.monitor.listMonitor.empty":"(空)","gui.monitor.listMonitor.listLength":"長さ {length}","gui.monitor.contextMenu.default":"普通の表示","gui.monitor.contextMenu.large":"大きな表示","gui.monitor.contextMenu.slider":"スライダー","gui.monitor.contextMenu.sliderRange":"スライダーの指定範囲を変更","gui.monitor.contextMenu.import":"読み込み","gui.monitor.contextMenu.export":"書き出し","gui.monitor.contextMenu.hide":"隠す","gui.playButton.play":"再生","gui.playButton.stop":"止める","gui.gui.variableScopeOptionAllSprites":"すべてのスプライト用","gui.gui.variableScopeOptionSpriteOnly":"このスプライトのみ","gui.gui.cloudVariableOption":"クラウド変数 (サーバーに保存)","gui.gui.variablePromptAllSpritesMessage":"この変数はすべてのスプライトで利用できます。","gui.gui.listPromptAllSpritesMessage":"このリストはすべてのスプライトで利用できます。","gui.prompt.cancel":"キャンセル","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"停止","gui.playbackStep.playMsg":"再生","gui.playbackStep.loadingMsg":"読み込み中...","gui.playbackStep.saveMsg":"保存","gui.playbackStep.reRecordMsg":"再録音","gui.recordModal.title":"録音","gui.recordingStep.beginRecord":"下のボタンを押して録音する","gui.recordingStep.permission":"{arrow}マイクの使用許可が必要です。","gui.recordingStep.stop":"録音をやめる","gui.recordingStep.record":"録音する","gui.sliderModal.min":"最小値","gui.sliderModal.max":"最大値","gui.sliderModal.title":"スライダーの指定範囲を変更","gui.sliderPrompt.cancel":"キャンセル","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"音","gui.soundEditor.play":"再生","gui.soundEditor.stop":"止める","gui.soundEditor.copy":"コピー","gui.soundEditor.paste":"貼り付け","gui.soundEditor.copyToNew":"音をコピー","gui.soundEditor.delete":"削除","gui.soundEditor.save":"保存","gui.soundEditor.undo":"元に戻す","gui.soundEditor.redo":"やり直す","gui.soundEditor.faster":"速く","gui.soundEditor.slower":"遅く","gui.soundEditor.echo":"エコー","gui.soundEditor.robot":"ロボット","gui.soundEditor.louder":"大きく","gui.soundEditor.softer":"小さく","gui.soundEditor.reverse":"逆向き","gui.soundEditor.fadeOut":"フェードアウト","gui.soundEditor.fadeIn":"フェードイン","gui.soundEditor.mute":"ミュート","gui.SpriteInfo.spritePlaceholder":"名前","gui.SpriteInfo.sprite":"スプライト","gui.SpriteInfo.show":"表示する","gui.SpriteInfo.size":"大きさ","gui.spriteSelectorItem.contextMenuDuplicate":"複製","gui.spriteSelectorItem.contextMenuExport":"書き出し","gui.spriteSelectorItem.contextMenuDelete":"削除","gui.spriteSelector.addSpriteFromLibrary":"スプライトを選ぶ","gui.spriteSelector.addSpriteFromPaint":"描く","gui.spriteSelector.addSpriteFromSurprise":"サプライズ","gui.spriteSelector.addSpriteFromFile":"スプライトをアップロード","gui.stageHeader.stageSizeLarge":"大きなステージに切り替え","gui.stageHeader.stageSizeSmall":"小さいステージに切り替える","gui.stageHeader.stageSizeFull":"全画面表示にする","gui.stageHeader.stageSizeUnFull":"全画面表示をやめる","gui.stageHeader.fullscreenControl":"全画面表示","gui.spriteSelector.addBackdropFromLibrary":"背景を選ぶ","gui.stageSelector.addBackdropFromPaint":"描く","gui.stageSelector.addBackdropFromSurprise":"サプライズ","gui.stageSelector.addBackdropFromFile":"背景をアップロード","gui.stageSelector.stage":"ステージ","gui.stageSelector.backdrops":"背景","gui.telemetryOptIn.label":"Scratchを改善するため統計情報を送信する","gui.telemetryOptIn.body1":"Scratchチームは、世界中でScratchがどのように使われているかを、いつもよく理解しようとしています。 この作業をサポートするために、Scratchの利用情報をScratchチームに自動的に送信できます。","gui.telemetryOptIn.body2":"集める情報には言語設定、ブロックの使用状況、保存や読み込み、アップロードなどのいくらかの行動が含まれます。私たちは個人情報を収集しません。詳しくは{privacyPolicyLink}をご覧ください。","gui.telemetryOptIn.privacyPolicyLink":"プライバシー・ポリシー","gui.telemetryOptIn.optInText":"Scratchチームと使用状況を共有する","gui.telemetryOptIn.optInTooltip":"統計データの収集を開始する","gui.telemetryOptIn.optOutText":"Scratchチームと使用状況を共有しない","gui.telemetryOptIn.optOutTooltip":"統計データの収集をやめる","gui.telemetryOptIn.settingWasUpdated":"設定が更新されました。","gui.telemetryOptIn.buttonClose":"閉じる","gui.turboMode.active":"ターボモード","gui.webglModal.label":"ブラウザーはWebGLをサポートしていないようです","gui.webglModal.webgllink":"WebGLをサポートしていない","gui.costumeLibrary.chooseABackdrop":"背景を選ぶ","gui.costumeLibrary.chooseACostume":"コスチュームを選ぶ","gui.costumeTab.addBackdropFromLibrary":"背景を選ぶ","gui.costumeTab.addCostumeFromLibrary":"コスチュームを選ぶ","gui.costumeTab.addBlankCostume":" 描く","gui.costumeTab.addSurpriseCostume":"サプライズ","gui.costumeTab.addFileBackdrop":"背景をアップロード","gui.costumeTab.addFileCostume":"コスチュームをアップロード","gui.extensionLibrary.chooseAnExtension":"拡張機能を選ぶ","gui.extensionLibrary.extensionUrl":"拡張機能のURLを入力","gui.monitors.importListColumnPrompt":"どの欄を使いますか? (1-{numberOfColumns})","gui.recordingStep.alertMsg":"録音を開始できません","gui.soundLibrary.chooseASound":"音を選ぶ","gui.soundTab.fileUploadSound":"音をアップロードする","gui.soundTab.surpriseSound":"サプライズ","gui.soundTab.recordSound":"録音する","gui.soundTab.addSoundFromLibrary":" 音を選ぶ","gui.spriteLibrary.chooseASprite":"スプライトを選ぶ","gui.tipsLibrary.tutorials":"チュートリアルを選ぶ","gui.alerts.createsuccess":"新しいプロジェクトが作成されました。","gui.alerts.createcopysuccess":"プロジェクトのコピーが保存されました。","gui.alerts.createremixsuccess":"プロジェクトのリミックスが保存されました。","gui.alerts.creating":"プロジェクトを作成中...","gui.alerts.creatingCopy":"プロジェクトをコピー中...","gui.alerts.creatingRemix":"プロジェクトをリミックス中...","gui.alerts.creatingError":"プロジェクトが作成できませんでした。もう一度お願いします。","gui.alerts.savingError":"プロジェクトは保存できませんでした。","gui.alerts.savesuccess":"プロジェクトが保存されました。","gui.alerts.saving":"プロジェクトを保存中...","gui.alerts.cloudInfo":"クラウド変数は数字のみサポートしています。文字や記号は入れられません。{learnMoreLink}","gui.alerts.cloudInfoLearnMore":"もっと詳しく。","gui.alerts.importing":"読み込み中...","gui.defaultProject.variable":"変数","gui.extension.music.name":"音楽","gui.extension.music.description":"楽器やドラムを演奏する。","gui.extension.pen.name":"ペン","gui.extension.pen.description":"スプライトで絵を描く。","gui.extension.videosensing.name":"ビデオモーションセンサー","gui.extension.videosensing.description":"カメラで動きを検知する。","gui.extension.text2speech.name":"音声合成","gui.extension.text2speech.description":"言葉をしゃべるプロジェクトを作ろう。","gui.extension.translate.name":"翻訳","gui.extension.translate.description":"色々な言語にテキストを翻訳する。","gui.extension.makeymakey.description":"なんでもキーボードにしてみる。","gui.extension.microbit.description":"プロジェクトを現実の世界と接続する。","gui.extension.microbit.connectingMessage":"接続中","gui.extension.ev3.description":"対話型ロボットなどを作る。","gui.extension.ev3.connectingMessage":"接続中です。EV3のPINが1234に設定されていることを確認してください。","gui.extension.boost.description":"ロボット作品に命を吹き込もう。","gui.extension.boost.connectingMessage":"接続中","gui.extension.wedo2.description":"モーターとセンサーを使って作る。","gui.extension.wedo2.connectingMessage":"接続中","gui.extension.gdxfor.description":"押す力、引く力、動き、回転を検出する。","gui.extension.gdxfor.connectingMessage":"接続中","gui.libraryTags.all":"すべて","gui.libraryTags.animals":"動物","gui.libraryTags.dance":"ダンス","gui.libraryTags.effects":"効果","gui.libraryTags.fantasy":"ファンタジー","gui.libraryTags.fashion":"ファッション","gui.libraryTags.food":"食べ物","gui.libraryTags.indoors":"屋内","gui.libraryTags.loops":"ループ","gui.libraryTags.music":"音楽","gui.libraryTags.notes":"音符","gui.libraryTags.outdoors":"屋外","gui.libraryTags.patterns":"模様","gui.libraryTags.people":"人","gui.libraryTags.percussion":"打楽器","gui.libraryTags.space":"宇宙","gui.libraryTags.sports":"スポーツ","gui.libraryTags.underwater":"海中","gui.libraryTags.voice":"声","gui.libraryTags.wacky":"奇妙な音","gui.libraryTags.animation":"アニメーション","gui.libraryTags.art":"アート","gui.libraryTags.games":"ゲーム","gui.libraryTags.stories":"物語","gui.libraryTags.letters":"文字","gui.opcodeLabels.direction":"向き","gui.opcodeLabels.xposition":"x座標","gui.opcodeLabels.yposition":"y座標","gui.opcodeLabels.size":"大きさ","gui.opcodeLabels.costumename":"コスチューム名","gui.opcodeLabels.costumenumber":"コスチュームの番号","gui.opcodeLabels.backdropname":"背景の名前","gui.opcodeLabels.backdropnumber":"背景の番号","gui.opcodeLabels.volume":"音量","gui.opcodeLabels.tempo":"テンポ","gui.opcodeLabels.answer":"答え","gui.opcodeLabels.loudness":"音量","gui.opcodeLabels.username":"ユーザー名","gui.opcodeLabels.year":"年","gui.opcodeLabels.month":"月","gui.opcodeLabels.date":"日","gui.opcodeLabels.dayofweek":"曜日","gui.opcodeLabels.hour":"時","gui.opcodeLabels.minute":"分","gui.opcodeLabels.second":"秒","gui.opcodeLabels.timer":"タイマー","gui.sharedMessages.backdrop":"背景{index}","gui.sharedMessages.costume":"コスチューム{index}","gui.sharedMessages.sprite":"スプライト{index}","gui.sharedMessages.pop":"ポップ","gui.sharedMessages.replaceProjectWarning":"現在のプロジェクトの内容を置き換えますか?","gui.sharedMessages.loadFromComputerTitle":"コンピューターから読み込む","boost.color.any":"どれかの色","boost.color.black":"黒","boost.color.blue":"青","boost.color.green":"緑","boost.color.red":"赤","boost.color.white":"白","boost.color.yellow":"黄色","boost.getMotorPosition":"モーター[MOTOR_REPORTER_ID]の位置 ","boost.getTiltAngle":"[TILT_DIRECTION]方向の傾き","boost.motorDirection.backward":"あちら向き","boost.motorDirection.forward":"こちら向き","boost.motorDirection.reverse":"逆向き","boost.motorOff":"モーター[MOTOR_ID]をオフにする","boost.motorOn":"モーター[MOTOR_ID]をオンにする","boost.motorOnFor":"モーター[MOTOR_ID]を[DURATION]秒間オンにする","boost.motorOnForRotation":"モーター[MOTOR_ID]を[ROTATION]回転させる","boost.seeingColor":"[COLOR] を見ている?","boost.setLightHue":"ライトの色を[HUE]にする","boost.setMotorDirection":"モーター[MOTOR_ID]の向きを[MOTOR_DIRECTION]にする","boost.setMotorPower":"モーター[MOTOR_ID]の速さを[POWER]%にする ","boost.tiltDirection.any":"どれかの向き","boost.tiltDirection.down":"下","boost.tiltDirection.left":"左","boost.tiltDirection.right":"右","boost.tiltDirection.up":"上","boost.whenColor":"[COLOR] を見たとき","boost.whenTilted":"[TILT_DIRECTION_ANY]に傾いたとき","ev3.beepNote":"[NOTE]の音符を[TIME]秒鳴らす","ev3.buttonPressed":"ボタン[PORT]が押された","ev3.getBrightness":"明るさ","ev3.getDistance":"距離","ev3.getMotorPosition":"モーター[PORT]の位置","ev3.motorSetPower":"モーター[PORT]のパワーを[POWER]%にする","ev3.motorTurnClockwise":"モーター[PORT]をこちら向きに[TIME]秒間回す","ev3.motorTurnCounterClockwise":"モーター[PORT]をあちら向きに[TIME]秒間回す","ev3.whenBrightnessLessThan":"明るさ < [DISTANCE]のとき","ev3.whenButtonPressed":"ボタン[PORT]が押されたとき","ev3.whenDistanceLessThan":"距離 < [DISTANCE]のとき","gdxfor.getAcceleration":"[DIRECTION]方向への加速度","gdxfor.getForce":"force","gdxfor.getSpin":"[DIRECTION]回転のはやさ","gdxfor.getTilt":"[TILT]方向の傾き","gdxfor.isFreeFalling":"落下中","gdxfor.isTilted":"[TILT]に傾いた","gdxfor.pulled":"引かれた","gdxfor.pushed":"押された","gdxfor.shaken":"振られた","gdxfor.startedFalling":"落下を始めた","gdxfor.tiltDirectionMenu.any":"どれかの向き","gdxfor.tiltDirectionMenu.back":"後ろ","gdxfor.tiltDirectionMenu.front":"前","gdxfor.tiltDirectionMenu.left":"左","gdxfor.tiltDirectionMenu.right":"右","gdxfor.turnedFaceDown":"表面が下","gdxfor.turnedFaceUp":"表面が上","gdxfor.whenForcePushedOrPulled":"force sensorが[PUSH_PULL]とき","gdxfor.whenGesture":"[GESTURE]とき","gdxfor.whenTilted":"[TILT]に傾いたとき","makeymakey.downArrow":"下向き矢印","makeymakey.downArrowShort":"下","makeymakey.leftArrow":"左向き矢印","makeymakey.leftArrowShort":"左","makeymakey.rightArrow":"右向き矢印","makeymakey.rightArrowShort":"右","makeymakey.spaceKey":"スペース","makeymakey.upArrow":"上向き矢印","makeymakey.upArrowShort":"上","makeymakey.whenKeyPressed":"[KEY]キーが押されたとき","makeymakey.whenKeysPressedInOrder":"[SEQUENCE]が順番に押されたとき","microbit.buttonsMenu.any":"どれかの","microbit.clearDisplay":"画面を消す","microbit.defaultTextToDisplay":"Hello!","microbit.displaySymbol":"[MATRIX]を表示する","microbit.displayText":"[TEXT]を表示する","microbit.gesturesMenu.jumped":"ジャンプした","microbit.gesturesMenu.moved":"動いた","microbit.gesturesMenu.shaken":"振られた","microbit.isButtonPressed":"ボタン[BTN]が押された","microbit.isTilted":"[DIRECTION]に傾いた","microbit.pinStateMenu.off":"切","microbit.pinStateMenu.on":"入","microbit.tiltAngle":"[DIRECTION]方向の傾き","microbit.tiltDirectionMenu.any":"どれかの向き","microbit.tiltDirectionMenu.back":"後ろ","microbit.tiltDirectionMenu.front":"前","microbit.tiltDirectionMenu.left":"左","microbit.tiltDirectionMenu.right":"右","microbit.whenButtonPressed":"ボタン[BTN]が押されたとき","microbit.whenGesture":"[GESTURE]とき","microbit.whenPinConnected":"ピン[PIN]がつながったとき","microbit.whenTilted":"[DIRECTION]に傾いたとき","music.categoryName":"音楽","music.changeTempo":"テンポを[TEMPO]ずつ変える","music.drumBass":"(2) バスドラム","music.drumBongo":"(13) ボンゴ","music.drumCabasa":"(15) カバサ","music.drumClaves":"(9) クラーベ","music.drumClosedHiHat":"(6) クローズハイハット","music.drumConga":"(14) コンガ","music.drumCowbell":"(11) カウベル","music.drumCrashCymbal":"(4) クラッシュシンバル","music.drumCuica":"(18) クイーカ","music.drumGuiro":"(16) ギロ","music.drumHandClap":"(8) 手拍子","music.drumOpenHiHat":"(5) オープンハイハット","music.drumSideStick":"(3) サイドスティック","music.drumSnare":"(1) スネアドラム","music.drumTambourine":"(7) タンバリン","music.drumTriangle":"(12) トライアングル","music.drumVibraslap":"(17) ビブラスラップ","music.drumWoodBlock":"(10) ウッドブロック","music.getTempo":"テンポ","music.instrumentBass":"(6) ベース","music.instrumentBassoon":"(14) バスーン","music.instrumentCello":"(8) チェロ","music.instrumentChoir":"(15) 合唱団","music.instrumentClarinet":"(10) クラリネット","music.instrumentElectricGuitar":"(5) エレキギター","music.instrumentElectricPiano":"(2) 電子ピアノ","music.instrumentFlute":"(12) フルート","music.instrumentGuitar":"(4) ギター","music.instrumentMarimba":"(19) マリンバ","music.instrumentMusicBox":"(17) ミュージックボックス","music.instrumentOrgan":"(3) オルガン","music.instrumentPiano":"(1) ピアノ","music.instrumentPizzicato":"(7) ピチカート","music.instrumentSaxophone":"(11) サクソフォン","music.instrumentSteelDrum":"(18) スチールドラム","music.instrumentSynthLead":"(20) シンセリード","music.instrumentSynthPad":"(21) シンセパッド","music.instrumentTrombone":"(9) トロンボーン","music.instrumentVibraphone":"(16) ビブラフォン","music.instrumentWoodenFlute":"(13) 木管フルート","music.midiPlayDrumForBeats":"[DRUM]のドラムを[BEATS]拍鳴らす","music.midiSetInstrument":"楽器を[INSTRUMENT]にする","music.playDrumForBeats":"[DRUM]のドラムを[BEATS]拍鳴らす","music.playNoteForBeats":"[NOTE]の音符を[BEATS]拍鳴らす","music.restForBeats":"[BEATS]拍休む","music.setInstrument":"楽器を[INSTRUMENT]にする","music.setTempo":"テンポを[TEMPO]にする","pen.categoryName":"ペン","pen.changeColorParam":"ペンの[COLOR_PARAM]を[VALUE]ずつ変える","pen.changeHue":"ペンの色を[HUE]ずつ変える","pen.changeShade":"ペンの濃さを[SHADE]ずつ変える","pen.changeSize":"ペンの太さを[SIZE]ずつ変える","pen.clear":"全部消す","pen.colorMenu.brightness":"明るさ","pen.colorMenu.color":"色","pen.colorMenu.saturation":"鮮やかさ","pen.colorMenu.transparency":"透明度","pen.penDown":"ペンを下ろす","pen.penUp":"ペンを上げる","pen.setColor":"ペンの色を[COLOR]にする","pen.setColorParam":"ペンの[COLOR_PARAM]を[VALUE]にする","pen.setHue":"ペンの色を[HUE]にする","pen.setShade":"ペンの濃さを[SHADE]にする","pen.setSize":"ペンの太さを[SIZE]にする","pen.stamp":"スタンプ","text2speech.alto":"アルト","text2speech.categoryName":"音声合成","text2speech.defaultTextToSpeak":"こんにちは","text2speech.giant":"巨人","text2speech.kitten":"子猫","text2speech.setLanguageBlock":"言語を[LANGUAGE]にする","text2speech.setVoiceBlock":"声を[VOICE]にする","text2speech.speakAndWaitBlock":"[WORDS]としゃべる","text2speech.squeak":"ねずみ","text2speech.tenor":"テノール","translate.categoryName":"翻訳","translate.defaultTextToTranslate":"こんにちは","translate.translateBlock":"[WORDS]を[LANGUAGE]に翻訳する","translate.viewerLanguage":"言語","videoSensing.categoryName":"ビデオモーションセンサー","videoSensing.direction":"向き","videoSensing.motion":"モーション","videoSensing.off":"切","videoSensing.on":"入","videoSensing.onFlipped":"左右反転","videoSensing.setVideoTransparency":"ビデオの透明度を[TRANSPARENCY]にする","videoSensing.sprite":"スプライト","videoSensing.stage":"ステージ","videoSensing.videoOn":"[SUBJECT]のビデオの[ATTRIBUTE]","videoSensing.videoToggle":"ビデオを[VIDEO_STATE]にする","videoSensing.whenMotionGreaterThan":"ビデオモーション > [REFERENCE]のとき","wedo2.getDistance":"距離","wedo2.getTiltAngle":"[TILT_DIRECTION]方向の傾き","wedo2.isTilted":"[TILT_DIRECTION_ANY]に傾いた","wedo2.motorDirection.backward":"あちら向き","wedo2.motorDirection.forward":"こちら向き","wedo2.motorDirection.reverse":"逆向き","wedo2.motorId.a":"モーターA","wedo2.motorId.all":"すべてのモーター","wedo2.motorId.b":"モーターB","wedo2.motorId.default":"モーター","wedo2.motorOff":"[MOTOR_ID]をオフにする","wedo2.motorOn":"[MOTOR_ID]をオンにする","wedo2.motorOnFor":"[MOTOR_ID]を[DURATION]秒間オンにする","wedo2.playNoteFor":"[NOTE]の音符を[DURATION]秒間鳴らす","wedo2.setLightHue":"ライトの色を[HUE]にする","wedo2.setMotorDirection":"[MOTOR_ID]の方向を[MOTOR_DIRECTION]にする","wedo2.startMotorPower":"[MOTOR_ID]のパワーを[POWER]にする","wedo2.tiltDirection.any":"どれかの向き","wedo2.tiltDirection.down":"下","wedo2.tiltDirection.left":"左","wedo2.tiltDirection.right":"右","wedo2.tiltDirection.up":"上","wedo2.whenDistance":"距離[OP][REFERENCE]のとき","wedo2.whenTilted":"[TILT_DIRECTION_ANY]に傾いたとき","paint.paintEditor.hue":"色","paint.paintEditor.saturation":"鮮やかさ","paint.paintEditor.brightness":"明るさ","paint.paintEditor.costume":"コスチューム","paint.paintEditor.group":"グループ化","paint.paintEditor.ungroup":"グループ解除","paint.paintEditor.undo":"取り消し","paint.paintEditor.redo":"やり直し","paint.paintEditor.forward":"手前に出す","paint.paintEditor.backward":"奥に下げる","paint.paintEditor.front":"最前面","paint.paintEditor.back":"最背面","paint.paintEditor.more":"もっと","paint.modeTools.brushSize":"大きさ","paint.modeTools.eraserSize":"消しゴムの大きさ","paint.modeTools.copy":"コピー","paint.modeTools.paste":"貼り付け","paint.modeTools.delete":"削除","paint.modeTools.curved":"滑らか","paint.modeTools.pointed":"角ばった","paint.modeTools.thickness":"太さ","paint.modeTools.flipHorizontal":"左右反転","paint.modeTools.flipVertical":"上下反転","paint.modeTools.filled":"塗りつぶし","paint.modeTools.outlined":"輪郭","paint.paintEditor.bitmap":"ビットマップに変換","paint.paintEditor.vector":"ベクターに変換","paint.paintEditor.fill":"塗りつぶし","paint.paintEditor.stroke":"枠線","paint.brushMode.brush":"筆","paint.eraserMode.eraser":"消しゴム","paint.fillMode.fill":"塗りつぶし","paint.lineMode.line":"直線","paint.ovalMode.oval":"円","paint.rectMode.rect":"四角形","paint.reshapeMode.reshape":"形を変える","paint.roundedRectMode.roundedRect":"角丸の長方形","paint.selectMode.select":"選択","paint.textMode.text":"テキスト","paint.colorPicker.swap":"入れ替え","tw.alerts.autosaving":"復元しています…","tw.alerts.lostPeripheralConnection":"{extensionName}との接続が切れました。","tw.alerts.savedToDisk":"コンピューターに保存する","tw.backpack.rename":"新しい名前:","tw.browserModal.desc":"Google Chrome、Mozilla Firefox、Microsoft Edge、Apple Safari が最新バージョンであることを確認してください。","tw.cantUseCloud":"クラウド変数を作成することはできますが、このプロジェクトをScratchにアップロードするか、{packager}などのツールを使用しないと、動作しません。","tw.changeUsername.cannotChangeWhileRunning":"ユーザー名をプロジェクトの実行中に変えることはできません。","tw.cloudVariableBadge":"このプロジェクトはクラウド変数を使用しています。TurboWarpは独自のサーバーを使用しており、Scratchとは連携しておりません。また、ユーザー名はScratchなどのユーザーと違う可能性があることに注意してください。{learnMore}","tw.code":"ソースコード","tw.confirmIncompatibleExtension":"この拡張機能はScratchとの互換性がありません。これを使って作ったプロジェクトは、Scratchのウェブサイトにアップロードできません。本当に使いますか?","tw.customExtension.description":"URLから拡張機能を読み込みます。開発者向けで、実験段階です。","tw.customExtension.name":"カスタム拡張機能","tw.featuredProjectsStudio":"Scratchのスタジオで見る。","tw.feedback":"フィードバックとバグ","tw.feedbackButton":"TurboWarpへのフィードバック","tw.footer.credits":"クレジット","tw.footer.disclaimer":"TurboWarpはScratch、Scratch Team、Scratch財団と提携していません。","tw.footer.donate":"寄付する","tw.footer.embed":"埋め込みコード","tw.footer.fosshost":"Fosshostが提供するホスティング","tw.footer.parameters":"URLパラメーター","tw.footer.translate":"TurboWarpの翻訳を手伝う","tw.gui.crashMessage.description":"大変申し訳ございませんが、ページがクラッシュしたようです。ページを再読み込みして再度お試しください。","tw.gui.defaultProjectTitle":"プロジェクト","tw.guiDefaultTitle":"Scratchのプロジェクトを速く動かす","tw.home.credit":"メモとクレジット","tw.home.description":"TurboWarpはScratchのMODで、速く動かすためにプロジェクトをJavaScriptにコンパイルしたものです。プロジェクトのIDやURLを入力するか、下のプロジェクトの特集から選んでみてください。","tw.home.instructions":"使い方","tw.input.tooltip":"ScratchのプロジェクトのURLをコピー&ペーストして見ることができます","tw.interpolationEnabled":"補完機能","tw.invalidParameters.clones":"「クローン」のURLパラメーターが無効です","tw.invalidParameters.fps":"「FPS」のURLパラメーターが無効です","tw.loadError":"プロジェクトを読み込めませんでした: {error}","tw.loader.assets.known":"{total}個中{complete}個のダウンロードを完了…","tw.loader.assets.unknown":"ダウンロード中…","tw.loader.data":"プロジェクトのデータをダウンロード中…","tw.loader.generic":"プロジェクトを読み込み中…","tw.menuBar.60off":"60FPSモードを解除する","tw.menuBar.60on":"60FPSモードにする","tw.menuBar.addons":"アドオン","tw.menuBar.advanced":"高度な設定","tw.menuBar.changeUsername":"ユーザー名を変える","tw.menuBar.cloudOff":"クラウド変数を無効にする","tw.menuBar.cloudOn":"クラウド変数を有効にする","tw.menuBar.cloudUnavailable":"クラウド変数は使用できません","tw.menuBar.cloudUnavailableAlert":"中を見たのでクラウド変数を使用できません。","tw.menuBar.loadRestorePoint":"前回のプロジェクトを復元する","tw.menuBar.moreSettings":"高度な設定","tw.menuBar.newFramerate":"新しいフレームレート:","tw.menuBar.package":"プロジェクトをパッケージ化する","tw.menuBar.reportError1":"コンパイルされていないスクリプトがあります。","tw.menuBar.reportError2":"これはバグです。報告してください。","tw.menuBar.saveAs":"{file}として保存する","tw.menuBar.seeInside":"中を見る","tw.oldDownload":"別ファイルで保存する...","tw.paint.alpha":"透明度","tw.privacy":"プライバシーポリシー","tw.restorePoint.confirm":"このエディタは、何か問題が発生し、保存を忘れた場合に備えて、1つ自動復元データを記録します。しかし、これは信頼できるものではありません。また、プロジェクトの復旧を保証するものではありません。読み込みますか?","tw.restorePoint.loadFail":"復元データを読み込めませんでした: {error}","tw.saveAs":"…として保存する","tw.saveTo":"{file}に保存する","tw.scratchUnsafeCloud":"このクラウド変数を作ると、{number}変数のScratchの上限を超えます。Scratchにこのプロジェクトをアップロードしたとき、一部の変数が機能しなくなります。","tw.settingsModal.customStageSize":"ステージの大きさを変える:","tw.settingsModal.customStageSizeHelp":"ステージのサイズを480x360から他のサイズに変更します。ステージをワイドスクリーンにするには、640x360をお試しください。これを適切に処理できるプロジェクトはほとんどありません。","tw.settingsModal.dangerZone":"危険区域","tw.settingsModal.disableCompiler":"コンパイラを無効にする","tw.settingsModal.disableCompilerHelp":"TurboWarpコンパイラを無効にします。プロジェクトの編集中にこれを有効にすると、スクリプトがすぐに更新されるようになります。必要ない場合は無効にしてください。","tw.settingsModal.featured":"おすすめ","tw.settingsModal.fps":"60 FPS (カスタム FPS)","tw.settingsModal.fpsHelp":"通常FPSが30の所、60でスクリプトを動かします。この機能を有効にすると、ほとんどのプロジェクトが正しく動作しません。そのような場合は、この機能を無効にして「補間機能」を試してください。{customFramerate}","tw.settingsModal.fpsHelp.customFramerate":"30または60以外のFPSを設定する","tw.settingsModal.help":"クリックしてヘルプ","tw.settingsModal.highQualityPen":"ペンできれいに描画する","tw.settingsModal.highQualityPenHelp":"ペンのプロジェクトをより高い解像度でレンダリングする代わりに、エディタでのの座標丸めを一部無効にします。全てのプロジェクトでこの設定が有効とはいえず、パフォーマンスに影響を与えることがあります。","tw.settingsModal.infiniteClones":"クローンの制限を解除","tw.settingsModal.infiniteClonesHelp":"Scratchの、クローンが300個までしか作れない制限を解除します。","tw.settingsModal.interpolation":"補完機能","tw.settingsModal.interpolationHelp":"スプライトの動きを補間することで、プロジェクトをより滑らかに見せます。この機能は、3Dのプロジェクト、レイトレーサー、ペンを使ったプロジェクトや、重いプロジェクトには使用しないでください。スムーズではなくなり、動作が遅くなります。","tw.settingsModal.largeStageWarning":"ステージのサイズを大きくすることはおすすめできません。その代わり、同じアスペクト比の小さなサイズを使用し、フルスクリーンにすることでお使いのディスプレイの大きさに合わせてください。","tw.settingsModal.removeFencing":"動く範囲と大きさの制限を解除する","tw.settingsModal.removeFencingHelp":"スプライトを画面の外へ移動させたり、好きなだけ大きさを変えたり、触れたブロックを画面外で作動させたりすることができます。","tw.settingsModal.removeLimits":"制限を解除する","tw.settingsModal.removeMiscLimits":"その他の制限を解除","tw.settingsModal.removeMiscLimitsHelp":"効果音の制限とペンの大きさの制限を解除する","tw.settingsModal.storeProjectOptions":"高度な設定を保存する","tw.settingsModal.storeProjectOptionsHelp":"選択した設定をプロジェクトに保存し、TurboWarpがこのプロジェクトを読み込んだときに自動的に適用されるようにします。Warpタイマーとコンパイラの無効は保存されません。","tw.settingsModal.title":"高度な設定","tw.settingsModal.warpTimer":"Warpタイマー","tw.settingsModal.warpTimerHelp":"スクリプトが長いループや無限ループに陥っているかどうかをチェックし、ループが終了するまで動けないのを避け、低いフレームレートで実行するようにします。これにより、ほとんどのクラッシュが修正されます。しかし、パフォーマンスへの影響が大きいため、デフォルトではエディタでのみ有効になっています。","tw.spriteSelectorItem.rename":"名前を変える","tw.studioview.error":"プロジェクトを次のページで読み込む際にエラーが発生しました。","tw.twExtension.description":"奇妙な新しいブロック。Scratchでは使えません。","tw.twExtension.name":"TurboWarpのブロック","tw.unshared.1":"Scratch API の変更に伴い、非共有プロジェクトは将来的にプロジェクト ID でアクセスできなくなる予定です。","tw.unshared.2":"詳しくはこちらをご覧ください: {link}","tw.usernameModal.help":"この名前は、ブラウザのストレージに保存されます。クラウド変数を含むプロジェクトを見る際に記録されることがあります。","tw.usernameModal.help2":"有効なScratchのアカウント名に対応していないと、通常はクラウド変数サーバに拒否されます。そのままにしておくか、Scratchのユーザー名に変えることをおすすめします。","tw.usernameModal.mustChange":"申し訳ありません、あなたのユーザー名が安全でない可能性があります。他のユーザー名に変更するか、{resetIt}をしてください。","tw.usernameModal.mustChange.resetIt":"リセット(おすすめ)","tw.usernameModal.reset":"リセット","tw.usernameModal.title":"ユーザー名を変える","tw.viewFeaturedProjects":"クリックしてプロジェクトの特集を見る。","tw.viewOnScratch":"Scratchでプロジェクトを見る","tw.webglModal.description":"残念ながら、お使いのブラウザやコンピュータは{webGlLink}のようです。このサイトを実行するには、操作が必要です。お使いのブラウザやグラフィックドライバをアップデートするか、コンピュータを再起動してみてください。"},"ja-Hira":{"gui.alerts.tryAgain":"もういちどためす ","gui.alerts.download":"ダウンロード","gui.connection.reconnect":"さいせつぞく","gui.backpack.costumeLabel":"コスチューム","gui.backpack.soundLabel":"おと","gui.backpack.scriptLabel":"スクリプト","gui.backpack.spriteLabel":"スプライト","gui.backpack.header":"バックパック","gui.backpack.errorBackpack":"バックパックのよみこみじにエラーがはっせいしました","gui.backpack.loadingBackpack":"よみこみちゅう...","gui.backpack.more":"もっと","gui.backpack.emptyBackpack":"バックパックはからです","gui.unsupportedBrowser.label":" ブラウザーはサポートされていません","gui.cards.all-tutorials":"チュートリアル","gui.cards.shrink":"しゅくしょう","gui.cards.expand":"かくだい","gui.cards.close":"とじる","gui.cards.more-things-to-try":"もっとやってみる!","gui.cards.see-more":"もっとみる","gui.comingSoon.message1":"ごあんしんください。かいはつちゅうです {emoji}","gui.comingSoon.message2":"きんじつこうかい","gui.comingSoon.message3":"かいはつちゅうです {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"デバイスがみつかりませんでした","gui.connection.auto-scanning.prescan":"デバイスをちかくにおいて、けんさくをかいしする","gui.connection.auto-scanning.pressbutton":"デバイスのボタンをおす","gui.connection.auto-scanning.start-search":"けんさくをかいし","gui.connection.connecting-searchbutton":"けんさくちゅう...","gui.connection.auto-scanning.try-again":"もういちどくりかえす","gui.connection.connected":"せつぞくされました","gui.connection.disconnect":"せつだんする","gui.connection.go-to-editor":"エディターへいく","gui.connection.connecting-cancelbutton":"せつぞくちゅうです...","gui.connection.error.errorMessage":"うわっ! なにか、もんだいがおきたようです。","gui.connection.error.tryagainbutton":"もういちどくりかえす","gui.connection.error.helpbutton":"ヘルプ","gui.connection.peripheral-name-label":"デバイスめい","gui.connection.connect":"せつぞくする","gui.connection.scanning.lookingforperipherals":"デバイスをさがしています","gui.connection.scanning.noPeripheralsFound":"デバイスがみつかりませんでした","gui.connection.scanning.instructions":"うえのリストからデバイスをえらんでください。","gui.connection.search":"こうしん","gui.connection.unavailable.installscratchlink":"Scratchリンクがインストールされ、うごいていることをかくにんしてください","gui.connection.unavailable.enablebluetooth":"Bluetoothがゆうこうになっていることを、かくにんしてください","gui.connection.unavailable.tryagainbutton":"もういちどくりかえす","gui.connection.unavailable.helpbutton":"ヘルプ","gui.controls.go":"じっこう","gui.controls.stop":"とめる","gui.crashMessage.label":"うわっ! なにかもんだいがはっせいしました。","gui.crashMessage.errorNumber":"エラーはID {errorId}としてきろくされました。","gui.crashMessage.reload":"さいよみこみ","gui.customProcedures.myblockModalTitle":"ブロックをつくる","gui.customProcedures.addAnInputNumberText":"ひきすうをついか","gui.customProcedures.numberTextType":"すうちまたはテキスト","gui.customProcedures.addAnInputBoolean":"ひきすうをついか","gui.customProcedures.booleanType":"しんぎち","gui.customProcedures.addALabel":"ラベルのテキストをついか","gui.customProcedures.runWithoutScreenRefresh":"がめんをさいびょうがせずにじっこうする","gui.customProcedures.cancel":"キャンセル","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"むき","gui.directionPicker.rotationStyles.allAround":"じゆうにかいてん","gui.directionPicker.rotationStyles.leftRight":"さゆうのみ","gui.directionPicker.rotationStyles.dontRotate":"かいてんしない","gui.gui.addExtension":"かくちょうきのうをついか","gui.gui.codeTab":"コード","gui.gui.backdropsTab":"はいけい","gui.gui.costumesTab":"コスチューム","gui.gui.soundsTab":"おと","gui.extensionLibrary.comingSoon":"きんじつこうかい","gui.extensionLibrary.requires":"ひつようなもの","gui.extensionLibrary.collaboration":"きょうりょく","gui.library.filterPlaceholder":"けんさく","gui.library.allTag":"すべて","gui.loader.headline":"プロジェクトをよみこみちゅう…","gui.loader.creating":"プロジェクトをつくる","gui.authorInfo.byUser":"{username}さく","gui.menuBar.seeProjectPage":"プロジェクトページをみる","gui.menuBar.LanguageSelector":"げんごのせんたく","gui.menuBar.tutorialsLibrary":"チュートリアル","gui.menuBar.restoreSprite":"さくじょのとりけし(スプライト)","gui.menuBar.restoreSound":"さくじょのとりけし(おと)","gui.menuBar.restoreCostume":"さくじょのとりけし(コスチューム)","gui.menuBar.restore":"さくじょのとりけし","gui.menuBar.saveNow":"ただちにほぞん","gui.menuBar.saveAsCopy":"コピーをほぞん","gui.menuBar.remix":"リミックス","gui.menuBar.new":"しんき","gui.menuBar.file":"ファイル","gui.menuBar.downloadToComputer":"コンピューターにほぞんする","gui.menuBar.edit":"へんしゅう","gui.menuBar.turboModeOff":"ターボモードをかいじょする","gui.menuBar.turboModeOn":"ターボモードにする","gui.gui.projectTitlePlaceholder":"プロジェクトのタイトルをにゅうりょく","gui.menuBar.isShared":"きょうゆうされたもの","gui.menuBar.share":"きょうゆうする","gui.modal.help":"ヘルプ","gui.modal.back":"もどる","gui.monitor.listMonitor.empty":"(から)","gui.monitor.listMonitor.listLength":"ながさ{length}","gui.monitor.contextMenu.default":"ふつうのひょうじ","gui.monitor.contextMenu.large":"おおきなひょうじ","gui.monitor.contextMenu.slider":"スライダー","gui.monitor.contextMenu.sliderRange":"スライダーのしていはんいをへんこう","gui.monitor.contextMenu.import":"よみこみ","gui.monitor.contextMenu.export":"かきだし","gui.monitor.contextMenu.hide":"かくす","gui.playButton.play":"さいせい","gui.playButton.stop":"とめる","gui.gui.variableScopeOptionAllSprites":"すべてのスプライトよう","gui.gui.variableScopeOptionSpriteOnly":"このスプライトのみ","gui.gui.cloudVariableOption":"クラウドへんすう (サーバーにほぞんされます)","gui.gui.variablePromptAllSpritesMessage":"このへんすうは、すべてのスプライトでつかえます。","gui.gui.listPromptAllSpritesMessage":"このリストはすべてのスプライトでりようできます。","gui.prompt.cancel":"キャンセル","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"ていし","gui.playbackStep.playMsg":"さいせい","gui.playbackStep.loadingMsg":"よみこみちゅう...","gui.playbackStep.saveMsg":"ほぞん","gui.playbackStep.reRecordMsg":"さいろくおん","gui.recordModal.title":"ろくおん","gui.recordingStep.beginRecord":"したのボタンをおしてろくおんする","gui.recordingStep.permission":"{arrow}マイクのしようきょかがひつようです。","gui.recordingStep.stop":"ろくおんをやめる","gui.recordingStep.record":"ろくおんする","gui.sliderModal.min":"さいしょうち","gui.sliderModal.max":"さいだいち","gui.sliderModal.title":"スライダーのしていはんいをへんこう","gui.sliderPrompt.cancel":"キャンセル","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"おと","gui.soundEditor.play":"さいせい","gui.soundEditor.stop":"とめる","gui.soundEditor.copy":"コピー","gui.soundEditor.paste":"はりつけ","gui.soundEditor.copyToNew":"おとをコピー","gui.soundEditor.delete":"さくじょ","gui.soundEditor.save":"ほぞん","gui.soundEditor.undo":"もとにもどす","gui.soundEditor.redo":"やりなおす","gui.soundEditor.faster":"はやく","gui.soundEditor.slower":"おそく","gui.soundEditor.echo":"エコー","gui.soundEditor.robot":"ロボット","gui.soundEditor.louder":"おおきく","gui.soundEditor.softer":"ちいさく","gui.soundEditor.reverse":"ぎゃくむき","gui.soundEditor.fadeOut":"フェードアウト","gui.soundEditor.fadeIn":"フェードイン","gui.soundEditor.mute":"ミュート","gui.SpriteInfo.spritePlaceholder":"なまえ","gui.SpriteInfo.sprite":"スプライト","gui.SpriteInfo.show":"ひょうじする","gui.SpriteInfo.size":"おおきさ","gui.spriteSelectorItem.contextMenuDuplicate":"ふくせい","gui.spriteSelectorItem.contextMenuExport":"かきだし","gui.spriteSelectorItem.contextMenuDelete":"さくじょ","gui.spriteSelector.addSpriteFromLibrary":"スプライトをえらぶ","gui.spriteSelector.addSpriteFromPaint":"えがく","gui.spriteSelector.addSpriteFromSurprise":"サプライズ","gui.spriteSelector.addSpriteFromFile":"スプライトをアップロード","gui.stageHeader.stageSizeLarge":"おおきなステージにきりかえ","gui.stageHeader.stageSizeSmall":"ちいさいステージにきりかえる","gui.stageHeader.stageSizeFull":"ぜんがめんひょうじにする","gui.stageHeader.stageSizeUnFull":"ぜんがめんひょうじをやめる","gui.stageHeader.fullscreenControl":"ぜんがめんひょうじ","gui.spriteSelector.addBackdropFromLibrary":"はいけいをえらぶ","gui.stageSelector.addBackdropFromPaint":"えがく","gui.stageSelector.addBackdropFromSurprise":"サプライズ","gui.stageSelector.addBackdropFromFile":"はいけいをアップロード","gui.stageSelector.stage":"ステージ","gui.stageSelector.backdrops":"はいけい","gui.telemetryOptIn.label":"Scratchをかいぜんするためとうけいじょうほうをそうしんする","gui.telemetryOptIn.body1":"Scratchチームは、せかいじゅうでScratchがどのようにつわれているかを、いつもよくりかいしようとしています。 このさぎょうをサポートするために、Scratchのしようじょうほうをスクラッチチームにじどうてきにそうしんできます。","gui.telemetryOptIn.body2":"あつめるじょうほうには、げんごせってい、ブロックのしようじょうきょう、ほぞんやよみこみ、アップロードなどのいくらかのイベントがふくまれます。わたしたちはこじんじょうほうをしゅうしゅうしません。くわしくは{privacyPolicyLink}をごらんください。","gui.telemetryOptIn.privacyPolicyLink":"プライバシー・ポリシー","gui.telemetryOptIn.optInText":"Scratchチームとしようじょうきょうをきょうゆうする","gui.telemetryOptIn.optInTooltip":"とうけいデータのしゅうしゅうをかいしする","gui.telemetryOptIn.optOutText":"Scratchチームとしようじょうきょうをきょうゆうしない","gui.telemetryOptIn.optOutTooltip":"とうけいデータのしゅうしゅうをやめる","gui.telemetryOptIn.settingWasUpdated":"せっていがこうしんされました。","gui.telemetryOptIn.buttonClose":"とじる","gui.turboMode.active":"ターボモード","gui.webglModal.label":"ブラウザーはWebGLをサポートしていないようです","gui.webglModal.webgllink":"WebGLをサポートしていない","gui.costumeLibrary.chooseABackdrop":"はいけいをえらぶ","gui.costumeLibrary.chooseACostume":"コスチュームをえらぶ","gui.costumeTab.addBackdropFromLibrary":"はいけいをえらぶ","gui.costumeTab.addCostumeFromLibrary":"コスチュームをえらぶ","gui.costumeTab.addBlankCostume":" えがく","gui.costumeTab.addSurpriseCostume":"サプライズ","gui.costumeTab.addFileBackdrop":"はいけいをアップロード","gui.costumeTab.addFileCostume":"コスチュームをアップロード","gui.extensionLibrary.chooseAnExtension":"かくちょうきのうをえらぶ","gui.extensionLibrary.extensionUrl":"かくちょうきのうのURLをにゅうりょく","gui.monitors.importListColumnPrompt":"どのらんをつかいますか? (1-{numberOfColumns})","gui.recordingStep.alertMsg":"ろくおんをかいしできません","gui.soundLibrary.chooseASound":"おとをえらぶ","gui.soundTab.fileUploadSound":"おとをアップロードする","gui.soundTab.surpriseSound":"サプライズ","gui.soundTab.recordSound":"ろくおんする","gui.soundTab.addSoundFromLibrary":" おとをえらぶ","gui.spriteLibrary.chooseASprite":"スプライトをえらぶ","gui.tipsLibrary.tutorials":"チュートリアルをえらぶ","gui.alerts.createsuccess":"あたらしいプロジェクトがさくせいされました。","gui.alerts.createcopysuccess":"プロジェクトのコピーがほぞんされました。","gui.alerts.createremixsuccess":"プロジェクトのリミックスがほぞんされました。","gui.alerts.creating":"プロジェクトをさくせいちゅう...","gui.alerts.creatingCopy":"プロジェクトをコピーちゅう...","gui.alerts.creatingRemix":"プロジェクトをリミックスちゅう...","gui.alerts.creatingError":"プロジェクトがさくせいできませんでした。もういちどおねがいします。","gui.alerts.savingError":"プロジェクトはほぞんできませんでした。","gui.alerts.savesuccess":"プロジェクトがほぞんされました。","gui.alerts.saving":"プロジェクトをほぞんちゅう...","gui.alerts.cloudInfo":"クラウドへんすうはすうじのみサポートしています。もじやきごうはいれられません。{learnMoreLink}","gui.alerts.cloudInfoLearnMore":"もっとくわしく。","gui.alerts.importing":"よみこみちゅう...","gui.defaultProject.variable":"へんすう","gui.extension.music.name":"おんがく","gui.extension.music.description":"がっきやドラムをえんそうする。","gui.extension.pen.name":"ペン","gui.extension.pen.description":"スプライトで、えをかく。","gui.extension.videosensing.name":"ビデオモーションセンサー","gui.extension.videosensing.description":"カメラでうごきをしらべる。","gui.extension.text2speech.name":"おんせいごうせい","gui.extension.text2speech.description":"ことばをしゃべるプロジェクトをつくろう。","gui.extension.translate.name":"ほんやく","gui.extension.translate.description":"いろいろなことばにテキストをほんやくします。","gui.extension.makeymakey.description":"なんでもキーボードにしてみる。","gui.extension.microbit.description":"あなたのプロジェクトを、ほんとうのせかいと、つなぎます。","gui.extension.microbit.connectingMessage":"せつぞくちゅう","gui.extension.ev3.description":"たいわするロボットなどをつくる。","gui.extension.ev3.connectingMessage":"せつぞくちゅうです。EV3のピンが1234にせっていされていることを、かくにんしてください。","gui.extension.boost.description":"ロボットさくひんに、いのちをふきこもう。","gui.extension.boost.connectingMessage":"せつぞくちゅう","gui.extension.wedo2.description":"モーターとセンサーをつかってつくる。","gui.extension.wedo2.connectingMessage":"せつぞくちゅう","gui.extension.gdxfor.description":"おすちから、ひくちから、うごきや、かいてんをけんしゅつする。","gui.extension.gdxfor.connectingMessage":"せつぞくちゅう","gui.libraryTags.all":"すべて","gui.libraryTags.animals":"どうぶつ","gui.libraryTags.dance":"ダンス","gui.libraryTags.effects":"こうか","gui.libraryTags.fantasy":"ファンタジー","gui.libraryTags.fashion":"ファッション","gui.libraryTags.food":"たべもの","gui.libraryTags.indoors":"おくない","gui.libraryTags.loops":"ループ","gui.libraryTags.music":"おんがく","gui.libraryTags.notes":"ノート","gui.libraryTags.outdoors":"おくがい","gui.libraryTags.patterns":"もよう","gui.libraryTags.people":"ひと","gui.libraryTags.percussion":"だがっき","gui.libraryTags.space":"うちゅう","gui.libraryTags.sports":"スポーツ","gui.libraryTags.underwater":"かいちゅう","gui.libraryTags.voice":"こえ","gui.libraryTags.wacky":"きみょうなおと","gui.libraryTags.animation":"アニメーション","gui.libraryTags.art":"アート","gui.libraryTags.games":"ゲーム","gui.libraryTags.stories":"ものがたり","gui.libraryTags.letters":"もじ","gui.opcodeLabels.direction":"むき","gui.opcodeLabels.xposition":"xざひょう","gui.opcodeLabels.yposition":"yざひょう","gui.opcodeLabels.size":"おおきさ","gui.opcodeLabels.costumename":"コスチュームめい","gui.opcodeLabels.costumenumber":"コスチュームのばんごう","gui.opcodeLabels.backdropname":"はいけいのなまえ","gui.opcodeLabels.backdropnumber":"はいけいのばんごう","gui.opcodeLabels.volume":"おんりょう","gui.opcodeLabels.tempo":"テンポ","gui.opcodeLabels.answer":"こたえ","gui.opcodeLabels.loudness":"おんりょう","gui.opcodeLabels.username":"ユーザーめい","gui.opcodeLabels.year":"ねん","gui.opcodeLabels.month":"つき","gui.opcodeLabels.date":"ひ","gui.opcodeLabels.dayofweek":"ようび","gui.opcodeLabels.hour":"じ","gui.opcodeLabels.minute":"ぶん","gui.opcodeLabels.second":"びょう","gui.opcodeLabels.timer":"タイマー","gui.sharedMessages.backdrop":"はいけい{index}","gui.sharedMessages.costume":"コスチューム{index}","gui.sharedMessages.sprite":"スプライト{index}","gui.sharedMessages.pop":"ポップ","gui.sharedMessages.replaceProjectWarning":"げんざいのプロジェクトのないようをおきかえますか?","gui.sharedMessages.loadFromComputerTitle":"コンピューターからよみこむ","boost.color.any":"どれかのいろ","boost.color.black":"くろ","boost.color.blue":"あお","boost.color.green":"みどり","boost.color.red":"あか","boost.color.white":"しろ","boost.color.yellow":"きいろ","boost.getMotorPosition":"モーター[MOTOR_REPORTER_ID]のいち","boost.getTiltAngle":"[TILT_DIRECTION]ほうこうのかたむき","boost.motorDirection.backward":"あちらむき","boost.motorDirection.forward":"こちらむき","boost.motorDirection.reverse":"ぎゃくむき","boost.motorOff":"モーター[MOTOR_ID]をオフにする","boost.motorOn":"モーター[MOTOR_ID]をオンにする","boost.motorOnFor":"モーター[MOTOR_ID]を[DURATION]びょうかんオンにする","boost.motorOnForRotation":"モーター[MOTOR_ID]を[ROTATION]かいてんさせる","boost.seeingColor":"[COLOR] をみている?","boost.setLightHue":"ライトのいろを[HUE]にする","boost.setMotorDirection":"モーター[MOTOR_ID]のむきを[MOTOR_DIRECTION]にする","boost.setMotorPower":"モーター[MOTOR_ID]のはやさを[POWER]%にする","boost.tiltDirection.any":"どれかのむき","boost.tiltDirection.down":"した","boost.tiltDirection.left":"ひだり","boost.tiltDirection.right":"みぎ","boost.tiltDirection.up":"うえ","boost.whenColor":"[COLOR] をみたとき","boost.whenTilted":"[TILT_DIRECTION_ANY]にかたむいたとき","ev3.beepNote":"[NOTE]のおんぷを[TIME]びょうならす","ev3.buttonPressed":"ボタン[PORT]がおされた","ev3.getBrightness":"あかるさ","ev3.getDistance":"きょり","ev3.getMotorPosition":"モーター[PORT]のいち","ev3.motorSetPower":"モーター[PORT]のパワーを[POWER]%にする","ev3.motorTurnClockwise":"モーター[PORT]をこちらむきに[TIME]びょうかんまわす","ev3.motorTurnCounterClockwise":"モーター[PORT]をあちらむきに[TIME]びょうかんまわす","ev3.whenBrightnessLessThan":"あかるさ < [DISTANCE]のとき","ev3.whenButtonPressed":"ボタン[PORT]がおされたとき","ev3.whenDistanceLessThan":"きょり < [DISTANCE]のとき","gdxfor.getAcceleration":"[DIRECTION]のかそく","gdxfor.getForce":"ちから","gdxfor.getSpin":"[DIRECTION]かいてんのはやさ","gdxfor.getTilt":"[TILT]ほうこうのかたむき","gdxfor.isFreeFalling":"らっかちゅう","gdxfor.isTilted":"[TILT]にかたむいた","gdxfor.pulled":"ひかれた","gdxfor.pushed":"おされた","gdxfor.shaken":"ふられた","gdxfor.startedFalling":"らっかをはじめた","gdxfor.tiltDirectionMenu.any":"どれかのむき","gdxfor.tiltDirectionMenu.back":"うしろ","gdxfor.tiltDirectionMenu.front":"まえ","gdxfor.tiltDirectionMenu.left":"ひだり","gdxfor.tiltDirectionMenu.right":"みぎ","gdxfor.turnedFaceDown":"ひょうめんがした","gdxfor.turnedFaceUp":"ひょうめんがうえ","gdxfor.whenForcePushedOrPulled":"ちからのセンサーが[PUSH_PULL]とき","gdxfor.whenGesture":"[GESTURE]とき","gdxfor.whenTilted":"[TILT]にかたむいたとき","makeymakey.downArrow":"したむきやじるし","makeymakey.downArrowShort":"した","makeymakey.leftArrow":"ひだりむきやじるし","makeymakey.leftArrowShort":"ひだり","makeymakey.rightArrow":"みぎむきやじるし","makeymakey.rightArrowShort":"みぎ","makeymakey.spaceKey":"スペース","makeymakey.upArrow":"うわむきやじるし","makeymakey.upArrowShort":"うえ","makeymakey.whenKeyPressed":"[KEY]キーがおされたとき","makeymakey.whenKeysPressedInOrder":"[SEQUENCE] がじゅんばんにおされたとき","microbit.buttonsMenu.any":"どれかの","microbit.clearDisplay":"がめんをけす","microbit.defaultTextToDisplay":"Hello!","microbit.displaySymbol":"[MATRIX]をひょうじする","microbit.displayText":"[TEXT]をひょうじする","microbit.gesturesMenu.jumped":"ジャンプした","microbit.gesturesMenu.moved":"うごいた","microbit.gesturesMenu.shaken":"ふられた","microbit.isButtonPressed":"ボタン[BTN]がおされた","microbit.isTilted":"[DIRECTION]にかたむいた","microbit.pinStateMenu.off":"きり","microbit.pinStateMenu.on":"いり","microbit.tiltAngle":"[DIRECTION]ほうこうのかたむき","microbit.tiltDirectionMenu.any":"どれかのむき","microbit.tiltDirectionMenu.back":"うしろ","microbit.tiltDirectionMenu.front":"まえ","microbit.tiltDirectionMenu.left":"ひだり","microbit.tiltDirectionMenu.right":"みぎ","microbit.whenButtonPressed":"ボタン[BTN]がおされたとき","microbit.whenGesture":"[GESTURE]とき","microbit.whenPinConnected":"ピン[PIN]がつながったとき","microbit.whenTilted":"[DIRECTION]にかたむいたとき","music.categoryName":"おんがく","music.changeTempo":"テンポを[TEMPO]ずつかえる","music.drumBass":"(2) バスドラム","music.drumBongo":"(13) ボンゴ","music.drumCabasa":"(15) カバサ","music.drumClaves":"(9) クラーベ","music.drumClosedHiHat":"(6) クローズハイハット","music.drumConga":"(14) コンガ","music.drumCowbell":"(11) カウベル","music.drumCrashCymbal":"(4) クラッシュシンバル","music.drumCuica":"(18) クイーカ","music.drumGuiro":"(16) ギロ","music.drumHandClap":"(8) てびょうし","music.drumOpenHiHat":"(5) オープンハイハット","music.drumSideStick":"(3) サイドスティック","music.drumSnare":"(1) スネアドラム","music.drumTambourine":"(7) タンバリン","music.drumTriangle":"(12) トライアングル","music.drumVibraslap":"(17) ビブラスラップ","music.drumWoodBlock":"(10) ウッドブロック","music.getTempo":"テンポ","music.instrumentBass":"(6) ベース","music.instrumentBassoon":"(14) バスーン","music.instrumentCello":"(8) チェロ","music.instrumentChoir":"(15) がっしょうだん","music.instrumentClarinet":"(10) クラリネット","music.instrumentElectricGuitar":"(5) エレキギター","music.instrumentElectricPiano":"(2) でんしピアノ","music.instrumentFlute":"(12) フルート","music.instrumentGuitar":"(4) ギター","music.instrumentMarimba":"(19) マリンバ","music.instrumentMusicBox":"(17) ミュージックボックス","music.instrumentOrgan":"(3) オルガン","music.instrumentPiano":"(1) ピアノ","music.instrumentPizzicato":"(7) ピチカート","music.instrumentSaxophone":"(11) サクソフォン","music.instrumentSteelDrum":"(18) スチールドラム","music.instrumentSynthLead":"(20) シンセリード","music.instrumentSynthPad":"(21) シンセパッド","music.instrumentTrombone":"(9) トロンボーン","music.instrumentVibraphone":"(16) ビブラフォン","music.instrumentWoodenFlute":"(13) もっかんフルート","music.midiPlayDrumForBeats":"[DRUM]のドラムを[BEATS]はくならす","music.midiSetInstrument":"がっきを[INSTRUMENT]にする","music.playDrumForBeats":"[DRUM]のドラムを[BEATS]はくならす","music.playNoteForBeats":"[NOTE]のおんぷを[BEATS]はくならす","music.restForBeats":"[BEATS]はくやすむ","music.setInstrument":"がっきを[INSTRUMENT]にする","music.setTempo":"テンポを[TEMPO]にする","pen.categoryName":"ペン","pen.changeColorParam":"ペンの[COLOR_PARAM]を[VALUE]ずつかえる","pen.changeHue":"ペンのいろを[HUE]ずつかえる","pen.changeShade":"ペンのこさを[SHADE]ずつかえる","pen.changeSize":"ペンのふとさを[SIZE]ずつかえる","pen.clear":"ぜんぶけす","pen.colorMenu.brightness":"あかるさ","pen.colorMenu.color":"いろ","pen.colorMenu.saturation":"あざやかさ","pen.colorMenu.transparency":"とうめいど","pen.penDown":"ペンをおろす","pen.penUp":"ペンをあげる","pen.setColor":"ペンのいろを[COLOR]にする","pen.setColorParam":"ペンの[COLOR_PARAM]を[VALUE]にする","pen.setHue":"ペンのいろを[HUE]にする","pen.setShade":"ペンのこさを[SHADE]にする","pen.setSize":"ペンのふとさを[SIZE]にする","pen.stamp":"スタンプ","text2speech.alto":"アルト","text2speech.categoryName":"おんせいごうせい","text2speech.defaultTextToSpeak":"こんにちは","text2speech.giant":"きょじん","text2speech.kitten":"こねこ","text2speech.setLanguageBlock":"げんごを[LANGUAGE]にする","text2speech.setVoiceBlock":"こえを[VOICE]にする","text2speech.speakAndWaitBlock":"[WORDS]としゃべる","text2speech.squeak":"ねずみ","text2speech.tenor":"テノール","translate.categoryName":"ほんやく","translate.defaultTextToTranslate":"こんにちは","translate.translateBlock":"[WORDS]を[LANGUAGE]にほんやくする","translate.viewerLanguage":"げんご","videoSensing.categoryName":"ビデオモーションセンサー","videoSensing.direction":"むき","videoSensing.motion":"モーション","videoSensing.off":"きり","videoSensing.on":"いり","videoSensing.onFlipped":"さゆうはんてん","videoSensing.setVideoTransparency":"ビデオのとうめいどを[TRANSPARENCY]にする","videoSensing.sprite":"スプライト","videoSensing.stage":"ステージ","videoSensing.videoOn":"[SUBJECT]のビデオの[ATTRIBUTE]","videoSensing.videoToggle":"ビデオを[VIDEO_STATE]にする","videoSensing.whenMotionGreaterThan":"ビデオモーション > [REFERENCE]のとき","wedo2.getDistance":"きょり","wedo2.getTiltAngle":"[TILT_DIRECTION]ほうこうのかたむき","wedo2.isTilted":"[TILT_DIRECTION_ANY]にかたむいた","wedo2.motorDirection.backward":"あちらむき","wedo2.motorDirection.forward":"こちらむき","wedo2.motorDirection.reverse":"ぎゃくむき","wedo2.motorId.a":"モーターA","wedo2.motorId.all":"すべてのモーター","wedo2.motorId.b":"モーターB","wedo2.motorId.default":"モーター","wedo2.motorOff":"[MOTOR_ID]をオフにする","wedo2.motorOn":"[MOTOR_ID]をオンにする","wedo2.motorOnFor":"[MOTOR_ID]を[DURATION]びょうかんオンにする","wedo2.playNoteFor":"[NOTE]のおんぷを[DURATION]びょうかんならす","wedo2.setLightHue":"ライトのいろを[HUE]にする","wedo2.setMotorDirection":"[MOTOR_ID]のほうこうを[MOTOR_DIRECTION]にする","wedo2.startMotorPower":"[MOTOR_ID]のパワーを[POWER]にする","wedo2.tiltDirection.any":"どれかのむき","wedo2.tiltDirection.down":"した","wedo2.tiltDirection.left":"ひだり","wedo2.tiltDirection.right":"みぎ","wedo2.tiltDirection.up":"うえ","wedo2.whenDistance":"きょり[OP][REFERENCE]のとき","wedo2.whenTilted":"[TILT_DIRECTION_ANY]にかたむいたとき","paint.paintEditor.hue":"いろ","paint.paintEditor.saturation":"あざやかさ","paint.paintEditor.brightness":"あかるさ","paint.paintEditor.costume":"コスチューム","paint.paintEditor.group":"ぐるーぷか","paint.paintEditor.ungroup":"グループかいじょ","paint.paintEditor.undo":"とりけし","paint.paintEditor.redo":"やりなおし","paint.paintEditor.forward":"てまえにだす","paint.paintEditor.backward":"おくにさげる","paint.paintEditor.front":"さいぜんめん","paint.paintEditor.back":"さいはいめん","paint.paintEditor.more":"もっと","paint.modeTools.brushSize":"おおきさ","paint.modeTools.eraserSize":"けしごむのおおきさ","paint.modeTools.copy":"コピー","paint.modeTools.paste":"はりつけ","paint.modeTools.delete":"さくじょ","paint.modeTools.curved":"なめらか","paint.modeTools.pointed":"かどばった","paint.modeTools.thickness":"ふとさ","paint.modeTools.flipHorizontal":"さゆうはんてん","paint.modeTools.flipVertical":"じょうげはんてん","paint.modeTools.filled":"ぬりつぶし","paint.modeTools.outlined":"りんかく","paint.paintEditor.bitmap":"ビットマップにへんかん","paint.paintEditor.vector":"ベクターにへんかん","paint.paintEditor.fill":"ぬりつぶし","paint.paintEditor.stroke":"わくせん","paint.brushMode.brush":"ふで","paint.eraserMode.eraser":"けしごむ","paint.fillMode.fill":"ぬりつぶし","paint.lineMode.line":"ちょくせん","paint.ovalMode.oval":"えん","paint.rectMode.rect":"しかくけい","paint.reshapeMode.reshape":"かたちをかえる","paint.roundedRectMode.roundedRect":"かくまるのちょうほうけい","paint.selectMode.select":"せんたく","paint.textMode.text":"テキスト","paint.colorPicker.swap":"いれかえ","tw.alerts.autosaving":"復元(ふくげん)しています…","tw.alerts.savedToDisk":"コンピューターに保存(ほぞん)する","tw.backpack.rename":"あたらしい名前(なまえ):","tw.browserModal.desc":"Google Chrome、Mozilla Firefox、Microsoft Edge、Apple Safari が最新(さいしん)バージョンであることを確認(かくにん)してください。","tw.changeUsername.cannotChangeWhileRunning":"ユーザーめいをプロジェクトを実行中(じっこうちゅう)にかえることはできません。","tw.cloudVariableBadge":"このプロジェクトはクラウド変数(へんすう)を使用(しよう)しています。TurboWarpは独自(どくじ)のサーバーを使用(しよう)しており、Scratchとは連携(れんけい)しておりません。また、ユーザーめいはScratchなどのユーザーとちがう可能性(かのうせい)があることに注意(ちゅうい)してください。{learnMore}","tw.code":"ソースコード","tw.customExtension.description":"URLから拡張機能(かくちょうきのう)をよみこみます。開発者(かいはつしゃ)むけで、実験段階(じっけんだんかい)です。","tw.customExtension.name":"カスタム拡張機能(かくちょうきのう)","tw.featuredProjectsStudio":"Scratchのスタジオでみる。","tw.feedback":"フィードバックとバグ","tw.feedbackButton":"TurboWarpへのフィードバック","tw.footer.credits":"クレジット","tw.footer.disclaimer":"TurboWarpはScratch、Scratch Team、Scratch財団(ざいだん)と提携(ていけい)していません。","tw.footer.embed":"うめこみコード","tw.footer.fosshost":"Fosshostが提供(ていきょう)するホスティング","tw.footer.parameters":"URLパラメーター","tw.footer.translate":"TurboWarpのほんやくをてつだう","tw.gui.defaultProjectTitle":"プロジェクト","tw.guiDefaultTitle":"Scratchのプロジェクトをはやくうごかす","tw.home.credit":"メモとクレジット","tw.home.description":"TurboWarpはScratchのMODで、はやくうごかすためにプロジェクトをJavaScriptにコンパイルしたものです。プロジェクトのIDやURLを入力(にゅうりょく)するか、したのプロジェクトの特集(とくしゅう)からえらんでみてください。","tw.home.instructions":"つかいかた","tw.input.tooltip":"ScratchのプロジェクトのURLをコピー&ペーストしてみることができます","tw.interpolationEnabled":"ほかんきのう","tw.invalidParameters.clones":"「クローン」のURLパラメーターが無効(むこう)です","tw.invalidParameters.fps":"「FPS」のURLパラメーターが無効(むこう)です","tw.loader.assets.known":"{total}つのうち{complete}つダウンロードをかんりょう…","tw.loader.assets.unknown":"ダウンロードちゅう…","tw.loader.data":"プロジェクトのデータをダウンロードちゅう…","tw.loader.generic":"プロジェクトをよみこみちゅう…","tw.menuBar.60off":"60FPSモードをかいじょする","tw.menuBar.60on":"60FPSモードにする","tw.menuBar.addons":"アドオン","tw.menuBar.advanced":"こうどなせってい","tw.menuBar.changeUsername":"ユーザーめいをかえる","tw.menuBar.cloudOff":"クラウドへんすうをむこうにする","tw.menuBar.cloudOn":"クラウドへんすうをゆうこうにする","tw.menuBar.cloudUnavailable":"クラウドへんすうはしようできません","tw.menuBar.loadRestorePoint":"ぜんかいのプロジェクトをふくげんする","tw.menuBar.moreSettings":"こうどなせってい","tw.menuBar.newFramerate":"あたらしいフレームレート:","tw.menuBar.reportError1":"コンパイルされていないスクリプトがあります。","tw.menuBar.reportError2":"これはバグです。ほうこくしてください。","tw.menuBar.saveAs":"{file}としてほぞんする","tw.menuBar.seeInside":"なかをみる","tw.oldDownload":"別(べつ)ファイルで保存(ほぞん)する...","tw.paint.alpha":"とうめいど","tw.privacy":"プライバシーポリシー","tw.saveAs":"…として保存(ほぞん)する","tw.saveTo":"{file}に保存(ほぞん)する","tw.settingsModal.customStageSize":"ステージのおおきさをかえる:","tw.settingsModal.dangerZone":"危険区域(きけんくいき)","tw.settingsModal.disableCompiler":"コンパイラをむこうにする","tw.settingsModal.disableCompilerHelp":"TurboWarpコンパイラを無効(むこう)にします。プロジェクトの編集中(へんしゅうちゅう)にこれを有効(ゆうこう)にすると、スクリプトがすぐに更新(こうしん)されるようになります。必要(ひつよう)ない場合(ばあい)は無効(むこう)にしてください。","tw.settingsModal.featured":"おすすめ","tw.settingsModal.fps":"60 FPS (カスタム FPS)","tw.settingsModal.fpsHelp":"通常(つうじょう)FPSが30のところ、60でスクリプトをうごかします。この機能(きのう)を有効(ゆうこう)にすると、ほとんどのプロジェクトがただしく動作(どうさ)しません。そのような場合(ばあい)は、この機能(きのう)を無効(むこう)にして「ほかんきのう」をためしてください。{customFramerate}","tw.settingsModal.fpsHelp.customFramerate":"クリックして30または60いがいのFPSを設定(せってい)する","tw.settingsModal.help":"クリックしてヘルプ","tw.settingsModal.highQualityPen":"ペンできれいにびょうがする","tw.settingsModal.highQualityPenHelp":"ペンのプロジェクトをよりたかい解像度(かいぞうど)でレンダリングするかわりに、エディタでのの座標(ざひょう)まるめを一部無効(いちぶむこう)にします。すべてのプロジェクトでこの設定(せってい)が有効(ゆうこう)とはいえず、パフォーマンスに影響(えいきょう)をあたえることがあります。","tw.settingsModal.infiniteClones":"クローンの制限(せいげん)を解除(かいじょ)","tw.settingsModal.infiniteClonesHelp":"Scratchの、クローンが300こまでしかつくれない制限(せいげん)を解除(かいじょ)します。","tw.settingsModal.interpolation":"ほかんきのう","tw.settingsModal.interpolationHelp":"スプライトのうごきを補間(ほかん)することで、プロジェクトをよりなめらかに見(み)せます。この機能(きのう)は、3Dのプロジェクト、レイトレーサー、ペンをつかったプロジェクトや、おもいプロジェクトには使用(しよう)しないでください。動作(どうさ)がおそくなります。","tw.settingsModal.removeFencing":"うごく範囲(はんい)とおおきさの制限(せいげん)を解除(かいじょ)する","tw.settingsModal.removeFencingHelp":"スプライトを画面(がめん)の外(そと)へ移動(いどう)させたり、すきなだけおおきさをかえたり、ふれたブロックを画面外(がめんがい)でうごかしたりすることができます。","tw.settingsModal.removeLimits":"制限(せいげん)を解除(かいじょ)する","tw.settingsModal.removeMiscLimits":"そのたの制限(せいげん)を解除(かいじょ)","tw.settingsModal.removeMiscLimitsHelp":"効果音(こうかおん)の制限(せいげん)とペンのおおきさの制限(せいげん)を解除(かいじょ)する","tw.settingsModal.storeProjectOptions":"高度(こうど)な設定(せってい)を保存(ほぞん)する","tw.settingsModal.title":"こうどなせってい","tw.settingsModal.warpTimer":"Warpタイマー","tw.settingsModal.warpTimerHelp":"スクリプトがながいループや無限(むげん)ループにおちいっているかどうかをチェックし、ループが終了(しゅうりょう)するまでうごけないのをさけ、ひくいフレームレートで実行(じっこう)するようにします。これにより、ほとんどのクラッシュが修正(しゅうせい)されます。しかし、パフォーマンスへの影響(えいきょう)がおおきいため、デフォルトではエディタでのみ有効(ゆうこう)になっています。","tw.spriteSelectorItem.rename":"なまえをかえる","tw.studioview.error":"プロジェクトをつぎのページでよみこむときにエラーが発生(はっせい)しました。","tw.twExtension.description":"奇妙(きみょう)なあたらしいブロック。Scratchではつかえません。","tw.twExtension.name":"TurboWarpのブロック","tw.usernameModal.mustChange":"もうしわけありません、あなたのユーザーめいが安全(あんぜん)でない可能性(かのうせい)があります。ほかのユーザーめいに変更(へんこう)するか、{resetIt}をしてください。","tw.usernameModal.mustChange.resetIt":"リセット(おすすめ)","tw.usernameModal.reset":"リセット","tw.usernameModal.title":"ユーザーめいをかえる","tw.viewFeaturedProjects":"クリックしてプロジェクトの特集(とくしゅう)をみる。","tw.viewOnScratch":"Scratchでプロジェクトをみる"},"nb":{"gui.alerts.tryAgain":"Prøv igjen","gui.alerts.download":"Last ned","gui.connection.reconnect":"Koble til igjen","gui.backpack.costumeLabel":"drakt","gui.backpack.soundLabel":"lyd","gui.backpack.scriptLabel":"skript","gui.backpack.spriteLabel":"figur","gui.backpack.header":"Ryggsekk","gui.backpack.errorBackpack":"Noe gikk feil med ryggsekken","gui.backpack.loadingBackpack":"Laster...","gui.backpack.more":"Mer","gui.backpack.emptyBackpack":"Ryggsekken er tom","gui.unsupportedBrowser.label":"Nettleseren støttes ikke","gui.cards.all-tutorials":"Veiledninger","gui.cards.shrink":"Skjul","gui.cards.expand":"Åpne","gui.cards.close":"Lukk","gui.cards.more-things-to-try":"Andre ting du kan prøve","gui.cards.see-more":"Vis flere","gui.comingSoon.message1":"Ingen fare, vi arbeider med dette {emoji}","gui.comingSoon.message2":"Kommer snart...","gui.comingSoon.message3":"Vi arbeider med dette {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Fant ingen enheter","gui.connection.auto-scanning.prescan":"Ha enheten i nærheten og start søk.","gui.connection.auto-scanning.pressbutton":"Trykk på knappen på enheten din.","gui.connection.auto-scanning.start-search":"Start søk","gui.connection.connecting-searchbutton":"Søker...","gui.connection.auto-scanning.try-again":"Prøv igjen","gui.connection.connected":"Tilkoblet","gui.connection.disconnect":"Koble fra","gui.connection.go-to-editor":"Gå til programredigering","gui.connection.connecting-cancelbutton":"Kobler til...","gui.connection.error.errorMessage":"Heisann, det ser ut til at noe gikk galt.","gui.connection.error.tryagainbutton":"Prøv igjen","gui.connection.error.helpbutton":"Hjelp","gui.connection.peripheral-name-label":"Enhetsnavn","gui.connection.connect":"Koble til","gui.connection.scanning.lookingforperipherals":"Søker etter enheter","gui.connection.scanning.noPeripheralsFound":"Fant ingen enheter","gui.connection.scanning.instructions":"Velg din enhet i listen ovenfor","gui.connection.search":"Søk igjen","gui.connection.unavailable.installscratchlink":"Sjekk at du har installert og startet \\"Scratch Link\\"","gui.connection.unavailable.enablebluetooth":"Sjekk at Bluetooth er skrudd på","gui.connection.unavailable.tryagainbutton":"Prøv igjen","gui.connection.unavailable.helpbutton":"Hjelp","gui.controls.go":"Start","gui.controls.stop":"Stopp","gui.crashMessage.label":"Uff, noe gikk galt.","gui.crashMessage.errorNumber":"Feilen er logget med ID {errorId}","gui.crashMessage.reload":"Last på nytt","gui.customProcedures.myblockModalTitle":"Lag en kloss","gui.customProcedures.addAnInputNumberText":"Legg til et felt","gui.customProcedures.numberTextType":"tall eller tekst","gui.customProcedures.addAnInputBoolean":"Legg til et felt","gui.customProcedures.booleanType":"logisk verdi","gui.customProcedures.addALabel":"Legg til tekst","gui.customProcedures.runWithoutScreenRefresh":"Kjør uten å oppdatere skjermen","gui.customProcedures.cancel":"Avbryt","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Retning","gui.directionPicker.rotationStyles.allAround":"Fri rotasjon","gui.directionPicker.rotationStyles.leftRight":"Vend sideveis","gui.directionPicker.rotationStyles.dontRotate":"Ikke roter","gui.gui.addExtension":"Hent tilleggsfunksjon","gui.gui.codeTab":"Kode","gui.gui.backdropsTab":"Bakgrunner","gui.gui.costumesTab":"Drakter","gui.gui.soundsTab":"Lyder","gui.extensionLibrary.comingSoon":"Kommer snart","gui.extensionLibrary.requires":"Utstyrsbehov","gui.extensionLibrary.collaboration":"Samarbeid med","gui.library.filterPlaceholder":"Søk","gui.library.allTag":"Alle","gui.loader.headline":"Laster prosjekt","gui.loader.creating":"Oppretter prosjekt","gui.authorInfo.byUser":"av {username}","gui.menuBar.seeProjectPage":"Se prosjektsiden","gui.menuBar.LanguageSelector":"velg språk","gui.menuBar.tutorialsLibrary":"Veiledninger","gui.menuBar.restoreSprite":"Angle sletting av figur","gui.menuBar.restoreSound":"Angre sletting av lyd","gui.menuBar.restoreCostume":"Angre sletting av drakt","gui.menuBar.restore":"Angre sletting","gui.menuBar.saveNow":"Lagre nå","gui.menuBar.saveAsCopy":"Lagre som kopi","gui.menuBar.remix":"Remiks","gui.menuBar.new":"Ny","gui.menuBar.file":"Fil","gui.menuBar.downloadToComputer":"Lagre på datamaskinen","gui.menuBar.edit":"Rediger","gui.menuBar.turboModeOff":"Skru av turbofart","gui.menuBar.turboModeOn":"Skru på turbofart","gui.gui.projectTitlePlaceholder":"Prosjektets navn her","gui.menuBar.isShared":"Lagt ut","gui.menuBar.share":"Legg ut","gui.modal.help":"Hjelp","gui.modal.back":"Tilbake","gui.monitor.listMonitor.empty":"(tom)","gui.monitor.listMonitor.listLength":"lengde {length}","gui.monitor.contextMenu.default":"vanlig visning","gui.monitor.contextMenu.large":"stor visning","gui.monitor.contextMenu.slider":"skyveknapp","gui.monitor.contextMenu.sliderRange":"endre verdiområde","gui.monitor.contextMenu.import":"importer","gui.monitor.contextMenu.export":"Eksporter","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Spill av","gui.playButton.stop":"Stopp","gui.gui.variableScopeOptionAllSprites":"For alle figurer","gui.gui.variableScopeOptionSpriteOnly":"For denne figuren","gui.gui.cloudVariableOption":"Nettvariabel (lagret på nettstedet til Scratch)","gui.gui.variablePromptAllSpritesMessage":"Denne variabelen kan brukes av alle figurer","gui.gui.listPromptAllSpritesMessage":"Alle figurer har tilgang til denne listen.","gui.prompt.cancel":"Avbryt","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Stopp","gui.playbackStep.playMsg":"Spill av","gui.playbackStep.loadingMsg":"Laster...","gui.playbackStep.saveMsg":"Lagre","gui.playbackStep.reRecordMsg":"Spill inn igjen","gui.recordModal.title":"Spill inn lyd","gui.recordingStep.beginRecord":"Klikk på knappen nedenfor for å starte opptak","gui.recordingStep.permission":"{arrow}Du må godkjenne at Scratch bruker mikrofonen","gui.recordingStep.stop":"Stopp opptak","gui.recordingStep.record":"Spill inn lyd","gui.sliderModal.min":"Laveste verdi","gui.sliderModal.max":"Høyeste verdi","gui.sliderModal.title":"Endre verdiområde","gui.sliderPrompt.cancel":"Avbryt","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Lyd","gui.soundEditor.play":"Spill av","gui.soundEditor.stop":"Stopp","gui.soundEditor.copy":"Kopier","gui.soundEditor.paste":"Lim inn","gui.soundEditor.copyToNew":"Kopi til ny","gui.soundEditor.delete":"Slett","gui.soundEditor.save":"Lagre","gui.soundEditor.undo":"Angre","gui.soundEditor.redo":"Gjør igjen","gui.soundEditor.faster":"Raskere","gui.soundEditor.slower":"Saktere","gui.soundEditor.echo":"Ekko","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Høyere lyd","gui.soundEditor.softer":"Svakere lyd","gui.soundEditor.reverse":"Baklengs","gui.soundEditor.fadeOut":"Ton ut","gui.soundEditor.fadeIn":"Ton inn","gui.soundEditor.mute":"Stille","gui.SpriteInfo.spritePlaceholder":"Figurens navn","gui.SpriteInfo.sprite":"Figur","gui.SpriteInfo.show":"Vis","gui.SpriteInfo.size":"Størrelse","gui.spriteSelectorItem.contextMenuDuplicate":"lag en kopi","gui.spriteSelectorItem.contextMenuExport":"eksport","gui.spriteSelectorItem.contextMenuDelete":"slett","gui.spriteSelector.addSpriteFromLibrary":"Velg en figur","gui.spriteSelector.addSpriteFromPaint":"Tegn","gui.spriteSelector.addSpriteFromSurprise":"Overraskelse","gui.spriteSelector.addSpriteFromFile":"Last opp figur","gui.stageHeader.stageSizeLarge":"Bytt til stor scene","gui.stageHeader.stageSizeSmall":"Bytt til liten scene","gui.stageHeader.stageSizeFull":"Gå til fullskjerm","gui.stageHeader.stageSizeUnFull":"Avslutt fullskjerm","gui.stageHeader.fullscreenControl":"Fullskjerm av/på","gui.spriteSelector.addBackdropFromLibrary":"Velg et bakgrunnsbilde","gui.stageSelector.addBackdropFromPaint":"Tegn","gui.stageSelector.addBackdropFromSurprise":"Overraskelse","gui.stageSelector.addBackdropFromFile":"Last opp bakgrunn","gui.stageSelector.stage":"Scene","gui.stageSelector.backdrops":"Bakgrunner","gui.telemetryOptIn.label":"Send statistikk for å forbedre Scratch","gui.telemetryOptIn.body1":"Scratch-gruppen studerer hvordan Scratch brukes rundt i verden. Du kan bidra ved å la Scratch automatisk sende inn statistikk over hvordan du bruker Scratch.","gui.telemetryOptIn.body2":"Informasjonen som samles inn inn er blant annet hvilket språk du bruker Scartch på, hvilke klosser du bruker, og registrering av handlinger som for eksempel lagring, åpning og opplasting av prosjekter. Vi samler IKKE inn personinformasjon. Se {privacyPolicyLink} for mer informasjon.","gui.telemetryOptIn.privacyPolicyLink":"Personvern","gui.telemetryOptIn.optInText":"La Scratch-administratorene få tilgang til mine bruksdata","gui.telemetryOptIn.optInTooltip":"Godta innsamling av statistiske bruksdata","gui.telemetryOptIn.optOutText":"Ikke del mine bruksdata med Scratch-administratorene.","gui.telemetryOptIn.optOutTooltip":"Slå av innsamling av statistiske bruksdata","gui.telemetryOptIn.settingWasUpdated":"Dine valg er oppdatert.","gui.telemetryOptIn.buttonClose":"Lukk","gui.turboMode.active":"Turbo-hastighet","gui.webglModal.label":"Nettleseren støtter ikke WebGL","gui.webglModal.webgllink":"ikke støtter WebGL","gui.costumeLibrary.chooseABackdrop":"Velg et bakgrunnsbilde","gui.costumeLibrary.chooseACostume":"Velg en drakt","gui.costumeTab.addBackdropFromLibrary":"Velg et bakgrunnsbilde","gui.costumeTab.addCostumeFromLibrary":"Velg en drakt","gui.costumeTab.addBlankCostume":"Tegn","gui.costumeTab.addSurpriseCostume":"Overraskelse","gui.costumeTab.addFileBackdrop":"Last opp bakgrunn","gui.costumeTab.addFileCostume":"Last opp drakt","gui.extensionLibrary.chooseAnExtension":"Velg en tilleggsfunksjon","gui.extensionLibrary.extensionUrl":"Skriv inn URL til tilleggsfunksjonen","gui.monitors.importListColumnPrompt":"Hvilken kolonne skal brukes (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Feil ved start av innspilling","gui.soundLibrary.chooseASound":"Velg en lyd","gui.soundTab.fileUploadSound":"Last opp en lyd","gui.soundTab.surpriseSound":"Overraskelse","gui.soundTab.recordSound":"Spill inn lyd","gui.soundTab.addSoundFromLibrary":"Velg en lyd","gui.spriteLibrary.chooseASprite":"Velg en figur","gui.tipsLibrary.tutorials":"Velg en veiledning","gui.alerts.createsuccess":"Nytt prosjekt opprettet","gui.alerts.createcopysuccess":"Prosjektet er lagret som kopi","gui.alerts.createremixsuccess":"Prosjektet er lagret som remiks.","gui.alerts.creating":"Oppretter...","gui.alerts.creatingCopy":"Kopierer prosjektet...","gui.alerts.creatingRemix":"Remikser prosjektet...","gui.alerts.creatingError":"Noe gikk feil. Prøv å opprette nytt prosjekt igjen.","gui.alerts.savingError":"Noe gikk feil ved lagring av prosjektet.","gui.alerts.savesuccess":"Prosjektet er lagret.","gui.alerts.saving":"Lagrer prosjektet...","gui.alerts.cloudInfo":"Merk at nettvariabler kan bare lagre tall, ikke bokstaver eller symboler. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Les mer.","gui.alerts.importing":"Importerer …","gui.defaultProject.variable":"min variabel","gui.extension.music.name":"Musikk","gui.extension.music.description":"Spill instrumenter","gui.extension.pen.name":"Penn","gui.extension.pen.description":"Få figurene til å tegne","gui.extension.videosensing.name":"Sansing med kamera","gui.extension.videosensing.description":"La kameraet sanse bevegelser","gui.extension.text2speech.name":"Tekst til tale","gui.extension.text2speech.description":"Lag prosjekter som snakker","gui.extension.translate.name":"Oversette","gui.extension.translate.description":"Oversett tekst til andre språk","gui.extension.makeymakey.description":"Bruk hva som helst som tastatur","gui.extension.microbit.description":"Koble prosjektet ditt til den fysiske verden","gui.extension.microbit.connectingMessage":"Kobler til","gui.extension.ev3.description":"Lag interaktive roboter og maskiner","gui.extension.ev3.connectingMessage":"Kobler til. Pass på at PIN-koden på din EV3 er satt til 1234.","gui.extension.boost.description":"Lag liv i Lego-roboter.","gui.extension.boost.connectingMessage":"Kobler til","gui.extension.wedo2.description":"Bygg med motorer og sensorer","gui.extension.wedo2.connectingMessage":"Kobler til","gui.extension.gdxfor.description":"Sensor for kraft, bevegelse og rotasjon.","gui.extension.gdxfor.connectingMessage":"Kobler til","gui.libraryTags.all":"Alt","gui.libraryTags.animals":"Dyr","gui.libraryTags.dance":"Dans","gui.libraryTags.effects":"Effekter","gui.libraryTags.fantasy":"Fantasi","gui.libraryTags.fashion":"Mote","gui.libraryTags.food":"Mat","gui.libraryTags.indoors":"Innendørs","gui.libraryTags.loops":"Musikkloop","gui.libraryTags.music":"Musikk","gui.libraryTags.notes":"Noter","gui.libraryTags.outdoors":"Utendørs","gui.libraryTags.patterns":"Mønstre","gui.libraryTags.people":"Mennesker","gui.libraryTags.percussion":"Slaginstrumenter","gui.libraryTags.space":"Romfart","gui.libraryTags.sports":"Sport","gui.libraryTags.underwater":"Under vann","gui.libraryTags.voice":"Stemme","gui.libraryTags.wacky":"Rart","gui.libraryTags.animation":"Animasjon","gui.libraryTags.art":"Kunst","gui.libraryTags.games":"Spill","gui.libraryTags.stories":"Fortellinger","gui.libraryTags.letters":"Bokstaver","gui.opcodeLabels.direction":"retning","gui.opcodeLabels.xposition":"x-posisjon","gui.opcodeLabels.yposition":"y-posisjon","gui.opcodeLabels.size":"størrelse","gui.opcodeLabels.costumename":"draktnavn","gui.opcodeLabels.costumenumber":"draktnummer","gui.opcodeLabels.backdropname":"navn på bakgrunn","gui.opcodeLabels.backdropnumber":"bakgrunnsnummer","gui.opcodeLabels.volume":"volum","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"svar","gui.opcodeLabels.loudness":"lydnivå","gui.opcodeLabels.username":"brukernavn","gui.opcodeLabels.year":"år","gui.opcodeLabels.month":"måned","gui.opcodeLabels.date":"dato","gui.opcodeLabels.dayofweek":"ukedag","gui.opcodeLabels.hour":"time","gui.opcodeLabels.minute":"minutt","gui.opcodeLabels.second":"sekund","gui.opcodeLabels.timer":"sekundklokke","gui.sharedMessages.backdrop":"bakgrunn{index}","gui.sharedMessages.costume":"drakt{index}","gui.sharedMessages.sprite":"Figur{index}","gui.sharedMessages.pop":"plopp","gui.sharedMessages.replaceProjectWarning":"Starte på nytt uten å lagre?","gui.sharedMessages.loadFromComputerTitle":"Last opp fra datamaskinen","boost.color.any":"hvilken som helst","boost.color.black":"svart","boost.color.blue":"blå","boost.color.green":"grønn","boost.color.red":"rød","boost.color.white":"hvit","boost.color.yellow":"gul","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] posisjon","boost.getTiltAngle":"helningsvinkel [TILT_DIRECTION]","boost.motorDirection.backward":"den andre veien","boost.motorDirection.forward":"den ene veien","boost.motorDirection.reverse":"bytt retning","boost.motorOff":"skru av motor [MOTOR_ID]","boost.motorOn":"skru på motor [MOTOR_ID]","boost.motorOnFor":"kjør motor [MOTOR_ID] i [DURATION] sekunder","boost.motorOnForRotation":"kjør motor [MOTOR_ID] rundt [ROTATION] rotasjoner","boost.seeingColor":"ser [COLOR] kloss?","boost.setLightHue":"sett lysfarge [HUE]","boost.setMotorDirection":"velg motor [MOTOR_ID] retning [MOTOR_DIRECTION]","boost.setMotorPower":"sett motor [MOTOR_ID] fart til [POWER] %","boost.tiltDirection.any":"hvilken som helst","boost.tiltDirection.down":"ned","boost.tiltDirection.left":"venstre","boost.tiltDirection.right":"høyre","boost.tiltDirection.up":"opp","boost.whenColor":"når [COLOR] kloss sett","boost.whenTilted":"når helning [TILT_DIRECTION_ANY]","ev3.beepNote":"tone [NOTE] i [TIME] sekunder","ev3.buttonPressed":"knapp [PORT] trykket?","ev3.getBrightness":"lysstyrke","ev3.getDistance":"avstand","ev3.getMotorPosition":"motor [PORT] vinkel","ev3.motorSetPower":"motor [PORT] sett fart [POWER] %","ev3.motorTurnClockwise":"motor [PORT] kjør den ene veien i [TIME] sekunder","ev3.motorTurnCounterClockwise":"motor [PORT] kjør den andre veien i [TIME] sekunder","ev3.whenBrightnessLessThan":"når lysnivå < [DISTANCE]","ev3.whenButtonPressed":"når knapp [PORT] trykkes","ev3.whenDistanceLessThan":"når avstand < [DISTANCE]","gdxfor.getAcceleration":"akselerasjon [DIRECTION]","gdxfor.getForce":"kraft","gdxfor.getSpin":"rotasjonsfart [DIRECTION]","gdxfor.getTilt":"helningsvinkel [TILT]","gdxfor.isFreeFalling":"fritt fall","gdxfor.isTilted":"heller [TILT]?","gdxfor.pulled":"trekkes","gdxfor.pushed":"dyttes","gdxfor.shaken":"ristet","gdxfor.startedFalling":"begynner å falle","gdxfor.tiltDirectionMenu.any":"hvilken som helst","gdxfor.tiltDirectionMenu.back":"bakover","gdxfor.tiltDirectionMenu.front":"framover","gdxfor.tiltDirectionMenu.left":"venstre","gdxfor.tiltDirectionMenu.right":"høyre","gdxfor.turnedFaceDown":"vender forsiden ned","gdxfor.turnedFaceUp":"vender forsiden opp","gdxfor.whenForcePushedOrPulled":"når kraftsensoren [PUSH_PULL]","gdxfor.whenGesture":"når [GESTURE]","gdxfor.whenTilted":"ved helning [TILT]","makeymakey.downArrow":"pil ned","makeymakey.downArrowShort":"ned","makeymakey.leftArrow":"pil venstre","makeymakey.leftArrowShort":"venstre","makeymakey.rightArrow":"pil høyre","makeymakey.rightArrowShort":"høyre","makeymakey.spaceKey":"mellomrom","makeymakey.upArrow":"pil opp","makeymakey.upArrowShort":"opp","makeymakey.whenKeyPressed":"når [KEY] trykkes","makeymakey.whenKeysPressedInOrder":"når [SEQUENCE] trykkes i rekkefølge","microbit.buttonsMenu.any":"hvilken som helst","microbit.clearDisplay":"tøm skjermen","microbit.defaultTextToDisplay":"Hei!","microbit.displaySymbol":"vis bilde [MATRIX]","microbit.displayText":"vis tekst [TEXT]","microbit.gesturesMenu.jumped":"hoppet","microbit.gesturesMenu.moved":"flyttet","microbit.gesturesMenu.shaken":"ristet","microbit.isButtonPressed":"[BTN] knapp trykket?","microbit.isTilted":"helning [DIRECTION]?","microbit.pinStateMenu.off":"av","microbit.pinStateMenu.on":"på","microbit.tiltAngle":"helningsvinkel [DIRECTION]","microbit.tiltDirectionMenu.any":"hvilken som helst","microbit.tiltDirectionMenu.back":"bakover","microbit.tiltDirectionMenu.front":"forover","microbit.tiltDirectionMenu.left":"venstre","microbit.tiltDirectionMenu.right":"høyre","microbit.whenButtonPressed":"når [BTN] knapp trykkes","microbit.whenGesture":"når [GESTURE]","microbit.whenPinConnected":"når kontakt [PIN] trykkes","microbit.whenTilted":"når helning [DIRECTION]","music.categoryName":"Musikk","music.changeTempo":"endre tempo med [TEMPO]","music.drumBass":"(2) Stortromme","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Pinner","music.drumClosedHiHat":"(6) Lukket hi-hat","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Kubjelle","music.drumCrashCymbal":"(4) Crash cymbal","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Håndklapp","music.drumOpenHiHat":"(5) Åpen hi-hat","music.drumSideStick":"(3) Kantslag","music.drumSnare":"(1) Skarptromme","music.drumTambourine":"(7) Tamburin","music.drumTriangle":"(12) Triangel","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Treblokk","music.getTempo":"tempo","music.instrumentBass":"(6) Kontrabass","music.instrumentBassoon":"(14) Fagott","music.instrumentCello":"(8) Cello","music.instrumentChoir":"(15) Kor","music.instrumentClarinet":"(10) Klarinett","music.instrumentElectricGuitar":"(5) Elektrisk gitar","music.instrumentElectricPiano":"(2) Elektrisk piano","music.instrumentFlute":"(12) Fløyte","music.instrumentGuitar":"(4) Gitar","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Spilledåse","music.instrumentOrgan":"(3) Orgel","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saksofon","music.instrumentSteelDrum":"(18) Steel drum","music.instrumentSynthLead":"(20) Synth","music.instrumentSynthPad":"(21) Synth-akkord","music.instrumentTrombone":"(9) Trombone","music.instrumentVibraphone":"(16) Vibrafon","music.instrumentWoodenFlute":"(13) Blokkfløyte","music.midiPlayDrumForBeats":"trommeslag [DRUM] som varer [BEATS] taktslag","music.midiSetInstrument":"velg instrument [INSTRUMENT]","music.playDrumForBeats":"trommeslag [DRUM] som varer [BEATS] taktslag","music.playNoteForBeats":"spill tone [NOTE] som varer [BEATS] taktslag","music.restForBeats":"pause i [BEATS] taktslag","music.setInstrument":"velg instrument [INSTRUMENT]","music.setTempo":"sett tempo til [TEMPO]","pen.categoryName":"Penn","pen.changeColorParam":"endre pennens [COLOR_PARAM] med [VALUE]","pen.changeHue":"endre pennfarge med [HUE]","pen.changeShade":"endre pennens lysstyrke med [SHADE]","pen.changeSize":"endre pennens bredde med [SIZE]","pen.clear":"slett alt","pen.colorMenu.brightness":"lysstyrke","pen.colorMenu.color":"farge","pen.colorMenu.saturation":"fargemetning","pen.colorMenu.transparency":"gjennomsiktighet","pen.penDown":"penn på","pen.penUp":"penn av","pen.setColor":"sett pennfarge til [COLOR]","pen.setColorParam":"sett pennens [COLOR_PARAM] til [VALUE]","pen.setHue":"sett pennens farge til [HUE]","pen.setShade":"sett pennens lysstyrke til [SHADE]","pen.setSize":"sett pennbredde til [SIZE]","pen.stamp":"stemple avtrykk","text2speech.alto":"alt","text2speech.categoryName":"Tekst til tale","text2speech.defaultTextToSpeak":"hei","text2speech.giant":"kjempe","text2speech.kitten":"kattunge","text2speech.setLanguageBlock":"velg språk [LANGUAGE]","text2speech.setVoiceBlock":"velg stemme [VOICE]","text2speech.speakAndWaitBlock":"si [WORDS]","text2speech.squeak":"knirk","text2speech.tenor":"tenor","translate.categoryName":"Oversette","translate.defaultTextToTranslate":"hei","translate.translateBlock":"oversett [WORDS] til [LANGUAGE]","translate.viewerLanguage":"språk","videoSensing.categoryName":"Sansing med kamera","videoSensing.direction":"retning","videoSensing.motion":"bevegelse","videoSensing.off":"av","videoSensing.on":"på","videoSensing.onFlipped":"på speilvendt","videoSensing.setVideoTransparency":"sett [TRANSPARENCY] gjennomsiktighet av video","videoSensing.sprite":"figur","videoSensing.stage":"scene","videoSensing.videoOn":"video [ATTRIBUTE] på [SUBJECT]","videoSensing.videoToggle":"sett video [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"når videobevegelse > [REFERENCE]","wedo2.getDistance":"avstand","wedo2.getTiltAngle":"helningsvinkel [TILT_DIRECTION]","wedo2.isTilted":"helning [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"den ene veien","wedo2.motorDirection.forward":"den andre veien","wedo2.motorDirection.reverse":"snu","wedo2.motorId.a":"motor A","wedo2.motorId.all":"alle motorer","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"skru av [MOTOR_ID]","wedo2.motorOn":"skru på [MOTOR_ID]","wedo2.motorOnFor":"skru på [MOTOR_ID] i [DURATION] sekunder","wedo2.playNoteFor":"spill tone [NOTE] i [DURATION] sekunder","wedo2.setLightHue":"sett lysfarge [HUE]","wedo2.setMotorDirection":"velg [MOTOR_ID] retning [MOTOR_DIRECTION]","wedo2.startMotorPower":"sett [MOTOR_ID] fart [POWER]","wedo2.tiltDirection.any":"hvilken som helst","wedo2.tiltDirection.down":"ned","wedo2.tiltDirection.left":"venstre","wedo2.tiltDirection.right":"høyre","wedo2.tiltDirection.up":"opp","wedo2.whenDistance":"når avstand [OP] [REFERENCE]","wedo2.whenTilted":"når helning [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Farge","paint.paintEditor.saturation":"Fargemetning","paint.paintEditor.brightness":"Lysstyrke","paint.paintEditor.costume":"Drakt","paint.paintEditor.group":"Gruppér","paint.paintEditor.ungroup":"Del opp gruppe","paint.paintEditor.undo":"Angre","paint.paintEditor.redo":"Gjør igjen","paint.paintEditor.forward":"Flytt frem","paint.paintEditor.backward":"Flytt tilbake","paint.paintEditor.front":"Foran alt","paint.paintEditor.back":"Tilbake","paint.paintEditor.more":"Flere","paint.modeTools.brushSize":"Størrelse","paint.modeTools.eraserSize":"Viskelærbredde","paint.modeTools.copy":"Kopier","paint.modeTools.paste":"Lim inn","paint.modeTools.delete":"Slett","paint.modeTools.curved":"Glatt","paint.modeTools.pointed":"Skarp","paint.modeTools.thickness":"Tykkelse","paint.modeTools.flipHorizontal":"Speilvend","paint.modeTools.flipVertical":"Opp ned","paint.modeTools.filled":"Fylt","paint.modeTools.outlined":"Omriss","paint.paintEditor.bitmap":"Gå til pikselgrafikk","paint.paintEditor.vector":"Gjør om til vektorgrafikk","paint.paintEditor.fill":"Fyll","paint.paintEditor.stroke":"Kant","paint.brushMode.brush":"Malepensel","paint.eraserMode.eraser":"Viskelær","paint.fillMode.fill":"Fyll","paint.lineMode.line":"Linje","paint.ovalMode.oval":"Sirkel","paint.rectMode.rect":"Rektangel","paint.reshapeMode.reshape":"Bøy","paint.roundedRectMode.roundedRect":"Avrundet rektangel","paint.selectMode.select":"Velg","paint.textMode.text":"Tekst","paint.colorPicker.swap":"Bytt","tw.alerts.savedToDisk":"Lagret på datamaskinet.","tw.backpack.rename":"Nytt navn:","tw.changeUsername.cannotChangeWhileRunning":"Brukernavn kan ikke byttes mens prosjektet er på.","tw.code":"Kildekode","tw.featuredProjectsStudio":"Se galeriet på Scratch.","tw.feedback":"Tilbakemelding & feil","tw.feedbackButton":"TurboWarp tillbakemelding","tw.footer.disclaimer":"TurboWarp er ikke tilknyttet Scratch, Scratch Team eller Scratch Foundation.","tw.footer.parameters":"URL-parametere","tw.footer.translate":"Hjelp å oversett TurboWarp","tw.gui.defaultProjectTitle":"Prosjekt","tw.guiDefaultTitle":"Kjør Scratch prosjekter raskere","tw.home.credit":"Merknader og bidragsytere","tw.home.description":"TurboWarp er en Scratch-mod som samler prosjekter til JavaScript for å få dem til å kjøre veldig raskt. Prøv det ved å legge inn en prosjekt-ID eller URL ovenfor eller velge et utvalgt prosjekt nedenfor.","tw.home.instructions":"Hvordan bruke prosjektet","tw.interpolationEnabled":"Interpolasjon","tw.invalidParameters.clones":"\\"klon\\" Url-parameteren er ugyldig","tw.invalidParameters.fps":"\\"fps\\" Url-parameteren er ugyldig","tw.loader.assets.known":"Laster ned eiendeler ({complete}/{total}) ...","tw.loader.assets.unknown":"Laster ned eiendeler ...","tw.loader.data":"Laster ned prosjektdata ...","tw.loader.generic":"Laster prosjekt ...","tw.menuBar.60off":"Slå av 60 FPS Modus","tw.menuBar.60on":"Slå på 60 FPS Modus","tw.menuBar.addons":"Utvidelser","tw.menuBar.advanced":"Avansert","tw.menuBar.changeUsername":"Bytt Brukernavn","tw.menuBar.cloudOff":"Slå av nett-variabler","tw.menuBar.cloudOn":"Slå på nett-variabler","tw.menuBar.cloudUnavailable":"Nett-variabler er ikke tilgjengelig","tw.menuBar.cloudUnavailableAlert":"Kan ikke bruke nett-variabler, det er kanskje fordi du åpnet redigerer","tw.menuBar.compileError":"{sprite}:{error}","tw.menuBar.moreSettings":"Avansert innstillinger","tw.menuBar.newFramerate":"Nytt bildefrekvens:","tw.menuBar.reportError1":"Noen skripter kunne ikke kompileres.","tw.menuBar.reportError2":"Dette er en feil. Vennligst meld det.","tw.menuBar.saveAs":"Lagre som {file}","tw.menuBar.seeInside":"Se inni","tw.paint.alpha":"Opasitet","tw.privacy":"Personvernregler","tw.settingsModal.customStageSize":"Bytt scene størrelse:","tw.settingsModal.dangerZone":"Faresone","tw.settingsModal.featured":"Anbefalt","tw.settingsModal.fps":"60 FPS (tilpassede fps)","tw.settingsModal.fpsHelp.customFramerate":"Klikk her til å velge mellom 30 eller 60 FPS","tw.settingsModal.help":"Klikk her for hjelp","tw.settingsModal.highQualityPen":"Høy kvalitet penn ","tw.settingsModal.infiniteClones":"Uendelige kloner","tw.settingsModal.infiniteClonesHelp":"Den slår av Scratchs 300 klon grense","tw.settingsModal.interpolation":"Interpolasjon","tw.settingsModal.removeLimits":"Fjern grenser","tw.settingsModal.title":"Avansert innstillinger","tw.spriteSelectorItem.rename":"endre navn","tw.studioview.authorAttribution":"fra {author}","tw.studioview.error":"Det oppsto en feil under innlasting av neste side av prosjekter.","tw.studioview.hoverText":"{title} fra {author}","tw.twExtension.description":"Rar klosser. Ikke kompatibel med Scratch.","tw.twExtension.name":"TurboWarp Klosser","tw.usernameModal.mustChange":"Beklager, Nett-variabel server tror at brukernavnet din er usikre. Bytt brukernavnet eller {resetIt}","tw.usernameModal.mustChange.resetIt":"nullstille det (anbefales)","tw.usernameModal.reset":"Nullstille","tw.usernameModal.title":"Bytt Brukernavn","tw.viewFeaturedProjects":"Klikk til å se anbefalte prosjekter.","tw.viewOnScratch":"Se prosjektet på Scratch"},"nn":{"gui.alerts.tryAgain":"Prøv på nytt","gui.alerts.download":"Last ned","gui.connection.reconnect":"Kopla til på nytt","gui.backpack.costumeLabel":"drakt","gui.backpack.soundLabel":"lyd","gui.backpack.scriptLabel":"skript","gui.backpack.spriteLabel":"figur","gui.backpack.header":"Ryggsekk","gui.backpack.errorBackpack":"Feil ved lasting av ryggsekk","gui.backpack.loadingBackpack":"Lastar …","gui.backpack.more":"Fleire","gui.backpack.emptyBackpack":"Ryggsekken er tom","gui.unsupportedBrowser.label":"Nettlesaren er ikkje støtta","gui.cards.all-tutorials":"Innføringar","gui.cards.shrink":"Krymp","gui.cards.expand":"Utvid","gui.cards.close":"Lukk","gui.cards.more-things-to-try":"Fleire ting å prøva!","gui.cards.see-more":"Vis fleire","gui.comingSoon.message1":"Slapp av – me er på saka {emoji}","gui.comingSoon.message2":"Er rett rundt hjørnet …","gui.comingSoon.message3":"Me arbeider med det {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Fann ingen einingar","gui.connection.auto-scanning.prescan":"Har eininga i nærleiken, og start så søk.","gui.connection.auto-scanning.pressbutton":"Trykk på knappen på eininga.","gui.connection.auto-scanning.start-search":"Start søk","gui.connection.connecting-searchbutton":"Søkjer …","gui.connection.auto-scanning.try-again":"Prøv på nytt","gui.connection.connected":"Tilkopla","gui.connection.disconnect":"Kopla frå","gui.connection.go-to-editor":"Tilbake til prosjektet","gui.connection.connecting-cancelbutton":"Koplar til …","gui.connection.error.errorMessage":"Å nei! Noko gjekk gale.","gui.connection.error.tryagainbutton":"Prøv på nytt","gui.connection.error.helpbutton":"Hjelp","gui.connection.peripheral-name-label":"Einingsnamn","gui.connection.connect":"Kopla til","gui.connection.scanning.lookingforperipherals":"Søkjer etter einingar","gui.connection.scanning.noPeripheralsFound":"Fann ikkje nokon einingar","gui.connection.scanning.instructions":"Vel eininga di frå lista ovanfor.","gui.connection.search":"Søk igjen","gui.connection.unavailable.installscratchlink":"Sjå til at du har installert og starta «Scratch Link»","gui.connection.unavailable.enablebluetooth":"Sjå til at Bluetooth-støtte er slått på","gui.connection.unavailable.tryagainbutton":"Prøv på nytt","gui.connection.unavailable.helpbutton":"Hjelp","gui.controls.go":"Gå til","gui.controls.stop":"Stopp","gui.crashMessage.label":"Å nei! Noko gjekk gale.","gui.crashMessage.errorNumber":"Feilen vart logga med ID-en {errorId}","gui.crashMessage.reload":"Last på nytt","gui.customProcedures.myblockModalTitle":"Lag ein kloss","gui.customProcedures.addAnInputNumberText":"Legg til eit felt","gui.customProcedures.numberTextType":"tal eller tekst","gui.customProcedures.addAnInputBoolean":"Legg til eit felt","gui.customProcedures.booleanType":"logisk verdi","gui.customProcedures.addALabel":"Legg til tekst","gui.customProcedures.runWithoutScreenRefresh":"Køyr utan å oppdatera skjermen","gui.customProcedures.cancel":"Avbryt","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Retning","gui.directionPicker.rotationStyles.allAround":"Roter fritt","gui.directionPicker.rotationStyles.leftRight":"Venstre–høgre","gui.directionPicker.rotationStyles.dontRotate":"Ikkje roter","gui.gui.addExtension":"Hent tilleggsfunksjon","gui.gui.codeTab":"Kode","gui.gui.backdropsTab":"Bakgrunnar","gui.gui.costumesTab":"Drakter","gui.gui.soundsTab":"Lydar","gui.extensionLibrary.comingSoon":"Er rett rundt hjørnet","gui.extensionLibrary.requires":"Utstyrskrav","gui.extensionLibrary.collaboration":"Samarbeid med","gui.library.filterPlaceholder":"Søk","gui.library.allTag":"Alle","gui.loader.headline":"Les inn prosjekt","gui.loader.creating":"Opprettar prosjekt","gui.authorInfo.byUser":"av {username}","gui.menuBar.seeProjectPage":"Sjå prosjektsida","gui.menuBar.LanguageSelector":"språkval","gui.menuBar.tutorialsLibrary":"Innføringar","gui.menuBar.restoreSprite":"Angra sletting av figur","gui.menuBar.restoreSound":"Angra sletting av lyd","gui.menuBar.restoreCostume":"Angra sletting av drakt","gui.menuBar.restore":"Angra sletting","gui.menuBar.saveNow":"Lagra no","gui.menuBar.saveAsCopy":"Lagra som kopi","gui.menuBar.remix":"Remiks","gui.menuBar.new":"Ny","gui.menuBar.file":"Fil","gui.menuBar.downloadToComputer":"Lagra til datamaskina","gui.menuBar.edit":"Rediger","gui.menuBar.turboModeOff":"Slå av turbofart","gui.menuBar.turboModeOn":"Slå på turbofart","gui.gui.projectTitlePlaceholder":"Namn på prosjektet","gui.menuBar.isShared":"Lagt ut","gui.menuBar.share":"Legg ut","gui.modal.help":"Hjelp","gui.modal.back":"Tilbake","gui.monitor.listMonitor.empty":"(tom)","gui.monitor.listMonitor.listLength":"lengd {length}","gui.monitor.contextMenu.default":"vanleg skrift","gui.monitor.contextMenu.large":"stor skrift","gui.monitor.contextMenu.slider":"glidebrytar","gui.monitor.contextMenu.sliderRange":"endra verdiområde","gui.monitor.contextMenu.import":"importer","gui.monitor.contextMenu.export":"eksporter","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Spel av","gui.playButton.stop":"Stopp","gui.gui.variableScopeOptionAllSprites":"For alle figurar","gui.gui.variableScopeOptionSpriteOnly":"For denne figuren","gui.gui.cloudVariableOption":"Nettvariabel (lagra på Scratch-nettstaden)","gui.gui.variablePromptAllSpritesMessage":"Variabelen vert tilgjengelege for alle figurane.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Avbryt","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Stopp","gui.playbackStep.playMsg":"Spel av","gui.playbackStep.loadingMsg":"Les inn …","gui.playbackStep.saveMsg":"Lagra","gui.playbackStep.reRecordMsg":"Spel inn på nytt","gui.recordModal.title":"Spel inn lyd","gui.recordingStep.beginRecord":"Trykk på knappen nedanfor for å starta opptak","gui.recordingStep.permission":"{arrow}Du må gje Scratch løyve til å bruka mikrofonen","gui.recordingStep.stop":"Stopp opptak","gui.recordingStep.record":"Spel inn","gui.sliderModal.min":"Minste verdi","gui.sliderModal.max":"Største verdi","gui.sliderModal.title":"Endra verdiområde","gui.sliderPrompt.cancel":"Avbryt","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Lyd","gui.soundEditor.play":"Spel av","gui.soundEditor.stop":"Stopp","gui.soundEditor.copy":"Kopier","gui.soundEditor.paste":"Lim inn","gui.soundEditor.copyToNew":"Kopier til ny","gui.soundEditor.delete":"Slett","gui.soundEditor.save":"Lagra","gui.soundEditor.undo":"Angra","gui.soundEditor.redo":"Gjer om","gui.soundEditor.faster":"Raskare","gui.soundEditor.slower":"Saktare","gui.soundEditor.echo":"Ekko","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Høgare","gui.soundEditor.softer":"Lågare","gui.soundEditor.reverse":"Baklengs","gui.soundEditor.fadeOut":"Ton ut","gui.soundEditor.fadeIn":"Ton inn","gui.soundEditor.mute":"Demp","gui.SpriteInfo.spritePlaceholder":"Namn","gui.SpriteInfo.sprite":"Figur","gui.SpriteInfo.show":"Vis","gui.SpriteInfo.size":"Storleik","gui.spriteSelectorItem.contextMenuDuplicate":"lag ein kopi","gui.spriteSelectorItem.contextMenuExport":"eksporter","gui.spriteSelectorItem.contextMenuDelete":"slett","gui.spriteSelector.addSpriteFromLibrary":"Vel ein figur","gui.spriteSelector.addSpriteFromPaint":"Teikn","gui.spriteSelector.addSpriteFromSurprise":"Overrasking","gui.spriteSelector.addSpriteFromFile":"Last opp figur","gui.stageHeader.stageSizeLarge":"Byt til stor scene","gui.stageHeader.stageSizeSmall":"Byt til lita scene","gui.stageHeader.stageSizeFull":"Gå til fullskjerm","gui.stageHeader.stageSizeUnFull":"Gå ut av fullskjerm","gui.stageHeader.fullscreenControl":"Fullskjerm på/av","gui.spriteSelector.addBackdropFromLibrary":"Vel eit bakgrunnsbilete","gui.stageSelector.addBackdropFromPaint":"Teikn","gui.stageSelector.addBackdropFromSurprise":"Overrasking","gui.stageSelector.addBackdropFromFile":"Last opp bakgrunn","gui.stageSelector.stage":"Scene","gui.stageSelector.backdrops":"Bakgrunnar","gui.telemetryOptIn.label":"Send statistikk for å forbetra Scratch","gui.telemetryOptIn.body1":"Scratch-gruppa arbeider heile tida med å betre forstå korleis Scratch vert brukt. Du kan bidra inn her ved å la Scratch automatisk senda inn statistikk over korleis du brukar Scratch til Scratch-gruppa.","gui.telemetryOptIn.body2":"Informasjonen me samlar inn er blant anna kva språk du brukar Scartch på og kor ofte du brukar dei ulike klossane, samt ulike handlingar, som for eksempel lagring, opning og opplasting av prosjekt. Me samlar IKKJE inn personinformasjon. Sjå {privacyPolicyLink} for meir informasjon.","gui.telemetryOptIn.privacyPolicyLink":"personvernerklæringa vår","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Turbofart","gui.webglModal.label":"Nettlesaren din støttar ikkje WebGL","gui.webglModal.webgllink":"ikkje støttar WebGL","gui.costumeLibrary.chooseABackdrop":"Vel eit bakgrunnsbilete","gui.costumeLibrary.chooseACostume":"Vel ei drakt","gui.costumeTab.addBackdropFromLibrary":"Vel eit bakgrunnsbilete","gui.costumeTab.addCostumeFromLibrary":"Vel ei drakt","gui.costumeTab.addBlankCostume":"Teikn","gui.costumeTab.addSurpriseCostume":"Overrasking","gui.costumeTab.addFileBackdrop":"Last opp bakgrunn","gui.costumeTab.addFileCostume":"Last opp drakt","gui.extensionLibrary.chooseAnExtension":"Vel ein tilleggsfunksjon","gui.extensionLibrary.extensionUrl":"Skriv inn nettadressa til tilleggsfunksjonen","gui.monitors.importListColumnPrompt":"Kva kolonne vil du bruka (1–{numberOfColumns})?","gui.recordingStep.alertMsg":"Feil ved lydopptak","gui.soundLibrary.chooseASound":"Vel ein lyd","gui.soundTab.fileUploadSound":"Last opp ein lyd","gui.soundTab.surpriseSound":"Overrasking","gui.soundTab.recordSound":"Spel inn","gui.soundTab.addSoundFromLibrary":"Vel ein lyd","gui.spriteLibrary.chooseASprite":"Vel ein figur","gui.tipsLibrary.tutorials":"Vel ei innføring","gui.alerts.createsuccess":"Nytt prosjekt oppretta.","gui.alerts.createcopysuccess":"Lagra kopi av prosjektet.","gui.alerts.createremixsuccess":"Lagra remiks av prosjektet.","gui.alerts.creating":"Lagar nytt …","gui.alerts.creatingCopy":"Kopierer prosjekt …","gui.alerts.creatingRemix":"Remiksar prosjekt …","gui.alerts.creatingError":"Klarte ikkje oppretta prosjektet. Prøv på nytt!","gui.alerts.savingError":"Klarte ikkje lagra prosjektet.","gui.alerts.savesuccess":"Prosjektet vart lagra.","gui.alerts.saving":"Lagrar prosjekt …","gui.alerts.cloudInfo":"Merk at nettvariablar berre støttar tal, ikkje bokstavar eller symbol. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Lær meir.","gui.alerts.importing":"Importerer …","gui.defaultProject.variable":"min variabel","gui.extension.music.name":"Musikk","gui.extension.music.description":"Spel musikkinstrument.","gui.extension.pen.name":"Penn","gui.extension.pen.description":"Få figurane til å teikna.","gui.extension.videosensing.name":"Sansing med kamera","gui.extension.videosensing.description":"Oppdag rørsle med kameraet.","gui.extension.text2speech.name":"Tekst til tale","gui.extension.text2speech.description":"Lag prosjekt som snakkar.","gui.extension.translate.name":"Omsetjing","gui.extension.translate.description":"Set om tekst til mange språk.","gui.extension.makeymakey.description":"Bruk kva som helst som tastatur.","gui.extension.microbit.description":"Kopla prosjekta til den fysiske verda.","gui.extension.microbit.connectingMessage":"Koplar til","gui.extension.ev3.description":"Bygg interaktive robotar og maskiner.","gui.extension.ev3.connectingMessage":"Koplar til. Sjå til at PIN-koden på EV3-en er sett til 1234.","gui.extension.boost.description":"Gjer robotskapningar levande.","gui.extension.boost.connectingMessage":"Koplar til","gui.extension.wedo2.description":"Bygg med motorar og sensorar.","gui.extension.wedo2.connectingMessage":"Koplar til","gui.extension.gdxfor.description":"Sans skyving, trekking, rørsle og snurring.","gui.extension.gdxfor.connectingMessage":"Koplar til","gui.libraryTags.all":"Alle","gui.libraryTags.animals":"Dyr","gui.libraryTags.dance":"Dans","gui.libraryTags.effects":"Effektar","gui.libraryTags.fantasy":"Fantasi","gui.libraryTags.fashion":"Mote","gui.libraryTags.food":"Mat","gui.libraryTags.indoors":"Innandørs","gui.libraryTags.loops":"Musikksløyfer","gui.libraryTags.music":"Musikk","gui.libraryTags.notes":"Tonar","gui.libraryTags.outdoors":"Utandørs","gui.libraryTags.patterns":"Mønster","gui.libraryTags.people":"Menneske","gui.libraryTags.percussion":"Slaginstrument","gui.libraryTags.space":"Romfart","gui.libraryTags.sports":"Sport","gui.libraryTags.underwater":"Nede i havet","gui.libraryTags.voice":"Stemmer","gui.libraryTags.wacky":"Merkeleg","gui.libraryTags.animation":"Animasjonar","gui.libraryTags.art":"Kunst","gui.libraryTags.games":"Spel","gui.libraryTags.stories":"Forteljingar","gui.libraryTags.letters":"Bokstavar","gui.opcodeLabels.direction":"retning","gui.opcodeLabels.xposition":"x-posisjon","gui.opcodeLabels.yposition":"y-posisjon","gui.opcodeLabels.size":"storleik","gui.opcodeLabels.costumename":"draktnamn","gui.opcodeLabels.costumenumber":"draktnummer","gui.opcodeLabels.backdropname":"bakgrunnsnamn","gui.opcodeLabels.backdropnumber":"bakgrunnsnummer","gui.opcodeLabels.volume":"lydstyrke","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"svar","gui.opcodeLabels.loudness":"lydstyrke","gui.opcodeLabels.username":"brukarnamn","gui.opcodeLabels.year":"år","gui.opcodeLabels.month":"månad","gui.opcodeLabels.date":"dato","gui.opcodeLabels.dayofweek":"vekedag","gui.opcodeLabels.hour":"time","gui.opcodeLabels.minute":"minutt","gui.opcodeLabels.second":"sekund","gui.opcodeLabels.timer":"sekundklokke","gui.sharedMessages.backdrop":"bakgrunn{index}","gui.sharedMessages.costume":"drakt{index}","gui.sharedMessages.sprite":"Figur{index}","gui.sharedMessages.pop":"plopp","gui.sharedMessages.replaceProjectWarning":"Vil du byta ut innhaldet i gjeldande prosjekt?","gui.sharedMessages.loadFromComputerTitle":"Last opp frå datamaskina","boost.color.any":"vilkårleg farge","boost.color.black":"svart","boost.color.blue":"blå","boost.color.green":"grøn","boost.color.red":"raud","boost.color.white":"kvit","boost.color.yellow":"gul","boost.getMotorPosition":"posisjon til motor [MOTOR_REPORTER_ID]","boost.getTiltAngle":"hellingsvinkel [TILT_DIRECTION]","boost.motorDirection.backward":"mot klokka","boost.motorDirection.forward":"med klokka","boost.motorDirection.reverse":"baklengs","boost.motorOff":"slå av [MOTOR_ID]","boost.motorOn":"slå på [MOTOR_ID]","boost.motorOnFor":"slå på [MOTOR_ID] i [DURATION] sekund","boost.motorOnForRotation":"roter [MOTOR_ID] [ROTATION] omdreiingar","boost.seeingColor":"ser [COLOR] kloss?","boost.setLightHue":"set lysfargen til [HUE]","boost.setMotorDirection":"set motor [MOTOR_ID]-retning til [MOTOR_DIRECTION]","boost.setMotorPower":"set motor [MOTOR_ID]-fart til [POWER] %","boost.tiltDirection.any":"vilkårleg","boost.tiltDirection.down":"ned","boost.tiltDirection.left":"venstre","boost.tiltDirection.right":"høgre","boost.tiltDirection.up":"opp","boost.whenColor":"når [COLOR] kloss vert sett","boost.whenTilted":"ved helling [TILT_DIRECTION_ANY]","ev3.beepNote":"tonen [NOTE] i [TIME] sekund","ev3.buttonPressed":"knapp [PORT] trykt?","ev3.getBrightness":"lysstyrke","ev3.getDistance":"avstand","ev3.getMotorPosition":"posisjon til motor [PORT]","ev3.motorSetPower":"set styrken til motor [PORT] til [POWER] %","ev3.motorTurnClockwise":"snu motor [PORT] med klokka i [TIME] sekund","ev3.motorTurnCounterClockwise":"snu motor [PORT] mot klokka i [TIME] sekund","ev3.whenBrightnessLessThan":"når lysstyrken < [DISTANCE]","ev3.whenButtonPressed":"når knappen [PORT] er trykt","ev3.whenDistanceLessThan":"når avstanden < [DISTANCE]","gdxfor.getAcceleration":"akselerasjon [DIRECTION]","gdxfor.getForce":"kraft","gdxfor.getSpin":"rotasjonsfart [DIRECTION]","gdxfor.getTilt":"hellingsvinkel [TILT]","gdxfor.isFreeFalling":"i fritt fall?","gdxfor.isTilted":"heller [TILT]?","gdxfor.pulled":"trekt","gdxfor.pushed":"skubba","gdxfor.shaken":"rista","gdxfor.startedFalling":"starta å falla","gdxfor.tiltDirectionMenu.any":"vilkårleg","gdxfor.tiltDirectionMenu.back":"bakover","gdxfor.tiltDirectionMenu.front":"framover","gdxfor.tiltDirectionMenu.left":"venstre","gdxfor.tiltDirectionMenu.right":"høgre","gdxfor.turnedFaceDown":"framsida ned","gdxfor.turnedFaceUp":"framsida opp","gdxfor.whenForcePushedOrPulled":"når kraftsensoren vert [PUSH_PULL]","gdxfor.whenGesture":"når [GESTURE]","gdxfor.whenTilted":"ved helling [TILT]","makeymakey.downArrow":"pil ned","makeymakey.downArrowShort":"ned","makeymakey.leftArrow":"pil venstre","makeymakey.leftArrowShort":"venstre","makeymakey.rightArrow":"pil høgre","makeymakey.rightArrowShort":"høgre","makeymakey.spaceKey":"mellomrom","makeymakey.upArrow":"pil opp","makeymakey.upArrowShort":"opp","makeymakey.whenKeyPressed":"når [KEY] vert trykt","makeymakey.whenKeysPressedInOrder":"når [SEQUENCE] vert trykt i rekkjefølgje","microbit.buttonsMenu.any":"vilkårleg","microbit.clearDisplay":"tøm skjermen","microbit.defaultTextToDisplay":"Hei!","microbit.displaySymbol":"vis bilete [MATRIX]","microbit.displayText":"vis tekst [TEXT]","microbit.gesturesMenu.jumped":"hoppa","microbit.gesturesMenu.moved":"flytta","microbit.gesturesMenu.shaken":"rista","microbit.isButtonPressed":"[BTN]-knapp trykt?","microbit.isTilted":"helling [DIRECTION]?","microbit.pinStateMenu.off":"av","microbit.pinStateMenu.on":"på","microbit.tiltAngle":"hellingsvinkel [DIRECTION]","microbit.tiltDirectionMenu.any":"vilkårleg","microbit.tiltDirectionMenu.back":"bakover","microbit.tiltDirectionMenu.front":"framover","microbit.tiltDirectionMenu.left":"venstre","microbit.tiltDirectionMenu.right":"høgre","microbit.whenButtonPressed":"når [BTN]-knappen er trykt","microbit.whenGesture":"når [GESTURE]","microbit.whenPinConnected":"når kontakten [PIN] får signal","microbit.whenTilted":"ved helling [DIRECTION]","music.categoryName":"Musikk","music.changeTempo":"endra tempo med [TEMPO]","music.drumBass":"(2) Stortromme","music.drumBongo":"(13) Bongotromme","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Trepinnar","music.drumClosedHiHat":"(6) Lukka hihat","music.drumConga":"(14) Congatrommer","music.drumCowbell":"(11) Kubjøller","music.drumCrashCymbal":"(4) Krasjcymbal","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Handklapping","music.drumOpenHiHat":"(5) Open hihat","music.drumSideStick":"(3) Kantslag","music.drumSnare":"(1) Skarptromme","music.drumTambourine":"(7) Tamburin","music.drumTriangle":"(12) Triangel","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Trekloss","music.getTempo":"tempo","music.instrumentBass":"(6) Bass","music.instrumentBassoon":"(14) Fagott","music.instrumentCello":"(8) Cello","music.instrumentChoir":"(15) Kor","music.instrumentClarinet":"(10) Klarinett","music.instrumentElectricGuitar":"(5) Elektrisk gitar","music.instrumentElectricPiano":"(2) Elektrisk piano","music.instrumentFlute":"(12) Fløyte","music.instrumentGuitar":"(4) Gitar","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Speledåse","music.instrumentOrgan":"(3) Orgel","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saksofon","music.instrumentSteelDrum":"(18) Oljefat","music.instrumentSynthLead":"(20) Synthesizer (lead)","music.instrumentSynthPad":"(21) Synthesizer (pad)","music.instrumentTrombone":"(9) Trombone","music.instrumentVibraphone":"(16) Vibrafon","music.instrumentWoodenFlute":"(13) Trefløyte","music.midiPlayDrumForBeats":"trommeslag [DRUM] som varer i [BEATS] taktslag","music.midiSetInstrument":"bruk instrumentet [INSTRUMENT]","music.playDrumForBeats":"trommeslag [DRUM] som varer i [BEATS] taktslag","music.playNoteForBeats":"spel tonen [NOTE] i [BEATS] taktslag","music.restForBeats":"pause i [BEATS] taktslag","music.setInstrument":"bruk instrumentet [INSTRUMENT]","music.setTempo":"set tempo til [TEMPO]","pen.categoryName":"Penn","pen.changeColorParam":"endra pennens [COLOR_PARAM] med [VALUE]","pen.changeHue":"endra pennefarge med [HUE]","pen.changeShade":"endra penneskugge med [SHADE]","pen.changeSize":"endra pennebreidd med [SIZE]","pen.clear":"visk vekk alt","pen.colorMenu.brightness":"lysstyrke","pen.colorMenu.color":"farge","pen.colorMenu.saturation":"fargemetting","pen.colorMenu.transparency":"gjennomsikt","pen.penDown":"penn ned","pen.penUp":"penn opp","pen.setColor":"bruk pennefargen [COLOR]","pen.setColorParam":"set [COLOR_PARAM] til [VALUE]","pen.setHue":"bruk pennefargen [HUE]","pen.setShade":"set penneskugge til [SHADE]","pen.setSize":"set pennebreidd til [SIZE]","pen.stamp":"lag avtrykk","text2speech.alto":"alt","text2speech.categoryName":"Tekst til tale","text2speech.defaultTextToSpeak":"hei","text2speech.giant":"kjempe","text2speech.kitten":"kattunge","text2speech.setLanguageBlock":"set språket til [LANGUAGE]","text2speech.setVoiceBlock":"bruk stemmen [VOICE]","text2speech.speakAndWaitBlock":"les opp [WORDS]","text2speech.squeak":"pipestemme","text2speech.tenor":"tenor","translate.categoryName":"Omsetjing","translate.defaultTextToTranslate":"hei","translate.translateBlock":"set om [WORDS] til [LANGUAGE]","translate.viewerLanguage":"språk","videoSensing.categoryName":"Sansing med kamera","videoSensing.direction":"retning","videoSensing.motion":"rørsle","videoSensing.off":"av","videoSensing.on":"på","videoSensing.onFlipped":"spegelvend","videoSensing.setVideoTransparency":"set gjennomsikt av video til [TRANSPARENCY]","videoSensing.sprite":"figur","videoSensing.stage":"scene","videoSensing.videoOn":"video-[ATTRIBUTE] på [SUBJECT]","videoSensing.videoToggle":"set video [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"når videorørsle > [REFERENCE]","wedo2.getDistance":"avstand","wedo2.getTiltAngle":"hellingsvinkel [TILT_DIRECTION]","wedo2.isTilted":"helling [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"mot klokka","wedo2.motorDirection.forward":"med klokka","wedo2.motorDirection.reverse":"baklengs","wedo2.motorId.a":"motor A","wedo2.motorId.all":"alle motorar","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"slå av [MOTOR_ID]","wedo2.motorOn":"slå på [MOTOR_ID]","wedo2.motorOnFor":"slå på [MOTOR_ID] i [DURATION] sekund","wedo2.playNoteFor":"spel tonen [NOTE] i [DURATION] sekund","wedo2.setLightHue":"set lysfargen til [HUE]","wedo2.setMotorDirection":"set [MOTOR_ID]-retninga til [MOTOR_DIRECTION]","wedo2.startMotorPower":"set [MOTOR_ID]-styrken til [POWER]","wedo2.tiltDirection.any":"vilkårleg","wedo2.tiltDirection.down":"ned","wedo2.tiltDirection.left":"venstre","wedo2.tiltDirection.right":"høgre","wedo2.tiltDirection.up":"opp","wedo2.whenDistance":"når avstanden [OP] [REFERENCE]","wedo2.whenTilted":"ved helling [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Farge","paint.paintEditor.saturation":"Fargemetting","paint.paintEditor.brightness":"Lysstyrke","paint.paintEditor.costume":"Drakt","paint.paintEditor.group":"Lag gruppe","paint.paintEditor.ungroup":"Løys opp gruppe","paint.paintEditor.undo":"Angra","paint.paintEditor.redo":"Gjer om","paint.paintEditor.forward":"Framover","paint.paintEditor.backward":"Bakover","paint.paintEditor.front":"Heilt fram","paint.paintEditor.back":"Heilt bak","paint.paintEditor.more":"Fleire","paint.modeTools.brushSize":"Storleik","paint.modeTools.eraserSize":"Viskelêrstorleik","paint.modeTools.copy":"Kopier","paint.modeTools.paste":"Lim inn","paint.modeTools.delete":"Slett","paint.modeTools.curved":"Glatt","paint.modeTools.pointed":"Spiss","paint.modeTools.thickness":"Strekbreidd","paint.modeTools.flipHorizontal":"Spegelvend","paint.modeTools.flipVertical":"Opp ned","paint.modeTools.filled":"Fylt","paint.modeTools.outlined":"Omriss","paint.paintEditor.bitmap":"Gjer om til punktgrafikk","paint.paintEditor.vector":"Gjer om til vektorgrafikk","paint.paintEditor.fill":"Fyll","paint.paintEditor.stroke":"Kantlinje","paint.brushMode.brush":"Målarpensel","paint.eraserMode.eraser":"Viskelêr","paint.fillMode.fill":"Fyll","paint.lineMode.line":"Linje","paint.ovalMode.oval":"Sirkel","paint.rectMode.rect":"Rektangel","paint.reshapeMode.reshape":"Endra form","paint.roundedRectMode.roundedRect":"Avrunda rektangel","paint.selectMode.select":"Vel","paint.textMode.text":"Tekst","paint.colorPicker.swap":"Byt"},"oc":{"gui.alerts.tryAgain":"Tornar ensajar","gui.alerts.download":"Telecargar","gui.connection.reconnect":"Torna connectar","gui.backpack.costumeLabel":"costum","gui.backpack.soundLabel":"son","gui.backpack.scriptLabel":"escript","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Sac d\'esquina","gui.backpack.errorBackpack":"Error del cargament de la saca d\'esquina","gui.backpack.loadingBackpack":"Cargament...","gui.backpack.more":"Mai","gui.backpack.emptyBackpack":"La saca d\'esquina es vuèja","gui.unsupportedBrowser.label":"Navigator pas suportat","gui.cards.all-tutorials":"Tutorials","gui.cards.shrink":"Redusir","gui.cards.expand":"Espandir","gui.cards.close":"Tampar","gui.cards.more-things-to-try":"Mai de causas d\'ensajar !","gui.cards.see-more":"Veire mai","gui.comingSoon.message1":"Te\'n fagas pas, nos en tracham ! {emoji}","gui.comingSoon.message2":"Arriba lèu...","gui.comingSoon.message3":"Sèm a i trabalhar {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Cap de periferic pas trobat","gui.connection.auto-scanning.prescan":"Sarra ton aparelh, puèi comença la cerca.","gui.connection.auto-scanning.pressbutton":"Premsa lo boton sus ton aparelh.","gui.connection.auto-scanning.start-search":"Començar de cercar","gui.connection.connecting-searchbutton":"Recèrca...","gui.connection.auto-scanning.try-again":"Tornar ensajar","gui.connection.connected":"Connectat","gui.connection.disconnect":"Desconnectar","gui.connection.go-to-editor":"Anar al Editor","gui.connection.connecting-cancelbutton":"Connexion...","gui.connection.error.errorMessage":"Nifle, sembla que quicòm se passèt mal.","gui.connection.error.tryagainbutton":"Tornar ensajar","gui.connection.error.helpbutton":"Ajuda","gui.connection.peripheral-name-label":"Nom del periferic","gui.connection.connect":"Connectar","gui.connection.scanning.lookingforperipherals":"A cercar de periferics","gui.connection.scanning.noPeripheralsFound":"Cap de periferic pas trobat","gui.connection.scanning.instructions":"Selecciona ton periferic dins la tièra aquí-dessús.","gui.connection.search":"Refrescar","gui.connection.unavailable.installscratchlink":"Assegura-te d\'aver lo ligam Scratch Link installat e en foncionament.","gui.connection.unavailable.enablebluetooth":"Verifica que lo Bluetooth es activat.","gui.connection.unavailable.tryagainbutton":"Tornar ensajar","gui.connection.unavailable.helpbutton":"Ajuda","gui.controls.go":"Anar","gui.controls.stop":"Arrestar","gui.crashMessage.label":"Nifle ! Quicòm se passèt mal.","gui.crashMessage.errorNumber":"La tieuna error foguèt registrada amb l\'id {errorId}","gui.crashMessage.reload":"Tornar cargar","gui.customProcedures.myblockModalTitle":"Fargar un blòc","gui.customProcedures.addAnInputNumberText":"Apondre una entrada","gui.customProcedures.numberTextType":"nombre o tèxt","gui.customProcedures.addAnInputBoolean":"Apondre una entrada","gui.customProcedures.booleanType":"boolean","gui.customProcedures.addALabel":"Apondre una etiqueta","gui.customProcedures.runWithoutScreenRefresh":"Aviar sens refrescar l\'ecran","gui.customProcedures.cancel":"Anullar","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Direccion","gui.directionPicker.rotationStyles.allAround":"Tot a l\'entorn","gui.directionPicker.rotationStyles.leftRight":"Esquèrra/Drecha","gui.directionPicker.rotationStyles.dontRotate":"De virar pas","gui.gui.addExtension":"Apondre Extension","gui.gui.codeTab":"Còdi","gui.gui.backdropsTab":"Fons","gui.gui.costumesTab":"Costums","gui.gui.soundsTab":"Sons","gui.extensionLibrary.comingSoon":"D\'arribar lèu","gui.extensionLibrary.requires":"Necessita","gui.extensionLibrary.collaboration":"Collaboracion amb","gui.library.filterPlaceholder":"Cercar","gui.library.allTag":"Tot","gui.loader.headline":"A cargar lo Projècte","gui.loader.creating":"A crear lo projècte","gui.authorInfo.byUser":"per {username}","gui.menuBar.seeProjectPage":"Veire la pagina del projècte","gui.menuBar.LanguageSelector":"Selector de lenga","gui.menuBar.tutorialsLibrary":"Tutorials","gui.menuBar.restoreSprite":"Restaurar Sprite","gui.menuBar.restoreSound":"Restaurar Son","gui.menuBar.restoreCostume":"Restaurar Costum","gui.menuBar.restore":"Restaurar","gui.menuBar.saveNow":"Enregistrar ara","gui.menuBar.saveAsCopy":"Enesgistrar coma còpia","gui.menuBar.remix":"Remix","gui.menuBar.new":"Nòu","gui.menuBar.file":"Fichièr","gui.menuBar.downloadToComputer":"Enregistra sus ton ordinator","gui.menuBar.edit":"Editar","gui.menuBar.turboModeOff":"Atudar lo Mode Turbo","gui.menuBar.turboModeOn":"Alucar lo Mòde Turbo","gui.gui.projectTitlePlaceholder":"Titol del projècte aquí","gui.menuBar.isShared":"Partejat","gui.menuBar.share":"Partejar","gui.modal.help":"Ajuda","gui.modal.back":"Endarrièr","gui.monitor.listMonitor.empty":"(void)","gui.monitor.listMonitor.listLength":"longor {length}","gui.monitor.contextMenu.default":"lectura normala","gui.monitor.contextMenu.large":"lectura bèla","gui.monitor.contextMenu.slider":"cursor","gui.monitor.contextMenu.sliderRange":"cambiar l\'espandi del cursor","gui.monitor.contextMenu.import":"importar","gui.monitor.contextMenu.export":"exportar","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Jogar","gui.playButton.stop":"Arrestar","gui.gui.variableScopeOptionAllSprites":"Per totas las sprites","gui.gui.variableScopeOptionSpriteOnly":"Sonque per aquela sprite","gui.gui.cloudVariableOption":"Variabla de Cloud (estocada sul servidor)","gui.gui.variablePromptAllSpritesMessage":"Aquela variabla serà disponibla a totas las sprites","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Anullar","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Arrestar","gui.playbackStep.playMsg":"Jogar","gui.playbackStep.loadingMsg":"Cargament...","gui.playbackStep.saveMsg":"Enregistrar","gui.playbackStep.reRecordMsg":"Tornar enregistrar","gui.recordModal.title":"Enregistrar son","gui.recordingStep.beginRecord":"Començar d\'enregistrar en clicant sul boton aquí dejos","gui.recordingStep.permission":"{arrow}Necessitam la tieuna permission per utilizar lo microfòn","gui.recordingStep.stop":"Arrestar d\'enregistrar","gui.recordingStep.record":"Enregistrar","gui.sliderModal.min":"Valor minimala","gui.sliderModal.max":"Valor maximal","gui.sliderModal.title":"Cambiar l\'espandi del cursor","gui.sliderPrompt.cancel":"Anullar","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Son","gui.soundEditor.play":"Jogar","gui.soundEditor.stop":"Arrestar","gui.soundEditor.copy":"Copiar","gui.soundEditor.paste":"Pegar","gui.soundEditor.copyToNew":"Copiar cap a novèl","gui.soundEditor.delete":"Escafar","gui.soundEditor.save":"Enregistrar","gui.soundEditor.undo":"Anullar","gui.soundEditor.redo":"Tornar far","gui.soundEditor.faster":"Mai lèu","gui.soundEditor.slower":"Mens lèu","gui.soundEditor.echo":"Resson","gui.soundEditor.robot":"Robòt","gui.soundEditor.louder":"Mai fòrt","gui.soundEditor.softer":"Mai dòç","gui.soundEditor.reverse":"Endarrèr","gui.soundEditor.fadeOut":"Fondut entrant","gui.soundEditor.fadeIn":"Fondut sortent","gui.soundEditor.mute":"Silenciós","gui.SpriteInfo.spritePlaceholder":"Nom","gui.SpriteInfo.sprite":"Sprite","gui.SpriteInfo.show":"Mostrar","gui.SpriteInfo.size":"Talha","gui.spriteSelectorItem.contextMenuDuplicate":"desdoblar","gui.spriteSelectorItem.contextMenuExport":"exportar","gui.spriteSelectorItem.contextMenuDelete":"escafar","gui.spriteSelector.addSpriteFromLibrary":"Causir a Sprite","gui.spriteSelector.addSpriteFromPaint":"Pintrar","gui.spriteSelector.addSpriteFromSurprise":"Suspresa","gui.spriteSelector.addSpriteFromFile":"Cargar Sprite","gui.stageHeader.stageSizeLarge":"Cambiar per una scèna bèla","gui.stageHeader.stageSizeSmall":"Cambiar per una scèna petita","gui.stageHeader.stageSizeFull":"Passar en mòde plen ecran","gui.stageHeader.stageSizeUnFull":"Quitar lo mòde plen ecran","gui.stageHeader.fullscreenControl":"Contraròtle del plen ecran","gui.spriteSelector.addBackdropFromLibrary":"Causir un fons","gui.stageSelector.addBackdropFromPaint":"Pintrar","gui.stageSelector.addBackdropFromSurprise":"Suspresa","gui.stageSelector.addBackdropFromFile":"Cargar un fons","gui.stageSelector.stage":"Scèna","gui.stageSelector.backdrops":"Fons","gui.telemetryOptIn.label":"Reportar las estatisticas per melhorar Scratch.","gui.telemetryOptIn.body1":"L\'Equipa Scratch es totjorn a cercar de comprene melhor l\'utilizacion de Scrach dins lo mond. Per ajudar aquel esfòrç, pòdes autorizar Scratch de mandar automaticament d\'informacions d\'utilizacion a l\'Equipa Scratch.","gui.telemetryOptIn.body2":"Las informacions que collectam compren la lenga utilizada, l\'utilizacion dels blòcs, e qualques eveniments tal coma enregistrar, cargar e partejar un projècte. Collectam PAS d\'informacions personalas. Pòdes legir nòstra {privacyPolicyLink} per mai d\'informacions.","gui.telemetryOptIn.privacyPolicyLink":"Politica de confidencialitat","gui.telemetryOptIn.optInText":"Partejar mas donadas d\'utilizacion amb l\'Equipa de Scratch","gui.telemetryOptIn.optInTooltip":"Activar la telemetria","gui.telemetryOptIn.optOutText":"De partejar pas mas donadas d\'utilizacion amb l\'Equipa Scratch","gui.telemetryOptIn.optOutTooltip":"Descativar la telemetria","gui.telemetryOptIn.settingWasUpdated":"Tos reglatges foguèron meses a jorn.","gui.telemetryOptIn.buttonClose":"Tampar","gui.turboMode.active":"Mòde Turbo","gui.webglModal.label":"Lo tèu navigator supòrta pas WebGL","gui.webglModal.webgllink":"Supòrta pas WebGL","gui.costumeLibrary.chooseABackdrop":"Causir fons","gui.costumeLibrary.chooseACostume":"Causir un Costum","gui.costumeTab.addBackdropFromLibrary":"Causir fons","gui.costumeTab.addCostumeFromLibrary":"Causir un Costum","gui.costumeTab.addBlankCostume":"Pintrar","gui.costumeTab.addSurpriseCostume":"Suspresa","gui.costumeTab.addFileBackdrop":"Cargar un fons","gui.costumeTab.addFileCostume":"Cargar un Costum","gui.extensionLibrary.chooseAnExtension":"Causir una extension","gui.extensionLibrary.extensionUrl":"Dintrar l\'URL de l\'extension","gui.monitors.importListColumnPrompt":"Quina colomna se deu utilizar (1-{numberOfColumns}) ?","gui.recordingStep.alertMsg":"Posquèt pas començar l\'enregistrament","gui.soundLibrary.chooseASound":"Causir un son","gui.soundTab.fileUploadSound":"Cargar un son","gui.soundTab.surpriseSound":"Suspresa","gui.soundTab.recordSound":"Enregistrar","gui.soundTab.addSoundFromLibrary":"Causir un son","gui.spriteLibrary.chooseASprite":"Causís a Sprite","gui.tipsLibrary.tutorials":"Causir un Tutorial","gui.alerts.createsuccess":"Novèl projècte creat.","gui.alerts.createcopysuccess":"Projècte enregistrat coma un còpia.","gui.alerts.createremixsuccess":"Projècte enregistrat coma un remix.","gui.alerts.creating":"A crear un novèl...","gui.alerts.creatingCopy":"A copiar lo projècte...","gui.alerts.creatingRemix":"A remixar lo projècte...","gui.alerts.creatingError":"Posquèt pas crear lo projècte. Torna ensajar stp !","gui.alerts.savingError":"Lo projècte se posquèt pas enregistrar","gui.alerts.savesuccess":"Projècte enregistrar","gui.alerts.saving":"A enregistrar lo projècte","gui.alerts.cloudInfo":"Vòlga plan notar, las variablas de cloud supòrtan pas que los nombres, pas de letras nimai de simbòls. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"N\'aprene mai.","gui.alerts.importing":"A importar...","gui.defaultProject.variable":"ma variabla","gui.extension.music.name":"Musica","gui.extension.music.description":"Jogar d\'Instruments e Percussions","gui.extension.pen.name":"Estilò","gui.extension.pen.description":"Dessenha amb tas Sprites","gui.extension.videosensing.name":"Percepcion de Video","gui.extension.videosensing.description":"Percebre de Moviment amb la Camèra","gui.extension.text2speech.name":"Escriches de Dire","gui.extension.text2speech.description":"Fa Parlar tos Projèctes","gui.extension.translate.name":"Revirar","gui.extension.translate.description":"Revirar lo text dins mantuna lenga","gui.extension.makeymakey.description":"Tot Far coma una toca.","gui.extension.microbit.description":"Connecta tos projèctes al mond.","gui.extension.microbit.connectingMessage":"A se connectar","gui.extension.ev3.description":"Bastir de robòts interactiu e mai.","gui.extension.ev3.connectingMessage":"A se connectar. Assegura-te que lo pin de ton EV3 es reglat sus 1234.","gui.extension.boost.description":"Balha vida a tas creations roboticas.","gui.extension.boost.connectingMessage":"A se connectar","gui.extension.wedo2.description":"Bastís amb motors e captors.","gui.extension.wedo2.connectingMessage":"A se connectar","gui.extension.gdxfor.description":"Percep butar, tirar, moviment e rotacion.","gui.extension.gdxfor.connectingMessage":"A se connectar","gui.libraryTags.all":"Tot","gui.libraryTags.animals":"Animals","gui.libraryTags.dance":"Dança","gui.libraryTags.effects":"Efièches","gui.libraryTags.fantasy":"Fantasia","gui.libraryTags.fashion":"Mòda","gui.libraryTags.food":"Noiridura","gui.libraryTags.indoors":"Interiors","gui.libraryTags.loops":"Boclas","gui.libraryTags.music":"Musica","gui.libraryTags.notes":"Nòtas","gui.libraryTags.outdoors":"Exteriors","gui.libraryTags.patterns":"Motius","gui.libraryTags.people":"Gents","gui.libraryTags.percussion":"Percussion","gui.libraryTags.space":"Espaci","gui.libraryTags.sports":"Espòrts","gui.libraryTags.underwater":"Josmarin","gui.libraryTags.voice":"Votz","gui.libraryTags.wacky":"Folastre","gui.libraryTags.animation":"Animacion","gui.libraryTags.art":"rt","gui.libraryTags.games":"Jòcs","gui.libraryTags.stories":"Istòrias","gui.libraryTags.letters":"Letras","gui.opcodeLabels.direction":"direccion","gui.opcodeLabels.xposition":"posicion x","gui.opcodeLabels.yposition":"posicion y","gui.opcodeLabels.size":"talha","gui.opcodeLabels.costumename":"nom del costum","gui.opcodeLabels.costumenumber":"numèro del costum","gui.opcodeLabels.backdropname":"nom del fons","gui.opcodeLabels.backdropnumber":"numèro del fons","gui.opcodeLabels.volume":"volum","gui.opcodeLabels.tempo":"tempò","gui.opcodeLabels.answer":"responsa","gui.opcodeLabels.loudness":"intensitat","gui.opcodeLabels.username":"nom d\'utilizator","gui.opcodeLabels.year":"annada","gui.opcodeLabels.month":"mes","gui.opcodeLabels.date":"data","gui.opcodeLabels.dayofweek":"jorn de la setmana","gui.opcodeLabels.hour":"ora","gui.opcodeLabels.minute":"minuta","gui.opcodeLabels.second":"segonda","gui.opcodeLabels.timer":"minutor","gui.sharedMessages.backdrop":"fons{index}","gui.sharedMessages.costume":"costum{index}","gui.sharedMessages.sprite":"Sprite{index}","gui.sharedMessages.pop":"pòp","gui.sharedMessages.replaceProjectWarning":"Remplaçar los contenguts del projècte en cors ?","gui.sharedMessages.loadFromComputerTitle":"Carga a partir ton ordenador","boost.color.any":"quina color que siá","boost.color.black":"negre","boost.color.blue":"blau","boost.color.green":"verd","boost.color.red":"roge","boost.color.white":"blanc","boost.color.yellow":"jaune","boost.getMotorPosition":"posicion del motor [MOTOR_REPORTER_ID] ","boost.getTiltAngle":"Anle d\'enclinason [TILT_DIRECTION]","boost.motorDirection.backward":"per aquí","boost.motorDirection.forward":"per ailà","boost.motorDirection.reverse":"endarrièr","boost.motorOff":"atudar lo motor [MOTOR_ID]","boost.motorOn":"alucar lo motor [MOTOR_ID]","boost.motorOnFor":"Alucar lo motor [MOTOR_ID] pendent [DURATION] segondas","boost.motorOnForRotation":"Alucar lo motor [MOTOR_ID] pendent [ROTATION] rotacions","boost.seeingColor":"A veire la brica [COLOR] ?","boost.setLightHue":"reglar la color del lum sus [HUE]","boost.setMotorDirection":"Reglar la direccion del motor [MOTOR_ID] sus [MOTOR_DIRECTION]","boost.setMotorPower":"Reglar la velocitat del motor [MOTOR_ID] sus [POWER] %","boost.tiltDirection.any":"quin que siá","boost.tiltDirection.down":"enbàs","boost.tiltDirection.left":"esquèrra","boost.tiltDirection.right":"drecha","boost.tiltDirection.up":"ennaut","boost.whenColor":"quand la brica de color [COLOR] es vista","boost.whenTilted":"quand clinat [TILT_DIRECTION_ANY]","ev3.beepNote":"tindar la nòta [NOTE] pendent [TIME] s.","ev3.buttonPressed":"boton [PORT] premsat ?","ev3.getBrightness":"luminositat","ev3.getDistance":"distància","ev3.getMotorPosition":"posicion del motor [PORT]","ev3.motorSetPower":"Poténcia del motor [PORT] reglat a [POWER] %","ev3.motorTurnClockwise":"Motor [PORT] virant per aquí pendent [TIME] segondas","ev3.motorTurnCounterClockwise":"Motor [PORT] virant per ailà pendent [TIME] segondas","ev3.whenBrightnessLessThan":"quand la luminositat < [DISTANCE]","ev3.whenButtonPressed":"quand lo boton [PORT] es premsat","ev3.whenDistanceLessThan":"quand la distància < [DISTANCE]","gdxfor.getAcceleration":"acceleracion [DIRECTION]","gdxfor.getForce":"fòrça","gdxfor.getSpin":"Velocitat de rotacion [DIRECTION]","gdxfor.getTilt":"Angle d\'enclinason [TILT]","gdxfor.isFreeFalling":"A tombar ?","gdxfor.isTilted":"clinat [TILT] ?","gdxfor.pulled":"tirat ?","gdxfor.pushed":"butat?","gdxfor.shaken":"brandit","gdxfor.startedFalling":"a començat de tombar","gdxfor.tiltDirectionMenu.any":"quin que siá","gdxfor.tiltDirectionMenu.back":"darrièr","gdxfor.tiltDirectionMenu.front":"davant","gdxfor.tiltDirectionMenu.left":"esquèrra","gdxfor.tiltDirectionMenu.right":"drecha","gdxfor.turnedFaceDown":"virat fàcia enbas","gdxfor.turnedFaceUp":"virat fàcia ennaut","gdxfor.whenForcePushedOrPulled":"quand lo captor de fòrça [PUSH_PULL]","gdxfor.whenGesture":"quand [GESTURE]","gdxfor.whenTilted":"quand clinat [TILT]","makeymakey.downArrow":"sageta bas","makeymakey.downArrowShort":"enbàs","makeymakey.leftArrow":"sageta esquèrra","makeymakey.leftArrowShort":"esquèrra","makeymakey.rightArrow":"sageta drecha","makeymakey.rightArrowShort":"drecha","makeymakey.spaceKey":"espaci","makeymakey.upArrow":"sageta naut","makeymakey.upArrowShort":"ennaut","makeymakey.whenKeyPressed":"quand la toca [KEY] es premsada","makeymakey.whenKeysPressedInOrder":"quand [SEQUENCE] son premsadas dins l\'òrdre","microbit.buttonsMenu.any":"quin que siá","microbit.clearDisplay":"escafar l\'ecran","microbit.defaultTextToDisplay":"Adieu !","microbit.displaySymbol":"afichar [MATRIX]","microbit.displayText":"afichar lo tèxt [TEXT]","microbit.gesturesMenu.jumped":"sautat","microbit.gesturesMenu.moved":"bolegat","microbit.gesturesMenu.shaken":"brandit","microbit.isButtonPressed":"boton [BTN] premsat ?","microbit.isTilted":"clinat [DIRECTION] ?","microbit.pinStateMenu.off":"off","microbit.pinStateMenu.on":"on","microbit.tiltAngle":"enclinason [DIRECTION]","microbit.tiltDirectionMenu.any":"Quin que siá","microbit.tiltDirectionMenu.back":"darrièr","microbit.tiltDirectionMenu.front":"davant","microbit.tiltDirectionMenu.left":"esquèrra","microbit.tiltDirectionMenu.right":"drecha","microbit.whenButtonPressed":"quand lo boton [BTN] es premsat","microbit.whenGesture":"quand [GESTURE]","microbit.whenPinConnected":"quand lo pin [PIN] es connectat","microbit.whenTilted":"qaund clinat [DIRECTION]","music.categoryName":"Musica","music.changeTempo":"cambiar lo tempò per [TEMPO]","music.drumBass":"(2) Caissa gròssa","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) Charleston tampada","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Sonalha","music.drumCrashCymbal":"(4) Cimbala Crash","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Trucamans","music.drumOpenHiHat":"(5) Charleston","music.drumSideStick":"(3) Baston de costat","music.drumSnare":"(1) Caissa clara","music.drumTambourine":"(7) Tamborin","music.drumTriangle":"(12) Triangle","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Blòc de fusta","music.getTempo":"tempò","music.instrumentBass":"(6) Bassa","music.instrumentBassoon":"(14) Basson","music.instrumentCello":"(8) Violoncèl","music.instrumentChoir":"(15) Corala","music.instrumentClarinet":"(10) Clarineta","music.instrumentElectricGuitar":"(5) Guitara Electrica","music.instrumentElectricPiano":"(2) Pianò Electric ","music.instrumentFlute":"(12) Flauta","music.instrumentGuitar":"(4) Guitara","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Boita de musica","music.instrumentOrgan":"(3) Òrgue","music.instrumentPiano":"(1) Pianò","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxofòn","music.instrumentSteelDrum":"(18) Tonèl d\'acièr","music.instrumentSynthLead":"(20) Synth Lead","music.instrumentSynthPad":"(21) Synth Pad","music.instrumentTrombone":"(9) Trombòn","music.instrumentVibraphone":"(16) Vibrafòn","music.instrumentWoodenFlute":"(13) Flauta de fusta","music.midiPlayDrumForBeats":"jogar la percussion [DRUM] pendent [BEATS] pulsacions","music.midiSetInstrument":"reglar l\'instrument sus [INSTRUMENT] ","music.playDrumForBeats":"jogar la percussion [DRUM] al batèc [BEATS]","music.playNoteForBeats":"jogar la nòta [NOTE] pendent [BEATS] pulsacions","music.restForBeats":"pausa pendent [BEATS] pulsacions","music.setInstrument":"reglar l\'instrument sus [INSTRUMENT] ","music.setTempo":"reglar lo tempò sus [TEMPO]","pen.categoryName":"Estilò","pen.changeColorParam":"cambiar [COLOR_PARAM] del estilò per [VALUE]","pen.changeHue":"cambiar la color del estilò per [HUE]","pen.changeShade":"cambiar la nuança del estilò per [SHADE]","pen.changeSize":"cambiar la talha del estilò per [SIZE]","pen.clear":"escafar tot","pen.colorMenu.brightness":"luminositat","pen.colorMenu.color":"amagar totes las sprites","pen.colorMenu.saturation":"saturacion","pen.colorMenu.transparency":"transparéncia","pen.penDown":"estilò pausat","pen.penUp":"estilò levat","pen.setColor":"reglar la color de l\'estilò sus [COLOR]","pen.setColorParam":"reglar [COLOR_PARAM] del estilò per [VALUE]","pen.setHue":"reglar la color del estilò per [HUE]","pen.setShade":"reglar la nuança del estilò per [SHADE]","pen.setSize":"reglar la talha del estilò per [SIZE]","pen.stamp":"sagel","text2speech.alto":"alto","text2speech.categoryName":"Escriches de Dire","text2speech.defaultTextToSpeak":"Adieu","text2speech.giant":"gigant","text2speech.kitten":"gaton","text2speech.setLanguageBlock":"reglar la lenga sus [LANGUAGE]","text2speech.setVoiceBlock":"reglar la votz sus [VOICE]","text2speech.speakAndWaitBlock":"dire [WORDS]","text2speech.squeak":"coïnar","text2speech.tenor":"tenor","translate.categoryName":"Revirar","translate.defaultTextToTranslate":"adieu","translate.translateBlock":"traduire [WORDS] en [LANGUAGE]","translate.viewerLanguage":"lenga","videoSensing.categoryName":"Percepcion de Video","videoSensing.direction":"direccion","videoSensing.motion":"moviment","videoSensing.off":"off","videoSensing.on":"on","videoSensing.onFlipped":"on flipped","videoSensing.setVideoTransparency":"reglar la transparéncia sus [TRANSPARENCY]","videoSensing.sprite":"sprite","videoSensing.stage":"scèna","videoSensing.videoOn":"[ATTRIBUTE] de la vidèo sus [SUBJECT]","videoSensing.videoToggle":"Comutar la video sus [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"quand lo moviment de video > [REFERENCE]","wedo2.getDistance":"distància","wedo2.getTiltAngle":"Anle d\'enclinason [TILT_DIRECTION]","wedo2.isTilted":"clinat [TILT_DIRECTION_ANY] ?","wedo2.motorDirection.backward":"per aquí","wedo2.motorDirection.forward":"per ailà","wedo2.motorDirection.reverse":"endarrièr","wedo2.motorId.a":"motor A","wedo2.motorId.all":"totes los motors","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"Atudar lo motor [MOTOR_ID] ","wedo2.motorOn":"Alucar lo motor [MOTOR_ID]","wedo2.motorOnFor":"Alucar lo motor [MOTOR_ID] pendent [DURATION] segondas","wedo2.playNoteFor":"jogar la nòta [NOTE] pendent [DURATION] segondas","wedo2.setLightHue":"reglar la color del lum sus [HUE]","wedo2.setMotorDirection":"reglar la direccion del motor [MOTOR_ID] cap a [MOTOR_DIRECTION]","wedo2.startMotorPower":"reglar la poténcia del motor [MOTOR_ID] sus [POWER]","wedo2.tiltDirection.any":"quin que siá","wedo2.tiltDirection.down":"enbàs","wedo2.tiltDirection.left":"esquèrra","wedo2.tiltDirection.right":"drecha","wedo2.tiltDirection.up":"ennaut","wedo2.whenDistance":"quand la distància [OP] [REFERENCE]","wedo2.whenTilted":"quand clinat [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Color","paint.paintEditor.saturation":"Saturacion","paint.paintEditor.brightness":"Luminositat","paint.paintEditor.costume":"Costum","paint.paintEditor.group":"Grop","paint.paintEditor.ungroup":"Desgroupar","paint.paintEditor.undo":"Anullar","paint.paintEditor.redo":"Tornar far","paint.paintEditor.forward":"Endavant","paint.paintEditor.backward":"Endarrièr","paint.paintEditor.front":"Davant","paint.paintEditor.back":"Endarrièr","paint.paintEditor.more":"Mai","paint.modeTools.brushSize":"Talha","paint.modeTools.eraserSize":"Talha de la goma","paint.modeTools.copy":"Copiar","paint.modeTools.paste":"Pegar","paint.modeTools.delete":"Escafar","paint.modeTools.curved":"Corbat","paint.modeTools.pointed":"Ponchut","paint.modeTools.thickness":"Espessor","paint.modeTools.flipHorizontal":"Revirar Orizontalement","paint.modeTools.flipVertical":"Revirar Verticalement","paint.modeTools.filled":"Emplenat","paint.modeTools.outlined":"Suslinhat","paint.paintEditor.bitmap":"Convertir en Bitmap","paint.paintEditor.vector":"Convertir en Vectors","paint.paintEditor.fill":"Emplenar","paint.paintEditor.stroke":"Suslinhar","paint.brushMode.brush":"Bròssa","paint.eraserMode.eraser":"Goma","paint.fillMode.fill":"Emplenar","paint.lineMode.line":"Linha","paint.ovalMode.oval":"Cercle","paint.rectMode.rect":"Rectangle","paint.reshapeMode.reshape":"Remodelar","paint.roundedRectMode.roundedRect":"Rectangle arredondit","paint.selectMode.select":"Seleccionar","paint.textMode.text":"Tèxt","paint.colorPicker.swap":"Escambiar"},"or":{"gui.alerts.tryAgain":"ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ","gui.alerts.download":"ଡାଉନଲୋଡ୍ କରନ୍ତୁ","gui.connection.reconnect":"ପୁଣି ସଂଯୋଗ କରନ୍ତୁ","gui.backpack.costumeLabel":"ପୋଷାକ","gui.backpack.soundLabel":"ଧ୍ୱନି","gui.backpack.scriptLabel":"ସ୍କ୍ରିପ୍ଟ (ଲେଖା)","gui.backpack.spriteLabel":"ସ୍ପ୍ରାଇଟ","gui.backpack.header":"ବ୍ୟାକପ୍ୟାକ୍","gui.backpack.errorBackpack":"ବ୍ୟାକପ୍ୟାକ୍ ଲୋଡ୍ କରିବାରେ ତ୍ରୁଟି","gui.backpack.loadingBackpack":"ଲୋଡିଂ...","gui.backpack.more":"ଆଉ","gui.backpack.emptyBackpack":"ବ୍ୟାକପ୍ୟାକ୍ ଖାଲି ଅଛି","gui.unsupportedBrowser.label":"ବ୍ରାଉଜର୍ ସମର୍ଥିତ ନୁହେଁ","gui.cards.all-tutorials":"ଟ୍ୟୁଟୋରିଆଲ୍","gui.cards.shrink":"ସଙ୍କୋଚନ କରନ୍ତୁ","gui.cards.expand":"ବିସ୍ତାର କରନ୍ତୁ","gui.cards.close":"ବନ୍ଦ","gui.cards.more-things-to-try":"ଚେଷ୍ଟା କରିବାକୁ ଅଧିକ ଜିନିଷ!","gui.cards.see-more":"ଆଉ ଦେଖନ୍ତୁ","gui.comingSoon.message1":"ବ୍ୟସ୍ତ ହୁଅନ୍ତୁ ନାହିଁ, ଆମେ ଏହା ଉପରେ କାମ କରୁଛୁ {emoji}","gui.comingSoon.message2":"ଶୀଘ୍ର ଆସୁଅଛି...","gui.comingSoon.message3":"ଆମେ ଏହା ଉପରେ କାମ କରୁଛୁ {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"କୌଣସି ଡିଭାଇସ ମିଳିଲା ନାହିଁ","gui.connection.auto-scanning.prescan":"ଆପଣଙ୍କର ଡିଭାଇସ୍ ପାଖରେ ରଖନ୍ତୁ, ତାପରେ ଖୋଜିବା ଆରମ୍ଭ କରନ୍ତୁ","gui.connection.auto-scanning.pressbutton":"ଆପଣଙ୍କ ଡିଭାଇସରେ ବଟନ୍ ଦବାନ୍ତୁ","gui.connection.auto-scanning.start-search":"ସନ୍ଧାନ ଆରମ୍ଭ କରନ୍ତୁ","gui.connection.connecting-searchbutton":"ଖୋଜୁଛି ...","gui.connection.auto-scanning.try-again":"ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ","gui.connection.connected":"ସଂଯୋଗ ହୋଇଛି","gui.connection.disconnect":"ବିଚ୍ଛିନ୍ନ କରନ୍ତୁ","gui.connection.go-to-editor":"ସମ୍ପାଦକକୁ ଯାଆନ୍ତୁ","gui.connection.connecting-cancelbutton":"ସଂଯୋଗ କରୁଛୁ...","gui.connection.error.errorMessage":"ଦେଖାଯାଉଛି କିଛି ଭୁଲ୍ ହୋଇଛି","gui.connection.error.tryagainbutton":"ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ","gui.connection.error.helpbutton":"ସାହାଯ୍ୟ","gui.connection.peripheral-name-label":"ଡିଭାଇସ ନାମ","gui.connection.connect":"ସଂଯୋଗ କରନ୍ତୁ","gui.connection.scanning.lookingforperipherals":"ଡିଭାଇସ ଖୋଜୁଛି","gui.connection.scanning.noPeripheralsFound":"କୌଣସି ଡିଭାଇସ ମିଳିଲା ନାହିଁ","gui.connection.scanning.instructions":"ଉପର ତାଲିକାରେ ଆପଣଙ୍କର ଡିଭାଇସ୍ ବାଛନ୍ତୁ","gui.connection.search":"ସତେଜ କରନ୍ତୁ","gui.connection.unavailable.installscratchlink":"ନିଶ୍ଚିତ କରନ୍ତୁ ଯେ ଆପଣଙ୍କର ସ୍କ୍ରାଚ୍ ଲିଙ୍କ୍ ସଂସ୍ଥାପିତ ଏବଂ ଚାଲୁଛି","gui.connection.unavailable.enablebluetooth":"ଯାଞ୍ଚ କରନ୍ତୁ ଯେ ବ୍ଲୁଟୁଥ୍ ସକ୍ଷମ ହୋଇଛି","gui.connection.unavailable.tryagainbutton":"ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ","gui.connection.unavailable.helpbutton":"ସାହାଯ୍ୟ","gui.controls.go":"ଯାଅ","gui.controls.stop":"ବନ୍ଦ କର","gui.crashMessage.label":"ଓହୋ! କିଛି ଭୁଲ ହୋଇ ଗଲା।","gui.crashMessage.errorNumber":"ଆପଣଙ୍କର ତ୍ରୁଟି id {errorId} ସହିତ ଲଗ୍ ହୋଇଛି","gui.crashMessage.reload":"ପୁଣି ଲୋଡ୍ କରନ୍ତୁ","gui.customProcedures.myblockModalTitle":"ଏକ ବ୍ଲକ ପ୍ରସ୍ତୁତ କରନ୍ତୁ","gui.customProcedures.addAnInputNumberText":"ଏକ ଇନପୁଟ୍ ଯୋଡନ୍ତୁ","gui.customProcedures.numberTextType":"ସଂଖ୍ୟା କିମ୍ବା ବର୍ଣ୍ଣ","gui.customProcedures.addAnInputBoolean":"ଏକ ଇନପୁଟ୍ ଯୋଡନ୍ତୁ","gui.customProcedures.booleanType":"ବୁଲିଅନ୍","gui.customProcedures.addALabel":"ଏକ ଲେବଲ୍ ଯୋଡନ୍ତୁ","gui.customProcedures.runWithoutScreenRefresh":"ସ୍କ୍ରିନ୍ ସତେଜ ବିନା ଚଲାନ୍ତୁ","gui.customProcedures.cancel":"ବାତିଲ୍ କରନ୍ତୁ","gui.customProcedures.ok":"ଠିକ୍ ଅଛି","gui.SpriteInfo.direction":"ଦିଗ","gui.directionPicker.rotationStyles.allAround":"ଚାରିଆଡେ","gui.directionPicker.rotationStyles.leftRight":"ବାମ/ଡାହାଣ","gui.directionPicker.rotationStyles.dontRotate":"ଘୁରାଅ ନାହିଁ","gui.gui.addExtension":"ଏକ୍ସଟେନ୍ସନ୍ ଯୋଡନ୍ତୁ","gui.gui.codeTab":"କୋଡ୍","gui.gui.backdropsTab":"ପୃଷ୍ଠପଟ (ବେକଡ୍ରପ)","gui.gui.costumesTab":"ପୋଷାକ","gui.gui.soundsTab":"ଧ୍ୱନି","gui.extensionLibrary.comingSoon":"ଶୀଘ୍ର ଆସୁଅଛି","gui.extensionLibrary.requires":"ଆବଶ୍ୟକ କରେ","gui.extensionLibrary.collaboration":"ସହଯୋଗ ସହିତ","gui.library.filterPlaceholder":"ଖୋଜ","gui.library.allTag":"ସମସ୍ତ","gui.loader.headline":"ଲୋଡିଂ ପ୍ରୋଜେକ୍ଟ","gui.loader.creating":"ପ୍ରୋଜେକ୍ଟ ସୃଷ୍ଟି କରିବା","gui.authorInfo.byUser":"{username} ଦ୍ୱାରା ","gui.menuBar.seeProjectPage":"ପ୍ରୋଜେକ୍ଟ ପୃଷ୍ଠା ଦେଖନ୍ତୁ","gui.menuBar.LanguageSelector":"ଭାଷା ଚୟନକର୍ତ୍ତା","gui.menuBar.tutorialsLibrary":"ଟ୍ୟୁଟୋରିଆଲ୍","gui.menuBar.restoreSprite":"ସ୍ପ୍ରାଇଟ ପୁନରୁଦ୍ଧାର(ରିସ୍ଟୋର) କରନ୍ତୁ","gui.menuBar.restoreSound":"ଧ୍ୱନି ପୁନରୁଦ୍ଧାର(ରିସ୍ଟୋର) କରନ୍ତୁ","gui.menuBar.restoreCostume":"ପୋଷାକ ପୁନରୁଦ୍ଧାର(ରିସ୍ଟୋର) କରନ୍ତୁ","gui.menuBar.restore":"ପୁନରୁଦ୍ଧାର(ରିସ୍ଟୋର) କରନ୍ତୁ","gui.menuBar.saveNow":"ବର୍ତ୍ତମାନ ସେଭ୍ କରନ୍ତୁ","gui.menuBar.saveAsCopy":"ଏକ କପି ଭାବରେ ସେଭ୍ କରନ୍ତୁ","gui.menuBar.remix":"ରିମିକ୍ସ","gui.menuBar.new":"ନୂତନ","gui.menuBar.file":"ଫାଇଲ୍","gui.menuBar.downloadToComputer":"ଆପଣଙ୍କ କମ୍ପ୍ୟୁଟରକୁ ସେଭ୍ କରନ୍ତୁ","gui.menuBar.edit":"ସଂପାଦନା କରନ୍ତୁ","gui.menuBar.turboModeOff":"ଟର୍ବୋ ମୋଡ୍ ବନ୍ଦ(ଅଫ) କରନ୍ତୁ","gui.menuBar.turboModeOn":"ଟର୍ବୋ ମୋଡ୍ ଟର୍ନ୍ ଅନ୍ କରନ୍ତୁ","gui.gui.projectTitlePlaceholder":"ପ୍ରୋଜେକ୍ଟ ଟାଇଟଲ୍ ଏଠାରେ","gui.menuBar.isShared":"ଅଂଶୀଦାର","gui.menuBar.share":"ଅଂଶୀଦାର କରନ୍ତୁ","gui.modal.help":"ସାହାଯ୍ୟ","gui.modal.back":"ପଛକୁ","gui.monitor.listMonitor.empty":"(ଖାଲି)","gui.monitor.listMonitor.listLength":"ଦର୍ଘ୍ୟ {length}","gui.monitor.contextMenu.default":"ସାଧାରଣ ପଠନ","gui.monitor.contextMenu.large":"ବଡ଼ ପଠନ","gui.monitor.contextMenu.slider":"ସ୍ଲାଇଡର୍","gui.monitor.contextMenu.sliderRange":"ସ୍ଲାଇଡର୍ ରେଞ୍ଜ ପରିବର୍ତ୍ତନ କରନ୍ତୁ","gui.monitor.contextMenu.import":"ଆମଦାନି (ଇମ୍ପୋର୍ଟ)","gui.monitor.contextMenu.export":"ରପ୍ତାନି (ଏକ୍ସପୋର୍ଟ)","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"ଖେଳନ୍ତୁ","gui.playButton.stop":"ବନ୍ଦ କର","gui.gui.variableScopeOptionAllSprites":"ସମସ୍ତ ସ୍ପ୍ରାଇଟ ପାଇଁ","gui.gui.variableScopeOptionSpriteOnly":"କେବଳ ଏହି ସ୍ପ୍ରାଇଟ ପାଇଁ","gui.gui.cloudVariableOption":"କ୍ଲାଉଡ୍ ଭେରିଏବଲ୍ (ସର୍ଭରରେ ଗଚ୍ଛିତ)","gui.gui.variablePromptAllSpritesMessage":"ଏହି ଭେରିଏବଲ୍ ସମସ୍ତ ସ୍ପ୍ରାଇଟସ ପାଇଁ ଉପଲବ୍ଧ ହେବ","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"ବାତିଲ୍ କରନ୍ତୁ","gui.prompt.ok":"ଠିକ୍ ଅଛି","gui.playbackStep.stopMsg":"ବନ୍ଦ କର","gui.playbackStep.playMsg":"ଖେଳନ୍ତୁ","gui.playbackStep.loadingMsg":"ଲୋଡିଂ ...","gui.playbackStep.saveMsg":"ସଞ୍ଚୟ କରନ୍ତୁ","gui.playbackStep.reRecordMsg":"ପୁଣି ରେକର୍ଡ କରନ୍ତୁ","gui.recordModal.title":"ରେକର୍ଡ ସାଉଣ୍ଡ","gui.recordingStep.beginRecord":"ନିମ୍ନରେ ଥିବା ବଟନ୍ କ୍ଲିକ୍ କରି ରେକର୍ଡିଂ ଆରମ୍ଭ କରନ୍ତୁ","gui.recordingStep.permission":"{arrow} ଆପଣଙ୍କର ମାଇକ୍ରୋଫୋନ୍ ବ୍ୟବହାର କରିବାକୁ ଆମେ ଆପଣଙ୍କର ଅନୁମତି ଆବଶ୍ୟକ କରୁ","gui.recordingStep.stop":"ରେକର୍ଡିଂ ବନ୍ଦ କରନ୍ତୁ","gui.recordingStep.record":"ରେକର୍ଡ କରନ୍ତୁ","gui.sliderModal.min":"ସର୍ବନିମ୍ନ ମୂଲ୍ୟ","gui.sliderModal.max":"ସର୍ବାଧିକ ମୂଲ୍ୟ","gui.sliderModal.title":"ସ୍ଲାଇଡର୍ ରେଞ୍ଜ ପରିବର୍ତ୍ତନ କରନ୍ତୁ","gui.sliderPrompt.cancel":"ବାତିଲ୍ କରନ୍ତୁ","gui.sliderPrompt.ok":"ଠିକ୍ ଅଛି","gui.soundEditor.sound":"ଶବ୍ଦ","gui.soundEditor.play":"ଖେଳନ୍ତୁ","gui.soundEditor.stop":"ବନ୍ଦ କର","gui.soundEditor.copy":"କପି କରନ୍ତୁ","gui.soundEditor.paste":"ପେଷ୍ଟ କରନ୍ତୁ","gui.soundEditor.copyToNew":"ନୂତନକୁ କପି କରନ୍ତୁ","gui.soundEditor.delete":"ବିଲୋପ କରନ୍ତୁ","gui.soundEditor.save":"ସଞ୍ଚୟ କରନ୍ତୁ","gui.soundEditor.undo":"ପ୍ରତ୍ୟାଶିତ କରନ୍ତୁ (undo)","gui.soundEditor.redo":"ପୁନର୍ବାର କରନ୍ତୁ","gui.soundEditor.faster":"ଶୀଘ୍ର","gui.soundEditor.slower":"ଧୀର","gui.soundEditor.echo":"ଇକୋ","gui.soundEditor.robot":"ରୋବଟ୍","gui.soundEditor.louder":"ଉଚ୍ଚ ସ୍ୱର","gui.soundEditor.softer":"ନରମ","gui.soundEditor.reverse":"ଓଲଟା","gui.soundEditor.fadeOut":"ଫେଡ ଆଉଟ","gui.soundEditor.fadeIn":"ଫେଡ ଇନ","gui.soundEditor.mute":"ଶବ୍ଦ ବନ୍ଦ","gui.SpriteInfo.spritePlaceholder":"ନାମ","gui.SpriteInfo.sprite":"ସ୍ପ୍ରାଇଟ","gui.SpriteInfo.show":"ଦେଖାନ୍ତୁ","gui.SpriteInfo.size":"ଆକାର","gui.spriteSelectorItem.contextMenuDuplicate":"ନକଲ","gui.spriteSelectorItem.contextMenuExport":"ରପ୍ତାନି (ଏକ୍ସପୋର୍ଟ)","gui.spriteSelectorItem.contextMenuDelete":"ଡିଲିଟ୍ କରନ୍ତୁ","gui.spriteSelector.addSpriteFromLibrary":"ଏକ ସ୍ପ୍ରାଇଟ ବାଛନ୍ତୁ","gui.spriteSelector.addSpriteFromPaint":"ରଙ୍ଗ କରନ୍ତୁ","gui.spriteSelector.addSpriteFromSurprise":"ଆଶ୍ଚର୍ଯ୍ୟ","gui.spriteSelector.addSpriteFromFile":"ସ୍ପ୍ରାଇଟ ଅପଲୋଡ୍ କରନ୍ତୁ","gui.stageHeader.stageSizeLarge":"ବଡ଼ ମଞ୍ଚକୁ ଯାଆନ୍ତୁ","gui.stageHeader.stageSizeSmall":"ଛୋଟ ମଞ୍ଚକୁ ଯାଆନ୍ତୁ","gui.stageHeader.stageSizeFull":"ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନ୍ ମୋଡ୍ ପ୍ରବେଶ କରନ୍ତୁ","gui.stageHeader.stageSizeUnFull":"ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନ୍ ମୋଡ୍ ଛାଡନ୍ତୁ","gui.stageHeader.fullscreenControl":"ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନ୍ ନିୟନ୍ତ୍ରଣ","gui.spriteSelector.addBackdropFromLibrary":"ଏକ ପୃଷ୍ଠଭୂମି(ବେକଡ୍ରପ) ବାଛନ୍ତୁ","gui.stageSelector.addBackdropFromPaint":"ରଙ୍ଗ କରନ୍ତୁ","gui.stageSelector.addBackdropFromSurprise":"ଆଶ୍ଚର୍ଯ୍ୟ","gui.stageSelector.addBackdropFromFile":"ପୃଷ୍ଠଭୂମି(ବେକଡ୍ରପ) ଅପଲୋଡ୍ କରନ୍ତୁ","gui.stageSelector.stage":"ପର୍ଯ୍ୟାୟ/ମଞ୍ଚ","gui.stageSelector.backdrops":"ପୃଷ୍ଠପଟ(ବେକଡ୍ରପ) ଗୁଡିକ","gui.telemetryOptIn.label":"ସ୍କ୍ରାଚ୍ ଉନ୍ନତି କରିବାକୁ ପରିସଂଖ୍ୟାନ ରିପୋର୍ଟ କରନ୍ତୁ","gui.telemetryOptIn.body1":"ସ୍କ୍ରାଚ୍ ଦଳ ସର୍ବଦା ବିଶ୍ୱରେ ସ୍କ୍ରାଚ୍ କିପରି ବ୍ୟବହାର କରାଯାଏ ତାହା ଭଲ ଭାବରେ ବୁଝିବାକୁ ଚାହିଁଥାଏ । ଏହି ପ୍ରୟାସକୁ ସମର୍ଥନ କରିବାରେ ସାହାଯ୍ୟ କରିବାକୁ, ଆପଣ ସ୍କ୍ରାଚ୍ ଦଳକୁ ସ୍ୱୟଂଚାଳିତ ଭାବରେ ବ୍ୟବହାର ସୂଚନା ପଠାଇବାକୁ ଅନୁମତି ଦେଇପାରିବେ |","gui.telemetryOptIn.body2":"ଆମେ ସଂଗ୍ରହ କରୁଥିବା ସୂଚନାରେ ଭାଷା ଚୟନ, ବ୍ଲକ୍ ବ୍ୟବହାର ଏବଂ କିଛି ଘଟଣା ଯେପରିକି ଏକ ପ୍ରୋଜେକ୍ଟ ସଞ୍ଚୟ, ଲୋଡିଂ ଏବଂ ଅପଲୋଡ୍ ଅନ୍ତର୍ଭୁକ୍ତ| ଆମେ କୌଣସି ବ୍ୟକ୍ତିଗତ ସୂଚନା ସଂଗ୍ରହ କରୁ ନାହିଁ । ଅଧିକ ସୂଚନା ପାଇଁ ଦୟାକରି ଆମର {privacyPolicyLink} ଦେଖନ୍ତୁ |","gui.telemetryOptIn.privacyPolicyLink":"ଗୋପନୀୟତା ନୀତି","gui.telemetryOptIn.optInText":"ସ୍କ୍ରାଚ୍ ଟିମ୍ ସହିତ ମୋର ବ୍ୟବହାର ତଥ୍ୟ ଅଂଶୀଦାର କରନ୍ତୁ","gui.telemetryOptIn.optInTooltip":"ଟେଲିମେଟ୍ରି ସକ୍ଷମ କରନ୍ତୁ","gui.telemetryOptIn.optOutText":"ସ୍କ୍ରାଚ୍ ଟିମ୍ ସହିତ ମୋର ବ୍ୟବହାର ତଥ୍ୟ ଅଂଶୀଦାର କରନ୍ତୁ ନାହିଁ","gui.telemetryOptIn.optOutTooltip":"ଟେଲିମେଟ୍ରି ନିଷ୍କ୍ରିୟ କରନ୍ତୁ","gui.telemetryOptIn.settingWasUpdated":"ଆପଣଙ୍କର ସେଟିଂ ଅଦ୍ୟତନ କରାଯାଇଥିଲା |","gui.telemetryOptIn.buttonClose":"ବନ୍ଦ କରନ୍ତୁ","gui.turboMode.active":"ଟର୍ବୋ ମୋଡ୍","gui.webglModal.label":"ଆପଣଙ୍କର ବ୍ରାଉଜର୍ WebGL କୁ ସମର୍ଥନ କରେନାହିଁ","gui.webglModal.webgllink":"WebGL କୁ ସମର୍ଥନ କରେନାହିଁ","gui.costumeLibrary.chooseABackdrop":"ଏକ ପୃଷ୍ଠଭୂମି ବାଛନ୍ତୁ","gui.costumeLibrary.chooseACostume":"ଏକ ପୋଷାକ ବାଛନ୍ତୁ","gui.costumeTab.addBackdropFromLibrary":"ଏକ ପୃଷ୍ଠଭୂମି ବାଛନ୍ତୁ","gui.costumeTab.addCostumeFromLibrary":"ଏକ ପୋଷାକ ବାଛନ୍ତୁ","gui.costumeTab.addBlankCostume":"ରଙ୍ଗ କରନ୍ତୁ","gui.costumeTab.addSurpriseCostume":"ଆଶ୍ଚର୍ଯ୍ୟ","gui.costumeTab.addFileBackdrop":"ପୃଷ୍ଠଭୂମି ଅପଲୋଡ୍ କରନ୍ତୁ","gui.costumeTab.addFileCostume":"ପୋଷାକ ଅପଲୋଡ୍ କରନ୍ତୁ","gui.extensionLibrary.chooseAnExtension":"ଏକ ଏକ୍ସଟେନ୍ସନ୍ ବାଛନ୍ତୁ","gui.extensionLibrary.extensionUrl":"ଏକ୍ସଟେନ୍ସନ୍ର URL ଦିଅନ୍ତୁ ","gui.monitors.importListColumnPrompt":"କେଉଁ ସ୍ତମ୍ଭ (କଲମ) ବ୍ୟବହାର କରାଯିବା ଉଚିତ୍ (1- {numberOfColumns})?","gui.recordingStep.alertMsg":"ରେକର୍ଡିଂ ଆରମ୍ଭ କରିପାରିଲା ନାହିଁ","gui.soundLibrary.chooseASound":"ଏକ ଧ୍ୱନି ବାଛନ୍ତୁ","gui.soundTab.fileUploadSound":"ଧ୍ୱନି ଅପଲୋଡ୍ କରନ୍ତୁ","gui.soundTab.surpriseSound":"ଆଶ୍ଚର୍ଯ୍ୟ","gui.soundTab.recordSound":"ରେକର୍ଡ କରନ୍ତୁ","gui.soundTab.addSoundFromLibrary":"ଏକ ଧ୍ୱନି ବାଛନ୍ତୁ","gui.spriteLibrary.chooseASprite":"ଏକ ସ୍ପ୍ରାଇଟ ବାଛନ୍ତୁ","gui.tipsLibrary.tutorials":"ଏକ ଟ୍ୟୁଟୋରିଆଲ୍ ବାଛନ୍ତୁ","gui.alerts.createsuccess":"ନୂତନ ପ୍ରକଳ୍ପ ସୃଷ୍ଟି","gui.alerts.createcopysuccess":"ପ୍ରୋଜେକ୍ଟ ଏକ କପି ଭାବରେ ସେଭ୍ ହୋଇଛି","gui.alerts.createremixsuccess":"ପ୍ରୋଜେକ୍ଟ ଏକ ରିମିକ୍ସ ଭାବରେ ସେଭ୍ ହୋଇଛି","gui.alerts.creating":"ନୂତନ ସୃଷ୍ଟି…","gui.alerts.creatingCopy":"ପ୍ରୋଜେକ୍ଟ କପି…","gui.alerts.creatingRemix":"ରିମିକ୍ସ ପ୍ରୋଜେକ୍ଟ…","gui.alerts.creatingError":"ପ୍ରକଳ୍ପ ସୃଷ୍ଟି କରିପାରିଲା ନାହିଁ ଦୟାକରି ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ!","gui.alerts.savingError":"ପ୍ରକଳ୍ପ ସଞ୍ଚୟ କରିପାରିଲା ନାହିଁ","gui.alerts.savesuccess":"ପ୍ରୋଜେକ୍ଟ ସଞ୍ଚୟ ହୋଇଛି","gui.alerts.saving":"ପ୍ରୋଜେକ୍ଟ ସଞ୍ଚୟ…","gui.alerts.cloudInfo":"ଦୟାକରି ଧ୍ୟାନ ଦିଅନ୍ତୁ, କ୍ଲାଉଡ୍ ଭେରିଏବଲ୍ କେବଳ ସଂଖ୍ୟାକୁ ସମର୍ଥନ କରେ, କ୍ୟାରକ୍ଟର କିମ୍ବା ସିମବଲ ନୁହେଁ {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"ଆଉ ସିଖନ୍ତୁ","gui.alerts.importing":"ଆମଦାନି…","gui.defaultProject.variable":"ମୋ ଭେରିଏବଲ୍","gui.extension.music.name":"ସଙ୍ଗୀତ","gui.extension.music.description":"ବାଦ୍ୟଯନ୍ତ୍ର ଏବଂ ଡ଼୍ରମ୍ ବଜାନ୍ତୁ","gui.extension.pen.name":"କଲମ","gui.extension.pen.description":"ତୁମର ସ୍ପ୍ରାଇଟସ ସହିତ ଅଙ୍କନ କର","gui.extension.videosensing.name":"ଭିଡିଓ ସେନ୍ସିଂ","gui.extension.videosensing.description":"କ୍ୟାମେରା ସହିତ ଗତିକୁ ଅନୁଭବ କରନ୍ତୁ","gui.extension.text2speech.name":"ଭାଷଣକୁ ପାଠ","gui.extension.text2speech.description":"ତୁମର ପ୍ରୋଜେକ୍ଟଗୁଡ଼ିକୁ କଥାବାର୍ତ୍ତା କରିବାର କ୍ଷମତା ଦିଅ","gui.extension.translate.name":"ଅନୁବାଦ କରନ୍ତୁ","gui.extension.translate.description":"ବାକ୍ୟଗୁଡ଼ିକ ଅନେକ ଭାଷାରେ ଅନୁବାଦ କରନ୍ତୁ","gui.extension.makeymakey.description":"ଯେ କୌଣସି ଜିନିଷକୁ ଚାବିରେ ପରିଣତ କରନ୍ତୁ ।","gui.extension.microbit.description":"ନିଜର ପ୍ରୋଜେକ୍ଟଗୁଡ଼ିକୁ ବିଶ୍ୱ ସହିତ ସଂଯୋଗ କରନ୍ତୁ","gui.extension.microbit.connectingMessage":"ସଂଯୋଗ କରୁଛି","gui.extension.ev3.description":"ଇଣ୍ଟରାକ୍ଟିଭ୍ ରୋବଟ୍ ନିର୍ମାଣ କରନ୍ତୁ ଏବଂ ଆଉ ଅଧିକ|","gui.extension.ev3.connectingMessage":"ସଂଯୋଗ କରୁଛି, ନିଶ୍ଚିତ କରନ୍ତୁ ଯେ ଆପଣଙ୍କର EV3 ରେ ଥିବା ପିନ୍ 1234 ରେ ସେଟ୍ ହୋଇଛି","gui.extension.boost.description":"ରୋବୋଟିକ୍ ସୃଷ୍ଟିଗୁଡ଼ିକୁ ଜୀବନରେ ଆଣ","gui.extension.boost.connectingMessage":"ସଂଯୋଗ କରୁଛି","gui.extension.wedo2.description":"ମୋଟର ଏବଂ ସେନ୍ସରକୁ ନେଇ ନିର୍ମାଣ କରନ୍ତୁ","gui.extension.wedo2.connectingMessage":"ସଂଯୋଗ କରୁଛି","gui.extension.gdxfor.description":"\\nଠେଲିବା, ଟାଣିବା, ଗତି, ଏବଂ ସ୍ପିନ୍କୁ ଅନୁଭବ କରନ୍ତୁ","gui.extension.gdxfor.connectingMessage":"ସଂଯୋଗ କରୁଛି","gui.libraryTags.all":"ସମସ୍ତ","gui.libraryTags.animals":"ପଶୁମାନେ","gui.libraryTags.dance":"ନୃତ୍ୟ","gui.libraryTags.effects":"ପ୍ରଭାବ","gui.libraryTags.fantasy":"କଳ୍ପନା","gui.libraryTags.fashion":"ଫ୍ୟାଶନ୍","gui.libraryTags.food":"ଖାଦ୍ୟ","gui.libraryTags.indoors":"ଘର ଭିତରେ","gui.libraryTags.loops":"ଲୁପ୍","gui.libraryTags.music":"ସଙ୍ଗୀତ","gui.libraryTags.notes":"ଟିପ୍ପଣୀ","gui.libraryTags.outdoors":"ବାହାଘର","gui.libraryTags.patterns":"ନମୁନା","gui.libraryTags.people":"ଲୋକମାନେ","gui.libraryTags.percussion":"ପରକ୍ୟୁସନ","gui.libraryTags.space":"ସ୍ଥାନ","gui.libraryTags.sports":"କ୍ରୀଡା","gui.libraryTags.underwater":"ଅଣ୍ଡରୱାଟର (ପାଣି ଭିତରେ)","gui.libraryTags.voice":"ସ୍ୱର","gui.libraryTags.wacky":"ୱାକି","gui.libraryTags.animation":"ଆନିମେସନ୍","gui.libraryTags.art":"କଳା","gui.libraryTags.games":"ଖେଳଗୁଡିକ","gui.libraryTags.stories":"କାହାଣୀଗୁଡିକ","gui.libraryTags.letters":"କ୍ୟାରକ୍ଟରଗୁଡ଼ିକ","gui.opcodeLabels.direction":"ଦିଗ","gui.opcodeLabels.xposition":"x ସ୍ଥିତି (ପୋଜିସନ)","gui.opcodeLabels.yposition":"y ସ୍ଥିତି (ପୋଜିସନ)","gui.opcodeLabels.size":"ଆକାର","gui.opcodeLabels.costumename":"ପୋଷାକ ନାମ","gui.opcodeLabels.costumenumber":"ପୋଷାକ ସଂଖ୍ୟା","gui.opcodeLabels.backdropname":"ପୃଷ୍ଠପଟ ନାମ","gui.opcodeLabels.backdropnumber":"ପୃଷ୍ଠପଟ ସଂଖ୍ୟା","gui.opcodeLabels.volume":"ଭଲ୍ୟୁମ୍","gui.opcodeLabels.tempo":"ଟେମ୍ପୋ","gui.opcodeLabels.answer":"ଉତ୍ତର ଦିଅ","gui.opcodeLabels.loudness":"ଉଚ୍ଚ ସ୍ୱର","gui.opcodeLabels.username":"ୟୁଜର ନେମ୍","gui.opcodeLabels.year":"ବର୍ଷ","gui.opcodeLabels.month":"ମାସ","gui.opcodeLabels.date":"ତାରିଖ","gui.opcodeLabels.dayofweek":"ସପ୍ତାହର ଦିନ","gui.opcodeLabels.hour":"ଘଣ୍ଟା","gui.opcodeLabels.minute":"ମିନିଟ୍","gui.opcodeLabels.second":"ଦ୍ୱିତୀୟ","gui.opcodeLabels.timer":"ଟାଇମର୍","gui.sharedMessages.backdrop":"ପୃଷ୍ଠପଟ{index}","gui.sharedMessages.costume":"ପୋଷାକ{index}","gui.sharedMessages.sprite":"ସ୍ପ୍ରାଇଟ{index}","gui.sharedMessages.pop":"ପପ୍","gui.sharedMessages.replaceProjectWarning":"ସାମ୍ପ୍ରତିକ ପ୍ରକଳ୍ପର ବିଷୟବସ୍ତୁକୁ ବଦଳାନ୍ତୁ?","gui.sharedMessages.loadFromComputerTitle":"ଆପଣଙ୍କ କମ୍ପ୍ୟୁଟରରୁ ଲୋଡ୍ କରନ୍ତୁ","boost.color.any":"ଯେକୌଣସି ରଙ୍ଗ","boost.color.black":"କଳା","boost.color.blue":"ନୀଳ","boost.color.green":"ସବୁଜ","boost.color.red":"ଲାଲ","boost.color.white":"ଧଳା","boost.color.yellow":"ହଳଦିଆ","boost.getMotorPosition":"ମୋଟର [MOTOR_REPORTER_ID] की स्थिति ","boost.getTiltAngle":"ଝୁଙ୍କାଇବାର ଦିଗ [TILT_DIRECTION]","boost.motorDirection.backward":"ସେ ପଟେ","boost.motorDirection.forward":"ଏ ପଟେ","boost.motorDirection.reverse":"ଓଲଟା ପଟେ","boost.motorOff":"[MOTOR_ID] ମୋଟର ବନ୍ଦ କର","boost.motorOn":"[MOTOR_ID] ମୋଟର ଟର୍ନ୍ ଅନ୍ କରନ୍ତୁ","boost.motorOnFor":"[MOTOR_ID] ମୋଟର ଚଲାନ୍ତୁ [DURATION] କ୍ଷଣ ପାଇଁ","boost.motorOnForRotation":"[MOTOR_ID]ମୋଟର ଚଲାନ୍ତୁ [ROTATION] ରାଉଣ୍ଡ ପାଇଁ","boost.seeingColor":"କେଉଁ [COLOR] ଇଟା ଦେଖିଲ?","boost.setLightHue":"ଆଲୁଅ କଲଡର [HUE] ରଖ","boost.setMotorDirection":"ମୋଟର [MOTOR_ID] ଦିଗ [MOTOR_DIRECTION] ସେଟ୍ କରନ୍ତୁ","boost.setMotorPower":"ମୋଟର [MOTOR_ID] ଗତି ସ୍ଥିର କରନ୍ତୁ [POWER] % ଯାଏଁ ","boost.tiltDirection.any":"କୌଣସି ","boost.tiltDirection.down":"ତଳକୁ","boost.tiltDirection.left":"ବାମ","boost.tiltDirection.right":"ଡାହାଣ","boost.tiltDirection.up":"ଉପର","boost.whenColor":"ଯେତେବେଳେ ତୁମେ [COLOR] ଇଟା ଦେଖିବ","boost.whenTilted":"ଝୁଙ୍କି ଥିଲା ବେଳେ [TILT_DIRECTION_ANY]","ev3.beepNote":"[NOTE] बीप लय को [TIME] क्षण तक चलाए ","ev3.buttonPressed":"କେଉଁ [PORT] ବଟନ୍ ଦବେଇଲ?","ev3.getBrightness":"ଉଜ୍ଜ୍ୱଳତା","ev3.getDistance":"ଦୂରତା","ev3.getMotorPosition":"[PORT] ମୋଟର ସ୍ଥିତି | ","ev3.motorSetPower":"[PORT] ମୋଟର ଶକ୍ତି [POWER]% ସେଟ୍ କରନ୍ତୁ ","ev3.motorTurnClockwise":" ମୋଟର କୁ [PORT] [TIME] ସେକେଣ୍ଡ ପାଇଁ ଏହି ପଟେ ବୁଲାନ୍ତୁ","ev3.motorTurnCounterClockwise":" ମୋଟର କୁ [PORT] [TIME] ସେକେଣ୍ଡ ପାଇଁ ସେହି ପଟେ ବୁଲାନ୍ତୁ","ev3.whenBrightnessLessThan":"ଯେତେବେଳେ ଉଜ୍ଜ୍ୱଳ < [DISTANCE]","ev3.whenButtonPressed":"ଯେତେବେଳେ ବଟନ୍ [PORT] ଦବାଗଲା","ev3.whenDistanceLessThan":"ଯେତେବେଳେ ଦୂରତା < [DISTANCE]","gdxfor.getAcceleration":"ତ୍ୱରଣ [DIRECTION]","gdxfor.getForce":"ବଳ","gdxfor.getSpin":"ଘୂରିବା ଗତି [DIRECTION]","gdxfor.getTilt":"ପ୍ଝୁଙ୍କିବା ର କୋଣ [TILT]","gdxfor.isFreeFalling":"ପଡୁଛି?","gdxfor.isTilted":" ଏହା କେତେ ଝୁଙ୍କିଛି [TILT]?","gdxfor.pulled":"ଟଣା ଯାଇଥିବା","gdxfor.pushed":"ଠେଲା ଯାଇଥିବା","gdxfor.shaken":"କମ୍ପିତ","gdxfor.startedFalling":"ପଡିବା ଆରମ୍ଭ କଲା","gdxfor.tiltDirectionMenu.any":"ଯେକୌଣସି","gdxfor.tiltDirectionMenu.back":"ପଛ","gdxfor.tiltDirectionMenu.front":"ଆଗ","gdxfor.tiltDirectionMenu.left":"ବାମ","gdxfor.tiltDirectionMenu.right":"ଡାହାଣ","gdxfor.turnedFaceDown":"ମୁହଁ ତଳକୁ ହୋଇଗଲା","gdxfor.turnedFaceUp":"ମୁହଁ ଉପରୁକୁ ହୋଇଗଲା ","gdxfor.whenForcePushedOrPulled":"ଯେବେ ଫୋର୍ସ ସେନ୍ସର [PUSH_PULL]","gdxfor.whenGesture":"ଯେବେ [GESTURE]","gdxfor.whenTilted":"ଯେତେବେଳେ ଝୁଂକିଛି [TILT]","makeymakey.downArrow":"ତଳକୁ ତୀର ","makeymakey.downArrowShort":"ତଳ","makeymakey.leftArrow":"ବାମ ତୀର","makeymakey.leftArrowShort":"ବାମ","makeymakey.rightArrow":"ଡାହାଣ ତୀର","makeymakey.rightArrowShort":"ଡାହାଣ","makeymakey.spaceKey":"ଜାଗା","makeymakey.upArrow":"ଉପର ତୀର","makeymakey.upArrowShort":"ଉପର","makeymakey.whenKeyPressed":"ଯେତେବେଳେ [KEY] ଚାବି ଦବାଗଲା","makeymakey.whenKeysPressedInOrder":"ଯେତେବେଳେ [SEQUENCE] କ୍ରମରେ ଦବାଗଲା","microbit.buttonsMenu.any":"କୌଣସି","microbit.clearDisplay":"ସ୍କ୍ରିନ୍ ସଫା କର","microbit.defaultTextToDisplay":"Hello!","microbit.displaySymbol":"ସ୍କ୍ରିନ୍ [MATRIX]","microbit.displayText":"ଦୃଶ୍ୟ ଅକ୍ଷର [TEXT]","microbit.gesturesMenu.jumped":"ଡେଇଁପଡ଼ିଲା","microbit.gesturesMenu.moved":"ଘୁଞ୍ଚିଗଲା","microbit.gesturesMenu.shaken":"ହଲିଗଲା","microbit.isButtonPressed":"କୌ ବଟନ [BTN] ଚିପିଲ?","microbit.isTilted":"ଝୁଙ୍କିଛି [DIRECTION] ?","microbit.pinStateMenu.off":"ବନ୍ଦ","microbit.pinStateMenu.on":"ଅନ୍","microbit.tiltAngle":"ଝୁଙ୍କିବାର କୋଣ [DIRECTION]","microbit.tiltDirectionMenu.any":"ଯେକୌଣସି","microbit.tiltDirectionMenu.back":"ପଛକୁ","microbit.tiltDirectionMenu.front":"ଆଗକୁ","microbit.tiltDirectionMenu.left":"ବାମ","microbit.tiltDirectionMenu.right":"ଡାହାଣ","microbit.whenButtonPressed":"ଯେତେବେଳେ [BTN] ବଟନ୍ ଦବାଗଲା","microbit.whenGesture":"ଯେବେ [GESTURE]","microbit.whenPinConnected":"ଯେତେବେଳେ ପିନ୍ [PIN] ସଂଯୁକ୍ତ","microbit.whenTilted":"ଯେବେ ଝୁଙ୍କିକି ଥିବ [DIRECTION] दिशामे झुका हो ","music.categoryName":"ସଙ୍ଗୀତ","music.changeTempo":"ତାଳ କୁ [TEMPO] ରେ ବଦଳାନ୍ତୁ ","music.drumBass":"(2) ବ୍ୟାସ୍ ଡ୍ରମ୍ ","music.drumBongo":"(13) ବଙ୍ଗୋ","music.drumCabasa":"(15)କାବାସା","music.drumClaves":"(9) କ୍ଲାଭସ୍","music.drumClosedHiHat":"(6)ବନ୍ଦ ହାଏ-ହାଟ","music.drumConga":"(14) କଙ୍ଗା","music.drumCowbell":"(11) ଗାଈ ଘଣ୍ଟି ","music.drumCrashCymbal":"(4) ଝାଞ୍ଜ ","music.drumCuica":"(18) କୁଇକା","music.drumGuiro":"(16) ଗୁଇରୋ","music.drumHandClap":"(8) କରତାଳି","music.drumOpenHiHat":"(5) ଖୋଲ ହାଇ-ହ୍ୟାଟ୍","music.drumSideStick":"(3) ପାର୍ଶ୍ବ କାଠି","music.drumSnare":"(1) ସ୍ନେର ଢୋଲ","music.drumTambourine":"(7) ଡଫଲି","music.drumTriangle":"(12) ତ୍ରିଭୁଜ","music.drumVibraslap":"(17) ଭାଇବ୍ରାସ୍ଲାପ୍","music.drumWoodBlock":"(10) କାଠ ବ୍ଲକ","music.getTempo":"ଲୟ ","music.instrumentBass":"(6) ବାସ୍","music.instrumentBassoon":"(14) ବାସୂନ","music.instrumentCello":"(8) ଚେଲୋ","music.instrumentChoir":"(15) ଗାୟକ ମଣ୍ଡଳୀ","music.instrumentClarinet":"(10) କ୍ଲାରିନେଟ୍","music.instrumentElectricGuitar":"(5) ଇଲେକ୍ଟ୍ରିକ୍ ଗିଟାର୍","music.instrumentElectricPiano":"(2)ଇଲେକ୍ଟ୍ରିକ୍ ପିଆନୋ","music.instrumentFlute":"(12) ବଂଶୀ ","music.instrumentGuitar":"(4) ଗିଟାର","music.instrumentMarimba":"(19) ମାରିମ୍ବା","music.instrumentMusicBox":"(17) ସଙ୍ଗୀତ ପେଡି ","music.instrumentOrgan":"(3) ଅର୍ଗାନ","music.instrumentPiano":"(1) ପିଆନୋ","music.instrumentPizzicato":"(7) ପିଜିକାଟୋ","music.instrumentSaxophone":"(11) ସାକ୍ସୋଫୋନ୍","music.instrumentSteelDrum":"(18) ଷ୍ଟିଲ୍ ଡ୍ରମ୍","music.instrumentSynthLead":"(20) ସିନ୍ଥ୍ ଲିଡ୍","music.instrumentSynthPad":"(21) ସିନ୍ଥ ପ୍ୟାଡ୍","music.instrumentTrombone":"(9) ଟ୍ରମ୍ବୋନ","music.instrumentVibraphone":"(16) ଭିବ୍ରାଫୋନ୍","music.instrumentWoodenFlute":"(13) କାଠ ବଂଶୀ","music.midiPlayDrumForBeats":"[BEATS] ବିଟ୍ ପାଇଁ ଡ୍ରମ୍ [DRUM] ବଜାନ୍ତୁ","music.midiSetInstrument":"ବାଦ୍ୟଯନ୍ତ୍ରକୁ [INSTRUMENT] ରେ ରଖନ୍ତୁ","music.playDrumForBeats":"[BEATS] ବିଟ୍ ପାଇଁ ଡ୍ରମ୍ [DRUM] ବଜାନ୍ତୁ","music.playNoteForBeats":"[BEATS] ବିଟ୍ ପାଇଁ [NOTE] ଟିପ୍ପଣୀ ସ୍ବର ବଜାନ୍ତୁ","music.restForBeats":"ଏତିକି [BEATS] ତାଳ ପାଇଂ ରୁହ","music.setInstrument":"ବାଦ୍ୟଯନ୍ତ୍ରକୁ [INSTRUMENT] ରେ ରଖନ୍ତୁ","music.setTempo":" [TEMPO] ଲୟକୁ ସେଟ୍ କରନ୍ତୁ","pen.categoryName":"କଲମ","pen.changeColorParam":"[COLOR_PARAM] କଲମ କୁ [VALUE] ଦ୍ୱାରା ପରିବର୍ତ୍ତନ କରନ୍ତୁ","pen.changeHue":"କଲମ ରଙ୍ଗ [HUE] ଦ୍ୱାରା ପରିବର୍ତ୍ତନ କରନ୍ତୁ","pen.changeShade":"କଲମ ରଙ୍ଗର ଗଭୀରତା [SHADE] ଦ୍ୱାରା ପରିବର୍ତ୍ତନ ","pen.changeSize":"କାଲାମ ର ଆକାର [SIZE] से ବଦଳାa","pen.clear":"ସବୁ ଲିଭାଇ ଦିଅ","pen.colorMenu.brightness":"ଉଜ୍ଜ୍ଵଳତା","pen.colorMenu.color":"ରଙ୍ଗ","pen.colorMenu.saturation":"ପରିପୂର୍ଣତା","pen.colorMenu.transparency":"ପାରଦର୍ଶିତା","pen.penDown":"ପେନ୍ ତଳକୁ","pen.penUp":"ପେଁ ଉପରକୁ","pen.setColor":"କଲମ ର ରଙ୍ଗ କୁ [COLOR] ରେ ରଖ","pen.setColorParam":"କଲମ [COLOR_PARAM] କୁ [VALUE] ରେ ରଖ","pen.setHue":"କଲମ ର ରଙ୍ଗ କୁ [HUE] ରେ ରଖ","pen.setShade":"କଲମ ର ଗଭୀରତା କୁ [SHADE] ରେ ରଖ","pen.setSize":"କଲମ ର ଆକାର କୁ [SIZE] ରେ ରଖ","pen.stamp":"ଷ୍ଟାମ୍ପ ଲଗାଅ","text2speech.alto":"ଆଳାପ","text2speech.categoryName":"ଲିପି ରୁ ଧ୍ୱନି","text2speech.defaultTextToSpeak":"ନମସ୍କାର","text2speech.giant":"ବିଶାଳକାୟ","text2speech.kitten":"ବିଲେଇ ଛୁଆ","text2speech.setLanguageBlock":" [LANGUAGE] ରେ ଭାଷା କୁ ରଖ","text2speech.setVoiceBlock":" [VOICE] ଉପରେ ସ୍ବର ରଖ","text2speech.speakAndWaitBlock":"କୁହ [WORDS]","text2speech.squeak":"ଚିଲାଇବା","text2speech.tenor":"ଉଚ୍ଚ ସ୍ଵର","translate.categoryName":"ଅନୁବାଦ","translate.defaultTextToTranslate":"ନମସ୍କାର","translate.translateBlock":" [WORDS] କୁ [LANGUAGE] ରେ ଅନୁବାଦ କର","translate.viewerLanguage":"ଭାଷା","videoSensing.categoryName":"ଭିଡିଓ ଜାଣିବା","videoSensing.direction":"ଦିଗ","videoSensing.motion":"ଗତି","videoSensing.off":"ବନ୍ଦ","videoSensing.on":"ଚଳାଅ","videoSensing.onFlipped":"ଓଲଟାଇବା ପରେ","videoSensing.setVideoTransparency":"ଭିଡିଓ ପାରଦର୍ଶିତା କୁ [TRANSPARENCY] ରେ ରଖ","videoSensing.sprite":"ସ୍ପ୍ରାଇଟ","videoSensing.stage":"ମଞ୍ଚ","videoSensing.videoOn":"ଭିଡିଓ [ATTRIBUTE] [SUBJECT] ଉପରେ","videoSensing.videoToggle":"ଭିଡିଓ କୁ ଘୂରାଅ [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"ଯେବେ ଭିଡିଓ ର ଗତି > [REFERENCE]","wedo2.getDistance":"ଦୂରତ୍ବ","wedo2.getTiltAngle":"ଝୁଙ୍କିବା ର ଦିଗ [TILT_DIRECTION]","wedo2.isTilted":"ଝୁଙ୍କିବା [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"ସେ ପଟେ","wedo2.motorDirection.forward":"ଏ ପଟେ","wedo2.motorDirection.reverse":"ଓଲଟା ପଟେ","wedo2.motorId.a":"ମୋଟର A","wedo2.motorId.all":"ସବୁ ମୋଟର","wedo2.motorId.b":"ମୋଟର B ","wedo2.motorId.default":"ମୋଟର","wedo2.motorOff":"[MOTOR_ID] ବନ୍ଦ କର","wedo2.motorOn":"[MOTOR_ID] ଚଳାଅ","wedo2.motorOnFor":"[MOTOR_ID] କୁ [DURATION] ସେକେଣ୍ଡ ପାଇଁ ଚଳାଅ","wedo2.playNoteFor":"[NOTE] ସ୍ବର କୁ [DURATION] ସେକେଣ୍ଡ ପାଇଁ ବଜାଅ","wedo2.setLightHue":"ଆଲୁଅ ର ରଙ୍ଗ [HUE] ରଖ","wedo2.setMotorDirection":"[MOTOR_ID] ର ଦିଗ କୁ [MOTOR_DIRECTION] ରଖ","wedo2.startMotorPower":"[MOTOR_ID] ର କ୍ଷମତା [POWER] ରଖ","wedo2.tiltDirection.any":"କୌଣସି","wedo2.tiltDirection.down":"ତଳ","wedo2.tiltDirection.left":"ବାମ","wedo2.tiltDirection.right":"ଡାହାଣ","wedo2.tiltDirection.up":"ଉପର","wedo2.whenDistance":"ଯେବେ ଦୂରତା [OP][REFERENCE]","wedo2.whenTilted":"ଯେବେ ଝୁଙ୍କିକି ଥିବ [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"ରଙ୍ଗ","paint.paintEditor.saturation":"ପରିପୂର୍ଣତା","paint.paintEditor.brightness":"ଉଜ୍ଜ୍ୱଳତା","paint.paintEditor.costume":"ପୋଷାକ","paint.paintEditor.group":"ସମୂହ","paint.paintEditor.ungroup":"ଅଲଗା କର","paint.paintEditor.undo":"ଆଗ ପରି","paint.paintEditor.redo":"ପୁଣି କର","paint.paintEditor.forward":"ଆଗକୁ କର","paint.paintEditor.backward":"ପଛକୁ କର","paint.paintEditor.front":"ସାମନା","paint.paintEditor.back":"ପଛପାଖ","paint.paintEditor.more":"ଆହୁରି","paint.modeTools.brushSize":"ଆକାର","paint.modeTools.eraserSize":"ରବର ଆକାର","paint.modeTools.copy":"ନକଲ କର","paint.modeTools.paste":"ଲଗାଅ","paint.modeTools.delete":"ଲିଭାଅ","paint.modeTools.curved":"ବକ୍ର","paint.modeTools.pointed":"ମୁନିଆ","paint.modeTools.thickness":"ମୋଟେଇ","paint.modeTools.flipHorizontal":"ଭୁସମାନ୍ତରାଳ ଭାବରେ ଓଲଟାଅ","paint.modeTools.flipVertical":"ଭୁଲମ୍ବାକାରରେଓଲଟାଅ ","paint.modeTools.filled":"ଭର୍ତି","paint.modeTools.outlined":"ସୀମା ନିର୍ଦ୍ଧାରିତ","paint.paintEditor.bitmap":"ବିଟମ୍ଯାପ ରେ ବଦଳେଇଦିଅ","paint.paintEditor.vector":"ଭେକ୍ଟର ରେ ବଦଳେଇଦିଅ","paint.paintEditor.fill":"ଭର୍ତି କର","paint.paintEditor.stroke":"ସୀମା","paint.brushMode.brush":"ବ୍ରଶ","paint.eraserMode.eraser":"ରବର","paint.fillMode.fill":"ଭର୍ତି କର","paint.lineMode.line":"ରେଖା","paint.ovalMode.oval":"ବୃତ୍ତ","paint.rectMode.rect":"ଆୟତକାର","paint.reshapeMode.reshape":"ପୁଣି ଆକାର ତିଆରିକର","paint.roundedRectMode.roundedRect":"ବୃତ୍ତାକାର କୋଣ ବିଶିଷ୍ଟ ଆୟତକାର ","paint.selectMode.select":"ବାଛ","paint.textMode.text":"ଲେଖା","paint.colorPicker.swap":"ପରସ୍ପର ମଧ୍ୟରେ ବଦଳେଇଦିଅ "},"uz":{"gui.alerts.tryAgain":"Qaytadan harakat qilib ko\'ring","gui.alerts.download":"Yuklash","gui.connection.reconnect":"Qayta ulanish","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Shaxsiy ombor","gui.backpack.errorBackpack":"Orqa yuzni yuklashda xatolik yuz berdi","gui.backpack.loadingBackpack":"Yuklanmoqda ...","gui.backpack.more":"Ko\'proq","gui.backpack.emptyBackpack":"Orqa xalqa bo\'sh","gui.unsupportedBrowser.label":"Brauzer qo\'llab-quvvatlanmaydi","gui.cards.all-tutorials":"O‘z-o‘zini o‘qitish","gui.cards.shrink":"Shrink","gui.cards.expand":"Expand","gui.cards.close":"Yopish","gui.cards.more-things-to-try":"Takrorlash kerakli bo\'lgan narsalar ko\'p!","gui.cards.see-more":"Yana ko\'rish","gui.comingSoon.message1":"xavotir olmang. Bu ish ustida ishlayapmiz.{emoji}","gui.comingSoon.message2":"Tez kunda...","gui.comingSoon.message3":"Biz uning ustida ishlayapmiz {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"U yerda yo\'q","gui.connection.auto-scanning.prescan":"Qurilmangizni yaqin qiling, so\'ngra izlashni boshlang.","gui.connection.auto-scanning.pressbutton":"Qurilmaning tugmasini bosing.","gui.connection.auto-scanning.start-search":"Qidiruvni boshlash","gui.connection.connecting-searchbutton":"Qidirilmoqda ...","gui.connection.auto-scanning.try-again":"Qayta urinib ko\'ring","gui.connection.connected":"Ulangan","gui.connection.disconnect":"Ulanish tugatildi","gui.connection.go-to-editor":"O\'zgartirishga borish","gui.connection.connecting-cancelbutton":"Ulanmoqda...","gui.connection.error.errorMessage":"Bu yerda, nimadir notog\'ri","gui.connection.error.tryagainbutton":"Qayta urinib ko\'ring","gui.connection.error.helpbutton":"Yordam","gui.connection.peripheral-name-label":"Qurilma nomi","gui.connection.connect":"Ulanish","gui.connection.scanning.lookingforperipherals":"Qurilma qidirilmoqda","gui.connection.scanning.noPeripheralsFound":"Yangi qurilma yo\'q","gui.connection.scanning.instructions":"Yuqoridagi ro\'yxatda qurilmangizni tanlang.","gui.connection.search":"Yangilash","gui.connection.unavailable.installscratchlink":"Scratch Link o\'rnatilgan va ishlayotganligini tekshirib ko\'ring","gui.connection.unavailable.enablebluetooth":"Bluetoothdan qo\'llanilish mumkinligini tekshirib ko\'ring","gui.connection.unavailable.tryagainbutton":"Qayta urinib ko\'ring","gui.connection.unavailable.helpbutton":"Yordam","gui.controls.go":"Boshlash","gui.controls.stop":"To\'xtatish","gui.crashMessage.label":"Bu yerda, nimadir notog\'ri","gui.crashMessage.errorNumber":"Bu muammo ID {errorId} orqala kirgan","gui.crashMessage.reload":"Yangilash","gui.customProcedures.myblockModalTitle":"Blok yaratish","gui.customProcedures.addAnInputNumberText":"Kiritish qiymatini qo\'shish","gui.customProcedures.numberTextType":"raqam yoki matn","gui.customProcedures.addAnInputBoolean":"Kiritish qiymatini qo\'shish","gui.customProcedures.booleanType":"mantiqiy qiymat","gui.customProcedures.addALabel":"Yorliq qo\'shish","gui.customProcedures.runWithoutScreenRefresh":"Ekrani yangilamasdan ishga tushirish","gui.customProcedures.cancel":"Bekor qilish","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Yo\'nalish","gui.directionPicker.rotationStyles.allAround":"Aylanish","gui.directionPicker.rotationStyles.leftRight":"chap tomon / o\'ng tomon","gui.directionPicker.rotationStyles.dontRotate":"Aylanmaslik","gui.gui.addExtension":"Kengaytirish buyrug\'ini qo\'shish","gui.gui.codeTab":"Kod","gui.gui.backdropsTab":"Fon","gui.gui.costumesTab":"Ko\'rinish","gui.gui.soundsTab":"Ovoz","gui.extensionLibrary.comingSoon":"Tez orada foydalanish mumkin","gui.extensionLibrary.requires":"Talab qiladi","gui.extensionLibrary.collaboration":"Birlashish","gui.library.filterPlaceholder":"Qidiruv","gui.library.allTag":"Hammasi","gui.loader.headline":"Loyiha yuklanmoqda...","gui.loader.creating":"Yaratilgan loyiha","gui.authorInfo.byUser":"Ishlab chiqaruvchi: {username}","gui.menuBar.seeProjectPage":"Loyiha sahifasini ko\'rish","gui.menuBar.LanguageSelector":"til tanlash","gui.menuBar.tutorialsLibrary":"Darsliklar","gui.menuBar.restoreSprite":"Spraytni orqaga aylantirish","gui.menuBar.restoreSound":"Ovozni tiklash","gui.menuBar.restoreCostume":"Kostyumni tiklash","gui.menuBar.restore":"Orqaga qaytarish","gui.menuBar.saveNow":"Saqlash","gui.menuBar.saveAsCopy":"Nusxasi sifatida saqlash","gui.menuBar.remix":"Musiqiy qorishma","gui.menuBar.new":"Yangi yaratish","gui.menuBar.file":"Fayl","gui.menuBar.downloadToComputer":"Kompyuteringizga saqlang","gui.menuBar.edit":"Oʻzgartirish","gui.menuBar.turboModeOff":"Turbo rejimini o\'chiring","gui.menuBar.turboModeOn":"Turbo rejimini yoqish","gui.gui.projectTitlePlaceholder":"Loyiha nomini kirgizing","gui.menuBar.isShared":"Ulashilgan","gui.menuBar.share":"Ulashish","gui.modal.help":"Yordam","gui.modal.back":"Orqaga","gui.monitor.listMonitor.empty":"(Bo\'sh)","gui.monitor.listMonitor.listLength":"uzunligi {length}","gui.monitor.contextMenu.default":"o\'zgaruvchi nomi-qiymatini ko\'rish","gui.monitor.contextMenu.large":"o\'zgaruvchi qiymatini kattalshtirib ko\'rish","gui.monitor.contextMenu.slider":"slayderdan foydalanish","gui.monitor.contextMenu.sliderRange":"slayder oralig\'ini o\'zgartirish","gui.monitor.contextMenu.import":"olib kelish","gui.monitor.contextMenu.export":"eksport qilish","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Play","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"Barcha spraytlarda foydalanish","gui.gui.variableScopeOptionSpriteOnly":"Faqat bu spraytda foydalanish","gui.gui.cloudVariableOption":"Cloud o\'zgaruvchisi (serverda saqlanadi)","gui.gui.variablePromptAllSpritesMessage":"Ushbu o\'zgaruvchini barcha spritlarda foydalanish mumkin.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Bekor qilish","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"To\'xtatish","gui.playbackStep.playMsg":"O\'ynash","gui.playbackStep.loadingMsg":"Yuklanmoqda ...","gui.playbackStep.saveMsg":"Saqlash","gui.playbackStep.reRecordMsg":"Qayta ovoz yozish","gui.recordModal.title":"Ovoz yozish","gui.recordingStep.beginRecord":"Quyidagi tugmani bosib ovoz yozishni boshlang.","gui.recordingStep.permission":"{arrow} Mikrofondan foydalanish uchun foydalanuvchining ruxsati kerak","gui.recordingStep.stop":"Ovoz yozishni to\'xtatish","gui.recordingStep.record":"Ovoz yozish","gui.sliderModal.min":"Minimal qiymat","gui.sliderModal.max":"Maksimal qiymat","gui.sliderModal.title":"Slayder oralig\'ini o\'zgartirish","gui.sliderPrompt.cancel":"Bekor qilish","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Ovoz","gui.soundEditor.play":"O\'ynash","gui.soundEditor.stop":"To\'xtatish","gui.soundEditor.copy":"Copy","gui.soundEditor.paste":"Paste","gui.soundEditor.copyToNew":"Copy to New","gui.soundEditor.delete":"Delete","gui.soundEditor.save":"Saqlash","gui.soundEditor.undo":"Orqaga aylantirish","gui.soundEditor.redo":"Qaytarish","gui.soundEditor.faster":"Tezlashtirish","gui.soundEditor.slower":"Sekinlashtirish","gui.soundEditor.echo":"Sado","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Kattaroq","gui.soundEditor.softer":"Kichikroq","gui.soundEditor.reverse":"Teskarisiga o\'girish","gui.soundEditor.fadeOut":"Fade out","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Mute","gui.SpriteInfo.spritePlaceholder":"Nomi","gui.SpriteInfo.sprite":"Sprayt","gui.SpriteInfo.show":"Koʻrsatish","gui.SpriteInfo.size":"O\'lchami","gui.spriteSelectorItem.contextMenuDuplicate":"nusxasini yaratish","gui.spriteSelectorItem.contextMenuExport":"eksport qilish","gui.spriteSelectorItem.contextMenuDelete":"o\'chirish","gui.spriteSelector.addSpriteFromLibrary":"Sprayt tanlash","gui.spriteSelector.addSpriteFromPaint":"Chizish","gui.spriteSelector.addSpriteFromSurprise":"Ajablanish","gui.spriteSelector.addSpriteFromFile":"Spraytni yuklab olish","gui.stageHeader.stageSizeLarge":"Katta bosqichga o\'ting","gui.stageHeader.stageSizeSmall":"Kichik bosqichga o\'ting","gui.stageHeader.stageSizeFull":"To\'liq ekran rejimiga o\'tish","gui.stageHeader.stageSizeUnFull":"To\'liq ekrandan chiqish","gui.stageHeader.fullscreenControl":"To\'liq ekran nazorati","gui.spriteSelector.addBackdropFromLibrary":"Fonni tanlash","gui.stageSelector.addBackdropFromPaint":"Chizish","gui.stageSelector.addBackdropFromSurprise":"Ajablanish","gui.stageSelector.addBackdropFromFile":"Orqa fonni yuklab olish","gui.stageSelector.stage":"Sahna","gui.stageSelector.backdrops":"Fonlar","gui.telemetryOptIn.label":"Yo\'naltirishni yaxshilash statistikasi","gui.telemetryOptIn.body1":"Scratch jamoasi har doim Scratchning butun dunyoda qanday qo\'llanilishini yaxshiroq tushunishga harakat qilmoqda. Ushbu ishni qo\'llab-quvvatlash uchun, Scratch-dan foydalanish ma\'lumotlarini avtomatik ravishda Scratch Team-ga yuborishingiz mumkin.","gui.telemetryOptIn.body2":"Biz to\'playdigan ma\'lumotlarga tilni tanlash, blokni ishlatish va loyihani saqlash, yuklash va yuklash kabi ba\'zi hodisalar kiradi. Biz shaxsiy ma\'lumotlarni to\'plamaymiz. Qo\'shimcha ma\'lumot olish uchun, iltimos, {privacyPolicyLink} -ga qarang.","gui.telemetryOptIn.privacyPolicyLink":"Shaxsiy ma\'lumotni himoya siyosati","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Turbo Rejimi","gui.webglModal.label":"Brauzeringiz WebGL-ni qo\'llab-quvvatlamaydi","gui.webglModal.webgllink":"webgl-ni qo\'llab-quvvatlamaydi","gui.costumeLibrary.chooseABackdrop":"Fonni tanlash","gui.costumeLibrary.chooseACostume":"Ko\'rinishni tanlash","gui.costumeTab.addBackdropFromLibrary":"Fonni tanlash","gui.costumeTab.addCostumeFromLibrary":"Ko\'rinishni tanlash","gui.costumeTab.addBlankCostume":"Chizish","gui.costumeTab.addSurpriseCostume":"Ajablanish","gui.costumeTab.addFileBackdrop":"Orqa fonni yuklab olish","gui.costumeTab.addFileCostume":"Ko\'rinishni yuklab olish","gui.extensionLibrary.chooseAnExtension":"Kengaytmani tanlang","gui.extensionLibrary.extensionUrl":"Kengaytma URL manzilini kiriting","gui.monitors.importListColumnPrompt":"Qanday yangi chiziqdan foydalanilsin?(1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Ovoz yozishni boshlab bo\'lmaydi","gui.soundLibrary.chooseASound":"Ovozni tanlash","gui.soundTab.fileUploadSound":"Ovozni yuklash","gui.soundTab.surpriseSound":"Ajablanish","gui.soundTab.recordSound":"Ovoz yozish","gui.soundTab.addSoundFromLibrary":"Ovozni tanlash","gui.spriteLibrary.chooseASprite":"Sprayt tanlash","gui.tipsLibrary.tutorials":"Bir darslik tanlash","gui.alerts.createsuccess":"Yangi loyiha yaratildi.","gui.alerts.createcopysuccess":"Loyiha nusxasi sifatida saqlandi.","gui.alerts.createremixsuccess":"Loyiha remix sifatida saqlandi.","gui.alerts.creating":"Yangi yaratish ...","gui.alerts.creatingCopy":"Loyihani nusxalash ...","gui.alerts.creatingRemix":"Loyihani qayta tuzish ...","gui.alerts.creatingError":"Loyihani yaratib bo\'lmadi. Qayta urinib ko\'ring!","gui.alerts.savingError":"Loyihani saqlab bo\'lmadi.","gui.alerts.savesuccess":"Loyiha saqlandi.","gui.alerts.saving":"Loyihani saqlash ...","gui.alerts.cloudInfo":"Bulutli o\'zgaruvchilar faqat harflar yoki belgilar emas, balki raqamlarni qo\'llab-quvvatlaydi. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Ko\'proq ma\'lumot oling.","gui.alerts.importing":"Import qilinmoqda ...","gui.defaultProject.variable":"mening o\'zgaruvchim","gui.extension.music.name":"Musiqa","gui.extension.music.description":"Musiqa saboblari va barabanlarni ijro etish","gui.extension.pen.name":"Qalam","gui.extension.pen.description":"Spraytdan foydalanib chizib ko\'ring","gui.extension.videosensing.name":"Vidioni taqiqlash","gui.extension.videosensing.description":"Kamera bilan harakatlanishning ma\'nosi.","gui.extension.text2speech.name":"Matn ovozini o\'zgartirish","gui.extension.text2speech.description":"Loyihalaringizni muhokama qiling.","gui.extension.translate.name":"Tarjima","gui.extension.translate.description":"Matnni turli xil tillarga tarjima qilib ko\'ring.","gui.extension.makeymakey.description":"Nima bo\'lsa ham klavyatura orqala yaratib ko\'ring","gui.extension.microbit.description":"Loyihani dunyo bilan ulashib ko\'ring","gui.extension.microbit.connectingMessage":"Unalmoqda...","gui.extension.ev3.description":"Interaktiv robotlarni va boshqalarni yarating.","gui.extension.ev3.connectingMessage":"Ulanmoqda...EV3 dagi pin 1234 ga o\'rnatilganligi tekshirib ko\'ring","gui.extension.boost.description":"Robot mavjudotlariga hayotga olib keling","gui.extension.boost.connectingMessage":"Ulanmoqda...","gui.extension.wedo2.description":"Motor va sensorlardan foydalanib yaratib ko\'ring","gui.extension.wedo2.connectingMessage":"Ulanmoqda...","gui.extension.gdxfor.description":"Surish, tortish, harakat va aylanishni sezish","gui.extension.gdxfor.connectingMessage":"Ulanmoqda...","gui.libraryTags.all":"Hammasi","gui.libraryTags.animals":"Hayvonlar","gui.libraryTags.dance":"Raqs","gui.libraryTags.effects":"Ta\'sir","gui.libraryTags.fantasy":"Fantastika","gui.libraryTags.fashion":"Moda","gui.libraryTags.food":"Oziq-ovqat","gui.libraryTags.indoors":"Uy ichkarisida","gui.libraryTags.loops":"Takrorlash","gui.libraryTags.music":"Musiqa","gui.libraryTags.notes":"Nota","gui.libraryTags.outdoors":"Tashqarida","gui.libraryTags.patterns":"Naqshlar","gui.libraryTags.people":"Odamlar","gui.libraryTags.percussion":"Cholg\'u asbob","gui.libraryTags.space":"Kosmos","gui.libraryTags.sports":"Sport","gui.libraryTags.underwater":"Dengiz osti","gui.libraryTags.voice":"Ovozi","gui.libraryTags.wacky":"G\'alati tovush","gui.libraryTags.animation":"Animatsiya","gui.libraryTags.art":"San’at","gui.libraryTags.games":"O‘yinlar","gui.libraryTags.stories":"Hikoyalar","gui.libraryTags.letters":"Harflar","gui.opcodeLabels.direction":"yo\'nalish","gui.opcodeLabels.xposition":"x kordinatasi","gui.opcodeLabels.yposition":"y kordinatasi","gui.opcodeLabels.size":"o\'lcham","gui.opcodeLabels.costumename":"kostyum nomi","gui.opcodeLabels.costumenumber":"kostyum raqami","gui.opcodeLabels.backdropname":"fon nomi","gui.opcodeLabels.backdropnumber":"fon raqami","gui.opcodeLabels.volume":"ovoz","gui.opcodeLabels.tempo":"Zarba tezligi","gui.opcodeLabels.answer":"javob","gui.opcodeLabels.loudness":"tovush","gui.opcodeLabels.username":"foydalanuvchi ismi","gui.opcodeLabels.year":"yil","gui.opcodeLabels.month":"oy","gui.opcodeLabels.date":"sana","gui.opcodeLabels.dayofweek":"hafta kuni","gui.opcodeLabels.hour":"soat","gui.opcodeLabels.minute":"daqiqa","gui.opcodeLabels.second":"soniya","gui.opcodeLabels.timer":"taymer","gui.sharedMessages.backdrop":"fon {index}","gui.sharedMessages.costume":"kostyum{index} ","gui.sharedMessages.sprite":"Sprayt {index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Xozirgi loyihani mazmunini almashtiringmi?","gui.sharedMessages.loadFromComputerTitle":"Kompyuteringizdan yuklab oling","boost.color.any":"ixtiyoriy rang","boost.color.black":"qora","boost.color.blue":"havo rang","boost.color.green":"yashil","boost.color.red":"qizil","boost.color.white":"oq","boost.color.yellow":"sariq","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] positsiyasi","boost.getTiltAngle":" [TILT_DIRECTION] burilish burchagi","boost.motorDirection.backward":"shu yo\'l","boost.motorDirection.forward":"shu yo\'l","boost.motorDirection.reverse":"teskari","boost.motorOff":"motor [MOTOR_ID]  ni ochiring","boost.motorOn":"motor [MOTOR_ID] ni yoqing","boost.motorOnFor":"motorni [MOTOR_ID] soniyalar [DURATION] davomida aylantiring","boost.motorOnForRotation":"motorni aylantiring [MOTOR_ID] aylanishi [ROTATION] uchun","boost.seeingColor":" [COLOR] rangdagi g\'ishtni ko\'ryapsizmi?","boost.setLightHue":"ochiq rangni [HUE] ga o\'rnatish","boost.setMotorDirection":"motorni joylashtirish [MOTOR_ID] yo\'nalishi [MOTOR_DIRECTION]","boost.setMotorPower":"motorni [MOTOR_ID] tezligini [POWER] ga qo\'ying","boost.tiltDirection.any":"Hech narsa","boost.tiltDirection.down":"pastga","boost.tiltDirection.left":"chapga","boost.tiltDirection.right":"oʻngga","boost.tiltDirection.up":"tepaga","boost.whenColor":"when [COLOR] brick seen","boost.whenTilted":"[TILT_DIRECTION_ANY] o\'girildikda","ev3.beepNote":"[TIME] soniya davomida [NOTE] ta ovozli signal eshitiladi","ev3.buttonPressed":"tugma [PORT] bosildimi?","ev3.getBrightness":"yorqinlik","ev3.getDistance":"masofa","ev3.getMotorPosition":"motor [PORT] holatiga o\'tish","ev3.motorSetPower":"motor [PORT] kuchini [POWER] % sozlash","ev3.motorTurnClockwise":"[PORT] Motorni [TIME] soniya davomida ushbu tomonga aylantiring","ev3.motorTurnCounterClockwise":"[PORT] Motorni [TIME] soniya davomida u er tomonga aylantiring","ev3.whenBrightnessLessThan":"Yorqinligi < [DISTANCE] bo\'lganda","ev3.whenButtonPressed":"[PORT] tugmasi bosilganda","ev3.whenDistanceLessThan":"masofa < [DISTANCE]","gdxfor.getAcceleration":"tezlashtirish [DIRECTION]","gdxfor.getForce":"kuch","gdxfor.getSpin":"siqish tezligi [DIRECTION]","gdxfor.getTilt":" [TILT] egilish","gdxfor.isFreeFalling":"tushganmi?","gdxfor.isTilted":"egilish burchagi [TILT]?","gdxfor.pulled":"tortdi","gdxfor.pushed":"itarib yuborishdi","gdxfor.shaken":"Shoklandi","gdxfor.startedFalling":"tushib ketdi","gdxfor.tiltDirectionMenu.any":"Hech narsa","gdxfor.tiltDirectionMenu.back":"orqaga","gdxfor.tiltDirectionMenu.front":"oldinga","gdxfor.tiltDirectionMenu.left":"chapga","gdxfor.tiltDirectionMenu.right":"oʻngga","gdxfor.turnedFaceDown":"yuzini pastga qaratdi","gdxfor.turnedFaceUp":"yuzi yuqoriga ko\'tarildi","gdxfor.whenForcePushedOrPulled":"Majburiy sensor [PUSH_PULL]","gdxfor.whenGesture":"[GESTURE] bo\'lganda","gdxfor.whenTilted":"[TILT] yiqilganida ","makeymakey.downArrow":"past ko\'rsatgich","makeymakey.downArrowShort":"pastga","makeymakey.leftArrow":"chap ko\'rsatgich","makeymakey.leftArrowShort":"chapga","makeymakey.rightArrow":"Oʻng koʻrsatkichi","makeymakey.rightArrowShort":"oʻngga","makeymakey.spaceKey":"bo\'sh joy","makeymakey.upArrow":"yuqori ko\'rsatgich","makeymakey.upArrowShort":"tepaga","makeymakey.whenKeyPressed":"[KEY] tugma bosilganda","makeymakey.whenKeysPressedInOrder":"[SEQUENCE] tartibda bosilganda ","microbit.buttonsMenu.any":"Hech narsa","microbit.clearDisplay":"aniq ko\'rsatiladi","microbit.defaultTextToDisplay":"Salom!","microbit.displaySymbol":"ekran [MATRIX]","microbit.displayText":"ekran yozuvi [TEXT]","microbit.gesturesMenu.jumped":"sakragan","microbit.gesturesMenu.moved":"harakatlangan","microbit.gesturesMenu.shaken":"silkingan","microbit.isButtonPressed":"[BTN] tugmasini bosdingizmi?","microbit.isTilted":"[DIRECTION] tomoniga egilish?","microbit.pinStateMenu.off":"o‘chiq","microbit.pinStateMenu.on":"yoniq","microbit.tiltAngle":"burilish burchagi [DIRECTION]","microbit.tiltDirectionMenu.any":"Hech narsa","microbit.tiltDirectionMenu.back":"orqaga","microbit.tiltDirectionMenu.front":"oldinga","microbit.tiltDirectionMenu.left":"chapga","microbit.tiltDirectionMenu.right":"oʻngga","microbit.whenButtonPressed":"[BTN] tugmasi bosilganda","microbit.whenGesture":"[GESTURE] bo\'lganda","microbit.whenPinConnected":"pin [PIN] ulanganda","microbit.whenTilted":"egilib [DIRECTION]","music.categoryName":"Musiqa","music.changeTempo":"tezlikni [TEMPO] o\'zgartirish","music.drumBass":"(2) Baraban ","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Kabasa","music.drumClaves":"(9) Klave","music.drumClosedHiHat":"(6) yopiq hay-het","music.drumConga":"(14) konga","music.drumCowbell":"(11) Kovbell","music.drumCrashCymbal":"(4) Kresh","music.drumCuica":"(18) Kuika","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Qarsak","music.drumOpenHiHat":"(5) Ochiq hay-het","music.drumSideStick":"(3) Side Stick","music.drumSnare":"(1) Kichik baraban","music.drumTambourine":"(7) Tamburin","music.drumTriangle":"(12) Uchburchak","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Korobo\'chka","music.getTempo":"tezlik","music.instrumentBass":"(6) Bass","music.instrumentBassoon":"(14) Fago\'t","music.instrumentCello":"(8) Violonchel ","music.instrumentChoir":"(15) Xo\'r","music.instrumentClarinet":"(10) Klarnet","music.instrumentElectricGuitar":"(5) Elektr gitara","music.instrumentElectricPiano":"(2) Elektr pianino","music.instrumentFlute":"(12) Fleyta","music.instrumentGuitar":"(4) Gitara","music.instrumentMarimba":"(19) Marimba ","music.instrumentMusicBox":"(17) Musiqa qutisi","music.instrumentOrgan":"(3) Organ","music.instrumentPiano":"(1) Pianino","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saksafon","music.instrumentSteelDrum":"(18) Temirli baraban","music.instrumentSynthLead":"(20) Sentezator","music.instrumentSynthPad":"(21) Synth Pad","music.instrumentTrombone":"(9) Trombon","music.instrumentVibraphone":"(16) Vibrafon","music.instrumentWoodenFlute":"(13) Yog\'ochli Floyd","music.midiPlayDrumForBeats":"[DRUM] asbobda [BEATS] zarbada ijro etish","music.midiSetInstrument":"asbobni [INSTRUMENT]ga sozlash","music.playDrumForBeats":"[DRUM] asbobda [BEATS] zarbada ijro etish","music.playNoteForBeats":"[NOTE] ni [BEATS] zarbada ijro etish","music.restForBeats":"[BEATS] zarba kutish","music.setInstrument":"asbobni [INSTRUMENT] ga sozlash","music.setTempo":"tezlikni [TEMPO] ga sozlash","pen.categoryName":"Qalam ","pen.changeColorParam":"qalamni [COLOR_PARAM] [VALUE] ga o\'zgartirish ","pen.changeHue":"qalam rangini [HUE] ga o\'zgartirish","pen.changeShade":"[SHADE] tomonidan qalam shadi o\'zgarishi","pen.changeSize":"qalam o\'lchamini [SIZE] ga o\'zgartirish","pen.clear":"tozalash","pen.colorMenu.brightness":"yorqinlik","pen.colorMenu.color":"rang","pen.colorMenu.saturation":"to\'qlik","pen.colorMenu.transparency":"tiniqlik","pen.penDown":"qalamni tushirish","pen.penUp":"qalamni ko\'tarish","pen.setColor":"qalam rangini [COLOR] ga sozlash","pen.setColorParam":"qalamni [COLOR_PARAM] [VALUE] ga sozlash","pen.setHue":"qalam rangini [HUE] ga sozlash","pen.setShade":"[SHADE] ga sozlamalarni joylashtirish","pen.setSize":"qalam o\'lchamini [SIZE] ga sozlash","pen.stamp":"pechat qo\'yish","text2speech.alto":"Alto","text2speech.categoryName":"Matn ovozini o\'zgartirish","text2speech.defaultTextToSpeak":"salom","text2speech.giant":"ulkan ","text2speech.kitten":"mushukcha","text2speech.setLanguageBlock":"tilni [LANGUAGE]ga sozlash","text2speech.setVoiceBlock":"ovozni [VOICE] ga sozlash ","text2speech.speakAndWaitBlock":"gapirish [WORDS]","text2speech.squeak":"g\'ichirlash ","text2speech.tenor":"tenor","translate.categoryName":"Tarjima","translate.defaultTextToTranslate":"salom","translate.translateBlock":"[WORDS] ni [LANGUAGE] ga tarjima qilish","translate.viewerLanguage":"til","videoSensing.categoryName":"vidioni aniqlash","videoSensing.direction":"yo\'nalish","videoSensing.motion":"harakat","videoSensing.off":"o\'chirish","videoSensing.on":"yoqish","videoSensing.onFlipped":"tirnalgan","videoSensing.setVideoTransparency":"vidio shaffofligini [TRANSPARENCY] ga sozlash","videoSensing.sprite":"sprayt","videoSensing.stage":"bosqichda","videoSensing.videoOn":"vidio [ATTRIBUTE] da [SUBJECT]","videoSensing.videoToggle":"video [VIDEO_STATE] yoqing","videoSensing.whenMotionGreaterThan":"vidio harakati > [REFERENCE] bo\'lganda","wedo2.getDistance":"masofa","wedo2.getTiltAngle":" [TILT_DIRECTION] burilish burchagi","wedo2.isTilted":"tilga olingan [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"shu yo\'l","wedo2.motorDirection.forward":"shu yo\'l","wedo2.motorDirection.reverse":"teskari","wedo2.motorId.a":"motor A","wedo2.motorId.all":"hamma matorlar","wedo2.motorId.b":"mator B","wedo2.motorId.default":"motor","wedo2.motorOff":"[MOTOR_ID] ni o\'chiring","wedo2.motorOn":"[MOTOR_ID] ni yoqing","wedo2.motorOnFor":"[DURATION] soniya uchun [MOTOR_ID] yoqing","wedo2.playNoteFor":"[DURATION] soniya uchun [NOTE] eslatmasini ijro eting","wedo2.setLightHue":"ochiq rangni [HUE] ga o\'rnatish","wedo2.setMotorDirection":"[MOTOR_ID] yo\'nalishini [MOTOR_DIRECTION] tomonga o\'rnatish","wedo2.startMotorPower":"[MOTOR_ID] kuchini [POWER] ga qo\'ying","wedo2.tiltDirection.any":"Hech narsa","wedo2.tiltDirection.down":"pastga","wedo2.tiltDirection.left":"chapga","wedo2.tiltDirection.right":"oʻngga","wedo2.tiltDirection.up":"tepaga","wedo2.whenDistance":"[OP] [REFERENCE] ga yetganingizda","wedo2.whenTilted":"[TILT_DIRECTION_ANY] o\'girildikda","paint.paintEditor.hue":"Rang","paint.paintEditor.saturation":"To\'yinganlik","paint.paintEditor.brightness":"Yorqinlik","paint.paintEditor.costume":"Kostyum","paint.paintEditor.group":"Guruh","paint.paintEditor.ungroup":"Guruhlashni bekor qilish","paint.paintEditor.undo":"Bekor qilish","paint.paintEditor.redo":"Qaytarish","paint.paintEditor.forward":"Oldiga","paint.paintEditor.backward":"Orqaga","paint.paintEditor.front":"Eng oldiga","paint.paintEditor.back":"Eng orqaga","paint.paintEditor.more":"Ko\'proq","paint.modeTools.brushSize":"O\'lchami","paint.modeTools.eraserSize":"O\'chirg\'ich o\'lchami","paint.modeTools.copy":"Nusxa olish","paint.modeTools.paste":"Joylashtirish","paint.modeTools.delete":"O\'chirish","paint.modeTools.curved":"Egri","paint.modeTools.pointed":"Ko\'rsatilgan","paint.modeTools.thickness":"Qalinligi","paint.modeTools.flipHorizontal":"Chapdan o\'ngga burish","paint.modeTools.flipVertical":"Yuqoridan pastga burish","paint.modeTools.filled":"Bo\'yash","paint.modeTools.outlined":"Qisqartirilgan","paint.paintEditor.bitmap":"Rastr tasvirga o\'zgartirish","paint.paintEditor.vector":"Vektor tasvirga o\'zgartirish","paint.paintEditor.fill":"To\'ldirish","paint.paintEditor.stroke":"Ramqa","paint.brushMode.brush":"Kistichka","paint.eraserMode.eraser":"O\'chirg\'ich","paint.fillMode.fill":"Bo\'yash","paint.lineMode.line":"Chiziq","paint.ovalMode.oval":"Aylana","paint.rectMode.rect":"Toʻrtburchak","paint.reshapeMode.reshape":"Burchakli to\'rtburchak","paint.roundedRectMode.roundedRect":"Aval shakl berish","paint.selectMode.select":"Tanlash","paint.textMode.text":"Yozuv","paint.colorPicker.swap":"Almashtirish"},"th":{"gui.alerts.tryAgain":"ลองใหม่อีกครั้ง","gui.alerts.download":"ดาวน์โหลด","gui.connection.reconnect":"เชื่อมต่อใหม่","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"กระเป๋าเป้","gui.backpack.errorBackpack":"เกิดความผิดพลาดขณะโหลดกระเป๋าเป้","gui.backpack.loadingBackpack":"กำลังโหลด...","gui.backpack.more":"เพิ่มเติม","gui.backpack.emptyBackpack":"กระเป๋าเป้ว่างเปล่า","gui.unsupportedBrowser.label":"ไม่รองรับเบราเซอร์","gui.cards.all-tutorials":"บทเรียน","gui.cards.shrink":"หด","gui.cards.expand":"คลี่ออก","gui.cards.close":"ปิด","gui.cards.more-things-to-try":"มีอีกเยอะให้ลอง!","gui.cards.see-more":"ดูเพิ่มเติม","gui.comingSoon.message1":"ไม่ต้องกังวล เรากำลังทำอยู่ {emoji}","gui.comingSoon.message2":"เร็วๆ นี้...","gui.comingSoon.message3":"เรากำลังทำอยู่ {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"ไม่พบอุปกรณ์","gui.connection.auto-scanning.prescan":"นำอุปกรณ์ของคุณมาใกล้ๆ จากนั้นเริ่มค้นหา","gui.connection.auto-scanning.pressbutton":"กดปุ่มที่อุปกรณ์ของคุณ","gui.connection.auto-scanning.start-search":"เริ่มค้นหา","gui.connection.connecting-searchbutton":"ค้นหา...","gui.connection.auto-scanning.try-again":"ลองใหม่อีกครั้ง","gui.connection.connected":"เชื่อมต่อแล้ว","gui.connection.disconnect":"ตัดการเชื่อมต่อ","gui.connection.go-to-editor":"กลับไปยังตัวแก้ไขโค้ด","gui.connection.connecting-cancelbutton":"กำลังเชื่อมต่อ...","gui.connection.error.errorMessage":"อ๊ะ ดูเหมือนว่ามีบางอย่างผิดพลาด","gui.connection.error.tryagainbutton":"ลองใหม่อีกครั้ง","gui.connection.error.helpbutton":"ช่วยเหลือ","gui.connection.peripheral-name-label":"ชื่ออุปกรณ์","gui.connection.connect":"เชื่อมต่อ","gui.connection.scanning.lookingforperipherals":"กำลังมองหาอุปกรณ์","gui.connection.scanning.noPeripheralsFound":"ไม่พบอุปกรณ์","gui.connection.scanning.instructions":"เลือกอุปกรณ์ของคุณในรายการด้านบน","gui.connection.search":"รีเฟรช","gui.connection.unavailable.installscratchlink":"ตรวจสอบว่าคุณได้ติดตั้ง Scratch Link และเปิดใช้งานอยู่","gui.connection.unavailable.enablebluetooth":"ตรวจสอบว่าเปิด Bluetooth แล้ว","gui.connection.unavailable.tryagainbutton":"ลองใหม่อีกครั้ง","gui.connection.unavailable.helpbutton":"ช่วยเหลือ","gui.controls.go":"ไป","gui.controls.stop":"หยุด","gui.crashMessage.label":"อุ๊ย! มีบางอย่างผิดพลาด","gui.crashMessage.errorNumber":"ข้อผิดพลาดของคุณได้ถูกเก็บบันทึกไว้ด้วยไอดี {errorId}","gui.crashMessage.reload":"โหลดใหม่","gui.customProcedures.myblockModalTitle":"สร้างบล็อกใหม่","gui.customProcedures.addAnInputNumberText":"เพิ่มช่องรับ","gui.customProcedures.numberTextType":"ตัวเลขหรือข้อความ","gui.customProcedures.addAnInputBoolean":"เพิ่มช่องรับ","gui.customProcedures.booleanType":"บูลีน","gui.customProcedures.addALabel":"เพิ่มข้อความ","gui.customProcedures.runWithoutScreenRefresh":"รันโดยไม่รีเฟรชหน้าจอ ","gui.customProcedures.cancel":"ยกเลิก","gui.customProcedures.ok":"ตกลง","gui.SpriteInfo.direction":"ทิศทาง","gui.directionPicker.rotationStyles.allAround":"รอบด้าน","gui.directionPicker.rotationStyles.leftRight":"ซ้าย/ขวา","gui.directionPicker.rotationStyles.dontRotate":"อย่าหมุน","gui.gui.addExtension":"เพิ่มส่วนขยาย","gui.gui.codeTab":"โค้ด","gui.gui.backdropsTab":"ฉากหลัง","gui.gui.costumesTab":"คอสตูม","gui.gui.soundsTab":"เสียง","gui.extensionLibrary.comingSoon":"เร็วๆ นี้","gui.extensionLibrary.requires":"ต้องการ","gui.extensionLibrary.collaboration":"ร่วมมือกับ","gui.library.filterPlaceholder":"ค้นหา","gui.library.allTag":"ทั้งหมด","gui.loader.headline":"กำลังโหลดโครงงาน","gui.loader.creating":"การสร้างโครงการ","gui.authorInfo.byUser":"โดย {username}","gui.menuBar.seeProjectPage":"ดูหน้าโครงงาน","gui.menuBar.LanguageSelector":"เลือกภาษา","gui.menuBar.tutorialsLibrary":"บทเรียน","gui.menuBar.restoreSprite":"กู้คืนสไปร์ท","gui.menuBar.restoreSound":"กู้คืนเสียง","gui.menuBar.restoreCostume":"กู้คืนคอสตูม","gui.menuBar.restore":"กู้คืน","gui.menuBar.saveNow":"บันทึกทันที","gui.menuBar.saveAsCopy":"บันทึกเป็น","gui.menuBar.remix":"รีมิกซ์","gui.menuBar.new":"ใหม่","gui.menuBar.file":"แฟ้ม","gui.menuBar.downloadToComputer":"บันทึกลงในคอมพิวเตอร์ของคุณ","gui.menuBar.edit":"แก้ไข","gui.menuBar.turboModeOff":"ปิดโหมดเทอร์โบ","gui.menuBar.turboModeOn":"เปิดโหมดเทอร์โบ","gui.gui.projectTitlePlaceholder":"ชื่อโครงงานที่นี่","gui.menuBar.isShared":"แบ่งปัน","gui.menuBar.share":"แชร์","gui.modal.help":"ช่วยเหลือ","gui.modal.back":"ย้อนกลับ","gui.monitor.listMonitor.empty":"(ว่างเปล่า)","gui.monitor.listMonitor.listLength":"ความยาว {length}","gui.monitor.contextMenu.default":"เปลี่ยนเป็นจอปกติ","gui.monitor.contextMenu.large":"เปลี่ยนเป็นจอใหญ่","gui.monitor.contextMenu.slider":"ตัวเลื่อน","gui.monitor.contextMenu.sliderRange":"เปลี่ยนระยะตัวเลื่อน","gui.monitor.contextMenu.import":"นำเข้า","gui.monitor.contextMenu.export":"ส่งออก","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"เล่น","gui.playButton.stop":"หยุด","gui.gui.variableScopeOptionAllSprites":"สำหรับสไปรต์ทั้งหมด","gui.gui.variableScopeOptionSpriteOnly":"สำหรับสไปรต์นี้เท่านั้น","gui.gui.cloudVariableOption":"ตัวแปรคลาวด์ (เก็บไว้บนเซิร์ฟเวอร์)","gui.gui.variablePromptAllSpritesMessage":"ตัวแปรนี้จะมีให้ใช้สำหรับสไปร์ททั้งหมด","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"ยกเลิก","gui.prompt.ok":"ตกลง","gui.playbackStep.stopMsg":"หยุด","gui.playbackStep.playMsg":"เล่น","gui.playbackStep.loadingMsg":"กำลังโหลด...","gui.playbackStep.saveMsg":"บันทึก","gui.playbackStep.reRecordMsg":"บันทึกใหม่","gui.recordModal.title":"บันทึกเสียง","gui.recordingStep.beginRecord":"เริ่มการอัดบันทึกโดยการคลิกปุ่มข้างล่าง","gui.recordingStep.permission":"{arrow}เราต้องได้รับอนุญาตจากคุณเพื่อใช้ไมโครโฟน","gui.recordingStep.stop":"หยุดการอัดบันทึก","gui.recordingStep.record":"อัดบันทึก","gui.sliderModal.min":"ค่าต่ำสุด","gui.sliderModal.max":"ค่าสูงสุด","gui.sliderModal.title":"เปลี่ยนระยะตัวเลื่อน","gui.sliderPrompt.cancel":"ยกเลิก","gui.sliderPrompt.ok":"ตกลง","gui.soundEditor.sound":"เสียง","gui.soundEditor.play":"เล่น","gui.soundEditor.stop":"หยุด","gui.soundEditor.copy":"คัดลอก","gui.soundEditor.paste":"วาง","gui.soundEditor.copyToNew":"Copy to New","gui.soundEditor.delete":"ลบ","gui.soundEditor.save":"บันทึก","gui.soundEditor.undo":"ย้อนกลับ","gui.soundEditor.redo":"ทำซ้ำ","gui.soundEditor.faster":"เร็วขึ้น","gui.soundEditor.slower":"ช้าลง","gui.soundEditor.echo":"สะท้อน","gui.soundEditor.robot":"หุ่นยนต์","gui.soundEditor.louder":"ดัง","gui.soundEditor.softer":"เบา","gui.soundEditor.reverse":"กลับด้าน","gui.soundEditor.fadeOut":"Fade out","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Mute","gui.SpriteInfo.spritePlaceholder":"ชื่อ","gui.SpriteInfo.sprite":"สไปรต์","gui.SpriteInfo.show":"แสดง","gui.SpriteInfo.size":"ขนาด","gui.spriteSelectorItem.contextMenuDuplicate":"ทำซ้ำ","gui.spriteSelectorItem.contextMenuExport":"ส่งออก","gui.spriteSelectorItem.contextMenuDelete":"ลบ","gui.spriteSelector.addSpriteFromLibrary":"เลือกสไปรต์","gui.spriteSelector.addSpriteFromPaint":"วาดรูป","gui.spriteSelector.addSpriteFromSurprise":"เซอร์ไพรส์","gui.spriteSelector.addSpriteFromFile":"อัปโหลดสไปรต์","gui.stageHeader.stageSizeLarge":"เปลี่ยนเป็นเวทีใหญ่","gui.stageHeader.stageSizeSmall":"เปลี่ยนเป็นเวทีเล็ก","gui.stageHeader.stageSizeFull":"เข้าโหมดเต็มจอ","gui.stageHeader.stageSizeUnFull":"ออกจากโหมดเต็มจอ","gui.stageHeader.fullscreenControl":"สลับโหมดเต็มจอ","gui.spriteSelector.addBackdropFromLibrary":"เลือกฉากหลัง","gui.stageSelector.addBackdropFromPaint":"วาดรูป","gui.stageSelector.addBackdropFromSurprise":"เซอร์ไพรส์","gui.stageSelector.addBackdropFromFile":"อัปโหลดฉากหลัง","gui.stageSelector.stage":"เวที","gui.stageSelector.backdrops":"ฉากหลัง","gui.telemetryOptIn.label":"รายงานสถิติเพื่อพัฒนาปรับปรุง Scratch","gui.telemetryOptIn.body1":"ทีมงาน Scratch พยายามหาวิธีที่จะเข้าใจว่าคนทั่วโลกใช้ Scratch อย่างไรบ้างอยู่เสมอ เพื่อช่วยสนับสนุนความพยายามเหล่านี้ คุณสามารถอนุญาตให้ Scratch ส่งข้อมูลการใช้งานต่าง ๆ ให้ทีมงาน Scratch โดยอัตโนมัติ","gui.telemetryOptIn.body2":"ข้อมูลที่เรารวบรวมนั้นประกอบด้วย ภาษาที่เลือก การใช้บล็อก และเหตุการณ์บางอย่างเช่น การบันทึก การโหลด และการอัปโหลดโครงงาน เราจะไม่เก็บข้อมูลส่วนตัวใด ๆ ทั้งสิ้น กรุณาเยี่ยมชม {privacyPolicyLink} เพื่อดูรายละเอียดเพิ่มเติม","gui.telemetryOptIn.privacyPolicyLink":"นโยบายความเป็นส่วนตัว","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"โหมดเทอร์โบ","gui.webglModal.label":"เบราเซอร์ของคุณไม่รองรับ WebGL","gui.webglModal.webgllink":"ไม่รองรับ WebGL","gui.costumeLibrary.chooseABackdrop":"เลือกฉากหลัง","gui.costumeLibrary.chooseACostume":"เลือกคอสตูม","gui.costumeTab.addBackdropFromLibrary":"เลือกฉากหลัง","gui.costumeTab.addCostumeFromLibrary":"เลือกคอสตูม","gui.costumeTab.addBlankCostume":"วาดรูป","gui.costumeTab.addSurpriseCostume":"เซอร์ไพรส์","gui.costumeTab.addFileBackdrop":"อัปโหลดฉากหลัง","gui.costumeTab.addFileCostume":"อัปโหลดคอสตูม","gui.extensionLibrary.chooseAnExtension":"เลือกส่วนขยาย","gui.extensionLibrary.extensionUrl":"ใส่ URL ของส่วนขยาย","gui.monitors.importListColumnPrompt":"คอลัมน์ไหนที่ควรจะนำมาใช้ (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"ไม่สามารถเริ่มบันทึกได้","gui.soundLibrary.chooseASound":"เลือกเสียง","gui.soundTab.fileUploadSound":"อัปโหลดเสียง","gui.soundTab.surpriseSound":"เซอร์ไพรส์","gui.soundTab.recordSound":"บันทึก","gui.soundTab.addSoundFromLibrary":"เลือกเสียง","gui.spriteLibrary.chooseASprite":"เลือกสไปรต์","gui.tipsLibrary.tutorials":"เลือกบทเรียน","gui.alerts.createsuccess":"โครงงานใหม่ได้ถูกสร้างแล้ว","gui.alerts.createcopysuccess":"บันทึกโครงงานเป็นแบบสำเนา","gui.alerts.createremixsuccess":"โครงงานบันทึกในฐานะรีมิกซ์","gui.alerts.creating":"กำลังสร้างขึ้นใหม่…","gui.alerts.creatingCopy":"กำลังคัดลอกโครงงาน...","gui.alerts.creatingRemix":"กำลังรีมิกซ์โครงงาน…","gui.alerts.creatingError":"ไม่สามารถสร้างโครงการได้ โปรดลองใหม่อีกครั้ง","gui.alerts.savingError":"โครงการไม่สามารถบันทึกได้","gui.alerts.savesuccess":"โครงงานถูกบันทึกแล้ว","gui.alerts.saving":"กำลังบันทึกโครงงาน...","gui.alerts.cloudInfo":"โปรดทราบว่า ตัวแปรคลาวด์รอบรับเฉพาะตัวเลขเท่านั้น ใช้ตัวอักษรหรือเครื่องหมายไม่ได้ {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"เรียนรู้เพิ่มเติม","gui.alerts.importing":"กำลังนำเข้า...","gui.defaultProject.variable":"ตัวแปรของฉัน","gui.extension.music.name":"ดนตรี","gui.extension.music.description":"เล่นเครื่องดนตรีและกลอง","gui.extension.pen.name":"ปากกา","gui.extension.pen.description":"วาดด้วยสไปรต์ของคุณ","gui.extension.videosensing.name":"การตรวจจับวิดีโอ","gui.extension.videosensing.description":"ตรวจจับการเคลื่อนไหวด้วยกล้อง","gui.extension.text2speech.name":"ข้อความเป็นเสียงพูด","gui.extension.text2speech.description":"ทำให้โครงงานของคุณพูดได้","gui.extension.translate.name":"แปลภาษา","gui.extension.translate.description":"แปลข้อความเป็นหลายภาษา","gui.extension.makeymakey.description":"ทำทุกอย่างให้เป็นกุญแจ","gui.extension.microbit.description":"เชื่อมต่อโครงงานของคุณกับทั่วโลก","gui.extension.microbit.connectingMessage":"กำลังเชื่อมต่อ","gui.extension.ev3.description":"สร้างหุ่นยนต์โต้ตอบและอื่นๆ","gui.extension.ev3.connectingMessage":"กำลังเชื่อมต่อ ตรวจสอบให้แน่ใจว่าขาของ EV3 ตั้งไว้ที่ 1234","gui.extension.boost.description":"ทำสิ่งประดิษฐ์หุ่นยนต์ให้มีชีวิต","gui.extension.boost.connectingMessage":"กำลังเชื่อมต่อ","gui.extension.wedo2.description":"สร้างด้วยมอเตอร์และเซนเซอร์","gui.extension.wedo2.connectingMessage":"กำลังเชื่อมต่อ","gui.extension.gdxfor.description":"รับรู้การผลัก การดึง การเคลื่อนไหว และการหมุน","gui.extension.gdxfor.connectingMessage":"กำลังเชื่อมต่อ","gui.libraryTags.all":"ทั้งหมด","gui.libraryTags.animals":"สัตว์","gui.libraryTags.dance":"การเต้นรำ","gui.libraryTags.effects":"เอฟเฟกต์","gui.libraryTags.fantasy":"ความเพ้อฝัน","gui.libraryTags.fashion":"แฟชั่น","gui.libraryTags.food":"อาหาร","gui.libraryTags.indoors":"ในบ้าน","gui.libraryTags.loops":"ลูป","gui.libraryTags.music":"ดนตรี","gui.libraryTags.notes":"โน้ต","gui.libraryTags.outdoors":"นอกบ้าน","gui.libraryTags.patterns":"ลวดลาย","gui.libraryTags.people":"ผู้คน","gui.libraryTags.percussion":"เครื่องเคาะ","gui.libraryTags.space":"อวกาศ","gui.libraryTags.sports":"กีฬา","gui.libraryTags.underwater":"ใต้น้ำ","gui.libraryTags.voice":"เสียงคน","gui.libraryTags.wacky":"ประหลาด","gui.libraryTags.animation":"แอนิเมชัน","gui.libraryTags.art":"ศิลปะ","gui.libraryTags.games":"เกม","gui.libraryTags.stories":"เรื่องราว","gui.libraryTags.letters":"ตัวอักษร","gui.opcodeLabels.direction":"ทิศทาง","gui.opcodeLabels.xposition":"ตำแหน่ง x ","gui.opcodeLabels.yposition":"ตำแหน่ง y","gui.opcodeLabels.size":"ขนาด","gui.opcodeLabels.costumename":"ชื่อคอสตูม","gui.opcodeLabels.costumenumber":"หมายเลขคอสตูม","gui.opcodeLabels.backdropname":"ชื่อฉากหลัง","gui.opcodeLabels.backdropnumber":"หมายเลขฉากหลัง","gui.opcodeLabels.volume":"ระดับเสียง","gui.opcodeLabels.tempo":"จังหวะ","gui.opcodeLabels.answer":"คำตอบ","gui.opcodeLabels.loudness":"ระดับความดัง","gui.opcodeLabels.username":"ชื่อผู้ใช้","gui.opcodeLabels.year":"ปี","gui.opcodeLabels.month":"เดือน","gui.opcodeLabels.date":"วันที่","gui.opcodeLabels.dayofweek":"วันของสัปดาห์","gui.opcodeLabels.hour":"ชั่วโมง","gui.opcodeLabels.minute":"นาที","gui.opcodeLabels.second":"วินาที","gui.opcodeLabels.timer":"ตัวจับเวลา","gui.sharedMessages.backdrop":"ฉากหลัง{index}","gui.sharedMessages.costume":"คอสตูม{index}","gui.sharedMessages.sprite":"สไปรต์{index}","gui.sharedMessages.pop":"ป๊อบ","gui.sharedMessages.replaceProjectWarning":"แทนที่เนื้อหาของโครงงานปัจจุบันหรือไม่?","gui.sharedMessages.loadFromComputerTitle":"อัปโหลดจากคอมพิวเตอร์ของคุณ","boost.color.any":"any color","boost.color.black":"ดำ","boost.color.blue":"น้ำเงิน","boost.color.green":"เขียว","boost.color.red":"แดง","boost.color.white":"ขาว","boost.color.yellow":"เหลือง","boost.getMotorPosition":"ตำแหน่งมอเตอร์ [MOTOR_REPORTER_ID]","boost.getTiltAngle":"มุมเอียง [TILT_DIRECTION]","boost.motorDirection.backward":"ทางนั้น","boost.motorDirection.forward":"ทางนี้","boost.motorDirection.reverse":"ย้อนกลับ","boost.motorOff":"ปิดมอเตอร์ [MOTOR_ID]","boost.motorOn":"เปิดมอเตอร์ [MOTOR_ID]","boost.motorOnFor":"turn motor [MOTOR_ID] for [DURATION] seconds","boost.motorOnForRotation":"turn motor [MOTOR_ID] for [ROTATION] rotations","boost.seeingColor":"seeing [COLOR] brick?","boost.setLightHue":"ตั้งสีหลอดไฟเป็น [HUE]","boost.setMotorDirection":"set motor [MOTOR_ID] direction [MOTOR_DIRECTION]","boost.setMotorPower":"set motor [MOTOR_ID] speed to [POWER] %","boost.tiltDirection.any":"ทิศใดก็ได้","boost.tiltDirection.down":"ลง","boost.tiltDirection.left":"ซ้าย","boost.tiltDirection.right":"ขวา","boost.tiltDirection.up":"ขึ้น","boost.whenColor":"when [COLOR] brick seen","boost.whenTilted":"เมื่อเอียง [TILT_DIRECTION_ANY]","ev3.beepNote":"เล่นโน้ต [NOTE] เป็นเวลา [TIME] วินาที","ev3.buttonPressed":"ปุ่ม [PORT] ถูกกด?","ev3.getBrightness":"ความสว่าง","ev3.getDistance":"ระยะห่าง","ev3.getMotorPosition":"ตำแหน่งมอเตอร์ [PORT]","ev3.motorSetPower":"ตั้งค่ากำลังมอเตอร์ [PORT] เป็น [POWER] %","ev3.motorTurnClockwise":"มอเตอร์ [PORT] หมุนทางนี้ เป็นเวลา [TIME] วินาที","ev3.motorTurnCounterClockwise":"มอเตอร์ [PORT] หมุนทางนั้น เป็นเวลา [TIME] วินาที","ev3.whenBrightnessLessThan":"เมื่อความสว่าง < [DISTANCE]","ev3.whenButtonPressed":"เมื่อกดปุ่ม [PORT]","ev3.whenDistanceLessThan":"เมื่อระยะห่าง < [DISTANCE]","gdxfor.getAcceleration":"เร่ง [DIRECTION]","gdxfor.getForce":"force","gdxfor.getSpin":"spin speed [DIRECTION]","gdxfor.getTilt":"tilt angle [TILT]","gdxfor.isFreeFalling":"ตกไหม?","gdxfor.isTilted":"tilted [TILT]?","gdxfor.pulled":"pulled","gdxfor.pushed":"pushed","gdxfor.shaken":"เขย่า","gdxfor.startedFalling":"เริ่มตกลงมา","gdxfor.tiltDirectionMenu.any":"ทิศใดก็ได้","gdxfor.tiltDirectionMenu.back":"หลัง","gdxfor.tiltDirectionMenu.front":"หน้า","gdxfor.tiltDirectionMenu.left":"ซ้าย","gdxfor.tiltDirectionMenu.right":"ขวา","gdxfor.turnedFaceDown":"turned face down","gdxfor.turnedFaceUp":"turned face up","gdxfor.whenForcePushedOrPulled":"when force sensor [PUSH_PULL]","gdxfor.whenGesture":"เมื่อ [GESTURE]","gdxfor.whenTilted":"when tilted [TILT]","makeymakey.downArrow":"ลูกศรลง","makeymakey.downArrowShort":"ลง","makeymakey.leftArrow":"ลูกศรซ้าย","makeymakey.leftArrowShort":"ซ้าย","makeymakey.rightArrow":"ลูกศรขวา","makeymakey.rightArrowShort":"ขวา","makeymakey.spaceKey":"สเปซบาร์","makeymakey.upArrow":"ลูกศรขึ้น","makeymakey.upArrowShort":"ขึ้น","makeymakey.whenKeyPressed":"เมื่อคีย์ [KEY] ถูกกด","makeymakey.whenKeysPressedInOrder":"when [SEQUENCE] pressed in order","microbit.buttonsMenu.any":"ทิศใดก็ได้","microbit.clearDisplay":"ล้างหน้าจอ","microbit.defaultTextToDisplay":"Sawasdee!","microbit.displaySymbol":"แสดง [MATRIX]","microbit.displayText":"แสดงข้อความ [TEXT]","microbit.gesturesMenu.jumped":"กระโดด","microbit.gesturesMenu.moved":"เคลื่อนไหว","microbit.gesturesMenu.shaken":"เขย่า","microbit.isButtonPressed":"ปุ่ม [BTN] ถูกกด?","microbit.isTilted":"เอียง [DIRECTION]?","microbit.pinStateMenu.off":"ปิด","microbit.pinStateMenu.on":"เปิด","microbit.tiltAngle":"มุมเอียง [DIRECTION]","microbit.tiltDirectionMenu.any":"ทิศใดก็ได้","microbit.tiltDirectionMenu.back":"หลัง","microbit.tiltDirectionMenu.front":"หน้า","microbit.tiltDirectionMenu.left":"ซ้าย","microbit.tiltDirectionMenu.right":"ขวา","microbit.whenButtonPressed":"เมื่อปุ่ม [BTN] ถูกกด","microbit.whenGesture":"เมื่อ [GESTURE]","microbit.whenPinConnected":"เมื่อขา [PIN] เชื่อมต่อแล้ว","microbit.whenTilted":"เมื่อเอียง [DIRECTION]","music.categoryName":"ดนตรี","music.changeTempo":"เปลี่ยนความเร็วทีละ [TEMPO]","music.drumBass":"(2) กลองใหญ่","music.drumBongo":"(13) บองโก","music.drumCabasa":"(15) คาบาซา","music.drumClaves":"(9) เคลฟ","music.drumClosedHiHat":"(6) ฉาบไฮแฮทปิด","music.drumConga":"(14) คองกา","music.drumCowbell":"(11) คาวเบล","music.drumCrashCymbal":"(4) ฉาบ","music.drumCuica":"(18) คุยกา","music.drumGuiro":"(16) กวีโร","music.drumHandClap":"(8) ตบมือ","music.drumOpenHiHat":"(5) ฉาบไฮแฮทเปิด","music.drumSideStick":"(3) ไซด์สติค","music.drumSnare":"(1) กลองเล็ก","music.drumTambourine":"(7) แทมบูรีน","music.drumTriangle":"(12) กิ๋ง","music.drumVibraslap":"(17) ไวบราสแลป","music.drumWoodBlock":"(10) วูดบล็อก","music.getTempo":"จังหวะ","music.instrumentBass":"(6) เบส","music.instrumentBassoon":"(14) บาสซูน","music.instrumentCello":"(8) เชลโล","music.instrumentChoir":"(15) เสียงประสาน","music.instrumentClarinet":"(10) แคลริเน็ต","music.instrumentElectricGuitar":"(5) กีต้าร์ไฟฟ้า ","music.instrumentElectricPiano":"(2) เปียโนไฟฟ้า","music.instrumentFlute":"(12) ฟลูต","music.instrumentGuitar":"(4) กีตาร์","music.instrumentMarimba":"(19) มาริมบา","music.instrumentMusicBox":"(17) กล่องดนตรี ","music.instrumentOrgan":"(3) ออร์แกน","music.instrumentPiano":"(1) เปียโน","music.instrumentPizzicato":"(7) พิซซิคาโต","music.instrumentSaxophone":"(11) แซกโซโฟน","music.instrumentSteelDrum":"(18) กลองเหล็ก","music.instrumentSynthLead":"(20) ซินธ์ลีด","music.instrumentSynthPad":"(21) ซินธ์แพด","music.instrumentTrombone":"(9) ทรอมโบน","music.instrumentVibraphone":"(16) ไวปราโฟน","music.instrumentWoodenFlute":"(13) ฟลูตไม้","music.midiPlayDrumForBeats":"เล่น [DRUM] [BEATS] จังหวะ","music.midiSetInstrument":"ตั้งเครื่องดนตรีเป็น [INSTRUMENT]","music.playDrumForBeats":"เล่น [DRUM] [BEATS] จังหวะ","music.playNoteForBeats":"เล่นโน๊ต [NOTE] [BEATS] จังหวะ","music.restForBeats":"หยุด [BEATS] จังหวะ","music.setInstrument":"ตั้งเครื่องดนตรีเป็น [INSTRUMENT]","music.setTempo":"ตั้งค่าความเร็วเป็น [TEMPO]จังหวะต่อนาที ","pen.categoryName":"ปากกา","pen.changeColorParam":"เปลี่ยน [COLOR_PARAM] ปากกาทีละ [VALUE]","pen.changeHue":"เปลี่ยนสีปากกาทีละ [HUE]","pen.changeShade":"เปลี่ยนเฉดสีปากกาทีละ [SHADE]","pen.changeSize":"เปลี่ยนขนาดปากกาทีละ [SIZE]","pen.clear":"ลบทั้งหมด","pen.colorMenu.brightness":"ความสว่าง","pen.colorMenu.color":"สี","pen.colorMenu.saturation":"ความอิ่มตัวของสี","pen.colorMenu.transparency":"ความโปร่งใส","pen.penDown":"จรดปากกา","pen.penUp":"ยกปากกาขึ้น","pen.setColor":"ตั้งค่าสีปากกาเป็น [COLOR]","pen.setColorParam":"ตั้งค่า [COLOR_PARAM] ปากกาเป็น[VALUE]","pen.setHue":"ตั้งสีปากกาเป็น [HUE]","pen.setShade":"ตั้งค่าเฉดสีเป็น [SHADE]","pen.setSize":"ตั้งขนาดปากกาเป็น [SIZE]","pen.stamp":"ประทับ","text2speech.alto":"อัลโต","text2speech.categoryName":"ข้อความเป็นเสียงพูด","text2speech.defaultTextToSpeak":"สวัสดี","text2speech.giant":"ไจแอนท์","text2speech.kitten":"ลูกแมว","text2speech.setLanguageBlock":"ตั้งภาษาเป็น [LANGUAGE]","text2speech.setVoiceBlock":"ตั้งเสียงเป็น [VOICE]","text2speech.speakAndWaitBlock":"พูด [WORDS]","text2speech.squeak":"เอี๊ยด ๆ","text2speech.tenor":"เทเนอร์","translate.categoryName":"แปลภาษา","translate.defaultTextToTranslate":"สวัสดี","translate.translateBlock":"แปล [WORDS] เป็น [LANGUAGE]","translate.viewerLanguage":"ภาษา","videoSensing.categoryName":"การตรวจจับวิดีโอ","videoSensing.direction":"ทิศทาง","videoSensing.motion":"การเคลื่อนไหว","videoSensing.off":"ปิด","videoSensing.on":"เปิด","videoSensing.onFlipped":"พลิก","videoSensing.setVideoTransparency":"ตั้งค่าความโปร่งใสของวิดีโอเป็น [TRANSPARENCY]","videoSensing.sprite":"สไปรต์","videoSensing.stage":"เวที","videoSensing.videoOn":"[ATTRIBUTE] วิดีโอ บน [SUBJECT]","videoSensing.videoToggle":"[VIDEO_STATE] วิดีโอ","videoSensing.whenMotionGreaterThan":"เมื่อวิดีโอเคลื่อนไหว > [REFERENCE]","wedo2.getDistance":"ระยะทาง","wedo2.getTiltAngle":"มุมเอียง [TILT_DIRECTION]","wedo2.isTilted":"เอียง [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"ทางนั้น","wedo2.motorDirection.forward":"ทางนี้","wedo2.motorDirection.reverse":"ย้อนกลับ","wedo2.motorId.a":"มอเตอร์ A","wedo2.motorId.all":"มอเตอร์ทั้งหมด","wedo2.motorId.b":"มอเตอร์ B","wedo2.motorId.default":"มอเตอร์","wedo2.motorOff":"ปิดมอเตอร์[MOTOR_ID] ","wedo2.motorOn":"เปิดมอเตอร์ [MOTOR_ID]","wedo2.motorOnFor":"เปิดมอเตอร์ [MOTOR_ID] เป็นเวลา [DURATION] วินาที","wedo2.playNoteFor":"เล่นโน้ต [NOTE] เป็นเวลา [DURATION] วินาที","wedo2.setLightHue":"ตั้งสีหลอดไฟเป็น [HUE]","wedo2.setMotorDirection":"ตั้งทิศทางมอเตอร์ [MOTOR_ID] เป็น [MOTOR_DIRECTION]","wedo2.startMotorPower":"ตั้งค่ากำลังมอเตอร์ [MOTOR_ID] เป็น [POWER]","wedo2.tiltDirection.any":"ทิศใดก็ได้","wedo2.tiltDirection.down":"ลง","wedo2.tiltDirection.left":"ซ้าย","wedo2.tiltDirection.right":"ขวา","wedo2.tiltDirection.up":"ขึ้น","wedo2.whenDistance":"เมื่อระยะห่าง [OP] [REFERENCE]","wedo2.whenTilted":"เมื่อเอียง [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"สี","paint.paintEditor.saturation":"ความอิ่มตัว","paint.paintEditor.brightness":"ความสว่าง","paint.paintEditor.costume":"คอสตูม","paint.paintEditor.group":"กลุ่ม","paint.paintEditor.ungroup":"แยกกลุ่ม","paint.paintEditor.undo":"ย้อนกลับ","paint.paintEditor.redo":"ทำซ้ำ","paint.paintEditor.forward":"มาข้างหน้า","paint.paintEditor.backward":"ไปข้างหลัง","paint.paintEditor.front":"หน้าสุด","paint.paintEditor.back":"หลังสุด","paint.paintEditor.more":"เพิ่มเติม","paint.modeTools.brushSize":"ขนาด","paint.modeTools.eraserSize":"ขนาดยางลบ","paint.modeTools.copy":"คัดลอก","paint.modeTools.paste":"วาง","paint.modeTools.delete":"ลบ","paint.modeTools.curved":"โค้ง","paint.modeTools.pointed":"แหลม","paint.modeTools.thickness":"ความหนา","paint.modeTools.flipHorizontal":"พลิกแนวนอน","paint.modeTools.flipVertical":"พลิกแนวตั้ง","paint.modeTools.filled":"เติมสี","paint.modeTools.outlined":"สีขอบ","paint.paintEditor.bitmap":"แปลงเป็นบิตแมป","paint.paintEditor.vector":"แปลงเป็นเวกเตอร์","paint.paintEditor.fill":"สีพื้น","paint.paintEditor.stroke":"สีขอบ","paint.brushMode.brush":"แปรง","paint.eraserMode.eraser":"ยางลบ","paint.fillMode.fill":"สีพื้น","paint.lineMode.line":"เส้น","paint.ovalMode.oval":"วงกลม","paint.rectMode.rect":"สี่เหลี่ยม","paint.reshapeMode.reshape":"จัดรูปร่างใหม่","paint.roundedRectMode.roundedRect":"สี่เหลี่ยมขอบมน","paint.selectMode.select":"เลือก","paint.textMode.text":"ข้อความ","paint.colorPicker.swap":"สลับสี","tw.settingsModal.featured":"ได้รับการฟีเจอร์","tw.usernameModal.reset":"รีเซ็ต"},"km":{"gui.alerts.tryAgain":"ព្យាយាមម្តងទៀត","gui.alerts.download":"ទាញយក","gui.connection.reconnect":"ភ្ជាប់ម្តងទៀត","gui.backpack.costumeLabel":"រូបរាង","gui.backpack.soundLabel":"សម្លេង","gui.backpack.scriptLabel":"ស្រ្គីប","gui.backpack.spriteLabel":"តួអង្គ","gui.backpack.header":"កាបូបស្ពាយ","gui.backpack.errorBackpack":"មានបញ្ហាពេលដំណើរការកាបូបស្ពាយ","gui.backpack.loadingBackpack":"កំពុងដំណើរការ...","gui.backpack.more":"ច្រើនទៀត","gui.backpack.emptyBackpack":"កាបូបស្ពាយទទេ","gui.unsupportedBrowser.label":"កម្មវិធីរុករកមិនអាចប្រើបាន","gui.cards.all-tutorials":"ការបង្ហាញ","gui.cards.shrink":"បង្រួម","gui.cards.expand":"ពង្រីក","gui.cards.close":"បិទ","gui.cards.more-things-to-try":"របស់ច្រើនទៀតសម្រាប់សាក!","gui.cards.see-more":"មើលច្រើនទៀត","gui.comingSoon.message1":"កុំបារម្ភ! ពួកយើងកំពុងតែធ្វើការលើហ្នឹងហើយ {emoji}","gui.comingSoon.message2":"មកដល់ឆាប់ៗ...","gui.comingSoon.message3":"ពួកយើងកំពុងតែធ្វើការលើហ្នឹងហើយ {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"រកមិនឃើញឧបករណ៍ទេ","gui.connection.auto-scanning.prescan":"ដាក់ឧបករណ៍នៅជិតៗនេះ រួចចាប់ផ្តើមស្វែងរក","gui.connection.auto-scanning.pressbutton":"ចុចប៊ូតុងលើឧបករណ៍របស់អ្នក","gui.connection.auto-scanning.start-search":"ចាប់ផ្តើមស្វែងរក","gui.connection.connecting-searchbutton":"កំពុងស្វែងរក...","gui.connection.auto-scanning.try-again":"សាកម្តងទៀត","gui.connection.connected":"បានភ្ជាប់","gui.connection.disconnect":"ផ្តាច់","gui.connection.go-to-editor":"ទៅកាន់កម្មវិធីសរសេរ","gui.connection.connecting-cancelbutton":"កំពុងភ្ជាប់...","gui.connection.error.errorMessage":"អុញនុះ! ដូចជាមានអីខុស!","gui.connection.error.tryagainbutton":"សាកម្តងទៀត","gui.connection.error.helpbutton":"ជំនួយ","gui.connection.peripheral-name-label":"ឈ្មោះឧបករណ៍","gui.connection.connect":"ភ្ជាប់","gui.connection.scanning.lookingforperipherals":"កំពុងរកមើលឧបករណ៍","gui.connection.scanning.noPeripheralsFound":"រកមិនឃើញឧបករណ៍ទេ","gui.connection.scanning.instructions":"ជ្រើសរើសឧបករណ៍របស់អ្នកពីក្នុងបញ្ជីខាងលើ","gui.connection.search":"ធ្វើជាថ្មី","gui.connection.unavailable.installscratchlink":"សូមឲ្យប្រាកដថាអ្នកបានដំឡើង Scratch Link ហើយវាកំពុងដំណើរការ","gui.connection.unavailable.enablebluetooth":"ពិនិត្យថា Bluetooth ត្រូវបានបើក","gui.connection.unavailable.tryagainbutton":"សាកម្តងទៀត","gui.connection.unavailable.helpbutton":"ជំនួយ","gui.controls.go":"ទៅ","gui.controls.stop":"ឈប់","gui.crashMessage.label":"អុញនុះ! មានអីខុសហើយ!","gui.crashMessage.errorNumber":"បញ្ហានេះត្រូវបានកត់ត្រាទុកដោយលេខសម្គាល់ {errorId}","gui.crashMessage.reload":"ដំណើរការជាថ្មី","gui.customProcedures.myblockModalTitle":"បង្កើតប្លុកមួយ","gui.customProcedures.addAnInputNumberText":"បញ្ចូលតម្លៃ","gui.customProcedures.numberTextType":"លេខ ឬអត្ថបទ","gui.customProcedures.addAnInputBoolean":"បញ្ចូលតម្លៃ","gui.customProcedures.booleanType":"ប៊ូលីន","gui.customProcedures.addALabel":"បន្ថែមស្លាក","gui.customProcedures.runWithoutScreenRefresh":"ដំណើរការដោយមិនបាច់លោតទំព័រជាថ្មី","gui.customProcedures.cancel":"បោះបង់","gui.customProcedures.ok":"យល់ព្រម","gui.SpriteInfo.direction":"ទិសដៅ","gui.directionPicker.rotationStyles.allAround":"ពេញមួយជុំ","gui.directionPicker.rotationStyles.leftRight":"ឆ្វេង/ស្តាំ","gui.directionPicker.rotationStyles.dontRotate":"កុំបង្វិល","gui.gui.addExtension":"បន្ថែមកម្មវិធីបន្ថែម","gui.gui.codeTab":"កូដ","gui.gui.backdropsTab":"ផ្ទាំងខាងក្រោយ","gui.gui.costumesTab":"រូបរាង","gui.gui.soundsTab":"សម្លេង","gui.extensionLibrary.comingSoon":"ជិតមកដល់ហើយ","gui.extensionLibrary.requires":"ទាមទារ","gui.extensionLibrary.collaboration":"ការសហការជាមួយ","gui.library.filterPlaceholder":"ស្វែងរក","gui.library.allTag":"ទាំងអស់","gui.loader.headline":"កំពុងដំណើរការកិច្ចការ","gui.loader.creating":"កំពុងបង្កើតកិច្ចការ","gui.authorInfo.byUser":"ដោយ​ {username}","gui.menuBar.seeProjectPage":"មើលទំព័រកិច្ចការ","gui.menuBar.LanguageSelector":"បញ្ជីភាសា","gui.menuBar.tutorialsLibrary":"ការបង្រៀន","gui.menuBar.restoreSprite":"ទាញយកតួអង្គមកវិញ","gui.menuBar.restoreSound":"ទាញយកសម្លេងមកវិញ","gui.menuBar.restoreCostume":"ទាញយករូបរាងមកវិញ","gui.menuBar.restore":"ស្តារមកវិញ","gui.menuBar.saveNow":"រក្សាទុកឥឡូវ","gui.menuBar.saveAsCopy":"រក្សាទុកជាច្បាប់ថ្មី","gui.menuBar.remix":"កែបន្ថែម","gui.menuBar.new":"ថ្មី","gui.menuBar.file":"ឯកសារ","gui.menuBar.downloadToComputer":"រក្សាទុកក្នុងកុំព្យូទ័រ","gui.menuBar.edit":"កែសម្រួល","gui.menuBar.turboModeOff":"បិទម៉ូត Turbo","gui.menuBar.turboModeOn":"បើកម៉ូត Turbo","gui.gui.projectTitlePlaceholder":"ដាក់ចំណងជើងកិច្ចការទីនេះ","gui.menuBar.isShared":"កិច្ចការបានចែករំលែក","gui.menuBar.share":"ចែករំលែក","gui.modal.help":"ជំនួយ","gui.modal.back":"ក្រោយ","gui.monitor.listMonitor.empty":"(ទទេ)","gui.monitor.listMonitor.listLength":"ប្រវែង{length}","gui.monitor.contextMenu.default":"អេក្រង់ធម្មតា","gui.monitor.contextMenu.large":"អេក្រង់ធំ","gui.monitor.contextMenu.slider":"រំកិល","gui.monitor.contextMenu.sliderRange":"ប្តូរដែនរំកិល","gui.monitor.contextMenu.import":"នាំចូល","gui.monitor.contextMenu.export":"នាំចេញ","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"លេង","gui.playButton.stop":"ឈប់","gui.gui.variableScopeOptionAllSprites":"សម្រាប់តួអង្គទាំងអស់","gui.gui.variableScopeOptionSpriteOnly":"សម្រាប់តែតួអង្គនេះប៉ុណ្ណោះ","gui.gui.cloudVariableOption":"អថេរលើបណ្តាញ (ផ្ទុកក្នុងម៉ាស៊ីនបម្រើ)","gui.gui.variablePromptAllSpritesMessage":"អថេរនេះនឹងអាចប្រើបានជាមួយនឹងតួអង្គទាំងអស់","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"បោះបង់","gui.prompt.ok":"យល់ព្រម","gui.playbackStep.stopMsg":"ឈប់","gui.playbackStep.playMsg":"លេង","gui.playbackStep.loadingMsg":"កំពុងដំណើរការ...","gui.playbackStep.saveMsg":"រក្សាទុក","gui.playbackStep.reRecordMsg":"ថតម្តងទៀត","gui.recordModal.title":"ថតសម្លេង","gui.recordingStep.beginRecord":"ចាប់ផ្តើមថតដោយចុចប៊ូតុងខាងក្រោម","gui.recordingStep.permission":"{arrow}យើងត្រូវការការអនុញ្ញាតពីអ្នកដើម្បីអាចប្រើម៉ៃក្រូហ្វូនបាន","gui.recordingStep.stop":"ឈប់ថត","gui.recordingStep.record":"ថត","gui.sliderModal.min":"តម្លៃអប្បបរមា","gui.sliderModal.max":"តម្លៃអតិបរមា","gui.sliderModal.title":"ប្តូរដែនរំកិល","gui.sliderPrompt.cancel":"បោះបង់","gui.sliderPrompt.ok":"យល់ព្រម","gui.soundEditor.sound":"សម្លេង","gui.soundEditor.play":"លេង","gui.soundEditor.stop":"ឈប់","gui.soundEditor.copy":"ចម្លង","gui.soundEditor.paste":"ភ្ជាប់","gui.soundEditor.copyToNew":"ចម្លងជាថ្មី","gui.soundEditor.delete":"លុប","gui.soundEditor.save":"រក្សាទុក","gui.soundEditor.undo":"មិនធ្វើវិញ","gui.soundEditor.redo":"ធ្វើឡើងវិញ","gui.soundEditor.faster":"លឿនជាងមុន","gui.soundEditor.slower":"យឺតជាងមុន","gui.soundEditor.echo":"សម្លេងឡង","gui.soundEditor.robot":"រ៉ូបូ","gui.soundEditor.louder":"លឺជាងមុន","gui.soundEditor.softer":"ខ្សោយជាងមុន","gui.soundEditor.reverse":"បញ្ច្រាស់","gui.soundEditor.fadeOut":"ថយម្តងបន្តិច","gui.soundEditor.fadeIn":"កើនម្តងបន្តិច","gui.soundEditor.mute":"បិទសម្លេង","gui.SpriteInfo.spritePlaceholder":"ឈ្មោះ","gui.SpriteInfo.sprite":"តួអង្គ","gui.SpriteInfo.show":"បង្ហាញ","gui.SpriteInfo.size":"ទំហំ","gui.spriteSelectorItem.contextMenuDuplicate":"ចម្លង","gui.spriteSelectorItem.contextMenuExport":"នាំចេញ","gui.spriteSelectorItem.contextMenuDelete":"លុប","gui.spriteSelector.addSpriteFromLibrary":"ជ្រើសតួអង្គ","gui.spriteSelector.addSpriteFromPaint":"កម្មវិធីគូរ","gui.spriteSelector.addSpriteFromSurprise":"ចៃដន្យ","gui.spriteSelector.addSpriteFromFile":"ផ្ទុកពីកុំព្យូទ័រ","gui.stageHeader.stageSizeLarge":"ប្តូរទៅឆាកធំ","gui.stageHeader.stageSizeSmall":"ប្តូរទៅឆាកតូច","gui.stageHeader.stageSizeFull":"ចូលទៅកាន់ម៉ូតអេក្រង់ពេញ","gui.stageHeader.stageSizeUnFull":"ចេញពីម៉ូតអេក្រង់ពេញ","gui.stageHeader.fullscreenControl":"ប៊ូតុងចេញចូលម៉ូតអេក្រង់ពេញ","gui.spriteSelector.addBackdropFromLibrary":"ជ្រើសផ្ទាំងខាងក្រោយ","gui.stageSelector.addBackdropFromPaint":"កម្មវិធីគូរ","gui.stageSelector.addBackdropFromSurprise":"ចៃដន្យ","gui.stageSelector.addBackdropFromFile":"ផ្ទុកពីកុំព្យូទ័រ","gui.stageSelector.stage":"ឆាក","gui.stageSelector.backdrops":"ផ្ទាំងខាងក្រោយ","gui.telemetryOptIn.label":"រាយការណ៍ពីស្ថិតិដើម្បីធ្វើឲ្យ Scratch កាន់តែប្រសើរ","gui.telemetryOptIn.body1":"ក្រុម Scratch តែងតែស្វែងយល់ឲ្យកាន់តែច្បាស់អំពីរបៀបដែល Scratch ត្រូវបានប្រើប្រាស់នៅជុំវិញពិភពលោក។ ដើម្បីជួយដល់កិច្ចខិតខំប្រឹងប្រែងនេះ អ្នកអាចអនុញ្ញាតឱ្យកម្មវិធី Scratch ផ្ញើព័ត៌មានប្រើប្រាស់ទៅក្រុម Scratch ដោយស្វ័យប្រវត្តិ។","gui.telemetryOptIn.body2":"ព័ត៌មានដែលយើងប្រមូលរួមមានការជ្រើសរើសភាសា ការប្រើប្រាស់ប្លុក និងព្រឹត្តិការណ៍មួយចំនួនដូចជាការរក្សាទុក ការបើកកិច្ចការ និងការផ្ទុកកិច្ចការឡើង។ យើងមិនប្រមូលព័ត៌មានផ្ទាល់ខ្លួនទេ។ សូមមើល {privacyPolicyLink} របស់យើង សម្រាប់ព័ត៌មានបន្ថែម។","gui.telemetryOptIn.privacyPolicyLink":"គោលការណ៍ឯកជនភាព","gui.telemetryOptIn.optInText":"ចែករំលែកទិន្នន័យពីការប្រើប្រាស់របស់ខ្ញុំជាមួយនឹង Scratch Team","gui.telemetryOptIn.optInTooltip":"បើកការប្រមូលទិន្នន័យ","gui.telemetryOptIn.optOutText":"កុំចែករំលែកទិន្នន័យពីការប្រើប្រាស់របស់ខ្ញុំជាមួយនឹង Scratch Team","gui.telemetryOptIn.optOutTooltip":"បិទការប្រមូលទិន្នន័យ","gui.telemetryOptIn.settingWasUpdated":"ការកំណត់របស់អ្នកត្រូវបានកែប្រែ និងរក្សាទុក។","gui.telemetryOptIn.buttonClose":"បិទ","gui.turboMode.active":"ម៉ូត Turbo","gui.webglModal.label":"កម្មវិធីរុករកមិនអាចប្រើ WebGL បានទេ","gui.webglModal.webgllink":"មិនអាចប្រើ WebGL ទេ","gui.costumeLibrary.chooseABackdrop":"ជ្រើសផ្ទាំងខាងក្រោយ","gui.costumeLibrary.chooseACostume":"ជ្រើសរើសរូបរាង","gui.costumeTab.addBackdropFromLibrary":"ជ្រើសផ្ទាំងខាងក្រោយ","gui.costumeTab.addCostumeFromLibrary":"ជ្រើសរើសរូបរាង","gui.costumeTab.addBlankCostume":"កម្មវិធីគូរ","gui.costumeTab.addSurpriseCostume":"ចៃដន្យ","gui.costumeTab.addFileBackdrop":"ផ្ទុកពីកុំព្យូទ័រ","gui.costumeTab.addFileCostume":"ផ្ទុកពីកុំព្យូទ័រ","gui.extensionLibrary.chooseAnExtension":"ជ្រើសរើសកម្មវិធីបន្ថែម","gui.extensionLibrary.extensionUrl":"បញ្ចូលតំណ URL នៃកម្មវិធីបន្ថែម","gui.monitors.importListColumnPrompt":"តើគួរប្រើជួរមួយណា (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"មិនអាចចាប់ផ្តើមថតទេ","gui.soundLibrary.chooseASound":"ជ្រើសរើសសម្លេង","gui.soundTab.fileUploadSound":"ផ្ទុកពីកុំព្យូទ័រ","gui.soundTab.surpriseSound":"ចៃដន្យ","gui.soundTab.recordSound":"ថត","gui.soundTab.addSoundFromLibrary":"ជ្រើសរើសសម្លេង","gui.spriteLibrary.chooseASprite":"ជ្រើសតួអង្គ","gui.tipsLibrary.tutorials":"ជ្រើសរើសការបង្ហាញ","gui.alerts.createsuccess":"បានបង្កើតកិច្ចការថ្មីមួយ","gui.alerts.createcopysuccess":"កិច្ចការត្រូវបានរក្សាទុកជាកិច្ចការថ្មី","gui.alerts.createremixsuccess":"បានចម្លងកិច្ចការសម្រាប់កែបន្ថែម","gui.alerts.creating":"កំពុងបង្កើតថ្មី...","gui.alerts.creatingCopy":"កំពុងចម្លងកិច្ចការ...","gui.alerts.creatingRemix":"កំពុងចម្លងកិច្ចការសម្រាប់កែបន្ថែម...","gui.alerts.creatingError":"មិនអាចបង្កើតកិច្ចការទេ! សូមសាកម្តងទៀត!","gui.alerts.savingError":"រក្សាទុកកិច្ចការមិនបានទេ","gui.alerts.savesuccess":"បានរក្សាទុកកិច្ចការ","gui.alerts.saving":"កំពុងរក្សាកិច្ចការទុក...","gui.alerts.cloudInfo":"សូមចាំថាអថេរលើបណ្តាញអាចតែជាលេខប៉ុណ្ណោះ មិនអាចជាអក្សរ ឬសញ្ញាទេ។ {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"ស្វែងយល់បន្ថែម","gui.alerts.importing":"កំពុងនាំចូល...","gui.defaultProject.variable":"អថេរខ្ញុំ","gui.extension.music.name":"តន្រ្តី","gui.extension.music.description":"លេងឧបករណ៍តន្រ្តី និងស្គរ","gui.extension.pen.name":"ប៊ិច","gui.extension.pen.description":"គូរដោយប្រើតួអង្គរបស់អ្នក","gui.extension.videosensing.name":"ញ្ញាណតាមវីដេអូ","gui.extension.videosensing.description":"ចាប់ចលនាដោយប្រើកាមេរ៉ា","gui.extension.text2speech.name":"អត្ថបទទៅសម្លេង","gui.extension.text2speech.description":"ធ្វើឲ្យតួអង្គក្នុងកិច្ចការរបស់អ្នកនិយាយ","gui.extension.translate.name":"បកប្រែ","gui.extension.translate.description":"បកប្រែអត្ថបទទៅភាសាជាច្រើន","gui.extension.makeymakey.description":"យកអ្វីធ្វើជាច្នុចក៏បាន","gui.extension.microbit.description":"ភ្ជាប់កិច្ចការរបស់អ្នកជាមួយនឹងពិភពលោក។","gui.extension.microbit.connectingMessage":"កំពុងភ្ជាប់","gui.extension.ev3.description":"បង្កើតរ៉ូបូតមានចលនា និង របស់ជាច្រើនទៀត។","gui.extension.ev3.connectingMessage":"កំពុងភ្ជាប់! សូមឲ្យប្រាកដថាលេខសម្គាល់នៅលើឧបករណ៍ EV3 របស់អ្នកត្រូវបានដាក់ទៅជា 1234 ។","gui.extension.boost.description":"បង្កើតឧបករណ៍រ៉ូបូត","gui.extension.boost.connectingMessage":"កំពុងភ្ជាប់","gui.extension.wedo2.description":"បង្កើតដោយប្រើម៉ូទ័រ និងឧបករណ៍ចាប់សញ្ញា","gui.extension.wedo2.connectingMessage":"កំពុងភ្ជាប់...","gui.extension.gdxfor.description":"ដឹងពីការរុញ ការទាញ ចលនា និង រង្វិល។","gui.extension.gdxfor.connectingMessage":"កំពុងភ្ជាប់...","gui.libraryTags.all":"ទាំងអស់","gui.libraryTags.animals":"សត្វ","gui.libraryTags.dance":"រាំ","gui.libraryTags.effects":"បែបផែន","gui.libraryTags.fantasy":"ស្រមើស្រមៃ","gui.libraryTags.fashion":"ម៉ូត","gui.libraryTags.food":"អាហារ","gui.libraryTags.indoors":"ខាងក្នុង","gui.libraryTags.loops":"រង្វិលជុំ","gui.libraryTags.music":"តន្រ្តី","gui.libraryTags.notes":"ណូត","gui.libraryTags.outdoors":"ខាងក្រៅ","gui.libraryTags.patterns":"ក្រឡា","gui.libraryTags.people":"មនុស្ស","gui.libraryTags.percussion":"សម្លេងវាយ","gui.libraryTags.space":"លំហ","gui.libraryTags.sports":"កីឡា","gui.libraryTags.underwater":"ក្នុងទឹក","gui.libraryTags.voice":"សម្លេង","gui.libraryTags.wacky":"សម្លេងចម្លែកៗ","gui.libraryTags.animation":"រូបជីវចល","gui.libraryTags.art":"សិល្បៈ","gui.libraryTags.games":"ហ្គេម","gui.libraryTags.stories":"រឿង","gui.libraryTags.letters":"តួអក្សរ","gui.opcodeLabels.direction":"ទិសដៅ","gui.opcodeLabels.xposition":"ទីតាំង x","gui.opcodeLabels.yposition":"ទីតាំង y","gui.opcodeLabels.size":"ទំហំ","gui.opcodeLabels.costumename":"ឈ្មោះរូបរាង","gui.opcodeLabels.costumenumber":"លេខរូបរាង","gui.opcodeLabels.backdropname":"ឈ្មោះផ្ទាំងខាងក្រោយ","gui.opcodeLabels.backdropnumber":"លេខផ្ទាំងខាងក្រោយ","gui.opcodeLabels.volume":"កម្រិតសម្លេង","gui.opcodeLabels.tempo":"ចង្វាក់","gui.opcodeLabels.answer":"ចម្លើយ","gui.opcodeLabels.loudness":"កម្រិតឮ","gui.opcodeLabels.username":"ឈ្មោះគណនី","gui.opcodeLabels.year":"ឆ្នាំ","gui.opcodeLabels.month":"ខែ","gui.opcodeLabels.date":"ថ្ងៃខែ","gui.opcodeLabels.dayofweek":"ថ្ងៃប្រចាំសប្តាហ៍","gui.opcodeLabels.hour":"ម៉ោង","gui.opcodeLabels.minute":"នាទី","gui.opcodeLabels.second":"វិនាទី","gui.opcodeLabels.timer":"ម៉ោងរាប់ថយក្រោយ","gui.sharedMessages.backdrop":"ផ្ទាំងខាងក្រោយ {index}","gui.sharedMessages.costume":"រូបរាង {index}","gui.sharedMessages.sprite":"តួអង្គ {index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"ជំនួសខ្លឹមសារនៃកិច្ចការបច្ចុប្បន្នមែនទេ?","gui.sharedMessages.loadFromComputerTitle":"ដំណើរការពីកុំព្យូទ័ររបស់អ្នក","boost.color.any":"ពណ៌ណាមួយ","boost.color.black":"ខ្មៅ","boost.color.blue":"ខៀវ","boost.color.green":"បៃតង","boost.color.red":"ក្រហម","boost.color.white":"ស","boost.color.yellow":"លឿង","boost.getMotorPosition":"ទីតាំងម៉ូទ័រ [MOTOR_REPORTER_ID]","boost.getTiltAngle":"លម្អៀងមុំ [TILT_DIRECTION]","boost.motorDirection.backward":"ទៅក្រោយ","boost.motorDirection.forward":"ទៅមុខ","boost.motorDirection.reverse":"បញ្ច្រាស់","boost.motorOff":"បិទម៉ូទ័រ [MOTOR_ID]","boost.motorOn":"បើកម៉ូទ័រ [MOTOR_ID]","boost.motorOnFor":"បង្វិលម៉ូទ័រ [MOTOR_ID] រយៈពេល [DURATION] វិនាទី","boost.motorOnForRotation":"បង្វិលម៉ូទ័រ [MOTOR_ID] ចំនួន [ROTATION] ជុំ","boost.seeingColor":"ឃើញដុំពណ៌ [COLOR]?","boost.setLightHue":"ដាក់ពណ៌របស់ភ្លើងទៅជា [HUE]","boost.setMotorDirection":"ដាក់ទិសដៅរបស់ [MOTOR_ID] ទៅជា [MOTOR_DIRECTION]","boost.setMotorPower":"ដាក់ល្បឿនម៉ូទ័រ [MOTOR_ID] ត្រឹម [POWER] %","boost.tiltDirection.any":"ខ្លះ","boost.tiltDirection.down":"ចុះក្រោម","boost.tiltDirection.left":"ឆ្វេង","boost.tiltDirection.right":"ស្ដាំ","boost.tiltDirection.up":"លើ","boost.whenColor":"ពេលឃើញពណ៌ [COLOR]","boost.whenTilted":"ពេលលំអៀង [TILT_DIRECTION_ANY]","ev3.beepNote":"លេងណូត [NOTE] រយៈពេល​ [TIME] វិនាទី","ev3.buttonPressed":"ប៊ូតុងលើ [PORT] ត្រូវបានចុច?","ev3.getBrightness":"កម្រិតពន្លឺ","ev3.getDistance":"កម្រិតចម្ងាយ","ev3.getMotorPosition":"ទីតាំងម៉ូទ័រ [PORT] ","ev3.motorSetPower":"ដាក់ថាមពលម៉ូទ័រ [PORT] ត្រឹម [POWER] %","ev3.motorTurnClockwise":"ម៉ូទ័រ [PORT] បែរតាមទ្រនិចនាឡិការយៈពេល [TIME] វិនាទី","ev3.motorTurnCounterClockwise":"ម៉ូទ័រ [PORT] បែរបញ្ច្រាសទ្រនិចនាឡិការយៈពេល [TIME] វិនាទី","ev3.whenBrightnessLessThan":"ពេលកម្រិតពន្លឺ < [DISTANCE]","ev3.whenButtonPressed":"ពេលប៊ូតុង [PORT] បានចុច","ev3.whenDistanceLessThan":"ពេលចម្ងាយ < [DISTANCE]","gdxfor.getAcceleration":"សំទុះ [DIRECTION]","gdxfor.getForce":"កម្លាំង","gdxfor.getSpin":"ល្បឿនបង្វិល [DIRECTION]","gdxfor.getTilt":"លម្អៀងមុំ [TILT]","gdxfor.isFreeFalling":"ធ្លាក់សេរី?","gdxfor.isTilted":"លំអៀង [TILT]?","gdxfor.pulled":"ត្រូវបានទាញ","gdxfor.pushed":"ត្រូវបានរុញ","gdxfor.shaken":"ញាក់","gdxfor.startedFalling":"បានចាប់ផ្តើមធ្លាក់","gdxfor.tiltDirectionMenu.any":"ណាមួយ","gdxfor.tiltDirectionMenu.back":"ក្រោយ","gdxfor.tiltDirectionMenu.front":"មុខ","gdxfor.tiltDirectionMenu.left":"ឆ្វេង","gdxfor.tiltDirectionMenu.right":"ស្តាំ","gdxfor.turnedFaceDown":"បែរមុខចុះ","gdxfor.turnedFaceUp":"បែរមុខឡើង","gdxfor.whenForcePushedOrPulled":"ពេលសិនស័រកម្លាំង [PUSH_PULL]","gdxfor.whenGesture":"ពេល [GESTURE]","gdxfor.whenTilted":"ពេលលំអៀង [TILT]","makeymakey.downArrow":"ព្រួញខាងក្រោម","makeymakey.downArrowShort":"ចុះក្រោម","makeymakey.leftArrow":"ព្រួញខាង​ឆ្វេង","makeymakey.leftArrowShort":"ឆ្វេង","makeymakey.rightArrow":"ព្រួញ​ខាងស្ដាំ","makeymakey.rightArrowShort":"ស្តាំ","makeymakey.spaceKey":"ច្នុចដក​ឃ្លា","makeymakey.upArrow":"ព្រួញ​ខាង​លើ","makeymakey.upArrowShort":"លើ","makeymakey.whenKeyPressed":"ពេលចុច [KEY]","makeymakey.whenKeysPressedInOrder":"ពេលចុច [SEQUENCE] តាមលំដាប់","microbit.buttonsMenu.any":"ណាមួយ","microbit.clearDisplay":"សម្អាតអេក្រង់","microbit.defaultTextToDisplay":"Hello!","microbit.displaySymbol":"បង្ហាញ [MATRIX]","microbit.displayText":"បង្ហាញអត្ថបទ [TEXT]","microbit.gesturesMenu.jumped":"បានលោត","microbit.gesturesMenu.moved":"បានផ្លាស់ទី","microbit.gesturesMenu.shaken":"ញាក់","microbit.isButtonPressed":"ប៊ូតុង [BTN] ​ត្រូវ​បាន​ចុច?","microbit.isTilted":"លំអៀង [DIRECTION]?","microbit.pinStateMenu.off":"បិទ","microbit.pinStateMenu.on":"បើក","microbit.tiltAngle":"លម្អៀងមុំ [DIRECTION]","microbit.tiltDirectionMenu.any":"ណាមួយ","microbit.tiltDirectionMenu.back":"ត្រឡប់","microbit.tiltDirectionMenu.front":"មុខ","microbit.tiltDirectionMenu.left":"ឆ្វេង","microbit.tiltDirectionMenu.right":"ស្តាំ","microbit.whenButtonPressed":"ពេលប៊ូតុង [BTN] ​ត្រូវ​បាន​ចុច","microbit.whenGesture":"ពេល [GESTURE]","microbit.whenPinConnected":"ពេលម្ជុលតំណរ [PIN] ត្រូវបានភ្ជាប់","microbit.whenTilted":"ពេលលំអៀង [DIRECTION]","music.categoryName":"តន្រ្តី","music.changeTempo":"ប្តូរចង្វាក់ចំនួន [TEMPO]","music.drumBass":"(2) Bass Drum","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) Closed Hi-Hat","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Cowbell","music.drumCrashCymbal":"(4) Crash Cymbal","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) ទះដៃ","music.drumOpenHiHat":"(5) Open Hi-Hat","music.drumSideStick":"(3) Side Stick","music.drumSnare":"(1) Snare Drum","music.drumTambourine":"(7) Tambourine","music.drumTriangle":"(12) Triangle","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Wood Block","music.getTempo":"ចង្វាក់","music.instrumentBass":"(6) Bass","music.instrumentBassoon":"(14) Bassoon","music.instrumentCello":"(8) Cello","music.instrumentChoir":"(15) Choir","music.instrumentClarinet":"(10) Clarinet","music.instrumentElectricGuitar":"(5) Electric Guitar","music.instrumentElectricPiano":"(2) Electric Piano","music.instrumentFlute":"(12) Flute","music.instrumentGuitar":"(4) Guitar","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Music Box","music.instrumentOrgan":"(3) Organ","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxophone","music.instrumentSteelDrum":"(18) Steel Drum","music.instrumentSynthLead":"(20) Synth Lead","music.instrumentSynthPad":"(21) Synth Pad","music.instrumentTrombone":"(9) Trombone","music.instrumentVibraphone":"(16) Vibraphone","music.instrumentWoodenFlute":"(13) Wooden Flute","music.midiPlayDrumForBeats":"លេងសូរ [DRUM] ចំនួន [BEATS] ប៊ីត","music.midiSetInstrument":"ដាក់ឧបករណ៍ទៅជា [INSTRUMENT]","music.playDrumForBeats":"លេងសូរ [DRUM] ចំនួន [BEATS] ប៊ីត","music.playNoteForBeats":"លេងណូត [NOTE] ចំនួន [BEATS] ប៊ីត","music.restForBeats":"ផ្អាកចំនួន [BEATS] ប៊ីត","music.setInstrument":"ដាក់ឧបករណ៍ទៅជា [INSTRUMENT]","music.setTempo":"ដាក់ចង្វាក់ត្រឹម [TEMPO]","pen.categoryName":"ប៊ិច","pen.changeColorParam":"ប្តូរ [COLOR_PARAM] របស់ប៊ិចចំនួន [VALUE]","pen.changeHue":"ប្ដូរពណ៌ប៊ិចចំនួន [HUE]","pen.changeShade":"ប្តូរកម្រិតដិតរបស់ប៊ិចចំនួន [SHADE]","pen.changeSize":"ប្តូរទំហំប៊ិចចំនួន [SIZE]","pen.clear":"លុបទាំងអស់","pen.colorMenu.brightness":"កម្រិតពន្លឺ","pen.colorMenu.color":"ពណ៌","pen.colorMenu.saturation":"កម្រិត​ដិត","pen.colorMenu.transparency":"កម្រិតឆ្លុះ","pen.penDown":"ចាប់គូស","pen.penUp":"ឈប់គូស","pen.setColor":"ដាក់ពណ៌ប៊ិចទៅជា [COLOR]","pen.setColorParam":"ដាក់ [COLOR_PARAM] របស់ប៊ិចត្រឹម [VALUE]","pen.setHue":"ដាក់ពណ៌ប៊ិចទៅជា [HUE]","pen.setShade":"ដាក់កម្រិតដឹតរបស់ប៊ិចត្រឹម [SHADE]","pen.setSize":"ដាក់ទំហំប៊ិចត្រឹម [SIZE]","pen.stamp":"ដាក់ផ្តិតរូប","text2speech.alto":"alto","text2speech.categoryName":"អត្ថបទទៅសម្លេង","text2speech.defaultTextToSpeak":"សួស្តី","text2speech.giant":"យក្ស","text2speech.kitten":"កូនឆ្មា","text2speech.setLanguageBlock":"ដាក់ភាសាទៅជា [LANGUAGE]","text2speech.setVoiceBlock":"ដាក់សម្លេងទៅជា [VOICE]","text2speech.speakAndWaitBlock":"និយាយ [WORDS]","text2speech.squeak":"ស្រែកញ៉េក","text2speech.tenor":"tenor","translate.categoryName":"បកប្រែ","translate.defaultTextToTranslate":"សួស្តី","translate.translateBlock":"បកប្រែ [WORDS] ទៅជាភាសា [LANGUAGE]","translate.viewerLanguage":"ភាសា","videoSensing.categoryName":"ញ្ញាណតាមវីដេអូ","videoSensing.direction":"ទិសដៅ","videoSensing.motion":"ចលនា","videoSensing.off":"បិទ","videoSensing.on":"បើក","videoSensing.onFlipped":"ត្រឡប់","videoSensing.setVideoTransparency":"ដាក់កម្រិតឆ្លុះរបស់វីដេអូត្រឹម [TRANSPARENCY]","videoSensing.sprite":"តួអង្គ","videoSensing.stage":"ឆាក","videoSensing.videoOn":"[ATTRIBUTE] របស់វីដេអូទៅលើ [SUBJECT]","videoSensing.videoToggle":"[VIDEO_STATE] វីដេអូ","videoSensing.whenMotionGreaterThan":"ពេលកម្រិតចលនាក្នុងវីដេអូ > [REFERENCE]","wedo2.getDistance":"ចម្ងាយ","wedo2.getTiltAngle":"លម្អៀងមុំ [TILT_DIRECTION]","wedo2.isTilted":"លំអៀង [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"ទៅក្រោយ","wedo2.motorDirection.forward":"ទៅមុខ","wedo2.motorDirection.reverse":"បញ្ច្រាស់","wedo2.motorId.a":"ម៉ូទ័រ A","wedo2.motorId.all":"ម៉ូទ័រទាំងអស់","wedo2.motorId.b":"ម៉ូទ័រ B","wedo2.motorId.default":"ម៉ូទ័រ","wedo2.motorOff":"បិទម៉ូទ័រ [MOTOR_ID]","wedo2.motorOn":"បើកម៉ូទ័រ [MOTOR_ID]","wedo2.motorOnFor":"បើកម៉ូទ័រ [MOTOR_ID] រយៈពេល [DURATION] វិនាទី","wedo2.playNoteFor":"លេងណូត [NOTE] រយៈពេល​ [DURATION] វិនាទី","wedo2.setLightHue":"ដាក់ពណ៌ភ្លើងទៅជា [HUE]","wedo2.setMotorDirection":"ដាក់ទិសដៅរបស់ [MOTOR_ID] ទៅជា [MOTOR_DIRECTION]","wedo2.startMotorPower":"ដាក់ថាមពលម៉ូទ័រ [MOTOR_ID] ត្រឹម [POWER] %","wedo2.tiltDirection.any":"ណាមួយ","wedo2.tiltDirection.down":"ចុះក្រោម","wedo2.tiltDirection.left":"ឆ្វេង","wedo2.tiltDirection.right":"ស្តាំ","wedo2.tiltDirection.up":"លើ","wedo2.whenDistance":"ពេលចម្ងាយ [OP] [REFERENCE]","wedo2.whenTilted":"ពេលលំអៀង [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"ពណ៌","paint.paintEditor.saturation":"កម្រិតដិត","paint.paintEditor.brightness":"កម្រិតពន្លឺ","paint.paintEditor.costume":"រូបរាង","paint.paintEditor.group":"ដាក់ក្រុម","paint.paintEditor.ungroup":"បំបែកក្រុម","paint.paintEditor.undo":"មិនធ្វើវិញ","paint.paintEditor.redo":"ធ្វើឡើងវិញ","paint.paintEditor.forward":"ទៅមុខ","paint.paintEditor.backward":"ថយក្រោយ","paint.paintEditor.front":"មុខគេ","paint.paintEditor.back":"ក្រោយគេ","paint.paintEditor.more":"ច្រើនទៀត","paint.modeTools.brushSize":"ទំហំ","paint.modeTools.eraserSize":"ទំហំជ័រលុប","paint.modeTools.copy":"ចម្លង","paint.modeTools.paste":"ភ្ជាប់","paint.modeTools.delete":"លុប","paint.modeTools.curved":"កោង","paint.modeTools.pointed":"ស្រួច","paint.modeTools.thickness":"កម្រាស់","paint.modeTools.flipHorizontal":"ត្រឡប់ផ្ដេក","paint.modeTools.flipVertical":"ត្រឡប់ឈរ","paint.modeTools.filled":"មានផ្ទៃ","paint.modeTools.outlined":"មានគ្រោង","paint.paintEditor.bitmap":"បម្លែងជា Bitmap","paint.paintEditor.vector":"បម្លែងជា Vector","paint.paintEditor.fill":"ផ្ទៃ","paint.paintEditor.stroke":"បន្ទាត់គែម","paint.brushMode.brush":"ជក់","paint.eraserMode.eraser":"ជ័រលុប","paint.fillMode.fill":"ផ្ទៃ","paint.lineMode.line":"បន្ទាត់","paint.ovalMode.oval":"រង្វង់","paint.rectMode.rect":"ចតុកោណកែង","paint.reshapeMode.reshape":"កែរូបរាង","paint.roundedRectMode.roundedRect":"ចតុកោណកែងជ្រុងមូល","paint.selectMode.select":"ជ្រើសរើស","paint.textMode.text":"អត្ថបទ","paint.colorPicker.swap":"ប្តូរពណ៌"},"pl":{"gui.alerts.tryAgain":"Spróbuj ponownie","gui.alerts.download":"Pobierz","gui.connection.reconnect":"Połącz ponownie","gui.backpack.costumeLabel":"kostium","gui.backpack.soundLabel":"dźwięk","gui.backpack.scriptLabel":"skrypt","gui.backpack.spriteLabel":"duszek","gui.backpack.header":"Plecak","gui.backpack.errorBackpack":"Błąd wczytywania plecaka","gui.backpack.loadingBackpack":"Ładowanie...","gui.backpack.more":"Więcej","gui.backpack.emptyBackpack":"Plecak jest pusty","gui.unsupportedBrowser.label":"Przeglądarka nie jest wspierana","gui.cards.all-tutorials":"Samouczki","gui.cards.shrink":"Zmniejsz","gui.cards.expand":"Rozwiń","gui.cards.close":"Zamknij","gui.cards.more-things-to-try":"Więcej rzeczy do spróbowania!","gui.cards.see-more":"Zobacz więcej","gui.comingSoon.message1":"Nie martw się, pracujemy nad tym {emoji}","gui.comingSoon.message2":"Już wkrótce...","gui.comingSoon.message3":"Pracujemy nad tym {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Nie znaleziono urządzeń","gui.connection.auto-scanning.prescan":"Umieść swoje urządzenie w pobliżu, a następnie rozpocznij szukać.","gui.connection.auto-scanning.pressbutton":"Naciśnij przycisk na swoim urządzeniu","gui.connection.auto-scanning.start-search":"Zacznij szukać","gui.connection.connecting-searchbutton":"Szukanie...","gui.connection.auto-scanning.try-again":"Spróbuj ponownie","gui.connection.connected":"Połączone","gui.connection.disconnect":"Rozłącz","gui.connection.go-to-editor":"Przejdź do edytora","gui.connection.connecting-cancelbutton":"Trwa łączenie...","gui.connection.error.errorMessage":"Ups, wygląda na to, że coś poszło nie tak.","gui.connection.error.tryagainbutton":"Spróbuj ponownie","gui.connection.error.helpbutton":"Pomoc","gui.connection.peripheral-name-label":"Nazwa urządzenia","gui.connection.connect":"Połącz","gui.connection.scanning.lookingforperipherals":"Trwa szukanie urządzeń","gui.connection.scanning.noPeripheralsFound":"Nie znaleziono urządzeń","gui.connection.scanning.instructions":"Wybierz urządzenie z powyższej listy.","gui.connection.search":"Odśwież","gui.connection.unavailable.installscratchlink":"Upewnij się, że zainstalowałeś Scratch Link, oraz że aplikacja jest uruchomiona.","gui.connection.unavailable.enablebluetooth":"Upewnij się, że usługa Bluetooth jest włączona","gui.connection.unavailable.tryagainbutton":"Spróbuj ponownie","gui.connection.unavailable.helpbutton":"Pomoc","gui.controls.go":"Idź","gui.controls.stop":"Zatrzymaj","gui.crashMessage.label":"Ups! Coś poszło nie tak.","gui.crashMessage.errorNumber":"Twój błąd został zgłoszony pod numerem {errorId}","gui.crashMessage.reload":"Załaduj ponownie","gui.customProcedures.myblockModalTitle":"Utwórz blok","gui.customProcedures.addAnInputNumberText":"Dodaj dane wejściowe","gui.customProcedures.numberTextType":"liczba lub tekst","gui.customProcedures.addAnInputBoolean":"Dodaj dane wejściowe","gui.customProcedures.booleanType":"Boolean","gui.customProcedures.addALabel":"Dodaj etykietę","gui.customProcedures.runWithoutScreenRefresh":"Wykonaj bez odświeżania ekranu","gui.customProcedures.cancel":"Anuluj","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Kierunek","gui.directionPicker.rotationStyles.allAround":"Dookoła","gui.directionPicker.rotationStyles.leftRight":"lewo/prawo","gui.directionPicker.rotationStyles.dontRotate":"nie obracaj","gui.gui.addExtension":"Dodaj rozszerzenie","gui.gui.codeTab":"Skrypt","gui.gui.backdropsTab":"Tła","gui.gui.costumesTab":"Kostiumy","gui.gui.soundsTab":"Dźwięki","gui.extensionLibrary.comingSoon":"Już wkrótce","gui.extensionLibrary.requires":"Wymagania","gui.extensionLibrary.collaboration":"Współpraca z ","gui.library.filterPlaceholder":"Szukaj","gui.library.allTag":"Wszystko","gui.loader.headline":"Ładowanie projektu","gui.loader.creating":"Tworzenie projektu","gui.authorInfo.byUser":"przez {username}","gui.menuBar.seeProjectPage":"Przejdź do strony projektu","gui.menuBar.LanguageSelector":"Wybór języka","gui.menuBar.tutorialsLibrary":"Samouczki","gui.menuBar.restoreSprite":"Przywróć duszka","gui.menuBar.restoreSound":"Przywróć dźwięk","gui.menuBar.restoreCostume":"Przywróć kostium","gui.menuBar.restore":"Przywróć","gui.menuBar.saveNow":"Zapisz teraz","gui.menuBar.saveAsCopy":"Zapisz jako kopię","gui.menuBar.remix":"Remiks","gui.menuBar.new":"Nowy","gui.menuBar.file":"Plik","gui.menuBar.downloadToComputer":"Zapisz na swoim komputerze ","gui.menuBar.edit":"Edycja","gui.menuBar.turboModeOff":"Wyłącz tryb turbo","gui.menuBar.turboModeOn":"Włącz tryb turbo","gui.gui.projectTitlePlaceholder":"Tutaj wpisz tytuł projektu","gui.menuBar.isShared":"Udostępnione","gui.menuBar.share":"Udostępnij","gui.modal.help":"Pomoc","gui.modal.back":"Powrót","gui.monitor.listMonitor.empty":"(puste)","gui.monitor.listMonitor.listLength":"długość {length}","gui.monitor.contextMenu.default":"normalny widok","gui.monitor.contextMenu.large":"powiększony widok","gui.monitor.contextMenu.slider":"suwak","gui.monitor.contextMenu.sliderRange":"Zmień zakres suwaka","gui.monitor.contextMenu.import":"importuj","gui.monitor.contextMenu.export":"eksportuj","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Zagraj","gui.playButton.stop":"Zatrzymaj","gui.gui.variableScopeOptionAllSprites":"Dla wszystkich duszków","gui.gui.variableScopeOptionSpriteOnly":"Tylko dla tego duszka","gui.gui.cloudVariableOption":"Zmienna w chmurze (przechowywana na serwerze)","gui.gui.variablePromptAllSpritesMessage":"Ta zmienna będzie dostępna dla wszystkich duszków.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Anuluj","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Zatrzymaj","gui.playbackStep.playMsg":"Zagraj","gui.playbackStep.loadingMsg":"Ładowanie...","gui.playbackStep.saveMsg":"Zapisz","gui.playbackStep.reRecordMsg":"Nagraj ponownie","gui.recordModal.title":"Nagraj dźwięk","gui.recordingStep.beginRecord":"Rozpocznij nagrywanie, klikając przycisk poniżej","gui.recordingStep.permission":"{arrow}Potrzebujemy twojego pozwolenia na używanie mikrofonu","gui.recordingStep.stop":"Zatrzymaj nagrywanie","gui.recordingStep.record":"Nagraj","gui.sliderModal.min":"Najmniejsza wartość","gui.sliderModal.max":"Największa wartość","gui.sliderModal.title":"Zmień zakres suwaka","gui.sliderPrompt.cancel":"Anuluj","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Dźwięk","gui.soundEditor.play":"Zagraj","gui.soundEditor.stop":"Zatrzymaj","gui.soundEditor.copy":"Kopiuj","gui.soundEditor.paste":"Wklej","gui.soundEditor.copyToNew":"Skopiuj do Nowych","gui.soundEditor.delete":"Usuń","gui.soundEditor.save":"Zapisz","gui.soundEditor.undo":"Cofnij","gui.soundEditor.redo":"Ponów","gui.soundEditor.faster":"Szybciej","gui.soundEditor.slower":"Wolniej","gui.soundEditor.echo":"Echo","gui.soundEditor.robot":"Robotyczny głos","gui.soundEditor.louder":"Głośniej","gui.soundEditor.softer":"Zmiękczenie","gui.soundEditor.reverse":"Odwróć","gui.soundEditor.fadeOut":"Wycisz koniec","gui.soundEditor.fadeIn":"Wycisz początek","gui.soundEditor.mute":"Wycisz","gui.SpriteInfo.spritePlaceholder":"Imię","gui.SpriteInfo.sprite":"Duszek","gui.SpriteInfo.show":"Pokaż","gui.SpriteInfo.size":"Rozmiar","gui.spriteSelectorItem.contextMenuDuplicate":"duplikuj","gui.spriteSelectorItem.contextMenuExport":"eksportuj","gui.spriteSelectorItem.contextMenuDelete":"usuń","gui.spriteSelector.addSpriteFromLibrary":"Wybierz duszka","gui.spriteSelector.addSpriteFromPaint":"Maluj","gui.spriteSelector.addSpriteFromSurprise":"Niespodzianka","gui.spriteSelector.addSpriteFromFile":"Wczytaj duszka","gui.stageHeader.stageSizeLarge":"Przełącz na większą scenę","gui.stageHeader.stageSizeSmall":"Przełącz na małą scenę","gui.stageHeader.stageSizeFull":"Wejdź do trybu pełnego ekranu","gui.stageHeader.stageSizeUnFull":"Wyjdź z trybu pełnoekranowego","gui.stageHeader.fullscreenControl":"Kontrola pełnego ekranu","gui.spriteSelector.addBackdropFromLibrary":"Wybierz tło","gui.stageSelector.addBackdropFromPaint":"Maluj","gui.stageSelector.addBackdropFromSurprise":"Niespodzianka","gui.stageSelector.addBackdropFromFile":"Wczytaj tło","gui.stageSelector.stage":"Scena","gui.stageSelector.backdrops":"Tła","gui.telemetryOptIn.label":"Zgłoś statystyki, aby ulepszyć Scratch","gui.telemetryOptIn.body1":"Twórcy Scratcha ciągle starają się zrozumieć, w jaki sposób ludzie z całego świata używają Scratcha. Żeby im to ułatwić, możesz zgodzić się, żeby Scratch wysyłał do swoich twórców informacje o tym, jak jest używany.","gui.telemetryOptIn.body2":"Informacje, które zbieramy zawierają wybór języka, użytek bloków, i niektóre wydarzenia jak zapisywanie, wczytywanie, i udostępnianie projektu. NIE zbieramy żadnych danych osobistych. Proszę zapoznać się z naszym {privacyPolicyLink}, aby uzyskać więcej informacji.","gui.telemetryOptIn.privacyPolicyLink":"Polityka prywatności","gui.telemetryOptIn.optInText":"Udostępnij dane Zespołowi Scratch","gui.telemetryOptIn.optInTooltip":"Włącz telemetrię","gui.telemetryOptIn.optOutText":"Nie udostępniaj danych Zespołowi Scratch","gui.telemetryOptIn.optOutTooltip":"Wyłącz telemetrię","gui.telemetryOptIn.settingWasUpdated":"Ustawienia zostały zapisane.","gui.telemetryOptIn.buttonClose":"Zamknij","gui.turboMode.active":"Tryb turbo","gui.webglModal.label":"Twoja przeglądarka nie wspiera WebGL","gui.webglModal.webgllink":"nie wspiera WebG","gui.costumeLibrary.chooseABackdrop":"Wybierz tło","gui.costumeLibrary.chooseACostume":"Wybierz kostium","gui.costumeTab.addBackdropFromLibrary":"Wybierz tło","gui.costumeTab.addCostumeFromLibrary":"Wybierz kostium","gui.costumeTab.addBlankCostume":"Maluj","gui.costumeTab.addSurpriseCostume":"Niespodzianka","gui.costumeTab.addFileBackdrop":"Prześlij tło","gui.costumeTab.addFileCostume":"Prześlij kostium","gui.extensionLibrary.chooseAnExtension":"Wybierz rozszerzenie","gui.extensionLibrary.extensionUrl":"Wpisz adres URL rozszerzenia","gui.monitors.importListColumnPrompt":"Która kolumna powinna być użyta (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Rozpoczęcie odtwarzania nie powiodło się","gui.soundLibrary.chooseASound":"Wybierz dźwięk","gui.soundTab.fileUploadSound":"Prześlij dźwięk","gui.soundTab.surpriseSound":"Niespodzianka","gui.soundTab.recordSound":"Nagraj","gui.soundTab.addSoundFromLibrary":"Wybierz dźwięk","gui.spriteLibrary.chooseASprite":"Wybierz duszka","gui.tipsLibrary.tutorials":"Wybierz tutorial","gui.alerts.createsuccess":"Nowy projekt został utworzony.","gui.alerts.createcopysuccess":"Projekt zapisany jako kopia","gui.alerts.createremixsuccess":"Projekt zapisany jako remiks.","gui.alerts.creating":"Trwa tworzenie nowego projektu...","gui.alerts.creatingCopy":"Trwa kopiowanie projektu...","gui.alerts.creatingRemix":"Trwa remiksowanie projektu...","gui.alerts.creatingError":"Nie można stworzyć projektu. Prosimy spróbować ponownie!","gui.alerts.savingError":"Projekt nie mógł zostać zapisany.","gui.alerts.savesuccess":"Projekt zapisany.","gui.alerts.saving":"Zapisywanie projektu...","gui.alerts.cloudInfo":"Pamiętaj, że zmienne w chmurze obsługują jedynie liczby, a nie litery i symbole. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Dowiedz się więcej.","gui.alerts.importing":"Importowanie...","gui.defaultProject.variable":"moja zmienna","gui.extension.music.name":"Muzyka","gui.extension.music.description":"Graj na instrumentach i bębnach.","gui.extension.pen.name":"Pióro","gui.extension.pen.description":"Narysuj za pomocą swoich duszków","gui.extension.videosensing.name":"Czujniki wideo","gui.extension.videosensing.description":"Wykrywa ruch dzięki kamerze.","gui.extension.text2speech.name":"Tekst na Mowę","gui.extension.text2speech.description":"Spraw by twoje projekty mówiły","gui.extension.translate.name":"Tłumacz","gui.extension.translate.description":"Tłumacz tekst na wiele języków.","gui.extension.makeymakey.description":"Zamień wszystko w klawisz.","gui.extension.microbit.description":"Podziel się projektami ze światem.","gui.extension.microbit.connectingMessage":"Łączenie","gui.extension.ev3.description":"Buduj interaktywne roboty i inne rzeczy.","gui.extension.ev3.connectingMessage":"Łączenie. Upewnij się, że PIN na twoim EV3 ustawiony jest na 1234.","gui.extension.boost.description":"Ożyw robota.","gui.extension.boost.connectingMessage":"Łączenie","gui.extension.wedo2.description":"Buduj za pomocą silników i czujników.","gui.extension.wedo2.connectingMessage":"Łączenie","gui.extension.gdxfor.description":"Wykrywaj naciskanie, ciągnięcie, ruch i obrót.","gui.extension.gdxfor.connectingMessage":"Łączenie","gui.libraryTags.all":"Wszystko","gui.libraryTags.animals":"Zwierzęta","gui.libraryTags.dance":"Taniec","gui.libraryTags.effects":"Efekty","gui.libraryTags.fantasy":"Fikcja","gui.libraryTags.fashion":"Moda","gui.libraryTags.food":"Jedzenie","gui.libraryTags.indoors":"W pomieszczeniu","gui.libraryTags.loops":"Pętle","gui.libraryTags.music":"Muzyka","gui.libraryTags.notes":"Notatki","gui.libraryTags.outdoors":"Na zewnątrz","gui.libraryTags.patterns":"Wzory","gui.libraryTags.people":"Ludzie","gui.libraryTags.percussion":"Perkusja","gui.libraryTags.space":"Kosmos","gui.libraryTags.sports":"Sport","gui.libraryTags.underwater":"Pod wodą","gui.libraryTags.voice":"Głos","gui.libraryTags.wacky":"Zwariowany","gui.libraryTags.animation":"Animacja","gui.libraryTags.art":"Sztuka","gui.libraryTags.games":"Gry","gui.libraryTags.stories":"Opowiadania","gui.libraryTags.letters":"Litery","gui.opcodeLabels.direction":"Kierunek","gui.opcodeLabels.xposition":"Pozycja x","gui.opcodeLabels.yposition":"Pozycja y","gui.opcodeLabels.size":"rozmiar","gui.opcodeLabels.costumename":"Nazwa kostiumu","gui.opcodeLabels.costumenumber":"numer kostiumu","gui.opcodeLabels.backdropname":"Tło: nazwa","gui.opcodeLabels.backdropnumber":"numer tła","gui.opcodeLabels.volume":"Głośność","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"Odpowiedź","gui.opcodeLabels.loudness":"Głośność","gui.opcodeLabels.username":"Nazwa użytkownika","gui.opcodeLabels.year":"Rok","gui.opcodeLabels.month":"Miesiąc","gui.opcodeLabels.date":"Data","gui.opcodeLabels.dayofweek":"Dzień tygodnia","gui.opcodeLabels.hour":"Godzina","gui.opcodeLabels.minute":"Minuta","gui.opcodeLabels.second":"Sekunda","gui.opcodeLabels.timer":"Stoper","gui.sharedMessages.backdrop":"tło{index}","gui.sharedMessages.costume":"kostium{index}","gui.sharedMessages.sprite":"Duszek{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Czy zastąpić zawartość bieżącego projektu?","gui.sharedMessages.loadFromComputerTitle":"Wczytaj ze swojego komputera","boost.color.any":"dowolny kolor","boost.color.black":"czarny","boost.color.blue":"niebieski","boost.color.green":"zielony","boost.color.red":"czerwony","boost.color.white":"biały","boost.color.yellow":"żółty","boost.getMotorPosition":"pozycja silnika [MOTOR_REPORTER_ID]","boost.getTiltAngle":"Kąt pochylenia [TILT_DIRECTION]","boost.motorDirection.backward":"w tamten sposób","boost.motorDirection.forward":"w ten sposób","boost.motorDirection.reverse":"odwróć","boost.motorOff":"wyłącz silnik [MOTOR_ID]","boost.motorOn":"turn motor [MOTOR_ID] on","boost.motorOnFor":"turn motor [MOTOR_ID] for [DURATION] seconds","boost.motorOnForRotation":"turn motor [MOTOR_ID] for [ROTATION] rotations","boost.seeingColor":"widzi [COLOR] klocek?","boost.setLightHue":"Ustaw kolor światła na [HUE]","boost.setMotorDirection":"ustaw kierunek obrotu silnika [MOTOR_ID] na [MOTOR_DIRECTION]","boost.setMotorPower":"ustaw moc silnika [MOTOR_ID] na [POWER] %","boost.tiltDirection.any":"dowolnie","boost.tiltDirection.down":"w dół","boost.tiltDirection.left":"w lewo","boost.tiltDirection.right":"w prawo","boost.tiltDirection.up":"w górę","boost.whenColor":"kiedy widzi [COLOR] klocek","boost.whenTilted":"Gdy pochylony [TILT_DIRECTION_ANY]","ev3.beepNote":"graj nutę [NOTE] przez [TIME] sekund","ev3.buttonPressed":"Klawisz [PORT] naciśnięty?","ev3.getBrightness":"jasność","ev3.getDistance":"odległość","ev3.getMotorPosition":"pozycja silnika [PORT]","ev3.motorSetPower":"ustaw moc silnika [PORT] na [POWER] %","ev3.motorTurnClockwise":"Obróć silnik [PORT] do ruchu wskazówek zegara na [TIME] sekund","ev3.motorTurnCounterClockwise":"motor [PORT] turn that way for [TIME] seconds","ev3.whenBrightnessLessThan":"Gdy jasność < [DISTANCE]","ev3.whenButtonPressed":"Gdy klawisz [PORT] naciśnięty","ev3.whenDistanceLessThan":"Gdy odległość < [DISTANCE]","gdxfor.getAcceleration":"acceleration [DIRECTION]","gdxfor.getForce":"siła","gdxfor.getSpin":"prędkość wirowania [DIRECTION]","gdxfor.getTilt":"kąt nachylenia [TILT]","gdxfor.isFreeFalling":"falling?","gdxfor.isTilted":"tilted [TILT]?","gdxfor.pulled":"pulled","gdxfor.pushed":"pushed","gdxfor.shaken":"shaken","gdxfor.startedFalling":"started falling","gdxfor.tiltDirectionMenu.any":"dowolny","gdxfor.tiltDirectionMenu.back":"back","gdxfor.tiltDirectionMenu.front":"front","gdxfor.tiltDirectionMenu.left":"left","gdxfor.tiltDirectionMenu.right":"right","gdxfor.turnedFaceDown":"turned face down","gdxfor.turnedFaceUp":"turned face up","gdxfor.whenForcePushedOrPulled":"when force sensor [PUSH_PULL]","gdxfor.whenGesture":"kiedy [GESTURE]","gdxfor.whenTilted":"when tilted [TILT]","makeymakey.downArrow":"strzałka w dół","makeymakey.downArrowShort":"dół","makeymakey.leftArrow":"strzałka w lewo","makeymakey.leftArrowShort":"lewo","makeymakey.rightArrow":"strzałka w prawo","makeymakey.rightArrowShort":"prawo","makeymakey.spaceKey":"spacja","makeymakey.upArrow":"strzałka w górę","makeymakey.upArrowShort":"góra","makeymakey.whenKeyPressed":"kiedy naciśnięto klawisz [KEY]","makeymakey.whenKeysPressedInOrder":"kiedy naciśnięto kolejno [SEQUENCE]","microbit.buttonsMenu.any":"Dowolny","microbit.clearDisplay":"wyczyść wyświetlacz","microbit.defaultTextToDisplay":"Cześć!","microbit.displaySymbol":"wyświetl [MATRIX]","microbit.displayText":"wyświetl tekst [TEXT]","microbit.gesturesMenu.jumped":"podrzucony","microbit.gesturesMenu.moved":"poruszony","microbit.gesturesMenu.shaken":"potrząśnięty","microbit.isButtonPressed":"[BTN] przycisk naciśnięty?","microbit.isTilted":"nachylony [DIRECTION]","microbit.pinStateMenu.off":"wyłączony","microbit.pinStateMenu.on":"włączony","microbit.tiltAngle":"kąt nachylenia [DIRECTION]","microbit.tiltDirectionMenu.any":"Dowolny","microbit.tiltDirectionMenu.back":"do tyłu","microbit.tiltDirectionMenu.front":"do przodu","microbit.tiltDirectionMenu.left":"w lewo","microbit.tiltDirectionMenu.right":"w prawo","microbit.whenButtonPressed":"Gdy [BTN]naciśnięty","microbit.whenGesture":"kiedy [GESTURE]","microbit.whenPinConnected":"kiedy pin[PIN]połączony","microbit.whenTilted":"gdy nachylony[DIRECTION]","music.categoryName":"Muzyka","music.changeTempo":"zmień tempo na [TEMPO]","music.drumBass":"(2) Bęben basowy","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Klawesy","music.drumClosedHiHat":"(6) Zamknięty hi-hat","music.drumConga":"(14) bęben Konga","music.drumCowbell":"(11) Krowi dzwonek","music.drumCrashCymbal":"(4) talerz uderzany pałeczką","music.drumCuica":"(18) Cuíca","music.drumGuiro":"(16) Güiro","music.drumHandClap":"(8) Klaśnięcie","music.drumOpenHiHat":"(5) Otwarty hi-hat","music.drumSideStick":"(3) Side Stick","music.drumSnare":"(1) Werbel","music.drumTambourine":"(7) Tamburyn","music.drumTriangle":"(12) Trójkąt","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Drewniany klocek","music.getTempo":"tempo","music.instrumentBass":"(6) Bas","music.instrumentBassoon":"(14) Fagot","music.instrumentCello":"(8) Wiolonczela","music.instrumentChoir":"(15) Chór","music.instrumentClarinet":"(10) Klarnet","music.instrumentElectricGuitar":"(5) Gitara elektryczna","music.instrumentElectricPiano":"(2) Pianino elektroniczne ","music.instrumentFlute":"(12) Flet","music.instrumentGuitar":"(4) Gitara","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Pozytywka","music.instrumentOrgan":"(3) Organy","music.instrumentPiano":"(1) Pianino","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saksofon","music.instrumentSteelDrum":"(18) Stalowy bęben","music.instrumentSynthLead":"(26) Wiodący dźwięk syntezatora","music.instrumentSynthPad":"(21) Pad syntezatora","music.instrumentTrombone":"(9) Puzon","music.instrumentVibraphone":"(16) Wibrafon","music.instrumentWoodenFlute":"(13) Drewniany flet","music.midiPlayDrumForBeats":"graj na [DRUM] przez [BEATS] taktów","music.midiSetInstrument":"ustaw instrument na [INSTRUMENT]","music.playDrumForBeats":"graj na [DRUM] przez [BEATS] taktów","music.playNoteForBeats":"zagraj nutę [NOTE] przez [BEATS] taktów","music.restForBeats":"pauzuj przez [BEATS] taktów","music.setInstrument":"ustaw instrument na [INSTRUMENT]","music.setTempo":"ustaw tempo na [TEMPO]","pen.categoryName":"Pisak","pen.changeColorParam":"Zmień [COLOR_PARAM]pisaka o[VALUE]","pen.changeHue":"Zmień kolor pisaka o [HUE]","pen.changeShade":"Zmień odcień pisaka o [SHADE]","pen.changeSize":"Zmień rozmiar pisaka o [SIZE]","pen.clear":"wyczyść wszystko ","pen.colorMenu.brightness":"Jasność","pen.colorMenu.color":"Kolor","pen.colorMenu.saturation":"nasycenie","pen.colorMenu.transparency":"przezroczystość","pen.penDown":"Przyłóż pisak","pen.penUp":"Podnieś pisak ","pen.setColor":"Ustaw kolor pisaka na [COLOR]","pen.setColorParam":"Ustaw [COLOR_PARAM]pisaka na [VALUE]","pen.setHue":"Ustaw kolor pisaka na [HUE]","pen.setShade":"Ustaw odcień pisaka na [SHADE]","pen.setSize":"Ustaw rozmiar pisaka na [SIZE]","pen.stamp":"Stempluj","text2speech.alto":"kobiecy","text2speech.categoryName":"Tekst na Mowę","text2speech.defaultTextToSpeak":"cześć","text2speech.giant":"zmodyfikowany","text2speech.kitten":"kociątko","text2speech.setLanguageBlock":"ustaw język na [LANGUAGE]","text2speech.setVoiceBlock":"Ustaw głos na [VOICE]","text2speech.speakAndWaitBlock":"Powiedz [WORDS]","text2speech.squeak":"dziecięcy","text2speech.tenor":"męski","translate.categoryName":"Tłumacz","translate.defaultTextToTranslate":"cześć","translate.translateBlock":"tłumacz [WORDS] na [LANGUAGE]","translate.viewerLanguage":"język","videoSensing.categoryName":"Czujniki wideo","videoSensing.direction":"Kierunek","videoSensing.motion":"ruch","videoSensing.off":"wyłączony","videoSensing.on":"włączony","videoSensing.onFlipped":"on flipped","videoSensing.setVideoTransparency":"ustaw transparentność wideo na [TRANSPARENCY]","videoSensing.sprite":"duszek","videoSensing.stage":"scena","videoSensing.videoOn":"nagranie wideo [ATTRIBUTE] na [SUBJECT]","videoSensing.videoToggle":" [VIDEO_STATE] nagranie wideo ","videoSensing.whenMotionGreaterThan":"kiedy ruch wideo > [REFERENCE]","wedo2.getDistance":"odległość","wedo2.getTiltAngle":"Kąt pochylenia [TILT_DIRECTION]","wedo2.isTilted":"Pochylony [TILT_DIRECTION_ANY]","wedo2.motorDirection.backward":"w tamten sposób","wedo2.motorDirection.forward":"w ten sposób","wedo2.motorDirection.reverse":"odwróć","wedo2.motorId.a":"silnik A","wedo2.motorId.all":"wszystkie silniki","wedo2.motorId.b":"silnik B","wedo2.motorId.default":"silnik","wedo2.motorOff":"Wyłącz silnik [MOTOR_ID]","wedo2.motorOn":"Włącz silnik [MOTOR_ID]","wedo2.motorOnFor":"Włącz silnik [MOTOR_ID] na [DURATION] sekund","wedo2.playNoteFor":"Graj nutę [NOTE] przez [DURATION] sekund","wedo2.setLightHue":"Ustaw kolor światła na [HUE]","wedo2.setMotorDirection":"Ustaw kierunek silnika [MOTOR_ID] na [MOTOR_DIRECTION]","wedo2.startMotorPower":"Ustaw moc silnika [MOTOR_ID] na [POWER]","wedo2.tiltDirection.any":"Dowolny","wedo2.tiltDirection.down":"dół","wedo2.tiltDirection.left":"lewo","wedo2.tiltDirection.right":"prawo","wedo2.tiltDirection.up":"góra","wedo2.whenDistance":"Gdy dystans [OP] [REFERENCE]","wedo2.whenTilted":"Gdy pochylony [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Kolor","paint.paintEditor.saturation":"Nasycenie","paint.paintEditor.brightness":"Jasność","paint.paintEditor.costume":"Kostium","paint.paintEditor.group":"Grupuj","paint.paintEditor.ungroup":"Rozgrupuj","paint.paintEditor.undo":"Cofnij","paint.paintEditor.redo":"Ponów","paint.paintEditor.forward":"Do przodu","paint.paintEditor.backward":"Do tyłu","paint.paintEditor.front":"Przód","paint.paintEditor.back":"Powrót","paint.paintEditor.more":"Więcej","paint.modeTools.brushSize":"Rozmiar","paint.modeTools.eraserSize":"Wielkość gumki","paint.modeTools.copy":"Kopiuj","paint.modeTools.paste":"Wklej","paint.modeTools.delete":"Usuń","paint.modeTools.curved":"Zakrzywiony","paint.modeTools.pointed":"Wskazany","paint.modeTools.thickness":"Grubość","paint.modeTools.flipHorizontal":"Odwróć w płaszczyźnie poziomej","paint.modeTools.flipVertical":"Odwróć w płaszczyźnie pionowej","paint.modeTools.filled":"Wypełniony","paint.modeTools.outlined":"Kontur","paint.paintEditor.bitmap":"Przekształć w bitmapę","paint.paintEditor.vector":"Konwertuj na wektor","paint.paintEditor.fill":"Wypełnij","paint.paintEditor.stroke":"Zarys","paint.brushMode.brush":"Pędzel","paint.eraserMode.eraser":"Gumka","paint.fillMode.fill":"Wypełnij","paint.lineMode.line":"Linia","paint.ovalMode.oval":"Okrąg","paint.rectMode.rect":"Prostokąt","paint.reshapeMode.reshape":"Przekształć","paint.roundedRectMode.roundedRect":"Zaokrąglony prostokąt","paint.selectMode.select":"Wybierz","paint.textMode.text":"Tekst","paint.colorPicker.swap":"Zamień","tw.alerts.autosaving":"Tworzenie punktu przywracania…","tw.alerts.lostPeripheralConnection":"Utracono połączenie do {extensionName}.","tw.alerts.savedToDisk":"Zapisano na twoim komputerze.","tw.backpack.rename":"Nowa nazwa:","tw.changeUsername.cannotChangeWhileRunning":"Nazwa użytkownika nie może zostać zmieniona, kiedy projekt jest uruchomiony","tw.cloudVariableBadge":"Ten projekt używa zmiennych w chmurze. TurboWarp używa własnego serwera zmiennych w chmurze, niezależnego od Scratch. Uważaj na podszywanie się, ponieważ każdy może zmienić swoją nazwę użytkownika na jakąkolwiek. {learnMore}","tw.code":"Kod Źródłowy","tw.customExtension.description":"Wczytaj niestandardowe rozszerzenia z adresów URL. Dla programistów. Eksperymentalny.","tw.customExtension.name":"Niestandardowe Rozszerzenie","tw.featuredProjectsStudio":"Zobacz studio w Scratchu.","tw.feedback":"Opinie i Błędy","tw.feedbackButton":"Opinia o TurboWarp","tw.footer.credits":"Podziękowania","tw.footer.disclaimer":"TurboWarp nie jest powiązany ze Scratch, Scratch Team, ani Scratch Foundation.","tw.footer.embed":"Osadzanie","tw.footer.fosshost":"Hosting dostarczany przez Fosshost","tw.footer.parameters":"Parametry URL","tw.footer.translate":"Pomóż Tłumaczyć TurboWarp","tw.gui.defaultProjectTitle":"Projekt","tw.guiDefaultTitle":"Uruchamiaj projekty Scratch szybciej","tw.home.credit":"Notatki i Podziękowania","tw.home.description":"TurboWarp to modyfikacja Scratcha która kompiluje projekty do JavaScript żeby chodziły bardzo szybko. Wypróbuj tą funkcje wprowadzając ID projektu lub jego URL powyżej lub wybierając polecany projekt poniżej.","tw.home.instructions":"Instrukcje","tw.input.tooltip":"Skopiuj i wklej link do projektu Scratcha tutaj!","tw.interpolationEnabled":"Interpolacja","tw.invalidParameters.clones":"Parametr URL \\"clone\\" jest nieprawidłowy","tw.invalidParameters.fps":"Parametr URL \\"fps\\" jest nieprawidłowy","tw.loadError":"Nie udało się załadować projektu: {error}","tw.loader.assets.known":"Pobieranie zasobów ({complete}/{total}) ...","tw.loader.assets.unknown":"Pobieranie zasobów ...","tw.loader.data":"Pobieranie danych projektu ...","tw.loader.generic":"Ładowanie projektu ...","tw.menuBar.60off":"Wyłącz tryb 60 FPS","tw.menuBar.60on":"Włącz tryb 60 FPS","tw.menuBar.addons":"Dodatki","tw.menuBar.advanced":"Zaawansowane","tw.menuBar.changeUsername":"Zmień Nazwę Użytkownika","tw.menuBar.cloudOff":"Wyłącz Zmienne W Chmurze","tw.menuBar.cloudOn":"Włącz Zmienne W Chmurze","tw.menuBar.cloudUnavailable":"Zmienne W Chmurze nie są Dostępne","tw.menuBar.cloudUnavailableAlert":"Nie można użyć zmiennych w chmurze, najprawdopodobniej dlatego, że masz włączony edytor.","tw.menuBar.loadRestorePoint":"Załaduj punkt przywracania","tw.menuBar.moreSettings":"Zaawansowane Ustawienia","tw.menuBar.newFramerate":"Nowa liczba klatek na sekundę:","tw.menuBar.reportError1":"Nie można skompilować niektórych skryptów.","tw.menuBar.reportError2":"To jest błąd. Proszę zgłoś to.","tw.menuBar.saveAs":"Zapisz jako {file}","tw.menuBar.seeInside":"Zajrzyj do środka","tw.oldDownload":"Zapisz do osobnego pliku...","tw.paint.alpha":"Nieprzezroczystość","tw.privacy":"Polityka Prywatności","tw.saveAs":"Zapisz jako...","tw.saveTo":"Zapisz do {file}","tw.settingsModal.customStageSize":"Niestandardowy Rozmiar Sceny:","tw.settingsModal.customStageSizeHelp":"Zmienia wielkość ekranu używanego w Scratchu z 480x360 do jakiejś innej wielkości. Spróbuj 640x360 żeby zrobić ekran szerszy. Bardzo niewiele projektów poradzi sobie z tym prawidłowo.","tw.settingsModal.dangerZone":"Niebezpieczna Strefa","tw.settingsModal.disableCompiler":"Wyłącz Kompilator","tw.settingsModal.featured":"Polecane","tw.settingsModal.fps":"60 FPS (Niestandardowe FPS)","tw.settingsModal.fpsHelp.customFramerate":"Kliknij, aby ustawić liczbę klatek na sekundę inną niż 30 lub 60","tw.settingsModal.help":"Kliknij po pomoc","tw.settingsModal.highQualityPen":"Wysokiej Jakości Pióro","tw.settingsModal.infiniteClones":"Nieskończone Klony","tw.settingsModal.infiniteClonesHelp":"Wyłącza Scratchowy limit 300 klonów.","tw.settingsModal.interpolation":"Interpolacja","tw.settingsModal.removeFencing":"Usuń Ograniczenia","tw.settingsModal.removeLimits":"Usuń Limity","tw.settingsModal.removeMiscLimits":"Usuń Różne Limity","tw.settingsModal.removeMiscLimitsHelp":"Usuwa limity efektów dźwiękowych i rozmiaru pisaka.","tw.settingsModal.storeProjectOptions":"Przechowaj ustawienia w projekcie","tw.settingsModal.title":"Zaawansowane Ustawienia","tw.settingsModal.warpTimer":"Warp Stoper","tw.spriteSelectorItem.rename":"zmień nazwę","tw.studioview.authorAttribution":"przez {author}","tw.studioview.error":"Wystąpił błąd w ładowaniu następnej strony projektów.","tw.studioview.hoverText":"{title} autorstwa {author}","tw.twExtension.description":"Dziwne nowe bloki. Niekompatybilne ze Scratchem.","tw.twExtension.name":"Bloki TurboWarp","tw.usernameModal.mustChange.resetIt":"zresetuj to (zalecane)","tw.usernameModal.reset":"Resetuj","tw.usernameModal.title":"Zmień Nazwę Użytkownika","tw.viewFeaturedProjects":"Kliknij, aby zobaczyć polecane projekty.","tw.viewOnScratch":"Zobacz projekt w Scratchu"},"pt":{"gui.alerts.tryAgain":"Tentar de Novo","gui.alerts.download":"Descarregar","gui.connection.reconnect":"Voltar a Ligar","gui.backpack.costumeLabel":"traje","gui.backpack.soundLabel":"som","gui.backpack.scriptLabel":"guião","gui.backpack.spriteLabel":"actor","gui.backpack.header":"Mochila","gui.backpack.errorBackpack":"Erro ao carregar a mochila","gui.backpack.loadingBackpack":"Carregando…","gui.backpack.more":"Mais","gui.backpack.emptyBackpack":"A mochila está vazia","gui.unsupportedBrowser.label":"O navegador não é suportado","gui.cards.all-tutorials":"Tutoriais","gui.cards.shrink":"Reduzir","gui.cards.expand":"Expandir","gui.cards.close":"Fechar","gui.cards.more-things-to-try":"Mais coisas a experimentar!","gui.cards.see-more":"Ver mais","gui.comingSoon.message1":"Não se preocupe, estamos a trabalhar afincadamente nisto {emoji}","gui.comingSoon.message2":"Em Breve...","gui.comingSoon.message3":"Estamos a trabalhar afincadamente nisto {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Não foram encontrados dispositivos","gui.connection.auto-scanning.prescan":"Mantenha o seu dispositivo por perto, depois comece uma procura.","gui.connection.auto-scanning.pressbutton":"Pressione o botão no seu dispositivo.","gui.connection.auto-scanning.start-search":"Começar Procura","gui.connection.connecting-searchbutton":"Procurando…","gui.connection.auto-scanning.try-again":"Tentar de novo","gui.connection.connected":"Ligado","gui.connection.disconnect":"Desligar","gui.connection.go-to-editor":"Ir para o Editor","gui.connection.connecting-cancelbutton":"Ligando…","gui.connection.error.errorMessage":"Ops, parece que algo correu mal.","gui.connection.error.tryagainbutton":"Tentar de novo","gui.connection.error.helpbutton":"Ajuda","gui.connection.peripheral-name-label":"Nome do dispositivo","gui.connection.connect":"Ligar","gui.connection.scanning.lookingforperipherals":"Procurando dispositivos","gui.connection.scanning.noPeripheralsFound":"Não foram encontrados dispositivos","gui.connection.scanning.instructions":"Seleccione o seu dispositivo na lista abaixo.","gui.connection.search":"Refrescar","gui.connection.unavailable.installscratchlink":"Assegure-se de que tem o Scratch Link instalado e em execução","gui.connection.unavailable.enablebluetooth":"Verifique se o Bluetooth está activo","gui.connection.unavailable.tryagainbutton":"Tentar de novo","gui.connection.unavailable.helpbutton":"Ajuda","gui.controls.go":"Começar","gui.controls.stop":"Parar","gui.crashMessage.label":"Oh lá! Algo correu mal.","gui.crashMessage.errorNumber":"O seu erro foi registado com o identificador {errorId}","gui.crashMessage.reload":"Recarregar","gui.customProcedures.myblockModalTitle":"Criar um Bloco","gui.customProcedures.addAnInputNumberText":"Adicionar uma entrada","gui.customProcedures.numberTextType":"numérica ou textual","gui.customProcedures.addAnInputBoolean":"Adicionar uma entrada","gui.customProcedures.booleanType":"booleana","gui.customProcedures.addALabel":"Adicionar uma etiqueta","gui.customProcedures.runWithoutScreenRefresh":"Executar sem actualizar o ecrã","gui.customProcedures.cancel":"Cancelar","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Direcção","gui.directionPicker.rotationStyles.allAround":"Girar a Toda a Volta","gui.directionPicker.rotationStyles.leftRight":"Olhar apenas para a esquerda e para a direita","gui.directionPicker.rotationStyles.dontRotate":"Não rodar","gui.gui.addExtension":"Adicionar Extensão","gui.gui.codeTab":"Código","gui.gui.backdropsTab":"Cenários","gui.gui.costumesTab":"Trajes","gui.gui.soundsTab":"Sons","gui.extensionLibrary.comingSoon":"Em Breve","gui.extensionLibrary.requires":"Requere","gui.extensionLibrary.collaboration":"Colaboração com","gui.library.filterPlaceholder":"Procurar","gui.library.allTag":"Tudo","gui.loader.headline":"A Carregar o Projecto","gui.loader.creating":"Criando Projecto","gui.authorInfo.byUser":"por {username}","gui.menuBar.seeProjectPage":"Ver Página do Projecto","gui.menuBar.LanguageSelector":"selector de língua","gui.menuBar.tutorialsLibrary":"Tutoriais","gui.menuBar.restoreSprite":"Recuperar Actor","gui.menuBar.restoreSound":"Recuperar Som","gui.menuBar.restoreCostume":"Recuperar Traje","gui.menuBar.restore":"Recuperar","gui.menuBar.saveNow":"Guardar agora","gui.menuBar.saveAsCopy":"Guardar como cópia","gui.menuBar.remix":"Remisturar","gui.menuBar.new":"Novo","gui.menuBar.file":"Arquivo","gui.menuBar.downloadToComputer":"Descarregar para o seu computador","gui.menuBar.edit":"Editar","gui.menuBar.turboModeOff":"Desligar o Modo Turbo","gui.menuBar.turboModeOn":"Ligar o Modo Turbo","gui.gui.projectTitlePlaceholder":"Introduza aqui o título do projecto","gui.menuBar.isShared":"Partilhado","gui.menuBar.share":"Partilhar","gui.modal.help":"Ajuda","gui.modal.back":"Voltar","gui.monitor.listMonitor.empty":"(vazia)","gui.monitor.listMonitor.listLength":"comprimento {length}","gui.monitor.contextMenu.default":"visor normal","gui.monitor.contextMenu.large":"visor grande","gui.monitor.contextMenu.slider":"deslizador","gui.monitor.contextMenu.sliderRange":"alterar gama de valores do deslizador","gui.monitor.contextMenu.import":"importar","gui.monitor.contextMenu.export":"exportar","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Tocar","gui.playButton.stop":"Parar","gui.gui.variableScopeOptionAllSprites":"Para todos os actores","gui.gui.variableScopeOptionSpriteOnly":"Apenas para este actor","gui.gui.cloudVariableOption":"Variável de nuvem (guardada em servidor)","gui.gui.variablePromptAllSpritesMessage":"Esta variável estará disponível para todos os actores.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Cancelar","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Parar","gui.playbackStep.playMsg":"Tocar","gui.playbackStep.loadingMsg":"Carregando…","gui.playbackStep.saveMsg":"Guardar","gui.playbackStep.reRecordMsg":"Voltar a Gravar","gui.recordModal.title":"Gravar Som","gui.recordingStep.beginRecord":"Começar a gravar clicando no botão abaixo","gui.recordingStep.permission":"{arrow}Precisamos da sua permissão para usar o seu microfone","gui.recordingStep.stop":"Parar a gravação","gui.recordingStep.record":"Gravar","gui.sliderModal.min":"Valor mínimo","gui.sliderModal.max":"Valor máximo","gui.sliderModal.title":"Alterar gama de valores do deslizador","gui.sliderPrompt.cancel":"Cancelar","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Som","gui.soundEditor.play":"Tocar","gui.soundEditor.stop":"Parar","gui.soundEditor.copy":"Copiar","gui.soundEditor.paste":"Colar","gui.soundEditor.copyToNew":"Copiar para Novo","gui.soundEditor.delete":"Remover","gui.soundEditor.save":"Guardar","gui.soundEditor.undo":"Desfazer","gui.soundEditor.redo":"Refazer","gui.soundEditor.faster":"Acelerar","gui.soundEditor.slower":"Retardar","gui.soundEditor.echo":"Eco","gui.soundEditor.robot":"Robô","gui.soundEditor.louder":"Maior Volume","gui.soundEditor.softer":"Menor Volume","gui.soundEditor.reverse":"Inverter","gui.soundEditor.fadeOut":"Desaparecer gradualmente","gui.soundEditor.fadeIn":"Aparecer gradualmente","gui.soundEditor.mute":"Silenciar","gui.SpriteInfo.spritePlaceholder":"Nome","gui.SpriteInfo.sprite":"Actor","gui.SpriteInfo.show":"Mostrar","gui.SpriteInfo.size":"Tamanho","gui.spriteSelectorItem.contextMenuDuplicate":"duplicar","gui.spriteSelectorItem.contextMenuExport":"exportar","gui.spriteSelectorItem.contextMenuDelete":"remover","gui.spriteSelector.addSpriteFromLibrary":"Escolher um Actor","gui.spriteSelector.addSpriteFromPaint":"Pintar","gui.spriteSelector.addSpriteFromSurprise":"Surpresa","gui.spriteSelector.addSpriteFromFile":"Carregar Actor","gui.stageHeader.stageSizeLarge":"Mudar para um palco grande","gui.stageHeader.stageSizeSmall":"Mudar para palco pequeno","gui.stageHeader.stageSizeFull":"Iniciar modo de ecrã completo","gui.stageHeader.stageSizeUnFull":"Sair do modo de ecrã completo","gui.stageHeader.fullscreenControl":"Controlo de Ecrã Completo","gui.spriteSelector.addBackdropFromLibrary":"Escolher um Cenário","gui.stageSelector.addBackdropFromPaint":"Pintar","gui.stageSelector.addBackdropFromSurprise":"Surpresa","gui.stageSelector.addBackdropFromFile":"Carregar Cenário","gui.stageSelector.stage":"Palco","gui.stageSelector.backdrops":"Cenários","gui.telemetryOptIn.label":"Reportar estatísticas para melhorar o Scratch","gui.telemetryOptIn.body1":"A Equipa Scratch está sempre a tentar compreender melhor como o Scratch é usado em todo o mundo. Para ajudar a apoiar este esforço, pode permitir que o Scratch envie automaticamente informação de uso para a Equipa Scratch.","gui.telemetryOptIn.body2":"A informação que recolhemos inclui a selecção da língua, a utilização dos blocos e alguns eventos tais como guardar, abrir e carregar um projecto. NÃO recolhemos nenhuma informação pessoal. Por favor veja as nossas {privacyPolicyLink} para mais informações.","gui.telemetryOptIn.privacyPolicyLink":"Política de Privacidade","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Modo Turbo","gui.webglModal.label":"O Seu Navegador Não Suporta WebGL","gui.webglModal.webgllink":"não suporta WebGL","gui.costumeLibrary.chooseABackdrop":"Escolher um Cenário","gui.costumeLibrary.chooseACostume":"Escolher um Traje","gui.costumeTab.addBackdropFromLibrary":"Escolher um Cenário","gui.costumeTab.addCostumeFromLibrary":"Escolher um Traje","gui.costumeTab.addBlankCostume":"Pintar","gui.costumeTab.addSurpriseCostume":"Surpresa","gui.costumeTab.addFileBackdrop":"Carregar Cenário","gui.costumeTab.addFileCostume":"Carregar Traje","gui.extensionLibrary.chooseAnExtension":"Escolher uma Extensão","gui.extensionLibrary.extensionUrl":"Introduza o URL da extensão","gui.monitors.importListColumnPrompt":"Que coluna deve ser usada (1 – {numberOfColumns})?","gui.recordingStep.alertMsg":"Não foi possível iniciar gravação","gui.soundLibrary.chooseASound":"Escolher um Som","gui.soundTab.fileUploadSound":"Carregar Som","gui.soundTab.surpriseSound":"Surpresa","gui.soundTab.recordSound":"Gravar","gui.soundTab.addSoundFromLibrary":"Escolher um Som","gui.spriteLibrary.chooseASprite":"Escolher um Actor","gui.tipsLibrary.tutorials":"Escolher um Tutorial","gui.alerts.createsuccess":"Criado novo projecto.","gui.alerts.createcopysuccess":"Projecto guardado como cópia.","gui.alerts.createremixsuccess":"Projecto guardado como uma remistura.","gui.alerts.creating":"A criar novo…","gui.alerts.creatingCopy":"A copiar o projecto…","gui.alerts.creatingRemix":"A remisturar o projecto…","gui.alerts.creatingError":"Não foi possível criar o projecto. Por favor tente novamente!","gui.alerts.savingError":"Não foi possível guardar o projecto.","gui.alerts.savesuccess":"Projecto guardado.","gui.alerts.saving":"A guardar o projecto…","gui.alerts.cloudInfo":"Por favor note que as variáveis de nuvem suportam apenas números, e não letras ou símbolos. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Saber mais.","gui.alerts.importing":"A importar…","gui.defaultProject.variable":"a minha variável","gui.extension.music.name":"Música","gui.extension.music.description":"Toque instrumentos e percussão.","gui.extension.pen.name":"Caneta","gui.extension.pen.description":"Desenhe com os seus actores.","gui.extension.videosensing.name":"Vídeo Sensorial","gui.extension.videosensing.description":"Use a câmara para sentir movimento.","gui.extension.text2speech.name":"Texto para Fala","gui.extension.text2speech.description":"Faça os seus projectos falar.","gui.extension.translate.name":"Traduzir","gui.extension.translate.description":"Traduza texto para muitas línguas.","gui.extension.makeymakey.description":"Transforme tudo numa tecla.","gui.extension.microbit.description":"Ligue os seus projectos ao mundo.","gui.extension.microbit.connectingMessage":"Ligando","gui.extension.ev3.description":"Crie robôs interactivos e muito mais.","gui.extension.ev3.connectingMessage":"Ligando. Assegure-se de que o pino no seu EV3 está configurado para 1234.","gui.extension.boost.description":"Dê vida a criações robóticas.","gui.extension.boost.connectingMessage":"Ligando","gui.extension.wedo2.description":"Construa com motores e sensores.","gui.extension.wedo2.connectingMessage":"Ligando","gui.extension.gdxfor.description":"Detecte puxões, empurrões, movimento e rotação.","gui.extension.gdxfor.connectingMessage":"Ligando","gui.libraryTags.all":"Tudo","gui.libraryTags.animals":"Animais","gui.libraryTags.dance":"Dança","gui.libraryTags.effects":"Efeitos","gui.libraryTags.fantasy":"Fantasia","gui.libraryTags.fashion":"Moda","gui.libraryTags.food":"Comida","gui.libraryTags.indoors":"Interior","gui.libraryTags.loops":"Ciclos de som","gui.libraryTags.music":"Música","gui.libraryTags.notes":"Notas","gui.libraryTags.outdoors":"Exterior","gui.libraryTags.patterns":"Padrões","gui.libraryTags.people":"Pessoas","gui.libraryTags.percussion":"Percussão","gui.libraryTags.space":"Espaço","gui.libraryTags.sports":"Desporto","gui.libraryTags.underwater":"Debaixo de água","gui.libraryTags.voice":"Vozes","gui.libraryTags.wacky":"Maluquices","gui.libraryTags.animation":"Animações","gui.libraryTags.art":"Arte","gui.libraryTags.games":"Jogos","gui.libraryTags.stories":"Estórias","gui.libraryTags.letters":"Letras","gui.opcodeLabels.direction":"direcção","gui.opcodeLabels.xposition":"x da posição","gui.opcodeLabels.yposition":"y da posição","gui.opcodeLabels.size":"tamanho","gui.opcodeLabels.costumename":"nome do traje","gui.opcodeLabels.costumenumber":"número do traje","gui.opcodeLabels.backdropname":"nome do cenário","gui.opcodeLabels.backdropnumber":"número do cenário","gui.opcodeLabels.volume":"volume","gui.opcodeLabels.tempo":"andamento","gui.opcodeLabels.answer":"resposta","gui.opcodeLabels.loudness":"volume no microfone","gui.opcodeLabels.username":"nome de utilizador","gui.opcodeLabels.year":"ano actual","gui.opcodeLabels.month":"mês actual","gui.opcodeLabels.date":"data actual","gui.opcodeLabels.dayofweek":"dia da semana actual","gui.opcodeLabels.hour":"hora actual","gui.opcodeLabels.minute":"minuto actual","gui.opcodeLabels.second":"segundo actual","gui.opcodeLabels.timer":"valor do cronómetro","gui.sharedMessages.backdrop":"Cenário {index}","gui.sharedMessages.costume":"Traje {index}","gui.sharedMessages.sprite":"o actor {index}","gui.sharedMessages.pop":"Pop!","gui.sharedMessages.replaceProjectWarning":"Substituir o conteúdo do projecto corrente?","gui.sharedMessages.loadFromComputerTitle":"Carregar a partir do seu computador","boost.color.any":"de qualquer cor","boost.color.black":"preto","boost.color.blue":"azul","boost.color.green":"verde","boost.color.red":"vermelho","boost.color.white":"branco","boost.color.yellow":"amarelo","boost.getMotorPosition":"a posição do motor [MOTOR_REPORTER_ID]","boost.getTiltAngle":"o ângulo da inclinação [TILT_DIRECTION]","boost.motorDirection.backward":"para ali","boost.motorDirection.forward":"para aqui","boost.motorDirection.reverse":"ao contrário","boost.motorOff":"desliga o motor [MOTOR_ID]","boost.motorOn":"liga o motor [MOTOR_ID]","boost.motorOnFor":"roda o motor [MOTOR_ID] durante [DURATION] s","boost.motorOnForRotation":"roda o motor [MOTOR_ID] [ROTATION] rotações","boost.seeingColor":"está a ver um tijolo [COLOR]","boost.setLightHue":"altera a cor da luz para [HUE]","boost.setMotorDirection":"altera a direcção do motor [MOTOR_ID] para [MOTOR_DIRECTION]","boost.setMotorPower":"altera a velocidade do motor [MOTOR_ID] para [POWER] %","boost.tiltDirection.any":"para qualquer lado","boost.tiltDirection.down":"para baixo","boost.tiltDirection.left":"para a esquerda","boost.tiltDirection.right":"para a direita","boost.tiltDirection.up":"cima","boost.whenColor":"Quando vir o tijolo [COLOR] ","boost.whenTilted":"Quando for inclinado [TILT_DIRECTION_ANY]","ev3.beepNote":"toca a nota [NOTE] durante [TIME]s","ev3.buttonPressed":"o botão [PORT] está a ser pressionado","ev3.getBrightness":"o brilho","ev3.getDistance":"a distância","ev3.getMotorPosition":"a posição do motor [PORT]","ev3.motorSetPower":"altera a potência do motor [PORT] para [POWER]%","ev3.motorTurnClockwise":"roda o motor [PORT] para aqui durante [TIME] s","ev3.motorTurnCounterClockwise":"roda o motor [PORT]para ali durante [TIME] s","ev3.whenBrightnessLessThan":"Quando o brilho for menor que [DISTANCE]","ev3.whenButtonPressed":"Quando o botão [PORT] for pressionado","ev3.whenDistanceLessThan":"Quando a distância for menor que [DISTANCE]","gdxfor.getAcceleration":"a aceleração [DIRECTION]","gdxfor.getForce":"a força","gdxfor.getSpin":"a velocidade de rotação [DIRECTION]","gdxfor.getTilt":"o ângulo de inclinação [TILT]","gdxfor.isFreeFalling":"a cair","gdxfor.isTilted":"está inclinado [TILT]","gdxfor.pulled":"for puxado","gdxfor.pushed":"for empurrado","gdxfor.shaken":"for abanado","gdxfor.startedFalling":"começar a cair","gdxfor.tiltDirectionMenu.any":"para qualquer lado","gdxfor.tiltDirectionMenu.back":"para trás","gdxfor.tiltDirectionMenu.front":"para a frente","gdxfor.tiltDirectionMenu.left":"para a esquerda","gdxfor.tiltDirectionMenu.right":"para a direita","gdxfor.turnedFaceDown":"está com a face para baixo","gdxfor.turnedFaceUp":"está com a face para cima","gdxfor.whenForcePushedOrPulled":"Quando o sensor de força [PUSH_PULL]","gdxfor.whenGesture":"Quando [GESTURE]","gdxfor.whenTilted":"Quando for inclinado [TILT]","makeymakey.downArrow":"seta para baixo","makeymakey.downArrowShort":"baixo","makeymakey.leftArrow":"seta para a esquerda","makeymakey.leftArrowShort":"esquerda","makeymakey.rightArrow":"seta para a direita","makeymakey.rightArrowShort":"direita","makeymakey.spaceKey":"espaço","makeymakey.upArrow":"seta para cima","makeymakey.upArrowShort":"cima","makeymakey.whenKeyPressed":"Quando a tecla [KEY] for pressionada","makeymakey.whenKeysPressedInOrder":"Quando [SEQUENCE] forem pressionadas por ordem","microbit.buttonsMenu.any":"qualquer","microbit.clearDisplay":"apaga o ecrã","microbit.defaultTextToDisplay":"Ola!","microbit.displaySymbol":"mostra [MATRIX]","microbit.displayText":"mostra o texto [TEXT]","microbit.gesturesMenu.jumped":"saltar","microbit.gesturesMenu.moved":"se mover","microbit.gesturesMenu.shaken":"for abanado","microbit.isButtonPressed":"o botão [BTN] está a ser pressionado","microbit.isTilted":"está inclinado [DIRECTION]","microbit.pinStateMenu.off":"desligado","microbit.pinStateMenu.on":"ligado","microbit.tiltAngle":"o ângulo da inclinação [DIRECTION]","microbit.tiltDirectionMenu.any":"para qualquer lado","microbit.tiltDirectionMenu.back":"para trás","microbit.tiltDirectionMenu.front":"para a frente","microbit.tiltDirectionMenu.left":"para a esquerda","microbit.tiltDirectionMenu.right":"para a direita","microbit.whenButtonPressed":"Quando o botão [BTN] for pressionado","microbit.whenGesture":"Quando [GESTURE]","microbit.whenPinConnected":"Quando o pino [PIN] for ligado","microbit.whenTilted":"Quando for inclinado [DIRECTION]","music.categoryName":"Música","music.changeTempo":"adiciona [TEMPO] bpm ao teu andamento","music.drumBass":"(2) Bombo","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabaça","music.drumClaves":"(9) Clavas","music.drumClosedHiHat":"(6) Pratos de Choque Fechados","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Caneca","music.drumCrashCymbal":"(4) Prato de Ataque","music.drumCuica":"(18) Cuíca","music.drumGuiro":"(16) Reco-Reco","music.drumHandClap":"(8) Palmas","music.drumOpenHiHat":"(5) Pratos de Choque Abertos","music.drumSideStick":"(3) Golpe no Fuste da Tarola","music.drumSnare":"(1) Caixa","music.drumTambourine":"(7) Pandeireta","music.drumTriangle":"(12) Triângulo","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Bloco Sonoro","music.getTempo":"o andamento","music.instrumentBass":"(6) Baixo","music.instrumentBassoon":"(14) Fagote","music.instrumentCello":"(8) Violoncelo","music.instrumentChoir":"(15) Coro","music.instrumentClarinet":"(10) Clarinete","music.instrumentElectricGuitar":"(5) Guitarra Eléctrica","music.instrumentElectricPiano":"(2) Piano Eléctrico","music.instrumentFlute":"(12) Flauta Transversal","music.instrumentGuitar":"(4) Guitarra","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Caixa de Música","music.instrumentOrgan":"(3) Órgão","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxofone","music.instrumentSteelDrum":"(18) Tambor de Aço","music.instrumentSynthLead":"(20) Sintetizador Melódico","music.instrumentSynthPad":"(21) Sintetizador de Fundo","music.instrumentTrombone":"(9) Trombone","music.instrumentVibraphone":"(16) Vibrafone","music.instrumentWoodenFlute":"(13) Flauta de Madeira","music.midiPlayDrumForBeats":"toca a percussão [DRUM] durante [BEATS] tempos","music.midiSetInstrument":"altera o teu instrumento para [INSTRUMENT]","music.playDrumForBeats":"toca a percussão [DRUM] durante [BEATS] tempos","music.playNoteForBeats":"toca a nota [NOTE] durante [BEATS] tempos","music.restForBeats":"faz uma pausa de [BEATS] tempos","music.setInstrument":"altera a teu instrumento para [INSTRUMENT]","music.setTempo":"altera o teu andamento para [TEMPO] bpm","pen.categoryName":"Caneta","pen.changeColorParam":"adiciona a [COLOR_PARAM] da tua caneta o valor [VALUE]","pen.changeHue":"adiciona [HUE] à cor da tua caneta","pen.changeShade":"adiciona [SHADE] ao tom da tua caneta","pen.changeSize":"adiciona [SIZE] à espessura da tua caneta","pen.clear":"apaga tudo do palco","pen.colorMenu.brightness":"o brilho","pen.colorMenu.color":"o matiz","pen.colorMenu.saturation":"a saturação","pen.colorMenu.transparency":"a transparência","pen.penDown":"baixa a tua caneta","pen.penUp":"levanta a tua caneta","pen.setColor":"altera a cor da tua caneta para [COLOR]","pen.setColorParam":"altera [COLOR_PARAM] da tua caneta para [VALUE]","pen.setHue":"altera a cor da tua caneta para [HUE]","pen.setShade":"altera o tom da tua caneta para [SHADE]","pen.setSize":"altera a espessura da tua caneta para [SIZE]","pen.stamp":"carimba-te","text2speech.alto":"alto","text2speech.categoryName":"Texto para Fala","text2speech.defaultTextToSpeak":"Olá!","text2speech.giant":"gigante","text2speech.kitten":"gatinho","text2speech.setLanguageBlock":"altera a língua para [LANGUAGE]","text2speech.setVoiceBlock":"altera a voz para [VOICE]","text2speech.speakAndWaitBlock":"fala [WORDS]","text2speech.squeak":"guincho","text2speech.tenor":"tenor","translate.categoryName":"Traduzir","translate.defaultTextToTranslate":"olá","translate.translateBlock":"a tradução de [WORDS] para [LANGUAGE]","translate.viewerLanguage":"a língua","videoSensing.categoryName":"Sensores de Vídeo","videoSensing.direction":"a direcção","videoSensing.motion":"o movimento","videoSensing.off":"desligado","videoSensing.on":"ligado","videoSensing.onFlipped":"ligado e espelhado","videoSensing.setVideoTransparency":"altera a transparência do vídeo para [TRANSPARENCY] %","videoSensing.sprite":"ti mesmo","videoSensing.stage":"o palco","videoSensing.videoOn":"[ATTRIBUTE] do vídeo em [SUBJECT]","videoSensing.videoToggle":"altera o estado do vídeo para [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"Quando o movimento do vídeo exceder [REFERENCE]","wedo2.getDistance":"a distância","wedo2.getTiltAngle":"o ângulo da inclinação [TILT_DIRECTION]","wedo2.isTilted":"está inclinado [TILT_DIRECTION_ANY]","wedo2.motorDirection.backward":"para ali","wedo2.motorDirection.forward":"para aqui","wedo2.motorDirection.reverse":"para trás","wedo2.motorId.a":"o motor A","wedo2.motorId.all":"todos os motores","wedo2.motorId.b":"o motor B","wedo2.motorId.default":"o motor","wedo2.motorOff":"desliga [MOTOR_ID]","wedo2.motorOn":"liga [MOTOR_ID]","wedo2.motorOnFor":"liga [MOTOR_ID] durante [DURATION] s","wedo2.playNoteFor":"toca a nota [NOTE] durante [DURATION] s","wedo2.setLightHue":"altera a cor da luz para [HUE]","wedo2.setMotorDirection":"altera a direcção de [MOTOR_ID] para [MOTOR_DIRECTION]","wedo2.startMotorPower":"altera a potência de [MOTOR_ID] para [POWER]","wedo2.tiltDirection.any":"para qualquer lado","wedo2.tiltDirection.down":"para baixo","wedo2.tiltDirection.left":"para a esquerda","wedo2.tiltDirection.right":"para a direita","wedo2.tiltDirection.up":"para cima","wedo2.whenDistance":"Quando a distância for [OP] [REFERENCE]","wedo2.whenTilted":"Quando for inclinado [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Matiz","paint.paintEditor.saturation":"Saturação","paint.paintEditor.brightness":"Brilho","paint.paintEditor.costume":"Traje","paint.paintEditor.group":"Agrupar","paint.paintEditor.ungroup":"Desagrupar","paint.paintEditor.undo":"Desfazer","paint.paintEditor.redo":"Refazer","paint.paintEditor.forward":"Avançar","paint.paintEditor.backward":"Recuar","paint.paintEditor.front":"Para a Frente","paint.paintEditor.back":"Para Trás","paint.paintEditor.more":"Mais","paint.modeTools.brushSize":"Tamanho","paint.modeTools.eraserSize":"Tamanho da borracha","paint.modeTools.copy":"Copiar","paint.modeTools.paste":"Colar","paint.modeTools.delete":"Remover","paint.modeTools.curved":"Arredondado","paint.modeTools.pointed":"Em Ângulo","paint.modeTools.thickness":"Espessura","paint.modeTools.flipHorizontal":"Inverter Horizontalmente","paint.modeTools.flipVertical":"Inverter Verticalmente","paint.modeTools.filled":"A cheio","paint.modeTools.outlined":"Com contorno","paint.paintEditor.bitmap":"Converter para Bitmap","paint.paintEditor.vector":"Converter para Vectorial","paint.paintEditor.fill":"Interior","paint.paintEditor.stroke":"Contorno","paint.brushMode.brush":"Pincel","paint.eraserMode.eraser":"Borracha","paint.fillMode.fill":"Preencher","paint.lineMode.line":"Linha","paint.ovalMode.oval":"Círculo","paint.rectMode.rect":"Rectângulo","paint.reshapeMode.reshape":"Remodelar","paint.roundedRectMode.roundedRect":"Rectângulo Arredondado","paint.selectMode.select":"Seleccionar","paint.textMode.text":"Texto","paint.colorPicker.swap":"Trocar","tw.alerts.autosaving":"Criando ponto de restauração...","tw.alerts.savedToDisk":"Salvo no seu computador.","tw.backpack.rename":"Novo nome:","tw.browserModal.desc":"Veja se você está usando uma versão recente do Google Chrome, Mozilla Firefox, Microsoft Edge ou Apple Safari.","tw.changeUsername.cannotChangeWhileRunning":"O nome de usuário não pode ser alterado enquanto o projeto está em execução.","tw.cloudVariableBadge":"Esse projeto usa variáveis na nuvem. O TurboWarp usa seu próprio servidor de variáveis na nuvem independente e separado do Scratch. Cuidado com imitadores, já que qualquer um pode mudar o nome de usuário para qualquer coisa. {learnMore}","tw.code":"Código-fonte","tw.confirmIncompatibleExtension":"Essa extensão não é compatível com o Scratch. Projetos feitos com ela não funcionarão se você fizer upload no site do Scratch. Tem certeza que quer ativá-la?","tw.customExtension.description":"Carregar extensões customizadas por URLs. Para desenvolvedores. Experimental.","tw.customExtension.name":"Extensão Customizada","tw.featuredProjectsStudio":"Ver estúdio no Scratch.","tw.feedback":"Feedback e bugs","tw.feedbackButton":"Feedback do TurboWarp","tw.footer.credits":"Créditos","tw.footer.disclaimer":"O TurboWarp não tem afiliação com o Scratch, a Equipe do Scratch ou a Fundação Scratch.","tw.footer.embed":"Incorporação","tw.footer.fosshost":"Hospedagem por Fosshost","tw.footer.parameters":"Parâmetros de URL","tw.footer.translate":"Ajude a traduzir o TurboWarp","tw.gui.defaultProjectTitle":"Projeto","tw.guiDefaultTitle":"Rode projetos do Scratch mais rapidamente","tw.home.credit":"Notas e Créditos","tw.home.description":"TurboWarp é um mod do Scratch que compila projetos para JavaScript para os executar mais rapidamente. Experimente colocando um ID ou URL de projeto acima ou escolhendo um dos projetos em destaque abaixo.","tw.home.instructions":"Instruções","tw.input.tooltip":"Copie e cole um link de um projeto no Scratch aqui!","tw.interpolationEnabled":"Interpolação","tw.invalidParameters.clones":"parâmetro de URL \\"clone\\" é inválido","tw.invalidParameters.fps":"parâmetro de URL \\"fps\\" é inválido","tw.loader.assets.known":"Baixando recursos ({complete}/{total}) ...","tw.loader.assets.unknown":"Baixando recursos ...","tw.loader.data":"Baixando dados do projeto ...","tw.loader.generic":"Carregando projeto …","tw.menuBar.60off":"Desativar modo 60 FPS","tw.menuBar.60on":"Ativar modo 60 FPS","tw.menuBar.advanced":"Avançado","tw.menuBar.changeUsername":"Mudar nome de usuário","tw.menuBar.cloudOff":"Desativar variáveis na nuvem","tw.menuBar.cloudOn":"Ativar variáveis na nuvem","tw.menuBar.cloudUnavailable":"Variáveis na nuvem não estão disponíveis","tw.menuBar.cloudUnavailableAlert":"Não pôde usar variáveis na nuvem, provavelmente porque você abriu o editor.","tw.menuBar.loadRestorePoint":"Carregar ponto de restauração","tw.menuBar.moreSettings":"Configurações Avançadas","tw.menuBar.newFramerate":"Novo FPS:","tw.menuBar.reportError1":"Alguns scripts não puderam ser compilados.","tw.menuBar.reportError2":"Isso é um bug. Por favor, reporte-o.","tw.menuBar.saveAs":"Salvar como {file}","tw.menuBar.seeInside":"Ver interior","tw.oldDownload":"Salvar como arquivo separado...","tw.paint.alpha":"Opacidade","tw.privacy":"Política de Privacidade","tw.saveAs":"Salvar como...","tw.saveTo":"Salvar como {file}","tw.settingsModal.customStageSize":"Tamanho Customizado do Palco:","tw.settingsModal.customStageSizeHelp":"Muda o tamanho do palco do Scratch de 480x360 para outro valor. Tente 640x360 para deixar o palco em widescreen. Quase nenhum projeto irá funcionar direito com essa opção.","tw.settingsModal.dangerZone":"Zona de Perigo","tw.settingsModal.disableCompiler":"Desativar Compilador","tw.settingsModal.disableCompilerHelp":"Desativa o compilador do TurboWarp. Você pode ativar isso enquanto estiver editando projetos para fazer os scripts serem atualizados imediatamente. Em qualquer outra hipótese, deixe esta opção desativada.","tw.settingsModal.featured":"Em destaque","tw.settingsModal.fps":"60 FPS (FPS customizado)","tw.settingsModal.fpsHelp":"Roda scripts 60 vezes por segundo ao invés de 30. A maioria dos projetos não vão funcionar adequadamente com isso ativado. Se esse for o caso, você pode tentar usar Interpolação e desligar o modo 60 FPS. {customFramerate}.","tw.settingsModal.fpsHelp.customFramerate":"Clique para escolher FPS além de 30 ou 60","tw.settingsModal.help":"Ajuda","tw.settingsModal.highQualityPen":"Caneta de Alta Qualidade","tw.settingsModal.highQualityPenHelp":"Permite que projetos renderizem a caneta em uma qualidade melhor e reduz arredondamento de coordenadas no editor. Nem todo projeto se beneficia dessa opção, e ela pode piorar a performance.","tw.settingsModal.infiniteClones":"Clones Infinitos","tw.settingsModal.infiniteClonesHelp":"Desativa o limite de 300 clones do Scratch.","tw.settingsModal.interpolation":"Interpolação","tw.settingsModal.interpolationHelp":"Faz projetos parecerem rodar em framerates mais altas interpolando o movimento de atores. Interpolação não deve ser usada em projetos 3D, raytracers, projetos que usam caneta e projetos lagados porque a interpolação só vai fazer eles rodarem mais devagar sem deixá-los mais suaves.","tw.settingsModal.largeStageWarning":"Não é recomendado usar um tamanho de palco tão grande! Ao invés disso, use um tamanho menor com a mesma proporção e o modo tela cheia irá aumentar o palco para preencher a tela do usuário.","tw.settingsModal.removeFencing":"Remover Borda","tw.settingsModal.removeFencingHelp":"Deixa atores andarem para fora da tela, ficarem grandes ou pequenos sem limitação de tamanho e permite que os blocos \\"tocando\\" funcionem fora dos limites do palco.","tw.settingsModal.removeLimits":"Remover Limites","tw.settingsModal.removeMiscLimits":"Remover Outros Limites","tw.settingsModal.removeMiscLimitsHelp":"Remove os limites de efeitos de som e tamanho da caneta.","tw.settingsModal.storeProjectOptions":"Salvar configurações no projeto","tw.settingsModal.storeProjectOptionsHelp":"Salva suas configurações no projeto e automaticamente os aplica quando você abrir o projeto no TurboWarp. \\"Warp timer\\" e \\"desativar compilador\\" não serão salvos.","tw.settingsModal.title":"Configurações Avançadas","tw.settingsModal.warpTimerHelp":"Faz scripts detectarem se estão presos em um loop longo ou infinito e roda a uma framerate baixa ao invés de travar até o loop terminar. Isso conserta a maioria dos crashes mas prejudica muito a performance, então não está ativado por padrão fora do editor.","tw.spriteSelectorItem.rename":"renomear","tw.studioview.authorAttribution":"por {author}","tw.studioview.error":"Erro ao carregar a próxima página de projetos.","tw.studioview.hoverText":"{title} por {author}","tw.twExtension.description":"Uns blocos novos esquisitos. Não compatíveis com o Scratch.","tw.twExtension.name":"Blocos do TurboWarp","tw.usernameModal.help":"Esse valor será guardado no armazenamento do seu navegador. Projetos que contenham variáveis na nuvem podem querer registrá-lo.","tw.usernameModal.help2":"Valores que não correspondem a uma conta válida no Scratch normalmente serão rejeitados pelo servidor de variáveis na nuvem. Recomendamos que você deixe este valor como está ou mude-o para o seu nome de usuário do Scratch.","tw.usernameModal.mustChange":"Desculpe, o servidor de variáveis na nuvem acha que o seu nome de usuário pode ser inapropriado. Por favor, mude para outra coisa ou {resetIt}.","tw.usernameModal.mustChange.resetIt":"resete-o (recomendado)","tw.usernameModal.reset":"Redefinir","tw.usernameModal.title":"Mudar nome de usuário","tw.viewFeaturedProjects":"Clique para ver projetos em destaque.","tw.viewOnScratch":"Ver projeto no Scratch","tw.webglModal.description":"Infelizmente parece que o seu navegador ou computador {webGlLink}. Essa tecnologia é necessária para o site funcionar. Tente atualizar o seu navegador e drivers gráficos ou reiniciar o seu computador."},"pt-br":{"gui.alerts.tryAgain":"Tente Novamente","gui.alerts.download":"Baixar","gui.connection.reconnect":"Reconectar","gui.backpack.costumeLabel":"fantasia","gui.backpack.soundLabel":"som","gui.backpack.scriptLabel":"código","gui.backpack.spriteLabel":"ator","gui.backpack.header":"Mochila","gui.backpack.errorBackpack":"Erro ao carregar a mochila","gui.backpack.loadingBackpack":"Carregando...","gui.backpack.more":"Mais","gui.backpack.emptyBackpack":"A mochila está vazia","gui.unsupportedBrowser.label":"O navegador não é suportado","gui.cards.all-tutorials":"Tutoriais","gui.cards.shrink":"Reduzir","gui.cards.expand":"Expandir","gui.cards.close":"Fechar","gui.cards.more-things-to-try":"Mais coisas para experimentar!","gui.cards.see-more":"Veja mais","gui.comingSoon.message1":"Não se preocupe, estamos trabalhando nisso {emoji}","gui.comingSoon.message2":"Em Breve...","gui.comingSoon.message3":"Estamos trabalhando nisso {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Nenhum dispositivo encontrado","gui.connection.auto-scanning.prescan":"Tenha seu dispositivo em mãos e então comece a busca.","gui.connection.auto-scanning.pressbutton":"Pressione o botão no seu dispositivo.","gui.connection.auto-scanning.start-search":"Inicie a Busca","gui.connection.connecting-searchbutton":"Procurando...","gui.connection.auto-scanning.try-again":"Tente novamente","gui.connection.connected":"Conectado","gui.connection.disconnect":"Desconectar","gui.connection.go-to-editor":"Ir para o Editor","gui.connection.connecting-cancelbutton":"Conectando...","gui.connection.error.errorMessage":"Ooops! Parece que deu algo errado. ","gui.connection.error.tryagainbutton":"Tente novamente","gui.connection.error.helpbutton":"Ajuda","gui.connection.peripheral-name-label":"Nome do dispositivo","gui.connection.connect":"Conectar","gui.connection.scanning.lookingforperipherals":"Procurando por dispositivos","gui.connection.scanning.noPeripheralsFound":"Nenhum dispositivo encontrado","gui.connection.scanning.instructions":"Selecione seu dispositivo na lista acima.","gui.connection.search":"Atualizar","gui.connection.unavailable.installscratchlink":"Confirme que o Scratch Link está instalado e funcionando ","gui.connection.unavailable.enablebluetooth":"Verifique se o Bluetooth está ligado","gui.connection.unavailable.tryagainbutton":"Tente novamente","gui.connection.unavailable.helpbutton":"Ajuda","gui.controls.go":"Ir","gui.controls.stop":"Pare","gui.crashMessage.label":"Ooops! Algo deu errado.","gui.crashMessage.errorNumber":"Seu erro foi registrado com o ID {errorId}","gui.crashMessage.reload":"Recarregue","gui.customProcedures.myblockModalTitle":"Criar um Bloco","gui.customProcedures.addAnInputNumberText":"Adicionar uma entrada","gui.customProcedures.numberTextType":"numérica ou texto","gui.customProcedures.addAnInputBoolean":"Adicionar uma entrada","gui.customProcedures.booleanType":"booleana","gui.customProcedures.addALabel":"Adicionar um rótulo","gui.customProcedures.runWithoutScreenRefresh":"Executar sem atualização de tela","gui.customProcedures.cancel":"Cancelar","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Direção","gui.directionPicker.rotationStyles.allAround":"Rotação Completa","gui.directionPicker.rotationStyles.leftRight":"Esquerda/Direita","gui.directionPicker.rotationStyles.dontRotate":"Não gire","gui.gui.addExtension":"Adicionar uma Extensão","gui.gui.codeTab":"Código","gui.gui.backdropsTab":"Cenários","gui.gui.costumesTab":"Fantasias","gui.gui.soundsTab":"Sons","gui.extensionLibrary.comingSoon":"Em Breve ","gui.extensionLibrary.requires":"Requer","gui.extensionLibrary.collaboration":"Em colaboração com","gui.library.filterPlaceholder":"Buscar","gui.library.allTag":"Tudo","gui.loader.headline":"Carregando Projeto","gui.loader.creating":"Criando Projeto","gui.authorInfo.byUser":"por {username}","gui.menuBar.seeProjectPage":"Veja a Página do Projeto","gui.menuBar.LanguageSelector":"Seletor de idioma","gui.menuBar.tutorialsLibrary":"Tutoriais","gui.menuBar.restoreSprite":"Restaurar Ator","gui.menuBar.restoreSound":"Restaurar Som","gui.menuBar.restoreCostume":"Restaurar a Fantasia","gui.menuBar.restore":"Restaurar","gui.menuBar.saveNow":"Salvar agora","gui.menuBar.saveAsCopy":"Salvar como cópia","gui.menuBar.remix":"Remix","gui.menuBar.new":"Novo","gui.menuBar.file":"Arquivo","gui.menuBar.downloadToComputer":"Baixar para o seu computador","gui.menuBar.edit":"Editar","gui.menuBar.turboModeOff":"Desligar o Modo Turbo","gui.menuBar.turboModeOn":"Ligar Modo Turbo","gui.gui.projectTitlePlaceholder":"Título do projeto","gui.menuBar.isShared":"Compartilhado","gui.menuBar.share":"Compartilhar","gui.modal.help":"Ajuda","gui.modal.back":"Voltar","gui.monitor.listMonitor.empty":"(vazio)","gui.monitor.listMonitor.listLength":"Comprimento {length}","gui.monitor.contextMenu.default":"letras tamanho normal","gui.monitor.contextMenu.large":"letras grandes","gui.monitor.contextMenu.slider":"controle deslizante","gui.monitor.contextMenu.sliderRange":"mudar o intervalo","gui.monitor.contextMenu.import":"importar","gui.monitor.contextMenu.export":"exportar","gui.monitor.contextMenu.hide":"esconder","gui.playButton.play":"Tocar","gui.playButton.stop":"Pare","gui.gui.variableScopeOptionAllSprites":"Para todos os atores","gui.gui.variableScopeOptionSpriteOnly":"Apenas para este ator","gui.gui.cloudVariableOption":"Variável na nuvem (armazenada no servidor)","gui.gui.variablePromptAllSpritesMessage":"Esta variável ficará disponível para todos os atores.","gui.gui.listPromptAllSpritesMessage":"Esta lista estará disponível para todos os atores.","gui.prompt.cancel":"Cancelar","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Parar","gui.playbackStep.playMsg":"Tocar","gui.playbackStep.loadingMsg":"Carregando...","gui.playbackStep.saveMsg":"Salvar","gui.playbackStep.reRecordMsg":"Regravar","gui.recordModal.title":"Gravar Som","gui.recordingStep.beginRecord":"Comece a gravação clicando no botão abaixo","gui.recordingStep.permission":"{arrow}Precisamos da sua permissão para usar seu microfone","gui.recordingStep.stop":"Parar gravação","gui.recordingStep.record":"Gravar","gui.sliderModal.min":"Valor mínimo","gui.sliderModal.max":"Valor máximo","gui.sliderModal.title":"Mudar o intervalo","gui.sliderPrompt.cancel":"Cancelar","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Som","gui.soundEditor.play":"Jogar","gui.soundEditor.stop":"Parar","gui.soundEditor.copy":"Copiar","gui.soundEditor.paste":"Colar","gui.soundEditor.copyToNew":"Copiar como novo","gui.soundEditor.delete":"Apagar","gui.soundEditor.save":"Salvar","gui.soundEditor.undo":"Desfazer","gui.soundEditor.redo":"Refazer","gui.soundEditor.faster":"Mais Rápido","gui.soundEditor.slower":"Mais Devagar","gui.soundEditor.echo":"Eco","gui.soundEditor.robot":"Robô","gui.soundEditor.louder":"Mais Alto","gui.soundEditor.softer":"Mais Baixo","gui.soundEditor.reverse":"Inverter","gui.soundEditor.fadeOut":"Desaparecer","gui.soundEditor.fadeIn":"Aparecer","gui.soundEditor.mute":"Silenciar","gui.SpriteInfo.spritePlaceholder":"Nome","gui.SpriteInfo.sprite":"Ator","gui.SpriteInfo.show":"Mostrar","gui.SpriteInfo.size":"Tamanho","gui.spriteSelectorItem.contextMenuDuplicate":"duplicar","gui.spriteSelectorItem.contextMenuExport":"exportar","gui.spriteSelectorItem.contextMenuDelete":"apagar","gui.spriteSelector.addSpriteFromLibrary":"Selecione um Ator","gui.spriteSelector.addSpriteFromPaint":"Pintar","gui.spriteSelector.addSpriteFromSurprise":"Surpresa","gui.spriteSelector.addSpriteFromFile":"Enviar Ator","gui.stageHeader.stageSizeLarge":"Mudar para um palco maior","gui.stageHeader.stageSizeSmall":"Mude para um palco pequeno","gui.stageHeader.stageSizeFull":"Entrar no modo de tela cheia","gui.stageHeader.stageSizeUnFull":"Sair do modo de tela cheia","gui.stageHeader.fullscreenControl":"Controle de Tela Cheia","gui.spriteSelector.addBackdropFromLibrary":"Selecionar Cenário","gui.stageSelector.addBackdropFromPaint":"Pintar","gui.stageSelector.addBackdropFromSurprise":"Surpresa","gui.stageSelector.addBackdropFromFile":"Carregar Cenário","gui.stageSelector.stage":"Palco","gui.stageSelector.backdrops":"Cenários","gui.telemetryOptIn.label":"Reporte estatísticas para melhorar o Scratch","gui.telemetryOptIn.body1":"A equipe do Scratch está sempre buscando entender melhor como o Scratch é usado ao redor do mundo. Para ajudá-la nesse sentido, você pode permitir que o Scratch envie, automaticamente, informações de seu uso para a equipe do Scratch.","gui.telemetryOptIn.body2":"A informação que coletamos inclui seleção de idioma, blocos utilizados, e alguns eventos como salvar, carregar e fazer o upload de um projeto. Nós NÃO coletamos nenhuma informação pessoal. Por favor, veja nossa {privacyPolicyLink} para mais informação.","gui.telemetryOptIn.privacyPolicyLink":"Política de Privacidade","gui.telemetryOptIn.optInText":"Compartilhar meus dados de utilização com a Equipe Scratch","gui.telemetryOptIn.optInTooltip":"Ativar telemetria","gui.telemetryOptIn.optOutText":"Não compartilhar meus dados de utilização com a Equipe Scratch","gui.telemetryOptIn.optOutTooltip":"Desativar telemetria. ","gui.telemetryOptIn.settingWasUpdated":"Sua configuração foi atualizada.","gui.telemetryOptIn.buttonClose":"Fechar","gui.turboMode.active":"Modo Turbo","gui.webglModal.label":"Seu navegador não suporta WebGL","gui.webglModal.webgllink":"não suporta WebGL","gui.costumeLibrary.chooseABackdrop":"Selecionar Cenário","gui.costumeLibrary.chooseACostume":"Escolher Fantasia","gui.costumeTab.addBackdropFromLibrary":"Selecionar Cenário","gui.costumeTab.addCostumeFromLibrary":"Escolher Fantasia","gui.costumeTab.addBlankCostume":"Pintar","gui.costumeTab.addSurpriseCostume":"Surpresa","gui.costumeTab.addFileBackdrop":"Carregar Cenário","gui.costumeTab.addFileCostume":"Carregar Fantasia","gui.extensionLibrary.chooseAnExtension":"Escolha uma Extensão","gui.extensionLibrary.extensionUrl":"Insira o URL para a extensão","gui.monitors.importListColumnPrompt":"Qual coluna deveria ser utilizada (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Não conseguiu iniciar a gravação","gui.soundLibrary.chooseASound":"Selecione um Som","gui.soundTab.fileUploadSound":"Carregar Som","gui.soundTab.surpriseSound":"Surpresa","gui.soundTab.recordSound":"Gravar","gui.soundTab.addSoundFromLibrary":"Selecionar um Som","gui.spriteLibrary.chooseASprite":"Selecione um Ator","gui.tipsLibrary.tutorials":"Escolher um tutorial","gui.alerts.createsuccess":"Novo projeto criado.","gui.alerts.createcopysuccess":"Projeto salvo como cópia.","gui.alerts.createremixsuccess":"Projeto salvo como remix.","gui.alerts.creating":"Criando novo...","gui.alerts.creatingCopy":"Copiando projeto...","gui.alerts.creatingRemix":"Remixando projeto...","gui.alerts.creatingError":"Não foi possível criar o projeto. Por favor, tente novamente!","gui.alerts.savingError":"Projeto não pode ser salvo.","gui.alerts.savesuccess":"Projeto salvo.","gui.alerts.saving":"Salvando projeto...","gui.alerts.cloudInfo":"Por favor, note que as variáveis em nuvem suportam apenas números, não letras ou símbolos. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Aprenda mais. ","gui.alerts.importing":"Importando...","gui.defaultProject.variable":"minha variável","gui.extension.music.name":"Música","gui.extension.music.description":"Toque instrumentos e tambores.","gui.extension.pen.name":"Caneta","gui.extension.pen.description":"Desenhe com os seus atores.","gui.extension.videosensing.name":"Detecção de Vídeo","gui.extension.videosensing.description":"Detecte movimento com a câmera.","gui.extension.text2speech.name":"Texto para Fala","gui.extension.text2speech.description":"Faça seus projetos falarem","gui.extension.translate.name":"Traduzir","gui.extension.translate.description":"Traduza texto para várias línguas.","gui.extension.makeymakey.description":"Transforme tudo em uma tecla.","gui.extension.microbit.description":"Conecte seus projetos ao mundo.","gui.extension.microbit.connectingMessage":"Conectando","gui.extension.ev3.description":"Construa robôs e outras coisas interativas.","gui.extension.ev3.connectingMessage":"Conectando. Garanta que o pin no seu EV3 esteja configurado para 1234.","gui.extension.boost.description":"Traga criações robóticas para a vida","gui.extension.boost.connectingMessage":"Conectando","gui.extension.wedo2.description":"Crie com motores e sensores.","gui.extension.wedo2.connectingMessage":"Conectando","gui.extension.gdxfor.description":"Detecte se empurrar, puxar, movimentos e giros.","gui.extension.gdxfor.connectingMessage":"Conectando","gui.libraryTags.all":"Tudo","gui.libraryTags.animals":"Animais","gui.libraryTags.dance":"Dança","gui.libraryTags.effects":"Efeitos","gui.libraryTags.fantasy":"Imaginários","gui.libraryTags.fashion":"Moda","gui.libraryTags.food":"Comida","gui.libraryTags.indoors":"Interior","gui.libraryTags.loops":"Loops","gui.libraryTags.music":"Música","gui.libraryTags.notes":"Notas","gui.libraryTags.outdoors":"Exterior","gui.libraryTags.patterns":"Padrões","gui.libraryTags.people":"Pessoas","gui.libraryTags.percussion":"Percussão","gui.libraryTags.space":"Espaço","gui.libraryTags.sports":"Esportes","gui.libraryTags.underwater":"Embaixo d\'água","gui.libraryTags.voice":"Voz","gui.libraryTags.wacky":"Maluco","gui.libraryTags.animation":"Animações","gui.libraryTags.art":"Arte","gui.libraryTags.games":"Jogos","gui.libraryTags.stories":"Histórias","gui.libraryTags.letters":"Letras","gui.opcodeLabels.direction":"direção","gui.opcodeLabels.xposition":"posição x","gui.opcodeLabels.yposition":"posição y","gui.opcodeLabels.size":"tamanho","gui.opcodeLabels.costumename":"nome da fantasia","gui.opcodeLabels.costumenumber":"fantasia número","gui.opcodeLabels.backdropname":"nome do cenário","gui.opcodeLabels.backdropnumber":"cenário número","gui.opcodeLabels.volume":"volume","gui.opcodeLabels.tempo":"ritmo","gui.opcodeLabels.answer":"resposta","gui.opcodeLabels.loudness":"nível de ruído","gui.opcodeLabels.username":"nome de usuário","gui.opcodeLabels.year":"ano","gui.opcodeLabels.month":"mês","gui.opcodeLabels.date":"data","gui.opcodeLabels.dayofweek":"dia da semana","gui.opcodeLabels.hour":"hora","gui.opcodeLabels.minute":"minuto","gui.opcodeLabels.second":"segundo","gui.opcodeLabels.timer":"cronômetro","gui.sharedMessages.backdrop":"cenário{index}","gui.sharedMessages.costume":"fantasia{index}","gui.sharedMessages.sprite":"Ator{index}","gui.sharedMessages.pop":"saltar","gui.sharedMessages.replaceProjectWarning":"Substituir conteúdos do projeto atual?","gui.sharedMessages.loadFromComputerTitle":"Carregar do seu computador","boost.color.any":"qualquer cor","boost.color.black":"preto","boost.color.blue":"azul","boost.color.green":"verde","boost.color.red":"vermelho","boost.color.white":"branco","boost.color.yellow":"amarelo","boost.getMotorPosition":"posição do motor [MOTOR_REPORTER_ID]","boost.getTiltAngle":"ângulo de inclinação [TILT_DIRECTION]","boost.motorDirection.backward":"por aí","boost.motorDirection.forward":"por aqui","boost.motorDirection.reverse":"inverter","boost.motorOff":"desligue o motor [MOTOR_ID]","boost.motorOn":"ligue o motor [MOTOR_ID]","boost.motorOnFor":"ligue o motor [MOTOR_ID] por [DURATION] segundos","boost.motorOnForRotation":"ligue o motor [MOTOR_ID] por [ROTATION] rotações","boost.seeingColor":"vendo bloco [COLOR]?","boost.setLightHue":"defina a cor como [HUE]","boost.setMotorDirection":"mude a direção do motor [MOTOR_ID] para [MOTOR_DIRECTION]","boost.setMotorPower":"mude a velocidade do motor [MOTOR_ID] para [POWER] %","boost.tiltDirection.any":"qualquer","boost.tiltDirection.down":"baixo","boost.tiltDirection.left":"esquerda","boost.tiltDirection.right":"direita","boost.tiltDirection.up":"para cima","boost.whenColor":"quando um bloco [COLOR] for visto","boost.whenTilted":"quando inclinado para [TILT_DIRECTION_ANY]","ev3.beepNote":"som de bip [NOTE] por [TIME] segundos","ev3.buttonPressed":"botão [PORT] pressionado?","ev3.getBrightness":"brilho","ev3.getDistance":"distância","ev3.getMotorPosition":"posição do motor [PORT]","ev3.motorSetPower":"defina potência do motor [PORT] em [POWER] %","ev3.motorTurnClockwise":"gire o motor [PORT] nesse sentido por [TIME] segundos","ev3.motorTurnCounterClockwise":"gire o motor [PORT] naquele sentido por [TIME] segundos","ev3.whenBrightnessLessThan":"quando brilho < [DISTANCE]","ev3.whenButtonPressed":"quando botão [PORT] for pressionado","ev3.whenDistanceLessThan":"quando distância < [DISTANCE]","gdxfor.getAcceleration":"aceleração [DIRECTION]","gdxfor.getForce":"força","gdxfor.getSpin":"velocidade de rotação [DIRECTION]","gdxfor.getTilt":"ângulo de inclinação para [TILT]","gdxfor.isFreeFalling":"caindo?","gdxfor.isTilted":"inclinado para [TILT]?","gdxfor.pulled":"puxado","gdxfor.pushed":"empurrado","gdxfor.shaken":"agitado","gdxfor.startedFalling":"começar a cair","gdxfor.tiltDirectionMenu.any":"qualquer","gdxfor.tiltDirectionMenu.back":"trás","gdxfor.tiltDirectionMenu.front":"frente","gdxfor.tiltDirectionMenu.left":"esquerda","gdxfor.tiltDirectionMenu.right":"direita","gdxfor.turnedFaceDown":"virado para baixo","gdxfor.turnedFaceUp":"virado para cima","gdxfor.whenForcePushedOrPulled":"quando o sensor de força estiver sendo [PUSH_PULL]","gdxfor.whenGesture":"quando [GESTURE]","gdxfor.whenTilted":"quando inclinado para [TILT]","makeymakey.downArrow":"seta para baixo","makeymakey.downArrowShort":"baixo","makeymakey.leftArrow":"seta para esquerda","makeymakey.leftArrowShort":"esquerda","makeymakey.rightArrow":"seta para direita","makeymakey.rightArrowShort":"direita","makeymakey.spaceKey":"espaço","makeymakey.upArrow":"seta para cima","makeymakey.upArrowShort":"para cima","makeymakey.whenKeyPressed":"quando a tecla [KEY] for pressionada","makeymakey.whenKeysPressedInOrder":"quando [SEQUENCE] forem pressionados em ordem","microbit.buttonsMenu.any":"qualquer","microbit.clearDisplay":"limpe a tela","microbit.defaultTextToDisplay":"Olá!","microbit.displaySymbol":"exiba [MATRIX]","microbit.displayText":"exiba o texto [TEXT]","microbit.gesturesMenu.jumped":"pular","microbit.gesturesMenu.moved":"mover","microbit.gesturesMenu.shaken":"agitar","microbit.isButtonPressed":"botão [BTN] pressionado?","microbit.isTilted":"inclinado para [DIRECTION]?","microbit.pinStateMenu.off":"desligado","microbit.pinStateMenu.on":"ligado","microbit.tiltAngle":"ângulo de inclinação para [DIRECTION]","microbit.tiltDirectionMenu.any":"qualquer","microbit.tiltDirectionMenu.back":"trás","microbit.tiltDirectionMenu.front":"frente","microbit.tiltDirectionMenu.left":"esquerda","microbit.tiltDirectionMenu.right":"direita","microbit.whenButtonPressed":"quando o botão [BTN] for pressionado","microbit.whenGesture":"quando [GESTURE]","microbit.whenPinConnected":"quando o pino [PIN] for conectado","microbit.whenTilted":"quando inclinado para [DIRECTION]","music.categoryName":"Música","music.changeTempo":"alterar ritmo por [TEMPO]","music.drumBass":"(2) Bumbo","music.drumBongo":"(13) Bongô","music.drumCabasa":"(15) Afoxé","music.drumClaves":"(9) Claves Cubanas","music.drumClosedHiHat":"(6) Prato Chimbau","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Chocalho","music.drumCrashCymbal":"(4) Prato","music.drumCuica":"(18) Cuíca","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Palmas","music.drumOpenHiHat":"(5) Prato Hi-Hat","music.drumSideStick":"(3) Bastão Lateral","music.drumSnare":"(1) Tarol","music.drumTambourine":"(7) Pandeiro","music.drumTriangle":"(12) Triângulo","music.drumVibraslap":"(17) Queixada","music.drumWoodBlock":"(10) Bloco Sonoro","music.getTempo":"ritmo","music.instrumentBass":"(6) Baixo","music.instrumentBassoon":"(14) Fagote","music.instrumentCello":"(8) Violoncelo","music.instrumentChoir":"(15) Coral","music.instrumentClarinet":"(10) Clarinete","music.instrumentElectricGuitar":"(5) Guitarra Elétrica","music.instrumentElectricPiano":"(2) Teclado","music.instrumentFlute":"(12) Flauta","music.instrumentGuitar":"(4) Violão","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Caixa de Música","music.instrumentOrgan":"(3) Órgão","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxofone","music.instrumentSteelDrum":"(18) Tambor de Aço","music.instrumentSynthLead":"(20) Sintetizador principal","music.instrumentSynthPad":"(21) Bloco Sintetizador","music.instrumentTrombone":"(9) Trombone","music.instrumentVibraphone":"(16) Vibrafone","music.instrumentWoodenFlute":"(13) Flauta de madeira","music.midiPlayDrumForBeats":"toque instrumento [DRUM] por [BEATS] batidas","music.midiSetInstrument":"mudar instrumento para [INSTRUMENT]","music.playDrumForBeats":"toque instrumento [DRUM] por [BEATS] batidas","music.playNoteForBeats":"toque a nota [NOTE] por [BEATS] batidas","music.restForBeats":"pausa por [BEATS] batidas","music.setInstrument":"mudar instrumento para [INSTRUMENT]","music.setTempo":"ajuste ritmo para [TEMPO]","pen.categoryName":"Caneta","pen.changeColorParam":"adicione [VALUE] [COLOR_PARAM] da caneta","pen.changeHue":"adicione [HUE] a cor da caneta ","pen.changeShade":"adicione [SHADE] a tonalidade da caneta ","pen.changeSize":"adicione [SIZE] ao tamanho da caneta","pen.clear":"apague tudo","pen.colorMenu.brightness":"ao brilho","pen.colorMenu.color":"a cor","pen.colorMenu.saturation":"a saturação","pen.colorMenu.transparency":"a transparência","pen.penDown":"use a caneta","pen.penUp":"levante a caneta","pen.setColor":"mude a cor da caneta para [COLOR]","pen.setColorParam":"mude [COLOR_PARAM] da caneta para [VALUE]","pen.setHue":"mude a cor da caneta para [HUE]","pen.setShade":"mude a tonalidade da caneta para [SHADE]","pen.setSize":"mude o tamanho da caneta para [SIZE]","pen.stamp":"carimbe","text2speech.alto":"loud","text2speech.categoryName":"Texto para Fala","text2speech.defaultTextToSpeak":"olá","text2speech.giant":"gigante","text2speech.kitten":"gatinho","text2speech.setLanguageBlock":"defina o idioma como [LANGUAGE]","text2speech.setVoiceBlock":"defina a voz para [VOICE]","text2speech.speakAndWaitBlock":"falar [WORDS]","text2speech.squeak":"rangido","text2speech.tenor":"tenor","translate.categoryName":"Traduzir","translate.defaultTextToTranslate":"olá","translate.translateBlock":"traduza [WORDS] para [LANGUAGE]","translate.viewerLanguage":"idioma","videoSensing.categoryName":"Detecção de Vídeo","videoSensing.direction":"direção","videoSensing.motion":"movimento","videoSensing.off":"desligado","videoSensing.on":"ligado","videoSensing.onFlipped":"ligado invertido","videoSensing.setVideoTransparency":"ajuste transparência do vídeo para [TRANSPARENCY]","videoSensing.sprite":"ator","videoSensing.stage":"palco","videoSensing.videoOn":"vídeo [ATTRIBUTE] para [SUBJECT]","videoSensing.videoToggle":"mude vídeo para [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"quando detectar sensor de vídeo > [REFERENCE]","wedo2.getDistance":"distância","wedo2.getTiltAngle":"ângulo de inclinação [TILT_DIRECTION]","wedo2.isTilted":"inclinado para [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"por aí","wedo2.motorDirection.forward":"por aqui","wedo2.motorDirection.reverse":"inverter","wedo2.motorId.a":"motor A","wedo2.motorId.all":"todos os motores","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"desligue o motor [MOTOR_ID]","wedo2.motorOn":"ligue o motor [MOTOR_ID]","wedo2.motorOnFor":"ligue o motor [MOTOR_ID] por [DURATION] segundos","wedo2.playNoteFor":"toque a nota [NOTE] por [DURATION] segundos","wedo2.setLightHue":"defina a cor como [HUE]","wedo2.setMotorDirection":"defina a direção de [MOTOR_ID] como [MOTOR_DIRECTION]","wedo2.startMotorPower":"defina a potência de [MOTOR_ID] como [POWER]","wedo2.tiltDirection.any":"qualquer","wedo2.tiltDirection.down":"baixo","wedo2.tiltDirection.left":"esquerda","wedo2.tiltDirection.right":"direita","wedo2.tiltDirection.up":"para cima","wedo2.whenDistance":"quando distância [OP] [REFERENCE]","wedo2.whenTilted":"quando inclinado para [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Cor","paint.paintEditor.saturation":"Saturação","paint.paintEditor.brightness":"Brilho","paint.paintEditor.costume":"Fantasia","paint.paintEditor.group":"Agrupar","paint.paintEditor.ungroup":"Desagrupar","paint.paintEditor.undo":"Desfazer","paint.paintEditor.redo":"Refazer","paint.paintEditor.forward":"Pra frente","paint.paintEditor.backward":"Pra Trás","paint.paintEditor.front":"Frente","paint.paintEditor.back":"Atrás","paint.paintEditor.more":"Mais","paint.modeTools.brushSize":"Tamanho","paint.modeTools.eraserSize":"Tamanho da borracha","paint.modeTools.copy":"Copiar","paint.modeTools.paste":"Colar","paint.modeTools.delete":"Apagar","paint.modeTools.curved":"Curvado","paint.modeTools.pointed":"Apontado","paint.modeTools.thickness":"Espessura","paint.modeTools.flipHorizontal":"Espelhar Horizontalmente","paint.modeTools.flipVertical":"Espelhar Verticalmente","paint.modeTools.filled":"Preenchido","paint.modeTools.outlined":"Contornar","paint.paintEditor.bitmap":"Converter para Bitmap","paint.paintEditor.vector":"Converter pra Vetor","paint.paintEditor.fill":"Preencher","paint.paintEditor.stroke":"Contornar","paint.brushMode.brush":"Pincel","paint.eraserMode.eraser":"Apagador","paint.fillMode.fill":"Preencher","paint.lineMode.line":"Linha","paint.ovalMode.oval":"Círculo","paint.rectMode.rect":"Retângulo","paint.reshapeMode.reshape":"Remodelar","paint.roundedRectMode.roundedRect":"Retângulo Arredondado","paint.selectMode.select":"Selecionar","paint.textMode.text":"Texto","paint.colorPicker.swap":"Troque","tw.alerts.autosaving":"Criando ponto de restauração...","tw.alerts.savedToDisk":"Salvo no seu computador.","tw.backpack.rename":"Novo nome:","tw.browserModal.desc":"Veja se você está usando uma versão recente do Google Chrome, Mozilla Firefox, Microsoft Edge ou Apple Safari.","tw.changeUsername.cannotChangeWhileRunning":"O nome de usuário não pode ser alterado enquanto o projeto está em execução.","tw.cloudVariableBadge":"Esse projeto usa variáveis na nuvem. O TurboWarp usa seu próprio servidor de variáveis na nuvem independente e separado do Scratch. Cuidado com imitadores, já que qualquer um pode mudar o nome de usuário para qualquer coisa. {learnMore}","tw.code":"Código-fonte","tw.confirmIncompatibleExtension":"Essa extensão não é compatível com o Scratch. Projetos feitos com ela não funcionarão se você fizer upload no site do Scratch. Tem certeza que quer ativá-la?","tw.customExtension.description":"Carregar extensões customizadas por URLs. Para desenvolvedores. Experimental.","tw.customExtension.name":"Extensão Customizada","tw.featuredProjectsStudio":"Ver estúdio no Scratch.","tw.feedback":"Feedback e bugs","tw.feedbackButton":"Feedback do TurboWarp","tw.footer.credits":"Créditos","tw.footer.disclaimer":"O TurboWarp não tem afiliação com o Scratch, a Equipe do Scratch ou a Fundação Scratch.","tw.footer.embed":"Incorporação","tw.footer.fosshost":"Hospedagem por Fosshost","tw.footer.parameters":"Parâmetros de URL","tw.footer.translate":"Ajude a traduzir o TurboWarp","tw.gui.defaultProjectTitle":"Projeto","tw.guiDefaultTitle":"Rode projetos do Scratch mais rapidamente","tw.home.credit":"Notas e Créditos","tw.home.description":"TurboWarp é um mod do Scratch que compila projetos para JavaScript para os executar mais rapidamente. Experimente colocando um ID ou URL de projeto acima ou escolhendo um dos projetos em destaque abaixo.","tw.home.instructions":"Instruções","tw.input.tooltip":"Copie e cole um link de um projeto no Scratch aqui!","tw.interpolationEnabled":"Interpolação","tw.invalidParameters.clones":"parâmetro de URL \\"clone\\" é inválido","tw.invalidParameters.fps":"parâmetro de URL \\"fps\\" é inválido","tw.loader.assets.known":"Baixando recursos ({complete}/{total}) ...","tw.loader.assets.unknown":"Baixando recursos ...","tw.loader.data":"Baixando dados do projeto ...","tw.loader.generic":"Carregando projeto …","tw.menuBar.60off":"Desativar modo 60 FPS","tw.menuBar.60on":"Ativar modo 60 FPS","tw.menuBar.advanced":"Avançado","tw.menuBar.changeUsername":"Mudar nome de usuário","tw.menuBar.cloudOff":"Desativar variáveis na nuvem","tw.menuBar.cloudOn":"Ativar variáveis na nuvem","tw.menuBar.cloudUnavailable":"Variáveis na nuvem não estão disponíveis","tw.menuBar.cloudUnavailableAlert":"Não pôde usar variáveis na nuvem, provavelmente porque você abriu o editor.","tw.menuBar.loadRestorePoint":"Carregar ponto de restauração","tw.menuBar.moreSettings":"Configurações Avançadas","tw.menuBar.newFramerate":"Novo FPS:","tw.menuBar.reportError1":"Alguns scripts não puderam ser compilados.","tw.menuBar.reportError2":"Isso é um bug. Por favor, reporte-o.","tw.menuBar.saveAs":"Salvar como {file}","tw.menuBar.seeInside":"Ver interior","tw.oldDownload":"Salvar como arquivo separado...","tw.paint.alpha":"Opacidade","tw.privacy":"Política de Privacidade","tw.saveAs":"Salvar como...","tw.saveTo":"Salvar como {file}","tw.settingsModal.customStageSize":"Tamanho Customizado do Palco:","tw.settingsModal.customStageSizeHelp":"Muda o tamanho do palco do Scratch de 480x360 para outro valor. Tente 640x360 para deixar o palco em widescreen. Quase nenhum projeto irá funcionar direito com essa opção.","tw.settingsModal.dangerZone":"Zona de Perigo","tw.settingsModal.disableCompiler":"Desativar Compilador","tw.settingsModal.disableCompilerHelp":"Desativa o compilador do TurboWarp. Você pode ativar isso enquanto estiver editando projetos para fazer os scripts serem atualizados imediatamente. Em qualquer outra hipótese, deixe esta opção desativada.","tw.settingsModal.featured":"Em destaque","tw.settingsModal.fps":"60 FPS (FPS customizado)","tw.settingsModal.fpsHelp":"Roda scripts 60 vezes por segundo ao invés de 30. A maioria dos projetos não vão funcionar adequadamente com isso ativado. Se esse for o caso, você pode tentar usar Interpolação e desligar o modo 60 FPS. {customFramerate}.","tw.settingsModal.fpsHelp.customFramerate":"Clique para escolher FPS além de 30 ou 60","tw.settingsModal.help":"Ajuda","tw.settingsModal.highQualityPen":"Caneta de Alta Qualidade","tw.settingsModal.highQualityPenHelp":"Permite que projetos renderizem a caneta em uma qualidade melhor e reduz arredondamento de coordenadas no editor. Nem todo projeto se beneficia dessa opção, e ela pode piorar a performance.","tw.settingsModal.infiniteClones":"Clones Infinitos","tw.settingsModal.infiniteClonesHelp":"Desativa o limite de 300 clones do Scratch.","tw.settingsModal.interpolation":"Interpolação","tw.settingsModal.interpolationHelp":"Faz projetos parecerem rodar em framerates mais altas interpolando o movimento de atores. Interpolação não deve ser usada em projetos 3D, raytracers, projetos que usam caneta e projetos lagados porque a interpolação só vai fazer eles rodarem mais devagar sem deixá-los mais suaves.","tw.settingsModal.largeStageWarning":"Não é recomendado usar um tamanho de palco tão grande! Ao invés disso, use um tamanho menor com a mesma proporção e o modo tela cheia irá aumentar o palco para preencher a tela do usuário.","tw.settingsModal.removeFencing":"Remover Borda","tw.settingsModal.removeFencingHelp":"Deixa atores andarem para fora da tela, ficarem grandes ou pequenos sem limitação de tamanho e permite que os blocos \\"tocando\\" funcionem fora dos limites do palco.","tw.settingsModal.removeLimits":"Remover Limites","tw.settingsModal.removeMiscLimits":"Remover Outros Limites","tw.settingsModal.removeMiscLimitsHelp":"Remove os limites de efeitos de som e tamanho da caneta.","tw.settingsModal.storeProjectOptions":"Salvar configurações no projeto","tw.settingsModal.storeProjectOptionsHelp":"Salva suas configurações no projeto e automaticamente os aplica quando você abrir o projeto no TurboWarp. \\"Warp timer\\" e \\"desativar compilador\\" não serão salvos.","tw.settingsModal.title":"Configurações Avançadas","tw.settingsModal.warpTimerHelp":"Faz scripts detectarem se estão presos em um loop longo ou infinito e roda a uma framerate baixa ao invés de travar até o loop terminar. Isso conserta a maioria dos crashes mas prejudica muito a performance, então não está ativado por padrão fora do editor.","tw.spriteSelectorItem.rename":"renomear","tw.studioview.authorAttribution":"por {author}","tw.studioview.error":"Erro ao carregar a próxima página de projetos.","tw.studioview.hoverText":"{title} por {author}","tw.twExtension.description":"Uns blocos novos esquisitos. Não compatíveis com o Scratch.","tw.twExtension.name":"Blocos do TurboWarp","tw.usernameModal.help":"Esse valor será guardado no armazenamento do seu navegador. Projetos que contenham variáveis na nuvem podem querer registrá-lo.","tw.usernameModal.help2":"Valores que não correspondem a uma conta válida no Scratch normalmente serão rejeitados pelo servidor de variáveis na nuvem. Recomendamos que você deixe este valor como está ou mude-o para o seu nome de usuário do Scratch.","tw.usernameModal.mustChange":"Desculpe, o servidor de variáveis na nuvem acha que o seu nome de usuário pode ser inapropriado. Por favor, mude para outra coisa ou {resetIt}.","tw.usernameModal.mustChange.resetIt":"resete-o (recomendado)","tw.usernameModal.reset":"Redefinir","tw.usernameModal.title":"Mudar nome de usuário","tw.viewFeaturedProjects":"Clique para ver projetos em destaque.","tw.viewOnScratch":"Ver projeto no Scratch","tw.webglModal.description":"Infelizmente parece que o seu navegador ou computador {webGlLink}. Essa tecnologia é necessária para o site funcionar. Tente atualizar o seu navegador e drivers gráficos ou reiniciar o seu computador."},"rap":{"gui.alerts.tryAgain":"ka aŋa haka ʾou","gui.alerts.download":"haka topa","gui.connection.reconnect":"ka haka uru","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"pute","gui.backpack.errorBackpack":"ko hape ā i te haī haŋa o te putē","gui.backpack.loadingBackpack":"haī...","gui.backpack.more":"te tahi","gui.backpack.emptyBackpack":"ina etahi meʾe i rote putē","gui.unsupportedBrowser.label":"te navegador kai tano","gui.cards.all-tutorials":"haka hapi","gui.cards.shrink":"Shrink","gui.cards.expand":"Expand","gui.cards.close":"puru","gui.cards.more-things-to-try":"¡a ta rahi te meʾe mo haka atu!","gui.cards.see-more":"ata uʾi","gui.comingSoon.message1":"ina koe ko tipa tipa, i matou e aŋa a mo ra meʾe {emoji}","gui.comingSoon.message2":"Na he oho mai…","gui.comingSoon.message3":"e aŋa a mo ra meʾe {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"ka ravaʾa a te dispositivo","gui.connection.auto-scanning.prescan":"e hahine te dispositivo e ka haʾamata te kimi","gui.connection.auto-scanning.pressbutton":"ka ŋatu te pito pito o ta dispositivo ","gui.connection.auto-scanning.start-search":"ē haʾamata te kimi","gui.connection.connecting-searchbutton":" e kimi ā...","gui.connection.auto-scanning.try-again":"e aŋa haka ʾou","gui.connection.connected":"ko raʾu a","gui.connection.disconnect":"ka hore","gui.connection.go-to-editor":"e oho ki te editor","gui.connection.connecting-cancelbutton":"e kimi a te raʾu …","gui.connection.error.errorMessage":"Ups, ko hapeʾa e tahi meʾe","gui.connection.error.tryagainbutton":"e aŋa haka ʾou","gui.connection.error.helpbutton":"hāʾuʾu","gui.connection.peripheral-name-label":"iŋoa o te dispositivo","gui.connection.connect":"Conectar","gui.connection.scanning.lookingforperipherals":"ē kimi ā te dispositivo","gui.connection.scanning.noPeripheralsFound":"ka ravaʾa a te dispositivo","gui.connection.scanning.instructions":"ka tuhita dispositivo hāŋa","gui.connection.search":"haka a","gui.connection.unavailable.installscratchlink":"ka uʾi riva riva a na ai ko hahaʾo a te scratch link instalado","gui.connection.unavailable.enablebluetooth":"ka uʾi riva riva ko tanoʾa te bluetooth","gui.connection.unavailable.tryagainbutton":"e aŋa haka ʾou","gui.connection.unavailable.helpbutton":"hāʾuʾu","gui.controls.go":"oho","gui.controls.stop":"noho","gui.crashMessage.label":"¡Ups! Ko hapeʾa e tahi meʾe","gui.crashMessage.errorNumber":"Su error ha sido registrado con id {errorId}","gui.crashMessage.reload":"ka haī haka ʾou ","gui.customProcedures.myblockModalTitle":"he manaʾu mo āŋa e tahi avahata poto roa mekerā","gui.customProcedures.addAnInputNumberText":"ka hahaʾo te oʾo","gui.customProcedures.numberTextType":"numera o papaʾi","gui.customProcedures.addAnInputBoolean":"ka hahaʾo te oʾo","gui.customProcedures.booleanType":"boolean","gui.customProcedures.addALabel":"hahaʾo te parau papaʾi","gui.customProcedures.runWithoutScreenRefresh":"ē āŋa i tu hora a","gui.customProcedures.cancel":"haka motu","gui.customProcedures.ok":"haʾatiʾa","gui.SpriteInfo.direction":"ara","gui.directionPicker.rotationStyles.allAround":"ki te taʾatoʾa kona","gui.directionPicker.rotationStyles.leftRight":"maūi - mataʾu","gui.directionPicker.rotationStyles.dontRotate":"ina ko teka","gui.gui.addExtension":"ka hahaʾo te haka roa roa","gui.gui.codeTab":"he ta","gui.gui.backdropsTab":"tuʾa nui","gui.gui.costumesTab":"diseños","gui.gui.soundsTab":"pakeke","gui.extensionLibrary.comingSoon":"na he oho mai","gui.extensionLibrary.requires":"e ai","gui.extensionLibrary.collaboration":"hai hāʾuʾu o","gui.library.filterPlaceholder":"kimi","gui.library.allTag":"taʾatoʾa","gui.loader.headline":"e haī a te aŋa","gui.loader.creating":"e aŋa a te aŋa","gui.authorInfo.byUser":"hai {username}","gui.menuBar.seeProjectPage":"See Project Page","gui.menuBar.LanguageSelector":"tuhi reʾo haŋa","gui.menuBar.tutorialsLibrary":"haka hapi","gui.menuBar.restoreSprite":"haka aŋa haka ʾou te sprite","gui.menuBar.restoreSound":"haka aŋa haka ʾou te pakeke","gui.menuBar.restoreCostume":"haka titika te diseño","gui.menuBar.restore":"haka titika","gui.menuBar.saveNow":"ka hapaʾo i te hora nei","gui.menuBar.saveAsCopy":"ka hapaʾo te copia","gui.menuBar.remix":"e aŋa haka ʾou","gui.menuBar.new":"apī","gui.menuBar.file":"parau hapaʾo","gui.menuBar.downloadToComputer":"hapaʾo te kona apapa","gui.menuBar.edit":"haka titika","gui.menuBar.turboModeOff":"ka haka hore hai Turbo","gui.menuBar.turboModeOn":"ē āŋa hai huru turbo","gui.gui.projectTitlePlaceholder":"iŋoa o te aŋa i nei","gui.menuBar.isShared":"e amui","gui.menuBar.share":"vaʾai","gui.modal.help":"hāʾuʾu","gui.modal.back":"a tuʾa ","gui.monitor.listMonitor.empty":"(kore)","gui.monitor.listMonitor.listLength":"roa roa o te {length}","gui.monitor.contextMenu.default":"normal readout","gui.monitor.contextMenu.large":"nui nui tano","gui.monitor.contextMenu.slider":"haka nini","gui.monitor.contextMenu.sliderRange":"e kamiare te rango p te deslizador ","gui.monitor.contextMenu.import":"e maʾu mai mai haho","gui.monitor.contextMenu.export":"exportar","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Play","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"For all sprites","gui.gui.variableScopeOptionSpriteOnly":"For this sprite only","gui.gui.cloudVariableOption":"variable i te raŋi (hapaʾo i rote servidor)","gui.gui.variablePromptAllSpritesMessage":"te variable nei he rovaʾa koe i te sprite taʾa toʾa","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"haka motu","gui.prompt.ok":"haʾatiʾa","gui.playbackStep.stopMsg":"oho","gui.playbackStep.playMsg":"haka āŋa","gui.playbackStep.loadingMsg":"haī...","gui.playbackStep.saveMsg":"hapaʾo ","gui.playbackStep.reRecordMsg":"e graba haka ʾou","gui.recordModal.title":"ka graba te pakeke","gui.recordingStep.beginRecord":"mo haʾamata te grabacion ka ŋatu hai clic te rua pito pito","gui.recordingStep.permission":"{arrow} e hatiʾa mai koe mo aŋa hai microfono","gui.recordingStep.stop":"haka noho te grabacion","gui.recordingStep.record":"hapaʾo","gui.sliderModal.min":"te mau iti","gui.sliderModal.max":"te mau rahi","gui.sliderModal.title":"e kamiare te rango p te deslizador ","gui.sliderPrompt.cancel":"haka motu","gui.sliderPrompt.ok":"haʾatiʾa","gui.soundEditor.sound":"pakeke","gui.soundEditor.play":"haka āŋa","gui.soundEditor.stop":"oho","gui.soundEditor.copy":"Copy","gui.soundEditor.paste":"Paste","gui.soundEditor.copyToNew":"Copy to New","gui.soundEditor.delete":"Delete","gui.soundEditor.save":"hapaʾo ","gui.soundEditor.undo":"moumou","gui.soundEditor.redo":"he anga haka ʾou","gui.soundEditor.faster":"ata horohorou","gui.soundEditor.slower":"ata kora iti","gui.soundEditor.echo":"reʾo ŋaro","gui.soundEditor.robot":"makini","gui.soundEditor.louder":"a ta puai","gui.soundEditor.softer":"a ta rehe","gui.soundEditor.reverse":"rori","gui.soundEditor.fadeOut":"Fade out","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Mute","gui.SpriteInfo.spritePlaceholder":"iŋoa","gui.SpriteInfo.sprite":"Sprite","gui.SpriteInfo.show":"haka tikeʾa","gui.SpriteInfo.size":"he haito","gui.spriteSelectorItem.contextMenuDuplicate":"haka rahi","gui.spriteSelectorItem.contextMenuExport":"exportar","gui.spriteSelectorItem.contextMenuDelete":"haka kore","gui.spriteSelector.addSpriteFromLibrary":"Choose a Sprite","gui.spriteSelector.addSpriteFromPaint":"ka paru","gui.spriteSelector.addSpriteFromSurprise":"he mahia etahi meʾe","gui.spriteSelector.addSpriteFromFile":"haka eke te meʾe","gui.stageHeader.stageSizeLarge":"ka kamiare te escenario iti iti ","gui.stageHeader.stageSizeSmall":"ka kamiare te escenario nui nui","gui.stageHeader.stageSizeFull":"e oho ki te teata nui nui","gui.stageHeader.stageSizeUnFull":"e eʾa mai te teata nui nui","gui.stageHeader.fullscreenControl":"control ki te teata nui nui","gui.spriteSelector.addBackdropFromLibrary":"ka aʾaru te tuʾa nui","gui.stageSelector.addBackdropFromPaint":"ka paru","gui.stageSelector.addBackdropFromSurprise":"he mahia etahi meʾe","gui.stageSelector.addBackdropFromFile":"ka haka ēke te tuʾa nui","gui.stageSelector.stage":"Ahu","gui.stageSelector.backdrops":"tuʾa nui","gui.telemetryOptIn.label":"e haka ite te estadistica ki te Scratch ","gui.telemetryOptIn.body1":"te nunaʾa o te Scratch e kimi a pehe ana aŋa te Scratcha a te Ao taʾatoʾa. mo haʾuʾu nei aŋa , e riva ro mo hatiʾa ki te Scratch mo haka oho te información automatico ki te nunaʾa aŋa o te Scratch.","gui.telemetryOptIn.body2":"te información e haʾaputu nei, he reʾo, aŋa o te bloques e he aŋa vara vara pahe hapaʾo, haī e he eke te aŋa. E ko toʾo te información o te unʾu. e riva ro mo ʾui {privacyPolicyLink} mo te tahi información.","gui.telemetryOptIn.privacyPolicyLink":"poritika o te privacidad","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"modo turbo","gui.webglModal.label":"ta navegador ina kai tano mo te WebGL","gui.webglModal.webgllink":"e ko tano te WebGL","gui.costumeLibrary.chooseABackdrop":"ka aʾaru te tuʾa nui","gui.costumeLibrary.chooseACostume":"ka tuhi te diseño","gui.costumeTab.addBackdropFromLibrary":"ka aʾaru te tuʾa nui","gui.costumeTab.addCostumeFromLibrary":"ka tuhi te diseño","gui.costumeTab.addBlankCostume":"ka paru","gui.costumeTab.addSurpriseCostume":"he mahia etahi meʾe","gui.costumeTab.addFileBackdrop":"ka haka ēke te tuʾa nui","gui.costumeTab.addFileCostume":"Upload Costume","gui.extensionLibrary.chooseAnExtension":"ka tuhi taʾa roa roa hāŋa","gui.extensionLibrary.extensionUrl":"ka hahaʾo te URL o te haka roa roa","gui.monitors.importListColumnPrompt":"¿he aha te tika mo aŋa (1-{numberOfColumns}?","gui.recordingStep.alertMsg":"kai tano ʾa mo haʾamata te gravacion","gui.soundLibrary.chooseASound":"ka tuhi taʾa meʾe hāŋa","gui.soundTab.fileUploadSound":"ka hahaʾo te pakeke","gui.soundTab.surpriseSound":"he mahia etahi meʾe","gui.soundTab.recordSound":"hapaʾo","gui.soundTab.addSoundFromLibrary":"ka tuhi taʾa meʾe hāŋa","gui.spriteLibrary.chooseASprite":"Choose a Sprite","gui.tipsLibrary.tutorials":"ka tuhi te meʾe mo haka hapī atu","gui.alerts.createsuccess":"aŋa api aŋa era","gui.alerts.createcopysuccess":"aŋa hapaʾo pahe aŋa hakaʾou e tahi","gui.alerts.createremixsuccess":"ko hapaʾo a te aŋa pahe aŋa api haka ʾou","gui.alerts.creating":"e aŋa a haka ʾou...","gui.alerts.creatingCopy":"e haka aŋa haka ʾou te rua aŋa…","gui.alerts.creatingRemix":"he aŋa haka ʾou te aŋa…","gui.alerts.creatingError":"kai tano mo aŋa te aŋa, e riva ro mo aŋa haka ʾou","gui.alerts.savingError":"kai tano ā mo hapaʾo te aŋa","gui.alerts.savesuccess":"ko hapaʾo a te aŋa","gui.alerts.saving":"hapaʾo a te aŋa...","gui.alerts.cloudInfo":"ka manaʾu koe te variables i te raŋi e riva ro no mo hahaʾo te numera, taʾe te tiaraʾa e taʾe te simbolos. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"mo te ʾui","gui.alerts.importing":"mai haho","gui.defaultProject.variable":"toʾoku variable","gui.extension.music.name":"Música","gui.extension.music.description":"ka haka taŋi te rahi o te meʾe pahe tampuru","gui.extension.pen.name":"pentara","gui.extension.pen.description":"Draw with your sprites.","gui.extension.videosensing.name":"Sensor de video","gui.extension.videosensing.description":"Detecta movimientos con la cámara.","gui.extension.text2speech.name":"papaʾi hai reʾo","gui.extension.text2speech.description":"ka hahaʾo te reʾo ki taʾa āŋa","gui.extension.translate.name":"huri vanāŋa","gui.extension.translate.description":"ka huri ki te rahi o te reʾo","gui.extension.makeymakey.description":"ka rori taʾatoʾa meʾe i te etahi no pito pito","gui.extension.microbit.description":"ka hahaʾo taʾa āŋa mo haka tikeʾa ki te tahi hau o te ao","gui.extension.microbit.connectingMessage":"e raʾu a","gui.extension.ev3.description":"ka āŋa te makini haka tere e te tahi meʾe","gui.extension.ev3.connectingMessage":"raʾu. Ka aŋi aŋi ana ai te PIN o toʾu V3 KO 1234.","gui.extension.boost.description":"ka vaʾai te ora ki te aŋa aʾau páhe robotica","gui.extension.boost.connectingMessage":"e raʾu a","gui.extension.wedo2.description":"ka āŋa hai motores e he sensores","gui.extension.wedo2.connectingMessage":"e raʾu a","gui.extension.gdxfor.description":"Sense push, pull, motion, and spin.","gui.extension.gdxfor.connectingMessage":"e raʾu a","gui.libraryTags.all":"taʾatoʾa","gui.libraryTags.animals":"manu tere henua","gui.libraryTags.dance":"ori","gui.libraryTags.effects":"Efectos","gui.libraryTags.fantasy":"Fantasía","gui.libraryTags.fashion":"haka nehe nehe","gui.libraryTags.food":"kai","gui.libraryTags.indoors":"rori ki tuʾa","gui.libraryTags.loops":"Bucles","gui.libraryTags.music":"Música","gui.libraryTags.notes":"papaʾi","gui.libraryTags.outdoors":"i haho","gui.libraryTags.patterns":"Patrones","gui.libraryTags.people":"nunaʾa","gui.libraryTags.percussion":"haka taŋi tampuru","gui.libraryTags.space":"kona","gui.libraryTags.sports":"makenu hakari","gui.libraryTags.underwater":"raro o te vaikava","gui.libraryTags.voice":"reʾo","gui.libraryTags.wacky":"maʾa maʾa mira mira","gui.libraryTags.animation":"haka makenu","gui.libraryTags.art":"tapura","gui.libraryTags.games":"kori","gui.libraryTags.stories":"āʾāmu","gui.libraryTags.letters":"tiaraʾa","gui.opcodeLabels.direction":"ara","gui.opcodeLabels.xposition":"he noho o te x","gui.opcodeLabels.yposition":"he noho o te y","gui.opcodeLabels.size":"he haito","gui.opcodeLabels.costumename":"iŋoa o te diseño","gui.opcodeLabels.costumenumber":"costume number","gui.opcodeLabels.backdropname":"iŋoa o te tuʾa nui","gui.opcodeLabels.backdropnumber":"tataku o te tuʾa nui","gui.opcodeLabels.volume":"re´o o te computador","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"pahono","gui.opcodeLabels.loudness":"volumen o te pakeke","gui.opcodeLabels.username":"iŋoa o te usuario","gui.opcodeLabels.year":"matahiti","gui.opcodeLabels.month":"avaʾe","gui.opcodeLabels.date":"mahana","gui.opcodeLabels.dayofweek":"mahana o te tapati","gui.opcodeLabels.hour":"hōra","gui.opcodeLabels.minute":"minuti","gui.opcodeLabels.second":"segundo","gui.opcodeLabels.timer":"cronómetro","gui.sharedMessages.backdrop":"tuʾa nui {index}","gui.sharedMessages.costume":"diseño {index}","gui.sharedMessages.sprite":"Sprite {index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"¿e hahaʾo te rua aŋa o te aŋa e aŋa mai ena?","gui.sharedMessages.loadFromComputerTitle":"Load from your computer","boost.color.any":"any color","boost.color.black":"black","boost.color.blue":"blue","boost.color.green":"green","boost.color.red":"red","boost.color.white":"white","boost.color.yellow":"yellow","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] position","boost.getTiltAngle":"tilt angle [TILT_DIRECTION]","boost.motorDirection.backward":"that way","boost.motorDirection.forward":"this way","boost.motorDirection.reverse":"rori","boost.motorOff":"turn motor [MOTOR_ID] off","boost.motorOn":"turn motor [MOTOR_ID] on","boost.motorOnFor":"turn motor [MOTOR_ID] for [DURATION] seconds","boost.motorOnForRotation":"turn motor [MOTOR_ID] for [ROTATION] rotations","boost.seeingColor":"seeing [COLOR] brick?","boost.setLightHue":"haka tano te peni o te morī ki te [HUE]","boost.setMotorDirection":"set motor [MOTOR_ID] direction [MOTOR_DIRECTION]","boost.setMotorPower":"set motor [MOTOR_ID] speed to [POWER] %","boost.tiltDirection.any":"taʾatoʾa meʾe","boost.tiltDirection.down":"raro","boost.tiltDirection.left":"maūi","boost.tiltDirection.right":"mataʾu","boost.tiltDirection.up":"ruŋa","boost.whenColor":"when [COLOR] brick seen","boost.whenTilted":"mo haka taha ki [TILT_DIRECTION_ANY]","ev3.beepNote":"beep note [NOTE] for [TIME] secs","ev3.buttonPressed":"button [PORT] pressed?","ev3.getBrightness":"ʾuira","ev3.getDistance":"roa ki","ev3.getMotorPosition":"te noho o te motor [PORT]","ev3.motorSetPower":"motor [PORT] set power [POWER] %","ev3.motorTurnClockwise":"motor [PORT] turn this way for [TIME] seconds","ev3.motorTurnCounterClockwise":"motor [PORT] turn that way for [TIME] seconds","ev3.whenBrightnessLessThan":"a he te uira < [DISTANCE]","ev3.whenButtonPressed":"ki ŋatu te pito pito [PORT]","ev3.whenDistanceLessThan":"a he te roa haka tano < [DISTANCE]","gdxfor.getAcceleration":"acceleration [DIRECTION]","gdxfor.getForce":"puai","gdxfor.getSpin":"te horou o te teka [DIRECTION]","gdxfor.getTilt":"tilt angle [TILT]","gdxfor.isFreeFalling":"¿e hiŋa?","gdxfor.isTilted":"tilted [TILT]?","gdxfor.pulled":"pulled","gdxfor.pushed":"pushed","gdxfor.shaken":"shaken","gdxfor.startedFalling":"started falling","gdxfor.tiltDirectionMenu.any":"taʾatoʾa meʾe","gdxfor.tiltDirectionMenu.back":"i tuʾa","gdxfor.tiltDirectionMenu.front":"a muʾa ki te tahi","gdxfor.tiltDirectionMenu.left":"maūi","gdxfor.tiltDirectionMenu.right":"mataʾu","gdxfor.turnedFaceDown":"turned face down","gdxfor.turnedFaceUp":"turned face up","gdxfor.whenForcePushedOrPulled":"ki he te sensor o te puai [PUSH_PULL]","gdxfor.whenGesture":"when [GESTURE]","gdxfor.whenTilted":"ki haka taha [TILT]","makeymakey.downArrow":"teʾa ki raro","makeymakey.downArrowShort":"raro","makeymakey.leftArrow":"teʾa maui","makeymakey.leftArrowShort":"maūi","makeymakey.rightArrow":"teʾa mataʾu","makeymakey.rightArrowShort":"mataʾu","makeymakey.spaceKey":"kona","makeymakey.upArrow":"teʾa ki ruŋa","makeymakey.upArrowShort":"ruŋa","makeymakey.whenKeyPressed":"mo ŋatu te pito pito [KEY]","makeymakey.whenKeysPressedInOrder":"when [SEQUENCE] pressed in order","microbit.buttonsMenu.any":"taʾatoʾa meʾe","microbit.clearDisplay":"miaitaki te teata","microbit.defaultTextToDisplay":"¡Iorana!","microbit.displaySymbol":"display [MATRIX]","microbit.displayText":"haka tikeʾa te papaʾi[TEXT]","microbit.gesturesMenu.jumped":"jumped","microbit.gesturesMenu.moved":"moved","microbit.gesturesMenu.shaken":"shaken","microbit.isButtonPressed":"[BTN] button pressed?","microbit.isTilted":"tilted [DIRECTION]?","microbit.pinStateMenu.off":"haka mate","microbit.pinStateMenu.on":"haka pura","microbit.tiltAngle":"tilt angle [DIRECTION]","microbit.tiltDirectionMenu.any":"taʾatoʾa meʾe","microbit.tiltDirectionMenu.back":"i tuʾa","microbit.tiltDirectionMenu.front":"a muʾa ki te tahi","microbit.tiltDirectionMenu.left":"maūi","microbit.tiltDirectionMenu.right":"mataʾu","microbit.whenButtonPressed":"mo ŋatu te pito pito [BTN]","microbit.whenGesture":"when [GESTURE]","microbit.whenPinConnected":"mo hahaʾo te pin [PIN]","microbit.whenTilted":"mo haka taha ki te [DIRECTION]","music.categoryName":"Música","music.changeTempo":"change tempo by [TEMPO]","music.drumBass":"(2) Bombo","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) Charles cerrado","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Cencerro","music.drumCrashCymbal":"(4) Platillo crash","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Güiro","music.drumHandClap":"(8) Palmada","music.drumOpenHiHat":"(5) Charles abierto","music.drumSideStick":"(3) Golpe lateral","music.drumSnare":"(1) avahata mob haka taŋi","music.drumTambourine":"(7) Pandereta","music.drumTriangle":"(12) taimana","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) avahata tenito","music.getTempo":"tempo","music.instrumentBass":"(6) Bajo","music.instrumentBassoon":"(14) Fagot","music.instrumentCello":"(8) Violonchelo","music.instrumentChoir":"(15) Coro","music.instrumentClarinet":"(10) Clarinete","music.instrumentElectricGuitar":"(5) kitara electronico","music.instrumentElectricPiano":"(2) Piano eléctrico","music.instrumentFlute":"(12) Flauta","music.instrumentGuitar":"(4) kitara","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Caja de música","music.instrumentOrgan":"(3) Órgano","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxofón","music.instrumentSteelDrum":"(18) Tambor metálico","music.instrumentSynthLead":"(20) Sintetizador melódico","music.instrumentSynthPad":"(21) Sintetizador de fondo","music.instrumentTrombone":"(9) Trombón","music.instrumentVibraphone":"(16) Vibráfono","music.instrumentWoodenFlute":"(13) Flauta de madera","music.midiPlayDrumForBeats":"haka taŋi te tampuru [DRUM] Aa rote [BEATS] hora","music.midiSetInstrument":"haka tano te meʾe mo haka taŋi ki te [INSTRUMENT]","music.playDrumForBeats":"haka taŋi te tampuru [DRUM] Aa rote [BEATS] hora","music.playNoteForBeats":"haka taŋi te nota [NOTE] a rote [BEATS] hora","music.restForBeats":"he mou o te [BEATS] hora","music.setInstrument":"haka tano te meʾe mo haka taŋi ki te [INSTRUMENT]","music.setTempo":"ka vaʾai te tempo ki te mau [TEMPO]","pen.categoryName":"pentara","pen.changeColorParam":"change pen [COLOR_PARAM] by [VALUE]","pen.changeHue":"ka kamiare te kiea o te pentara por [HUE]","pen.changeShade":"ka kamiare te kohu o te pentara ki te [SHADE]","pen.changeSize":"ka kamiare te nui nui o te pentara ki te [SIZE]","pen.clear":"haka kore tahi","pen.colorMenu.brightness":"ʾuira","pen.colorMenu.color":"kiʾea","pen.colorMenu.saturation":"saturación","pen.colorMenu.transparency":"transparency","pen.penDown":"haka turu te pentara","pen.penUp":"haka iri te pentara","pen.setColor":"haka tano te kiea o te pentara ko te [COLOR]","pen.setColorParam":"set pen [COLOR_PARAM] to [VALUE]","pen.setHue":"haka tano te kiea o te pentara ko te [HUE]","pen.setShade":"haka tano te kohu o te pentara ki te [SHADE]","pen.setSize":"haka tano te nui nui o te pentara ki te [SIZE]","pen.stamp":"tapa´o","text2speech.alto":"contralto","text2speech.categoryName":"papaʾi hai reʾo","text2speech.defaultTextToSpeak":"iorana","text2speech.giant":"nui nui tetu","text2speech.kitten":"kuri iti","text2speech.setLanguageBlock":"haka tano te reʾo ki te [LANGUAGE]","text2speech.setVoiceBlock":"ka hahaʾo te reʾo ki te [VOICE]","text2speech.speakAndWaitBlock":"e ki [WORDS]","text2speech.squeak":"chillido","text2speech.tenor":"tenor","translate.categoryName":"huri vanāŋa","translate.defaultTextToTranslate":"iorana","translate.translateBlock":"ka huri [WORDS] ki te [LANGUAGE]","translate.viewerLanguage":"reʾo","videoSensing.categoryName":"Sensor de video","videoSensing.direction":"ara","videoSensing.motion":"makenu","videoSensing.off":"haka mate","videoSensing.on":"haka pura","videoSensing.onFlipped":"on flipped","videoSensing.setVideoTransparency":"haka tano te maeha o te teata ki te [TRANSPARENCY]","videoSensing.sprite":"sprite","videoSensing.stage":"ahu","videoSensing.videoOn":"video [ATTRIBUTE] on [SUBJECT]","videoSensing.videoToggle":"turn video [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"a he te makenu o te teata [REFERENCE]","wedo2.getDistance":"roa ki","wedo2.getTiltAngle":"tilt angle [TILT_DIRECTION]","wedo2.isTilted":"tilted [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"that way","wedo2.motorDirection.forward":"this way","wedo2.motorDirection.reverse":"rori","wedo2.motorId.a":"motor A","wedo2.motorId.all":"te taʾatoʾa motores","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"turn [MOTOR_ID] off","wedo2.motorOn":"turn [MOTOR_ID] on","wedo2.motorOnFor":"turn [MOTOR_ID] on for [DURATION] seconds","wedo2.playNoteFor":"ka haka taŋi[NOTE] hai hora [DURATION] piere","wedo2.setLightHue":"haka tano te peni o te morī ki te [HUE]","wedo2.setMotorDirection":"set [MOTOR_ID] direction to [MOTOR_DIRECTION]","wedo2.startMotorPower":"set [MOTOR_ID] power to [POWER]","wedo2.tiltDirection.any":"taʾatoʾa meʾe","wedo2.tiltDirection.down":"raro","wedo2.tiltDirection.left":"maūi","wedo2.tiltDirection.right":"mataʾu","wedo2.tiltDirection.up":"ruŋa","wedo2.whenDistance":"a he te roa haka tano [OP] [REFERENCE]","wedo2.whenTilted":"mo haka taha ki [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Kiʾea","paint.paintEditor.saturation":"Saturación","paint.paintEditor.brightness":"ʾUira","paint.paintEditor.costume":"Diseño","paint.paintEditor.group":"piri","paint.paintEditor.ungroup":"haka kore te piri","paint.paintEditor.undo":"moumou","paint.paintEditor.redo":"he anga haka ʾou","paint.paintEditor.forward":"a muʾa","paint.paintEditor.backward":"A tuʾa ","paint.paintEditor.front":"i muʾa","paint.paintEditor.back":"a tuʾa ","paint.paintEditor.more":"te tahi","paint.modeTools.brushSize":"he haito","paint.modeTools.eraserSize":"he nui nui o te ua ua haka kore","paint.modeTools.copy":"ko tuʾu meʾe a","paint.modeTools.paste":"pipiri","paint.modeTools.delete":"haka kore","paint.modeTools.curved":"pikopiko","paint.modeTools.pointed":"titika","paint.modeTools.thickness":"peŋo peŋo","paint.modeTools.flipHorizontal":"haka teka pahe hau titika","paint.modeTools.flipVertical":"e rori mo haka titika","paint.modeTools.filled":"hāʾī","paint.modeTools.outlined":"Contorneado","paint.paintEditor.bitmap":"haka āŋa ki te mapa bits","paint.paintEditor.vector":"e rori ki te vector","paint.paintEditor.fill":"hāʾī","paint.paintEditor.stroke":"Tītī","paint.brushMode.brush":"purumu paru","paint.eraserMode.eraser":"ua ua haka kore","paint.fillMode.fill":"hāʾī","paint.lineMode.line":"hore hore","paint.ovalMode.oval":"taka taka","paint.rectMode.rect":"avahata poto roa","paint.reshapeMode.reshape":"e hoki mo haka titika te āŋa","paint.roundedRectMode.roundedRect":"avahata poto roa hai titi taka taka","paint.selectMode.select":"tuhi","paint.textMode.text":"papaʾi","paint.colorPicker.swap":"rori"},"ro":{"gui.alerts.tryAgain":"Încearcă din nou","gui.alerts.download":"Descarcă","gui.connection.reconnect":"Reconectare","gui.backpack.costumeLabel":"costum","gui.backpack.soundLabel":"sunet","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"personaj","gui.backpack.header":"Rucsac","gui.backpack.errorBackpack":"Eroare încărcare rucsac","gui.backpack.loadingBackpack":"Se încarcă...","gui.backpack.more":"Altele","gui.backpack.emptyBackpack":"Rucsacul este gol","gui.unsupportedBrowser.label":"Browser incompatibil","gui.cards.all-tutorials":"Tutoriale","gui.cards.shrink":"Micșorează","gui.cards.expand":"Extinde","gui.cards.close":"Închide","gui.cards.more-things-to-try":"Mai multe lucruri de încercat!","gui.cards.see-more":"Vezi mai multe","gui.comingSoon.message1":"Nu-ți face griji, ne ocupăm de asta {emoji}","gui.comingSoon.message2":"În curând...","gui.comingSoon.message3":"Lucrăm la asta {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Nu s-au găsit dispozitive.","gui.connection.auto-scanning.prescan":"Plasează dispozitivul în apropiere, apoi începe căutarea.","gui.connection.auto-scanning.pressbutton":"Apasă butonul de pe dispozitiv.","gui.connection.auto-scanning.start-search":"Începe căutarea","gui.connection.connecting-searchbutton":"Se caută...","gui.connection.auto-scanning.try-again":"Încearcă din nou","gui.connection.connected":"Conectat","gui.connection.disconnect":"Deconectează","gui.connection.go-to-editor":"Mergi la Editor","gui.connection.connecting-cancelbutton":"Se conectează...","gui.connection.error.errorMessage":"Hopa! Ceva nu a mers bine.","gui.connection.error.tryagainbutton":"Încearcă din nou","gui.connection.error.helpbutton":"Ajutor","gui.connection.peripheral-name-label":"Nume dispozitiv","gui.connection.connect":"Conectează","gui.connection.scanning.lookingforperipherals":"Se caută dispozitive","gui.connection.scanning.noPeripheralsFound":"Nu s-au găsit dispozitive.","gui.connection.scanning.instructions":"Selectează dispozitivul tău din listă.","gui.connection.search":"Actualizează","gui.connection.unavailable.installscratchlink":"Asigură-te că ai Scratch Link instalat și pornit","gui.connection.unavailable.enablebluetooth":"Verifică dacă Bluetooth-ul e activat","gui.connection.unavailable.tryagainbutton":"Încearcă din nou","gui.connection.unavailable.helpbutton":"Ajutor","gui.controls.go":"Mergi","gui.controls.stop":"Stop","gui.crashMessage.label":"Hopa! Ceva nu a mers bine.","gui.crashMessage.errorNumber":"Eroarea a fost înregistrată cu id {errorId}","gui.crashMessage.reload":"Reîncarcă","gui.customProcedures.myblockModalTitle":"Creează un bloc","gui.customProcedures.addAnInputNumberText":"Adaugă o intrare","gui.customProcedures.numberTextType":"număr sau text","gui.customProcedures.addAnInputBoolean":"Adaugă o intrare","gui.customProcedures.booleanType":"boolean","gui.customProcedures.addALabel":"Adaugă o etichetă","gui.customProcedures.runWithoutScreenRefresh":"Rulează fără împrospătarea ecranului","gui.customProcedures.cancel":"Renunţă","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Direcția","gui.directionPicker.rotationStyles.allAround":"de jur împrejur","gui.directionPicker.rotationStyles.leftRight":"stânga-dreapta","gui.directionPicker.rotationStyles.dontRotate":"nu roti","gui.gui.addExtension":"Adaugă o extensie","gui.gui.codeTab":"Cod","gui.gui.backdropsTab":"Decoruri","gui.gui.costumesTab":"Costume","gui.gui.soundsTab":"Sunete","gui.extensionLibrary.comingSoon":"În curând","gui.extensionLibrary.requires":"Necesită","gui.extensionLibrary.collaboration":"Colaborare cu","gui.library.filterPlaceholder":"Caută","gui.library.allTag":"Tot","gui.loader.headline":"Se încarcă proiectul","gui.loader.creating":"Se creează proiectul","gui.authorInfo.byUser":"de {username}","gui.menuBar.seeProjectPage":"Vezi pagina proiectului","gui.menuBar.LanguageSelector":"Selectare limbă","gui.menuBar.tutorialsLibrary":"Tutoriale","gui.menuBar.restoreSprite":"Anulează ștergere personaj","gui.menuBar.restoreSound":"Anulează ștergere sunet","gui.menuBar.restoreCostume":"Anulează ștergere costum","gui.menuBar.restore":"Anulează ștergere","gui.menuBar.saveNow":"Salvează acum","gui.menuBar.saveAsCopy":"Salveaza o copie","gui.menuBar.remix":"Remixează","gui.menuBar.new":"Nou","gui.menuBar.file":"Fișier","gui.menuBar.downloadToComputer":"Salvează pe calculatorul tău","gui.menuBar.edit":"Editează","gui.menuBar.turboModeOff":"Dezactivează modul Turbo","gui.menuBar.turboModeOn":"Activează modul Turbo","gui.gui.projectTitlePlaceholder":"Titlul proiectului se scrie aici","gui.menuBar.isShared":"Partajat","gui.menuBar.share":"Partajează","gui.modal.help":"Ajutor","gui.modal.back":"Înapoi","gui.monitor.listMonitor.empty":"(gol)","gui.monitor.listMonitor.listLength":"lungime {length}","gui.monitor.contextMenu.default":"afișaj normal","gui.monitor.contextMenu.large":"afișare in format mare","gui.monitor.contextMenu.slider":"cursor","gui.monitor.contextMenu.sliderRange":"modifică interval cursor","gui.monitor.contextMenu.import":"importă","gui.monitor.contextMenu.export":"exportă","gui.monitor.contextMenu.hide":"ascunde","gui.playButton.play":"Redare","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"Pentru toate personajele","gui.gui.variableScopeOptionSpriteOnly":"Doar pentru acest personaj","gui.gui.cloudVariableOption":"Variabilă Cloud (stocată pe server)","gui.gui.variablePromptAllSpritesMessage":"Această variabilă va fi accesibilă tuturor personajelor.","gui.gui.listPromptAllSpritesMessage":"Această listă va fi accesibilă tuturor personajelor.","gui.prompt.cancel":"Renunţă","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Stop","gui.playbackStep.playMsg":"Redare","gui.playbackStep.loadingMsg":"Se încarcă...","gui.playbackStep.saveMsg":"Salvează","gui.playbackStep.reRecordMsg":"Re-înregistrare","gui.recordModal.title":"Înregistrare sunet","gui.recordingStep.beginRecord":"Începe înregistrarea apăsând butonul de mai jos","gui.recordingStep.permission":"{arrow} Avem nevoie de permisiunea ta pentru folosirea microfonului","gui.recordingStep.stop":"Oprește inregistrarea","gui.recordingStep.record":"Înregistrare","gui.sliderModal.min":"Valoare minimă","gui.sliderModal.max":"Valoare maximă","gui.sliderModal.title":"Modifică interval cursor","gui.sliderPrompt.cancel":"Anulează","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Sunet","gui.soundEditor.play":"Redare","gui.soundEditor.stop":"Stop","gui.soundEditor.copy":"Copiază","gui.soundEditor.paste":"Lipește","gui.soundEditor.copyToNew":"Copiază către unul nou","gui.soundEditor.delete":"Șterge","gui.soundEditor.save":"Salvează","gui.soundEditor.undo":"Anulează ultima modificare","gui.soundEditor.redo":"Refă acțiunea anulată","gui.soundEditor.faster":"Mai rapid","gui.soundEditor.slower":"Mai lent","gui.soundEditor.echo":"Ecou","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Mai puternic","gui.soundEditor.softer":"Mai încet","gui.soundEditor.reverse":"Inversează","gui.soundEditor.fadeOut":"Terminare graduală","gui.soundEditor.fadeIn":"Pornire graduală","gui.soundEditor.mute":"Amuțește","gui.SpriteInfo.spritePlaceholder":"Numele","gui.SpriteInfo.sprite":"Personaj","gui.SpriteInfo.show":"Arată","gui.SpriteInfo.size":"Dimensiune","gui.spriteSelectorItem.contextMenuDuplicate":"duplică","gui.spriteSelectorItem.contextMenuExport":"exportă","gui.spriteSelectorItem.contextMenuDelete":"șterge","gui.spriteSelector.addSpriteFromLibrary":"Alege un personaj","gui.spriteSelector.addSpriteFromPaint":"Desenează","gui.spriteSelector.addSpriteFromSurprise":"Surpriză","gui.spriteSelector.addSpriteFromFile":"Încarcă personaj","gui.stageHeader.stageSizeLarge":"Comută scenă mare","gui.stageHeader.stageSizeSmall":"Comută scenă mică","gui.stageHeader.stageSizeFull":"Intră în mod ecran complet","gui.stageHeader.stageSizeUnFull":"Ieși din mod ecran complet","gui.stageHeader.fullscreenControl":"Control ecran complet","gui.spriteSelector.addBackdropFromLibrary":"Alege un Decor","gui.stageSelector.addBackdropFromPaint":"Desenează","gui.stageSelector.addBackdropFromSurprise":"Surpriză","gui.stageSelector.addBackdropFromFile":"Încarcă decor","gui.stageSelector.stage":"Scenă","gui.stageSelector.backdrops":"Decoruri","gui.telemetryOptIn.label":"Raportează date statistice pentru a îmbunătăți Scratch.","gui.telemetryOptIn.body1":"Echipa Scratch încearcă mereu să înțeleagă mai bine modul în care Scratch este folosit în întreaga lume. Pentru a sprijini acest efort, puteți permite ca Scratch să trimită automat informații de utilizare către echipa Scratch.","gui.telemetryOptIn.body2":"Informațiile pe care le colectăm includ limba selectată, utilizarea blocurilor și unele evenimente ca salvarea, deschiderea și încărcarea online a unui proiect. NU COLECTĂM nici o infrormație personală. Vezi {privacyPolicyLink} pentru mai multe detalii.","gui.telemetryOptIn.privacyPolicyLink":"Politica de confidențialitate","gui.telemetryOptIn.optInText":"Trimite datele mele de utilizare Echipei Scratch","gui.telemetryOptIn.optInTooltip":"Activează telemetria","gui.telemetryOptIn.optOutText":"Nu trimite datele mele de utilizare Echipei Scratch","gui.telemetryOptIn.optOutTooltip":"Dezactivează telemetria","gui.telemetryOptIn.settingWasUpdated":"Setarea a fost actualizată.","gui.telemetryOptIn.buttonClose":"Închide","gui.turboMode.active":"Modul Turbo","gui.webglModal.label":"Browser-ul tău nu e compatibil cu WebGL","gui.webglModal.webgllink":"nu e compatibil cu WebGL","gui.costumeLibrary.chooseABackdrop":"Alege un decor","gui.costumeLibrary.chooseACostume":"Alege un costum","gui.costumeTab.addBackdropFromLibrary":"Alege un decor","gui.costumeTab.addCostumeFromLibrary":"Alege un costum","gui.costumeTab.addBlankCostume":"Desenează","gui.costumeTab.addSurpriseCostume":"Surpriză","gui.costumeTab.addFileBackdrop":"Încarcă decor","gui.costumeTab.addFileCostume":"Încarcă un costum","gui.extensionLibrary.chooseAnExtension":"Alege o extensie","gui.extensionLibrary.extensionUrl":"Introdu URL-ul extensiei","gui.monitors.importListColumnPrompt":"Ce coloană trebuie folosită (1-{numberOfColumns}) ?","gui.recordingStep.alertMsg":"Nu s-a putut înregistra","gui.soundLibrary.chooseASound":"Alege un sunet","gui.soundTab.fileUploadSound":"Încarcă sunet","gui.soundTab.surpriseSound":"Surpriză","gui.soundTab.recordSound":"Înregistrare","gui.soundTab.addSoundFromLibrary":"Alege un sunet","gui.spriteLibrary.chooseASprite":"Alege un personaj","gui.tipsLibrary.tutorials":"Alege un tutorial","gui.alerts.createsuccess":"S-a creeat un proiect nou.","gui.alerts.createcopysuccess":"Proiect salvat în copie.","gui.alerts.createremixsuccess":"Proiect salvat ca remix.","gui.alerts.creating":"Se creează...","gui.alerts.creatingCopy":"Se copiază proiectul...","gui.alerts.creatingRemix":"Se remixează proiectul...","gui.alerts.creatingError":"Proiectul nu a putut fi creat. Încercați din nou!","gui.alerts.savingError":"Proiectul nu a putut fi salvat.","gui.alerts.savesuccess":"Proiect salvat.","gui.alerts.saving":"Se salvează proiectul ...","gui.alerts.cloudInfo":"Te rog reține că variabilele cloud pot conține doar numere, nu litere sau simboluri. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Află mai multe.","gui.alerts.importing":"Se importă...","gui.defaultProject.variable":"variabila mea","gui.extension.music.name":"Muzică","gui.extension.music.description":"Cântă la instrumente și tobe","gui.extension.pen.name":"Stilou","gui.extension.pen.description":"Desenează cu personajele tale.","gui.extension.videosensing.name":"Detectare video","gui.extension.videosensing.description":"Detectează mișcarea cu ajutorul camerei.","gui.extension.text2speech.name":"Text în Vorbire","gui.extension.text2speech.description":"Fă-ți proiectul să vorbească","gui.extension.translate.name":"Traducere","gui.extension.translate.description":"Tradu texte în alte limbi.","gui.extension.makeymakey.description":"Transformă orice obiect într-un buton.","gui.extension.microbit.description":"Conectează-ți proiectele cu lumea.","gui.extension.microbit.connectingMessage":"Conectare","gui.extension.ev3.description":"Construiește roboți interactivi și mai mult decât atât.","gui.extension.ev3.connectingMessage":"Conectare. Asigură-te că pin-ul dispozitivului EV3 este 1234.","gui.extension.boost.description":"Adu la viață creaturi robotizate.","gui.extension.boost.connectingMessage":"Conectare","gui.extension.wedo2.description":"Construiește cu motorașe și senzori.","gui.extension.wedo2.connectingMessage":"Conectare","gui.extension.gdxfor.description":"Simte împingerea, tragerea, mișcarea și rotirea.","gui.extension.gdxfor.connectingMessage":"Conectare","gui.libraryTags.all":"Tot","gui.libraryTags.animals":"Animale","gui.libraryTags.dance":"Dans","gui.libraryTags.effects":"Efecte","gui.libraryTags.fantasy":"Fantezie","gui.libraryTags.fashion":"Modă","gui.libraryTags.food":"Mâncare","gui.libraryTags.indoors":"Interioare","gui.libraryTags.loops":"Repetitive","gui.libraryTags.music":"Muzica","gui.libraryTags.notes":"Note","gui.libraryTags.outdoors":"Exterioare","gui.libraryTags.patterns":"Șabloane","gui.libraryTags.people":"Oameni","gui.libraryTags.percussion":"Percuție","gui.libraryTags.space":"Spațiu","gui.libraryTags.sports":"Sporturi","gui.libraryTags.underwater":"Subacvatic","gui.libraryTags.voice":"Voce","gui.libraryTags.wacky":"Trăznite","gui.libraryTags.animation":"Animații","gui.libraryTags.art":"Arta","gui.libraryTags.games":"Jocuri","gui.libraryTags.stories":"Povești","gui.libraryTags.letters":"Litere","gui.opcodeLabels.direction":"direcția","gui.opcodeLabels.xposition":"poziția x","gui.opcodeLabels.yposition":"poziția y","gui.opcodeLabels.size":"mărime","gui.opcodeLabels.costumename":"denumire costum","gui.opcodeLabels.costumenumber":"numărul costumului","gui.opcodeLabels.backdropname":"denumire decor","gui.opcodeLabels.backdropnumber":"nr. decor","gui.opcodeLabels.volume":"volum","gui.opcodeLabels.tempo":"ritm","gui.opcodeLabels.answer":"răspuns","gui.opcodeLabels.loudness":"intensitate sunet","gui.opcodeLabels.username":"nume utilizator","gui.opcodeLabels.year":"anul","gui.opcodeLabels.month":"luna","gui.opcodeLabels.date":"data","gui.opcodeLabels.dayofweek":"ziua săptămânii","gui.opcodeLabels.hour":"ora","gui.opcodeLabels.minute":"minutul","gui.opcodeLabels.second":"secunda","gui.opcodeLabels.timer":"cronometru","gui.sharedMessages.backdrop":"decor{index}","gui.sharedMessages.costume":"costum{index}","gui.sharedMessages.sprite":"Personaj{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Confirmi înlocuirea proiectului curent ?","gui.sharedMessages.loadFromComputerTitle":"Încarcă de pe calculator","boost.color.any":"orice culoare","boost.color.black":"negru","boost.color.blue":"albastru","boost.color.green":"verde","boost.color.red":"roșu","boost.color.white":"alb","boost.color.yellow":"galben","boost.getMotorPosition":"poziția motorului [MOTOR_REPORTER_ID]","boost.getTiltAngle":"unghiul de înclinare [TILT_DIRECTION]","boost.motorDirection.backward":"înapoi","boost.motorDirection.forward":"înainte","boost.motorDirection.reverse":"inversează","boost.motorOff":"oprește motorul [MOTOR_ID]","boost.motorOn":"pornește motorul [MOTOR_ID]","boost.motorOnFor":"pornește motorul [MOTOR_ID] pentru [DURATION] secunde","boost.motorOnForRotation":"pornește motorul [MOTOR_ID] pentru [ROTATION] rotații","boost.seeingColor":"vezi cărămida [COLOR]?","boost.setLightHue":"setează culoare LED la [HUE]","boost.setMotorDirection":"setează motorul [MOTOR_ID] în direcția [MOTOR_DIRECTION]","boost.setMotorPower":"setează viteza motorului [MOTOR_ID] la [POWER] %","boost.tiltDirection.any":"în orice direcție","boost.tiltDirection.down":"în jos","boost.tiltDirection.left":"în stânga","boost.tiltDirection.right":"în dreapta","boost.tiltDirection.up":"în sus","boost.whenColor":"când este vizibilă cărămida [COLOR]","boost.whenTilted":"când este înclinat [TILT_DIRECTION_ANY]","ev3.beepNote":"semnal sonor nota [NOTE] pentru [TIME] secunde","ev3.buttonPressed":"butonul [PORT]este apăsat?","ev3.getBrightness":"strălucire","ev3.getDistance":"distanța","ev3.getMotorPosition":"motor [PORT] poziția","ev3.motorSetPower":"motor [PORT] setează putere la [POWER] %","ev3.motorTurnClockwise":"motor [PORT] rotește înainte [TIME] secunde","ev3.motorTurnCounterClockwise":"motor [PORT] rotește înapoi [TIME] secunde","ev3.whenBrightnessLessThan":"când strălucirea < [DISTANCE]","ev3.whenButtonPressed":"când butonul [PORT] este apăsat","ev3.whenDistanceLessThan":"când distanța < [DISTANCE]","gdxfor.getAcceleration":"accelerație[DIRECTION]","gdxfor.getForce":"forță","gdxfor.getSpin":"viteza rotației[DIRECTION]","gdxfor.getTilt":"unghi de înclinare [TILT]","gdxfor.isFreeFalling":"în cădere?","gdxfor.isTilted":"înclinat [TILT]?","gdxfor.pulled":"tras","gdxfor.pushed":"împins","gdxfor.shaken":"scuturat","gdxfor.startedFalling":"cădere începută","gdxfor.tiltDirectionMenu.any":"în orice direcție","gdxfor.tiltDirectionMenu.back":"în spate","gdxfor.tiltDirectionMenu.front":"în față","gdxfor.tiltDirectionMenu.left":"în stânga","gdxfor.tiltDirectionMenu.right":"în dreapta","gdxfor.turnedFaceDown":"întors cu fața în jos","gdxfor.turnedFaceUp":"întors cu fața în sus","gdxfor.whenForcePushedOrPulled":"când senzorul de forță este [PUSH_PULL]","gdxfor.whenGesture":"când e [GESTURE]","gdxfor.whenTilted":"la înclinarea [TILT]","makeymakey.downArrow":"săgeată jos","makeymakey.downArrowShort":"jos","makeymakey.leftArrow":"săgeată stânga","makeymakey.leftArrowShort":"stânga","makeymakey.rightArrow":"săgeată dreapta","makeymakey.rightArrowShort":"dreapta","makeymakey.spaceKey":"spațiu","makeymakey.upArrow":"săgeată sus","makeymakey.upArrowShort":"sus","makeymakey.whenKeyPressed":"la apăsarea tastei [KEY]","makeymakey.whenKeysPressedInOrder":"la apăsarea în ordine a [SEQUENCE]","microbit.buttonsMenu.any":"oricare","microbit.clearDisplay":"șterge ecran","microbit.defaultTextToDisplay":"Salut!","microbit.displaySymbol":"afișează [MATRIX]","microbit.displayText":"afișează textul [TEXT]","microbit.gesturesMenu.jumped":"sărit","microbit.gesturesMenu.moved":"mutat","microbit.gesturesMenu.shaken":"scuturat","microbit.isButtonPressed":"butonul [BTN] este apăsat?","microbit.isTilted":"înclinat [DIRECTION]?","microbit.pinStateMenu.off":"oprit","microbit.pinStateMenu.on":"pornit","microbit.tiltAngle":"unghiul de înclinare [DIRECTION]","microbit.tiltDirectionMenu.any":"oricare","microbit.tiltDirectionMenu.back":"în spate","microbit.tiltDirectionMenu.front":"în față","microbit.tiltDirectionMenu.left":"în stânga","microbit.tiltDirectionMenu.right":"în dreapta","microbit.whenButtonPressed":"când butonul [BTN] este apăsat","microbit.whenGesture":"când e [GESTURE]","microbit.whenPinConnected":"când pinul [PIN] este conectat","microbit.whenTilted":"când este înclinat[DIRECTION]","music.categoryName":"Muzica","music.changeTempo":"schimbă ritmul cu [TEMPO]","music.drumBass":"(2) Tobă mare","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Bețe","music.drumClosedHiHat":"(6) Hi-Hat închis","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Cowbell","music.drumCrashCymbal":"(4) Cinel Crash ","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Aplauze","music.drumOpenHiHat":"(5) Hi-Hat deschis","music.drumSideStick":"(3) Bătaie pe margine","music.drumSnare":"(1) Tobă Snare ","music.drumTambourine":"(7) Tamburină","music.drumTriangle":"(12) Trianglu","music.drumVibraslap":" (17) Vibraslap","music.drumWoodBlock":"(10) Bloc de lemn","music.getTempo":"ritm","music.instrumentBass":"(6) Bass","music.instrumentBassoon":"(14) Fagot","music.instrumentCello":"(8) Violoncel","music.instrumentChoir":"(15) Cor","music.instrumentClarinet":"(10) Clarinet","music.instrumentElectricGuitar":"(5) Chitară electrică","music.instrumentElectricPiano":"(2) Pian electric","music.instrumentFlute":"(12) Flaut","music.instrumentGuitar":"(4) Chitară","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Cutie muzicală","music.instrumentOrgan":"(3) Orgă","music.instrumentPiano":"(1) Pian","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxofon","music.instrumentSteelDrum":"(18) Tobă din oțel","music.instrumentSynthLead":"(20) Synth Lead","music.instrumentSynthPad":"(21) Synth Pad","music.instrumentTrombone":"(9) Trombon","music.instrumentVibraphone":"(16) Vibrafon","music.instrumentWoodenFlute":"(13) Flaut de lemn","music.midiPlayDrumForBeats":"cântă la tobă [DRUM] pentru [BEATS] bătăi","music.midiSetInstrument":"setează instrumentul la [INSTRUMENT]","music.playDrumForBeats":"cântă la tobă [DRUM] pentru [BEATS] bătăi","music.playNoteForBeats":"cântă nota [NOTE] pentru [BEATS] bătăi","music.restForBeats":"ia o pauză pentru [BEATS] bătăi","music.setInstrument":"setează instrument la [INSTRUMENT]","music.setTempo":"setează viteaza la [TEMPO]","pen.categoryName":"Stilou","pen.changeColorParam":"schimbă [COLOR_PARAM] stiloului cu [VALUE]","pen.changeHue":"schimbă culoarea stiloului cu [HUE]","pen.changeShade":"schimbă nuanța stiloului cu [SHADE]","pen.changeSize":"schimbă grosimea stiloului cu [SIZE]","pen.clear":"șterge tot","pen.colorMenu.brightness":"strălucirea","pen.colorMenu.color":"culoarea","pen.colorMenu.saturation":"saturația","pen.colorMenu.transparency":"transparența","pen.penDown":"stilou jos","pen.penUp":"stilou sus","pen.setColor":"setează culoarea stiloului la [COLOR]","pen.setColorParam":"setează [COLOR_PARAM] stiloului la [VALUE]","pen.setHue":"setează culoarea stiloului la [HUE]","pen.setShade":"setează nuanța stiloului la [SHADE]","pen.setSize":"setează grosimea stiloului la [SIZE]","pen.stamp":"ștampila","text2speech.alto":"alto","text2speech.categoryName":"Text în Vorbire","text2speech.defaultTextToSpeak":"salut","text2speech.giant":"uriaș","text2speech.kitten":"pisicuță","text2speech.setLanguageBlock":"setează limba [LANGUAGE]","text2speech.setVoiceBlock":"setează vocea [VOICE]","text2speech.speakAndWaitBlock":"spune [WORDS]","text2speech.squeak":"chiţăit","text2speech.tenor":"tenor","translate.categoryName":"Traducere","translate.defaultTextToTranslate":"salut","translate.translateBlock":"tradu [WORDS] în [LANGUAGE]","translate.viewerLanguage":"limbă","videoSensing.categoryName":"Detectare video","videoSensing.direction":"direcția","videoSensing.motion":"mișcarea","videoSensing.off":"oprit","videoSensing.on":"pornit","videoSensing.onFlipped":"pornit în oglindă","videoSensing.setVideoTransparency":"setează transparența video la [TRANSPARENCY]","videoSensing.sprite":"personaj","videoSensing.stage":"scenă","videoSensing.videoOn":"[ATTRIBUTE] video față de [SUBJECT]","videoSensing.videoToggle":"setează video ca [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"când mișcarea video > [REFERENCE]","wedo2.getDistance":"distanța","wedo2.getTiltAngle":"unghiul de înclinare [TILT_DIRECTION]","wedo2.isTilted":"este înclinat [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"înapoi","wedo2.motorDirection.forward":"înainte","wedo2.motorDirection.reverse":"inversează","wedo2.motorId.a":"motorul A","wedo2.motorId.all":"toate motoarele","wedo2.motorId.b":"motorul B","wedo2.motorId.default":"motor","wedo2.motorOff":"oprește [MOTOR_ID] ","wedo2.motorOn":"pornește [MOTOR_ID] ","wedo2.motorOnFor":"pornește [MOTOR_ID] pentru [DURATION] secunde","wedo2.playNoteFor":"cântă nota [NOTE] pentru [DURATION] secunde","wedo2.setLightHue":"setează culoare LED la [HUE]","wedo2.setMotorDirection":"setează direcția [MOTOR_ID] pe [MOTOR_DIRECTION]","wedo2.startMotorPower":"setează puterea [MOTOR_ID] la [POWER]","wedo2.tiltDirection.any":"în orice direcție","wedo2.tiltDirection.down":"în jos","wedo2.tiltDirection.left":"în stânga","wedo2.tiltDirection.right":"în dreapta","wedo2.tiltDirection.up":"în sus","wedo2.whenDistance":"când distanța [OP] [REFERENCE]","wedo2.whenTilted":"când este înclinat [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Culoare","paint.paintEditor.saturation":"Saturație","paint.paintEditor.brightness":"Strălucire","paint.paintEditor.costume":"Costum","paint.paintEditor.group":"Grupează","paint.paintEditor.ungroup":"Degrupează","paint.paintEditor.undo":"Anulează ultima modificare","paint.paintEditor.redo":"Refă acțiunea anulată","paint.paintEditor.forward":"În față","paint.paintEditor.backward":"În spate","paint.paintEditor.front":"Primul","paint.paintEditor.back":"Înapoi","paint.paintEditor.more":"Altele","paint.modeTools.brushSize":"Dimensiune","paint.modeTools.eraserSize":"Grosimea radierei","paint.modeTools.copy":"Copiază","paint.modeTools.paste":"Lipește","paint.modeTools.delete":"Șterge","paint.modeTools.curved":"Curbat","paint.modeTools.pointed":"Unghi","paint.modeTools.thickness":"Grosime","paint.modeTools.flipHorizontal":"Întoarce orizontal","paint.modeTools.flipVertical":"Întoarce vertical","paint.modeTools.filled":"Plin","paint.modeTools.outlined":"Contur","paint.paintEditor.bitmap":"Convertește la bitmap","paint.paintEditor.vector":"Convertește în format vectorial","paint.paintEditor.fill":"Umplere","paint.paintEditor.stroke":"Contur","paint.brushMode.brush":"Pensulă","paint.eraserMode.eraser":"Radieră","paint.fillMode.fill":"Umplere","paint.lineMode.line":"Linie","paint.ovalMode.oval":"Cerc","paint.rectMode.rect":"Dreptunghi","paint.reshapeMode.reshape":"Remodelează","paint.roundedRectMode.roundedRect":"Dreptunghi rotunjit","paint.selectMode.select":"Selectează","paint.textMode.text":"Text","paint.colorPicker.swap":"Schimbă","tw.alerts.autosaving":"Se creează punctul de recuperare…","tw.alerts.savedToDisk":"Salvat pe calculatorul tău.","tw.changeUsername.cannotChangeWhileRunning":"Numele de utilizator nu poate fi schimbat cât timp proiectul rulează.","tw.code":"Cod sursă","tw.featuredProjectsStudio":"Vezi atilierul pe Scratch.","tw.feedback":"Sugestii și Erori","tw.feedbackButton":"Spune-ți Părerea despre TurboWarp","tw.footer.credits":"Credite","tw.footer.disclaimer":"TurboWarp nu este conectat cu Scratch, Echipa Scratch, sau Fundația Scratch.","tw.footer.embed":"Încorporare","tw.footer.parameters":"Parametri URL","tw.footer.translate":"Ajutați la Traducerea TurboWarp","tw.fps":"{framerate} Cadre Pe Secundă","tw.gui.defaultProjectTitle":"Proiect","tw.guiDefaultTitle":"Rulează proiecte Scratch mai rapid","tw.home.credit":"Observații și Credite","tw.home.description":"TurboWarp este un modul pentru Scratch care care compilează (transpune) proiectele în JavaScript pentru a le rula foarte rapid. Încearcă-l prin scrierea ID-ului sau URL-ului unui proiect în caseta de mai sus sau alege unul dintre proiectele recomandate de mai jos.","tw.home.instructions":"Instrucțiuni","tw.invalidParameters.clones":"parametrul URL „clone” este invalid","tw.invalidParameters.fps":"parametrul URL „fps” este invalid","tw.loader.generic":"Se încarcă proiectul …","tw.menuBar.60off":"Oprește modul de 60 Cadre Pe Secundă (FPS)","tw.menuBar.60on":"Pornește modul de 60 Cadre Pe Secundă (FPS)","tw.menuBar.addons":"Extensii","tw.menuBar.advanced":"Avansat","tw.menuBar.changeUsername":"Schimbă Utilizatorul","tw.menuBar.cloudOff":"Oprește Variabilele Cloud","tw.menuBar.cloudOn":"Pornește Variabilele Cloud","tw.menuBar.cloudUnavailable":"Variabilele Cloud nu sunt valabile","tw.menuBar.cloudUnavailableAlert":"Nu se pot folosi variabilele cloud, cel mai probabil deoarece ai deschis editorul.","tw.menuBar.loadRestorePoint":"Încarcă punctul de recuperare","tw.menuBar.newFramerate":"Cadre Pe Secundă:","tw.menuBar.reportError1":"Unele script-uri nu au putut fi compilate (transpuse)","tw.menuBar.reportError2":"Aceasta este o eroare. Vă rugăm s-o raportați.","tw.menuBar.saveAs":"Salvează ca {file}","tw.menuBar.seeInside":"Vezi în interior","tw.privacy":"Politica de Confidențialitate","tw.settingsModal.disableCompiler":"Oprește Compilerul","tw.studioview.authorAttribution":"de {author}","tw.studioview.error":"A apărut o eroare la încărcarea paginii urmatoare cu proiecte.","tw.studioview.hoverText":"{title} de {author}","tw.twExtension.name":"Blocuri TurboWarp","tw.usernameModal.reset":"Resetează","tw.usernameModal.title":"Schimbă Utilizatorul","tw.viewFeaturedProjects":"Vezi proiectele recomandate (dați click).","tw.webglModal.description":"Din păcate se pare că browserul sau calculatorul tău {webGlLink}. Această tehnologie trebuie să existe ca acest site să ruleze. Încearcă să-ți actualizezi browserul și discurile de grafici sau repornește-ți calculatorul."},"ru":{"gui.alerts.tryAgain":"Попробуй еще раз","gui.alerts.download":"Скачать","gui.connection.reconnect":"Переподключиться","gui.backpack.costumeLabel":"костюм","gui.backpack.soundLabel":"звук","gui.backpack.scriptLabel":"скрипт","gui.backpack.spriteLabel":"спрайт","gui.backpack.header":"Рюкзак","gui.backpack.errorBackpack":"Ошибка при загрузке рюкзака","gui.backpack.loadingBackpack":"Загрузка…","gui.backpack.more":"Ещё","gui.backpack.emptyBackpack":"Рюкзак пуст","gui.unsupportedBrowser.label":"Браузер не поддерживается","gui.cards.all-tutorials":"Учебники","gui.cards.shrink":"Свернуть","gui.cards.expand":"Развернуть","gui.cards.close":"Закрыть","gui.cards.more-things-to-try":"Дополнительные возможности!","gui.cards.see-more":"Узнать больше","gui.comingSoon.message1":"Не волнуйтесь, мы работаем над этим {emoji}","gui.comingSoon.message2":"Скоро…","gui.comingSoon.message3":"Мы работаем над этим {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Устройства не обнаружены","gui.connection.auto-scanning.prescan":"Поставьте ваше устройство поблизости и начните поиск","gui.connection.auto-scanning.pressbutton":"Нажмите кнопку на вашем устройстве.","gui.connection.auto-scanning.start-search":"Начать поиск","gui.connection.connecting-searchbutton":"Поиск...","gui.connection.auto-scanning.try-again":"Попробуйте еще","gui.connection.connected":"Подключено","gui.connection.disconnect":"Отсоединить","gui.connection.go-to-editor":"Перейти к редактору","gui.connection.connecting-cancelbutton":"Соединяю...","gui.connection.error.errorMessage":"Ой, кажется что-то пошло не так.","gui.connection.error.tryagainbutton":"Попробуйте еще","gui.connection.error.helpbutton":"Помощь","gui.connection.peripheral-name-label":"Название устройства","gui.connection.connect":"Соединить","gui.connection.scanning.lookingforperipherals":"Идет поиск устройств","gui.connection.scanning.noPeripheralsFound":"Устройства не обнаружены","gui.connection.scanning.instructions":"Выберите свое устройство из списка","gui.connection.search":"Обновить","gui.connection.unavailable.installscratchlink":"Убедитесь в том, что вы установили и запустили Scratch Link","gui.connection.unavailable.enablebluetooth":"Проверьте, включён ли Bluetooth","gui.connection.unavailable.tryagainbutton":"Попробовать еще","gui.connection.unavailable.helpbutton":"Помощь","gui.controls.go":"Вперед","gui.controls.stop":"Остановить","gui.crashMessage.label":"Упс! Что-то пошло не так.","gui.crashMessage.errorNumber":"Ваша ошибка зарегистрирована как {errorId}","gui.crashMessage.reload":"Перезагрузить","gui.customProcedures.myblockModalTitle":"Создать блок","gui.customProcedures.addAnInputNumberText":"Добавить значение","gui.customProcedures.numberTextType":"число или текст","gui.customProcedures.addAnInputBoolean":"Добавить значение","gui.customProcedures.booleanType":"логическое","gui.customProcedures.addALabel":"Добавить подпись","gui.customProcedures.runWithoutScreenRefresh":"Запустить без обновления экрана","gui.customProcedures.cancel":"Отменить","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Направление","gui.directionPicker.rotationStyles.allAround":"Кругом","gui.directionPicker.rotationStyles.leftRight":"Влево/направо","gui.directionPicker.rotationStyles.dontRotate":"Не вращать","gui.gui.addExtension":"Добавить расширение","gui.gui.codeTab":"Код","gui.gui.backdropsTab":"Фоны","gui.gui.costumesTab":"Костюмы","gui.gui.soundsTab":"Звуки","gui.extensionLibrary.comingSoon":"Скоро…","gui.extensionLibrary.requires":"Требуются","gui.extensionLibrary.collaboration":"В сотрудничестве","gui.library.filterPlaceholder":"Поиск","gui.library.allTag":"Все","gui.loader.headline":"Загрузка проекта","gui.loader.creating":"Создать проект","gui.authorInfo.byUser":"от{username}","gui.menuBar.seeProjectPage":"Посмотреть страницу проекта","gui.menuBar.LanguageSelector":"выбор языка","gui.menuBar.tutorialsLibrary":"Руководства","gui.menuBar.restoreSprite":"Восстановить Спрайт","gui.menuBar.restoreSound":"Восстановить Звук","gui.menuBar.restoreCostume":"Восстановить Костюм","gui.menuBar.restore":"Восстановить","gui.menuBar.saveNow":"Сохранить сейчас","gui.menuBar.saveAsCopy":"Сохранить как копию","gui.menuBar.remix":"Ремикс","gui.menuBar.new":"Новый","gui.menuBar.file":"Файл","gui.menuBar.downloadToComputer":"Сохранить на свой компьютер","gui.menuBar.edit":"Редактировать","gui.menuBar.turboModeOff":"Выключить Турбо режим","gui.menuBar.turboModeOn":"Включить Турбо режим","gui.gui.projectTitlePlaceholder":"Название проекта","gui.menuBar.isShared":"Доступен всем","gui.menuBar.share":"Поделиться","gui.modal.help":"Помощь","gui.modal.back":"Назад","gui.monitor.listMonitor.empty":"(пусто)","gui.monitor.listMonitor.listLength":"длина {length}","gui.monitor.contextMenu.default":"стандартный вид","gui.monitor.contextMenu.large":"крупный вид","gui.monitor.contextMenu.slider":"рычажок","gui.monitor.contextMenu.sliderRange":"изменить диапазон рычажка","gui.monitor.contextMenu.import":"импорт","gui.monitor.contextMenu.export":"экспорт","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Играть","gui.playButton.stop":"Остановить","gui.gui.variableScopeOptionAllSprites":"Для всех спрайтов","gui.gui.variableScopeOptionSpriteOnly":"Только для этого спрайта","gui.gui.cloudVariableOption":"Облачная переменная (хранится на сервере)","gui.gui.variablePromptAllSpritesMessage":"Эта переменная будет доступна для всех спрайтов.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Отменить","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Остановить","gui.playbackStep.playMsg":"Проиграть","gui.playbackStep.loadingMsg":"Загрузка…","gui.playbackStep.saveMsg":"Сохранить","gui.playbackStep.reRecordMsg":"Перезаписать","gui.recordModal.title":"Записать звук","gui.recordingStep.beginRecord":"Начните записывать, кликнув кнопку ниже","gui.recordingStep.permission":"{arrow}Нам требуется ваше разрешение для использования вашего микрофона","gui.recordingStep.stop":"Остановить запись","gui.recordingStep.record":"Записать","gui.sliderModal.min":"Минимальное значение","gui.sliderModal.max":"Максимальное значение","gui.sliderModal.title":"Изменить диапазон рычажка","gui.sliderPrompt.cancel":"Отмена","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Звук","gui.soundEditor.play":"Играть","gui.soundEditor.stop":"Остановить","gui.soundEditor.copy":"Копировать","gui.soundEditor.paste":"Вставить","gui.soundEditor.copyToNew":"Копировать в Новый Звук","gui.soundEditor.delete":"Удалить","gui.soundEditor.save":"Сохранить","gui.soundEditor.undo":"Отменить","gui.soundEditor.redo":"Вернуть","gui.soundEditor.faster":"Быстрее","gui.soundEditor.slower":"Медленнее","gui.soundEditor.echo":"Эхо","gui.soundEditor.robot":"Робот","gui.soundEditor.louder":"Громче","gui.soundEditor.softer":"Тише","gui.soundEditor.reverse":"Развернуть","gui.soundEditor.fadeOut":"Затухание","gui.soundEditor.fadeIn":"Усиление","gui.soundEditor.mute":"Заглушить","gui.SpriteInfo.spritePlaceholder":"Название","gui.SpriteInfo.sprite":"Спрайт","gui.SpriteInfo.show":"Показать","gui.SpriteInfo.size":"Размер","gui.spriteSelectorItem.contextMenuDuplicate":"дублировать","gui.spriteSelectorItem.contextMenuExport":"экспорт","gui.spriteSelectorItem.contextMenuDelete":"удалить","gui.spriteSelector.addSpriteFromLibrary":"Выбрать спрайт","gui.spriteSelector.addSpriteFromPaint":"Нарисовать","gui.spriteSelector.addSpriteFromSurprise":"Сюрприз","gui.spriteSelector.addSpriteFromFile":"Загрузить спрайт","gui.stageHeader.stageSizeLarge":"Большая сцена","gui.stageHeader.stageSizeSmall":"Маленькая сцена","gui.stageHeader.stageSizeFull":"Перейти в полноэкранный режим","gui.stageHeader.stageSizeUnFull":"Выйти из полноэкранного режима","gui.stageHeader.fullscreenControl":"Полноэкранный режим","gui.spriteSelector.addBackdropFromLibrary":"Выбрать фон","gui.stageSelector.addBackdropFromPaint":"Нарисовать","gui.stageSelector.addBackdropFromSurprise":"Сюрприз","gui.stageSelector.addBackdropFromFile":"Загрузить фон","gui.stageSelector.stage":"Сцена","gui.stageSelector.backdrops":"Фоны","gui.telemetryOptIn.label":"Отправь статистику, чтобы улучшить Scratch","gui.telemetryOptIn.body1":"Команда Scratch всегда хочет понять как Scratch используется во всем мире. Чтобы помочь в поддержке, вы можете разрешить Scratch автоматически отправлять информацию об использовании команде Scratch!","gui.telemetryOptIn.body2":"Мы собираем информацию о языке, использовании блоков и некоторые других событий, как сохранение, загрузка и загрузка проекта. Мы НЕ собираем личную информацию. Пожалуйста, посмотрите {privacyPolicyLink} для большего ознакомления. ","gui.telemetryOptIn.privacyPolicyLink":"Политика конфиденциальности","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Турбо режим","gui.webglModal.label":"Ваш браузер не поддерживает WebGL","gui.webglModal.webgllink":"не поддерживает WebGL","gui.costumeLibrary.chooseABackdrop":"Выбрать фон","gui.costumeLibrary.chooseACostume":"Выбрать костюм","gui.costumeTab.addBackdropFromLibrary":"Выбрать фон","gui.costumeTab.addCostumeFromLibrary":"Выбрать костюм","gui.costumeTab.addBlankCostume":"Рисовать","gui.costumeTab.addSurpriseCostume":"Сюрприз","gui.costumeTab.addFileBackdrop":"Загрузить фон","gui.costumeTab.addFileCostume":"Загрузить костюм","gui.extensionLibrary.chooseAnExtension":"Выбрать дополнение","gui.extensionLibrary.extensionUrl":"Введи URL расширения","gui.monitors.importListColumnPrompt":"Какая колонка должна быть использована (1- {numberOfColumns})? ","gui.recordingStep.alertMsg":"Не удалось начать запись","gui.soundLibrary.chooseASound":"Выбрать звук","gui.soundTab.fileUploadSound":"Загрузить звук","gui.soundTab.surpriseSound":"Сюрприз","gui.soundTab.recordSound":"Записать","gui.soundTab.addSoundFromLibrary":"Выбрать звук","gui.spriteLibrary.chooseASprite":"Выбрать спрайт","gui.tipsLibrary.tutorials":"Выбрать руководство","gui.alerts.createsuccess":"Создан новый проект.","gui.alerts.createcopysuccess":"Проект сохранён как копия.","gui.alerts.createremixsuccess":"Проект сохранён как ремикс.","gui.alerts.creating":"Создание нового ...","gui.alerts.creatingCopy":"Копирование проекта ...","gui.alerts.creatingRemix":"Создание ремикса проекта ...","gui.alerts.creatingError":"Не удалось создать проект. Попробуйте еще раз!","gui.alerts.savingError":"Проект не может быть сохранён","gui.alerts.savesuccess":"Проект сохранён.","gui.alerts.saving":"Сохранение проекта...","gui.alerts.cloudInfo":"Не забудьте, что облачные переменные могут быть только цифрами, а не буквами или символами. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Узнать больше.","gui.alerts.importing":"Импортируется...","gui.defaultProject.variable":"моя переменная","gui.extension.music.name":"Музыка","gui.extension.music.description":"Играть на инструментах и барабанах.","gui.extension.pen.name":"Перо","gui.extension.pen.description":"Рисуй своими спрайтами.","gui.extension.videosensing.name":"Видео распознавание","gui.extension.videosensing.description":"Распознай движение с видео камеры","gui.extension.text2speech.name":"Текст в речь","gui.extension.text2speech.description":"Оживи свои проекты речью!","gui.extension.translate.name":"Перевести","gui.extension.translate.description":"Переводи текст на другие языки.","gui.extension.makeymakey.description":"Превратить что угодно в ключ.","gui.extension.microbit.description":"Свяжи свои проекты с миром","gui.extension.microbit.connectingMessage":"Соединение","gui.extension.ev3.description":"Создавайте интерактивных роботов.","gui.extension.ev3.connectingMessage":"Подключение. Убедитесь, что пин-код на вашем EV3 задан, как 1234","gui.extension.boost.description":"Вдохните в робота жизнь.","gui.extension.boost.connectingMessage":"Соединение","gui.extension.wedo2.description":"Стройте с помощью моторов и датчиков.","gui.extension.wedo2.connectingMessage":"Соединение","gui.extension.gdxfor.description":"Измеряет толкающие и тянущие усилия, движение и повороты.","gui.extension.gdxfor.connectingMessage":"Соединение","gui.libraryTags.all":"Все","gui.libraryTags.animals":"Животные","gui.libraryTags.dance":"Танец","gui.libraryTags.effects":"Эффекты","gui.libraryTags.fantasy":"Фантастика","gui.libraryTags.fashion":"Мода","gui.libraryTags.food":"Еда","gui.libraryTags.indoors":"В помещении","gui.libraryTags.loops":"Циклы","gui.libraryTags.music":"Музыка","gui.libraryTags.notes":"Заметки","gui.libraryTags.outdoors":"На открытом воздухе","gui.libraryTags.patterns":"Узоры","gui.libraryTags.people":"Люди","gui.libraryTags.percussion":"Перкуссия","gui.libraryTags.space":"Космос","gui.libraryTags.sports":"Спорт","gui.libraryTags.underwater":"Подводный мир","gui.libraryTags.voice":"Голос","gui.libraryTags.wacky":"Безумцы","gui.libraryTags.animation":"Анимация","gui.libraryTags.art":"Искусство","gui.libraryTags.games":"Игры","gui.libraryTags.stories":"Истории","gui.libraryTags.letters":"Буквы","gui.opcodeLabels.direction":"направление","gui.opcodeLabels.xposition":"положение x","gui.opcodeLabels.yposition":"положение y","gui.opcodeLabels.size":"размер","gui.opcodeLabels.costumename":"имя костюма","gui.opcodeLabels.costumenumber":"номер костюма","gui.opcodeLabels.backdropname":"имя фона","gui.opcodeLabels.backdropnumber":"номер фона","gui.opcodeLabels.volume":"громкость","gui.opcodeLabels.tempo":"темп","gui.opcodeLabels.answer":"ответ","gui.opcodeLabels.loudness":"громкость","gui.opcodeLabels.username":"имя пользователя","gui.opcodeLabels.year":"год","gui.opcodeLabels.month":"месяц","gui.opcodeLabels.date":"дата","gui.opcodeLabels.dayofweek":"день недели","gui.opcodeLabels.hour":"час","gui.opcodeLabels.minute":"минута","gui.opcodeLabels.second":"секунда","gui.opcodeLabels.timer":"таймер","gui.sharedMessages.backdrop":"фон {index}","gui.sharedMessages.costume":"костюм {index}","gui.sharedMessages.sprite":"Спрайт {index}","gui.sharedMessages.pop":"поп","gui.sharedMessages.replaceProjectWarning":"Заменить содержимое текущего проекта?","gui.sharedMessages.loadFromComputerTitle":"Загрузить с компьютера","boost.color.any":"любой цвет","boost.color.black":"черный","boost.color.blue":"синий","boost.color.green":"зеленый","boost.color.red":"красный","boost.color.white":"белый","boost.color.yellow":"желтый","boost.getMotorPosition":"позиция мотора [MOTOR_REPORTER_ID]","boost.getTiltAngle":"угол наклона [TILT_DIRECTION]","boost.motorDirection.backward":"туда","boost.motorDirection.forward":"сюда","boost.motorDirection.reverse":"изменить направление","boost.motorOff":"выключить мотор [MOTOR_ID]","boost.motorOn":"включить мотор [MOTOR_ID]","boost.motorOnFor":"включить мотор [MOTOR_ID] на [DURATION] секунд","boost.motorOnForRotation":"включить мотор [MOTOR_ID] на [ROTATION] оборотов","boost.seeingColor":"виден [COLOR] кирпич?","boost.setLightHue":"установить цвет лампочки [HUE]","boost.setMotorDirection":"установить направление мотора [MOTOR_ID] в [MOTOR_DIRECTION]","boost.setMotorPower":"установить скорость [MOTOR_ID] в [POWER] %","boost.tiltDirection.any":"любая","boost.tiltDirection.down":"вниз","boost.tiltDirection.left":"налево","boost.tiltDirection.right":"направо","boost.tiltDirection.up":"вверх","boost.whenColor":"когда виден [COLOR] кирпич","boost.whenTilted":"когда наклонён [TILT_DIRECTION_ANY]","ev3.beepNote":"играть ноту [NOTE] [TIME] секунд","ev3.buttonPressed":"кнопка [PORT] нажата?","ev3.getBrightness":"яркость","ev3.getDistance":"расстояние","ev3.getMotorPosition":"позиция мотора [PORT]","ev3.motorSetPower":"мотор [PORT] установить мощность [POWER] %","ev3.motorTurnClockwise":"мотор [PORT] повернуть сюда на [TIME] секунд","ev3.motorTurnCounterClockwise":"мотор [PORT] повернуть туда на [TIME] секунд","ev3.whenBrightnessLessThan":"когда яркость < [DISTANCE]","ev3.whenButtonPressed":"когда кнопка [PORT] нажата","ev3.whenDistanceLessThan":"когда расстояние < [DISTANCE]","gdxfor.getAcceleration":"ускорение [DIRECTION]","gdxfor.getForce":"сила","gdxfor.getSpin":"скорость вращения [DIRECTION]","gdxfor.getTilt":"угол наклона [TILT]","gdxfor.isFreeFalling":"падение?","gdxfor.isTilted":"наклонён [TILT]?","gdxfor.pulled":"вытянут","gdxfor.pushed":"нажат","gdxfor.shaken":"встряхнут","gdxfor.startedFalling":"начал падать","gdxfor.tiltDirectionMenu.any":"любая","gdxfor.tiltDirectionMenu.back":"задний","gdxfor.tiltDirectionMenu.front":"передний","gdxfor.tiltDirectionMenu.left":"левый ","gdxfor.tiltDirectionMenu.right":"правый","gdxfor.turnedFaceDown":"повернут лицом вниз","gdxfor.turnedFaceUp":"повернут лицом вверх","gdxfor.whenForcePushedOrPulled":"когда датчик приложения силы [PUSH_PULL]","gdxfor.whenGesture":"когда [GESTURE]","gdxfor.whenTilted":"когда наклонён [TILT]","makeymakey.downArrow":"стрелка вниз","makeymakey.downArrowShort":"вниз","makeymakey.leftArrow":"стрелка влево","makeymakey.leftArrowShort":"влево","makeymakey.rightArrow":"стрелка вправо","makeymakey.rightArrowShort":"направо","makeymakey.spaceKey":"пробел","makeymakey.upArrow":"стрелка вверх","makeymakey.upArrowShort":"вверх","makeymakey.whenKeyPressed":"когда [KEY] клавиша нажата","makeymakey.whenKeysPressedInOrder":"при нажатии по порядку [SEQUENCE]","microbit.buttonsMenu.any":"любой из","microbit.clearDisplay":"очистить дисплей","microbit.defaultTextToDisplay":"Привет!","microbit.displaySymbol":"отобразить [MATRIX]","microbit.displayText":"показать текст [TEXT]","microbit.gesturesMenu.jumped":"подпрыгнули","microbit.gesturesMenu.moved":"передвинулись","microbit.gesturesMenu.shaken":"встряхнули","microbit.isButtonPressed":"[BTN] кнопка нажата?","microbit.isTilted":"наклонён [DIRECTION]?","microbit.pinStateMenu.off":"выключить","microbit.pinStateMenu.on":"включить","microbit.tiltAngle":"угол наклона [DIRECTION]","microbit.tiltDirectionMenu.any":"любой из","microbit.tiltDirectionMenu.back":"назад","microbit.tiltDirectionMenu.front":"вперёд","microbit.tiltDirectionMenu.left":"влево","microbit.tiltDirectionMenu.right":"направо","microbit.whenButtonPressed":"когда [BTN] кнопка нажата","microbit.whenGesture":"когда [GESTURE]","microbit.whenPinConnected":"когда подключён пин [PIN]","microbit.whenTilted":"когда наклонён [DIRECTION]","music.categoryName":"Музыка","music.changeTempo":"изменить темп на [TEMPO]","music.drumBass":"(2) Большой барабан","music.drumBongo":"(13) Бонго","music.drumCabasa":"(15) Кабаса","music.drumClaves":"(9) Клаве","music.drumClosedHiHat":"(16) Закрытый Хай-Хэт","music.drumConga":"(14) Конга","music.drumCowbell":"(11) Ковбелл","music.drumCrashCymbal":"(4) Крэш-тарелка","music.drumCuica":"(18) Куика","music.drumGuiro":"(16) Гуиро","music.drumHandClap":"(8) Хлопок","music.drumOpenHiHat":"(5) Открытый Хай-Хет","music.drumSideStick":"(3) Римшот","music.drumSnare":"(1) Малый барабан","music.drumTambourine":"(7) Бубен","music.drumTriangle":"(12) Треугольник","music.drumVibraslap":"(17) Вибраслэп","music.drumWoodBlock":"(10) Коробочка","music.getTempo":"темп","music.instrumentBass":"(6) Бас","music.instrumentBassoon":"(14) Фагот","music.instrumentCello":"(8) Виолончель","music.instrumentChoir":"(15) Хор","music.instrumentClarinet":"(10) Кларнет","music.instrumentElectricGuitar":"(5) Электрогитара","music.instrumentElectricPiano":"(2) Электрическое пианино","music.instrumentFlute":"(12) Флейта","music.instrumentGuitar":"(4) Гитара","music.instrumentMarimba":"(19) Маримба","music.instrumentMusicBox":"(17) Музыкальная шкатулка","music.instrumentOrgan":"(3) Орган","music.instrumentPiano":"(1) Фортепиано","music.instrumentPizzicato":"(7) Пиццикато","music.instrumentSaxophone":"(11) Саксофон","music.instrumentSteelDrum":"(18) Стальной барабан","music.instrumentSynthLead":"(20) Ведущий синтезатор","music.instrumentSynthPad":"(21) Синтезатор с функциями драм-машины","music.instrumentTrombone":"(9) Тромбон","music.instrumentVibraphone":"(16) Вибрафон","music.instrumentWoodenFlute":"(13) Деревянная флейта","music.midiPlayDrumForBeats":"барабану играть [DRUM] [BEATS] бита","music.midiSetInstrument":"изменить инструмент на [INSTRUMENT]","music.playDrumForBeats":"барабану играть [DRUM] [BEATS] бита","music.playNoteForBeats":"играй ноту [NOTE] [BEATS] бита","music.restForBeats":"пауза в течение [BEATS] бит","music.setInstrument":"изменить инструмент на [INSTRUMENT]","music.setTempo":"установить темп [TEMPO]","pen.categoryName":"Перо","pen.changeColorParam":"изменить [COLOR_PARAM] пера на [VALUE]","pen.changeHue":"изменить цвет пера на [HUE]","pen.changeShade":"изменить оттенок пера на [SHADE]","pen.changeSize":"изменить размер пера на [SIZE]","pen.clear":"стереть всё","pen.colorMenu.brightness":"яркость","pen.colorMenu.color":"цвет","pen.colorMenu.saturation":"насыщенность","pen.colorMenu.transparency":"прозрачность","pen.penDown":"опустить перо","pen.penUp":"поднять перо","pen.setColor":"установить для пера цвет [COLOR]","pen.setColorParam":"установить [COLOR_PARAM] пера [VALUE]","pen.setHue":"установить цвет пера [HUE]","pen.setShade":"установить оттенок пера [SHADE]","pen.setSize":"установить размер пера [SIZE]","pen.stamp":"печать","text2speech.alto":"альт","text2speech.categoryName":"Текст в речь","text2speech.defaultTextToSpeak":"привет","text2speech.giant":"гигант","text2speech.kitten":"котенок","text2speech.setLanguageBlock":"установить [LANGUAGE] язык","text2speech.setVoiceBlock":"установить [VOICE] голос","text2speech.speakAndWaitBlock":"сказать [WORDS] ","text2speech.squeak":"писк","text2speech.tenor":"тенор","translate.categoryName":"Перевести","translate.defaultTextToTranslate":"привет","translate.translateBlock":"перевести [WORDS] на [LANGUAGE]","translate.viewerLanguage":"язык","videoSensing.categoryName":"Видео Распознавание","videoSensing.direction":"направление","videoSensing.motion":"движение","videoSensing.off":"выключить","videoSensing.on":"включить","videoSensing.onFlipped":"включить в обратную","videoSensing.setVideoTransparency":"установить прозрачность видео [TRANSPARENCY]","videoSensing.sprite":"спрайт","videoSensing.stage":"сцена","videoSensing.videoOn":"видео [ATTRIBUTE] на [SUBJECT]","videoSensing.videoToggle":"включить видео [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"когда скорость видео > [REFERENCE]","wedo2.getDistance":"расстояние","wedo2.getTiltAngle":"угол наклона[TILT_DIRECTION]","wedo2.isTilted":"наклонён [TILT_DIRECTION_ANY] ?","wedo2.motorDirection.backward":"туда","wedo2.motorDirection.forward":"сюда","wedo2.motorDirection.reverse":"изменить направление","wedo2.motorId.a":"мотор A","wedo2.motorId.all":"все моторы","wedo2.motorId.b":"мотор B","wedo2.motorId.default":"мотор","wedo2.motorOff":"выключить [MOTOR_ID]","wedo2.motorOn":"включить [MOTOR_ID]","wedo2.motorOnFor":"включить [MOTOR_ID] на [DURATION] секунд","wedo2.playNoteFor":"играть ноту [NOTE] [DURATION] секунд","wedo2.setLightHue":"установить цвет лампочки [HUE]","wedo2.setMotorDirection":"установить направление [MOTOR_ID] в [MOTOR_DIRECTION]","wedo2.startMotorPower":"установить мощность [MOTOR_ID] в [POWER]","wedo2.tiltDirection.any":"любая","wedo2.tiltDirection.down":"вниз","wedo2.tiltDirection.left":"влево","wedo2.tiltDirection.right":"направо","wedo2.tiltDirection.up":"вверх","wedo2.whenDistance":"когда расстояние [OP] [REFERENCE]","wedo2.whenTilted":"когда наклонён [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Цвет","paint.paintEditor.saturation":"Насыщенность","paint.paintEditor.brightness":"Яркость","paint.paintEditor.costume":"Костюм","paint.paintEditor.group":"Группировать","paint.paintEditor.ungroup":"Разгруппировать","paint.paintEditor.undo":"Отменить","paint.paintEditor.redo":"Переделать","paint.paintEditor.forward":"Вперёд","paint.paintEditor.backward":"Назад","paint.paintEditor.front":"На передний план","paint.paintEditor.back":"На задний план","paint.paintEditor.more":"Ещё","paint.modeTools.brushSize":"Размер","paint.modeTools.eraserSize":"Ширина ластика","paint.modeTools.copy":"Копировать","paint.modeTools.paste":"Вставить","paint.modeTools.delete":"Удалить","paint.modeTools.curved":"Изогнуть","paint.modeTools.pointed":"Заострить","paint.modeTools.thickness":"Толщина","paint.modeTools.flipHorizontal":"Отразить по горизонтали","paint.modeTools.flipVertical":"Отразить по вертикали","paint.modeTools.filled":"Залитый","paint.modeTools.outlined":"Обведённый","paint.paintEditor.bitmap":"Конвертировать в растровую графику","paint.paintEditor.vector":"Конвертировать в векторную графику","paint.paintEditor.fill":"Заливка","paint.paintEditor.stroke":"Контур","paint.brushMode.brush":"Кисть","paint.eraserMode.eraser":"Ластик","paint.fillMode.fill":"Заливка","paint.lineMode.line":"Линия","paint.ovalMode.oval":"Круг","paint.rectMode.rect":"Прямоугольник","paint.reshapeMode.reshape":"Изменение формы","paint.roundedRectMode.roundedRect":"Скруглённый Прямоугольник","paint.selectMode.select":"Выбрать","paint.textMode.text":"Текст","paint.colorPicker.swap":"Заменить","tw.alerts.autosaving":"Создание точки восстановления...","tw.alerts.lostPeripheralConnection":"Потеря соединения с {extensionName}.","tw.alerts.savedToDisk":"Сохранено на ваш компьютер.","tw.backpack.rename":"Новое имя:","tw.browserModal.desc":"Убедитесь, что Вы используете последнюю версию Google Chrome, Mozilla Firefox, Microsoft Edge или Apple Safari.","tw.cantUseCloud":"Хотя вы можете создавать облачные переменные, они не будут работать до тех пор, пока проект не будет загружен в Scratch или преобразован с помощью такого инструмента, как {packager}.","tw.changeUsername.cannotChangeWhileRunning":"Имя пользователя не может быть изменено, пока проект запущен.","tw.cloudVariableBadge":"Этот проект использует облачные переменные. TurboWarp использует свой сервер облачных переменных, не связанный со Scratch. Обратите внимание, что пользователи могут быть не такими, как их имя пользователя. {learnMore}","tw.code":"Исходный код","tw.confirmIncompatibleExtension":"Это дополнение не совместимо со Scratch. Проекты, которые используют это дополнение, не могут быть опубликованы на сайт Scratch. Вы уверены, что хотите включить это дополнение?","tw.customExtension.description":"Загрузить пользовательские дополнения из адресной строки. Для разработчиков. Эксперементальная функция.","tw.customExtension.name":"Пользовательское дополнение","tw.featuredProjectsStudio":"Посмотреть студию на Scratch.","tw.feedback":"Обратная связь и ошибки","tw.feedbackButton":"Обратная связь","tw.footer.credits":"Благодарности","tw.footer.disclaimer":"TurboWarp не связан с Scratch, Командой Scratch или Фондом Scratch .","tw.footer.donate":"Пожертвование","tw.footer.embed":"Встраивание","tw.footer.fosshost":"Хостинг предоставлен Fosshost","tw.footer.parameters":"Параметры URL","tw.footer.translate":"Помочь переводить TurboWarp","tw.gui.crashMessage.description":"Нам очень жаль, но похоже, что страница дала сбой. Пожалуйста, обновите страницу, чтобы повторить попытку.","tw.gui.defaultProjectTitle":"Проект","tw.guiDefaultTitle":"Запускайте проекты Scratch быстрее","tw.home.credit":"Примечания и благодарности","tw.home.description":"TurboWarp - это мод Scratch, который компилирует проекты в JavaScript, чтобы они работали быстрее. Попробуйте ввести ссылку на проект выше или выберете из избранных проектов ниже.","tw.home.instructions":"Инструкции","tw.input.tooltip":"Скопируйте ссылку на проект Scratch и вставьте её сюда!","tw.interpolationEnabled":"Интерполяция","tw.invalidParameters.clones":"Параметр \\"clone\\" в URL некорректен","tw.invalidParameters.fps":"Параметр \\"fps\\" в URL некорректен","tw.loadError":"Не удалось загрузить проект: {error}","tw.loader.assets.known":"Скачивание ресурсов ({complete} / {total}) ...","tw.loader.assets.unknown":"Скачивание ресурсов …","tw.loader.data":"Загрузка данных проекта ...","tw.loader.generic":"Загрузка проекта ...","tw.menuBar.60off":"Выключить режим 60 FPS","tw.menuBar.60on":"Включить режим 60 FPS","tw.menuBar.addons":"Аддоны","tw.menuBar.advanced":"Дополнительно","tw.menuBar.changeUsername":"Изменить имя пользователя","tw.menuBar.cloudOff":"Отключить облачные переменные","tw.menuBar.cloudOn":"Включить облачные переменные","tw.menuBar.cloudUnavailable":"Облачные переменные недоступны","tw.menuBar.cloudUnavailableAlert":"Невозможно использовать облачные переменные, скорее всего, потому, что вы открыли редактор.","tw.menuBar.loadRestorePoint":"Загрузить точку восстановления","tw.menuBar.moreSettings":"Расширенные настройки","tw.menuBar.newFramerate":"Новая частота кадров:","tw.menuBar.package":"Упаковать проект","tw.menuBar.reportError1":"Некоторые скрипты не могут быть скомпилированы.","tw.menuBar.reportError2":"Это ошибка. Пожалуйста, сообщите о ней.","tw.menuBar.saveAs":"Сохранить как {file}","tw.menuBar.seeInside":"Войти внутрь проекта","tw.mono":"Моно","tw.oldDownload":"Сохранить в отдельный файл...","tw.openAdvanced":"Открыть дополнительные настройки","tw.paint.alpha":"Непрозрачность","tw.privacy":"Политика конфиденциальности","tw.restorePoint.confirm":"Редактор автоматически создаёт одну точку восстановления на случай, если что-то пойдёт не так и вы забудете сохраниться. Вы не должны полагаться на эту функцию, и мы не можем гарантировать, что она может восстановить ваш проект. Попробовать загрузить её?","tw.restorePoint.loadFail":"Не удалось загрузить точку восстановления: {error}","tw.saveAs":"Сохранить как...","tw.saveTo":"Сохранить в {file}","tw.scratchUnsafeCloud":"Если вы сделаете эту облачную переменную, проект превысит лимит Scratch в {number} переменных, и некоторые переменные не будут работать, если вы загрузите проект в Scratch.","tw.settingsModal.customStageSize":"Пользовательский размер сцены:","tw.settingsModal.customStageSizeHelp":"Изменяет размер сцены из 480х360 на что-то другое. Попробуйте использовать 640х360, чтобы сделать сцену широкоэкранной. Лишь некоторые проекты будут работать правильно с этой настройкой.","tw.settingsModal.dangerZone":"Опасная зона","tw.settingsModal.disableCompiler":"Отключить компилятор","tw.settingsModal.disableCompilerHelp":"Отключает компилятор TurboWarp. Рекомендуется включать эту настройку, когда вы редактируете проект, чтобы скрипты обновлялись моментально. В других случаях, не включайте эту настройку.","tw.settingsModal.featured":"Избранное","tw.settingsModal.fps":"60 FPS (Пользовательские FPS)","tw.settingsModal.fpsHelp":"Выполняет скрипты 60 раз в секунду вместо 30. Большинство проектов не будут работать должным образом, если этот параметр включен. Если это так, вам следует попробовать интерполяцию с отключенным режимом 60 FPS. {customFramerate}.","tw.settingsModal.fpsHelp.customFramerate":"Нажмите, чтобы использовать частоту кадров другую, чем 30 или 60","tw.settingsModal.help":"Нажмите для справки","tw.settingsModal.highQualityPen":"Перо в высоком качестве","tw.settingsModal.highQualityPenHelp":"Позволяет выполнять рендеринг проектов пера с более высоким разрешением и отключает некоторое округление координат в редакторе. Этот параметр полезен не для всех проектов, и это может повлиять на производительность.","tw.settingsModal.infiniteClones":"Бесконечные клоны","tw.settingsModal.infiniteClonesHelp":"Отключает ограничение Scratch в 300 клонов.","tw.settingsModal.interpolation":"Интерполяция","tw.settingsModal.interpolationHelp":"Делает, чтобы проекты производились более плавно, интерполируя движение спрайтов. Не используйте интерполяцию в 3D проектах, проектах с трассировкой лучей, проектах, выполненных пером и медленных проектах, интерполяция сделает их медленнее и не сделает их более плавными.","tw.settingsModal.largeStageWarning":"Использовать настолько большой пользовательский размер сцены не рекомендуется! Лучше, используйте сцену меньшего размера, но с таким же соотношением сторон изображения и дайте полноэкранному режиму увеличить сцену так, чтобы она могла подойти по размерам к дисплею пользователя.","tw.settingsModal.removeFencing":"Убрать рамку","tw.settingsModal.removeFencingHelp":"Позволяет спрайтам выходить за рамки сцены, становится настолько большими или маленькими, насколько они захотят, и делает, чтобы блоки касания работали за рамками сцены.","tw.settingsModal.removeLimits":"Убрать ограничения","tw.settingsModal.removeMiscLimits":"Удалить Разные Ограничения","tw.settingsModal.removeMiscLimitsHelp":"Убирает лимиты звуков и размера пера.","tw.settingsModal.storeProjectOptions":"Сохранить настройки проекта","tw.settingsModal.storeProjectOptionsHelp":"Сохранение выбранных настроек в проекте, чтобы они автоматически применялись при загрузке этого проекта TurboWarp\'ом. Warp-таймер и отключение компилятора не будут сохранены.","tw.settingsModal.title":"Расширенные настройки","tw.settingsModal.warpTimer":"Warp таймер","tw.settingsModal.warpTimerHelp":"Проверяет, какие скрипты застряли в долгом или бесконечном цикле и понижает частоту кадров, вместо того, чтобы он застыл пока цикл не завершится. Исправляет большую часть критических ошибок, но это негативно отражается на скорости проекта, поэтому он включается по умолчанию только в редакторе.","tw.spriteSelectorItem.rename":"переименовать","tw.stereo":"Стерео","tw.stereoAlert":"Редактирование этого стерео звука необратимо преобразует его в моно звук.","tw.studioview.authorAttribution":"от {author}","tw.studioview.error":"Произошла ошибка во время загрузки следующей страницы проектов.","tw.studioview.hoverText":"{title} от {author}","tw.tooLarge":"Этот звук может быть слишком большим для загрузки в Scratch.","tw.twExtension.description":"Странные новые блоки. Не совместимы со Scratch.","tw.twExtension.name":"Блоки TurboWarp","tw.unshared.1":"В некий момент в будущем проекты без общего доступа больше не будут доступны через их ID из-за предстоящих изменений в Scratch API.","tw.unshared.2":"Для получения большей информации посетите этот сайт: {link}","tw.usernameModal.help":"Это значение будет сохранено в данных вашего браузера. Оно будет использоваться, когда вы используете проекты, в которых есть облачные переменные.","tw.usernameModal.help2":"Значения, которые не соответствуют настоящим именам пользователя будут заблокированными сервером облачных переменных. Мы рекомендуем оставлять это значение, которым оно есть или изменять его на своё имя пользователя в Scratch.","tw.usernameModal.mustChange":"Извините, сервер облачных переменных считает, что ваше имя пользователя может быть небезопасным. Измените имя пользователя на другое или {resetIt}.","tw.usernameModal.mustChange.resetIt":"сбросьте его (рекомендуется)","tw.usernameModal.reset":"Сбросить","tw.usernameModal.title":"Изменить имя пользователя","tw.viewFeaturedProjects":"Нажмите, чтобы посмотреть избранные проекты.","tw.viewOnScratch":"Посмотреть проект на Scratch","tw.webglModal.description":"Похоже, ваш компьютер или браузер {webGlLink}. Эта технология нужна для работы TurboWarp. Попробуйте обновить драйвера и ваш браузер или перезагрузить компьютер."},"nso":{"gui.alerts.tryAgain":"Leka Gape","gui.alerts.download":"Fegolla","gui.connection.reconnect":"Kgokaganya gape","gui.backpack.costumeLabel":"khosetšhumo","gui.backpack.soundLabel":"modumo","gui.backpack.scriptLabel":"sengwalwa","gui.backpack.spriteLabel":"motšeakarolo","gui.backpack.header":"Mokotlana wa go atha magetleng","gui.backpack.errorBackpack":"Go bile le bothata go laiša morwalana wa go atha magetleng","gui.backpack.loadingBackpack":"E a Laiša...","gui.backpack.more":"Go feta","gui.backpack.emptyBackpack":"Morwalana wa go atha magetleng ga o na selo","gui.unsupportedBrowser.label":"Sephetli ga se thekgwe","gui.cards.all-tutorials":"Dithutišo","gui.cards.shrink":"Hunyela","gui.cards.expand":"Godiša","gui.cards.close":"Tswalela","gui.cards.more-things-to-try":"Dilo tšeo di oketšegilego tšeo o ka di lekago!","gui.cards.see-more":"Bona tše oketšegilego","gui.comingSoon.message1":"O se belaele, re šomana nayo{emoji}","gui.comingSoon.message2":"E a tla e se kgale...","gui.comingSoon.message3":"Re gare re šoma ka yona{emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Ga go na didirišwa tšeo di humanwego","gui.connection.auto-scanning.prescan":"Swara sedirišwa sa gago kgauswi gomme o thome go nyaka","gui.connection.auto-scanning.pressbutton":"Kgotla konopi go sedirišwa sa gago","gui.connection.auto-scanning.start-search":"Thomiša go nyaka","gui.connection.connecting-searchbutton":"Nyaka...","gui.connection.auto-scanning.try-again":"Leka gape","gui.connection.connected":"Kgokagane","gui.connection.disconnect":"Hakolla","gui.connection.go-to-editor":"Eya go Thulaganyo","gui.connection.connecting-cancelbutton":"Kgokaganya...","gui.connection.error.errorMessage":"Mmalo, go itaetša o kare se sengwe ga se se sepele gabotse.","gui.connection.error.tryagainbutton":"Leka gape","gui.connection.error.helpbutton":"Thuša","gui.connection.peripheral-name-label":"Leina la sedirišwa","gui.connection.connect":"Kgokaganya","gui.connection.scanning.lookingforperipherals":"Go nyaka didirišwa","gui.connection.scanning.noPeripheralsFound":"Ga go na didirišwa tšeo di humanwego","gui.connection.scanning.instructions":"Kgetha sedirišwa sa gago tatelanong ya ka godimo","gui.connection.search":"Tsošeletša","gui.connection.unavailable.installscratchlink":"Netefatša gore o na e tsentšhitšwe Scratch Link ebile e a šoma","gui.connection.unavailable.enablebluetooth":"Lebelela gore Bluetooth e tšhumilwe","gui.connection.unavailable.tryagainbutton":"Leka gape","gui.connection.unavailable.helpbutton":"Thuša","gui.controls.go":"Sepela","gui.controls.stop":"Ema","gui.crashMessage.label":"Mmalo! se sengwe ga se a sepela gabotse.","gui.crashMessage.errorNumber":"Phošo ya gago e tsentšhitšwe ka boitsebišo{errorId}","gui.crashMessage.reload":"Laišaleswa","gui.customProcedures.myblockModalTitle":"Dira Poloko","gui.customProcedures.addAnInputNumberText":"Oketša ka go ba le seabe","gui.customProcedures.numberTextType":"nomoro goba sengwalwa","gui.customProcedures.addAnInputBoolean":"Oketša ka go ba le seabe","gui.customProcedures.booleanType":"boolean","gui.customProcedures.addALabel":"Oketša setlankana","gui.customProcedures.runWithoutScreenRefresh":"Šoma ntle go tsošološa skrini","gui.customProcedures.cancel":"Khansela","gui.customProcedures.ok":"Go lokile","gui.SpriteInfo.direction":"Taetšo","gui.directionPicker.rotationStyles.allAround":"Go Dikologa Ka Moka","gui.directionPicker.rotationStyles.leftRight":"La nngele/ La goja","gui.directionPicker.rotationStyles.dontRotate":"O seke wa dikološa","gui.gui.addExtension":"Oketša koketšo","gui.gui.codeTab":"Khoutu","gui.gui.backdropsTab":"Bokamorago","gui.gui.costumesTab":"Dikhostšhumo","gui.gui.soundsTab":"Medumo","gui.extensionLibrary.comingSoon":"E a tla e se kgale","gui.extensionLibrary.requires":"E hloka","gui.extensionLibrary.collaboration":"Tšhomišano le","gui.library.filterPlaceholder":"Nyaka","gui.library.allTag":"Ka moka","gui.loader.headline":"E laiša Projeke","gui.loader.creating":"Go Hlama Projeke","gui.authorInfo.byUser":"ke{username}","gui.menuBar.seeProjectPage":"Bona Letlakala la Projeke","gui.menuBar.LanguageSelector":"sekgetha polelo","gui.menuBar.tutorialsLibrary":"Dithutišo","gui.menuBar.restoreSprite":"Tsošološa Motšeakarolo","gui.menuBar.restoreSound":"Tsošološa modumo","gui.menuBar.restoreCostume":"Tsošološa khosetšhumo","gui.menuBar.restore":"Tsošološa","gui.menuBar.saveNow":"Boloka gona bjale","gui.menuBar.saveAsCopy":"Boloka bjalo ka khophi","gui.menuBar.remix":"Hlakantšha","gui.menuBar.new":"Ntshwa","gui.menuBar.file":"Faele","gui.menuBar.downloadToComputer":"Boloka khomphuteng ya gago","gui.menuBar.edit":"Rulaganya","gui.menuBar.turboModeOff":"Tima Mokgwa wa Turbo","gui.menuBar.turboModeOn":"Tšhuma Mokgwa wa Turbo","gui.gui.projectTitlePlaceholder":"Sehlogo sa Projeke mo","gui.menuBar.isShared":"Abelane","gui.menuBar.share":"Abela","gui.modal.help":"Thuša","gui.modal.back":"Morago","gui.monitor.listMonitor.empty":"( a go na selo)","gui.monitor.listMonitor.listLength":"botelele{length}","gui.monitor.contextMenu.default":"Tshedimošo ya setlwaedi","gui.monitor.contextMenu.large":"Tshedimošo e kgolo","gui.monitor.contextMenu.slider":"setheledi","gui.monitor.contextMenu.sliderRange":"Fetola mathomo le magomo a setheledi","gui.monitor.contextMenu.import":"thekontle","gui.monitor.contextMenu.export":"iša ka ntle","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Bapala","gui.playButton.stop":"Ema","gui.gui.variableScopeOptionAllSprites":"Go batšeakarolo kamoka","gui.gui.variableScopeOptionSpriteOnly":"Go motšeakarolo o fela","gui.gui.cloudVariableOption":"Phapanyo lerung ( e bolokilwe go sever)","gui.gui.variablePromptAllSpritesMessage":"Phapanyo ye e tla humanego go batšeakarolo ka moka","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Khansela","gui.prompt.ok":"Go lokile","gui.playbackStep.stopMsg":"Ema","gui.playbackStep.playMsg":"Bapala","gui.playbackStep.loadingMsg":"E a Laiša...","gui.playbackStep.saveMsg":"Boloka","gui.playbackStep.reRecordMsg":"Gatiša leswa","gui.recordModal.title":"Gatiša Modumo","gui.recordingStep.beginRecord":"Thoma go gatiša ka go kgotla konopi ya ka fase","gui.recordingStep.permission":"{arrow}Re hloka tumelelo ya gago go šomiša maekrofone ya gago","gui.recordingStep.stop":"Emiša go gatiša","gui.recordingStep.record":"Gatiša","gui.sliderModal.min":"Boleng bja fase","gui.sliderModal.max":"Boleng bja godimo","gui.sliderModal.title":"Fetola mathomo le magomo a setheledi","gui.sliderPrompt.cancel":"Khansela","gui.sliderPrompt.ok":"Go lokile","gui.soundEditor.sound":"Modumo","gui.soundEditor.play":"Bapala","gui.soundEditor.stop":"Ema","gui.soundEditor.copy":"Kopisa","gui.soundEditor.paste":"Momaretša","gui.soundEditor.copyToNew":"Kopisetša go e mpsha","gui.soundEditor.delete":"Phumula","gui.soundEditor.save":"Boloka","gui.soundEditor.undo":"Dirolla","gui.soundEditor.redo":"Dira gape","gui.soundEditor.faster":"Ka lebelo","gui.soundEditor.slower":"Ka go nanya","gui.soundEditor.echo":"Ekho","gui.soundEditor.robot":"Roboto","gui.soundEditor.louder":"Godimonyana","gui.soundEditor.softer":"Boletiana","gui.soundEditor.reverse":"Revese","gui.soundEditor.fadeOut":"Timelela","gui.soundEditor.fadeIn":"Tšwelela","gui.soundEditor.mute":"Homotša","gui.SpriteInfo.spritePlaceholder":"Leina","gui.SpriteInfo.sprite":"Motšeakarolo","gui.SpriteInfo.show":"Laetša","gui.SpriteInfo.size":"Bogolo","gui.spriteSelectorItem.contextMenuDuplicate":"pedifatša","gui.spriteSelectorItem.contextMenuExport":"iša ntle","gui.spriteSelectorItem.contextMenuDelete":"Phumula","gui.spriteSelector.addSpriteFromLibrary":"Kgetha Motšeakarolo","gui.spriteSelector.addSpriteFromPaint":"Penta","gui.spriteSelector.addSpriteFromSurprise":"Makala","gui.spriteSelector.addSpriteFromFile":"Laiša Motšeakarolo","gui.stageHeader.stageSizeLarge":"Fetolela go sefala se segolo","gui.stageHeader.stageSizeSmall":"Fetolela go sefala se sennyane","gui.stageHeader.stageSizeFull":"Tsena mo go mokgwa wa go tlala wa skrini","gui.stageHeader.stageSizeUnFull":"Etšwa mo go mokgwa wa go tlala wa skrini","gui.stageHeader.fullscreenControl":"Taolo ye e Feletšego ya Skrini","gui.spriteSelector.addBackdropFromLibrary":"Kgetha Bokamorago","gui.stageSelector.addBackdropFromPaint":"Penta","gui.stageSelector.addBackdropFromSurprise":"Makala","gui.stageSelector.addBackdropFromFile":"Laiša Bokamorago","gui.stageSelector.stage":"Sefala","gui.stageSelector.backdrops":"Bokamorago","gui.telemetryOptIn.label":"Bega dipalopalo go kaonafatša Scratch","gui.telemetryOptIn.body1":"Sehlopha sa Scratch se dula se nyaka go kwešiša bokaone gore Scratch e šomišwa bjang go ralala le lefase. Go leka go thekga maiteko a, o ka dumelela Scratch go romela tshedimošo ya tirišo go Sehlopha sa Scratch ka go itiriša.","gui.telemetryOptIn.body2":"Tshedimošo yeo re e kgoboketšago e akaretša go kgetha polelo, go šomiša dipoloko,le dilo tša go swana le go boloka, go laiša le go tsenya projeke. GA RE kgobaketše tshedimošo ya motho. Hle bona{privacyPolicyLink}ya rena gore o hwetše tshedimošo ka botlalo.","gui.telemetryOptIn.privacyPolicyLink":"Pholisi ya Sephiri","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Mokgwa wa Turbo","gui.webglModal.label":"Sephetli sa gago ga se thekge WebGL","gui.webglModal.webgllink":"Ga e thekge WebGL","gui.costumeLibrary.chooseABackdrop":"Kgetha Bokamorago","gui.costumeLibrary.chooseACostume":"Kgetha Khosetšhumo","gui.costumeTab.addBackdropFromLibrary":"Kgetha Bokamorago","gui.costumeTab.addCostumeFromLibrary":"Kgetha Khosetšhumo","gui.costumeTab.addBlankCostume":"Penta","gui.costumeTab.addSurpriseCostume":"Makala","gui.costumeTab.addFileBackdrop":"Laiša Bokamorago","gui.costumeTab.addFileCostume":"Laiša Khosetšhumo","gui.extensionLibrary.chooseAnExtension":"Kgetha Koketšo","gui.extensionLibrary.extensionUrl":"Tsenya URL ya koketšo","gui.monitors.importListColumnPrompt":"Ke kholomo efe yeo e swanetšego go šomišwa (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Ga se e kgone go thoma go gatiša","gui.soundLibrary.chooseASound":"Kgetha Modumo","gui.soundTab.fileUploadSound":"Laiša Modumo","gui.soundTab.surpriseSound":"Makala","gui.soundTab.recordSound":"Gatiša","gui.soundTab.addSoundFromLibrary":"Kgetha Modumo","gui.spriteLibrary.chooseASprite":"Kgetha Motšeakarolo","gui.tipsLibrary.tutorials":"Kgetha Thutišo","gui.alerts.createsuccess":"Projeke e mpsha e hlamilwe.","gui.alerts.createcopysuccess":"Projeke e bolokilwe bjalo ka khophi.","gui.alerts.createremixsuccess":"Projeke e bolokilwe bjalo ka hlakantšho.","gui.alerts.creating":"Go hlama leswa...","gui.alerts.creatingCopy":"Go kopisa projeke...","gui.alerts.creatingRemix":"Go hlakanya projeke...","gui.alerts.creatingError":"Projeke e paletšwe ke go hlangwa. Hle, leka gape!","gui.alerts.savingError":"Projeke ga se ya boloka.","gui.alerts.savesuccess":"Projeke e bolokilwe.","gui.alerts.saving":"Projeke e a bolokega.....","gui.alerts.cloudInfo":"Hle lemoga, phapanyo ya leru e thekga fela dinomoro, e sego maletere le dika.{learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Ithute go feta.","gui.alerts.importing":"Go tliša...","gui.defaultProject.variable":"phapanyo ya ka","gui.extension.music.name":"Mmino","gui.extension.music.description":"Bapala diletšwa le meropa.","gui.extension.pen.name":"Pene","gui.extension.pen.description":"Thala ka batšeakarolo ba gago.","gui.extension.videosensing.name":"Sekhwi sa Video","gui.extension.videosensing.description":"Ekwa mosepelo ka khamera.","gui.extension.text2speech.name":"Sengwalwa go ya go Polelo","gui.extension.text2speech.description":"Dira diprojeke tša gago gore di bolele.","gui.extension.translate.name":"Fetolela","gui.extension.translate.description":"Fetolela sengwalwa go maleme a mantši","gui.extension.makeymakey.description":"Dira se sengwe le se sengwe gore ebe konopi.","gui.extension.microbit.description":"Kgokaganya diprojeke tša gago le lefase.","gui.extension.microbit.connectingMessage":"kgokagantšha...","gui.extension.ev3.description":"Aga diroboto tša go šomišana le go feta","gui.extension.ev3.connectingMessage":"Kgokagantšha. Netefatša gore nomoro ya sephiri go EV3 ya gago e beilwe go 1234.","gui.extension.boost.description":"Dira dihlamo tša diroboto gore di phele.","gui.extension.boost.connectingMessage":"Kgokaganya...","gui.extension.wedo2.description":"Aga dimmotho le dikwi.","gui.extension.wedo2.connectingMessage":"kgokagantšha...","gui.extension.gdxfor.description":"Ekwa go kgorometša, go goga, mosepelo le modikologo.","gui.extension.gdxfor.connectingMessage":"kgokagantšha...","gui.libraryTags.all":"Ka Moka","gui.libraryTags.animals":"Diphoofolo","gui.libraryTags.dance":"Bina","gui.libraryTags.effects":"Khuetšo","gui.libraryTags.fantasy":"Boikgopolelo","gui.libraryTags.fashion":"Fešene","gui.libraryTags.food":"Dijo","gui.libraryTags.indoors":"Ka ngwakong","gui.libraryTags.loops":"Poeletšo ya melawana mo lenaneong","gui.libraryTags.music":"Mmino","gui.libraryTags.notes":"Dinoutsu","gui.libraryTags.outdoors":"Kantle","gui.libraryTags.patterns":"Dipaterone","gui.libraryTags.people":"Batho","gui.libraryTags.percussion":"go betha seletšwa gore se ntšhe modumo","gui.libraryTags.space":"lefaufau","gui.libraryTags.sports":"Dipapadi","gui.libraryTags.underwater":"ka fase ga meetse","gui.libraryTags.voice":"Lentšu","gui.libraryTags.wacky":"Bogafi","gui.libraryTags.animation":"Go phediša","gui.libraryTags.art":"Bokgabo","gui.libraryTags.games":"Dipapadi","gui.libraryTags.stories":"Dikanegelo","gui.libraryTags.letters":"Maletere","gui.opcodeLabels.direction":"taetšo","gui.opcodeLabels.xposition":"boemo ba x","gui.opcodeLabels.yposition":"boemo ba y","gui.opcodeLabels.size":"bogolo","gui.opcodeLabels.costumename":"leina la khosetšhumo","gui.opcodeLabels.costumenumber":"nomoro ya khosetšhumo","gui.opcodeLabels.backdropname":"leina la bokamorago","gui.opcodeLabels.backdropnumber":"nomoro ya bokamorago","gui.opcodeLabels.volume":"volume","gui.opcodeLabels.tempo":"lebelo","gui.opcodeLabels.answer":"karabo","gui.opcodeLabels.loudness":"lešata","gui.opcodeLabels.username":"leinatšhomišo","gui.opcodeLabels.year":"ngwaga","gui.opcodeLabels.month":"kgwedi","gui.opcodeLabels.date":"letšatšikgwedi","gui.opcodeLabels.dayofweek":"letšatši la beke","gui.opcodeLabels.hour":"iri","gui.opcodeLabels.minute":"motsotso","gui.opcodeLabels.second":"motsotswana","gui.opcodeLabels.timer":"sešupi sa nako","gui.sharedMessages.backdrop":"bokamorago{index}","gui.sharedMessages.costume":"khosetšhumo{index}","gui.sharedMessages.sprite":"Motšeakarolo{index}","gui.sharedMessages.pop":"thunya","gui.sharedMessages.replaceProjectWarning":"Bea bakeng sa diteng tša projeke ye.","gui.sharedMessages.loadFromComputerTitle":"Laiša go tšwa khomphuthareng ya gago","boost.color.any":"mmala o mongwe le o mongwe","boost.color.black":"ntsho","boost.color.blue":"talalerata","boost.color.green":"talamorogo","boost.color.red":"khwibidu","boost.color.white":"tšhweu","boost.color.yellow":"serolwana","boost.getMotorPosition":"boemo bja mmotho [MOTOR_REPORTER_ID]","boost.getTiltAngle":"sekamiša sekhutlo [TILT_DIRECTION]","boost.motorDirection.backward":"ka tsela yela","boost.motorDirection.forward":"ka tsela ye","boost.motorDirection.reverse":"ribese","boost.motorOff":"Tima mmotho [MOTOR_ID]","boost.motorOn":"Bulela mmotho [MOTOR_ID]","boost.motorOnFor":"Bulela mmotho [MOTOR_ID] metsotswana ye [DURATION]","boost.motorOnForRotation":"bulela mmotho [MOTOR_ID] medikologo ye [ROTATION]","boost.seeingColor":"go bona [COLOR] wa setena?","boost.setLightHue":"bea mmala wa seetša go [HUE]","boost.setMotorDirection":"bea taetšo ya mmotho [MOTOR_ID] go [MOTOR_DIRECTION] ","boost.setMotorPower":"bea lebelo la mmotho [MOTOR_ID] go [POWER] %","boost.tiltDirection.any":"efe kapa efe","boost.tiltDirection.down":"fase","boost.tiltDirection.left":"la nngele","boost.tiltDirection.right":"la goja","boost.tiltDirection.up":"godimo","boost.whenColor":"Ge o bona setena se se [COLOR]","boost.whenTilted":"ge o sekamišitše [TILT_DIRECTION_ANY]","ev3.beepNote":"letša noto [NOTE] metsotswana ye [TIME]","ev3.buttonPressed":"konopi [PORT] e tobeditšwe","ev3.getBrightness":"go taga","ev3.getDistance":"bokgole","ev3.getMotorPosition":"boemo bja mmotho [PORT]","ev3.motorSetPower":"mmotho [PORT] o bulela maatla [POWER] %","ev3.motorTurnClockwise":"mmotho [PORT] o retologela ka mo metsotswana ye [TIME] ","ev3.motorTurnCounterClockwise":"mmotho [PORT] o retologela ka mo metsotswana ye [TIME] ","ev3.whenBrightnessLessThan":"ge go tagile < [DISTANCE]","ev3.whenButtonPressed":"ge konopi ya [PORT] e tobetšwa ","ev3.whenDistanceLessThan":"ge bokgole < [DISTANCE]","gdxfor.getAcceleration":"oketša makhura [DIRECTION]","gdxfor.getForce":"maatla","gdxfor.getSpin":"lebelo la go dikološa [DIRECTION]","gdxfor.getTilt":"sekamiša sekhutlo [TILT]","gdxfor.isFreeFalling":"e a wa?","gdxfor.isTilted":"sekamišitše [TILT]?","gdxfor.pulled":"gogile","gdxfor.pushed":"kgoromeditše","gdxfor.shaken":"šikinyegile","gdxfor.startedFalling":"thomile go wa","gdxfor.tiltDirectionMenu.any":"efe kapa efe","gdxfor.tiltDirectionMenu.back":"morago","gdxfor.tiltDirectionMenu.front":"pele","gdxfor.tiltDirectionMenu.left":"la nngele","gdxfor.tiltDirectionMenu.right":"la goja","gdxfor.turnedFaceDown":"inamišitše sefahlego ","gdxfor.turnedFaceUp":"išitše sefahlego godimo","gdxfor.whenForcePushedOrPulled":"ge sekwi sa maatla se [PUSH_PULL]","gdxfor.whenGesture":"ge [GESTURE]","gdxfor.whenTilted":"ge e sekamišitšwe [TILT]","makeymakey.downArrow":"mosebe wa go lebelela fase","makeymakey.downArrowShort":"fase","makeymakey.leftArrow":"mosebe wa go lanngele","makeymakey.leftArrowShort":"lanngele","makeymakey.rightArrow":"mosebe wa go la go ja","makeymakey.rightArrowShort":"la goja","makeymakey.spaceKey":"sekgoba","makeymakey.upArrow":"mosebe wa go lebelela godimo","makeymakey.upArrowShort":"godimo","makeymakey.whenKeyPressed":"ge konope [KEY] e tobetšwa","makeymakey.whenKeysPressedInOrder":"ge [SEQUENCE] e tobetšwa ka mokgwa wa maleba","microbit.buttonsMenu.any":"efe kapa efe","microbit.clearDisplay":"tloša taetšo","microbit.defaultTextToDisplay":"Dumela!","microbit.displaySymbol":"bontšha [MATRIX]","microbit.displayText":"bontšha sengwalwa [TEXT]","microbit.gesturesMenu.jumped":"fofile","microbit.gesturesMenu.moved":"šutile","microbit.gesturesMenu.shaken":"šikinyegile","microbit.isButtonPressed":"[BTN] konopi e tobeditšwe","microbit.isTilted":"e sekamišitšwe [DIRECTION]?","microbit.pinStateMenu.off":"timile","microbit.pinStateMenu.on":"tšhuma","microbit.tiltAngle":"sekamiša khutlo [DIRECTION]","microbit.tiltDirectionMenu.any":"efe kapa efe","microbit.tiltDirectionMenu.back":"morago","microbit.tiltDirectionMenu.front":"pele","microbit.tiltDirectionMenu.left":"lanngele","microbit.tiltDirectionMenu.right":"la goja","microbit.whenButtonPressed":"ge konopi [BTN] e tobeditšwe","microbit.whenGesture":"ge [GESTURE]","microbit.whenPinConnected":"ge nomoro ya sephiri [PIN] e kgokagantšwe","microbit.whenTilted":"ge e sekamišitšwe [DIRECTION]","music.categoryName":"Mmino","music.changeTempo":"fetola tempo ka [TEMPO]","music.drumBass":"(2) Moropa wa Peisi","music.drumBongo":"(13)Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) Hi-Hat yeo e tswalelegilego","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Cowbell","music.drumCrashCymbal":"(4)Crash Cymbal","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Go phaphatha matsogo","music.drumOpenHiHat":"(5) Hi-Hat yeo e bulegilego","music.drumSideStick":"(3) Kota ya ka thoko","music.drumSnare":"(1) Snare Drum","music.drumTambourine":"(7) Thamporini","music.drumTriangle":"(12) Khutlotharo","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Poloko ya Leplanka","music.getTempo":"lebelo","music.instrumentBass":"(6) Peisi","music.instrumentBassoon":"(14) Bassoon","music.instrumentCello":"(8) Cello","music.instrumentChoir":"(15) Khwaere","music.instrumentClarinet":"(10) Klarinete","music.instrumentElectricGuitar":"(5) Katara ya Mohlagase","music.instrumentElectricPiano":"(2) Piano ya Mohlagase","music.instrumentFlute":"(12) Flute","music.instrumentGuitar":"(4) Katara","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Lepokisi la Mmino","music.instrumentOrgan":"(3) Okene","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxophone","music.instrumentSteelDrum":"(18) Moropatšhipi","music.instrumentSynthLead":"(20) Synth Lead","music.instrumentSynthPad":"(21) Synth Pad","music.instrumentTrombone":"(9) Trombone","music.instrumentVibraphone":"(16) Vibraphone","music.instrumentWoodenFlute":"(13) Flute ya kota","music.midiPlayDrumForBeats":"bapala moropa [DRUM] go dira [BEATS] merethetho","music.midiSetInstrument":"bea seletšwa go [INSTRUMENT]","music.playDrumForBeats":"bapala moropa [DRUM] go dira [BEATS] merethetho","music.playNoteForBeats":"bapala noto [NOTE] ya [BEATS] merethetho","music.restForBeats":"khuletša [BEATS] merethetho","music.setInstrument":"bea seletšwa go [INSTRUMENT]","music.setTempo":"bea lebelo go [TEMPO]","pen.categoryName":"Pene","pen.changeColorParam":"fetola pene [COLOR_PARAM] ka [VALUE]","pen.changeHue":"fetola mmala wa pene ka [HUE]","pen.changeShade":"fetola mošidi wa pene ka [SHADE]","pen.changeSize":"fetola bogolo bja pene ka [SIZE]","pen.clear":"phumula ka moka","pen.colorMenu.brightness":"go taga","pen.colorMenu.color":"mmala","pen.colorMenu.saturation":"tlopelo","pen.colorMenu.transparency":"bonagatšago","pen.penDown":"pene fase","pen.penUp":"emiša pene","pen.setColor":"bea mmala wa pene go [COLOR]","pen.setColorParam":"bea pene [COLOR_PARAM] GO [VALUE]","pen.setHue":"bea mmala wa pene go [HUE]","pen.setShade":"bea moriti wa pene go [SHADE]","pen.setSize":"bea bogolo bja pene go [SIZE]","pen.stamp":"setempe","text2speech.alto":"alto","text2speech.categoryName":"Sengwalwa go ya go Polelo","text2speech.defaultTextToSpeak":"dumela","text2speech.giant":"lekgema","text2speech.kitten":"katsana","text2speech.setLanguageBlock":"bea polelo go [LANGUAGE]","text2speech.setVoiceBlock":"bea lentšu go [VOICE]","text2speech.speakAndWaitBlock":"bolela [WORDS]","text2speech.squeak":"tswinya","text2speech.tenor":"tenor","translate.categoryName":"Fetolela","translate.defaultTextToTranslate":"dumela","translate.translateBlock":"fetolela [WORDS] go [LANGUAGE]","translate.viewerLanguage":"polelo","videoSensing.categoryName":"Sekhwi sa Video","videoSensing.direction":"taetšo","videoSensing.motion":"mosepelo","videoSensing.off":"timile","videoSensing.on":"Tšhuma","videoSensing.onFlipped":"ge e phethotšwe","videoSensing.setVideoTransparency":"bea ponagatšo ya video go [TRANSPARENCY]","videoSensing.sprite":"motšeakarolo","videoSensing.stage":"sefala","videoSensing.videoOn":"video [ATTRIBUTE] go [SUBJECT]","videoSensing.videoToggle":"sotha video [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"ge mosepelo wa video > [REFERENCE]","wedo2.getDistance":"bokgole","wedo2.getTiltAngle":"sekamiša sekhutlo [TILT_DIRECTION]","wedo2.isTilted":"sekamišetša [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"Ke tsela yela","wedo2.motorDirection.forward":"ka tsela ye","wedo2.motorDirection.reverse":"ribese","wedo2.motorId.a":"mmotho wa A","wedo2.motorId.all":"memotho ka moka","wedo2.motorId.b":"mmotho wa B","wedo2.motorId.default":"mmotho","wedo2.motorOff":"tima [MOTOR_ID]","wedo2.motorOn":"tšhuma [MOTOR_ID]","wedo2.motorOnFor":"bulela [MOTOR_ID] metsotswana e [DURATION]","wedo2.playNoteFor":"bapala noto [NOTE] metsotswana ye [DURATION]","wedo2.setLightHue":"bea mmala wa seetša go [HUE]","wedo2.setMotorDirection":"bea taetšo ya [MOTOR_ID] go [MOTOR_DIRECTION] ","wedo2.startMotorPower":"bea maatla a [MOTOR_ID] go [POWER]","wedo2.tiltDirection.any":"efe kapa efe","wedo2.tiltDirection.down":"fase","wedo2.tiltDirection.left":"lanngele","wedo2.tiltDirection.right":"la goja","wedo2.tiltDirection.up":"godimo","wedo2.whenDistance":"ge bo kgole [OP] [REFERENCE]","wedo2.whenTilted":"ge e sekamišitše [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Mmala","paint.paintEditor.saturation":"Tlopelo","paint.paintEditor.brightness":"Go taga","paint.paintEditor.costume":"Khosetšhumo","paint.paintEditor.group":"Sehlopha","paint.paintEditor.ungroup":"Hlopholla","paint.paintEditor.undo":"Dirolla","paint.paintEditor.redo":"Dira gape","paint.paintEditor.forward":"Pele","paint.paintEditor.backward":"Morago","paint.paintEditor.front":"Pele","paint.paintEditor.back":"Morago","paint.paintEditor.more":"Go feta","paint.modeTools.brushSize":"Bogolo","paint.modeTools.eraserSize":"Bogolo bja sephumodi","paint.modeTools.copy":"Kopiša","paint.modeTools.paste":"Momaretša","paint.modeTools.delete":"Phumula","paint.modeTools.curved":"Kgopame","paint.modeTools.pointed":"Šupile","paint.modeTools.thickness":"Bokoto","paint.modeTools.flipHorizontal":"Phethola go Rapama","paint.modeTools.flipVertical":"Go phethola go tsepa","paint.modeTools.filled":"Tladitšwe","paint.modeTools.outlined":"Hlalositšwe","paint.paintEditor.bitmap":"Fetolela go Bitmap","paint.paintEditor.vector":"Fetolela go Vector","paint.paintEditor.fill":"Tlatša","paint.paintEditor.stroke":"Hlalosa","paint.brushMode.brush":"Poraša","paint.eraserMode.eraser":"Sephumodi","paint.fillMode.fill":"Tlatša","paint.lineMode.line":"Mothalo","paint.ovalMode.oval":"Sediko","paint.rectMode.rect":"Khutlonne","paint.reshapeMode.reshape":"Bopaleswa","paint.roundedRectMode.roundedRect":"Khutlonne ya go dirwa nkgokolo","paint.selectMode.select":"Kgetha","paint.textMode.text":"Sengwalwa","paint.colorPicker.swap":"Fetola"},"tn":{"gui.alerts.tryAgain":"Leka gape","gui.alerts.download":"Download","gui.connection.reconnect":"Momaganya gape","gui.backpack.costumeLabel":"seaparo","gui.backpack.soundLabel":"modumo","gui.backpack.scriptLabel":"mokwalo","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Mokotla","gui.backpack.errorBackpack":"Phoso ya go tsenya kgetsana ya mokotla","gui.backpack.loadingBackpack":"Re a tsenya...","gui.backpack.more":"Oketsegileng","gui.backpack.emptyBackpack":"Kgetsana ya mokotla e lolea ","gui.unsupportedBrowser.label":"Sediriswa sa go phuruphutsha ga se a tshegediwa","gui.cards.all-tutorials":"Dirutwa","gui.cards.shrink":"Fokotsega","gui.cards.expand":"Atolosa","gui.cards.close":"Tswala","gui.cards.more-things-to-try":"Dilo di le dintsi go di leka!","gui.cards.see-more":"Bona go le gontsi","gui.comingSoon.message1":"Se tshwenyege, re mo go yona{emoji}","gui.comingSoon.message2":"E a latela","gui.comingSoon.message3":"Re dira mo go yona {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Go go na didiriswa tse di fitlhetsweng","gui.connection.auto-scanning.prescan":"Thola sediriswa sa gago fa gaufi, mme o simolole go batlisisa","gui.connection.auto-scanning.pressbutton":"Tobetsa konopo e e mo sedirisweng sa gago","gui.connection.auto-scanning.start-search":"Simolola go phuruphutsha","gui.connection.connecting-searchbutton":"Phuruphutsha...","gui.connection.auto-scanning.try-again":"Leka gape","gui.connection.connected":"Gokaganye","gui.connection.disconnect":"Gokaganyolola","gui.connection.go-to-editor":"E ya go Motseleganyi","gui.connection.connecting-cancelbutton":"Gokaganya","gui.connection.error.errorMessage":"Oops, go lebega sengwe se sa tsamaya sentle.","gui.connection.error.tryagainbutton":"Leka gape","gui.connection.error.helpbutton":"Thusa","gui.connection.peripheral-name-label":"Leina la sediriswa","gui.connection.connect":"golaganya","gui.connection.scanning.lookingforperipherals":"Go batlana le didiriswa","gui.connection.scanning.noPeripheralsFound":"Go go na didiriswa tse di fitlhetsweng","gui.connection.scanning.instructions":"Tlhopha sediriswa sa gago mo lenaaneng le le fa godimo","gui.connection.search":"Ntšhwafatsa","gui.connection.unavailable.installscratchlink":"Netefatsa gore o na le kgokagano ya Scratch e e tsentsweng e bile e dira","gui.connection.unavailable.enablebluetooth":"Lekola fa Bluetooth e dira","gui.connection.unavailable.tryagainbutton":"Leka gape","gui.connection.unavailable.helpbutton":"Thusa","gui.controls.go":"Tsamaya","gui.controls.stop":"Ema","gui.crashMessage.label":"Oops! sengwe ga se a tsamaya sentle","gui.crashMessage.errorNumber":"Phoso ya gago e tsentshitswe ka id {errorId}","gui.crashMessage.reload":"Tlhatlhelela gape","gui.customProcedures.myblockModalTitle":"Dira lebokoso","gui.customProcedures.addAnInputNumberText":"Oketsa ka tshwaelo","gui.customProcedures.numberTextType":"Palo ya molaetsa","gui.customProcedures.addAnInputBoolean":"Oketsa ka tshwaelo","gui.customProcedures.booleanType":"boolean","gui.customProcedures.addALabel":"Oketsa ka leina","gui.customProcedures.runWithoutScreenRefresh":"Dirisa ntle le screen refresh","gui.customProcedures.cancel":"Phimola","gui.customProcedures.ok":"Go siame","gui.SpriteInfo.direction":"Kaelo","gui.directionPicker.rotationStyles.allAround":"Gotlhe","gui.directionPicker.rotationStyles.leftRight":"Molema/Moja","gui.directionPicker.rotationStyles.dontRotate":"O seka wa dikolosa","gui.gui.addExtension":"Oketsa","gui.gui.codeTab":"Khoutu","gui.gui.backdropsTab":"Ditatlhelo morago","gui.gui.costumesTab":"Diaparo","gui.gui.soundsTab":"Medumo","gui.extensionLibrary.comingSoon":"E a latela","gui.extensionLibrary.requires":"tlhoka","gui.extensionLibrary.collaboration":"Tirisano le","gui.library.filterPlaceholder":"Batla","gui.library.allTag":"Tsotlhe","gui.loader.headline":"Go tsenya Porojeke","gui.loader.creating":"Go simolola Porojeke","gui.authorInfo.byUser":"ka {username}","gui.menuBar.seeProjectPage":"Lebelela tsebe ya Porojeke","gui.menuBar.LanguageSelector":"setlhophi sa puo","gui.menuBar.tutorialsLibrary":"Dirutwa","gui.menuBar.restoreSprite":"Busetsa Sprite","gui.menuBar.restoreSound":"Busetsa Modumo","gui.menuBar.restoreCostume":"Busetsa Seaparo","gui.menuBar.restore":"Busetsa","gui.menuBar.saveNow":"Boloka jaanong","gui.menuBar.saveAsCopy":"Boloka jaaka setshwantso","gui.menuBar.remix":"Tlhakanya gape","gui.menuBar.new":"Mo bosheng","gui.menuBar.file":"Faele","gui.menuBar.downloadToComputer":"Boloka mo khomputareng ya gago.","gui.menuBar.edit":"Sekaseka","gui.menuBar.turboModeOff":"Tima Turbo Mode","gui.menuBar.turboModeOn":"Tshuma Turbo Mode","gui.gui.projectTitlePlaceholder":"Setlhogo sa Porojeke fa","gui.menuBar.isShared":"Abelanwe","gui.menuBar.share":"Abela","gui.modal.help":"Thusa","gui.modal.back":"Morago","gui.monitor.listMonitor.empty":"(lolea)","gui.monitor.listMonitor.listLength":"botelele {length}","gui.monitor.contextMenu.default":"Puiso ya tlwaelo","gui.monitor.contextMenu.large":"readout e kgolo","gui.monitor.contextMenu.slider":"sereledi","gui.monitor.contextMenu.sliderRange":"Fetola direledi tse di farologaneng","gui.monitor.contextMenu.import":"tsenya","gui.monitor.contextMenu.export":"romela","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Tshameka","gui.playButton.stop":"Ema","gui.gui.variableScopeOptionAllSprites":"Go di sprites tsotlhe","gui.gui.variableScopeOptionSpriteOnly":"Sprite sena fela","gui.gui.cloudVariableOption":"Dipharologano tsa maru (bolokilwe mo server)","gui.gui.variablePromptAllSpritesMessage":"Phetogo e , e tla nna teng go di sprites tsotlhe","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Phimola","gui.prompt.ok":"Go siame","gui.playbackStep.stopMsg":"Ema","gui.playbackStep.playMsg":"Tshameka","gui.playbackStep.loadingMsg":"Re a tsenya...","gui.playbackStep.saveMsg":"Boloka","gui.playbackStep.reRecordMsg":"Rekota gape","gui.recordModal.title":"Rekota Modumo","gui.recordingStep.beginRecord":"Simolola go rekota ka go tobetsa konopo e e fa tlase","gui.recordingStep.permission":"{arrow}Re tlhoka tetla ya gago go dirisa maekerofounu wa gago","gui.recordingStep.stop":"Emisa go gatisa","gui.recordingStep.record":"Gatisa","gui.sliderModal.min":"Boleng jo bo kwa tlase","gui.sliderModal.max":"Boleng jo bo kwa godimo","gui.sliderModal.title":"Fetola direledi tse di farologaneng","gui.sliderPrompt.cancel":"Phimola","gui.sliderPrompt.ok":"Go siame","gui.soundEditor.sound":"Modumo","gui.soundEditor.play":"Tshameka","gui.soundEditor.stop":"Ema","gui.soundEditor.copy":"Kopa","gui.soundEditor.paste":"Kgomaretsa","gui.soundEditor.copyToNew":"Kopa go e ntšhwa","gui.soundEditor.delete":"Phimola","gui.soundEditor.save":"Boloka","gui.soundEditor.undo":"Sutlha","gui.soundEditor.redo":"Dira gape","gui.soundEditor.faster":"Bonako","gui.soundEditor.slower":"Bonya","gui.soundEditor.echo":"Modumo wa fa o bua","gui.soundEditor.robot":"Roboto","gui.soundEditor.louder":"Godingwana","gui.soundEditor.softer":"Tlasenyana","gui.soundEditor.reverse":"Dirolola","gui.soundEditor.fadeOut":"nyelela kwa ntle","gui.soundEditor.fadeIn":"nyelela ka mo gare","gui.soundEditor.mute":"Didimatsa","gui.SpriteInfo.spritePlaceholder":"Leina","gui.SpriteInfo.sprite":"Sprite","gui.SpriteInfo.show":"Bontsha","gui.SpriteInfo.size":"Bogolo","gui.spriteSelectorItem.contextMenuDuplicate":"gabedi","gui.spriteSelectorItem.contextMenuExport":"romela","gui.spriteSelectorItem.contextMenuDelete":"phimola","gui.spriteSelector.addSpriteFromLibrary":"Tlhopha Sprite","gui.spriteSelector.addSpriteFromPaint":"Taka","gui.spriteSelector.addSpriteFromSurprise":"Kgakgamatso","gui.spriteSelector.addSpriteFromFile":"Bula Sprite","gui.stageHeader.stageSizeLarge":"Fetogela go kgato e kgolo","gui.stageHeader.stageSizeSmall":"Fetogela go kgato e nnye","gui.stageHeader.stageSizeFull":"Tsena mo sekerining se se tletseng","gui.stageHeader.stageSizeUnFull":"Tswaya mo sekerining se se tletseng","gui.stageHeader.fullscreenControl":"Taolo ya sekerini se se tletseng","gui.spriteSelector.addBackdropFromLibrary":"Tlhopha Tatlhelo morago","gui.stageSelector.addBackdropFromPaint":"Taka","gui.stageSelector.addBackdropFromSurprise":"Kgakgamatso","gui.stageSelector.addBackdropFromFile":"Bula Tatlhelo morago","gui.stageSelector.stage":"Serala","gui.stageSelector.backdrops":"Ditatlhelo morago","gui.telemetryOptIn.label":"Bega dipalopalo go tlhabolola Scratch","gui.telemetryOptIn.body1":"Setlhopha sa Scratch se leka ka dinako tsotlhe go tlhaloganya gore Scratch se dirisiwa jang lefatshe ka bophara. Go thusa go tshegetsa maiteko a, o ka dumelela Scratch go romela tiriso ya tshedimosetso go setlhopha sa Scratch ka boyona.","gui.telemetryOptIn.body2":"Tshedimosetso e re e kgobokanyang e akaretsa tlhopho ya puo, tiriso ya diboloko, ditiragalo dingwe jaaka go boloka, go tsenya le go bula porojeke. Ka kopo lebelela {privacyPolicyLink} go bona tshedimosetso e ntsi.","gui.telemetryOptIn.privacyPolicyLink":"Melao ya Sephiri","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Mokgwa wa turbo","gui.webglModal.label":"Sephuruphutshi sa gago ga se tshegetse WebGL","gui.webglModal.webgllink":"ga e tshegetse WebGL","gui.costumeLibrary.chooseABackdrop":"Tlhopha Tatlhelo morago","gui.costumeLibrary.chooseACostume":"Tlhopha seaparo","gui.costumeTab.addBackdropFromLibrary":"Tlhopha Tatlhelo morago","gui.costumeTab.addCostumeFromLibrary":"Tlhopha seaparo","gui.costumeTab.addBlankCostume":"Taka","gui.costumeTab.addSurpriseCostume":"Kgakgamatso","gui.costumeTab.addFileBackdrop":"Bula Tatlhelo morago","gui.costumeTab.addFileCostume":"Bula seaparo","gui.extensionLibrary.chooseAnExtension":"Tlhopha koketso","gui.extensionLibrary.extensionUrl":"Tsenya URL ya koketso","gui.monitors.importListColumnPrompt":"Ke kholomo efe e e tshwanetseng go dirisiwa ({numberOfColumns})?","gui.recordingStep.alertMsg":"Ga go a kgonagala go simolola go rekota","gui.soundLibrary.chooseASound":"Tlhopha Modumo","gui.soundTab.fileUploadSound":"Bula Modumo","gui.soundTab.surpriseSound":"Kgakgamatso","gui.soundTab.recordSound":"Gatisa","gui.soundTab.addSoundFromLibrary":"Tlhopha Modumo","gui.spriteLibrary.chooseASprite":"Tlhopha Sprite","gui.tipsLibrary.tutorials":"Tlhopha serutwa","gui.alerts.createsuccess":"Porojeke e ntšhwa e tlhamilwe.","gui.alerts.createcopysuccess":"Porojeke e bolokilwe jaaka khopi.","gui.alerts.createremixsuccess":"Porojeke e bolokilwe jaaka tlhakanyo","gui.alerts.creating":"Go tlhama ... e ntšhwa","gui.alerts.creatingCopy":"Go kwalolola porojeke...","gui.alerts.creatingRemix":"Tlhakanyo ya porojeke","gui.alerts.creatingError":"E reteletswe ke go tlhama porojeke. Ka kopo leka gape!","gui.alerts.savingError":"Porojeke e reteletswe ke go boloka.","gui.alerts.savesuccess":"Porojeke e bolokilwe.","gui.alerts.saving":"E boloka porojeke...","gui.alerts.cloudInfo":"Ka kopo ela tlhoko, leru la pharologanyo le tshegetsa dipalo, eseng ditlhaka kgotsa matshwao.{learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Ithute go le gontsi.","gui.alerts.importing":"E romela...","gui.defaultProject.variable":"pharologanyo ya me","gui.extension.music.name":"Mmino","gui.extension.music.description":"Tshameka didiriswa le meropa","gui.extension.pen.name":"Pene","gui.extension.pen.description":"Thala ka DiSprite tsa gago","gui.extension.videosensing.name":"Maikutlo a vidio","gui.extension.videosensing.description":"Batla motsamao ka khamera","gui.extension.text2speech.name":"Romela molaetsa ka puo","gui.extension.text2speech.description":"Dira diporojeke tsa gago gore di bue","gui.extension.translate.name":"Ranola","gui.extension.translate.description":"Ranolela molaetsa mo dipuong di le dintsi","gui.extension.makeymakey.description":"Dira sengwe le sengwe go nna konopo","gui.extension.microbit.description":"Golaganya porojeke ya gago le lefatshe","gui.extension.microbit.connectingMessage":"E a golaganya","gui.extension.ev3.description":"Aga diroboto le tse dingwe tsa tirisano","gui.extension.ev3.connectingMessage":"Go golaganya. Netefatsa gore lomapo lo lo mo EV3 le diretswe mo 1234.","gui.extension.boost.description":"Tlisa ditlhangwa tsa roboto mo botshelong","gui.extension.boost.connectingMessage":"E a golaganya","gui.extension.wedo2.description":"Aga motšhini o o dupelelang.","gui.extension.wedo2.connectingMessage":"E a golaganya","gui.extension.gdxfor.description":"Dupelela go kgarametsa, go goga, motsamao le go dikologa","gui.extension.gdxfor.connectingMessage":"E a golaganya","gui.libraryTags.all":"Tsotlhe","gui.libraryTags.animals":"Diphologolo","gui.libraryTags.dance":"Bina","gui.libraryTags.effects":"Selebego","gui.libraryTags.fantasy":"Toro kgotsa sengwe se se akanyeditsweng","gui.libraryTags.fashion":"Fešene","gui.libraryTags.food":"Dijo","gui.libraryTags.indoors":"Teng ga kago","gui.libraryTags.loops":"Dilupu","gui.libraryTags.music":"Mmino","gui.libraryTags.notes":"Dintlha","gui.libraryTags.outdoors":"Kwa ntle","gui.libraryTags.patterns":"Dipaterone","gui.libraryTags.people":"Batho","gui.libraryTags.percussion":"Diletso tse di letswang ka go tshekinngwa","gui.libraryTags.space":"Phatlha","gui.libraryTags.sports":"Metshameko","gui.libraryTags.underwater":"Ka fatlase ga mesti","gui.libraryTags.voice":"Lentswe","gui.libraryTags.wacky":"Kgatlhisa","gui.libraryTags.animation":"Khathunu","gui.libraryTags.art":"Botaki","gui.libraryTags.games":"Metshameko","gui.libraryTags.stories":"Dikgang","gui.libraryTags.letters":"Makwalo","gui.opcodeLabels.direction":"kaelo","gui.opcodeLabels.xposition":"boemo jwa x","gui.opcodeLabels.yposition":"boemo jwa y","gui.opcodeLabels.size":"selekanyo","gui.opcodeLabels.costumename":"leina la diaparo","gui.opcodeLabels.costumenumber":"palo ya seaparo","gui.opcodeLabels.backdropname":"latlhela morago leina","gui.opcodeLabels.backdropnumber":"Tatlhelomorago ya palo","gui.opcodeLabels.volume":"maemo a modumo","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"karabo","gui.opcodeLabels.loudness":"modumo","gui.opcodeLabels.username":"leinatiriso","gui.opcodeLabels.year":"ngwaga","gui.opcodeLabels.month":"kgwedi","gui.opcodeLabels.date":"letlha","gui.opcodeLabels.dayofweek":"letsatsi la beke","gui.opcodeLabels.hour":"ura","gui.opcodeLabels.minute":"motsotso","gui.opcodeLabels.second":"motsotswana","gui.opcodeLabels.timer":"tshupanako","gui.sharedMessages.backdrop":"Tatlhelomorago {index}","gui.sharedMessages.costume":"Seaparo {index}","gui.sharedMessages.sprite":"Sprite{index}","gui.sharedMessages.pop":"thwanya","gui.sharedMessages.replaceProjectWarning":"Emisetsa diteng tsa porojeke ya jaanong","gui.sharedMessages.loadFromComputerTitle":"Tsenya tshedimosetso go tswa mo khomputareng ya gago","boost.color.any":"mmala mongwe le mongwe","boost.color.black":"ntsho","boost.color.blue":"botala jwa loapi","boost.color.green":"tala","boost.color.red":"khibidu","boost.color.white":"tshweu","boost.color.yellow":"serolwana","boost.getMotorPosition":"motšhini [MOTOR_REPORTER_ID] maemo","boost.getTiltAngle":"sekamisa enkele [TILT_DIRECTION]","boost.motorDirection.backward":"ka tsela ele","boost.motorDirection.forward":"ka tsela e","boost.motorDirection.reverse":"busetsa morago","boost.motorOff":"tima motšhini [MOTOR_ID] ","boost.motorOn":"tshuma motšhini [MOTOR_ID] ","boost.motorOnFor":"tshuma motšhini [MOTOR_ID] [DURATION] metsotswana","boost.motorOnForRotation":"tshuma motšhini [MOTOR_ID] [ROTATION] ditshekeletso","boost.seeingColor":"a o bona [COLOR] setena?","boost.setLightHue":"tshuma lebone la mmala go [HUE]","boost.setMotorDirection":"tlhagisa motšhini [MOTOR_ID] kaelo [MOTOR_DIRECTION]","boost.setMotorPower":"tlhagisa motšhini [MOTOR_ID] lebelo go [POWER] %","boost.tiltDirection.any":"sengwe","boost.tiltDirection.down":"tlase","boost.tiltDirection.left":"molema","boost.tiltDirection.right":"moja","boost.tiltDirection.up":"godimo","boost.whenColor":"fa [COLOR] wa setena o bonwe","boost.whenTilted":"fa e sekamisitswe [TILT_DIRECTION_ANY]","ev3.beepNote":"letsa noto [NOTE] ya [TIME] metsotswana","ev3.buttonPressed":"konopo [PORT] tobeditswe?","ev3.getBrightness":"phatshimo","ev3.getDistance":"sekgala","ev3.getMotorPosition":"motšhini [PORT] maemo","ev3.motorSetPower":"motšhini [PORT] tlhagisa maatla [POWER] %","ev3.motorTurnClockwise":"motšhini [PORT] retologela ka fa [TIME] metsotswana","ev3.motorTurnCounterClockwise":"motšhini [PORT] retologela ka fale [TIME] metsotswana","ev3.whenBrightnessLessThan":"fa phatsimo < [DISTANCE]","ev3.whenButtonPressed":"fa konopo [PORT] e gateletswe","ev3.whenDistanceLessThan":"fa sekgala < [DISTANCE]","gdxfor.getAcceleration":"koketso [DIRECTION]","gdxfor.getForce":"maatla","gdxfor.getSpin":"dikolosa lebelo [DIRECTION]","gdxfor.getTilt":"sekamisa enkele [TILT]","gdxfor.isFreeFalling":" a o a wa?","gdxfor.isTilted":"sekametse [TILT]?","gdxfor.pulled":"gogilwe","gdxfor.pushed":"kgarameletsa","gdxfor.shaken":"reketlisiwa","gdxfor.startedFalling":"simolola go wa","gdxfor.tiltDirectionMenu.any":"sengwe","gdxfor.tiltDirectionMenu.back":"kwa morago","gdxfor.tiltDirectionMenu.front":"fa pele","gdxfor.tiltDirectionMenu.left":"molema","gdxfor.tiltDirectionMenu.right":"moja","gdxfor.turnedFaceDown":"fetoletse sefatlhego kwa tlase","gdxfor.turnedFaceUp":"fetoletse sefatlhego kwa godimo","gdxfor.whenForcePushedOrPulled":"fa maatla a dupelela [PUSH_PULL]","gdxfor.whenGesture":"fa [GESTURE]","gdxfor.whenTilted":"fa e sekamisitswe [TILT]","makeymakey.downArrow":"tshupo tlase","makeymakey.downArrowShort":"tlase","makeymakey.leftArrow":"tshupo molema","makeymakey.leftArrowShort":"molema","makeymakey.rightArrow":"tshupo moja","makeymakey.rightArrowShort":"moja","makeymakey.spaceKey":"sebaka","makeymakey.upArrow":"tshupo godimo","makeymakey.upArrowShort":"godimo","makeymakey.whenKeyPressed":"fa [KEY] konopo e tobeditswe","makeymakey.whenKeysPressedInOrder":"fa [SEQUENCE] e tobeditswe ka tolamo","microbit.buttonsMenu.any":"sengwe","microbit.clearDisplay":"phepafatsa dipontsho","microbit.defaultTextToDisplay":"Dumela!","microbit.displaySymbol":"bontsha [MATRIX]","microbit.displayText":"bontsha setlhangwa [TEXT]","microbit.gesturesMenu.jumped":"tloletse","microbit.gesturesMenu.moved":"sutisitswe","microbit.gesturesMenu.shaken":"reketlisiwa","microbit.isButtonPressed":"[BTN] konopo e gateletswe?","microbit.isTilted":"sekamisitswe [DIRECTION]?","microbit.pinStateMenu.off":"timile","microbit.pinStateMenu.on":"tshubile","microbit.tiltAngle":"sekamisa enkele [DIRECTION]","microbit.tiltDirectionMenu.any":"sengwe","microbit.tiltDirectionMenu.back":"kwa morago","microbit.tiltDirectionMenu.front":"fa pele","microbit.tiltDirectionMenu.left":"molema","microbit.tiltDirectionMenu.right":"moja","microbit.whenButtonPressed":"fa [BTN] konopo e tobeditswe","microbit.whenGesture":"fa [GESTURE]","microbit.whenPinConnected":"fa lomapo [PIN] golagane","microbit.whenTilted":"fa le sekamisitswe [DIRECTION]","music.categoryName":"Mmino","music.changeTempo":"fetola lebelo ka go [TEMPO]","music.drumBass":"(2) Moropa wa Base","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":" (9) tsa dikotana","music.drumClosedHiHat":"(6) Hi-Hat e etswalegileng","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Tleloko ya kgomo","music.drumCrashCymbal":"(4) Semebala e e opanngwang","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Opa Seatla","music.drumOpenHiHat":"(5) Bula Hi-Hat","music.drumSideStick":"(3) Thobane ya fa Tlhakoreng","music.drumSnare":"(1) Moropa wa Senare","music.drumTambourine":"(7) Moropana","music.drumTriangle":"(12) Khutlotharo","music.drumVibraslap":"(17) seletswa sa lerapo la motlhagare","music.drumWoodBlock":"(10) Sesane","music.getTempo":"lebelo","music.instrumentBass":"(6) Base","music.instrumentBassoon":"(14) Bassoon","music.instrumentCello":"(8) Seletswa sa Cello","music.instrumentChoir":"(15) Khwaere","music.instrumentClarinet":"(10) Kelarinete","music.instrumentElectricGuitar":"(5) Katara ya Motlakase","music.instrumentElectricPiano":"(2) Piano ya Motlakase","music.instrumentFlute":"(12) Fulutu","music.instrumentGuitar":"(4) Katara","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Lebokoso la Mmino","music.instrumentOrgan":"(3) Okene","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Sekesefone","music.instrumentSteelDrum":"(18) Moropa wa Tshipi","music.instrumentSynthLead":"(20) motlhabeletsi","music.instrumentSynthPad":"(21) motseeletsi","music.instrumentTrombone":"(9) Trombone","music.instrumentVibraphone":"(16) Vibraphone","music.instrumentWoodenFlute":"(13) Fulutu ya legong","music.midiPlayDrumForBeats":"tshameka moropa [DRUM] wa [BEATS] meporo","music.midiSetInstrument":"tlhagisa sediriswa go [INSTRUMENT]","music.playDrumForBeats":"tshameka moropa [DRUM] wa [BEATS] meporo","music.playNoteForBeats":"tshameka noto [NOTE] ya [BEATS] meporo","music.restForBeats":"ikhuletse [BEATS] meporo","music.setInstrument":"tlhagisa sediriswa go [INSTRUMENT]","music.setTempo":"tlhagisa lebelo go [TEMPO]","pen.categoryName":"Pene","pen.changeColorParam":"fetola pene [COLOR_PARAM] ka [VALUE]","pen.changeHue":"fetola mmala wa pene ka [HUE]","pen.changeShade":"fetola mmala wa pene ka [SHADE]","pen.changeSize":"fetola bogolo ba pene ka [SIZE]","pen.clear":"phimola tsotlhe","pen.colorMenu.brightness":"phatshimo","pen.colorMenu.color":"mmala","pen.colorMenu.saturation":"Go tlala","pen.colorMenu.transparency":"bosengbofitlha","pen.penDown":"pene fatshe","pen.penUp":"pene godimo","pen.setColor":"tlhagisa mmala wa pene go [COLOR]","pen.setColorParam":"tlhagisa pene [COLOR_PARAM] go [VALUE]","pen.setHue":"tlhagisa mmala wa pene go [HUE]","pen.setShade":"tlhagisa mmala wa pene go [SHADE]","pen.setSize":"tlhagisa bogolo ba pene go [SIZE]","pen.stamp":"setempe","text2speech.alto":"lentswe la bobedi","text2speech.categoryName":"Romela molaetsa ka puo","text2speech.defaultTextToSpeak":"dumela","text2speech.giant":"seganka","text2speech.kitten":"katsana","text2speech.setLanguageBlock":"tlhagisa puo go [LANGUAGE]","text2speech.setVoiceBlock":"tlhagisa lentswe go [VOICE]","text2speech.speakAndWaitBlock":"bua [WORDS]","text2speech.squeak":"lela","text2speech.tenor":"lentswe la boraro","translate.categoryName":"Ranola","translate.defaultTextToTranslate":"dumela","translate.translateBlock":"ranola [WORDS] go [LANGUAGE]","translate.viewerLanguage":"puo","videoSensing.categoryName":"Maikutlo a vidio","videoSensing.direction":"kaelo","videoSensing.motion":"tshikinyego","videoSensing.off":"timile","videoSensing.on":"tshubile","videoSensing.onFlipped":"timile","videoSensing.setVideoTransparency":"tlhagisa bosengbofitlha ba video [TRANSPARENCY]","videoSensing.sprite":"sprite","videoSensing.stage":"kgato","videoSensing.videoOn":"video [ATTRIBUTE] mo [SUBJECT]","videoSensing.videoToggle":"tshuma video [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"fa video e tshameka > [REFERENCE]","wedo2.getDistance":"sekgala","wedo2.getTiltAngle":"sekamisa enkele [TILT_DIRECTION]","wedo2.isTilted":"sekametse [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"ka tsela ele","wedo2.motorDirection.forward":"ka tsela e","wedo2.motorDirection.reverse":"busetswa kwa morago","wedo2.motorId.a":"motšhini A","wedo2.motorId.all":"metšhini yotlhe","wedo2.motorId.b":"motšhini B","wedo2.motorId.default":"motšhini","wedo2.motorOff":"tima [MOTOR_ID] ","wedo2.motorOn":"tshuma [MOTOR_ID] ","wedo2.motorOnFor":"tshuma [MOTOR_ID] [DURATION] metsotswana","wedo2.playNoteFor":"tshameka noto [NOTE] [DURATION] metsotswana","wedo2.setLightHue":"tshuma lebone la mmala go [HUE]","wedo2.setMotorDirection":"tlhagisa [MOTOR_ID] kaelo go [MOTOR_DIRECTION]","wedo2.startMotorPower":"tlhagisa [MOTOR_ID] maatla go [POWER]","wedo2.tiltDirection.any":"nngwe le nngwe","wedo2.tiltDirection.down":"tlase","wedo2.tiltDirection.left":"molema","wedo2.tiltDirection.right":"moja","wedo2.tiltDirection.up":"godimo","wedo2.whenDistance":"fa sekgala [OP] [REFERENCE]","wedo2.whenTilted":"fa e sekamisitswe [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Mmala","paint.paintEditor.saturation":"Go tlala","paint.paintEditor.brightness":"Phatsimo","paint.paintEditor.costume":"Seaparo","paint.paintEditor.group":"Setlhopa","paint.paintEditor.ungroup":"Kgobokanyolola","paint.paintEditor.undo":"Sutlha","paint.paintEditor.redo":"Dira gape","paint.paintEditor.forward":"Kwa pele","paint.paintEditor.backward":"Kwa morago","paint.paintEditor.front":"Fa pele","paint.paintEditor.back":"Morago","paint.paintEditor.more":"Oketsegileng","paint.modeTools.brushSize":"Tlolela kwa godimo le tlase","paint.modeTools.eraserSize":"Bogolo jwa sephimodi","paint.modeTools.copy":"Kopa","paint.modeTools.paste":"Kgomaretsa","paint.modeTools.delete":"Phimola","paint.modeTools.curved":"Obegile","paint.modeTools.pointed":"Supile","paint.modeTools.thickness":"Bokima","paint.modeTools.flipHorizontal":"Tlola go tswa mo letlhakoreng go ya go letlhakore le lengwe","paint.modeTools.flipVertical":"Tlolela kwa godimo le tlase","paint.modeTools.filled":"Tladitswe","paint.modeTools.outlined":"Tlhalositswe","paint.paintEditor.bitmap":"Fetolela go Bitmap","paint.paintEditor.vector":"Fetolela go Vector","paint.paintEditor.fill":"Tlatsa","paint.paintEditor.stroke":"Tlhalosa","paint.brushMode.brush":"Gotlha","paint.eraserMode.eraser":"Sephimodi","paint.fillMode.fill":"Tlatsa","paint.lineMode.line":"Mola","paint.ovalMode.oval":"Sediko","paint.rectMode.rect":"Khutlho nne tsepa","paint.reshapeMode.reshape":"Bopa gape ","paint.roundedRectMode.roundedRect":"Dikhutlonnetsepa tse di golokang","paint.selectMode.select":"Tlhopha","paint.textMode.text":"Mokwalo","paint.colorPicker.swap":"Refosana"},"sk":{"gui.alerts.tryAgain":"Skús znova uložiť","gui.alerts.download":"Ulož","gui.connection.reconnect":"Znova pripoj","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Batoh","gui.backpack.errorBackpack":"Chyba pri otváraní batohu","gui.backpack.loadingBackpack":"Otváram...","gui.backpack.more":"Viac","gui.backpack.emptyBackpack":"Batoh je prázdny","gui.unsupportedBrowser.label":"Scratch 3.0 nepodporuje tento prehliadač.","gui.cards.all-tutorials":"Návody","gui.cards.shrink":"Zbaľ","gui.cards.expand":"Rozbaľ","gui.cards.close":"Ukonči","gui.cards.more-things-to-try":"Vyskúšaj aj iné","gui.cards.see-more":"Ukáž viac","gui.comingSoon.message1":"Na tomto ešte pracujeme {emoji}","gui.comingSoon.message2":"Už čoskoro...","gui.comingSoon.message3":"Na tomto ešte pracujeme {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Nenašli sa zariadenia","gui.connection.auto-scanning.prescan":"Umiestni zariadenie blízko počítača a spusti vyhľadávanie.","gui.connection.auto-scanning.pressbutton":"Stlač tlačidlo na zariadení.","gui.connection.auto-scanning.start-search":"Vyhľadaj","gui.connection.connecting-searchbutton":"Vyhľadávam...","gui.connection.auto-scanning.try-again":"Skús znova","gui.connection.connected":"Pripojené","gui.connection.disconnect":"Odpoj","gui.connection.go-to-editor":"Prejdi do Editora","gui.connection.connecting-cancelbutton":"Pripájam...","gui.connection.error.errorMessage":"Ojoj, zdá sa, že sa niečo pokazilo.","gui.connection.error.tryagainbutton":"Skús znova","gui.connection.error.helpbutton":"Pomocník","gui.connection.peripheral-name-label":"Meno zariadenia","gui.connection.connect":"Pripoj","gui.connection.scanning.lookingforperipherals":"Vyhľadávam zariadenia","gui.connection.scanning.noPeripheralsFound":"Nenašiel som žiadne zariadenie","gui.connection.scanning.instructions":"Vyber si zariadenie zo zoznamu","gui.connection.search":"Znova","gui.connection.unavailable.installscratchlink":"Máš nainštalovaný a spustený program Scratch Link?","gui.connection.unavailable.enablebluetooth":"Skontroluj, či je Bluetooth zapnutý","gui.connection.unavailable.tryagainbutton":"Skús znova","gui.connection.unavailable.helpbutton":"Pomocník","gui.controls.go":"Spusti","gui.controls.stop":"Zastav","gui.crashMessage.label":"Ojoj, niečo sa pokazilo.","gui.crashMessage.errorNumber":"Túto chybu sme zaevidovali s číslom {errorId}","gui.crashMessage.reload":"Znova načítaj","gui.customProcedures.myblockModalTitle":"Nový blok","gui.customProcedures.addAnInputNumberText":"Pridaj vstup","gui.customProcedures.numberTextType":"číslo alebo text","gui.customProcedures.addAnInputBoolean":"Pridaj vstup","gui.customProcedures.booleanType":"logický","gui.customProcedures.addALabel":"Pridaj nápis","gui.customProcedures.runWithoutScreenRefresh":"Vykonaj bez obnovenia obrazovky","gui.customProcedures.cancel":"Odmietni","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Smer","gui.directionPicker.rotationStyles.allAround":"dokola","gui.directionPicker.rotationStyles.leftRight":"vľavo-vpravo","gui.directionPicker.rotationStyles.dontRotate":"neotáčaj","gui.gui.addExtension":"Pridaj rozšírenie","gui.gui.codeTab":"Scenáre","gui.gui.backdropsTab":"Pozadia","gui.gui.costumesTab":"Kostýmy","gui.gui.soundsTab":"Zvuky","gui.extensionLibrary.comingSoon":"Už čoskoro...","gui.extensionLibrary.requires":"Vyžaduje","gui.extensionLibrary.collaboration":"V spolupráci s","gui.library.filterPlaceholder":"Hľadať","gui.library.allTag":"Všetko","gui.loader.headline":"Otváram projekt","gui.loader.creating":"Vytváram projekt","gui.authorInfo.byUser":"od {username}","gui.menuBar.seeProjectPage":"Prejdi na stránku projektu","gui.menuBar.LanguageSelector":"výber jazyka","gui.menuBar.tutorialsLibrary":"Návody","gui.menuBar.restoreSprite":"Vráť postavu","gui.menuBar.restoreSound":"Vráť zvuk","gui.menuBar.restoreCostume":"Vráť kostým","gui.menuBar.restore":"Vráť","gui.menuBar.saveNow":"Ulož","gui.menuBar.saveAsCopy":"Ulož ako","gui.menuBar.remix":"Remixuj","gui.menuBar.new":"Nový","gui.menuBar.file":"Súbor","gui.menuBar.downloadToComputer":"Ulož do počítača","gui.menuBar.edit":"Úpravy","gui.menuBar.turboModeOff":"Vypni turbo","gui.menuBar.turboModeOn":"Zapni turbo","gui.gui.projectTitlePlaceholder":"Napíš názov projektu","gui.menuBar.isShared":"Zdieľaný","gui.menuBar.share":"Zdieľaj","gui.modal.help":"Pomocník","gui.modal.back":"Späť","gui.monitor.listMonitor.empty":"(prázdny)","gui.monitor.listMonitor.listLength":"dĺžka {length}","gui.monitor.contextMenu.default":"normálne","gui.monitor.contextMenu.large":"iba hodnota","gui.monitor.contextMenu.slider":"ako posúvač","gui.monitor.contextMenu.sliderRange":"change slider range","gui.monitor.contextMenu.import":"načítaj","gui.monitor.contextMenu.export":"ulož","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Play","gui.playButton.stop":"Stop","gui.gui.variableScopeOptionAllSprites":"Pre všetky postavy","gui.gui.variableScopeOptionSpriteOnly":"Len pre túto postavu","gui.gui.cloudVariableOption":"Cloudová premenná (uložená na serveri)","gui.gui.variablePromptAllSpritesMessage":"Táto premenná bude dostupná pre všetky postavy","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Odmietni","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Zastav","gui.playbackStep.playMsg":"Zahraj","gui.playbackStep.loadingMsg":"Otváram...","gui.playbackStep.saveMsg":"Ulož","gui.playbackStep.reRecordMsg":"Nahraj znova","gui.recordModal.title":"Nahraj zvuk","gui.recordingStep.beginRecord":"Stlač tlačidlo dolu a začni nahrávať ","gui.recordingStep.permission":"{arrow}Použitie mikrofónu si vyžaduje tvoj súhlas","gui.recordingStep.stop":"Skonči nahrávať","gui.recordingStep.record":"Nahraj","gui.sliderModal.min":"Minimum value","gui.sliderModal.max":"Maximum value","gui.sliderModal.title":"Change slider range","gui.sliderPrompt.cancel":"Cancel","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"zvuk","gui.soundEditor.play":"Zahraj","gui.soundEditor.stop":"Zastav","gui.soundEditor.copy":"Copy","gui.soundEditor.paste":"Paste","gui.soundEditor.copyToNew":"Copy to New","gui.soundEditor.delete":"Delete","gui.soundEditor.save":"Ulož","gui.soundEditor.undo":"Naspäť","gui.soundEditor.redo":"Znova","gui.soundEditor.faster":"Rýchlejšie","gui.soundEditor.slower":"Pomalšie","gui.soundEditor.echo":"Ozvena","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Hlasnejšie","gui.soundEditor.softer":"Tichšie","gui.soundEditor.reverse":"Odzadu","gui.soundEditor.fadeOut":"Fade out","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Mute","gui.SpriteInfo.spritePlaceholder":"Meno","gui.SpriteInfo.sprite":"Postava","gui.SpriteInfo.show":"Ukáž","gui.SpriteInfo.size":"Veľkosť","gui.spriteSelectorItem.contextMenuDuplicate":"duplikuj","gui.spriteSelectorItem.contextMenuExport":"ulož","gui.spriteSelectorItem.contextMenuDelete":"zruš","gui.spriteSelector.addSpriteFromLibrary":"Vyber si postavu","gui.spriteSelector.addSpriteFromPaint":"Nakresli","gui.spriteSelector.addSpriteFromSurprise":"Náhodne","gui.spriteSelector.addSpriteFromFile":"Zo súboru","gui.stageHeader.stageSizeLarge":"Prepni na veľkú scénu","gui.stageHeader.stageSizeSmall":"Prepni na malú scénu","gui.stageHeader.stageSizeFull":"Prejdi na režim celej obrazovky","gui.stageHeader.stageSizeUnFull":"Ukonči režim celej obrazovky","gui.stageHeader.fullscreenControl":"Na celú obrazovku","gui.spriteSelector.addBackdropFromLibrary":"Vyber si pozadie","gui.stageSelector.addBackdropFromPaint":"Nakresli","gui.stageSelector.addBackdropFromSurprise":"Náhodne","gui.stageSelector.addBackdropFromFile":"Zo súboru","gui.stageSelector.stage":"Scéna","gui.stageSelector.backdrops":"Pozadia","gui.telemetryOptIn.label":"Odošli štatistické údaje na zlepšenie verzie Scratch 3.0","gui.telemetryOptIn.body1":"Autori prostredia sa snažia lepšie rozumieť, ako sa používa Scratch 3.0. Ak nám chcete v tomto úsilí pomôcť, dovolte, aby sme automaticky dostávali informácie o práci s ním.","gui.telemetryOptIn.body2":"Zbierame informácie o voľbe jazyka, používaní blokov a niektorých akcií, napr. ukladaní, otváraní a nahrávaní projektu. NEZBIERAME žiadne osobné údaje. Prosíme, prečítaj si {privacyPolicyLink} a získaj viac informácii.","gui.telemetryOptIn.privacyPolicyLink":"Zásady ochrany súkromia","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Turbo","gui.webglModal.label":"Váš prehliadač nepodporuje WebGL.","gui.webglModal.webgllink":"nepodporuje WebGL","gui.costumeLibrary.chooseABackdrop":"Vyber si pozadie","gui.costumeLibrary.chooseACostume":"Vyber si kostým","gui.costumeTab.addBackdropFromLibrary":"Vyber si pozadie","gui.costumeTab.addCostumeFromLibrary":"Vyber si kostým","gui.costumeTab.addBlankCostume":"Nakresli","gui.costumeTab.addSurpriseCostume":"Náhodne","gui.costumeTab.addFileBackdrop":"Zo súboru","gui.costumeTab.addFileCostume":"Zo súboru","gui.extensionLibrary.chooseAnExtension":"Vyber si rozšírenie","gui.extensionLibrary.extensionUrl":"Zadaj webovú adresu rozšírenia","gui.monitors.importListColumnPrompt":"Ktorý stĺpec mám použiť (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Nemôžem začať nahrávať zvuk","gui.soundLibrary.chooseASound":"Vyber si zvuk","gui.soundTab.fileUploadSound":"Zo súboru","gui.soundTab.surpriseSound":"Náhodne","gui.soundTab.recordSound":"Nahraj","gui.soundTab.addSoundFromLibrary":"Vyber si zvuk","gui.spriteLibrary.chooseASprite":"Vyber si postavu","gui.tipsLibrary.tutorials":"Vyber si návod","gui.alerts.createsuccess":"Nový projekt vytvorený.","gui.alerts.createcopysuccess":"Kópia projektu bola uložená.","gui.alerts.createremixsuccess":"Odvodený projekt bol uložený.","gui.alerts.creating":"Vytváram nový projekt...","gui.alerts.creatingCopy":"Kopírujem projekt...","gui.alerts.creatingRemix":"Vytváram odvodený projekt...","gui.alerts.creatingError":"Nepodarilo sa vytvoriť projekt. Prosím, skús znova!","gui.alerts.savingError":"Projekt sa nepodarilo uložiť.","gui.alerts.savesuccess":"Projekt bol uložený.","gui.alerts.saving":"Ukladám projekt...","gui.alerts.cloudInfo":"Pozor, hodnotou cloudovej premennej môže byť iba číslo, nie znak alebo slovo. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Zisti viac","gui.alerts.importing":"Importing…","gui.defaultProject.variable":"premenná","gui.extension.music.name":"Hudba","gui.extension.music.description":"Hráme na nástroje a bicie.","gui.extension.pen.name":"Pero","gui.extension.pen.description":"Kreslíme perom.","gui.extension.videosensing.name":"Video zisťovanie","gui.extension.videosensing.description":"Vnímame pohyby pomocou kamery.","gui.extension.text2speech.name":"Syntéza reči","gui.extension.text2speech.description":"Dajme postavám hlas.","gui.extension.translate.name":"Preklad","gui.extension.translate.description":"Prekladáme text do iného jazyka.","gui.extension.makeymakey.description":"Vyrábame si vlastné klávesy.","gui.extension.microbit.description":"Programujme fyzické zariadenia.","gui.extension.microbit.connectingMessage":"Pripájam sa","gui.extension.ev3.description":"Vytvárame roboty a robotické hračky.","gui.extension.ev3.connectingMessage":"Pripájam sa. Presvedč sa, že pin na tvojom EV3 je nastavený na 1234.","gui.extension.boost.description":"Bring robotic creations to life.","gui.extension.boost.connectingMessage":"Connecting","gui.extension.wedo2.description":"Pracujeme s motormi a senzormi.","gui.extension.wedo2.connectingMessage":"Pripájam sa","gui.extension.gdxfor.description":"Sense push, pull, motion, and spin.","gui.extension.gdxfor.connectingMessage":"Connecting","gui.libraryTags.all":"Všetko","gui.libraryTags.animals":"Zvieratá","gui.libraryTags.dance":"Tanec","gui.libraryTags.effects":"Efekty","gui.libraryTags.fantasy":"Fantázia","gui.libraryTags.fashion":"Móda","gui.libraryTags.food":"Jedlo","gui.libraryTags.indoors":"Vnútri","gui.libraryTags.loops":"Slučky","gui.libraryTags.music":"Hudba","gui.libraryTags.notes":"Noty","gui.libraryTags.outdoors":"Vonku","gui.libraryTags.patterns":"Vzory","gui.libraryTags.people":"Ľudia","gui.libraryTags.percussion":"Bicie","gui.libraryTags.space":"Vesmír","gui.libraryTags.sports":"Šport","gui.libraryTags.underwater":"Pod vodou","gui.libraryTags.voice":"Hlasy","gui.libraryTags.wacky":"Šašoviny","gui.libraryTags.animation":"Animácie","gui.libraryTags.art":"Umenie","gui.libraryTags.games":"Hry","gui.libraryTags.stories":"Príbehy","gui.libraryTags.letters":"Písmená","gui.opcodeLabels.direction":"smer","gui.opcodeLabels.xposition":"pozícia x","gui.opcodeLabels.yposition":"pozícia y","gui.opcodeLabels.size":"veľkosť","gui.opcodeLabels.costumename":"meno kostýmu","gui.opcodeLabels.costumenumber":"číslo kostýmu","gui.opcodeLabels.backdropname":"meno pozadia","gui.opcodeLabels.backdropnumber":"číslo pozadia","gui.opcodeLabels.volume":"hlasitosť","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"odpoveď","gui.opcodeLabels.loudness":"hlasitosť","gui.opcodeLabels.username":"používateľ","gui.opcodeLabels.year":"rok","gui.opcodeLabels.month":"mesiac","gui.opcodeLabels.date":"deň v mesiaci","gui.opcodeLabels.dayofweek":"deň v týždni","gui.opcodeLabels.hour":"hodina","gui.opcodeLabels.minute":"minúta","gui.opcodeLabels.second":"sekunda","gui.opcodeLabels.timer":"časovač","gui.sharedMessages.backdrop":"pozadie{index}","gui.sharedMessages.costume":"kostým{index}","gui.sharedMessages.sprite":"Postava{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Replace contents of the current project?","gui.sharedMessages.loadFromComputerTitle":"Otvor z počítača","boost.color.any":"any color","boost.color.black":"black","boost.color.blue":"blue","boost.color.green":"green","boost.color.red":"red","boost.color.white":"white","boost.color.yellow":"yellow","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] position","boost.getTiltAngle":"tilt angle [TILT_DIRECTION]","boost.motorDirection.backward":"that way","boost.motorDirection.forward":"this way","boost.motorDirection.reverse":"reverse","boost.motorOff":"turn motor [MOTOR_ID] off","boost.motorOn":"turn motor [MOTOR_ID] on","boost.motorOnFor":"turn motor [MOTOR_ID] for [DURATION] seconds","boost.motorOnForRotation":"turn motor [MOTOR_ID] for [ROTATION] rotations","boost.seeingColor":"seeing [COLOR] brick?","boost.setLightHue":"set light color to [HUE]","boost.setMotorDirection":"set motor [MOTOR_ID] direction [MOTOR_DIRECTION]","boost.setMotorPower":"set motor [MOTOR_ID] speed to [POWER] %","boost.tiltDirection.any":"any","boost.tiltDirection.down":"down","boost.tiltDirection.left":"left","boost.tiltDirection.right":"right","boost.tiltDirection.up":"up","boost.whenColor":"when [COLOR] brick seen","boost.whenTilted":"when tilted [TILT_DIRECTION_ANY]","ev3.beepNote":"tón [NOTE] hraj [TIME] s","ev3.buttonPressed":"stlačené tlačidlo [PORT]?","ev3.getBrightness":"jas","ev3.getDistance":"vzdialenosť","ev3.getMotorPosition":"pozícia motora [PORT]","ev3.motorSetPower":"nastav výkon motora [PORT] na [POWER] %","ev3.motorTurnClockwise":"motor [PORT] otáčaj vpravo [TIME] s","ev3.motorTurnCounterClockwise":"motor [PORT] otáčaj vľavo [TIME] s","ev3.whenBrightnessLessThan":"pri jase < [DISTANCE]","ev3.whenButtonPressed":"pri stlačení tlačidla [PORT]","ev3.whenDistanceLessThan":"pri vzdialenosti < [DISTANCE]","gdxfor.getAcceleration":"zrýchenie [DIRECTION]","gdxfor.getForce":"sila","gdxfor.getSpin":"spin speed [DIRECTION]","gdxfor.getTilt":"tilt angle [TILT]","gdxfor.isFreeFalling":"falling?","gdxfor.isTilted":"tilted [TILT]?","gdxfor.pulled":"pulled","gdxfor.pushed":"pushed","gdxfor.shaken":"shaken","gdxfor.startedFalling":"started falling","gdxfor.tiltDirectionMenu.any":"any","gdxfor.tiltDirectionMenu.back":"back","gdxfor.tiltDirectionMenu.front":"front","gdxfor.tiltDirectionMenu.left":"left","gdxfor.tiltDirectionMenu.right":"right","gdxfor.turnedFaceDown":"turned face down","gdxfor.turnedFaceUp":"turned face up","gdxfor.whenForcePushedOrPulled":"when force sensor [PUSH_PULL]","gdxfor.whenGesture":"when [GESTURE]","gdxfor.whenTilted":"when tilted [TILT]","makeymakey.downArrow":"šípka dole","makeymakey.downArrowShort":"dole","makeymakey.leftArrow":"šípka vľavo","makeymakey.leftArrowShort":"vľavo","makeymakey.rightArrow":"šípka vpravo","makeymakey.rightArrowShort":"vpravo","makeymakey.spaceKey":"medzerník","makeymakey.upArrow":"šípka hore","makeymakey.upArrowShort":"hore","makeymakey.whenKeyPressed":"pri stlačení klávesu [KEY]","makeymakey.whenKeysPressedInOrder":"pri stlačení postupnosti [SEQUENCE]","microbit.buttonsMenu.any":"hociktorý","microbit.clearDisplay":"zmaž displej","microbit.defaultTextToDisplay":"Hello!","microbit.displaySymbol":"zobraz [MATRIX]","microbit.displayText":"zobraz text [TEXT]","microbit.gesturesMenu.jumped":"skoku","microbit.gesturesMenu.moved":"pohybe","microbit.gesturesMenu.shaken":"zatrasení","microbit.isButtonPressed":"tlačidlo [BTN] stlačené?","microbit.isTilted":"náklon smerom [DIRECTION]?","microbit.pinStateMenu.off":"vypnutý","microbit.pinStateMenu.on":"zapnutý","microbit.tiltAngle":"uhol náklonu [DIRECTION]","microbit.tiltDirectionMenu.any":"hociktorý","microbit.tiltDirectionMenu.back":"dozadu","microbit.tiltDirectionMenu.front":"dopredu","microbit.tiltDirectionMenu.left":"vľavo","microbit.tiltDirectionMenu.right":"vpravo","microbit.whenButtonPressed":"pri stlačení tlačidla [BTN]","microbit.whenGesture":"pri geste [GESTURE]","microbit.whenPinConnected":"pri zapojení pinu [PIN]","microbit.whenTilted":"pri náklone [DIRECTION]","music.categoryName":"Hudba","music.changeTempo":"zmeň tempo o [TEMPO]","music.drumBass":"(2) bubon","music.drumBongo":"(13) bongo","music.drumCabasa":"(15) cabasa","music.drumClaves":"(9) claves","music.drumClosedHiHat":"(6) zatvorená hajka","music.drumConga":"(14) konga","music.drumCowbell":"(11) kravský zvonec","music.drumCrashCymbal":"(4) činely","music.drumCuica":"(18) netlmená cuica","music.drumGuiro":"(16) guiro","music.drumHandClap":"(8) tlesknutie","music.drumOpenHiHat":"(5) otvorená hajka","music.drumSideStick":"(3) okraj bubna","music.drumSnare":"(1) bubienok","music.drumTambourine":"(7) tamburína","music.drumTriangle":"(12) triangel","music.drumVibraslap":"(17) vibraslap","music.drumWoodBlock":"(10) drevený blok","music.getTempo":"tempo","music.instrumentBass":"(6) kontrabas","music.instrumentBassoon":"(14) fagot","music.instrumentCello":"(8) violončelo","music.instrumentChoir":"(15) zbor","music.instrumentClarinet":"(10) klarinet","music.instrumentElectricGuitar":"(5) elektrická gitara","music.instrumentElectricPiano":"(2) elektrické klávesy","music.instrumentFlute":"(12) flauta","music.instrumentGuitar":"(4) gitara","music.instrumentMarimba":"(19) marimba","music.instrumentMusicBox":"(17) hracia skrinka","music.instrumentOrgan":"(3) organ","music.instrumentPiano":"(1) klavír","music.instrumentPizzicato":"(7) brnkanie prstom","music.instrumentSaxophone":"(11) saxofón","music.instrumentSteelDrum":"(18) plechový bubienok","music.instrumentSynthLead":"(20) syntetizátor sólo","music.instrumentSynthPad":"(21) syntetizátor pozadie","music.instrumentTrombone":"(9) trombón","music.instrumentVibraphone":"(16) vibrafón","music.instrumentWoodenFlute":"(13) zobcová flauta","music.midiPlayDrumForBeats":"zabubnuj [DRUM] taktov [BEATS]","music.midiSetInstrument":"nastav nástroj na [INSTRUMENT]","music.playDrumForBeats":"zabubnuj [DRUM] taktov [BEATS]","music.playNoteForBeats":"zahraj tón [NOTE] taktov [BEATS]","music.restForBeats":"nehraj taktov [BEATS]","music.setInstrument":"nastav nástroj na [INSTRUMENT]","music.setTempo":"nastav tempo na [TEMPO]","pen.categoryName":"Pero","pen.changeColorParam":"zmeň [COLOR_PARAM] pera o [VALUE]","pen.changeHue":"zmeň farbu pera o [HUE]","pen.changeShade":"zmeň odtieň pera o [SHADE]","pen.changeSize":"zmeň hrúbku pera o [SIZE]","pen.clear":"zmaž","pen.colorMenu.brightness":"jas","pen.colorMenu.color":"farba","pen.colorMenu.saturation":"sýtosť","pen.colorMenu.transparency":"priehľadnosť","pen.penDown":"pero zapni","pen.penUp":"pero vypni","pen.setColor":"nastav farbu pera na [COLOR]","pen.setColorParam":"nastav [COLOR_PARAM] pera na [VALUE]","pen.setHue":"nastav farbu pera na[HUE]","pen.setShade":"nastav odtieň pera na [SHADE]","pen.setSize":"nastav hrúbku pera na [SIZE]","pen.stamp":"opečiatkuj","text2speech.alto":"alt","text2speech.categoryName":"Text to Speech","text2speech.defaultTextToSpeak":"ahoj","text2speech.giant":"obor","text2speech.kitten":"mačiatko","text2speech.setLanguageBlock":"nastav jazyk na [LANGUAGE]","text2speech.setVoiceBlock":"nastav hlas na [VOICE]","text2speech.speakAndWaitBlock":"povedz [WORDS]","text2speech.squeak":"pisklavo","text2speech.tenor":"tenor","translate.categoryName":"prelož","translate.defaultTextToTranslate":"ahoj","translate.translateBlock":"prelož [WORDS] do [LANGUAGE]","translate.viewerLanguage":"jazyk","videoSensing.categoryName":"Video snímanie","videoSensing.direction":"smer","videoSensing.motion":"pohyb","videoSensing.off":"vypni","videoSensing.on":"zapni","videoSensing.onFlipped":"prepni","videoSensing.setVideoTransparency":"nastav priehľadnosť snímania na [TRANSPARENCY]","videoSensing.sprite":"postava","videoSensing.stage":"scéna","videoSensing.videoOn":"snímaný [ATTRIBUTE] na [SUBJECT]","videoSensing.videoToggle":"[VIDEO_STATE] snímanie","videoSensing.whenMotionGreaterThan":"pri snímanom pohybe > [REFERENCE]","wedo2.getDistance":"vzdialenosť","wedo2.getTiltAngle":"uhol náklonu [TILT_DIRECTION]","wedo2.isTilted":"náklon [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"vľavo","wedo2.motorDirection.forward":"vpravo","wedo2.motorDirection.reverse":"opačný","wedo2.motorId.a":"motor A","wedo2.motorId.all":"oba motory","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"vypni motor [MOTOR_ID]","wedo2.motorOn":"zapni motor [MOTOR_ID]","wedo2.motorOnFor":"zapni motor [MOTOR_ID] na [DURATION] s","wedo2.playNoteFor":"tón [NOTE] hraj [DURATION] s","wedo2.setLightHue":"nastav farbu svetla [HUE]","wedo2.setMotorDirection":"nastav smer [MOTOR_ID] na [MOTOR_DIRECTION]","wedo2.startMotorPower":"nastav rýchlosť motora [MOTOR_ID] na [POWER]","wedo2.tiltDirection.any":"hociktorý","wedo2.tiltDirection.down":"dole","wedo2.tiltDirection.left":"vľavo","wedo2.tiltDirection.right":"vpravo","wedo2.tiltDirection.up":"hore","wedo2.whenDistance":"pri vzdialenosti [OP] ako [REFERENCE]","wedo2.whenTilted":"pri naklonení [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"farba","paint.paintEditor.saturation":"sýtosť","paint.paintEditor.brightness":"jas","paint.paintEditor.costume":"kostým","paint.paintEditor.group":"Spoj","paint.paintEditor.ungroup":"Rozdeľ","paint.paintEditor.undo":"Naspäť","paint.paintEditor.redo":"Znova","paint.paintEditor.forward":"Dopredu","paint.paintEditor.backward":"Dozadu","paint.paintEditor.front":"Navrch","paint.paintEditor.back":"Naspodok","paint.paintEditor.more":"Viac","paint.modeTools.brushSize":"hrúbka","paint.modeTools.eraserSize":"hrúbka gumy","paint.modeTools.copy":"Kopíruj","paint.modeTools.paste":"Vlož","paint.modeTools.delete":"Zmaž","paint.modeTools.curved":"Krivky","paint.modeTools.pointed":"Hroty","paint.modeTools.thickness":"Hrúbka","paint.modeTools.flipHorizontal":"prevráť vodorovne","paint.modeTools.flipVertical":"prevráť zvislo","paint.modeTools.filled":"výplň","paint.modeTools.outlined":"obrys","paint.paintEditor.bitmap":"zmeň na raster","paint.paintEditor.vector":"zmeň na vektory","paint.paintEditor.fill":"výplň","paint.paintEditor.stroke":"obrys","paint.brushMode.brush":"štetec","paint.eraserMode.eraser":"guma","paint.fillMode.fill":"výplň","paint.lineMode.line":"úsečka","paint.ovalMode.oval":"elipsa (Shift: Kružnica)","paint.rectMode.rect":"obdĺžnik (Shift: štvorec)","paint.reshapeMode.reshape":"uprav tvar","paint.roundedRectMode.roundedRect":"zaoblený obdĺžnik","paint.selectMode.select":"označ","paint.textMode.text":"text","paint.colorPicker.swap":"zameň farby"},"sl":{"gui.alerts.tryAgain":"Poskusi ponovno","gui.alerts.download":"Prenesi","gui.connection.reconnect":"Ponovno poveži","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Shramba delčkov kode","gui.backpack.errorBackpack":"Napaka pri nalaganju shrambe delčkov kode","gui.backpack.loadingBackpack":"Nalagam...","gui.backpack.more":"Več","gui.backpack.emptyBackpack":"Shramba delčkov kode je prazna","gui.unsupportedBrowser.label":"Ta brskalnik ni podprt","gui.cards.all-tutorials":"Vadnice","gui.cards.shrink":"Skrči","gui.cards.expand":"Razširi","gui.cards.close":"Zapri","gui.cards.more-things-to-try":"Poskusi še več stvari!","gui.cards.see-more":"Oglej si še","gui.comingSoon.message1":"Ne skrbi, delamo na tem {emoji}","gui.comingSoon.message2":"Kmalu ...","gui.comingSoon.message3":"Delamo na tem {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Ni najdenih naprav","gui.connection.auto-scanning.prescan":"Poskrbi, da je naprava v bližini in nato prični z iskanjem.","gui.connection.auto-scanning.pressbutton":"Na napravi pritisni na gumb.","gui.connection.auto-scanning.start-search":"Začni z iskanjem","gui.connection.connecting-searchbutton":"Iščem...","gui.connection.auto-scanning.try-again":"Poskusi ponovno","gui.connection.connected":"Povezano","gui.connection.disconnect":"Prekini povezavo","gui.connection.go-to-editor":"V urejevalnik","gui.connection.connecting-cancelbutton":"Povezovanje...","gui.connection.error.errorMessage":"Ups, nekaj je šlo narobe.","gui.connection.error.tryagainbutton":"Poskusi ponovno","gui.connection.error.helpbutton":"Pomoč","gui.connection.peripheral-name-label":"Ime naprave","gui.connection.connect":"Poveži","gui.connection.scanning.lookingforperipherals":"Iščem naprave","gui.connection.scanning.noPeripheralsFound":"Ni najdenih naprav","gui.connection.scanning.instructions":"Izberi napravo z zgornjega spiska.","gui.connection.search":"Osveži","gui.connection.unavailable.installscratchlink":"Preveri, če je Scratch Link nameščen in zagnan","gui.connection.unavailable.enablebluetooth":"Preveri, če je Blootooth omogočen","gui.connection.unavailable.tryagainbutton":"Poskusi ponovno","gui.connection.unavailable.helpbutton":"Pomoč","gui.controls.go":"Pojdi","gui.controls.stop":"Ustavi","gui.crashMessage.label":"To pa je nerodno! Nekaj je šlo narobe.","gui.crashMessage.errorNumber":"Tvoja napaka je bila zabeležena s št. {errorId}","gui.crashMessage.reload":"Ponovno naloži","gui.customProcedures.myblockModalTitle":"Ustvari blok","gui.customProcedures.addAnInputNumberText":"Dodaj vnos","gui.customProcedures.numberTextType":"število ali besedilo","gui.customProcedures.addAnInputBoolean":"Dodaj vnos","gui.customProcedures.booleanType":"logične vrednosti","gui.customProcedures.addALabel":"Dodaj oznako","gui.customProcedures.runWithoutScreenRefresh":"Izvajaj brez osveževanja","gui.customProcedures.cancel":"Prekliči","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Smer","gui.directionPicker.rotationStyles.allAround":"Vsepovsod","gui.directionPicker.rotationStyles.leftRight":"Levo/Desno","gui.directionPicker.rotationStyles.dontRotate":"Ne obračaj","gui.gui.addExtension":"Dodaj razširitev","gui.gui.codeTab":"Koda","gui.gui.backdropsTab":"Ozadja","gui.gui.costumesTab":"Videzi","gui.gui.soundsTab":"Zvoki","gui.extensionLibrary.comingSoon":"Kmalu...","gui.extensionLibrary.requires":"Potrebno je","gui.extensionLibrary.collaboration":"Sodelovanje z","gui.library.filterPlaceholder":"Išči","gui.library.allTag":"Vse","gui.loader.headline":"Nalagam projekt","gui.loader.creating":"Ustvarjam projekt","gui.authorInfo.byUser":"avtor: {username}","gui.menuBar.seeProjectPage":"Glej stran projekta","gui.menuBar.LanguageSelector":"izbira jezika","gui.menuBar.tutorialsLibrary":"Vadnice","gui.menuBar.restoreSprite":"Povrni figuro","gui.menuBar.restoreSound":"Povrni zvok","gui.menuBar.restoreCostume":"Povrni videz","gui.menuBar.restore":"Povrni","gui.menuBar.saveNow":"Shrani takoj","gui.menuBar.saveAsCopy":"Shrani kot kopijo","gui.menuBar.remix":"Predelaj","gui.menuBar.new":"Nov","gui.menuBar.file":"Datoteka","gui.menuBar.downloadToComputer":"Shrani na računalnik","gui.menuBar.edit":"Uredi","gui.menuBar.turboModeOff":"Izključi Turbo način","gui.menuBar.turboModeOn":"Vključi Turbo način","gui.gui.projectTitlePlaceholder":"Tukaj je naslov projekt","gui.menuBar.isShared":"Deljeno","gui.menuBar.share":"Deli","gui.modal.help":"Pomoč","gui.modal.back":"Nazaj","gui.monitor.listMonitor.empty":"(prazno)","gui.monitor.listMonitor.listLength":"dolžina {length}","gui.monitor.contextMenu.default":"navaden prikaz","gui.monitor.contextMenu.large":"velik prikaz","gui.monitor.contextMenu.slider":"drsnik","gui.monitor.contextMenu.sliderRange":"spremeni območje drsnika","gui.monitor.contextMenu.import":"uvozi","gui.monitor.contextMenu.export":"izvozi","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Predvajaj","gui.playButton.stop":"Ustavi","gui.gui.variableScopeOptionAllSprites":"Za vse figure","gui.gui.variableScopeOptionSpriteOnly":"Samo za to figuro","gui.gui.cloudVariableOption":"Spremenljivka v oblaku (shranjena na strežniku)","gui.gui.variablePromptAllSpritesMessage":"Ta spremenljivka bo na voljo vsem figuram.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Prekliči","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Ustavi","gui.playbackStep.playMsg":"Predvajaj","gui.playbackStep.loadingMsg":"Nalagam ...","gui.playbackStep.saveMsg":"Shrani","gui.playbackStep.reRecordMsg":"Ponovno posnemi","gui.recordModal.title":"Posnemi zvok","gui.recordingStep.beginRecord":"Zaženi snemanje s klikom na spodnji gumb","gui.recordingStep.permission":"{arrow}Potrebujemo dovoljenje za uporabo tvojega mikrofona","gui.recordingStep.stop":"Ustavi snemanje","gui.recordingStep.record":"Snemaj","gui.sliderModal.min":"Najmanjša vrednost","gui.sliderModal.max":"Največja vrednost","gui.sliderModal.title":"Spremeni območje drsnika","gui.sliderPrompt.cancel":"Prekliči","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Zvok","gui.soundEditor.play":"Predvajaj","gui.soundEditor.stop":"Ustavi","gui.soundEditor.copy":"Kopiraj","gui.soundEditor.paste":"Prilepi","gui.soundEditor.copyToNew":"Kopiraj v novo","gui.soundEditor.delete":"Izbriši","gui.soundEditor.save":"Shrani","gui.soundEditor.undo":"Razveljavi","gui.soundEditor.redo":"Uveljavi","gui.soundEditor.faster":"Hitreje","gui.soundEditor.slower":"Počasneje","gui.soundEditor.echo":"Odmev","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Glasneje","gui.soundEditor.softer":"Mehkeje","gui.soundEditor.reverse":"Obrni","gui.soundEditor.fadeOut":"Znižuj glasnost","gui.soundEditor.fadeIn":"Zvišuj glasnost","gui.soundEditor.mute":"Utišaj","gui.SpriteInfo.spritePlaceholder":"Ime","gui.SpriteInfo.sprite":"Figura","gui.SpriteInfo.show":"Pokaži","gui.SpriteInfo.size":"Velikost","gui.spriteSelectorItem.contextMenuDuplicate":"podvoji","gui.spriteSelectorItem.contextMenuExport":"izvozi","gui.spriteSelectorItem.contextMenuDelete":"zbriši","gui.spriteSelector.addSpriteFromLibrary":"Izberi figuro","gui.spriteSelector.addSpriteFromPaint":"Nariši","gui.spriteSelector.addSpriteFromSurprise":"Presenečenje","gui.spriteSelector.addSpriteFromFile":"Naloži figuro","gui.stageHeader.stageSizeLarge":"Preklopi na večji oder","gui.stageHeader.stageSizeSmall":"Preklopi na manjši oder","gui.stageHeader.stageSizeFull":"Vklopi celozaslonski način","gui.stageHeader.stageSizeUnFull":"Izhod iz celozaslonskega načina","gui.stageHeader.fullscreenControl":"Celozaslonski način","gui.spriteSelector.addBackdropFromLibrary":"Izberi ozadje","gui.stageSelector.addBackdropFromPaint":"Paint","gui.stageSelector.addBackdropFromSurprise":"Presenečenje","gui.stageSelector.addBackdropFromFile":"Naloži ozadje","gui.stageSelector.stage":"Oder","gui.stageSelector.backdrops":"Ozadja","gui.telemetryOptIn.label":"Sporoči statistiko, da pomagaš izboljšati Scratch","gui.telemetryOptIn.body1":"Ekipa Scratch ves čas poskuša bolje razumeti, kako se Scratch uporablja širom sveta. K tem prizadevanjem lahko pripomoreš tako, da Scratchu dovoliš, da samodejno pošilja podatke o uporabi. ","gui.telemetryOptIn.body2":"Informacije, ki jih zbiramo, vsebujejo izbiro jezika, uporabo blokov in določene akcije, kot so shranjevanje, nalaganje in prenos projektov na splet. NE ZBIRAMO nobenih osebnih podatkov. Prosimo, oglej si povezavo {privacyPolicyLink} za več informacij.","gui.telemetryOptIn.privacyPolicyLink":"Politika zasebnosti","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Turbo način","gui.webglModal.label":"Tvoj brskalnik ne podpira WebGL","gui.webglModal.webgllink":"ne podpira WebGL","gui.costumeLibrary.chooseABackdrop":"Izberi ozadje","gui.costumeLibrary.chooseACostume":"Izberi videz","gui.costumeTab.addBackdropFromLibrary":"Izberi ozadje","gui.costumeTab.addCostumeFromLibrary":"Izberi videz","gui.costumeTab.addBlankCostume":"Nariši","gui.costumeTab.addSurpriseCostume":"Presenečenje","gui.costumeTab.addFileBackdrop":"Naloži ozadje","gui.costumeTab.addFileCostume":"Naloži videz","gui.extensionLibrary.chooseAnExtension":"Izberi razširitev","gui.extensionLibrary.extensionUrl":"Dodaj URL naslov razširitve","gui.monitors.importListColumnPrompt":"Kateri stolpec naj bo uporabljen (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Ni bilo mogoče snemati","gui.soundLibrary.chooseASound":"Izberi zvok","gui.soundTab.fileUploadSound":"Naloži zvočni posnetek...","gui.soundTab.surpriseSound":"Presenečenje","gui.soundTab.recordSound":"Snemaj","gui.soundTab.addSoundFromLibrary":"Izberi zvok","gui.spriteLibrary.chooseASprite":"Izberi figuro","gui.tipsLibrary.tutorials":"Izberi vadnico.","gui.alerts.createsuccess":"Nov projekt je ustvarjen.","gui.alerts.createcopysuccess":"Projekt je shranjen kot kopija.","gui.alerts.createremixsuccess":"Projekt shranjen kot predelava.","gui.alerts.creating":"Ustvarjanje novega...","gui.alerts.creatingCopy":"Kopiram projekt...","gui.alerts.creatingRemix":"Predelujem projekt...","gui.alerts.creatingError":"Projekta ni bilo možno ustvariti. Prosim, poskusite ponovno!","gui.alerts.savingError":"Nismo mogli shraniti projekta.","gui.alerts.savesuccess":"Projekt je shranjen.","gui.alerts.saving":"Shranjujem projekt...","gui.alerts.cloudInfo":"Oblačne spremenljivke podpirajo zgolj številke in ne črk ali simbolov. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Nauči se več.","gui.alerts.importing":"Uvažam...","gui.defaultProject.variable":"moja spremenljivka","gui.extension.music.name":"Glasba","gui.extension.music.description":"Igraj glasbila.","gui.extension.pen.name":"Svinčnik","gui.extension.pen.description":"Riši s figurami.","gui.extension.videosensing.name":"Video zaznavanje","gui.extension.videosensing.description":"Nadzor gibanja s kamero","gui.extension.text2speech.name":"Besedilo v govor","gui.extension.text2speech.description":"Naj tvoji projekti spregovorijo.","gui.extension.translate.name":"Prevedi","gui.extension.translate.description":"Prevedi v različne jezike.","gui.extension.makeymakey.description":"Poljubno stvar spremeni v tipko.","gui.extension.microbit.description":"Poveži svoje projekte s svetom.","gui.extension.microbit.connectingMessage":"Povezovanje","gui.extension.ev3.description":"Ustvari interaktivne robote in ... .","gui.extension.ev3.connectingMessage":"Povezovanje. preveri, da je pin na EV3 nastavljen na 1234.","gui.extension.boost.description":"Oživi robotske kreacije.","gui.extension.boost.connectingMessage":"Povezovanje","gui.extension.wedo2.description":"Gradi z motorji in senzorji.","gui.extension.wedo2.connectingMessage":"Povezovanje","gui.extension.gdxfor.description":"Zaznaj poriv, povlakm gibanje in vrtenje.","gui.extension.gdxfor.connectingMessage":"Povezovanje","gui.libraryTags.all":"Vse","gui.libraryTags.animals":"Živali","gui.libraryTags.dance":"Pleši","gui.libraryTags.effects":"Učinki","gui.libraryTags.fantasy":"Domišljija","gui.libraryTags.fashion":"Moda","gui.libraryTags.food":"Hrana","gui.libraryTags.indoors":"Notranjost","gui.libraryTags.loops":"Zanke","gui.libraryTags.music":"Glasba","gui.libraryTags.notes":"Zapiski","gui.libraryTags.outdoors":"Zunanjost","gui.libraryTags.patterns":"Vzorci","gui.libraryTags.people":"Osebe","gui.libraryTags.percussion":"Tolkala","gui.libraryTags.space":"Vesolje","gui.libraryTags.sports":"Šport","gui.libraryTags.underwater":"Pod vodo","gui.libraryTags.voice":"Glas","gui.libraryTags.wacky":"Wacky","gui.libraryTags.animation":"Animacije","gui.libraryTags.art":"Umetnost","gui.libraryTags.games":"Igre","gui.libraryTags.stories":"Zgodbe","gui.libraryTags.letters":"Črke","gui.opcodeLabels.direction":"smer","gui.opcodeLabels.xposition":"položaj x","gui.opcodeLabels.yposition":"položaj y","gui.opcodeLabels.size":"velikost","gui.opcodeLabels.costumename":"ime videza","gui.opcodeLabels.costumenumber":"številka preobleke","gui.opcodeLabels.backdropname":"ime ozadja","gui.opcodeLabels.backdropnumber":"številka ozadja","gui.opcodeLabels.volume":"glasnost","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"odgovor","gui.opcodeLabels.loudness":"glasnost","gui.opcodeLabels.username":"uporabniško ime","gui.opcodeLabels.year":"leto","gui.opcodeLabels.month":"mesec","gui.opcodeLabels.date":"datum","gui.opcodeLabels.dayofweek":"dan v tednu","gui.opcodeLabels.hour":"ura","gui.opcodeLabels.minute":"minuta","gui.opcodeLabels.second":"sekunda","gui.opcodeLabels.timer":"štoparica","gui.sharedMessages.backdrop":"ozadje{index}","gui.sharedMessages.costume":"preobleka{index}","gui.sharedMessages.sprite":"Lik{index}","gui.sharedMessages.pop":"poberi","gui.sharedMessages.replaceProjectWarning":"Ali zamenjam vsebino trenutnega projekta?","gui.sharedMessages.loadFromComputerTitle":"Naloži z računalnika","boost.color.any":"poljubna barva","boost.color.black":"črna","boost.color.blue":"modra","boost.color.green":"zelena","boost.color.red":"rdeča","boost.color.white":"bela","boost.color.yellow":"rumena","boost.getMotorPosition":"položaj motorja [MOTOR_REPORTER_ID] ","boost.getTiltAngle":"kot nagiba [TILT_DIRECTION]","boost.motorDirection.backward":"v tisto smer","boost.motorDirection.forward":"v to smer","boost.motorDirection.reverse":"obratno","boost.motorOff":"izklopi motor [MOTOR_ID] ","boost.motorOn":"vklopi motor [MOTOR_ID] ","boost.motorOnFor":"vklopi [MOTOR_ID] za [DURATION] sekund","boost.motorOnForRotation":"vklopi motor [MOTOR_ID] za [ROTATION] obratov","boost.seeingColor":"vidiš kocko, ki je [COLOR] ?","boost.setLightHue":"nastavi barvo svetlobe na [HUE]","boost.setMotorDirection":"nastavi smer motorja [MOTOR_ID] na [MOTOR_DIRECTION]","boost.setMotorPower":"motorju [MOTOR_ID] nastavi moč na [POWER] %","boost.tiltDirection.any":"poljubna","boost.tiltDirection.down":"dol","boost.tiltDirection.left":"levo","boost.tiltDirection.right":"desno","boost.tiltDirection.up":"gor","boost.whenColor":"ko vidiš kocko, ki je [COLOR]","boost.whenTilted":"ko je nagnjen [TILT_DIRECTION_ANY]","ev3.beepNote":"zapiskaj noto [NOTE] za [TIME] sekund","ev3.buttonPressed":"je gumb na [PORT] pritisnjen?","ev3.getBrightness":"svetlost","ev3.getDistance":"razdalja","ev3.getMotorPosition":"položaj motorja na [PORT]","ev3.motorSetPower":"motorju na [PORT] nastavi moč na [POWER] %","ev3.motorTurnClockwise":"motor na [PORT] obrni v smeri ure [TIME] sekund","ev3.motorTurnCounterClockwise":"motor [PORT]obrni v nasprotni smeri ure za [TIME] sekund","ev3.whenBrightnessLessThan":"ko je svetlost < [DISTANCE]","ev3.whenButtonPressed":"ko je gumb na [PORT] pritisnjen","ev3.whenDistanceLessThan":"ko je razdalja < [DISTANCE]","gdxfor.getAcceleration":"pospešek [DIRECTION]","gdxfor.getForce":"moč","gdxfor.getSpin":"hitrost vrtenja [DIRECTION]","gdxfor.getTilt":"kot nagiba [TILT]","gdxfor.isFreeFalling":"padajoč?","gdxfor.isTilted":"nagnjeno [TILT]?","gdxfor.pulled":"potegnjen","gdxfor.pushed":"potisnjen","gdxfor.shaken":"streseno","gdxfor.startedFalling":"začetek padanja","gdxfor.tiltDirectionMenu.any":"poljubna","gdxfor.tiltDirectionMenu.back":"zadaj","gdxfor.tiltDirectionMenu.front":"spredaj","gdxfor.tiltDirectionMenu.left":"levo","gdxfor.tiltDirectionMenu.right":"desno","gdxfor.turnedFaceDown":"obrnjen navzdol","gdxfor.turnedFaceUp":"obrnjen navzgor","gdxfor.whenForcePushedOrPulled":"ko je senzor sile [PUSH_PULL]","gdxfor.whenGesture":"ko je [GESTURE]","gdxfor.whenTilted":"ko je nagnjeno [TILT]","makeymakey.downArrow":"puščica dol","makeymakey.downArrowShort":"dol","makeymakey.leftArrow":"puščica levo","makeymakey.leftArrowShort":"levo","makeymakey.rightArrow":"puščica desno","makeymakey.rightArrowShort":"desno","makeymakey.spaceKey":"presledek","makeymakey.upArrow":"puščica gor","makeymakey.upArrowShort":"gor","makeymakey.whenKeyPressed":"ko je pritisnjena tipka [KEY] ","makeymakey.whenKeysPressedInOrder":"ko so tipke [SEQUENCE] pritisnjene v določenem vrstnem redu","microbit.buttonsMenu.any":"poljubna","microbit.clearDisplay":"pobriši prikazovalnik","microbit.defaultTextToDisplay":"Živjo!","microbit.displaySymbol":"prikaži [MATRIX]","microbit.displayText":"prikaži besedilo [TEXT]","microbit.gesturesMenu.jumped":"poskok","microbit.gesturesMenu.moved":"premaknjeno","microbit.gesturesMenu.shaken":"streseno","microbit.isButtonPressed":"[BTN] gumb pritisnjen?","microbit.isTilted":"nagnjeno [DIRECTION]?","microbit.pinStateMenu.off":"izključi","microbit.pinStateMenu.on":"vključi","microbit.tiltAngle":"kot nagiba [DIRECTION]","microbit.tiltDirectionMenu.any":"poljubna","microbit.tiltDirectionMenu.back":"zadaj","microbit.tiltDirectionMenu.front":"spredaj","microbit.tiltDirectionMenu.left":"levo","microbit.tiltDirectionMenu.right":"desno","microbit.whenButtonPressed":"ko je gumb [BTN]pritisnjen","microbit.whenGesture":"ko je [GESTURE]","microbit.whenPinConnected":"ko je pin [PIN] povezan","microbit.whenTilted":"ko je nagnjen [DIRECTION]","music.categoryName":"Glasba","music.changeTempo":"spremeni tempo za [TEMPO]","music.drumBass":"(2) Veliki boben","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Ropotulja kabasa","music.drumClaves":"(9) Palčke claves","music.drumClosedHiHat":"(6) zaprte činele","music.drumConga":"(14) Konga bobni","music.drumCowbell":"(11) Kravji zvonec","music.drumCrashCymbal":"(4) Crash činela","music.drumCuica":"(18) Boben Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Plosk","music.drumOpenHiHat":"(5) Enojna činela","music.drumSideStick":"(3) zvok Side Stick","music.drumSnare":"(1) Mali boben","music.drumTambourine":"(7) Tamburin","music.drumTriangle":"(12) Triangel","music.drumVibraslap":"(17) Udarec na vibrafon","music.drumWoodBlock":"(10) Leseni blok","music.getTempo":"tempo","music.instrumentBass":"(6) Bas","music.instrumentBassoon":"(14) fagot","music.instrumentCello":"(8) Čelo","music.instrumentChoir":"(15) Zbor","music.instrumentClarinet":"(10) Klarinet","music.instrumentElectricGuitar":"(5) Električna kitara","music.instrumentElectricPiano":"(2) Električni klavir","music.instrumentFlute":"(12) Piščal","music.instrumentGuitar":"(4) Kitara","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Lajna","music.instrumentOrgan":"(3) Orgle","music.instrumentPiano":"(1) Klavir","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saksofon","music.instrumentSteelDrum":"(18) Kovinski boben","music.instrumentSynthLead":"(20) sintetizator - vodilni zvok","music.instrumentSynthPad":"(21) Sintesajzer","music.instrumentTrombone":"(9) Trombon","music.instrumentVibraphone":"(16) Vibrafon","music.instrumentWoodenFlute":"(13) lesena piščal","music.midiPlayDrumForBeats":"na bobnu [DRUM] zaigraj [BEATS] udarcev","music.midiSetInstrument":"nastavi inštrument na [INSTRUMENT]","music.playDrumForBeats":"zaigraj na boben [DRUM] za [BEATS] udarcev","music.playNoteForBeats":"predvajaj noto [NOTE] za[BEATS] udarce","music.restForBeats":"pavza za [BEATS] udarcev","music.setInstrument":"nastavi inštrument na [INSTRUMENT]","music.setTempo":"nastavi tempo na [TEMPO]","pen.categoryName":"Svinčnik","pen.changeColorParam":"spremeni pero [COLOR_PARAM] za [VALUE]","pen.changeHue":"spremeni barvo peresa za [HUE]","pen.changeShade":"spremeni senco peresa za [SHADE]","pen.changeSize":"spremeni velikost peresa za [SIZE]","pen.clear":"izbriši vse","pen.colorMenu.brightness":"svetlost","pen.colorMenu.color":"barva","pen.colorMenu.saturation":"nasičenost","pen.colorMenu.transparency":"prosojnost","pen.penDown":"spusti pero","pen.penUp":"dvigni pero","pen.setColor":"nastavi barvo peresa na [COLOR]","pen.setColorParam":"nastavi pero [COLOR_PARAM] na [VALUE]","pen.setHue":"nastavi barvo peresa na [HUE]","pen.setShade":"nastavi senco peresa na [SHADE]","pen.setSize":"nastavi velikost peresa na [SIZE]","pen.stamp":"žig","text2speech.alto":"alto","text2speech.categoryName":"besedilo v govor","text2speech.defaultTextToSpeak":"Zdravo","text2speech.giant":"velikan","text2speech.kitten":"mucek","text2speech.setLanguageBlock":"nastavi jezik na [LANGUAGE]","text2speech.setVoiceBlock":"nastavi glas na [VOICE]","text2speech.speakAndWaitBlock":"reci [WORDS]","text2speech.squeak":"cviljenje","text2speech.tenor":"tenor","translate.categoryName":"Prevedi","translate.defaultTextToTranslate":"Zdravo","translate.translateBlock":"prevedi [WORDS] v [LANGUAGE]","translate.viewerLanguage":"jezik","videoSensing.categoryName":"Video zaznavanje","videoSensing.direction":"smer","videoSensing.motion":"gibanje","videoSensing.off":"izključi","videoSensing.on":"vključi","videoSensing.onFlipped":"vključeno zrcaljenje","videoSensing.setVideoTransparency":"nastavi prosojnost videa na [TRANSPARENCY]","videoSensing.sprite":"figura","videoSensing.stage":"oder","videoSensing.videoOn":"video [ATTRIBUTE] pri [SUBJECT]","videoSensing.videoToggle":"nastavi video [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"ko je video premik > [REFERENCE]","wedo2.getDistance":"razdalja","wedo2.getTiltAngle":"kot nagiba [TILT_DIRECTION]","wedo2.isTilted":"nagnjen [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"v tisto smer","wedo2.motorDirection.forward":"v to smer","wedo2.motorDirection.reverse":"obratno","wedo2.motorId.a":"motor A","wedo2.motorId.all":"vsi motorji","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"izključi [MOTOR_ID] ","wedo2.motorOn":"vključi [MOTOR_ID] ","wedo2.motorOnFor":"vključi [MOTOR_ID]za [DURATION] sekund","wedo2.playNoteFor":"predvajaj noto [NOTE] za [DURATION] sekund","wedo2.setLightHue":"snastavi barvo svetlobe na [HUE]","wedo2.setMotorDirection":"nastavi smer [MOTOR_ID] na [MOTOR_DIRECTION]","wedo2.startMotorPower":"za [MOTOR_ID] nastavi moč na [POWER]","wedo2.tiltDirection.any":"poljubna","wedo2.tiltDirection.down":"dol","wedo2.tiltDirection.left":"levo","wedo2.tiltDirection.right":"desno","wedo2.tiltDirection.up":"gor","wedo2.whenDistance":"ko je razdalja [OP] [REFERENCE]","wedo2.whenTilted":"ko je nagnjen [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Barva","paint.paintEditor.saturation":"nasičenost","paint.paintEditor.brightness":"Svetlost","paint.paintEditor.costume":"Videz","paint.paintEditor.group":"Združi","paint.paintEditor.ungroup":"Razdruži","paint.paintEditor.undo":"Razveljavi","paint.paintEditor.redo":"Uveljavi","paint.paintEditor.forward":"naprej","paint.paintEditor.backward":"nazaj","paint.paintEditor.front":"Spredaj","paint.paintEditor.back":"Nazaj","paint.paintEditor.more":"Več","paint.modeTools.brushSize":"Velikost","paint.modeTools.eraserSize":"Širina radirke","paint.modeTools.copy":"Kopiraj","paint.modeTools.paste":"prilepi","paint.modeTools.delete":"Izbriši","paint.modeTools.curved":"Zaobljeno","paint.modeTools.pointed":"Točkovno","paint.modeTools.thickness":"debelina","paint.modeTools.flipHorizontal":"Obrni vodoravno","paint.modeTools.flipVertical":"Obrni navpično","paint.modeTools.filled":"polnitev","paint.modeTools.outlined":"očrtano","paint.paintEditor.bitmap":"Pretvori v bitno sliko","paint.paintEditor.vector":"Pretvori v vektorsko sliko","paint.paintEditor.fill":"Zapolni","paint.paintEditor.stroke":"Obroba","paint.brushMode.brush":"Čopič","paint.eraserMode.eraser":"Radirka","paint.fillMode.fill":"Zapolni","paint.lineMode.line":"Črta","paint.ovalMode.oval":"Krog","paint.rectMode.rect":"Pravokotnik","paint.reshapeMode.reshape":"Preoblikuj","paint.roundedRectMode.roundedRect":"Zaokrožen pravokotnik","paint.selectMode.select":"Izberi","paint.textMode.text":"Besedilo","paint.colorPicker.swap":"zamenjaj","tw.alerts.autosaving":"Ustvarjanje obnovitvene različice...","tw.alerts.savedToDisk":"Shranjeno na računalnik.","tw.backpack.rename":"Novo ime:","tw.browserModal.desc":"Prepričajte se, da uporabljate sodobno različico brskalnika Google Chrome, Mozilla Firefox, Microsoft Edge ali Apple Safari.","tw.changeUsername.cannotChangeWhileRunning":"Uporabniškega imena ni mogoče spremeniti med izvajanjem projekta.","tw.cloudVariableBadge":"Ta projekt uporablja spremenljivke v oblaku. TurboWarp uporablja svoj strežnik za spremenljivke v oblaku, ki je neodvisen od Scratcha. Bodite pozorni, saj lahko kdorkoli uporabi poljubno uporabniško ime. {learnMore}","tw.code":"Izvirna koda","tw.confirmIncompatibleExtension":"Ta razširitev ni združljiva s Scratchem. Projektov, narejenih z njo, ni mogoče naložiti na Scratchevo spletno stran. Ste prepričani, da jo želite vključiti?","tw.customExtension.description":"Naložite razširitve z URL-jev. Za razvijalce razširitev. Poskusno.","tw.customExtension.name":"Razširitev po meri","tw.featuredProjectsStudio":"Ogled studia na Scratchu.","tw.feedback":"Povratne informacije in napake","tw.feedbackButton":"Povratne informacije za TurboWarp","tw.footer.credits":"Zasluge","tw.footer.disclaimer":"TurboWarp ni povezan s Scratchem, skupino Scratch ali fundacijo Scratch.","tw.footer.donate":"Prispevaj","tw.footer.embed":"Vgraditev","tw.footer.fosshost":"Gostovanje omogoča Fosshost","tw.footer.parameters":"URL parametri","tw.footer.translate":"Pomagajte prevesti TurboWarp","tw.gui.crashMessage.description":"Žal je videti, da je na tej strani prišlo do napake. Prosimo, da znova naložite stran, če želite poskusiti znova.","tw.gui.defaultProjectTitle":"Projekt","tw.guiDefaultTitle":"Izvedite Scratcheve projekte hitreje","tw.home.credit":"Opombe in zasluge","tw.home.description":"TurboWarp je spremenjena različica Scratcha, ki prevede projekte v JavaScript, da delujejo zelo hitro. Preizkusite ga tako, da zgoraj vnesete ID ali URL projekta ali pa spodaj izberete enega od izpostavljenih projektov.","tw.home.instructions":"Navodila","tw.input.tooltip":"Prilepite povezavo na Scratchev projekt sem!","tw.interpolationEnabled":"Interpolacija","tw.invalidParameters.clones":"Parameter \\"clone\\" v URL-ju ni veljaven","tw.invalidParameters.fps":"Parameter \\"fps\\" v URL-ju ni veljaven","tw.loadError":"Nalaganje projekta ni uspelo:{error}","tw.loader.assets.known":"Nalaganje projekta ({complete}/{total}) ...","tw.loader.assets.unknown":"Nalaganje projekta ...","tw.loader.data":"Nalaganje podatkov projekta ...","tw.loader.generic":"Nalaganje projekta ...","tw.menuBar.60off":"Izključi 60 FPS način","tw.menuBar.60on":"Vključi 60 FPS način","tw.menuBar.addons":"Dodatki","tw.menuBar.advanced":"Napredno","tw.menuBar.changeUsername":"Spremeni uporabniško ime","tw.menuBar.cloudOff":"Onemogoči spremenljivke v oblaku","tw.menuBar.cloudOn":"Omogoči spremenljivke v oblaku","tw.menuBar.cloudUnavailable":"Spremenljivke v oblaku niso na voljo","tw.menuBar.cloudUnavailableAlert":"Ni mogoče uporabiti spremenljivk v oblaku, verjetno zato, ker ste odprli urejevalnik","tw.menuBar.loadRestorePoint":"Naloži obnovitveno različico","tw.menuBar.moreSettings":"Napredne nastavitve","tw.menuBar.newFramerate":"Nov FPS:","tw.menuBar.reportError1":"Nekaterih skript ni bilo mogoče prevesti.","tw.menuBar.reportError2":"To je napaka. Prosimo, da jo prijavite.","tw.menuBar.saveAs":"Shrani kot {file}","tw.menuBar.seeInside":"Poglej v","tw.oldDownload":"Shrani v ločeno datoteko...","tw.openAdvanced":"Odpri napredne nastavitve","tw.paint.alpha":"Neprosojnost","tw.privacy":"Politika zasebnosti","tw.restorePoint.confirm":"Urejevalnik si zapomni eno obnovitveno točko za primer, da je nekaj narobe in pozabite shraniti projekt. Na to se ne zanašajte, saj ne moremo zagotoviti, da bo projekt popravljen. Naj jo poskusim naložiti?","tw.restorePoint.loadFail":"Nalaganje obnovitvene različice ni uspelo: {error}","tw.saveAs":"Shrani kot...","tw.saveTo":"Shrani v {file}","tw.scratchUnsafeCloud":"Če naredite to spremenljivko v oblaku, bo projekt prekoračil Scratchevo omejitev {number} spremenljivk. Nekatere spremenljivke ne bodo delovale, če projekt naložite v Scratch.","tw.settingsModal.customStageSize":"Velikost odra po meri:","tw.settingsModal.customStageSizeHelp":"Spremeni velikost Scratchevega odra iz običajne 480x360. Poskusite 640x360 za širokozaslonski prikaz. Samo zelo redki projekti se pravilno prilagodijo tej nastavitvi.","tw.settingsModal.dangerZone":"Nevarno območje","tw.settingsModal.disableCompiler":"Onemogoči prevajalnik","tw.settingsModal.disableCompilerHelp":"Izključi TurboWarpov prevajalnik. Morda boste to potrebovali med urejanjem projektov, da se skripte takoj posodobijo. Sicer je bolje, da te možnosti ne vključite.","tw.settingsModal.featured":"Izpostavljeno","tw.settingsModal.fps":"60 FPS (FPS po meri)","tw.settingsModal.fpsHelp":"Izvede skripte 60-krat na sekundo namesto 30-krat. Večina projektov ne deluje pravilno, če je ta nastavitev omogočena. V tem primeru preizkusite interpolacijo namesto 60 FPS načina. {customFramerate}.","tw.settingsModal.fpsHelp.customFramerate":"Kliknite, da uporabite hitrost, ki ni 30 ali 60 FPS","tw.settingsModal.help":"Kliknite za pomoč","tw.settingsModal.highQualityPen":"Visoka ločljivost svinčnika","tw.settingsModal.highQualityPenHelp":"Poveča ločljivost projektov, ki uporabljajo razširitev Svinčnik, in odstrani zaokroževanje koordinat v urejevalniku. Ta nastavitev ni primerna za vse projekte in lahko vpliva na hitrost delovanja.","tw.settingsModal.infiniteClones":"Neskončno klonov","tw.settingsModal.infiniteClonesHelp":"Odstrani Scratchevo omejitev 300 klonov.","tw.settingsModal.interpolation":"Interpolacija","tw.settingsModal.interpolationHelp":"S pomočjo interpolacije naredi gibanje figur bolj tekoče. Interpolacije ne uporabljajte za 3D projekte, projekte, ki uporabljajo svinčnik in počasne projekte. Zaradi interpolacije delovali počasneje, ne da bi izgledali bolje.","tw.settingsModal.largeStageWarning":"Uporaba tako velikega odra ni priporočena! Namesto tega nastavite manjšo velikost z istim razmerjem stranic, saj jo bo celozaslonski način povečal, da jo prilagodi uporabnikovemu zaslonu.","tw.settingsModal.removeFencing":"Odstrani omejitve premikanja figur","tw.settingsModal.removeFencingHelp":"Omogoči figuram, da se premaknejo ven iz odra in postanejo poljubno velike ali majhne ter omogoči uporabo blokov za zaznavanje dotikanja zunaj odra.","tw.settingsModal.removeLimits":"Odstrani omejitve","tw.settingsModal.removeMiscLimits":"Odstrani razne omejitve","tw.settingsModal.removeMiscLimitsHelp":"Odstrani omejitve zvočnih učinkov in velikosti svinčnika.","tw.settingsModal.storeProjectOptions":"Shrani nastavitve v projektu","tw.settingsModal.storeProjectOptionsHelp":"Shrani izbrane nastavitve v projektu. TurboWarp jih bo uporabil, ko naslednjič naloži ta projekt. Warp timer in onemogočen prevajalnik ne bosta shranjena.","tw.settingsModal.title":"Napredne nastavitve","tw.settingsModal.warpTimerHelp":"Preveri, če pride do dolge ali neskončne zanke, in v tem primeru zmanjša hitrost osveževanja zaslona, namesto da bi skripto zamrznil. To pogosto prepreči sesutje, vendar vpliva na hitrost projekta, zato običajno ni vključeno zunaj urejevalnika.","tw.spriteSelectorItem.rename":"preimenuj","tw.studioview.authorAttribution":"{author}","tw.studioview.error":"Pri nalaganju naslednje strani projektov je prišlo do napake.","tw.studioview.hoverText":"{title} avtorja {author}","tw.twExtension.description":"Čudni novi bloki. Niso združljivi s Scratchem.","tw.twExtension.name":"TurboWarpovi bloki","tw.unshared.1":"Dostop do nedeljenih projektov z njihovim ID-jem nekoč v prihodnosti ne bo več mogoč zaradi načrtovanih sprememb v Scratchevem programskem vmesniku.","tw.unshared.2":"Za več informacij obiščite: {link}","tw.usernameModal.help":"Ta vrednost bo shranjena v vašem brskalniku. Morda bo zapisana med uporabo projektov, ki vsebujejo spremenljivke v oblaku.","tw.usernameModal.help2":"Vrednosti, ki se ne ujemajo z obstoječim računom na Scratchu, bo strežnik za spremenljivke v oblaku običajno zavrnil. Priporočamo, da te nastavitve ne spreminjate ali pa uporabite svoje uporabniško ime na Scratchu.","tw.usernameModal.mustChange":"Strežnik za spremenljivke v oblaku misli, da vaše uporabniško ime morda ni varno. Prosimo, daga spremenite ali {resetIt}.","tw.usernameModal.mustChange.resetIt":"ga ponastavite (priporočeno)","tw.usernameModal.reset":"Ponastavi","tw.usernameModal.title":"Spremeni uporabniško ime","tw.viewFeaturedProjects":"Kliknite za ogled izpostavljenih projektov.","tw.viewOnScratch":"Ogled projekta na Scratchu","tw.webglModal.description":"Žal je videti, da vaš brskalnik ali računalnik ne podpira {webGlLink}. Ta stran potrebuje to tehnologijo za delovanje. Poskusite posodobiti svoj brskalnik in gonilnike ali znova zagnati svoj računalnik."},"sr":{"gui.alerts.tryAgain":"Покушај поново","gui.alerts.download":"Преузми","gui.connection.reconnect":"Поновно повезивање","gui.backpack.costumeLabel":"костим","gui.backpack.soundLabel":"звук","gui.backpack.scriptLabel":"програм","gui.backpack.spriteLabel":"лик","gui.backpack.header":"Остава","gui.backpack.errorBackpack":"Грешка при учитавању оставе","gui.backpack.loadingBackpack":"Учитавање...","gui.backpack.more":"Више","gui.backpack.emptyBackpack":"Остава је празна","gui.unsupportedBrowser.label":"Прегледач интернета није подржан","gui.cards.all-tutorials":"Приручници","gui.cards.shrink":"Умањи","gui.cards.expand":"Увећај","gui.cards.close":"Затвори","gui.cards.more-things-to-try":"Више ствари за испробавање!","gui.cards.see-more":"Погледај више","gui.comingSoon.message1":"Не брини, радимо на томе {emoji}","gui.comingSoon.message2":"Очекуј убрзо","gui.comingSoon.message3":"Тренутно радимо на томе {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Нема уређаја","gui.connection.auto-scanning.prescan":"Постави свој уређај близу, затим почни са претраживањем.","gui.connection.auto-scanning.pressbutton":"Притисни дугме на свом уређају.","gui.connection.auto-scanning.start-search":"Почни претраживање","gui.connection.connecting-searchbutton":"Претражујем...","gui.connection.auto-scanning.try-again":"Пробај поново","gui.connection.connected":"Повезан","gui.connection.disconnect":"Искључи","gui.connection.go-to-editor":"Иди у едитор","gui.connection.connecting-cancelbutton":"Повезивање...","gui.connection.error.errorMessage":"Упс, изгледа да нешто није уреду.","gui.connection.error.tryagainbutton":"Пробај поново","gui.connection.error.helpbutton":"Помоћ","gui.connection.peripheral-name-label":"Име уређаја","gui.connection.connect":"Повежи","gui.connection.scanning.lookingforperipherals":"Тражим уређаје","gui.connection.scanning.noPeripheralsFound":"Нема уређаја","gui.connection.scanning.instructions":"Изабери свој уређај са листе.","gui.connection.search":"Освежи","gui.connection.unavailable.installscratchlink":"Увери се да си инсталирао Скрач везу и да ради","gui.connection.unavailable.enablebluetooth":"Провери де ли је блутут омогућен","gui.connection.unavailable.tryagainbutton":"Пробај поново","gui.connection.unavailable.helpbutton":"Помоћ","gui.controls.go":"Крени","gui.controls.stop":"Заустави","gui.crashMessage.label":"Ух! Нешто није у реду.","gui.crashMessage.errorNumber":"Твоја грешка је евидентирана под идентификатором {errorId}","gui.crashMessage.reload":"Поново учитај","gui.customProcedures.myblockModalTitle":"Направи блок","gui.customProcedures.addAnInputNumberText":"Додај улаз","gui.customProcedures.numberTextType":"број или текст","gui.customProcedures.addAnInputBoolean":"Додај унос","gui.customProcedures.booleanType":"булов израз","gui.customProcedures.addALabel":"Додај натпис","gui.customProcedures.runWithoutScreenRefresh":"Изврши без освежавања екрана","gui.customProcedures.cancel":"Откажи","gui.customProcedures.ok":"У реду","gui.SpriteInfo.direction":"Смер","gui.directionPicker.rotationStyles.allAround":"На све стране","gui.directionPicker.rotationStyles.leftRight":"Лево/десно","gui.directionPicker.rotationStyles.dontRotate":"Без окретања","gui.gui.addExtension":"Додај проширење","gui.gui.codeTab":"Програм","gui.gui.backdropsTab":"Позадине","gui.gui.costumesTab":"Костими","gui.gui.soundsTab":"Звукови","gui.extensionLibrary.comingSoon":"Очекуј убрзо","gui.extensionLibrary.requires":"Захтева","gui.extensionLibrary.collaboration":"Сарадња са","gui.library.filterPlaceholder":"Тражи","gui.library.allTag":"Сви","gui.loader.headline":"Учитавам пројекат","gui.loader.creating":"Прављење пројекта","gui.authorInfo.byUser":"по {username}","gui.menuBar.seeProjectPage":"Погледај страну пројекта","gui.menuBar.LanguageSelector":"бирач језика","gui.menuBar.tutorialsLibrary":"Приручници","gui.menuBar.restoreSprite":"Поврати лик","gui.menuBar.restoreSound":"Поврати звук","gui.menuBar.restoreCostume":"Поврати костим","gui.menuBar.restore":"Поврати","gui.menuBar.saveNow":"Сачувај одмах","gui.menuBar.saveAsCopy":"Сачувај као копију","gui.menuBar.remix":"Преради","gui.menuBar.new":"Ново","gui.menuBar.file":"Датотека","gui.menuBar.downloadToComputer":"Сачувај на свом рачунару","gui.menuBar.edit":"Уреди","gui.menuBar.turboModeOff":"Искључи турбо начин","gui.menuBar.turboModeOn":"Укључи турбо начин","gui.gui.projectTitlePlaceholder":"Наслов пројекта","gui.menuBar.isShared":"Дељено","gui.menuBar.share":"Објави (дели)","gui.modal.help":"Помоћ","gui.modal.back":"Назад","gui.monitor.listMonitor.empty":"(празно)","gui.monitor.listMonitor.listLength":"дужина {length}","gui.monitor.contextMenu.default":"нормалан приказ","gui.monitor.contextMenu.large":"велики приказ","gui.monitor.contextMenu.slider":"клизач","gui.monitor.contextMenu.sliderRange":"промени опсег клизача","gui.monitor.contextMenu.import":"увези","gui.monitor.contextMenu.export":"извези","gui.monitor.contextMenu.hide":"сакриј","gui.playButton.play":"Репродукуј","gui.playButton.stop":"Заустави","gui.gui.variableScopeOptionAllSprites":"За све ликове","gui.gui.variableScopeOptionSpriteOnly":"Само за овај лик","gui.gui.cloudVariableOption":"Променљива у облаку (чува се на серверу путем интернета)","gui.gui.variablePromptAllSpritesMessage":"Променљива ће да буде доступна свим ликовима.","gui.gui.listPromptAllSpritesMessage":"Ова листа ће бити доступна свим ликовима.","gui.prompt.cancel":"Откажи","gui.prompt.ok":"У реду","gui.playbackStep.stopMsg":"Заустави","gui.playbackStep.playMsg":"Репродукуј","gui.playbackStep.loadingMsg":"Учитавање...","gui.playbackStep.saveMsg":"Сачувај","gui.playbackStep.reRecordMsg":"Поново сними","gui.recordModal.title":"Сними звук","gui.recordingStep.beginRecord":"Почни да снимаш притиснувши дугме испод","gui.recordingStep.permission":"{arrow}Потребна нам је твоја дозвола да би употребили твој микрофон","gui.recordingStep.stop":"Заустави снимање","gui.recordingStep.record":"Сними","gui.sliderModal.min":"минимална вредност","gui.sliderModal.max":"максимална вредност","gui.sliderModal.title":"Промени опсег клизача","gui.sliderPrompt.cancel":"Откажи","gui.sliderPrompt.ok":"У реду","gui.soundEditor.sound":"Звук","gui.soundEditor.play":"Репродукуј","gui.soundEditor.stop":"Заустави","gui.soundEditor.copy":"Умножи","gui.soundEditor.paste":"Уметни","gui.soundEditor.copyToNew":"Умножи у нови","gui.soundEditor.delete":"Обриши","gui.soundEditor.save":"Сачувај","gui.soundEditor.undo":"Опозови","gui.soundEditor.redo":"Понови","gui.soundEditor.faster":"Брже","gui.soundEditor.slower":"Спорије","gui.soundEditor.echo":"Одјек","gui.soundEditor.robot":"Робот","gui.soundEditor.louder":"Гласније","gui.soundEditor.softer":"Мекше","gui.soundEditor.reverse":"Окрени","gui.soundEditor.fadeOut":"Постепено изблди","gui.soundEditor.fadeIn":"Постепено прикажи","gui.soundEditor.mute":"Искључи звук","gui.SpriteInfo.spritePlaceholder":"Име","gui.SpriteInfo.sprite":"Лик","gui.SpriteInfo.show":"Прикажи","gui.SpriteInfo.size":"Величина","gui.spriteSelectorItem.contextMenuDuplicate":"умножи","gui.spriteSelectorItem.contextMenuExport":"извези","gui.spriteSelectorItem.contextMenuDelete":"обриши","gui.spriteSelector.addSpriteFromLibrary":"Изабери лик","gui.spriteSelector.addSpriteFromPaint":"Насликај","gui.spriteSelector.addSpriteFromSurprise":"Изненађење","gui.spriteSelector.addSpriteFromFile":"Пошаљи лик","gui.stageHeader.stageSizeLarge":"Пребаци на велику сцену","gui.stageHeader.stageSizeSmall":"Пребаци на малу сцену","gui.stageHeader.stageSizeFull":"Уђи у приказ преко целог екрана","gui.stageHeader.stageSizeUnFull":"Изађи из приказа преко целог екрана","gui.stageHeader.fullscreenControl":"Цео екран","gui.spriteSelector.addBackdropFromLibrary":"Одабери позадину","gui.stageSelector.addBackdropFromPaint":"Насликај","gui.stageSelector.addBackdropFromSurprise":"Изненађење","gui.stageSelector.addBackdropFromFile":"Пошаљи позадину","gui.stageSelector.stage":"Позорница","gui.stageSelector.backdrops":"Позадине","gui.telemetryOptIn.label":"Шаљи статистику да би усавршио Скрач","gui.telemetryOptIn.body1":"Скрач тим се стално труди да открије како се Скрач користи широм света. Да би помогао, можеш дозволити Скрачу да аутоматски шаље информације о коришћењу Скрач тиму. ","gui.telemetryOptIn.body2":"Информације које прикупљамо укључују избор језика, употребу блокова, и неке догађаје као што је чување, учитавање и слање пројеката. Ми НЕ сакупљамо личне податке. Молимо, погледајте нашу {privacyPolicyLink} за више података.","gui.telemetryOptIn.privacyPolicyLink":"Политика приватности","gui.telemetryOptIn.optInText":"Дели моје податке о коришћењу са Скрач тимом","gui.telemetryOptIn.optInTooltip":"Омогући телеметрију","gui.telemetryOptIn.optOutText":"Немој да делиш моје податке о коришћењу са Скрач тимом","gui.telemetryOptIn.optOutTooltip":"Онемогући телеметрију","gui.telemetryOptIn.settingWasUpdated":"Твоје подешавање је ажурирано.","gui.telemetryOptIn.buttonClose":"Затвори","gui.turboMode.active":"Турбо начин","gui.webglModal.label":"Твој прегледач интернета не подржава WebGL","gui.webglModal.webgllink":"не подржава WebGL","gui.costumeLibrary.chooseABackdrop":"Одабери позадину","gui.costumeLibrary.chooseACostume":"Изабери костим","gui.costumeTab.addBackdropFromLibrary":"Одабери позадину","gui.costumeTab.addCostumeFromLibrary":"Изабери костим","gui.costumeTab.addBlankCostume":"Насликај","gui.costumeTab.addSurpriseCostume":"Изненађење","gui.costumeTab.addFileBackdrop":"Пошаљи позадину","gui.costumeTab.addFileCostume":"Пошаљи костим","gui.extensionLibrary.chooseAnExtension":"Изабери проширење","gui.extensionLibrary.extensionUrl":"Унеси URL проширења","gui.monitors.importListColumnPrompt":"Која колона треба да се користи (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Не могу да започнем снимање","gui.soundLibrary.chooseASound":"Изабери звук","gui.soundTab.fileUploadSound":"Пошаљи звук","gui.soundTab.surpriseSound":"Изненађење","gui.soundTab.recordSound":"Сними","gui.soundTab.addSoundFromLibrary":"Изабери звук","gui.spriteLibrary.chooseASprite":"Изабери лик","gui.tipsLibrary.tutorials":"Изабери приручник","gui.alerts.createsuccess":"Нови пројекат је направљен.","gui.alerts.createcopysuccess":"Пројекат је сачуван као копија.","gui.alerts.createremixsuccess":"Пројекат сачуван као ремикс.","gui.alerts.creating":"Прављење новог...","gui.alerts.creatingCopy":"Прављење умножка пројекта...","gui.alerts.creatingRemix":"Ремиксовање пројекта...","gui.alerts.creatingError":"Не могу да направим пројекат. Молим те пробај поново!","gui.alerts.savingError":"Не могу да сачувам пројекат.","gui.alerts.savesuccess":"Пројекат је сачуван.","gui.alerts.saving":"Чување пројекта...","gui.alerts.cloudInfo":"Имајте у виду да променњиве у облаку могу бити само бројеви, а не могу бити слова и симболи {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Сазнај више.","gui.alerts.importing":"Учитава се...","gui.defaultProject.variable":"моја променљива","gui.extension.music.name":"Музика","gui.extension.music.description":"Свирај инструменте и бубњеве.","gui.extension.pen.name":"Оловка","gui.extension.pen.description":"Цртај помоћу својих ликова.","gui.extension.videosensing.name":"Видео детекција","gui.extension.videosensing.description":"Детектуј кретање камером.","gui.extension.text2speech.name":"Текст у Говор","gui.extension.text2speech.description":"Учини да пројекти пропричају","gui.extension.translate.name":"Преведи","gui.extension.translate.description":"Преводи текст на разне језике.","gui.extension.makeymakey.description":"Претвори било шта у кључ.","gui.extension.microbit.description":"Повежи своје пројекте са светом.","gui.extension.microbit.connectingMessage":"Повезивање","gui.extension.ev3.description":"Гради интерактивне роботе и још много тога.","gui.extension.ev3.connectingMessage":"Повезујем се. Провери да ли је пин на твом EV3 постављен на 1234.","gui.extension.boost.description":"Оживи роботске креације.","gui.extension.boost.connectingMessage":"Повезивање","gui.extension.wedo2.description":"Гради са моторима и сензорима.","gui.extension.wedo2.connectingMessage":"Повезивање","gui.extension.gdxfor.description":"Детектуј гурање, повлачење, кретање и окретање.","gui.extension.gdxfor.connectingMessage":"Повезивање","gui.libraryTags.all":"Сви","gui.libraryTags.animals":"Животиње","gui.libraryTags.dance":"Плес","gui.libraryTags.effects":"Ефекти","gui.libraryTags.fantasy":"Фантазија","gui.libraryTags.fashion":"Мода","gui.libraryTags.food":"Храна","gui.libraryTags.indoors":"Унутра","gui.libraryTags.loops":"Петље","gui.libraryTags.music":"Музика","gui.libraryTags.notes":"Белешке","gui.libraryTags.outdoors":"Природа","gui.libraryTags.patterns":"Шаблони","gui.libraryTags.people":"Људи","gui.libraryTags.percussion":"Удараљке","gui.libraryTags.space":"Свемир","gui.libraryTags.sports":"Спортови","gui.libraryTags.underwater":"Под водом","gui.libraryTags.voice":"Глас","gui.libraryTags.wacky":"Откачено","gui.libraryTags.animation":"Анимација","gui.libraryTags.art":"Уметност","gui.libraryTags.games":"Игре","gui.libraryTags.stories":"Приче","gui.libraryTags.letters":"Слова","gui.opcodeLabels.direction":"смер","gui.opcodeLabels.xposition":"x положај","gui.opcodeLabels.yposition":"y положај","gui.opcodeLabels.size":"величина","gui.opcodeLabels.costumename":"име костима","gui.opcodeLabels.costumenumber":"број костима","gui.opcodeLabels.backdropname":"име позадине","gui.opcodeLabels.backdropnumber":"број позадине","gui.opcodeLabels.volume":"јачина звука","gui.opcodeLabels.tempo":"темпо","gui.opcodeLabels.answer":"одговор","gui.opcodeLabels.loudness":"јачина звука","gui.opcodeLabels.username":"корисничко име","gui.opcodeLabels.year":"година","gui.opcodeLabels.month":"месец","gui.opcodeLabels.date":"датум","gui.opcodeLabels.dayofweek":"дан у недељи","gui.opcodeLabels.hour":"сат","gui.opcodeLabels.minute":"минут","gui.opcodeLabels.second":"секунда","gui.opcodeLabels.timer":"тајмер","gui.sharedMessages.backdrop":"позадина{index}","gui.sharedMessages.costume":"костим{index}","gui.sharedMessages.sprite":"Лик{index}","gui.sharedMessages.pop":"поп","gui.sharedMessages.replaceProjectWarning":"Заменити садржај тренутног пројекта?","gui.sharedMessages.loadFromComputerTitle":"Пошаљи са свог рачунара","boost.color.any":"било која боја","boost.color.black":"црна","boost.color.blue":"плава","boost.color.green":"зелена","boost.color.red":"црвена","boost.color.white":"бела","boost.color.yellow":"жута","boost.getMotorPosition":"место мотора [MOTOR_REPORTER_ID]","boost.getTiltAngle":"угао нагиба [TILT_DIRECTION]","boost.motorDirection.backward":"онај смер","boost.motorDirection.forward":"овај смер","boost.motorDirection.reverse":"промени","boost.motorOff":"искључи мотор [MOTOR_ID]","boost.motorOn":"укључи мотор [MOTOR_ID]","boost.motorOnFor":"укључи мотор [MOTOR_ID] током [DURATION] секунди","boost.motorOnForRotation":"укључи мотор [MOTOR_ID] током [ROTATION] окрета","boost.seeingColor":"виђена је [COLOR] цигла?","boost.setLightHue":"подеси боју светлости на [HUE]","boost.setMotorDirection":"подеси смер мотора [MOTOR_ID]: [MOTOR_DIRECTION]","boost.setMotorPower":"подеси брзину мотора [MOTOR_ID] на [POWER] %","boost.tiltDirection.any":"било који","boost.tiltDirection.down":"доле","boost.tiltDirection.left":"лево","boost.tiltDirection.right":"десно","boost.tiltDirection.up":"горе","boost.whenColor":"када је цигла боје [COLOR] виђена","boost.whenTilted":"када је нагнуто [TILT_DIRECTION_ANY]","ev3.beepNote":"изведи ноту [NOTE] током [TIME] секунди","ev3.buttonPressed":"дугме [PORT] је притиснуто?","ev3.getBrightness":"осветљеност","ev3.getDistance":"растојање","ev3.getMotorPosition":"мотор [PORT]: место","ev3.motorSetPower":"мотор [PORT]: подеси снагу [POWER] %","ev3.motorTurnClockwise":"мотор [PORT]: окрени овако током [TIME] секунди","ev3.motorTurnCounterClockwise":"мотор [PORT]: окрени овако током [TIME] секунди","ev3.whenBrightnessLessThan":"кад је осветљеност < [DISTANCE]","ev3.whenButtonPressed":"када је дугме [PORT] притиснуто","ev3.whenDistanceLessThan":"када је растојање < [DISTANCE]","gdxfor.getAcceleration":"убрзање [DIRECTION]","gdxfor.getForce":"сила","gdxfor.getSpin":"брзина обртања [DIRECTION]","gdxfor.getTilt":"угао нагиба [TILT]","gdxfor.isFreeFalling":"пада?","gdxfor.isTilted":"нагнуто [TILT]?","gdxfor.pulled":"повучено","gdxfor.pushed":"гурнуто","gdxfor.shaken":"протресен","gdxfor.startedFalling":"пад је почео","gdxfor.tiltDirectionMenu.any":"било који","gdxfor.tiltDirectionMenu.back":"назад","gdxfor.tiltDirectionMenu.front":"напред","gdxfor.tiltDirectionMenu.left":"лево","gdxfor.tiltDirectionMenu.right":"десно","gdxfor.turnedFaceDown":"окренут наниже","gdxfor.turnedFaceUp":"окренут навише","gdxfor.whenForcePushedOrPulled":"када је сензор силе [PUSH_PULL]","gdxfor.whenGesture":"када је [GESTURE]","gdxfor.whenTilted":"када је нагнуто [TILT]","makeymakey.downArrow":"стрелица доле","makeymakey.downArrowShort":"доле","makeymakey.leftArrow":"стрелица лево","makeymakey.leftArrowShort":"лево","makeymakey.rightArrow":"стрелица десно","makeymakey.rightArrowShort":"десно","makeymakey.spaceKey":"размак","makeymakey.upArrow":"стрелица горе","makeymakey.upArrowShort":"горе","makeymakey.whenKeyPressed":"када је дирка [KEY] притиснута","makeymakey.whenKeysPressedInOrder":"када је [SEQUENCE] притиснуто по реду","microbit.buttonsMenu.any":"било који","microbit.clearDisplay":"обриши екран","microbit.defaultTextToDisplay":"Здраво!","microbit.displaySymbol":"прикажи [MATRIX]","microbit.displayText":"прикажи текст [TEXT]","microbit.gesturesMenu.jumped":"скок","microbit.gesturesMenu.moved":"померен","microbit.gesturesMenu.shaken":"протресен","microbit.isButtonPressed":"[BTN] дугме притиснуто?","microbit.isTilted":"нагнуто [DIRECTION]?","microbit.pinStateMenu.off":"искључено","microbit.pinStateMenu.on":"укључено","microbit.tiltAngle":"угао нагиба [DIRECTION]","microbit.tiltDirectionMenu.any":"било који","microbit.tiltDirectionMenu.back":"назад","microbit.tiltDirectionMenu.front":"напред","microbit.tiltDirectionMenu.left":"лево","microbit.tiltDirectionMenu.right":"десно","microbit.whenButtonPressed":"када је [BTN] дугме притиснуто","microbit.whenGesture":"када је [GESTURE]","microbit.whenPinConnected":"када је пин [PIN] повезан","microbit.whenTilted":"када је нагнуто [DIRECTION]","music.categoryName":"Музика","music.changeTempo":"промени темпо за [TEMPO]","music.drumBass":"(2) Бас бубањ","music.drumBongo":"(13) Бонго","music.drumCabasa":"(15) Кабаса","music.drumClaves":"(9) Клавес","music.drumClosedHiHat":"(6) Затворена контра-чинела","music.drumConga":"(14) Конга","music.drumCowbell":"(11) Звоно за краве","music.drumCrashCymbal":"(4) Креш чинела","music.drumCuica":"(18) Куика","music.drumGuiro":"(16) Гиро","music.drumHandClap":"(8) Пљесак дланом","music.drumOpenHiHat":"(5) Отворена контра-чинела","music.drumSideStick":"(3) Ивица добоша","music.drumSnare":"(1) Добош","music.drumTambourine":"(7) Даире","music.drumTriangle":"(12) Троугао","music.drumVibraslap":"(17) Вибраслап","music.drumWoodBlock":"(10) Дрвени блок","music.getTempo":"темпо","music.instrumentBass":"(6) Бас","music.instrumentBassoon":"(14) Фагот","music.instrumentCello":"(8) Виолончело","music.instrumentChoir":"(15) Хор","music.instrumentClarinet":"(10) Кларинет","music.instrumentElectricGuitar":"(5) Електрична гитара","music.instrumentElectricPiano":"(2) Електрични клавир","music.instrumentFlute":"(12) Флаута","music.instrumentGuitar":"(4) Гитара","music.instrumentMarimba":"(19) Маримба","music.instrumentMusicBox":"(17) Музичка кутија","music.instrumentOrgan":"(3) Оргуље","music.instrumentPiano":"(1) Клавир","music.instrumentPizzicato":"(7) Пицикато","music.instrumentSaxophone":"(11) Саксофон","music.instrumentSteelDrum":"(18) Метални бубањ","music.instrumentSynthLead":"(20) Синти вођица","music.instrumentSynthPad":"(21) Синти педала","music.instrumentTrombone":"(9) Тромбон","music.instrumentVibraphone":"(16) Вибрафон","music.instrumentWoodenFlute":"(13) Дрвена флаута","music.midiPlayDrumForBeats":"удараљка [DRUM] током [BEATS] откуцаја","music.midiSetInstrument":"нека инструмент буде [INSTRUMENT]","music.playDrumForBeats":"удараљка [DRUM] током [BEATS] откуцаја","music.playNoteForBeats":"свирај ноту [NOTE] током [BEATS] откуцаја","music.restForBeats":"пауза [BEATS] откуцаја","music.setInstrument":"нека инструмент буде [INSTRUMENT]","music.setTempo":"нека темпо буде [TEMPO]","pen.categoryName":"Оловка","pen.changeColorParam":"промени [COLOR_PARAM] оловке за [VALUE]","pen.changeHue":"промени боју оловке за [HUE]","pen.changeShade":"промени сенку оловке за [SHADE]","pen.changeSize":"промени дебљину оловке за [SIZE]","pen.clear":"обриши све","pen.colorMenu.brightness":"осветљеност","pen.colorMenu.color":"боја","pen.colorMenu.saturation":"засићење","pen.colorMenu.transparency":"провидност","pen.penDown":"спусти оловку","pen.penUp":"подигни оловку","pen.setColor":"нека боја оловке буде [COLOR]","pen.setColorParam":"нека [COLOR_PARAM] оловке буде [VALUE]","pen.setHue":"нека боја оловке буде [HUE]","pen.setShade":"нека сенка оловке буде [SHADE]","pen.setSize":"нека дебљина оловке буде [SIZE]","pen.stamp":"печат","text2speech.alto":"алт","text2speech.categoryName":"Текст у Говор","text2speech.defaultTextToSpeak":"здраво","text2speech.giant":"џин","text2speech.kitten":"маца","text2speech.setLanguageBlock":"нека језик буде [LANGUAGE]","text2speech.setVoiceBlock":"нека глас буде [VOICE]","text2speech.speakAndWaitBlock":"изговори [WORDS]","text2speech.squeak":"писак","text2speech.tenor":"тенор","translate.categoryName":"Преведи","translate.defaultTextToTranslate":"здраво","translate.translateBlock":"преведи [WORDS] на [LANGUAGE]","translate.viewerLanguage":"језик","videoSensing.categoryName":"Видео детекција","videoSensing.direction":"смер","videoSensing.motion":"кретање","videoSensing.off":"искључено","videoSensing.on":"укључено","videoSensing.onFlipped":"измени укљученост","videoSensing.setVideoTransparency":"нека провидност видеа буде [TRANSPARENCY]","videoSensing.sprite":"лик","videoSensing.stage":"позорница","videoSensing.videoOn":"видео [ATTRIBUTE] на [SUBJECT]","videoSensing.videoToggle":"нека видео буде [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"када је кретање видеа > [REFERENCE]","wedo2.getDistance":"растојање","wedo2.getTiltAngle":"угао нагиба [TILT_DIRECTION]","wedo2.isTilted":"нагнуто [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"онај смер","wedo2.motorDirection.forward":"овај смер","wedo2.motorDirection.reverse":"промени","wedo2.motorId.a":"Мотор A","wedo2.motorId.all":"сви мотори","wedo2.motorId.b":"мотор B","wedo2.motorId.default":"мотор","wedo2.motorOff":"искључи [MOTOR_ID]","wedo2.motorOn":"укључи [MOTOR_ID]","wedo2.motorOnFor":"укључи [MOTOR_ID] током [DURATION] секунди","wedo2.playNoteFor":"свирај ноту [NOTE] током [DURATION] секунди","wedo2.setLightHue":"подеси боју светлости на [HUE]","wedo2.setMotorDirection":"подеси смер [MOTOR_ID] у [MOTOR_DIRECTION]","wedo2.startMotorPower":"подеси снагу [MOTOR_ID] на [POWER]","wedo2.tiltDirection.any":"било који","wedo2.tiltDirection.down":"доле","wedo2.tiltDirection.left":"лево","wedo2.tiltDirection.right":"десно","wedo2.tiltDirection.up":"горе","wedo2.whenDistance":"када је растојање [OP] од [REFERENCE]","wedo2.whenTilted":"када је нагнуто [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Боја","paint.paintEditor.saturation":"Засићење","paint.paintEditor.brightness":"Осветљеност","paint.paintEditor.costume":"Костим","paint.paintEditor.group":"Групиши","paint.paintEditor.ungroup":"Разгрупиши","paint.paintEditor.undo":"Опозови","paint.paintEditor.redo":"Понови","paint.paintEditor.forward":"Напред","paint.paintEditor.backward":"Назад","paint.paintEditor.front":"Напред","paint.paintEditor.back":"Назад","paint.paintEditor.more":"Више","paint.modeTools.brushSize":"Величина","paint.modeTools.eraserSize":"Величина брисача","paint.modeTools.copy":"Умножи","paint.modeTools.paste":"Уметни","paint.modeTools.delete":"Обриши","paint.modeTools.curved":"Заобљено","paint.modeTools.pointed":"Шиљаст","paint.modeTools.thickness":"Дебљина","paint.modeTools.flipHorizontal":"Обрни хоризонтално","paint.modeTools.flipVertical":"Обрни вертикално","paint.modeTools.filled":"Попуњено","paint.modeTools.outlined":"Контура","paint.paintEditor.bitmap":"Преведи у растерски облик","paint.paintEditor.vector":"Преведи у векторски облик","paint.paintEditor.fill":"Попуни","paint.paintEditor.stroke":"Контура","paint.brushMode.brush":"Четкица","paint.eraserMode.eraser":"Брисач","paint.fillMode.fill":"Попуни","paint.lineMode.line":"Линија","paint.ovalMode.oval":"Круг","paint.rectMode.rect":"Правоугаоник","paint.reshapeMode.reshape":"Преобликуј","paint.roundedRectMode.roundedRect":"Заобљени правоугаоник","paint.selectMode.select":"Изабери","paint.textMode.text":"Текст","paint.colorPicker.swap":"Замени","tw.alerts.autosaving":"Прављење тачке враћања...","tw.alerts.savedToDisk":"Сачувано на вашем компјутеру.","tw.backpack.rename":"Ново име:","tw.browserModal.desc":"Проверите да ли користите најновију верзију Google Chrome, Mozilla Firefox, Microsoft Edge или Apple Safari прегледача.","tw.changeUsername.cannotChangeWhileRunning":"Корисничко име се не може мењати док пројекат ради.","tw.cloudVariableBadge":"Овај пројекат користи променљиве у облаку. TurboWarp користи сопствени сервер за ове променљиве различит од Scratch-овог. Чувајте се лажног представаљања јер свако може променити своје корисничко име у било шта. {learnMore}","tw.code":"Изворни код","tw.confirmIncompatibleExtension":"Ово проширење није компатибилно са Scratch-ом. Пројекти са њим се не могу отпремити на Scratch сајт. Да ли сте сигурни да желите да га укључите?","tw.customExtension.description":"Учитава прилагођена проширења са URL-а. За програмере. Експериментално.","tw.customExtension.name":"Прилагођена проширења","tw.featuredProjectsStudio":"Погледај студио на Scratch-у.","tw.feedback":"Повратне информације и грешке","tw.feedbackButton":"Повратне информације","tw.footer.credits":"Заслуге","tw.footer.disclaimer":"TurboWarp није повезан са Scratch-ом, Scratch тимом, или Scratch фондацијом.","tw.footer.embed":"Уграђивање","tw.footer.fosshost":"Хостинг обезбеђује Fosshost","tw.footer.parameters":"URL параметри","tw.footer.translate":"Помозите у преводу TurboWarp-а","tw.gui.defaultProjectTitle":"Пројекат","tw.guiDefaultTitle":"Убрзајте Scratch пројекте","tw.home.credit":"Белешке и заслуге","tw.home.description":"TurboWarp је Scratch мод који преводи пројекте у JavaScript и тако их убрзава. Испробајте га уносом пројектовог ID-а или URL-а у поље изнад или одабиром једног од истакнутог пројекта испод.","tw.home.instructions":"Упутства","tw.input.tooltip":"Прекопирај линк Scratch пројекта овде!","tw.interpolationEnabled":"Интерполација","tw.invalidParameters.clones":"\\"clone\\" URL параметар није валидан","tw.invalidParameters.fps":"\\"fps\\" URL параметар није валидан","tw.loadError":"Пројекат се није могао учитати: {error}","tw.loader.assets.known":"Преузимање ресурса ({complete}/{total}) ...","tw.loader.assets.unknown":"Преузимање ресурса ...","tw.loader.data":"Преузимање података пројекта ...","tw.loader.generic":"Учитавање пројекта ...","tw.menuBar.60off":"Искључи опцију 60 FPS","tw.menuBar.60on":"Укључи опцију 60 FPS","tw.menuBar.addons":"Додаци","tw.menuBar.advanced":"Напредно","tw.menuBar.changeUsername":"Промени корисничко име","tw.menuBar.cloudOff":"Онемогући променљиве у облаку","tw.menuBar.cloudOn":"Омогући променљиве у облаку","tw.menuBar.cloudUnavailable":"Променљиве у облаку нису доступне","tw.menuBar.cloudUnavailableAlert":"Променљиве у облаку се не могу користити, вероватно зато што сте у едитору.","tw.menuBar.loadRestorePoint":"Учитај тачку враћања","tw.menuBar.moreSettings":"Напредна подешавања","tw.menuBar.newFramerate":"Нови FPS:","tw.menuBar.reportError1":"Део кода се није могао превести.","tw.menuBar.reportError2":"Ово је грешка. Молимо Вас да је пријавите.","tw.menuBar.saveAs":"Сачувај као {file}","tw.menuBar.seeInside":"Погледај изнутра","tw.oldDownload":"Сачувај у посебну датотеку...","tw.paint.alpha":"Непровидност","tw.privacy":"Политика приватности","tw.saveAs":"Сачувај као...","tw.saveTo":"Сачувај у {file}","tw.settingsModal.customStageSize":"Прилагођена величина позорнице:","tw.settingsModal.customStageSizeHelp":"Мења величину Scratch-ове позорнице са 480x360 на нешто друго. Пробајте 640x360 да би позорница постала широки екран. Мало пројеката ће ово подржати.","tw.settingsModal.dangerZone":"Опасно","tw.settingsModal.disableCompiler":"Онемогући преводилац кода","tw.settingsModal.disableCompilerHelp":"Онемогућава TurboWarp-ов преводилац кода. Ово можете да укључите док програмирате тако да се код не ажурира одмах. У другим случајевима, ово подешавање не треба укључивати.","tw.settingsModal.featured":"Истакнуто","tw.settingsModal.fps":"60 FPS (Прилагођен FPS)","tw.settingsModal.fpsHelp":"Покреће код 60 пута у секунди уместо 30. Многи пројекти неће исправно радити са овим подешавањем. Уместо тога онда искористите Интерполацију уместо опције 60 FPS. {customFramerate}.","tw.settingsModal.fpsHelp.customFramerate":"Кликните за FPS који није 30 или 60","tw.settingsModal.help":"Кликни за помоћ","tw.settingsModal.highQualityPen":"Оловка високог квалитета","tw.settingsModal.highQualityPenHelp":"Црта пројекте са оловком у већој резолуцији и онемогућава заокругљивање координата у едитору. Ово подешавање није најбоље за неке пројекте и може утицати на перформансе.","tw.settingsModal.infiniteClones":"Бесконачно умножака","tw.settingsModal.infiniteClonesHelp":"Онемогућава Scratch-ову границу од 300 умножака","tw.settingsModal.interpolation":"Интерполација","tw.settingsModal.interpolationHelp":"Чини да пројекти изгледају брже помоћу интерполације кретања ликова. Интерполација се не треба користити за 3D пројекте, пројекте са оловком и пројекте који лагују јер ће радити спорије, а да не изгледају брже.","tw.settingsModal.largeStageWarning":"Коришћење оволике величине позорнице није препоручљиво! Уместо тога, користите мање величине са истим односом ширине и висине, а онда укључите приказ преко целог екрана да све повећа тако да се поклапа са корисниковим приказом.","tw.settingsModal.removeFencing":"Уклони границе","tw.settingsModal.removeFencingHelp":"Дозвољава ликовима да се крећу ван граница екрана, да им величина не буде ограничена, и чини да \\"додирује ли\\" блокови раде ван екрана.","tw.settingsModal.removeLimits":"Уклони граничне вредности","tw.settingsModal.removeMiscLimits":"Уклони различите максималне вредности","tw.settingsModal.removeMiscLimitsHelp":"Уклања граничне вредности за звучне ефекте и величину оловке.","tw.settingsModal.storeProjectOptions":"Складишти подешавања у пројекту","tw.settingsModal.storeProjectOptionsHelp":"Складишти одабрана подешавања у пројекту тако да се аутоматски примене када TurboWarp учита пројекат. Warp тајмер и онемогућавање преводиоца кода се неће сачувати.","tw.settingsModal.title":"Напредна подешавања","tw.settingsModal.warpTimer":"Warp тајмер","tw.settingsModal.warpTimerHelp":"Чини да код проверава да ли је заглављен у дугачкој или бескрајној петљи и смањује квалитет уместо заглављивања док се петља не заврши. Поправља већину кварова, али има значајан утицај на перформансе, па је подразумевано укључен само у едитору.","tw.spriteSelectorItem.rename":"преименуј","tw.studioview.authorAttribution":"од {author}","tw.studioview.error":"Десила се грешка у учитавању следеће странице пројеката.","tw.studioview.hoverText":"{title} од {author}","tw.twExtension.description":"Необични нови блокови. Нису компатибилни са Scratch-ом.","tw.twExtension.name":"TurboWarp блокови","tw.usernameModal.help":"Ова вредност ће бити сачувана у меморији вашег прегледача. Може се сама учитати када користите пројекте са променљивама у облику.","tw.usernameModal.help2":"Вредности које не одговарају валидном Scratch налогу ће бити одбијене од стране сервера променљивих у облаку. Препоручујемо да га оставите како јесте или га промените у своје Scratch корисничко име.","tw.usernameModal.mustChange":"Извињавамо се, али сервер променљивих у облаку мисли да је Ваше корисничко име можда небезбедно. Молимо Вас да га промените или {resetIt}.","tw.usernameModal.mustChange.resetIt":"ресејтујте га (препоручено)","tw.usernameModal.reset":"Ресетуј","tw.usernameModal.title":"Промени корисничко име","tw.viewFeaturedProjects":"Кликни да видиш истакнуте пројекте","tw.viewOnScratch":"Погледај пројекат на Scratch-у","tw.webglModal.description":"Нажалост, изгледа да Ваш прегледач или компјутер {webGlLink}. Ова технологија је неопходна сајту да исправно ради. Пробајте да ажурирате прегледач и графичке драјвере или рестартујте компјутер."},"fi":{"gui.alerts.tryAgain":"Yritä uudelleen","gui.alerts.download":"Lataa","gui.connection.reconnect":"Yhdistä uudelleen","gui.backpack.costumeLabel":"asuste","gui.backpack.soundLabel":"ääni","gui.backpack.scriptLabel":"skripti","gui.backpack.spriteLabel":"hahmo","gui.backpack.header":"Reppu","gui.backpack.errorBackpack":"Virhe reppua ladattaessa","gui.backpack.loadingBackpack":"Ladataan...","gui.backpack.more":"Enemmän","gui.backpack.emptyBackpack":"Reppu on tyhjä","gui.unsupportedBrowser.label":"Selainta ei tueta","gui.cards.all-tutorials":"Oppitunnit","gui.cards.shrink":"Pienennä","gui.cards.expand":"Laajenna","gui.cards.close":"Sulje","gui.cards.more-things-to-try":"Lisää kokeiltavia asioita!","gui.cards.see-more":"Lue lisää","gui.comingSoon.message1":"Älä huoli, toteutamme sitä {emoji}","gui.comingSoon.message2":"Tulossa pian...","gui.comingSoon.message3":"Toteutamme sitä {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Laitteita ei löytynyt","gui.connection.auto-scanning.prescan":"Tuo laite lähelle ja aloita haku.","gui.connection.auto-scanning.pressbutton":"Paina laitteen painiketta.","gui.connection.auto-scanning.start-search":"Aloita haku","gui.connection.connecting-searchbutton":"Haetaan...","gui.connection.auto-scanning.try-again":"Yritä uudelleen","gui.connection.connected":"Yhdistetty","gui.connection.disconnect":"Katkaise yhteys","gui.connection.go-to-editor":"Siirry editoriin","gui.connection.connecting-cancelbutton":"Yhdistetään...","gui.connection.error.errorMessage":"Hupsis, näyttää siltä, että jokin meni pieleen.","gui.connection.error.tryagainbutton":"Yritä uudelleen","gui.connection.error.helpbutton":"Apua","gui.connection.peripheral-name-label":"Laitteen nimi","gui.connection.connect":"Yhdistä","gui.connection.scanning.lookingforperipherals":"Etsitään laitteita","gui.connection.scanning.noPeripheralsFound":"Laitteita ei löytynyt","gui.connection.scanning.instructions":"Valitse laitteesi ylläolevalta listalta.","gui.connection.search":"Päivitä","gui.connection.unavailable.installscratchlink":"Varmista, että Scratch Link on asennettu ja käynnissä","gui.connection.unavailable.enablebluetooth":"Tarkista, että Bluetooth on käytössä","gui.connection.unavailable.tryagainbutton":"Yritä uudelleen","gui.connection.unavailable.helpbutton":"Apua","gui.controls.go":"Mene","gui.controls.stop":"Pysäytä","gui.crashMessage.label":"Hupsis! Jokin meni pieleen.","gui.crashMessage.errorNumber":"Virheesi kirjattiin tunnuksella {errorId}","gui.crashMessage.reload":"Lataa uudelleen","gui.customProcedures.myblockModalTitle":"Tee lohko","gui.customProcedures.addAnInputNumberText":"Lisää syöte","gui.customProcedures.numberTextType":"luku tai teksti","gui.customProcedures.addAnInputBoolean":"Lisää syöte","gui.customProcedures.booleanType":"totuusarvo","gui.customProcedures.addALabel":"Lisää nimike","gui.customProcedures.runWithoutScreenRefresh":"Suorita ilman ruudunpäivitystä","gui.customProcedures.cancel":"Peruuta","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Suunta","gui.directionPicker.rotationStyles.allAround":"Joka suuntaan","gui.directionPicker.rotationStyles.leftRight":"Vasen/Oikea","gui.directionPicker.rotationStyles.dontRotate":"Älä kierrä","gui.gui.addExtension":"Lisää laajennus","gui.gui.codeTab":"Koodi","gui.gui.backdropsTab":"Taustat","gui.gui.costumesTab":"Asusteet","gui.gui.soundsTab":"Äänet","gui.extensionLibrary.comingSoon":"Tulossa pian","gui.extensionLibrary.requires":"Vaatii","gui.extensionLibrary.collaboration":"Yhteistyössä","gui.library.filterPlaceholder":"Haku","gui.library.allTag":"Kaikki","gui.loader.headline":"Projektia ladataan","gui.loader.creating":"Luodaan projektia","gui.authorInfo.byUser":"tekijä: {username}","gui.menuBar.seeProjectPage":"Katso projektisivu","gui.menuBar.LanguageSelector":"kielen valitsin","gui.menuBar.tutorialsLibrary":"Oppitunnit","gui.menuBar.restoreSprite":"Palauta hahmo","gui.menuBar.restoreSound":"Palauta ääni","gui.menuBar.restoreCostume":"Palauta asuste","gui.menuBar.restore":"Palauta","gui.menuBar.saveNow":"Tallenna nyt","gui.menuBar.saveAsCopy":"Tallenna kopio","gui.menuBar.remix":"Remix","gui.menuBar.new":"Uusi","gui.menuBar.file":"Tiedosto","gui.menuBar.downloadToComputer":"Tallenna tietokoneellesi","gui.menuBar.edit":"Muokkaa","gui.menuBar.turboModeOff":"Sammuta turbotila","gui.menuBar.turboModeOn":"Käynnistä turbotila","gui.gui.projectTitlePlaceholder":"Projektin otsikko tähän","gui.menuBar.isShared":"Jaetut","gui.menuBar.share":"Jaa","gui.modal.help":"Apua","gui.modal.back":"Takaisin","gui.monitor.listMonitor.empty":"(tyhjä)","gui.monitor.listMonitor.listLength":"pituus {length}","gui.monitor.contextMenu.default":"normaali näyttö","gui.monitor.contextMenu.large":"suuri näyttö","gui.monitor.contextMenu.slider":"säädin","gui.monitor.contextMenu.sliderRange":"muuta säätimen rajoja","gui.monitor.contextMenu.import":"tuo","gui.monitor.contextMenu.export":"vie","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Pelaa","gui.playButton.stop":"Pysäytä","gui.gui.variableScopeOptionAllSprites":"Kaikille hahmoille","gui.gui.variableScopeOptionSpriteOnly":"Vain tälle hahmolle","gui.gui.cloudVariableOption":"Pilvimuuttuja (tallennettu palvelimelle)","gui.gui.variablePromptAllSpritesMessage":"Tämä muuttuja on saatavilla kaikille hahmoille.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Peru","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Pysäytä","gui.playbackStep.playMsg":"Toista","gui.playbackStep.loadingMsg":"Ladataan...","gui.playbackStep.saveMsg":"Tallenna","gui.playbackStep.reRecordMsg":"Äänitä uudelleen","gui.recordModal.title":"Äänitä ääni","gui.recordingStep.beginRecord":"Aloita tallennus napsauttamalla alla olevaa painiketta","gui.recordingStep.permission":"{arrow}Tarvitsemme lupasi, jotta mikrofonia voidaan käyttää","gui.recordingStep.stop":"Lopeta tallennus","gui.recordingStep.record":"Äänitä","gui.sliderModal.min":"Vähimmäisarvo","gui.sliderModal.max":"Enimmäisarvo","gui.sliderModal.title":"Muuta säätimen rajoja","gui.sliderPrompt.cancel":"Peruuta","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Ääni","gui.soundEditor.play":"Toista","gui.soundEditor.stop":"Pysäytä","gui.soundEditor.copy":"Kopioi","gui.soundEditor.paste":"Liitä","gui.soundEditor.copyToNew":"Kopioi uuteen","gui.soundEditor.delete":"Poista","gui.soundEditor.save":"Tallenna","gui.soundEditor.undo":"Kumoa","gui.soundEditor.redo":"Tee uudelleen","gui.soundEditor.faster":"Nopeammin","gui.soundEditor.slower":"Hitaammin","gui.soundEditor.echo":"Kaiku","gui.soundEditor.robot":"Robotti","gui.soundEditor.louder":"Voimakkaammin","gui.soundEditor.softer":"Pehmeämmin","gui.soundEditor.reverse":"Vaihda suuntaa","gui.soundEditor.fadeOut":"Häivytä","gui.soundEditor.fadeIn":"Voimista","gui.soundEditor.mute":"Vaimenna","gui.SpriteInfo.spritePlaceholder":"Nimi","gui.SpriteInfo.sprite":"Hahmo","gui.SpriteInfo.show":"Näytä","gui.SpriteInfo.size":"Koko","gui.spriteSelectorItem.contextMenuDuplicate":"monista","gui.spriteSelectorItem.contextMenuExport":"vie","gui.spriteSelectorItem.contextMenuDelete":"poista","gui.spriteSelector.addSpriteFromLibrary":"Valitse hahmo","gui.spriteSelector.addSpriteFromPaint":"Piirrä","gui.spriteSelector.addSpriteFromSurprise":"Yllätä","gui.spriteSelector.addSpriteFromFile":"Lataa hahmo","gui.stageHeader.stageSizeLarge":"Vaihda suureen esiintymislavaan","gui.stageHeader.stageSizeSmall":"Vaihda pieneen esiintymislavaan","gui.stageHeader.stageSizeFull":"Siirry koko ruudun tilaan","gui.stageHeader.stageSizeUnFull":"Poistu koko ruudun tilasta","gui.stageHeader.fullscreenControl":"Koko ruudun hallinta","gui.spriteSelector.addBackdropFromLibrary":"Valitse tausta","gui.stageSelector.addBackdropFromPaint":"Piirrä","gui.stageSelector.addBackdropFromSurprise":"Yllätä","gui.stageSelector.addBackdropFromFile":"Lataa tausta","gui.stageSelector.stage":"Esiintymislava","gui.stageSelector.backdrops":"Taustat","gui.telemetryOptIn.label":"Raportoi tilastoja Scratchin parantamiseksi","gui.telemetryOptIn.body1":"Scratch-tiimi on kiinnostunut siitä, miten Scratchia käytetään ympäri maailmaa. Auttaaksesi tätä työtä voit sallia, että Scratch lähettää automaattisesti käyttötietoja Scratch-tiimille.","gui.telemetryOptIn.body2":"Keräämämme tieto sisältää kielivalinnan, lohkojen käytön ja muutamia tapahtumia, kuten tallennuksen, latauksen ja projektin lähetyksen. Me EMME kerää mitään henkilökohtaisia tietoa. Katso {privacyPolicyLink} lisätietojen saamiseksi.","gui.telemetryOptIn.privacyPolicyLink":"tietosuojamenettelymme","gui.telemetryOptIn.optInText":"Jaa käyttötietoni Scratch-tiimille","gui.telemetryOptIn.optInTooltip":"Ota tietojen lähetys käyttöön","gui.telemetryOptIn.optOutText":"Älä jaa käyttötietojani Scratch-tiimille","gui.telemetryOptIn.optOutTooltip":"Poista tietojen lähetys käytöstä","gui.telemetryOptIn.settingWasUpdated":"Asetuksesi päivitettiin.","gui.telemetryOptIn.buttonClose":"Sulje","gui.turboMode.active":"Turbotila","gui.webglModal.label":"Selaimesi ei tue WebGL:ää","gui.webglModal.webgllink":"ei tue WebGL:ää","gui.costumeLibrary.chooseABackdrop":"Valitse tausta","gui.costumeLibrary.chooseACostume":"Valitse asuste","gui.costumeTab.addBackdropFromLibrary":"Valitse tausta","gui.costumeTab.addCostumeFromLibrary":"Valitse asuste","gui.costumeTab.addBlankCostume":"Piirrä","gui.costumeTab.addSurpriseCostume":"Yllätä","gui.costumeTab.addFileBackdrop":"Lataa tausta","gui.costumeTab.addFileCostume":"Lataa asuste","gui.extensionLibrary.chooseAnExtension":"Valitse laajennus","gui.extensionLibrary.extensionUrl":"Syötä liitännäisen verkko-osoite","gui.monitors.importListColumnPrompt":"Mitä saraketta tulisi käyttää (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Ei voi aloittaa äänitystä","gui.soundLibrary.chooseASound":"Valitse ääni","gui.soundTab.fileUploadSound":"Lataa ääni","gui.soundTab.surpriseSound":"Yllätä","gui.soundTab.recordSound":"Äänitä","gui.soundTab.addSoundFromLibrary":"Valitse ääni","gui.spriteLibrary.chooseASprite":"Valitse hahmo","gui.tipsLibrary.tutorials":"Valitse oppitunti","gui.alerts.createsuccess":"Uusi projekti luotu.","gui.alerts.createcopysuccess":"Projekti on tallennettu kopiona.","gui.alerts.createremixsuccess":"Projekti on tallennettu remiksinä.","gui.alerts.creating":"Luodaan uutta...","gui.alerts.creatingCopy":"Projektia kopioidaan...","gui.alerts.creatingRemix":"Projektia remiksataan...","gui.alerts.creatingError":"Projektia ei voitu luoda. Yritä uudelleen!","gui.alerts.savingError":"Projektia ei voitu tallentaa.","gui.alerts.savesuccess":"Projekti tallennettu.","gui.alerts.saving":"Projektia tallennetaan...","gui.alerts.cloudInfo":"Huomaa, että pilvimuuttujat tukevat vain numeroita, eivät kirjaimia tai symboleja. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Lisätietoja.","gui.alerts.importing":"Tuodaan...","gui.defaultProject.variable":"muuttujani","gui.extension.music.name":"Musiikki","gui.extension.music.description":"Soita soittimia ja rumpuja.","gui.extension.pen.name":"Kynä","gui.extension.pen.description":"Piirrä hahmoillasi.","gui.extension.videosensing.name":"Videohavainnointi","gui.extension.videosensing.description":"Havaitse liike kameran avulla.","gui.extension.text2speech.name":"Teksti puheeksi","gui.extension.text2speech.description":"Tee projektisi puhuviksi.","gui.extension.translate.name":"Käännä","gui.extension.translate.description":"Käännä tekstiä useille kielille.","gui.extension.makeymakey.description":"Tee mistä tahansa näppäin.","gui.extension.microbit.description":"Yhdistä projektisi maailman kanssa.","gui.extension.microbit.connectingMessage":"Yhdistetään","gui.extension.ev3.description":"Rakenna vuorovaikutteisia robotteja ja paljon muuta.","gui.extension.ev3.connectingMessage":"Yhdistetään. Varmista, että EV3:n PIN-koodi on 1234.","gui.extension.boost.description":"Herätä robottiluomukset henkiin.","gui.extension.boost.connectingMessage":"Yhdistetään","gui.extension.wedo2.description":"Rakenna käyttäen moottoreita ja sensoreita.","gui.extension.wedo2.connectingMessage":"Yhdistetään","gui.extension.gdxfor.description":"Havaitse työntö, veto, liike ja pyöriminen.","gui.extension.gdxfor.connectingMessage":"Yhdistetään","gui.libraryTags.all":"Kaikki","gui.libraryTags.animals":"Eläimet","gui.libraryTags.dance":"Tanssi","gui.libraryTags.effects":"Efektit","gui.libraryTags.fantasy":"Fantasia","gui.libraryTags.fashion":"Muoti","gui.libraryTags.food":"Ruoka","gui.libraryTags.indoors":"Sisällä","gui.libraryTags.loops":"Toistorakenteet","gui.libraryTags.music":"Musiikki","gui.libraryTags.notes":"Nuotit","gui.libraryTags.outdoors":"Ulkona","gui.libraryTags.patterns":"Kuviot","gui.libraryTags.people":"Ihmiset","gui.libraryTags.percussion":"Rummut","gui.libraryTags.space":"Avaruus","gui.libraryTags.sports":"Urheilu","gui.libraryTags.underwater":"Vedenalainen","gui.libraryTags.voice":"Ääni","gui.libraryTags.wacky":"Outo","gui.libraryTags.animation":"Animaatio","gui.libraryTags.art":"Taide","gui.libraryTags.games":"Pelit","gui.libraryTags.stories":"Tarinat","gui.libraryTags.letters":"Kirjaimet","gui.opcodeLabels.direction":"suunta","gui.opcodeLabels.xposition":"x-sijainti","gui.opcodeLabels.yposition":"y-sijainti","gui.opcodeLabels.size":"koko","gui.opcodeLabels.costumename":"asusteen nimi","gui.opcodeLabels.costumenumber":"asusteen numero","gui.opcodeLabels.backdropname":"taustan nimi","gui.opcodeLabels.backdropnumber":"taustan numero","gui.opcodeLabels.volume":"äänenvoimakkuus","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"vastaus","gui.opcodeLabels.loudness":"äänentaso","gui.opcodeLabels.username":"käyttäjänimi","gui.opcodeLabels.year":"vuosi","gui.opcodeLabels.month":"kuukausi","gui.opcodeLabels.date":"päiväys","gui.opcodeLabels.dayofweek":"viikonpäivä","gui.opcodeLabels.hour":"tunti","gui.opcodeLabels.minute":"minuutti","gui.opcodeLabels.second":"sekunti","gui.opcodeLabels.timer":"ajastin","gui.sharedMessages.backdrop":"tausta{index}","gui.sharedMessages.costume":"asuste{index}","gui.sharedMessages.sprite":"Hahmo{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Korvataanko nykyisen projektin sisältö?","gui.sharedMessages.loadFromComputerTitle":"Avaa tietokoneeltasi","boost.color.any":"mikä tahansa väri","boost.color.black":"musta","boost.color.blue":"sininen","boost.color.green":"vihreä","boost.color.red":"punainen","boost.color.white":"valkoinen","boost.color.yellow":"keltainen","boost.getMotorPosition":"moottorin [MOTOR_REPORTER_ID] asento","boost.getTiltAngle":"kallista suuntaan [TILT_DIRECTION]","boost.motorDirection.backward":"tuohon suuntaan","boost.motorDirection.forward":"tähän suuntaan","boost.motorDirection.reverse":"vaihda suuntaa","boost.motorOff":"laita moottori [MOTOR_ID] pois päältä","boost.motorOn":"laita moottori [MOTOR_ID] päälle","boost.motorOnFor":"käynnistä moottori [MOTOR_ID] [DURATION] sekunniksi","boost.motorOnForRotation":"käynnistä moottori [MOTOR_ID] [ROTATION] kierroksen ajan","boost.seeingColor":"näkeekö värin [COLOR]?","boost.setLightHue":"aseta valon väriksi [HUE]","boost.setMotorDirection":"aseta moottorin [MOTOR_ID] suunnaksi [MOTOR_DIRECTION]","boost.setMotorPower":"aseta moottorin [MOTOR_ID] nopeudeksi [POWER] %","boost.tiltDirection.any":"mikä tahansa","boost.tiltDirection.down":"alas","boost.tiltDirection.left":"vasen","boost.tiltDirection.right":"oikea","boost.tiltDirection.up":"ylös","boost.whenColor":"kun [COLOR] nähty","boost.whenTilted":"kun kallistettu suuntaan [TILT_DIRECTION_ANY]","ev3.beepNote":"soita nuottia [NOTE] [TIME] sekuntia","ev3.buttonPressed":"onko nappia painettu portissa [PORT]?","ev3.getBrightness":"kirkkaus","ev3.getDistance":"etäisyys","ev3.getMotorPosition":"moottorin [PORT] asento","ev3.motorSetPower":"aseta moottorin [PORT] tehoksi [POWER] %","ev3.motorTurnClockwise":"käännä moottoria [PORT] myötäpäivään [TIME] sekuntia","ev3.motorTurnCounterClockwise":"käännä moottoria [PORT] vastapäivään [TIME] sekuntia","ev3.whenBrightnessLessThan":"kun kirkkaus < [DISTANCE]","ev3.whenButtonPressed":"kun nappia painetaan portissa [PORT]","ev3.whenDistanceLessThan":"kun etäisyys < [DISTANCE]","gdxfor.getAcceleration":"kiihtyvyys [DIRECTION]","gdxfor.getForce":"voima","gdxfor.getSpin":"pyörimisnopeus [DIRECTION]","gdxfor.getTilt":"kallistuskulma [TILT]","gdxfor.isFreeFalling":"putoaako?","gdxfor.isTilted":"onko kallistus [TILT]?","gdxfor.pulled":"vedetään","gdxfor.pushed":"työnnetään","gdxfor.shaken":"ravistettu","gdxfor.startedFalling":"putoaminen alkoi","gdxfor.tiltDirectionMenu.any":"mikä tahansa","gdxfor.tiltDirectionMenu.back":"taka","gdxfor.tiltDirectionMenu.front":"etu","gdxfor.tiltDirectionMenu.left":"vasen","gdxfor.tiltDirectionMenu.right":"oikea","gdxfor.turnedFaceDown":"käännetty alaspäin","gdxfor.turnedFaceUp":"käännetty ylöspäin","gdxfor.whenForcePushedOrPulled":"kun voima-anturia [PUSH_PULL]","gdxfor.whenGesture":"kun on [GESTURE]","gdxfor.whenTilted":"kun kallistus [TILT]","makeymakey.downArrow":"nuoli alas","makeymakey.downArrowShort":"alas","makeymakey.leftArrow":"nuoli vasemmalle","makeymakey.leftArrowShort":"vasen","makeymakey.rightArrow":"nuoli oikealle","makeymakey.rightArrowShort":"oikea","makeymakey.spaceKey":"välilyönti","makeymakey.upArrow":"nuoli ylös","makeymakey.upArrowShort":"ylös","makeymakey.whenKeyPressed":"kun [KEY]-näppäintä painetaan","makeymakey.whenKeysPressedInOrder":"kun [SEQUENCE] painetaan järjestyksessä","microbit.buttonsMenu.any":"mikä tahansa","microbit.clearDisplay":"tyhjennä näyttö","microbit.defaultTextToDisplay":"Hei!","microbit.displaySymbol":"näytä [MATRIX]","microbit.displayText":"näytä teksti [TEXT]","microbit.gesturesMenu.jumped":"hypätty","microbit.gesturesMenu.moved":"siirretty","microbit.gesturesMenu.shaken":"ravistettu","microbit.isButtonPressed":"onko nappia [BTN] painettu?","microbit.isTilted":"onko kallistus suuntaan [DIRECTION]?","microbit.pinStateMenu.off":"pois","microbit.pinStateMenu.on":"päälle","microbit.tiltAngle":"kallista suuntaan [DIRECTION]","microbit.tiltDirectionMenu.any":"mikä tahansa","microbit.tiltDirectionMenu.back":"taka","microbit.tiltDirectionMenu.front":"etu","microbit.tiltDirectionMenu.left":"vasen","microbit.tiltDirectionMenu.right":"oikea","microbit.whenButtonPressed":"kun nappia [BTN] painetaan","microbit.whenGesture":"kun on [GESTURE]","microbit.whenPinConnected":"kun nasta [PIN] yhdistetty","microbit.whenTilted":"kun kallistettu suuntaan [DIRECTION]","music.categoryName":"Musiikki","music.changeTempo":"lisää tempoa arvolla [TEMPO]","music.drumBass":"(2) Bassorumpu","music.drumBongo":"(13) Bongo-rumpu","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Rytmikapulat","music.drumClosedHiHat":"(6) Suljettu hi-hat","music.drumConga":"(14) Conga-rumpu","music.drumCowbell":"(11) Lehmänkello","music.drumCrashCymbal":"(4) Crash-lautanen","music.drumCuica":"(18) Cuica-rumpu","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Taputus","music.drumOpenHiHat":"(5) Avoin hi-hat","music.drumSideStick":"(3) Sivuisku rumpuun","music.drumSnare":"(1) Virvelirumpu","music.drumTambourine":"(7) Tamburiini","music.drumTriangle":"(12) Triangeli","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Puupalikka","music.getTempo":"tempo","music.instrumentBass":"(6) Basso","music.instrumentBassoon":"(14) Fagotti","music.instrumentCello":"(8) Sello","music.instrumentChoir":"(15) Kuoro","music.instrumentClarinet":"(10) Klarinetti","music.instrumentElectricGuitar":"(5) Sähkökitara","music.instrumentElectricPiano":"(2) Sähköpiano","music.instrumentFlute":"(12) Huilu","music.instrumentGuitar":"(4) Kitara","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Soittorasia","music.instrumentOrgan":"(3) Urut","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Näppäily","music.instrumentSaxophone":"(11) Saksofoni","music.instrumentSteelDrum":"(18) Tynnyrirumpu","music.instrumentSynthLead":"(20) Syntetisaattori (lead-efekti)","music.instrumentSynthPad":"(21) Syntetisaattori (pad-efekti)","music.instrumentTrombone":"(9) Pasuuna","music.instrumentVibraphone":"(16) Vibrafoni","music.instrumentWoodenFlute":"(13) Puuhuilu","music.midiPlayDrumForBeats":"soita rumpua [DRUM] [BEATS] iskun ajan","music.midiSetInstrument":"aseta soittimeksi [INSTRUMENT]","music.playDrumForBeats":"soita rumpua [DRUM] [BEATS] iskun ajan","music.playNoteForBeats":"soita nuottia [NOTE] [BEATS] iskun ajan","music.restForBeats":"tauko [BEATS] iskun ajan","music.setInstrument":"aseta soittimeksi [INSTRUMENT]","music.setTempo":"aseta tempoksi [TEMPO]","pen.categoryName":"Kynä","pen.changeColorParam":"lisää kynän väriä [COLOR_PARAM] arvolla [VALUE]","pen.changeHue":"lisää kynän väriä arvolla [HUE]","pen.changeShade":"lisää kynän tummuutta arvolla [SHADE]","pen.changeSize":"lisää kynän kokoa arvolla [SIZE]","pen.clear":"pyyhi kaikki","pen.colorMenu.brightness":"kirkkaus","pen.colorMenu.color":"väri","pen.colorMenu.saturation":"värikylläisyys","pen.colorMenu.transparency":"läpinäkyvyys","pen.penDown":"kynä alas","pen.penUp":"kynä ylös","pen.setColor":"aseta kynän väriksi [COLOR]","pen.setColorParam":"aseta kynän värin [COLOR_PARAM] arvoksi [VALUE]","pen.setHue":"aseta kynän väriksi [HUE]","pen.setShade":"aseta kynän tummuudeksi [SHADE]","pen.setSize":"aseta kynän kooksi [SIZE]","pen.stamp":"leimaa","text2speech.alto":"altto","text2speech.categoryName":"Teksti puheeksi","text2speech.defaultTextToSpeak":"hei","text2speech.giant":"jätti","text2speech.kitten":"kissanpentu","text2speech.setLanguageBlock":"aseta kieleksi [LANGUAGE]","text2speech.setVoiceBlock":"aseta ääneksi [VOICE]","text2speech.speakAndWaitBlock":"puhu [WORDS]","text2speech.squeak":"vingahdus","text2speech.tenor":"tenori","translate.categoryName":"Käännä","translate.defaultTextToTranslate":"hei","translate.translateBlock":"käännä [WORDS] kielelle [LANGUAGE]","translate.viewerLanguage":"kieli","videoSensing.categoryName":"Videohavainnointi","videoSensing.direction":"suunta","videoSensing.motion":"liike","videoSensing.off":"pois","videoSensing.on":"päälle","videoSensing.onFlipped":"käännettäessä","videoSensing.setVideoTransparency":"aseta videon läpinäkyvyys arvoon [TRANSPARENCY]","videoSensing.sprite":"hahmo","videoSensing.stage":"esiintymislava","videoSensing.videoOn":"[SUBJECT]n [ATTRIBUTE] videolla","videoSensing.videoToggle":"kytke video [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"kun videon liike > [REFERENCE]","wedo2.getDistance":"etäisyys","wedo2.getTiltAngle":"kallista suuntaan [TILT_DIRECTION]","wedo2.isTilted":"onko kallistettu suuntaan [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"tuohon suuntaan","wedo2.motorDirection.forward":"tähän suuntaan","wedo2.motorDirection.reverse":"vaihda suuntaa","wedo2.motorId.a":"moottori A","wedo2.motorId.all":"kaikki moottorit","wedo2.motorId.b":"moottori B","wedo2.motorId.default":"moottori","wedo2.motorOff":"laita [MOTOR_ID] pois päältä","wedo2.motorOn":"laita [MOTOR_ID] päälle","wedo2.motorOnFor":"laita [MOTOR_ID] päälle [DURATION] sekunniksi","wedo2.playNoteFor":"soita nuottia [NOTE] [DURATION] sekuntia","wedo2.setLightHue":"aseta valon väriksi [HUE]","wedo2.setMotorDirection":"aseta moottorin [MOTOR_ID] suunnaksi [MOTOR_DIRECTION]","wedo2.startMotorPower":"aseta moottorin [MOTOR_ID] teho arvoon [POWER]","wedo2.tiltDirection.any":"mikä tahansa","wedo2.tiltDirection.down":"alas","wedo2.tiltDirection.left":"vasen","wedo2.tiltDirection.right":"oikea","wedo2.tiltDirection.up":"ylös","wedo2.whenDistance":"kun etäisyys [OP] [REFERENCE]","wedo2.whenTilted":"kun kallistettu suuntaan [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Väri","paint.paintEditor.saturation":"Värikylläisyys","paint.paintEditor.brightness":"Kirkkaus","paint.paintEditor.costume":"Asuste","paint.paintEditor.group":"Ryhmitä","paint.paintEditor.ungroup":"Pura ryhmitys","paint.paintEditor.undo":"Kumoa","paint.paintEditor.redo":"Tee uudelleen","paint.paintEditor.forward":"Eteenpäin","paint.paintEditor.backward":"Taaksepäin","paint.paintEditor.front":"Eteen","paint.paintEditor.back":"Taakse","paint.paintEditor.more":"Enemmän","paint.modeTools.brushSize":"Koko","paint.modeTools.eraserSize":"Kumin koko","paint.modeTools.copy":"Kopioi","paint.modeTools.paste":"Liitä","paint.modeTools.delete":"Poista","paint.modeTools.curved":"Kaartuva","paint.modeTools.pointed":"Teräväkärkinen","paint.modeTools.thickness":"Paksuus","paint.modeTools.flipHorizontal":"Käännä vaakasuoraan","paint.modeTools.flipVertical":"Käännä pystysuoraan","paint.modeTools.filled":"Täytetty","paint.modeTools.outlined":"Ääriviivallinen","paint.paintEditor.bitmap":"Muunna bittikartaksi","paint.paintEditor.vector":"Muunna vektoriksi","paint.paintEditor.fill":"Täytä","paint.paintEditor.stroke":"Ääriviiva","paint.brushMode.brush":"Sivellin","paint.eraserMode.eraser":"Pyyhekumi","paint.fillMode.fill":"Täytä","paint.lineMode.line":"Viiva","paint.ovalMode.oval":"Ympyrä","paint.rectMode.rect":"Suorakulmio","paint.reshapeMode.reshape":"Muotoile uudelleen","paint.roundedRectMode.roundedRect":"Pyöristetty suorakulmio","paint.selectMode.select":"Valitse","paint.textMode.text":"Teksti","paint.colorPicker.swap":"Vaihda","tw.footer.disclaimer":"Turbowarp ei ole sidoksissa scratchiin, Scratch tiimiin tai Scratch Säätiöön","tw.privacy":"Privaatio Polisi","tw.usernameModal.reset":"Reseti"},"sv":{"gui.alerts.tryAgain":"Försök igen","gui.alerts.download":"Ladda ned","gui.connection.reconnect":"Återanslut","gui.backpack.costumeLabel":"klädsel","gui.backpack.soundLabel":"ljud","gui.backpack.scriptLabel":"skript","gui.backpack.spriteLabel":"sprajt","gui.backpack.header":"Ryggsäck","gui.backpack.errorBackpack":"Problem att ladda ryggsäcken","gui.backpack.loadingBackpack":"Laddar...","gui.backpack.more":"Mer","gui.backpack.emptyBackpack":"Ryggsäcken är tom","gui.unsupportedBrowser.label":"Webbläsaren stöds ej","gui.cards.all-tutorials":"Handledningar","gui.cards.shrink":"Förminska","gui.cards.expand":"Förstora","gui.cards.close":"Stäng","gui.cards.more-things-to-try":"Fler saker att pröva!","gui.cards.see-more":"Läs mera","gui.comingSoon.message1":"Det är lugnt, vi jobbar på det {emoji}","gui.comingSoon.message2":"Kommer snart...","gui.comingSoon.message3":"Vi jobbar på det {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Enheter saknas","gui.connection.auto-scanning.prescan":"Ha din enhet i närheten, sök sedan efter den.","gui.connection.auto-scanning.pressbutton":"Tryck på knappen på din enhet.","gui.connection.auto-scanning.start-search":"Börja söka","gui.connection.connecting-searchbutton":"Söker...","gui.connection.auto-scanning.try-again":"Försök igen","gui.connection.connected":"Uppkopplad","gui.connection.disconnect":"Koppla ur","gui.connection.go-to-editor":"Gå till redigeraren","gui.connection.connecting-cancelbutton":"Kopplar upp...","gui.connection.error.errorMessage":"Hoppsan, det verkar som om något gick fel.","gui.connection.error.tryagainbutton":"Försök igen","gui.connection.error.helpbutton":"Hjälp","gui.connection.peripheral-name-label":"Enhetens namn","gui.connection.connect":"Koppla upp","gui.connection.scanning.lookingforperipherals":"Letar efter enheter","gui.connection.scanning.noPeripheralsFound":"Enheter saknas","gui.connection.scanning.instructions":"Välj din enhet i ovanstående lista.","gui.connection.search":"Uppdatera","gui.connection.unavailable.installscratchlink":"Se till att du har Scratchkopplingen installerad och igång","gui.connection.unavailable.enablebluetooth":"Kolla så att bluetooth är igång","gui.connection.unavailable.tryagainbutton":"Försök igen","gui.connection.unavailable.helpbutton":"Hjälp","gui.controls.go":"Starta","gui.controls.stop":"Stoppa","gui.crashMessage.label":"Oj! Något gick fel.","gui.crashMessage.errorNumber":"Ditt fel loggades med id {errorId}","gui.crashMessage.reload":"Uppdatera","gui.customProcedures.myblockModalTitle":"Skapa ett block","gui.customProcedures.addAnInputNumberText":"Lägg till en indata","gui.customProcedures.numberTextType":"siffror eller text","gui.customProcedures.addAnInputBoolean":"Lägg till en indata","gui.customProcedures.booleanType":"boolesk","gui.customProcedures.addALabel":"Lägg till en etikett","gui.customProcedures.runWithoutScreenRefresh":"Kör utan skärmuppdatering","gui.customProcedures.cancel":"Avbryt","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Riktning","gui.directionPicker.rotationStyles.allAround":"Rotera","gui.directionPicker.rotationStyles.leftRight":"Vänster/Höger","gui.directionPicker.rotationStyles.dontRotate":"Rotera inte","gui.gui.addExtension":"Lägg till ett tillägg","gui.gui.codeTab":"Kod","gui.gui.backdropsTab":"Bakgrunder","gui.gui.costumesTab":"Klädslar","gui.gui.soundsTab":"Ljud","gui.extensionLibrary.comingSoon":"Kommer snart","gui.extensionLibrary.requires":"Kräver","gui.extensionLibrary.collaboration":"Samarbetar med","gui.library.filterPlaceholder":"Sök","gui.library.allTag":"Alla","gui.loader.headline":"Laddar projekt","gui.loader.creating":"Skapa projekt","gui.authorInfo.byUser":"av {username}","gui.menuBar.seeProjectPage":"Se projektsidan","gui.menuBar.LanguageSelector":"språkväljare","gui.menuBar.tutorialsLibrary":"Handledningar","gui.menuBar.restoreSprite":"Återställ sprajt","gui.menuBar.restoreSound":"Ta tillbaka ljud","gui.menuBar.restoreCostume":"Ta tillbaka sprajt","gui.menuBar.restore":"Återställ","gui.menuBar.saveNow":"Spara nu","gui.menuBar.saveAsCopy":"Spara som kopia","gui.menuBar.remix":"Remix","gui.menuBar.new":"Nytt","gui.menuBar.file":"Arkiv","gui.menuBar.downloadToComputer":"Spara till din dator","gui.menuBar.edit":"Redigera","gui.menuBar.turboModeOff":"Stäng av turboläge","gui.menuBar.turboModeOn":"Sätt på turboläge","gui.gui.projectTitlePlaceholder":"Projektets titel här","gui.menuBar.isShared":"Delade","gui.menuBar.share":"Dela","gui.modal.help":"Hjälp","gui.modal.back":"Tillbaka","gui.monitor.listMonitor.empty":"(tom)","gui.monitor.listMonitor.listLength":"längd {length}","gui.monitor.contextMenu.default":"normal avläsning","gui.monitor.contextMenu.large":"stor avläsning","gui.monitor.contextMenu.slider":"reglage","gui.monitor.contextMenu.sliderRange":"ändra skjutreglagets omfång","gui.monitor.contextMenu.import":"importera","gui.monitor.contextMenu.export":"exportera","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Spela upp","gui.playButton.stop":"Stoppa","gui.gui.variableScopeOptionAllSprites":"För alla sprajtar","gui.gui.variableScopeOptionSpriteOnly":"Enbart för denna sprajt","gui.gui.cloudVariableOption":"Molnvariabel (sparad på servern)","gui.gui.variablePromptAllSpritesMessage":"Variabeln blir tillgänglig för alla sprajtar.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Avbryt","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Stoppa","gui.playbackStep.playMsg":"Spela upp","gui.playbackStep.loadingMsg":"Laddar...","gui.playbackStep.saveMsg":"Spara","gui.playbackStep.reRecordMsg":"Spela in igen","gui.recordModal.title":"Spela in nytt ljud","gui.recordingStep.beginRecord":"Klicka på knappen nedan för att starta inspelningen","gui.recordingStep.permission":"{arrow}Vi behöver ditt tillstånd för att använda mikrofonen","gui.recordingStep.stop":"Stoppa inspelningen","gui.recordingStep.record":"Spela in","gui.sliderModal.min":"Minivärde","gui.sliderModal.max":"Maxvärde","gui.sliderModal.title":"Ändra skjutreglagets omfång","gui.sliderPrompt.cancel":"Avbryt","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Ljud","gui.soundEditor.play":"Spela upp","gui.soundEditor.stop":"Stoppa","gui.soundEditor.copy":"Kopiera","gui.soundEditor.paste":"Klistra in","gui.soundEditor.copyToNew":"Kopiera till ny","gui.soundEditor.delete":"Radera","gui.soundEditor.save":"Spara","gui.soundEditor.undo":"Ångra","gui.soundEditor.redo":"Gör om","gui.soundEditor.faster":"Snabbare","gui.soundEditor.slower":"Långsammare","gui.soundEditor.echo":"Eko","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Högre","gui.soundEditor.softer":"Lägre","gui.soundEditor.reverse":"Baklänges","gui.soundEditor.fadeOut":"Tona ut","gui.soundEditor.fadeIn":"Tona in","gui.soundEditor.mute":"Tyst","gui.SpriteInfo.spritePlaceholder":"Namn","gui.SpriteInfo.sprite":"Sprajt","gui.SpriteInfo.show":"Visa","gui.SpriteInfo.size":"Storlek","gui.spriteSelectorItem.contextMenuDuplicate":"kopiera","gui.spriteSelectorItem.contextMenuExport":"exportera","gui.spriteSelectorItem.contextMenuDelete":"radera","gui.spriteSelector.addSpriteFromLibrary":"Välj en sprajt","gui.spriteSelector.addSpriteFromPaint":"Måla","gui.spriteSelector.addSpriteFromSurprise":"Överraska","gui.spriteSelector.addSpriteFromFile":"Ladda upp sprajt","gui.stageHeader.stageSizeLarge":"Byt till en större scen","gui.stageHeader.stageSizeSmall":"Byt till en mindre scen","gui.stageHeader.stageSizeFull":"Byt till fullskärmsläge","gui.stageHeader.stageSizeUnFull":"Gå ur fullskärmsläge","gui.stageHeader.fullscreenControl":"Fullskärmsläge","gui.spriteSelector.addBackdropFromLibrary":"Välj en bakgrund","gui.stageSelector.addBackdropFromPaint":"Måla","gui.stageSelector.addBackdropFromSurprise":"Överraska","gui.stageSelector.addBackdropFromFile":"Ladda upp bakgrund","gui.stageSelector.stage":"Scen","gui.stageSelector.backdrops":"Bakgrunder","gui.telemetryOptIn.label":"Rapporterar statistik för att förbättra Scratch","gui.telemetryOptIn.body1":"Scratchteamet försöker hela tiden förstå hur Scratch används runt om i världen. För att hjälpa till kan du låta Scratch automatiskt skicka användarinformation till Scratchteamet.","gui.telemetryOptIn.body2":"Informationen som vi samlar in inkluderar val av språk, använda block och några händelser som spara, öppna och ladda upp ett projekt. Vi SAMLAR INTE in någon personlig information. Läs mer om vår {privacyPolicyLink}.","gui.telemetryOptIn.privacyPolicyLink":"Sekretess","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Aktivera fjärrmätning","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Inaktivera fjärrmätning","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Stäng","gui.turboMode.active":"Turboläge","gui.webglModal.label":"Din webbläsare stödjer inte WebGL","gui.webglModal.webgllink":"stödjer inte webGL","gui.costumeLibrary.chooseABackdrop":"Välj en bakgrund","gui.costumeLibrary.chooseACostume":"Välj en klädsel","gui.costumeTab.addBackdropFromLibrary":"Välj en bakgrund","gui.costumeTab.addCostumeFromLibrary":"Välj en klädsel","gui.costumeTab.addBlankCostume":"Måla","gui.costumeTab.addSurpriseCostume":"Överraska","gui.costumeTab.addFileBackdrop":"Ladda upp bakgrund","gui.costumeTab.addFileCostume":"Ladda upp klädsel","gui.extensionLibrary.chooseAnExtension":"Välj ett tillägg","gui.extensionLibrary.extensionUrl":"Skriv in en URL till tillägget","gui.monitors.importListColumnPrompt":"Vilken kolumn ska användas (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Kunde inte starta inspelning","gui.soundLibrary.chooseASound":"Välj ett ljud","gui.soundTab.fileUploadSound":"Ladda upp ljud från fil","gui.soundTab.surpriseSound":"Överraska","gui.soundTab.recordSound":"Spela in","gui.soundTab.addSoundFromLibrary":"Välj ett ljud","gui.spriteLibrary.chooseASprite":"Välj en sprajt","gui.tipsLibrary.tutorials":"Välj en handledning","gui.alerts.createsuccess":"Nytt projekt skapat.","gui.alerts.createcopysuccess":"Projektet sparat som en kopia.","gui.alerts.createremixsuccess":"Projektet sparat som en remix.","gui.alerts.creating":"Skapar nytt...","gui.alerts.creatingCopy":"Kopierar projektet...","gui.alerts.creatingRemix":"Remixar projektet...","gui.alerts.creatingError":"Kunde inte skapa projektet. Försök igen!","gui.alerts.savingError":"Projektet kunde inte sparas.","gui.alerts.savesuccess":"Projektet sparat.","gui.alerts.saving":"Sparar projektet...","gui.alerts.cloudInfo":"Observera att molnvariabler enbart stödjer siffror, inte bokstäver eller symboler. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Lär dig mer.","gui.alerts.importing":"Importerar...","gui.defaultProject.variable":"min variabel","gui.extension.music.name":"Musik","gui.extension.music.description":"Spela instrument och trummor.","gui.extension.pen.name":"Penna","gui.extension.pen.description":"Låt dina sprajts rita.","gui.extension.videosensing.name":"Video - Känna av","gui.extension.videosensing.description":"Känn av rörelse med kameran.","gui.extension.text2speech.name":"Text till tal","gui.extension.text2speech.description":"Gör så att dina projekt pratar.","gui.extension.translate.name":"Översätta","gui.extension.translate.description":"Översätt text till många språk.","gui.extension.makeymakey.description":"Gör vad som helst till en tangent.","gui.extension.microbit.description":"Koppla upp dina projekt med världen.","gui.extension.microbit.connectingMessage":"Kopplar upp","gui.extension.ev3.description":"Bygg interaktiva robotar och annat.","gui.extension.ev3.connectingMessage":"Kopplar upp. Kolla att pinkoden på din EV3 är satt till 1234.","gui.extension.boost.description":"Ge liv åt dina robotar.","gui.extension.boost.connectingMessage":"Kopplar upp","gui.extension.wedo2.description":"Bygg med motorer och sensorer.","gui.extension.wedo2.connectingMessage":"Kopplar upp","gui.extension.gdxfor.description":"Känn av knuffa, dra, rörelse och rotation.","gui.extension.gdxfor.connectingMessage":"Kopplar upp","gui.libraryTags.all":"Alla","gui.libraryTags.animals":"Djur","gui.libraryTags.dance":"Dansa","gui.libraryTags.effects":"Effekter","gui.libraryTags.fantasy":"Fantasy","gui.libraryTags.fashion":"Mode","gui.libraryTags.food":"Mat","gui.libraryTags.indoors":"Inomhus","gui.libraryTags.loops":"Loopar","gui.libraryTags.music":"Musik","gui.libraryTags.notes":"Toner","gui.libraryTags.outdoors":"Utomhus","gui.libraryTags.patterns":"Mönster","gui.libraryTags.people":"Människor","gui.libraryTags.percussion":"Slagverk","gui.libraryTags.space":"Rymden","gui.libraryTags.sports":"Sport","gui.libraryTags.underwater":"Under vatten","gui.libraryTags.voice":"Röst","gui.libraryTags.wacky":"Knäppt","gui.libraryTags.animation":"Animation","gui.libraryTags.art":"Konst","gui.libraryTags.games":"Spel","gui.libraryTags.stories":"Berättelser","gui.libraryTags.letters":"Bokstäver","gui.opcodeLabels.direction":"riktning","gui.opcodeLabels.xposition":"x position","gui.opcodeLabels.yposition":"y position","gui.opcodeLabels.size":"storlek","gui.opcodeLabels.costumename":"klädselnamn","gui.opcodeLabels.costumenumber":"klädselnummer","gui.opcodeLabels.backdropname":"bakgrundsnamn","gui.opcodeLabels.backdropnumber":"bakgrundsnummer","gui.opcodeLabels.volume":"volym ","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"svar","gui.opcodeLabels.loudness":"ljudstyrka","gui.opcodeLabels.username":"användarnamn ","gui.opcodeLabels.year":"år ","gui.opcodeLabels.month":"månad ","gui.opcodeLabels.date":"dag ","gui.opcodeLabels.dayofweek":"veckodag ","gui.opcodeLabels.hour":"timmar ","gui.opcodeLabels.minute":"minuter ","gui.opcodeLabels.second":"sekunder ","gui.opcodeLabels.timer":"timer","gui.sharedMessages.backdrop":"bakgrund{index}","gui.sharedMessages.costume":"klädsel{index}","gui.sharedMessages.sprite":"Sprajt{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Ersätt innehållet i det aktuella projektet?","gui.sharedMessages.loadFromComputerTitle":"Ladda upp från din dator","boost.color.any":"vilken färg som helst","boost.color.black":"svart","boost.color.blue":"blå","boost.color.green":"grön","boost.color.red":"röd","boost.color.white":"vit","boost.color.yellow":"gul","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] position","boost.getTiltAngle":"lutningsvinkel [TILT_DIRECTION]","boost.motorDirection.backward":"andra hållet","boost.motorDirection.forward":"detta hållet","boost.motorDirection.reverse":"ändra riktning","boost.motorOff":"vrid motor [MOTOR_ID] av","boost.motorOn":"vrid motor [MOTOR_ID] på","boost.motorOnFor":"vrid motor [MOTOR_ID] i [DURATION] sekunder","boost.motorOnForRotation":"vrid motor [MOTOR_ID] i [ROTATION] rotationer","boost.seeingColor":"ser [COLOR] kloss?","boost.setLightHue":"sätt ljusets färg till [HUE]","boost.setMotorDirection":"sätt motor [MOTOR_ID] riktning [MOTOR_DIRECTION]","boost.setMotorPower":"sätt motor [MOTOR_ID] hastighet till [POWER] %","boost.tiltDirection.any":"någon","boost.tiltDirection.down":"ned","boost.tiltDirection.left":"vänster","boost.tiltDirection.right":"höger","boost.tiltDirection.up":"upp","boost.whenColor":"när [COLOR] kloss upptäcks","boost.whenTilted":"om lutar [TILT_DIRECTION_ANY]","ev3.beepNote":"spela ton [NOTE] i [TIME]sekunder","ev3.buttonPressed":"knapp [PORT] nedtryckt?","ev3.getBrightness":"ljusstyrka","ev3.getDistance":"avstånd","ev3.getMotorPosition":"motor [PORT] position","ev3.motorSetPower":"motor [PORT] sätt kraft [POWER] %","ev3.motorTurnClockwise":"motor [PORT] rotera medsols i [TIME] sekunder","ev3.motorTurnCounterClockwise":"motor [PORT] rotera motsols i [TIME] sekunder","ev3.whenBrightnessLessThan":"om ljusstyrka < [DISTANCE]","ev3.whenButtonPressed":"när knapp [PORT] trycks ned","ev3.whenDistanceLessThan":"när avstånd < [DISTANCE]","gdxfor.getAcceleration":"acceleration [DIRECTION]","gdxfor.getForce":"kraft","gdxfor.getSpin":"rotationshastighet [DIRECTION]","gdxfor.getTilt":"lutningsvinkel [TILT]","gdxfor.isFreeFalling":"fritt fall?","gdxfor.isTilted":"lutar [TILT]?","gdxfor.pulled":"dragits","gdxfor.pushed":"knuffad","gdxfor.shaken":"skaka","gdxfor.startedFalling":"börjar falla","gdxfor.tiltDirectionMenu.any":"någon","gdxfor.tiltDirectionMenu.back":"tillbaka","gdxfor.tiltDirectionMenu.front":"översta","gdxfor.tiltDirectionMenu.left":"vänster","gdxfor.tiltDirectionMenu.right":"höger","gdxfor.turnedFaceDown":"vände logotyp nedåt","gdxfor.turnedFaceUp":"vände logotyp uppåt","gdxfor.whenForcePushedOrPulled":"när kraftsensorn [PUSH_PULL]","gdxfor.whenGesture":"om [GESTURE]","gdxfor.whenTilted":"när lutar [TILT]","makeymakey.downArrow":"nedåtpil","makeymakey.downArrowShort":"ned","makeymakey.leftArrow":"vänsterpil","makeymakey.leftArrowShort":"vänster","makeymakey.rightArrow":"högerpil","makeymakey.rightArrowShort":"höger","makeymakey.spaceKey":"mellanslag","makeymakey.upArrow":"uppåtpil","makeymakey.upArrowShort":"upp","makeymakey.whenKeyPressed":"när [KEY] tangenten trycks ned","makeymakey.whenKeysPressedInOrder":"när [SEQUENCE] trycks ned efter varandra","microbit.buttonsMenu.any":"någon","microbit.clearDisplay":"rensa skärmen","microbit.defaultTextToDisplay":"Hej!","microbit.displaySymbol":"visa [MATRIX]","microbit.displayText":"visa text [TEXT]","microbit.gesturesMenu.jumped":"hoppa","microbit.gesturesMenu.moved":"rör sig","microbit.gesturesMenu.shaken":"skaka","microbit.isButtonPressed":"[BTN] knappen nedtryckt?","microbit.isTilted":"luta [DIRECTION]?","microbit.pinStateMenu.off":"av","microbit.pinStateMenu.on":"på","microbit.tiltAngle":"luta riktning [DIRECTION]","microbit.tiltDirectionMenu.any":"någon","microbit.tiltDirectionMenu.back":"tillbaka","microbit.tiltDirectionMenu.front":"översta","microbit.tiltDirectionMenu.left":"vänster","microbit.tiltDirectionMenu.right":"höger","microbit.whenButtonPressed":"om knapp [BTN] trycks ned","microbit.whenGesture":"om [GESTURE]","microbit.whenPinConnected":"När pin [PIN] är kopplad","microbit.whenTilted":"om lutar [DIRECTION]","music.categoryName":"Musik","music.changeTempo":"ändra tempo med [TEMPO]","music.drumBass":"(2) Bastrumma","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Claves","music.drumClosedHiHat":"(6) Stängd Hi-Hat","music.drumConga":"(14) Congas","music.drumCowbell":"(11) Koskälla","music.drumCrashCymbal":"(4) Crashcymbal","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Handklapp","music.drumOpenHiHat":"(5) Öppen Hi-Hat","music.drumSideStick":"(3) Kantslag","music.drumSnare":"(1) Virveltrumma","music.drumTambourine":"(7) Tamburin","music.drumTriangle":"(12) Triangel","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Träblock","music.getTempo":"tempo","music.instrumentBass":"(6) Bas","music.instrumentBassoon":"(14) Fagott","music.instrumentCello":"(8) Cello","music.instrumentChoir":"(15) Kör","music.instrumentClarinet":"(10) Klarinett","music.instrumentElectricGuitar":"(5) Elgitarr","music.instrumentElectricPiano":"(2) Elpiano","music.instrumentFlute":"(12) Flöjt","music.instrumentGuitar":"(4) Gitarr","music.instrumentMarimba":"(19) Marimba","music.instrumentMusicBox":"(17) Speldosa","music.instrumentOrgan":"(3) Orgel","music.instrumentPiano":"(1) Piano","music.instrumentPizzicato":"(7) Pizzicato","music.instrumentSaxophone":"(11) Saxofon","music.instrumentSteelDrum":"(18) Steel Drum","music.instrumentSynthLead":"(20) Synth Lead","music.instrumentSynthPad":"(21) Synth Pad","music.instrumentTrombone":"(9) Trombon","music.instrumentVibraphone":"(16) Vibrafon","music.instrumentWoodenFlute":"(13) Träflöjt","music.midiPlayDrumForBeats":"spela trumma [DRUM]i [BEATS] takter","music.midiSetInstrument":"sätt instrument till [INSTRUMENT]","music.playDrumForBeats":"spela trumma [DRUM]i [BEATS] takter","music.playNoteForBeats":"spela not [NOTE]i [BEATS]takter","music.restForBeats":"pausa i [BEATS]takter","music.setInstrument":"sätt instrument till [INSTRUMENT]","music.setTempo":"sätt tempo till [TEMPO]","pen.categoryName":"Penna","pen.changeColorParam":"ändra pennans [COLOR_PARAM]med [VALUE]","pen.changeHue":"ändra pennans färg med [HUE]","pen.changeShade":"ändra pennans skugga med [SHADE]","pen.changeSize":"ändra pennans storlek med [SIZE]","pen.clear":"radera allt","pen.colorMenu.brightness":"ljusstyrka","pen.colorMenu.color":"färg","pen.colorMenu.saturation":"mättnad","pen.colorMenu.transparency":"genomskinlighet","pen.penDown":"penna ned","pen.penUp":"penna upp","pen.setColor":"sätt pennans färg [COLOR]","pen.setColorParam":"sätt penna [COLOR_PARAM]till [VALUE]","pen.setHue":"sätt pennans färg till [HUE]","pen.setShade":"sätt pennans skugga till [SHADE]","pen.setSize":"sätt pennans storlek [SIZE]","pen.stamp":"stämpla","text2speech.alto":"alt","text2speech.categoryName":"Text till tal","text2speech.defaultTextToSpeak":"hej","text2speech.giant":"jätte","text2speech.kitten":"kattunge","text2speech.setLanguageBlock":"sätt språk till [LANGUAGE]","text2speech.setVoiceBlock":"sätt röst till [VOICE]","text2speech.speakAndWaitBlock":"säg [WORDS]","text2speech.squeak":"pip","text2speech.tenor":"tenor","translate.categoryName":"Översätta","translate.defaultTextToTranslate":"hej","translate.translateBlock":"översätt [WORDS] till [LANGUAGE]","translate.viewerLanguage":"språk","videoSensing.categoryName":"Video - Känna av","videoSensing.direction":"riktning","videoSensing.motion":"rörelse","videoSensing.off":"av","videoSensing.on":"på","videoSensing.onFlipped":"vid förändring","videoSensing.setVideoTransparency":"sätt videotransparens till [TRANSPARENCY]","videoSensing.sprite":"sprajt","videoSensing.stage":"scen","videoSensing.videoOn":"video [ATTRIBUTE]på [SUBJECT]","videoSensing.videoToggle":"sätt video till [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"när videorörelse > [REFERENCE]","wedo2.getDistance":"avstånd","wedo2.getTiltAngle":"lutningsvinkel [TILT_DIRECTION]","wedo2.isTilted":"lutar [TILT_DIRECTION_ANY] ?","wedo2.motorDirection.backward":"andra hållet","wedo2.motorDirection.forward":"detta hållet","wedo2.motorDirection.reverse":"ändra riktning","wedo2.motorId.a":"motor A","wedo2.motorId.all":"alla motorer","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"stoppa [MOTOR_ID]","wedo2.motorOn":"starta [MOTOR_ID]","wedo2.motorOnFor":"starta [MOTOR_ID] i [DURATION] sekunder","wedo2.playNoteFor":"spela ton [NOTE] i [DURATION] sekunder","wedo2.setLightHue":"sätt ljusets färg till [HUE]","wedo2.setMotorDirection":"sätt [MOTOR_ID] riktning till [MOTOR_DIRECTION]","wedo2.startMotorPower":"sätt kraften på [MOTOR_ID] till [POWER]","wedo2.tiltDirection.any":"någon","wedo2.tiltDirection.down":"ned","wedo2.tiltDirection.left":"vänster","wedo2.tiltDirection.right":"höger","wedo2.tiltDirection.up":"upp","wedo2.whenDistance":"om avstånd [OP] [REFERENCE]","wedo2.whenTilted":"om lutar [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Färg","paint.paintEditor.saturation":"Mättnad","paint.paintEditor.brightness":"Ljusstyrka","paint.paintEditor.costume":"Klädsel","paint.paintEditor.group":"Gruppera","paint.paintEditor.ungroup":"Dela upp grupp","paint.paintEditor.undo":"Ångra","paint.paintEditor.redo":"Gör om","paint.paintEditor.forward":"Framåt","paint.paintEditor.backward":"Bakåt","paint.paintEditor.front":"Placera längst fram","paint.paintEditor.back":"Placera längst bak","paint.paintEditor.more":"Mer","paint.modeTools.brushSize":"Storlek","paint.modeTools.eraserSize":"Suddgummi storlek","paint.modeTools.copy":"Kopiera","paint.modeTools.paste":"Klistra in","paint.modeTools.delete":"Radera","paint.modeTools.curved":"Böjd","paint.modeTools.pointed":"Spetsig","paint.modeTools.thickness":"Tjocklek","paint.modeTools.flipHorizontal":"Vänd vågrätt","paint.modeTools.flipVertical":"Vänd lodrätt","paint.modeTools.filled":"Fylld","paint.modeTools.outlined":"Ofylld","paint.paintEditor.bitmap":"Gör till bitmapp","paint.paintEditor.vector":"Konvertera till vektor","paint.paintEditor.fill":"Fyll","paint.paintEditor.stroke":"Kontur","paint.brushMode.brush":"Pensel","paint.eraserMode.eraser":"Radergummi","paint.fillMode.fill":"Fyll","paint.lineMode.line":"Linje","paint.ovalMode.oval":"Cirkel","paint.rectMode.rect":"Rektangel","paint.reshapeMode.reshape":"Omforma","paint.roundedRectMode.roundedRect":"Rektangel rundade hörn","paint.selectMode.select":"Välj","paint.textMode.text":"Text","paint.colorPicker.swap":"Växla färg","tw.alerts.autosaving":"Skapar återställningspunkt...","tw.alerts.savedToDisk":"Sparad på datorn.","tw.backpack.rename":"Nytt namn: ","tw.browserModal.desc":"Titta om du använder den nyaste versionen av Google Chrome, Mozilla Firefox, Microsoft Edge eller Appel Safari.","tw.changeUsername.cannotChangeWhileRunning":"Användarnamn kan inte ändras när projektet är igång.","tw.code":"Källkod","tw.customExtension.description":"Ladda anpassade tillägg från URLs. För utvecklare. Experimentell.","tw.customExtension.name":"Anpassatt tillägg","tw.featuredProjectsStudio":"Se studion på Scratch.","tw.feedback":"Respons & buggar","tw.footer.credits":"Krediter","tw.footer.donate":"Donera","tw.footer.embed":"Inbäddning","tw.footer.fosshost":"Hosting tillhandahålls av Fosshost","tw.footer.parameters":"URL Parametrar","tw.footer.translate":"Hjälp att översätta TurboWarp","tw.gui.crashMessage.description":"Vi är ledsna men det ser ut som sidan har krashat. Ladda om sidan för att försöka igen.","tw.gui.defaultProjectTitle":"Projekt","tw.guiDefaultTitle":"Kör scratchprojekt snabbare","tw.home.credit":"Anteckningar och kerditer","tw.home.description":"TurboWarp är en modifikation som kompilerar project till JavaScript så att de körs väldigt fort. Testa med att skriva in projekt ID eller URL över eller att välja utvalda projekt nedan.","tw.home.instructions":"Instruktioner","tw.input.tooltip":"Kopiera och klistra in en Scratch länk här!","tw.invalidParameters.clones":"\\"klon\\" URL är ogiltig","tw.invalidParameters.fps":"\\"fps\\" URL parameter är ogiltig","tw.loader.assets.known":"Hämtar tillgångar ({complete}/{total})...","tw.loader.assets.unknown":"Hämtar tillgångar...","tw.loader.data":"Hämtar projektdata...","tw.loader.generic":"Laddar projekt...","tw.menuBar.60off":"Avaktivera 60 FPS","tw.menuBar.60on":"Aktivera 60 FPS","tw.menuBar.addons":"Tillägg","tw.menuBar.advanced":"Avancerat","tw.menuBar.changeUsername":"Ändra användarnamn","tw.menuBar.cloudOff":"Avaktivera molnvariabler","tw.menuBar.cloudOn":"Aktivera molnvariabler","tw.menuBar.cloudUnavailable":"Molnvariabler är inte tillgängliga","tw.menuBar.cloudUnavailableAlert":"Kan inte använda molnvariabler, mest troligt att du öppnade editorn.","tw.menuBar.compileError":"{sprite}:{error}","tw.menuBar.loadRestorePoint":"Ladda in återställningspunkten","tw.menuBar.moreSettings":"Avancerade inställningar","tw.menuBar.newFramerate":"Ny upplösningshastighet:","tw.menuBar.package":"Packa projektet","tw.menuBar.reportError1":"Några skript kunde inte kompileras","tw.menuBar.reportError2":"Detta är en bugg. Snälla rapportera buggen. ","tw.menuBar.saveAs":"Spara som {file}","tw.menuBar.seeInside":"Se innuti","tw.openAdvanced":"Öppna avancerade inställningar","tw.paint.alpha":"Opacitet","tw.privacy":"Integritetspolicy","tw.restorePoint.loadFail":"Kunde inte ladda in återställningspunkten: {error} ","tw.settingsModal.customStageSize":"Anpassad scenstorlek:","tw.settingsModal.dangerZone":"Farliga zonen","tw.settingsModal.disableCompiler":"Avaktivera kompilatorn","tw.settingsModal.disableCompilerHelp":"Avaktiverar TurboWarps kompilator. Du kanske vill att aktivera detta när du vill ändra koden så att skripterna uppdateras momentalt, annars så ska du aldrig aktivera detta.","tw.settingsModal.featured":"Utvalda","tw.settingsModal.fps":"60 FPS (Anpassat FPS)","tw.settingsModal.fpsHelp.customFramerate":"Klicka för att använda en hastighet förutom 30 och 60 FPS","tw.settingsModal.help":"Klicka för hjälp","tw.settingsModal.highQualityPen":"Högkvalitativ penna","tw.settingsModal.infiniteClones":"Oändliga kloner","tw.settingsModal.infiniteClonesHelp":"Avaktiverar Scratch\'s 300 klongräns.","tw.settingsModal.interpolationHelp":"Får projekt att se jämnare ut genom att interpolera sprite-rörelser. Interpolering bör inte användas på 3D-projekt, raytracers, pennprojekt och långsamma projekt eftersom interpolering kommer att göra att de går långsammare utan att få dem att se jämnare ut.","tw.settingsModal.removeFencing":"Ta bort scengränser","tw.settingsModal.removeLimits":"Ta bort limitationerna","tw.settingsModal.removeMiscLimits":"Ta bort diverse gränser","tw.settingsModal.removeMiscLimitsHelp":"Tar bort ljud limitationer och gränser för pennstorlek","tw.settingsModal.storeProjectOptions":"Spara inställningarna i projektet","tw.settingsModal.title":"Avancerade inställningar","tw.settingsModal.warpTimerHelp":"Ser till så att skript är inte fasta i en lång eller oändlig loop och gör så att de körs på låg hastighet istället för att fastna tills loopen blir klar. Detta fixar de flesta kraschar men har en betydande prestationspåverkan så det är bara aktiverat i editorn som standard.","tw.spriteSelectorItem.rename":"Döp om","tw.stereoAlert":"Om du redigerar detta stereoljud konverteras det oåterkalleligt till mono.","tw.studioview.authorAttribution":"av {author}","tw.studioview.error":"Det uppstod ett fel när nästa sida med projekt skulle laddas.","tw.studioview.hoverText":"{title} av {author}","tw.tooLarge":"Detta ljud kommer att kanske vara för stort för att ladda upp till Scratch.","tw.twExtension.description":"Konstiga nya block. Okompatibella med Scratch","tw.twExtension.name":"TurboWarps block","tw.unshared.2":"För mer information se: {link}","tw.unshared.cache":"Om projektet var delat nyligen så kan detta meddelandet vara ogiltigt i några minuter.","tw.usernameModal.mustChange":"Förlåt, men det ser ut som om att servern tänker att ditt användarnamn är osäkert. Ändra det till något annat eller {resetIt}.","tw.usernameModal.mustChange.resetIt":"Återställa (Rekomenderat)","tw.usernameModal.reset":"Starta om","tw.usernameModal.title":"Ändra användarnamn","tw.viewFeaturedProjects":"Klicka för att se utvalda projekt","tw.viewOnScratch":"Se projektet på Scratch","tw.webglModal.description":"Olyckligtvis ser det ut som om din webbläsare eller dator {webGlLink}. Denna sidan kräver denna teknologin för att sidan ska fungera. Försök att uppdatera din webbläsare och grafikdrivrutiner eller starta om din dator."},"vi":{"gui.alerts.tryAgain":"Vui lòng thử lại","gui.alerts.download":"Tải xuống","gui.connection.reconnect":"Kết nối lại","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Ba lô","gui.backpack.errorBackpack":"Không thể tải lên ba lô","gui.backpack.loadingBackpack":"Đang tải ...","gui.backpack.more":"Nhiều hơn","gui.backpack.emptyBackpack":"Ba lô trống","gui.unsupportedBrowser.label":"Trình duyệt web không hỗ trợ","gui.cards.all-tutorials":"Hướng dẫn","gui.cards.shrink":"Shrink","gui.cards.expand":"Mở rộng","gui.cards.close":"Đóng","gui.cards.more-things-to-try":"Thêm nhiều thứ nữa để thử!","gui.cards.see-more":"Xem thêm","gui.comingSoon.message1":"Đừng lo, chúng tôi làm việc với tính năng này {emoji}","gui.comingSoon.message2":"Sắp có...","gui.comingSoon.message3":"Chúng tôi đang làm việc với tính năng này {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Không tìm thấy thiết bị nào","gui.connection.auto-scanning.prescan":"Đặt thiết bị của bạn ở gần, và bắt đầu tìm kiếm.","gui.connection.auto-scanning.pressbutton":"Bấm nút trên thiết bị của bạn","gui.connection.auto-scanning.start-search":"Bắt đầu tìm kiếm","gui.connection.connecting-searchbutton":"Đang tìm kiếm...","gui.connection.auto-scanning.try-again":"Thử lại","gui.connection.connected":"Đã kết nối","gui.connection.disconnect":"Ngắt kết nối","gui.connection.go-to-editor":"Đi đến trình biên tập","gui.connection.connecting-cancelbutton":"Đang kết nối...","gui.connection.error.errorMessage":"Ôi, có vấn đề gì đó xảy ra.","gui.connection.error.tryagainbutton":"Thử lại","gui.connection.error.helpbutton":"Trợ giúp","gui.connection.peripheral-name-label":"Tên thiết bị","gui.connection.connect":"Kết nối","gui.connection.scanning.lookingforperipherals":"Đang tìm kiếm thiết bị","gui.connection.scanning.noPeripheralsFound":"Không tìm thấy thiết bị nào","gui.connection.scanning.instructions":"Chọn thiết bị của bạn trong danh sách phía trên","gui.connection.search":"Làm mới","gui.connection.unavailable.installscratchlink":"Hãy chắc chắn rằng bạn đã cài và chạy Scratch Link","gui.connection.unavailable.enablebluetooth":"Hãy kiểm tra kết nối Bluetooth bật hay chưa","gui.connection.unavailable.tryagainbutton":"Thử lại","gui.connection.unavailable.helpbutton":"Trợ giúp","gui.controls.go":"Đi","gui.controls.stop":"Dừng lại","gui.crashMessage.label":"Oops! Có vấn đề xảy ra.","gui.crashMessage.errorNumber":"Lỗi đã được lưu lại với ID {errorId}","gui.crashMessage.reload":"Tải lại","gui.customProcedures.myblockModalTitle":"Tạo một khối","gui.customProcedures.addAnInputNumberText":"Thêm dữ liệu đầu vào","gui.customProcedures.numberTextType":"số hay chữ","gui.customProcedures.addAnInputBoolean":"Thêm dữ liệu đầu vào","gui.customProcedures.booleanType":"điều kiện","gui.customProcedures.addALabel":"Thêm nhãn","gui.customProcedures.runWithoutScreenRefresh":"Chạy mà không làm mới màn hình","gui.customProcedures.cancel":"Hủy","gui.customProcedures.ok":"OK","gui.SpriteInfo.direction":"Hướng di chuyển","gui.directionPicker.rotationStyles.allAround":"Xung quanh","gui.directionPicker.rotationStyles.leftRight":"Trái/Phải","gui.directionPicker.rotationStyles.dontRotate":"Không quay","gui.gui.addExtension":"Thêm phần mở rộng","gui.gui.codeTab":"code","gui.gui.backdropsTab":"Phông nền","gui.gui.costumesTab":"Trang phục","gui.gui.soundsTab":"Âm thanh","gui.extensionLibrary.comingSoon":"Xuất hiện sớm","gui.extensionLibrary.requires":"Yêu cầu","gui.extensionLibrary.collaboration":"Cộng tác với","gui.library.filterPlaceholder":"Tìm kiếm","gui.library.allTag":"Tất cả","gui.loader.headline":"Đang tải dự án","gui.loader.creating":"Đang tạo dự án","gui.authorInfo.byUser":"bởi {username}","gui.menuBar.seeProjectPage":"Xem trang Dự án","gui.menuBar.LanguageSelector":"chọn ngôn ngữ","gui.menuBar.tutorialsLibrary":"Hướng dẫn","gui.menuBar.restoreSprite":"Khôi phục Nhân vật","gui.menuBar.restoreSound":"Khôi phục âm thanh","gui.menuBar.restoreCostume":"Khôi phục hình dạng","gui.menuBar.restore":"Khôi phục","gui.menuBar.saveNow":"Lưu bây giờ","gui.menuBar.saveAsCopy":"Lưu bản sao ","gui.menuBar.remix":"Phối lại","gui.menuBar.new":"Mới","gui.menuBar.file":"Tập tin","gui.menuBar.downloadToComputer":"Lưu về máy tính","gui.menuBar.edit":"Chỉnh sửa","gui.menuBar.turboModeOff":"Tắt chế độ Turbo","gui.menuBar.turboModeOn":"Bật chế độ Turbo","gui.gui.projectTitlePlaceholder":"Đề tên ở đây","gui.menuBar.isShared":"Đã chia sẻ","gui.menuBar.share":"Chia sẻ","gui.modal.help":"Trợ giúp","gui.modal.back":"Trở về","gui.monitor.listMonitor.empty":"(trống)","gui.monitor.listMonitor.listLength":"độ dài {length}","gui.monitor.contextMenu.default":"chế độ đọc bình thường","gui.monitor.contextMenu.large":"chế độ đọc lớn","gui.monitor.contextMenu.slider":"thanh trượt","gui.monitor.contextMenu.sliderRange":"thay đổi phạm vi thanh trượt","gui.monitor.contextMenu.import":"nhập vào","gui.monitor.contextMenu.export":"xuất ra","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Chơi","gui.playButton.stop":"Dừng lại","gui.gui.variableScopeOptionAllSprites":"Cho tất cả nhân vật","gui.gui.variableScopeOptionSpriteOnly":"Chỉ nhân vật này","gui.gui.cloudVariableOption":"Biến số (lưu tại máy chủ)","gui.gui.variablePromptAllSpritesMessage":"Biến này sẽ có sẵn cho tất cả nhân vật.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Hủy","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Dừng lại","gui.playbackStep.playMsg":"Chơi","gui.playbackStep.loadingMsg":"Đang tải ...","gui.playbackStep.saveMsg":"Lưu","gui.playbackStep.reRecordMsg":"thu âm lại","gui.recordModal.title":"Thu lại âm thanh ","gui.recordingStep.beginRecord":"Bắt đầu ghi âm bằng cách ấn nút bên dưới","gui.recordingStep.permission":"{arrow}Chúng tôi cần bạn cho phép để sử dụng micro","gui.recordingStep.stop":"Dừng ghi âm","gui.recordingStep.record":"Ghi lại","gui.sliderModal.min":"Giá trị nhỏ nhất","gui.sliderModal.max":"Giá trị lớn nhất","gui.sliderModal.title":"Thay đổi phạm vi thanh trượt","gui.sliderPrompt.cancel":"Hủy","gui.sliderPrompt.ok":"OK","gui.soundEditor.sound":"Âm thanh","gui.soundEditor.play":"Chơi","gui.soundEditor.stop":"Dừng lại","gui.soundEditor.copy":"Sao chép","gui.soundEditor.paste":"Dán","gui.soundEditor.copyToNew":"Copy to New","gui.soundEditor.delete":"Xóa","gui.soundEditor.save":"Lưu","gui.soundEditor.undo":"Hoàn tác","gui.soundEditor.redo":"Làm lại ","gui.soundEditor.faster":"Nhanh hơn","gui.soundEditor.slower":"chậm hơn","gui.soundEditor.echo":"Tiếng vang","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"To hơn","gui.soundEditor.softer":"nhẹ hơn","gui.soundEditor.reverse":"Đảo ngược","gui.soundEditor.fadeOut":"Fade out","gui.soundEditor.fadeIn":"Fade in","gui.soundEditor.mute":"Mute","gui.SpriteInfo.spritePlaceholder":"Tên","gui.SpriteInfo.sprite":"Nhân vật","gui.SpriteInfo.show":"Xuất hiện","gui.SpriteInfo.size":"Kích thước ","gui.spriteSelectorItem.contextMenuDuplicate":"nhân bản","gui.spriteSelectorItem.contextMenuExport":"xuất ra","gui.spriteSelectorItem.contextMenuDelete":"xoá","gui.spriteSelector.addSpriteFromLibrary":"Chọn một Nhân vật","gui.spriteSelector.addSpriteFromPaint":"Vẽ","gui.spriteSelector.addSpriteFromSurprise":"Bất ngờ","gui.spriteSelector.addSpriteFromFile":"Tải Nhân vật lên","gui.stageHeader.stageSizeLarge":"Chuyển qua sân khấu lớn","gui.stageHeader.stageSizeSmall":"Chuyển sang phông nền nhỏ","gui.stageHeader.stageSizeFull":"Chuyển đến chế độ toàn màn hình","gui.stageHeader.stageSizeUnFull":"Thoát toàn màn hình","gui.stageHeader.fullscreenControl":"điều khiển toàn màn hình","gui.spriteSelector.addBackdropFromLibrary":"Chọn một Phông nền","gui.stageSelector.addBackdropFromPaint":"Vẽ","gui.stageSelector.addBackdropFromSurprise":"Bất ngờ","gui.stageSelector.addBackdropFromFile":"Tải phông nền","gui.stageSelector.stage":"Sân khấu","gui.stageSelector.backdrops":"Phông nền","gui.telemetryOptIn.label":"Gửi số liệu thống kê để giúp cải thiện Scratch","gui.telemetryOptIn.body1":"Scratch Team luôn muốn biết thêm về việc Scratch được sử dụng như thế nào ở khắp thế giới. Để hỗ trợ chúng tôi, bạn có thể cho phép Scratch tự động gửi thông tin sử dụng đến Scratch Team.","gui.telemetryOptIn.body2":"Thông tin chúng tôi thu thập bao gồm lựa chọn ngôn ngữ, thời gian sử dụng, và một số thao tác như lưu, tải lên và lấy xuống một dự án. Chúng tôi KHÔNG thu thập bất cứ thông tin cá nhân nào. Xin xem chính sách bảo mật {privacyPolicyLink}của chúng tôi để biết thêm chi tiết.","gui.telemetryOptIn.privacyPolicyLink":"Chinh sách Bảo mật","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Chế độ Turbo","gui.webglModal.label":"Trình duyệt của bạn không hỗ trợ WebGL","gui.webglModal.webgllink":"không hỗ trợ WebGL","gui.costumeLibrary.chooseABackdrop":"Chọn một Phông nền","gui.costumeLibrary.chooseACostume":"Chọn một trang phục","gui.costumeTab.addBackdropFromLibrary":"Chọn một Phông nền","gui.costumeTab.addCostumeFromLibrary":"thay đổi trang phục ","gui.costumeTab.addBlankCostume":"Vẽ","gui.costumeTab.addSurpriseCostume":"Bất ngờ","gui.costumeTab.addFileBackdrop":"Tải Phông nền","gui.costumeTab.addFileCostume":"tải trang phục lên","gui.extensionLibrary.chooseAnExtension":"Chọn Phần mở rộng","gui.extensionLibrary.extensionUrl":"Thêm đường dẫn URL mở rộng","gui.monitors.importListColumnPrompt":"Nên dùng cột nào? (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Không thể bắt đầu thu âm","gui.soundLibrary.chooseASound":"chọn âm thanh ","gui.soundTab.fileUploadSound":"Tải âm thanh lên","gui.soundTab.surpriseSound":"Bất ngờ","gui.soundTab.recordSound":"Ghi lại","gui.soundTab.addSoundFromLibrary":"chọn âm thanh ","gui.spriteLibrary.chooseASprite":"Chọn một Nhân vật","gui.tipsLibrary.tutorials":"Chọn một bài hướng dẫn","gui.alerts.createsuccess":"Dự án mới đã được tạo xong.","gui.alerts.createcopysuccess":"Dự án đã được lưu dưới dạng bản sao.","gui.alerts.createremixsuccess":"Dự án đã được lưu thành một bản phối lại.","gui.alerts.creating":"Đang tạo mới...","gui.alerts.creatingCopy":"Đang copy dự án...","gui.alerts.creatingRemix":"Đang phối lại dự án...","gui.alerts.creatingError":"Không thể tạo dự án. Vui lòng thử lại!","gui.alerts.savingError":"Không thể lưu dự án.","gui.alerts.savesuccess":"Dự án đã được lưu.","gui.alerts.saving":"Đang lưu dự án...","gui.alerts.cloudInfo":"Xin lưu ý, biến số cloud chỉ hỗ trợ dạng số, không hỗ trợ dạng chữ cái và biểu tượng. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Tỉm hiểu thêm.","gui.alerts.importing":"Đang nhập...","gui.defaultProject.variable":"biến của tôi","gui.extension.music.name":"Âm nhạc","gui.extension.music.description":"Chơi nhạc cụ và trống","gui.extension.pen.name":"Bút vẽ","gui.extension.pen.description":"Vẽ bằng các nhân vật của bạn.","gui.extension.videosensing.name":"Cảm biến Video","gui.extension.videosensing.description":"Nhận diện chuyển động với máy ảnh","gui.extension.text2speech.name":"Text to Speech","gui.extension.text2speech.description":"Make your projects talk.","gui.extension.translate.name":"Dịch","gui.extension.translate.description":"Dịch văn bản ra nhiều ngôn ngữ.","gui.extension.makeymakey.description":"Make anything into a key.","gui.extension.microbit.description":"Kết nối dự án của bạn với thế giới.","gui.extension.microbit.connectingMessage":"Đang kết nối","gui.extension.ev3.description":"Làm những con rô-bốt tương tác và hơn thế nữa.","gui.extension.ev3.connectingMessage":"Đang kết nối. Hãy chắc chắn rằng mã PIN trên EV3 của bạn là 1234.","gui.extension.boost.description":"Bring robotic creations to life.","gui.extension.boost.connectingMessage":"Connecting","gui.extension.wedo2.description":"Xây dựng với mô-tơ và cảm biến.","gui.extension.wedo2.connectingMessage":"Đang kết nối","gui.extension.gdxfor.description":"Sense push, pull, motion, and spin.","gui.extension.gdxfor.connectingMessage":"Connecting","gui.libraryTags.all":"Tất cả","gui.libraryTags.animals":"Động vật","gui.libraryTags.dance":"Khiêu vũ","gui.libraryTags.effects":"Hiệu ứng","gui.libraryTags.fantasy":"Tưởng tượng","gui.libraryTags.fashion":"Thời trang","gui.libraryTags.food":"Food","gui.libraryTags.indoors":"Trong nhà","gui.libraryTags.loops":"Loops","gui.libraryTags.music":"Âm nhạc","gui.libraryTags.notes":"Các lưu ý","gui.libraryTags.outdoors":"Ngoài trời","gui.libraryTags.patterns":"Patterns","gui.libraryTags.people":"Con người","gui.libraryTags.percussion":"Bộ gõ","gui.libraryTags.space":"Khoảng trắng","gui.libraryTags.sports":"Thể thao","gui.libraryTags.underwater":"Dưới nước","gui.libraryTags.voice":"Voice","gui.libraryTags.wacky":"Wacky","gui.libraryTags.animation":"Phim hoạt hình","gui.libraryTags.art":"Nghệ thuật","gui.libraryTags.games":"Trò chơi","gui.libraryTags.stories":"Những câu chuyện","gui.libraryTags.letters":"Ký tự","gui.opcodeLabels.direction":"hướng","gui.opcodeLabels.xposition":"vị trí-x","gui.opcodeLabels.yposition":"vị trí-y","gui.opcodeLabels.size":"kích thước","gui.opcodeLabels.costumename":"tên trang phục","gui.opcodeLabels.costumenumber":"costume number","gui.opcodeLabels.backdropname":"tên phông nền","gui.opcodeLabels.backdropnumber":"backdrop number","gui.opcodeLabels.volume":"âm lượng","gui.opcodeLabels.tempo":"nhịp độ","gui.opcodeLabels.answer":"trả lời","gui.opcodeLabels.loudness":"độ ồn","gui.opcodeLabels.username":"tên đăng nhập","gui.opcodeLabels.year":"năm","gui.opcodeLabels.month":"tháng","gui.opcodeLabels.date":"ngày","gui.opcodeLabels.dayofweek":"ngày trong tuần","gui.opcodeLabels.hour":"giờ","gui.opcodeLabels.minute":"phút","gui.opcodeLabels.second":"giây","gui.opcodeLabels.timer":"đồng hồ bấm giờ","gui.sharedMessages.backdrop":"backdrop{index}","gui.sharedMessages.costume":"costume{index}","gui.sharedMessages.sprite":"Sprite{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Bạn có muốn thay thế nội dung của dự án hiện tại?","gui.sharedMessages.loadFromComputerTitle":"Mở từ máy tính","boost.color.any":"any color","boost.color.black":"black","boost.color.blue":"blue","boost.color.green":"green","boost.color.red":"red","boost.color.white":"white","boost.color.yellow":"yellow","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] position","boost.getTiltAngle":"tilt angle [TILT_DIRECTION]","boost.motorDirection.backward":"that way","boost.motorDirection.forward":"this way","boost.motorDirection.reverse":"reverse","boost.motorOff":"turn motor [MOTOR_ID] off","boost.motorOn":"turn motor [MOTOR_ID] on","boost.motorOnFor":"turn motor [MOTOR_ID] for [DURATION] seconds","boost.motorOnForRotation":"turn motor [MOTOR_ID] for [ROTATION] rotations","boost.seeingColor":"seeing [COLOR] brick?","boost.setLightHue":"set light color to [HUE]","boost.setMotorDirection":"set motor [MOTOR_ID] direction [MOTOR_DIRECTION]","boost.setMotorPower":"set motor [MOTOR_ID] speed to [POWER] %","boost.tiltDirection.any":"any","boost.tiltDirection.down":"down","boost.tiltDirection.left":"left","boost.tiltDirection.right":"right","boost.tiltDirection.up":"up","boost.whenColor":"when [COLOR] brick seen","boost.whenTilted":"when tilted [TILT_DIRECTION_ANY]","ev3.beepNote":"Phát nốt [NOTE] trong vòng [TIME] giây","ev3.buttonPressed":"Nút [PORT] đã được ấn?","ev3.getBrightness":"độ sáng","ev3.getDistance":"khoảng cách","ev3.getMotorPosition":"Đặt mô-tơ của đầu ra[PORT] đo độ xoay tổng cộng","ev3.motorSetPower":"Đặt mô-tơ của đầu ra [PORT]với sức mạnh [POWER]%","ev3.motorTurnClockwise":"Đặt mô-tơ của đầu ra [PORT] xoay chiều kim đồng hồ trong vòng [TIME] giây","ev3.motorTurnCounterClockwise":"Đặt mô-tơ của đầu ra [PORT] xoay ngược chiều kim đồng hồ trong vòng [TIME] giây","ev3.whenBrightnessLessThan":"khi độ sáng < [DISTANCE]","ev3.whenButtonPressed":"khi nút [PORT] được bấm","ev3.whenDistanceLessThan":"khi khoảng cách < [DISTANCE]","gdxfor.getAcceleration":"acceleration [DIRECTION]","gdxfor.getForce":"force","gdxfor.getSpin":"spin speed [DIRECTION]","gdxfor.getTilt":"tilt angle [TILT]","gdxfor.isFreeFalling":"falling?","gdxfor.isTilted":"tilted [TILT]?","gdxfor.pulled":"pulled","gdxfor.pushed":"pushed","gdxfor.shaken":"shaken","gdxfor.startedFalling":"started falling","gdxfor.tiltDirectionMenu.any":"any","gdxfor.tiltDirectionMenu.back":"back","gdxfor.tiltDirectionMenu.front":"front","gdxfor.tiltDirectionMenu.left":"left","gdxfor.tiltDirectionMenu.right":"right","gdxfor.turnedFaceDown":"turned face down","gdxfor.turnedFaceUp":"turned face up","gdxfor.whenForcePushedOrPulled":"when force sensor [PUSH_PULL]","gdxfor.whenGesture":"when [GESTURE]","gdxfor.whenTilted":"when tilted [TILT]","makeymakey.downArrow":"mũi tên xuống","makeymakey.downArrowShort":"xuống","makeymakey.leftArrow":"mũi tên trái","makeymakey.leftArrowShort":"trái","makeymakey.rightArrow":"mũi tên phải","makeymakey.rightArrowShort":"bên phải","makeymakey.spaceKey":"phím trắng","makeymakey.upArrow":"mũi tên lên","makeymakey.upArrowShort":"lên","makeymakey.whenKeyPressed":"when [KEY] key pressed","makeymakey.whenKeysPressedInOrder":"when [SEQUENCE] pressed in order","microbit.buttonsMenu.any":"bất kỳ","microbit.clearDisplay":"xóa hiển thị","microbit.defaultTextToDisplay":"Xin chào!","microbit.displaySymbol":"hiển thị [MATRIX]","microbit.displayText":"hiển thị văn bản [TEXT]","microbit.gesturesMenu.jumped":"jumped","microbit.gesturesMenu.moved":"moved","microbit.gesturesMenu.shaken":"shaken","microbit.isButtonPressed":"[BTN] được bấm?","microbit.isTilted":"tilted [DIRECTION]?","microbit.pinStateMenu.off":"tắt","microbit.pinStateMenu.on":"bật","microbit.tiltAngle":"tilt angle [DIRECTION]","microbit.tiltDirectionMenu.any":"bất kỳ","microbit.tiltDirectionMenu.back":"phía sau cùng","microbit.tiltDirectionMenu.front":"phía trên cùng","microbit.tiltDirectionMenu.left":"trái","microbit.tiltDirectionMenu.right":"bên phải","microbit.whenButtonPressed":"when [BTN] button pressed","microbit.whenGesture":"when [GESTURE]","microbit.whenPinConnected":"when pin [PIN] connected","microbit.whenTilted":"when tilted [DIRECTION]","music.categoryName":"Âm nhạc","music.changeTempo":"thay đổi nhịp độ một lượng [TEMPO]","music.drumBass":"(2) Trống Bass","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Đôi dùi gỗ","music.drumClosedHiHat":"(6) Chũm chọe","music.drumConga":"(14)Conga","music.drumCowbell":"(11) Cowbel","music.drumCrashCymbal":"(4) Chũm choẹ trung","music.drumCuica":"(18) Culca","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Hand Clap","music.drumOpenHiHat":"(5) Chũm chọe ","music.drumSideStick":"(3) Side stick","music.drumSnare":"(1) Trống lẫy ","music.drumTambourine":"(7) Tambourine","music.drumTriangle":"(12) Hình tam giác ","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Mảnh ghép gỗ","music.getTempo":"nhịp độ","music.instrumentBass":"(6) Bass","music.instrumentBassoon":"(14) Bassoon","music.instrumentCello":"(8) Đàn viô-lông-xen","music.instrumentChoir":"(15) Đội đồng ca ","music.instrumentClarinet":"(10)","music.instrumentElectricGuitar":"(5) Guitar điện","music.instrumentElectricPiano":"(2) Đàn Piano điện","music.instrumentFlute":"(12) Sáo","music.instrumentGuitar":"(4) Đàn guitar","music.instrumentMarimba":"(19) Mộc cầm","music.instrumentMusicBox":"(17) Hộp nhạc","music.instrumentOrgan":"(3) Đàn organ","music.instrumentPiano":"(1) đàn Piano","music.instrumentPizzicato":"(7) Móc dây","music.instrumentSaxophone":"(11) Kèn Saxophone ","music.instrumentSteelDrum":"(18) Steel Drum","music.instrumentSynthLead":"(20) Synth Lea","music.instrumentSynthPad":"(21) Synth Pad","music.instrumentTrombone":"(9) Trombone","music.instrumentVibraphone":"(16) Vibraphone","music.instrumentWoodenFlute":"(13) thanh sáo gỗ","music.midiPlayDrumForBeats":"chơi trống [DRUM] trong [BEATS] nhịp","music.midiSetInstrument":"đặt nhạc cụ là [INSTRUMENT]","music.playDrumForBeats":"chơi trống [DRUM] trong [BEATS] nhịp","music.playNoteForBeats":"chơi nốt nhạc [NOTE] trong [BEATS] nhịp","music.restForBeats":"nghỉ trong [BEATS] nhịp","music.setInstrument":"đặt nhạc cụ là [INSTRUMENT]","music.setTempo":"thay đổi nhịp độ thành [TEMPO]","pen.categoryName":"Bút vẽ","pen.changeColorParam":"thay đổi [COLOR_PARAM] bút một lượng [VALUE]","pen.changeHue":"thay đổi màu bút vẽ bằng [HUE]","pen.changeShade":"đổi độ đậm bút vẽ bằng [SHADE]","pen.changeSize":"thay đổi độ dày của nét bút [SIZE]","pen.clear":"Xóa tất cả","pen.colorMenu.brightness":"độ sáng","pen.colorMenu.color":"màu","pen.colorMenu.saturation":"độ bão hòa","pen.colorMenu.transparency":"độ trong suốt","pen.penDown":"đặt bút","pen.penUp":"nhấc bút","pen.setColor":"chọn bút màu [COLOR]","pen.setColorParam":"đặt [COLOR_PARAM] bút bằng [VALUE]","pen.setHue":"chọn bút màu [HUE]","pen.setShade":"đặt độ đậm của bút vẽ thành [SHADE]","pen.setSize":"đặt kích thước bút vẽ bằng [SIZE]","pen.stamp":"in hình","text2speech.alto":"alto","text2speech.categoryName":"Text to Speech","text2speech.defaultTextToSpeak":"xin chào","text2speech.giant":"giant","text2speech.kitten":"kitten","text2speech.setLanguageBlock":"set language to [LANGUAGE]","text2speech.setVoiceBlock":"set voice to [VOICE]","text2speech.speakAndWaitBlock":"nói [WORDS]","text2speech.squeak":"squeak","text2speech.tenor":"tenor","translate.categoryName":"Dịch","translate.defaultTextToTranslate":"xin chào","translate.translateBlock":"dịch [WORDS] sang ngôn ngữ [LANGUAGE]","translate.viewerLanguage":"language","videoSensing.categoryName":"Cảm biến Video","videoSensing.direction":"hướng","videoSensing.motion":"chuyển động","videoSensing.off":"tắt","videoSensing.on":"bật","videoSensing.onFlipped":"khi lật","videoSensing.setVideoTransparency":"đặt độ trong suốt của video thành [TRANSPARENCY]","videoSensing.sprite":"nhân vật","videoSensing.stage":"Sân khấu","videoSensing.videoOn":"mở [ATTRIBUTE] trên [SUBJECT]","videoSensing.videoToggle":"mở video [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"khi chuyển động của video > [REFERENCE]","wedo2.getDistance":"khoảng cách","wedo2.getTiltAngle":"tilt angle [TILT_DIRECTION]","wedo2.isTilted":"tilted [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"huớng kia","wedo2.motorDirection.forward":"hướng này","wedo2.motorDirection.reverse":"đảo ngược","wedo2.motorId.a":"motor A","wedo2.motorId.all":"all motors","wedo2.motorId.b":"motor B","wedo2.motorId.default":"motor","wedo2.motorOff":"turn [MOTOR_ID] off","wedo2.motorOn":"turn [MOTOR_ID] on","wedo2.motorOnFor":"turn [MOTOR_ID] on for [DURATION] seconds","wedo2.playNoteFor":"chơi nốt nhạc trong [NOTE] trong [DURATION] giây","wedo2.setLightHue":"set light color to [HUE]","wedo2.setMotorDirection":"set [MOTOR_ID] direction to [MOTOR_DIRECTION]","wedo2.startMotorPower":"set [MOTOR_ID] power to [POWER]","wedo2.tiltDirection.any":"bất kỳ","wedo2.tiltDirection.down":"xuống","wedo2.tiltDirection.left":"trái","wedo2.tiltDirection.right":"bên phải","wedo2.tiltDirection.up":"lên","wedo2.whenDistance":"when distance [OP] [REFERENCE]","wedo2.whenTilted":"when tilted [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Màu","paint.paintEditor.saturation":"Độ bão hòa","paint.paintEditor.brightness":"Độ sáng","paint.paintEditor.costume":"Trang phục","paint.paintEditor.group":"Nhóm","paint.paintEditor.ungroup":"Hủy nhóm","paint.paintEditor.undo":"Hoàn tác","paint.paintEditor.redo":"Làm lại ","paint.paintEditor.forward":"Đưa lên phía trên","paint.paintEditor.backward":"Đưa ra phía sau","paint.paintEditor.front":"Đưa lên phía trên cùng","paint.paintEditor.back":"Đưa ra phía sau cùng","paint.paintEditor.more":"Nhiều hơn","paint.modeTools.brushSize":"Kích thước ","paint.modeTools.eraserSize":"Kích thước tẩy","paint.modeTools.copy":"Sao chép","paint.modeTools.paste":"Dán","paint.modeTools.delete":"Xóa","paint.modeTools.curved":"Uốn cong","paint.modeTools.pointed":"Góc nhọn","paint.modeTools.thickness":"Độ dày ngòi bút","paint.modeTools.flipHorizontal":"Lật ngang","paint.modeTools.flipVertical":"Lật dọc","paint.modeTools.filled":"Hình đầy","paint.modeTools.outlined":"Hình rỗng","paint.paintEditor.bitmap":"Chuyển thành Bitmap","paint.paintEditor.vector":"Chuyển thành Vector","paint.paintEditor.fill":"Tô","paint.paintEditor.stroke":"Viền","paint.brushMode.brush":"Cọ vẽ","paint.eraserMode.eraser":"Tẩy","paint.fillMode.fill":"Tô","paint.lineMode.line":"Dòng","paint.ovalMode.oval":"Hình tròn","paint.rectMode.rect":"Hình chữ nhật","paint.reshapeMode.reshape":"Đổi hình dạng","paint.roundedRectMode.roundedRect":"Hình vuông góc tròn","paint.selectMode.select":"Chọn","paint.textMode.text":"Văn bản","paint.colorPicker.swap":"Đổi màu","tw.alerts.autosaving":"Đang tạo điiểm khôi phục","tw.alerts.lostPeripheralConnection":"Mất kết nối từ {extensionName}","tw.alerts.savedToDisk":"Đã lưu vời máy tính bạn.","tw.backpack.rename":"Tên mới:","tw.browserModal.desc":"Đảm bảo bạn đang sử dụng Google Chrome, Mozilla Firefox, Microsoft Edge, hoặc Apple Safari phiên bản mới nhất.","tw.changeUsername.cannotChangeWhileRunning":"Tên người dùng không thể đổi khi dự án đang chạy.","tw.feedbackButton":"Phản hồi TurboWarp","tw.fps":"{framerate}FPS","tw.gui.crashMessage.description":"Chúng tôi xin lỗi, nhưng hình như trang có vấn đề. Xin vui lòng tải lại trang của bạn để thử lại.","tw.home.credit":"Ghi chú và Tín dụng","tw.home.instructions":"Hướng đẫn","tw.input.tooltip":"Sao chép và đán một đường dẫn dự án Scratch vào đây!","tw.loader.data":"Đang tải dữ liệu dự án...","tw.loader.generic":"Đang tải dự án...","tw.menuBar.60off":"Tắt chế độ 60 FPS","tw.menuBar.60on":"Bật chế độ 60 FPS","tw.menuBar.advanced":"Nâng cao","tw.menuBar.changeUsername":"Đổi tên người dùng","tw.menuBar.cloudOff":"Vô hiệu hóa biến đám mây","tw.menuBar.cloudOn":"Kích hoạt biến đám mây","tw.menuBar.cloudUnavailable":"Biến đám mây không có sẵn","tw.menuBar.cloudUnavailableAlert":"Không thể dùng biến đám mây, hầu như vì bạn mở phần chỉnh sửa","tw.menuBar.loadRestorePoint":"Tải điểm khôi phục","tw.menuBar.moreSettings":"Cài đặt nâng cao","tw.menuBar.newFramerate":"Tỷ lệ mới:","tw.menuBar.package":"Đóng gói dự án","tw.menuBar.reportError1":"Một số khối lệnh không thể biên dịch","tw.menuBar.reportError2":"Đây là một lỗi. Xin vui lòng báo cáo.","tw.menuBar.saveAs":"Lưu thành {file}","tw.menuBar.seeInside":"Xem bên trong","tw.oldDownload":"Lưu để tách tệp tin...","tw.restorePoint.loadFail":"Không thể tải điểm khôi phục: {error}","tw.saveAs":"Lưu thành...","tw.saveTo":"Lưu về {file}","tw.settingsModal.customStageSize":"Cỡ sân khấu tùy chỉnh:","tw.settingsModal.dangerZone":"Vùng nguy hiểm","tw.settingsModal.disableCompiler":"Vô hiệu hóa biên dịch","tw.settingsModal.featured":"Đặc sắc","tw.settingsModal.fps":"60 FPS (FPS tủy chỉnh)","tw.settingsModal.fpsHelp.customFramerate":"Bấm để dùng một tỷ lệ khung hình từ 30 hoặc 60","tw.settingsModal.help":"Bấm để hỗ trợ","tw.settingsModal.highQualityPen":"Bút chất lượng Cao","tw.settingsModal.infiniteClones":"Bản sao vô hạn","tw.settingsModal.infiniteClonesHelp":"Vô hiệu hóa giới hạn 300 bản sao của Scratch","tw.settingsModal.removeLimits":"Xóa giới hạn","tw.settingsModal.removeMiscLimits":"Xóa các giới hạn khác","tw.settingsModal.removeMiscLimitsHelp":"Xóa giới hạn hiệu ứng âm thanh và cỡ bút.","tw.settingsModal.storeProjectOptions":"Lưu trữ cài đặt trong dự án","tw.settingsModal.title":"Cài đặt nâng cao","tw.spriteSelectorItem.rename":"đổi tên thành","tw.studioview.authorAttribution":"bởi {author}","tw.studioview.error":"Hình như có một lỗi tải trang tiếp theo của dự án","tw.studioview.hoverText":"{title} bởi {author}","tw.twExtension.name":"Khối TurboWarp","tw.usernameModal.mustChange.resetIt":"cài lại (khuyến nghị)","tw.usernameModal.reset":"Cài đặt lại","tw.usernameModal.title":"Đổi tên người dùng","tw.viewFeaturedProjects":"Bấm để xem dự án đặc sắc","tw.viewOnScratch":"Xem dự án trên Scratch"},"tr":{"gui.alerts.tryAgain":"Tekrar Dene","gui.alerts.download":"İndir","gui.connection.reconnect":"Tekrar Bağlan","gui.backpack.costumeLabel":"kostüm","gui.backpack.soundLabel":"ses","gui.backpack.scriptLabel":"dizi","gui.backpack.spriteLabel":"kukla","gui.backpack.header":"Sırt Çantası","gui.backpack.errorBackpack":"Sırt çantası yüklenirken hata oluştu","gui.backpack.loadingBackpack":"Yükleniyor...","gui.backpack.more":"Daha Fazla","gui.backpack.emptyBackpack":"Sırt Çantası boş","gui.unsupportedBrowser.label":"Web tarayıcınız desteklenmiyor","gui.cards.all-tutorials":"Öğreticiler","gui.cards.shrink":"Küçült","gui.cards.expand":"Açıkla","gui.cards.close":"Kapat","gui.cards.more-things-to-try":"Denemek için daha fazla şey!","gui.cards.see-more":"Daha fazla görüntüle","gui.comingSoon.message1":"Endişelenmeyin, üzerinde çalışıyoruz {emoji}","gui.comingSoon.message2":"Çok Yakında...","gui.comingSoon.message3":"Üzerinde çalışıyoruz {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Cihaz bulunamadı","gui.connection.auto-scanning.prescan":"Aramayı başlatmak için cihazını yakınında bulundur.","gui.connection.auto-scanning.pressbutton":"Cihazındaki düğmeye bas.","gui.connection.auto-scanning.start-search":"Aramaya Başla","gui.connection.connecting-searchbutton":"Aranıyor...","gui.connection.auto-scanning.try-again":"Tekrar dene","gui.connection.connected":"Bağlandı","gui.connection.disconnect":"Bağlantıyı Kes","gui.connection.go-to-editor":"Editöre Git","gui.connection.connecting-cancelbutton":"Bağlanıyor...","gui.connection.error.errorMessage":"Hoop! Bir şeyler yanlış gitti.","gui.connection.error.tryagainbutton":"Tekrar dene","gui.connection.error.helpbutton":"Yardım","gui.connection.peripheral-name-label":"Cihaz adı","gui.connection.connect":"Bağlan","gui.connection.scanning.lookingforperipherals":"Cihazlar aranıyor","gui.connection.scanning.noPeripheralsFound":"Cihaz bulunamadı","gui.connection.scanning.instructions":"Yukarıdaki listeden cihazını seç.","gui.connection.search":"Yenile","gui.connection.unavailable.installscratchlink":"Scratch Link programının kurulduğundan ve çalıştığından emin ol","gui.connection.unavailable.enablebluetooth":"Bluetooth\'un etkinleştirildiğini kontrol et","gui.connection.unavailable.tryagainbutton":"Tekrar dene","gui.connection.unavailable.helpbutton":"Yardım","gui.controls.go":"Git","gui.controls.stop":"Durdur","gui.crashMessage.label":"Hoop! Bir hata oldu.","gui.crashMessage.errorNumber":"{errorId} numaralı bir hata kaydedildi.","gui.crashMessage.reload":"Yeniden yükle","gui.customProcedures.myblockModalTitle":"Bir Blok Oluştur","gui.customProcedures.addAnInputNumberText":"Bir girdi ekle","gui.customProcedures.numberTextType":"sayı veya metin","gui.customProcedures.addAnInputBoolean":"Bir girdi ekle","gui.customProcedures.booleanType":"mantıksal","gui.customProcedures.addALabel":"Bir etiket ekle","gui.customProcedures.runWithoutScreenRefresh":"Ekranı yenilemeden çalışsın","gui.customProcedures.cancel":"Vazgeç","gui.customProcedures.ok":"Tamam","gui.SpriteInfo.direction":"Yön","gui.directionPicker.rotationStyles.allAround":"her yöne dön","gui.directionPicker.rotationStyles.leftRight":"sağa-sola","gui.directionPicker.rotationStyles.dontRotate":"döndürme","gui.gui.addExtension":"Eklenti Ekle","gui.gui.codeTab":"Kod","gui.gui.backdropsTab":"Dekorlar","gui.gui.costumesTab":"Kostümler","gui.gui.soundsTab":"Sesler","gui.extensionLibrary.comingSoon":"Çok Yakında","gui.extensionLibrary.requires":"Gereksinimler","gui.extensionLibrary.collaboration":"İşbirliği ile","gui.library.filterPlaceholder":"Ara","gui.library.allTag":"Tümü","gui.loader.headline":"Proje Yükleniyor","gui.loader.creating":"Proje Oluştur","gui.authorInfo.byUser":"{username} tarafından","gui.menuBar.seeProjectPage":"Proje sayfasına bak","gui.menuBar.LanguageSelector":"dil seçici","gui.menuBar.tutorialsLibrary":"Eğitici Dersler","gui.menuBar.restoreSprite":"Kuklayı Geri Getir","gui.menuBar.restoreSound":"Sesi Geri Getir","gui.menuBar.restoreCostume":"Kostümü Geri Getir","gui.menuBar.restore":"Geri Getir","gui.menuBar.saveNow":"Şimdi kaydet","gui.menuBar.saveAsCopy":"Kopya olarak kaydet","gui.menuBar.remix":"Katkı Yap","gui.menuBar.new":"Yeni","gui.menuBar.file":"Dosya","gui.menuBar.downloadToComputer":"Bilgisayarına kaydet","gui.menuBar.edit":"Düzenle","gui.menuBar.turboModeOff":"Turbo Modu kapat","gui.menuBar.turboModeOn":"Turbo Modu aç","gui.gui.projectTitlePlaceholder":"Proje başlığı buraya","gui.menuBar.isShared":"Paylaşılan","gui.menuBar.share":"Paylaş","gui.modal.help":"Yardım","gui.modal.back":"Geri","gui.monitor.listMonitor.empty":"(boş)","gui.monitor.listMonitor.listLength":"uzunluğu {length}","gui.monitor.contextMenu.default":"normal görünüm","gui.monitor.contextMenu.large":"geniş görünüm","gui.monitor.contextMenu.slider":"slider","gui.monitor.contextMenu.sliderRange":"Kaygan aralığını ayarla","gui.monitor.contextMenu.import":"içe aktar","gui.monitor.contextMenu.export":"dışarıya aktar","gui.monitor.contextMenu.hide":"gizle","gui.playButton.play":"Çal","gui.playButton.stop":"Durdur","gui.gui.variableScopeOptionAllSprites":"Tüm kuklalar için","gui.gui.variableScopeOptionSpriteOnly":"Sadece bu kukla için","gui.gui.cloudVariableOption":"Bulut değişkeni (sunucuda saklanır)","gui.gui.variablePromptAllSpritesMessage":"Bu değişken tüm kuklalar için geçerli olacak.","gui.gui.listPromptAllSpritesMessage":"Bu liste tüm kuklalara açık olacak.","gui.prompt.cancel":"Vazgeç","gui.prompt.ok":"OK","gui.playbackStep.stopMsg":"Durdur","gui.playbackStep.playMsg":"Çal","gui.playbackStep.loadingMsg":"Yükleniyor...","gui.playbackStep.saveMsg":"Kaydet","gui.playbackStep.reRecordMsg":"Yeniden kaydet","gui.recordModal.title":"Ses Kaydet","gui.recordingStep.beginRecord":"Aşağıdaki düğmeye tıklayarak kayda başlayın","gui.recordingStep.permission":"{arrow}Mikrofonunuzu kullanmak için izninize ihtiyacımız var","gui.recordingStep.stop":"Kaydı durdur","gui.recordingStep.record":"Kaydet","gui.sliderModal.min":"En düşük değer","gui.sliderModal.max":"En yüksek değer","gui.sliderModal.title":"Kaygan aralığını ayarla","gui.sliderPrompt.cancel":"İptal","gui.sliderPrompt.ok":"Tamam","gui.soundEditor.sound":"Ses","gui.soundEditor.play":"Çal","gui.soundEditor.stop":"Durdur","gui.soundEditor.copy":"Kopyala","gui.soundEditor.paste":"Yapıştır","gui.soundEditor.copyToNew":"Yenisine kopyala","gui.soundEditor.delete":"Sil","gui.soundEditor.save":"Kaydet","gui.soundEditor.undo":"Geri Al","gui.soundEditor.redo":"Geri Al","gui.soundEditor.faster":"Daha hızlı","gui.soundEditor.slower":"Daha Yavaş","gui.soundEditor.echo":"Yankı","gui.soundEditor.robot":"Robot","gui.soundEditor.louder":"Daha sesli","gui.soundEditor.softer":"Daha Yumuşak","gui.soundEditor.reverse":"Tersi","gui.soundEditor.fadeOut":"sesi azalt","gui.soundEditor.fadeIn":"Sesi çoğalt","gui.soundEditor.mute":"Sustur","gui.SpriteInfo.spritePlaceholder":"İsim","gui.SpriteInfo.sprite":"Kukla","gui.SpriteInfo.show":"Göster","gui.SpriteInfo.size":"Büyüklük","gui.spriteSelectorItem.contextMenuDuplicate":"kopyasını çıkart","gui.spriteSelectorItem.contextMenuExport":"dışarıya aktar","gui.spriteSelectorItem.contextMenuDelete":"sil","gui.spriteSelector.addSpriteFromLibrary":"Bir Kukla Seç","gui.spriteSelector.addSpriteFromPaint":"Çizim","gui.spriteSelector.addSpriteFromSurprise":"Sürpriz","gui.spriteSelector.addSpriteFromFile":"Kuklayı yükle","gui.stageHeader.stageSizeLarge":"Geniş ekrana geç","gui.stageHeader.stageSizeSmall":"Küçük sahneye geç","gui.stageHeader.stageSizeFull":"Tam ekran moduna geç","gui.stageHeader.stageSizeUnFull":"Tam ekran modundan çık","gui.stageHeader.fullscreenControl":"Tam Ekran Kontrolü","gui.spriteSelector.addBackdropFromLibrary":"Bir Dekor Seç","gui.stageSelector.addBackdropFromPaint":"Çizim","gui.stageSelector.addBackdropFromSurprise":"Sürpriz","gui.stageSelector.addBackdropFromFile":"Dekor Yükle","gui.stageSelector.stage":"Sahne","gui.stageSelector.backdrops":"Dekorlar","gui.telemetryOptIn.label":"Scratch\'ı iyileştirmek için istatistikleri raporla.","gui.telemetryOptIn.body1":"Scratch Ekibi, her zaman Scratch\'in tüm dünyada nasıl kullanıldığını daha iyi anlamaya çalışmaktadır. Bu çabaya destek olmak için Scratch\'in, kullanımı ile ilgili bilgileri Scratch Ekibine otomatik olarak göndermesine izin verebilirsiniz. ","gui.telemetryOptIn.body2":"Topladığımız bilgiler şunları içerir; blok kullanımı, kaydetme, geri yükleme ve proje yükleme gibi olaylar. Kişisel bilgileri TOPLAMIYORUZ. Lütfen daha fazla detay için {privacyPolicyLink} inceleyiniz.","gui.telemetryOptIn.privacyPolicyLink":"Gizlilik İlkesi","gui.telemetryOptIn.optInText":"Kullanım verilerimi Scratch Ekibi ile paylaş","gui.telemetryOptIn.optInTooltip":"Telemetriyi aç","gui.telemetryOptIn.optOutText":"Kullanım verilerimi Scratch Ekibi ile paylaşma","gui.telemetryOptIn.optOutTooltip":"Telemetriyi kapat","gui.telemetryOptIn.settingWasUpdated":"Ayarlarınız güncellendi.","gui.telemetryOptIn.buttonClose":"Kapat","gui.turboMode.active":"Turbo Modu","gui.webglModal.label":"Web Tarayıcınızın WebGL Desteği Bulunmamaktadır","gui.webglModal.webgllink":"WebGL desteğiniz bulunmamaktadır","gui.costumeLibrary.chooseABackdrop":"Bir Dekor Seç","gui.costumeLibrary.chooseACostume":"Bir Kostüm Seç","gui.costumeTab.addBackdropFromLibrary":"Bir Dekor Seç","gui.costumeTab.addCostumeFromLibrary":"Bir Kostüm Seç","gui.costumeTab.addBlankCostume":"Çizim","gui.costumeTab.addSurpriseCostume":"Sürpriz","gui.costumeTab.addFileBackdrop":"Dekor Yükle","gui.costumeTab.addFileCostume":"Kostüm Yükle","gui.extensionLibrary.chooseAnExtension":"Bir Uzantı Seç","gui.extensionLibrary.extensionUrl":"Uzantının URL\'ini giriniz","gui.monitors.importListColumnPrompt":"Hangi sütun kullanılmalı (1-{numberOfColumns}) ?","gui.recordingStep.alertMsg":"Kayıda başlanamıyor","gui.soundLibrary.chooseASound":"Bir Ses Seç","gui.soundTab.fileUploadSound":"Ses Yükle","gui.soundTab.surpriseSound":"Sürpriz","gui.soundTab.recordSound":"Kaydet","gui.soundTab.addSoundFromLibrary":"Bir Ses Seç","gui.spriteLibrary.chooseASprite":"Bir Kukla Seç","gui.tipsLibrary.tutorials":"Bir Öğretici Ders Seç","gui.alerts.createsuccess":"Yeni Proje oluşturuldu.","gui.alerts.createcopysuccess":"Proje kopya olarak kaydedildi.","gui.alerts.createremixsuccess":"Proje katkı olarak kaydedildi.","gui.alerts.creating":"Yeni oluşturuluyor...","gui.alerts.creatingCopy":"Proje kopyalanıyor...","gui.alerts.creatingRemix":"Proje katkılanıyor...","gui.alerts.creatingError":"Projeniz kaydedilemedi. Lütfen tekrar deneyin!","gui.alerts.savingError":"Proje kaydedilemedi.","gui.alerts.savesuccess":"Proje kaydedildi.","gui.alerts.saving":"Proje kaydediliyor...","gui.alerts.cloudInfo":"Lütfen dikkat, bulut değişkenleri sadece sayıları destekler; harfler ve semboller desteklenmiyor. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Daha fazlasını öğren.","gui.alerts.importing":"İçe aktarılıyor...","gui.defaultProject.variable":"değişkenim","gui.extension.music.name":"Müzik","gui.extension.music.description":"Çalgıları ve davulları çal.","gui.extension.pen.name":"Kalem","gui.extension.pen.description":"Kuklan ile çiz.","gui.extension.videosensing.name":"Video Algılama","gui.extension.videosensing.description":"Kamera ile hareketi algıla.","gui.extension.text2speech.name":"Metinden Sese","gui.extension.text2speech.description":"Projeni konuştur.","gui.extension.translate.name":"Çeviri","gui.extension.translate.description":"Metni birçok dile çevir.","gui.extension.makeymakey.description":"Herşeyi dokunmatik yap.","gui.extension.microbit.description":"Projelerini dünya ile paylaş.","gui.extension.microbit.connectingMessage":"Bağlanıyor","gui.extension.ev3.description":"Etkileşimli robotlar ve daha fazlasını oluştur.","gui.extension.ev3.connectingMessage":"Bağlanıyor. EV3\'teki Pinin 1234 olarak ayarlandığından emin ol.","gui.extension.boost.description":"Robotik kreasyonları hayata geçirin.","gui.extension.boost.connectingMessage":"Bağlanıyor","gui.extension.wedo2.description":"Motorlar ve sensörler ile yap.","gui.extension.wedo2.connectingMessage":"Bağlanıyor","gui.extension.gdxfor.description":"İtme, çekme, hareket, ve döndürme algıla.","gui.extension.gdxfor.connectingMessage":"Bağlanıyor","gui.libraryTags.all":"Tümü","gui.libraryTags.animals":"Hayvanlar","gui.libraryTags.dance":"Dans","gui.libraryTags.effects":"Etkiler","gui.libraryTags.fantasy":"Fantezi","gui.libraryTags.fashion":"Moda","gui.libraryTags.food":"Yiyecek","gui.libraryTags.indoors":"Bina içi","gui.libraryTags.loops":"Döngüler","gui.libraryTags.music":"Müzik","gui.libraryTags.notes":"Notalar","gui.libraryTags.outdoors":"Bina dışı","gui.libraryTags.patterns":"Desenler","gui.libraryTags.people":"İnsanlar","gui.libraryTags.percussion":"Vurmalılar","gui.libraryTags.space":"Uzay","gui.libraryTags.sports":"Sporlar","gui.libraryTags.underwater":"Su altı","gui.libraryTags.voice":"Ses","gui.libraryTags.wacky":"Tuhaf","gui.libraryTags.animation":"Animasyon","gui.libraryTags.art":"Sanat","gui.libraryTags.games":"Oyunlar","gui.libraryTags.stories":"Hikayeler","gui.libraryTags.letters":"Harfler","gui.opcodeLabels.direction":"yön","gui.opcodeLabels.xposition":"x konumu","gui.opcodeLabels.yposition":"y konumu","gui.opcodeLabels.size":"büyüklük","gui.opcodeLabels.costumename":"kostüm ismi","gui.opcodeLabels.costumenumber":"kostüm numarası","gui.opcodeLabels.backdropname":"dekorun adı","gui.opcodeLabels.backdropnumber":"dekor numarası","gui.opcodeLabels.volume":"ses düzeyi","gui.opcodeLabels.tempo":"tempo","gui.opcodeLabels.answer":"cevap","gui.opcodeLabels.loudness":"ses yüksekliği","gui.opcodeLabels.username":"kullanıcı adı","gui.opcodeLabels.year":"yıl","gui.opcodeLabels.month":"ay","gui.opcodeLabels.date":"tarih","gui.opcodeLabels.dayofweek":"haftanın günü","gui.opcodeLabels.hour":"saat","gui.opcodeLabels.minute":"dakika","gui.opcodeLabels.second":"saniye","gui.opcodeLabels.timer":"zamanlayıcı","gui.sharedMessages.backdrop":"dekor {index}","gui.sharedMessages.costume":"kostüm {index}","gui.sharedMessages.sprite":"Kukla {index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"Mevcut projenin üstüne yazayım mı?","gui.sharedMessages.loadFromComputerTitle":"Bilgisayarından yükle","boost.color.any":"herhangi bir renk","boost.color.black":"siyah","boost.color.blue":"mavi","boost.color.green":"yeşil","boost.color.red":"kırmızı","boost.color.white":"beyaz","boost.color.yellow":"sarı","boost.getMotorPosition":"motor [MOTOR_REPORTER_ID] motorunun konumu","boost.getTiltAngle":"eğim açısı [TILT_DIRECTION]","boost.motorDirection.backward":"diğer tarafa","boost.motorDirection.forward":"bu tarafa","boost.motorDirection.reverse":"tersine","boost.motorOff":"[MOTOR_ID] numaralı motoru kapat","boost.motorOn":"[MOTOR_ID] numaralı motoru aç","boost.motorOnFor":"[MOTOR_ID] numaralı motoru [DURATION] saniye çalıştır","boost.motorOnForRotation":"[MOTOR_ID] numaralı motoru [ROTATION] tur çalıştır","boost.seeingColor":"[COLOR] parça görüyor musun?","boost.setLightHue":"ışık rengini [HUE] olarak ayarla","boost.setMotorDirection":"motor [MOTOR_ID] motorunun yönünü [MOTOR_DIRECTION] olarak ayarla","boost.setMotorPower":"motor [MOTOR_ID] gücünü % [POWER] ayarla","boost.tiltDirection.any":"herhangi","boost.tiltDirection.down":"aşağı","boost.tiltDirection.left":"sol","boost.tiltDirection.right":"sağ","boost.tiltDirection.up":"yukarı","boost.whenColor":"parça, [COLOR] renginde görüldüğünde","boost.whenTilted":"[TILT_DIRECTION_ANY] eğildiğinde","ev3.beepNote":"[NOTE] notasını [TIME] saniye çal","ev3.buttonPressed":"[PORT] düğmesi basıldı mı?","ev3.getBrightness":"parlaklık","ev3.getDistance":"mesafe","ev3.getMotorPosition":"[PORT] motor konumu","ev3.motorSetPower":"[PORT] motor gücünü % [POWER] yap","ev3.motorTurnClockwise":"[PORT] motorunu > yönünde [TIME] saniye döndür","ev3.motorTurnCounterClockwise":"[PORT] motorunu < yönünde [TIME] saniye döndür","ev3.whenBrightnessLessThan":"parlaklık < [DISTANCE] olduğunda","ev3.whenButtonPressed":"[PORT] düğmesine basıldığında","ev3.whenDistanceLessThan":"mesafe < [DISTANCE] olduğunda","gdxfor.getAcceleration":"ivme [DIRECTION]","gdxfor.getForce":"güç","gdxfor.getSpin":"devir hızı [DIRECTION]","gdxfor.getTilt":"eğim açısı [TILT]","gdxfor.isFreeFalling":"düşüyor mu?","gdxfor.isTilted":"[TILT] eğimli mi?","gdxfor.pulled":"çekilmiş","gdxfor.pushed":"itilmiş","gdxfor.shaken":"sallanmış","gdxfor.startedFalling":"düşmeye başlamış","gdxfor.tiltDirectionMenu.any":"herhangi yöne","gdxfor.tiltDirectionMenu.back":"geriye","gdxfor.tiltDirectionMenu.front":"öne","gdxfor.tiltDirectionMenu.left":"sola","gdxfor.tiltDirectionMenu.right":"sağa","gdxfor.turnedFaceDown":"yüzü aşağı dönük","gdxfor.turnedFaceUp":"yüzü yukarı dönük","gdxfor.whenForcePushedOrPulled":"kuvvet sensörü [PUSH_PULL]","gdxfor.whenGesture":"[GESTURE] olduğunda","gdxfor.whenTilted":"Eğim [TILT] olduğunda","makeymakey.downArrow":"aşağı ok","makeymakey.downArrowShort":"aşağı","makeymakey.leftArrow":"sol ok","makeymakey.leftArrowShort":"sol","makeymakey.rightArrow":"sağ ok","makeymakey.rightArrowShort":"sağ","makeymakey.spaceKey":"boşluk","makeymakey.upArrow":"yukarı ok","makeymakey.upArrowShort":"yukarı","makeymakey.whenKeyPressed":"[KEY] tuşu basılınca","makeymakey.whenKeysPressedInOrder":"[SEQUENCE] dizisi sırayla basılınca","microbit.buttonsMenu.any":"herhangi","microbit.clearDisplay":"ekranı temizle","microbit.defaultTextToDisplay":"Merhaba!","microbit.displaySymbol":"[MATRIX]göster","microbit.displayText":"[TEXT] metnini göster","microbit.gesturesMenu.jumped":"atlanmış","microbit.gesturesMenu.moved":"taşınmış","microbit.gesturesMenu.shaken":"sallanmış","microbit.isButtonPressed":"[BTN] düğmesi basıldı mı?","microbit.isTilted":"[DIRECTION] eğildi mi?","microbit.pinStateMenu.off":"kapalı","microbit.pinStateMenu.on":"açık","microbit.tiltAngle":"[DIRECTION] eğim açısı","microbit.tiltDirectionMenu.any":"herhangi","microbit.tiltDirectionMenu.back":"geri","microbit.tiltDirectionMenu.front":"ön","microbit.tiltDirectionMenu.left":"sol","microbit.tiltDirectionMenu.right":"sağ","microbit.whenButtonPressed":"[BTN] düğmesi basıldığında","microbit.whenGesture":"[GESTURE] olduğunda","microbit.whenPinConnected":"[PIN] pini bağlandığında","microbit.whenTilted":"[DIRECTION] eğildiğinde","music.categoryName":"Müzik","music.changeTempo":"tempoyu [TEMPO] yap","music.drumBass":"(2) Bas Davul","music.drumBongo":"(13) Bongo","music.drumCabasa":"(15) Cabasa","music.drumClaves":"(9) Bagetler","music.drumClosedHiHat":"(6) Kapalı Hi-Hat","music.drumConga":"(14) Conga","music.drumCowbell":"(11) Çan","music.drumCrashCymbal":"(4) Çarpışma Zili","music.drumCuica":"(18) Cuica","music.drumGuiro":"(16) Guiro","music.drumHandClap":"(8) Alkışla","music.drumOpenHiHat":"(5) Açık Hi-Hat","music.drumSideStick":"(3) yan Çubuk","music.drumSnare":"(1) Trampet","music.drumTambourine":"(7) Tef","music.drumTriangle":"(12) Üçgen","music.drumVibraslap":"(17) Vibraslap","music.drumWoodBlock":"(10) Fagot","music.getTempo":"tempo","music.instrumentBass":"(6) Bas","music.instrumentBassoon":"(14) Fagot","music.instrumentCello":"(8) Çello","music.instrumentChoir":"(15) Koro","music.instrumentClarinet":"(10) Klarnet","music.instrumentElectricGuitar":"(5) Elektro Gitar","music.instrumentElectricPiano":"(2) Elektro Piyano","music.instrumentFlute":"(12) Flüt","music.instrumentGuitar":"(4) Gitar","music.instrumentMarimba":"(19) Klisifon","music.instrumentMusicBox":"(17) Müzik Kutusu","music.instrumentOrgan":"(3) Org","music.instrumentPiano":"(1) Piyano","music.instrumentPizzicato":"(7) Parmak Hareketi","music.instrumentSaxophone":"(11) Saksafon","music.instrumentSteelDrum":"(18) Çelik Tambur","music.instrumentSynthLead":"(20) Synth Kurşun","music.instrumentSynthPad":"(21) Synth Padi","music.instrumentTrombone":"(9) Trombon","music.instrumentVibraphone":"(16) Vibrafon","music.instrumentWoodenFlute":"(13) Tahta Flüt","music.midiPlayDrumForBeats":"[DRUM] davulunu [BEATS] vuruş çal","music.midiSetInstrument":"Enstrümanı [INSTRUMENT] yap","music.playDrumForBeats":"[DRUM] davulunu [BEATS] vuruş çal","music.playNoteForBeats":"[NOTE] notasını [BEATS] vuruşunda çal","music.restForBeats":"[BEATS] vuruş durakla","music.setInstrument":"Enstrümanı [INSTRUMENT] yap","music.setTempo":"tempoyu [TEMPO] yap","pen.categoryName":"Kalem","pen.changeColorParam":"kalem [COLOR_PARAM] [VALUE] artır","pen.changeHue":"kalem rengini [HUE] artır","pen.changeShade":"kalem tonunu [SHADE] artır","pen.changeSize":"kalem kalınlığını [SIZE] artır","pen.clear":"tümünü sil","pen.colorMenu.brightness":"parlaklık","pen.colorMenu.color":"rengi","pen.colorMenu.saturation":"doygunluk","pen.colorMenu.transparency":"saydamlık","pen.penDown":"kalemi bastır","pen.penUp":"kalemi kaldır","pen.setColor":"kalem rengini [COLOR] yap","pen.setColorParam":"kalem [COLOR_PARAM] [VALUE] yap","pen.setHue":"kalem rengini [HUE] yap","pen.setShade":"kalem tonunu [SHADE] yap","pen.setSize":"kalem kalınlığını [SIZE] yap","pen.stamp":"damgala","text2speech.alto":"alto","text2speech.categoryName":"Metinden Sese","text2speech.defaultTextToSpeak":"merhaba","text2speech.giant":"dev","text2speech.kitten":"kedi yavrusu","text2speech.setLanguageBlock":"dili [LANGUAGE]\'ye ayarla","text2speech.setVoiceBlock":"sesi [VOICE]e ayarla","text2speech.speakAndWaitBlock":"konuş [WORDS]","text2speech.squeak":"ciyak","text2speech.tenor":"tenor","translate.categoryName":"Çeviri","translate.defaultTextToTranslate":"merhaba","translate.translateBlock":"[WORDS] metnini [LANGUAGE] diline çevir","translate.viewerLanguage":"dil","videoSensing.categoryName":"Video Algılama","videoSensing.direction":"yönü","videoSensing.motion":"hareketi","videoSensing.off":"kapat","videoSensing.on":"aç","videoSensing.onFlipped":"ters çevrilmiş","videoSensing.setVideoTransparency":"videonun saydamlığını [TRANSPARENCY] yap","videoSensing.sprite":"kuklanın","videoSensing.stage":"sahnenin","videoSensing.videoOn":"[SUBJECT] video [ATTRIBUTE] ","videoSensing.videoToggle":"videoyu [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"video hareketi > [REFERENCE] olduğunda","wedo2.getDistance":"mesafe","wedo2.getTiltAngle":"[TILT_DIRECTION] eğim açısı","wedo2.isTilted":"[TILT_DIRECTION_ANY] eğildi mi?","wedo2.motorDirection.backward":"diğer tarafa","wedo2.motorDirection.forward":"bu tarafa","wedo2.motorDirection.reverse":"tersine","wedo2.motorId.a":"A motoru","wedo2.motorId.all":"tüm motorlar","wedo2.motorId.b":"B motoru","wedo2.motorId.default":"motor","wedo2.motorOff":"[MOTOR_ID] u kapat","wedo2.motorOn":"[MOTOR_ID] u aç","wedo2.motorOnFor":"[MOTOR_ID] u [DURATION] saniye çalıştır","wedo2.playNoteFor":"[NOTE] notasını [DURATION] saniye çal ","wedo2.setLightHue":"ışık rengini [HUE] \'ye ayarla","wedo2.setMotorDirection":"[MOTOR_ID] yönünü [MOTOR_DIRECTION]\'a ayarla","wedo2.startMotorPower":"[MOTOR_ID] gücünü [POWER]\'e ayarla","wedo2.tiltDirection.any":"herhangi","wedo2.tiltDirection.down":"aşağı","wedo2.tiltDirection.left":"sol","wedo2.tiltDirection.right":"sağ","wedo2.tiltDirection.up":"yukarı","wedo2.whenDistance":"mesafe [OP] [REFERENCE] olduğunda","wedo2.whenTilted":"[TILT_DIRECTION_ANY] eğildiğinde","paint.paintEditor.hue":"Renk","paint.paintEditor.saturation":"Doygunluk","paint.paintEditor.brightness":"Parlaklık","paint.paintEditor.costume":"Kostüm","paint.paintEditor.group":"Grup","paint.paintEditor.ungroup":"Grubu Dağıt","paint.paintEditor.undo":"Geri Al","paint.paintEditor.redo":"İleri Al","paint.paintEditor.forward":"Öne","paint.paintEditor.backward":"Geriye","paint.paintEditor.front":"En Öne","paint.paintEditor.back":"En Geriye","paint.paintEditor.more":"Daha Fazla","paint.modeTools.brushSize":"Büyüklük","paint.modeTools.eraserSize":"Silgi boyutu","paint.modeTools.copy":"Kopyala","paint.modeTools.paste":"Yapıştır","paint.modeTools.delete":"Sil","paint.modeTools.curved":"Kavisli","paint.modeTools.pointed":"işaretlendi","paint.modeTools.thickness":"Kalınlık","paint.modeTools.flipHorizontal":"Yatay Çevir","paint.modeTools.flipVertical":"Dikey Çevir","paint.modeTools.filled":"Dolmuş","paint.modeTools.outlined":"Ana Hatlarıyla Çizilen ","paint.paintEditor.bitmap":"Bitmap\'e Dönüştür","paint.paintEditor.vector":"Vektöre Dönüştür","paint.paintEditor.fill":"Doldur","paint.paintEditor.stroke":"Kontur","paint.brushMode.brush":"Fırça","paint.eraserMode.eraser":"silgi","paint.fillMode.fill":"Doldur","paint.lineMode.line":"Çizgi","paint.ovalMode.oval":"Çember","paint.rectMode.rect":"Dikdörtgen","paint.reshapeMode.reshape":"Şekli değiştir","paint.roundedRectMode.roundedRect":"Yuvarlatılmış dikdörtgen","paint.selectMode.select":"Seç","paint.textMode.text":"Metin","paint.colorPicker.swap":"Değiştir","tw.alerts.autosaving":"Yükleme noktası yapılıyor","tw.alerts.savedToDisk":"Bilgisayarına kaydedilmiştir.","tw.backpack.rename":"Yeni kullanıcı adı:","tw.browserModal.desc":"Lütfen Google Chrome, Mozilla Firefox, Microsoft Edge veya Apple Safari\'nin yeni bir sürümünü kullandığınızdan emin olun.","tw.changeUsername.cannotChangeWhileRunning":"Proje çalışırken kullanıcı adı değiştirilemez.","tw.cloudVariableBadge":"Bu proje bulut değişkenleri kullanıyor. TurboWarp, Scratch\'ten farklı olarak kendi bulut değişken sunucusunu kullanıyor. Kullanıcıların, kullanıcı adlarının söylediği kişi olmayabileceğini unutmayın. Herkes kullanıcı adını herhangi bir şeyle değiştirebileceğinden kimliğe bürünmeye dikkat edin. {learnMore}","tw.code":"Kaynak Kodu","tw.confirmIncompatibleExtension":"Bu eklenti Scratch ile kullanamılınıyor. Bununla yapılan projeler Scratch web sitesine yüklenemez. Etkinleştirmek istediğinizden emin misiniz?","tw.customExtension.description":"URL\'lardan görenek eklentiler yükleyin. Geliştiriciler için. Deneysel.","tw.customExtension.name":"Görenek Eklenti","tw.featuredProjectsStudio":"Stüdyoyu Scratch\'te görüntüleyin.","tw.feedback":"Geribildirim ve Hatalar","tw.feedbackButton":"Turbowarp geribildirim","tw.footer.credits":"Krediler","tw.footer.disclaimer":"TurboWarp, Scratch, Scratch Takım veya Scratch Vakıfı ile bağlantılı değildir.","tw.footer.embed":"Gömmek","tw.footer.fosshost":"Turbowarp\'u fosshost sağlıyor.","tw.footer.parameters":" URL parametreler","tw.footer.translate":"Turbowarp\'u çevirmeyi yardım edin","tw.gui.defaultProjectTitle":"Proje","tw.guiDefaultTitle":"Scratch Projeleri daha hızlı yapın","tw.home.credit":"Notlar ve Krediler","tw.home.description":"TurboWarp, projeleri çok hızlı çalıştırmaları için JavaScript\'e derleyen bir Scratch modudur. Yukarıda bir proje ID yada URL girerek yada özel projeleri şeçerek ile deneyin.","tw.home.instructions":"Kurallar","tw.input.tooltip":"Bir Scratch proje linki buraya kopyala ve yapıştır!","tw.interpolationEnabled":"Enterpolasyon","tw.invalidParameters.clones":"\\"klon\\" URL parametresi geçersizdir","tw.invalidParameters.fps":"\\"fps\\" URL parametresi geçersizdir","tw.loadError":"Bu projeyi yükleyemiyoruz: {error}","tw.loader.assets.known":"Varlıklar indiriliyor ({complete}/{total}) ...","tw.loader.assets.unknown":"Varlıklar indiriliyor ...","tw.loader.data":"Proje verileri indiriliyor ...","tw.loader.generic":"Proje yükleniyor ...","tw.menuBar.60off":"60 FPS modunu kapat","tw.menuBar.60on":"60 FPS modunu aç","tw.menuBar.addons":"Eklentiler","tw.menuBar.advanced":"Gelişmiş","tw.menuBar.changeUsername":"Adını değiştir","tw.menuBar.cloudOff":"Bulut değişkenleri kapat","tw.menuBar.cloudOn":"Bulut değişkenleri aç","tw.menuBar.cloudUnavailable":"Bulut Değişkenleri bulamıyoruz","tw.menuBar.cloudUnavailableAlert":"Bulut değişkenleri kullanamıyoruz, büyük ihtimalle editörü açtığınız için.","tw.menuBar.loadRestorePoint":"Yükleme noktasını yükle","tw.menuBar.moreSettings":"Gelişmiş Ayarlar","tw.menuBar.newFramerate":"Yeni karehızı:","tw.menuBar.reportError1":"Bazı komut dosyaları derlenemedi.","tw.menuBar.reportError2":"Bu bir hatadır. Lütfen bildirin.","tw.menuBar.saveAs":"{file} olarak kaydet","tw.menuBar.seeInside":"İçeri bak","tw.oldDownload":"Farklı dosyaya kaydet...","tw.paint.alpha":"Saydamlık","tw.privacy":"Gizillik Politikası","tw.saveAs":"Farklı kaydet...","tw.saveTo":"{file} dosyasına kaydet","tw.settingsModal.customStageSize":"Özel Sahne Büyüklüğü:","tw.settingsModal.customStageSizeHelp":"Scratch\'in büyüklüğünü 480x360\'den başka büyüklüğe değiştiriyor. Eğer geniş ekran istiyorsanız, 640x360yi deneyin. Sadece bir kaç projeler bunu düzgün bir şekilde halledebilir.","tw.settingsModal.dangerZone":"Tehlikeli yer","tw.settingsModal.disableCompiler":"Derlemeyi kapat","tw.settingsModal.disableCompilerHelp":"Turbowarp Derleyiciyi devre dışı bırakır. Blokları hemen güncellenmesi için projeleri düzenlerken bunu etkinleştirmek isteyebilirsiniz, aksi takdirde bunu etkinleştirmemelisiniz.","tw.settingsModal.featured":"Özellikli","tw.settingsModal.fps":"60 FPS (Özel FPS)","tw.settingsModal.fpsHelp":"Blokarı 30FPS yerinde 60FPS ile çalıştırır. Çoğu projeler bu mod ile 30FPS gibi çalışamaz. Bu durumda Enterpolasyonu 60 FPS modu devre dışı bırakarak denemelisiniz. {customFramerate}.","tw.settingsModal.fpsHelp.customFramerate":"30FPS yada 60FPS\'den başka kare hızı ile çalıştırmak istiyorsan bunu tıkla.","tw.settingsModal.help":"Yardım için buraya tıkla","tw.settingsModal.highQualityPen":"Yüksek kalite kalem","tw.settingsModal.highQualityPenHelp":"Yüksek Kaliteli Kalem, kalem projelerinin daha yüksek kalitede görüntülemekte sağlar. ve oluşturucudaki bazı yuvarlamaları da görünmemesini sağlar. Bu ayardan tüm projelere bir advantaj veremiyor ve performansı etkileyebilir.","tw.settingsModal.infiniteClones":"Sonsuz klonlar","tw.settingsModal.infiniteClonesHelp":"Scratch\'in 300 klon limiti çıkarıyor.","tw.settingsModal.interpolation":"Enterpolasyon","tw.settingsModal.interpolationHelp":"Enterpolasyon, hareketli grafik hareketini interpolasyon yaparak, projenin davranışını değiştirmeden daha yüksek kare hızlarında çalışıyormuş gibi görünmesini sağlayan deneysel bir özelliktir. Eğer bir projeyi 60 FPS\'de çalıştırdıysanız ve çok hızlı çalıştığını fark ettiyseniz, İnterpolasyon bunu çözer. Enterpolasyon 3B projelerde, raytracer ve kalem projelerde kullanmayın çünkü projeleri yavaşlatır ve daha pürüzsüz yapmaz.","tw.settingsModal.largeStageWarning":"Bu büyüklükte özel bir sahne boyutu kullanılması önerilmez! Bunun yerine, aynı en boy oranına sahip daha düşük bir boyut kullanın ve tam ekran modunun kullanıcının ekranına uyacak şekilde yükseltmesine izin verin.","tw.settingsModal.removeFencing":"Eskirimi çıkart","tw.settingsModal.removeFencingHelp":"Kuklaları ekran dışı yerler gitmeyi izin verir ve kuklaların istediği kadar büyük yada küçük olmasını izin verir, ve dokunma blokları ekran dışında kullanılabilir.","tw.settingsModal.removeLimits":"Limitleri çıkart","tw.settingsModal.removeMiscLimits":"Çeşitli Limitleri Kaldır","tw.settingsModal.removeMiscLimitsHelp":"Ses efekti limitleri gibi projeleri bozmaması olmayan çeşitli limitleri kaldırır.","tw.settingsModal.storeProjectOptions":"Proje ayarlarını kaydet","tw.settingsModal.storeProjectOptionsHelp":"TurboWarp bu projeyi yüklediğinde, ayarların otomatik olarak uygulanması için seçilmiş ayarları projede kaydeder. Warp zamanlayıcısı ve derleyiciyi devre dışı bırakma ayarları kaydedilmeyecektir.","tw.settingsModal.title":"Gelişmiş Ayarlar","tw.settingsModal.warpTimer":"Warp zamanlayıcı","tw.settingsModal.warpTimerHelp":"Warp zamanlayıcı bloklara uzun veya sonsuz bir döngüde takılıp kalmadıklarını kontrol etmesini sağlar ve çok yavaş bir karehızında yürütüyor, ve bu da çoğu çökmeyi düzeltir. Bunun çok büyük bir performans etkisi vardır, bu nedenle editörün dışında varsayılan olarak etkinleştirilmez.","tw.spriteSelectorItem.rename":"yeniden adlandır","tw.studioview.authorAttribution":"{author} tarafından","tw.studioview.error":"Sonraki proje sayfası yüklenirken hata oluştu.","tw.studioview.hoverText":"{title} tarafından {author}","tw.twExtension.description":"İlginç ve yeni bloklar. Bu bloklar Scratch ile kullanılamaz.","tw.twExtension.name":"Turbowarp Bloklar","tw.usernameModal.help":"Bu kullanıcı adı web tarayıcının çerezlerinde olacak. Bulut değişkenleri olan projelerle etkileşim kurduğunuzda kaydedilebilir.","tw.usernameModal.help2":"Geçerli bir Scratch hesabına karşılık gelen değerler genellikle bulut değişken sunucusu tarafından reddedilirecek. Olduğu gibi ybırakmanızı vea Scratch kullanıcı adınızı değiştirmenizi öneririz.","tw.usernameModal.mustChange":"Üzgünüz, bulut değişken sunucusu kullanıcı adınızın güvensiz olabileceğini düşünüyor. Lütfen başka bir şeyle değiştirin yada {resetIt}.","tw.usernameModal.mustChange.resetIt":"sıfırlayın (önerildi)","tw.usernameModal.reset":"Sıfırla","tw.usernameModal.title":"Adını değiştir","tw.viewFeaturedProjects":"Özellikli projeleri görmek için buraya tıklayınız.","tw.viewOnScratch":"Projeyi Scratch\'te görüntüleyin.","tw.webglModal.description":"Ne yazık ki senin web tarayıcının yada bilgisayarın {webGlLink}. Bu sitenin çalışması için bu teknolojiye ihtiyaç vardır. Web tarayıcını ve grafik sürücülerini güncelle yada bilgisayarını yeniden başlatmayı deneyin."},"uk":{"gui.alerts.tryAgain":"Спробуйте ще раз","gui.alerts.download":"Завантажити","gui.connection.reconnect":"Перепід\'єднання","gui.backpack.costumeLabel":"costume","gui.backpack.soundLabel":"sound","gui.backpack.scriptLabel":"script","gui.backpack.spriteLabel":"sprite","gui.backpack.header":"Сховок","gui.backpack.errorBackpack":"Збій завантаження сховку","gui.backpack.loadingBackpack":"Завантаження","gui.backpack.more":"Більше","gui.backpack.emptyBackpack":"Сховок порожній","gui.unsupportedBrowser.label":"Оглядач не підтримується","gui.cards.all-tutorials":"Посібники","gui.cards.shrink":"Зменшити","gui.cards.expand":"Розгорнути","gui.cards.close":"Закрити","gui.cards.more-things-to-try":"Спробуй більше!","gui.cards.see-more":"Дивитись ще","gui.comingSoon.message1":"Не хвилюйтесь, ми над цим {emoji}","gui.comingSoon.message2":"Незабаром...","gui.comingSoon.message3":"Ми над цим працюємо {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"Пристроїв не знайдено","gui.connection.auto-scanning.prescan":"Розмістіть пристрій поблизу, а потім розпочніть пошук.","gui.connection.auto-scanning.pressbutton":"Натисніть кнопку на своєму пристрої.","gui.connection.auto-scanning.start-search":"Розпочати пошук","gui.connection.connecting-searchbutton":"Пошук...","gui.connection.auto-scanning.try-again":"Спробуйте ще раз","gui.connection.connected":"Під\'єднано","gui.connection.disconnect":"Роз\'єднати","gui.connection.go-to-editor":"До Редактора","gui.connection.connecting-cancelbutton":"Під\'єднання...","gui.connection.error.errorMessage":"На жаль, щось пішло не так.","gui.connection.error.tryagainbutton":"Спробуйте ще раз","gui.connection.error.helpbutton":"Допомога","gui.connection.peripheral-name-label":"Ім\'я пристрою","gui.connection.connect":"Під\'єднати","gui.connection.scanning.lookingforperipherals":"Пошук пристроїв","gui.connection.scanning.noPeripheralsFound":"Пристроїв не знайдено","gui.connection.scanning.instructions":"Оберіть ваш пристрій зі списку","gui.connection.search":"Оновити","gui.connection.unavailable.installscratchlink":"Переконайтеся, що Scratch Link встановлено та запущено","gui.connection.unavailable.enablebluetooth":"Перевірте, що Bluetooth увімкнено","gui.connection.unavailable.tryagainbutton":"Спробуйте ще раз","gui.connection.unavailable.helpbutton":"Допомога","gui.controls.go":"Виконати","gui.controls.stop":"Зупинити","gui.crashMessage.label":"Ой! Щось пішло не так.","gui.crashMessage.errorNumber":"Ваша помилка зареєстрована з ідентифікатором {errorId}","gui.crashMessage.reload":"Перезавантажити","gui.customProcedures.myblockModalTitle":"Створити блок","gui.customProcedures.addAnInputNumberText":"Отримати","gui.customProcedures.numberTextType":"число або текст","gui.customProcedures.addAnInputBoolean":"Отримувати","gui.customProcedures.booleanType":"логічне значення","gui.customProcedures.addALabel":"Додати напис","gui.customProcedures.runWithoutScreenRefresh":"Виконання без оновлення екрану","gui.customProcedures.cancel":"Скасувати","gui.customProcedures.ok":"Гаразд","gui.SpriteInfo.direction":"Напрям","gui.directionPicker.rotationStyles.allAround":"Навколо","gui.directionPicker.rotationStyles.leftRight":"Зліва-направо","gui.directionPicker.rotationStyles.dontRotate":"Не обертати","gui.gui.addExtension":"Додати розширення","gui.gui.codeTab":"Код","gui.gui.backdropsTab":"Тло","gui.gui.costumesTab":"Образи","gui.gui.soundsTab":"Звуки","gui.extensionLibrary.comingSoon":"Незабаром","gui.extensionLibrary.requires":"Необхідно","gui.extensionLibrary.collaboration":"Співпраця з","gui.library.filterPlaceholder":"Шукати","gui.library.allTag":"Усі","gui.loader.headline":"Завантаження проєкту","gui.loader.creating":"Створення проекту","gui.authorInfo.byUser":" {username}","gui.menuBar.seeProjectPage":"Перегляд сторінки проєкту","gui.menuBar.LanguageSelector":"вибір мови","gui.menuBar.tutorialsLibrary":"Посібники","gui.menuBar.restoreSprite":"Відновити спрайт","gui.menuBar.restoreSound":"Відновити звук","gui.menuBar.restoreCostume":"Відновити образ","gui.menuBar.restore":"Відновити","gui.menuBar.saveNow":"Зберегти негайно","gui.menuBar.saveAsCopy":"Зберегти як копію","gui.menuBar.remix":"Ремікс","gui.menuBar.new":"Новий","gui.menuBar.file":"Файл","gui.menuBar.downloadToComputer":"Вивантажити на ваш комп’ютер","gui.menuBar.edit":"Правка","gui.menuBar.turboModeOff":"Вимкнути турбо-режим","gui.menuBar.turboModeOn":"Ввімкнути турбо-режим","gui.gui.projectTitlePlaceholder":"Тут назва проєкту","gui.menuBar.isShared":"Опубліковане","gui.menuBar.share":"Поділитись","gui.modal.help":"Допомога","gui.modal.back":"Назад","gui.monitor.listMonitor.empty":"(порожньо)","gui.monitor.listMonitor.listLength":"всього {length}","gui.monitor.contextMenu.default":"з назвою","gui.monitor.contextMenu.large":"тільки дані","gui.monitor.contextMenu.slider":"слайдер","gui.monitor.contextMenu.sliderRange":"змінити діапазон слайдера","gui.monitor.contextMenu.import":"імпорт","gui.monitor.contextMenu.export":"експорт","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"Відтворити","gui.playButton.stop":"Зупинити","gui.gui.variableScopeOptionAllSprites":"Для усіх спрайтів","gui.gui.variableScopeOptionSpriteOnly":"Тільки для цього спрайту","gui.gui.cloudVariableOption":"\\"Хмарна\\" змінна (зберігається на сервері)","gui.gui.variablePromptAllSpritesMessage":"Ця змінна буде доступна для всіх спрайтів.","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"Скасувати","gui.prompt.ok":"Гаразд","gui.playbackStep.stopMsg":"Зупинити","gui.playbackStep.playMsg":"Відтворити","gui.playbackStep.loadingMsg":"Завантаження","gui.playbackStep.saveMsg":"Зберегти","gui.playbackStep.reRecordMsg":"Перезаписати","gui.recordModal.title":"Запис звуку","gui.recordingStep.beginRecord":"Почніть запис, натиснувши кнопку нижче","gui.recordingStep.permission":"{arrow}Нам потрібен ваш дозвіл на використання мікрофону","gui.recordingStep.stop":"Зупинити запис","gui.recordingStep.record":"Записати","gui.sliderModal.min":"Найменше значення","gui.sliderModal.max":"Найбільше значення","gui.sliderModal.title":"Змінити діапазон слайдера","gui.sliderPrompt.cancel":"Скасувати","gui.sliderPrompt.ok":"Гаразд","gui.soundEditor.sound":"Звук","gui.soundEditor.play":"Відтворити","gui.soundEditor.stop":"Зупинити","gui.soundEditor.copy":"Копія","gui.soundEditor.paste":"Вставити","gui.soundEditor.copyToNew":"Копіювати до нового","gui.soundEditor.delete":"Вилучити","gui.soundEditor.save":"Зберегти","gui.soundEditor.undo":"Скасувати","gui.soundEditor.redo":"Повернути","gui.soundEditor.faster":"Швидше","gui.soundEditor.slower":"Повільніше","gui.soundEditor.echo":"Відлуння","gui.soundEditor.robot":"Робот","gui.soundEditor.louder":"Голосніше","gui.soundEditor.softer":"Тихіше","gui.soundEditor.reverse":"Обернути","gui.soundEditor.fadeOut":"Затухання","gui.soundEditor.fadeIn":"Посилення","gui.soundEditor.mute":"Заглушити","gui.SpriteInfo.spritePlaceholder":"Назва","gui.SpriteInfo.sprite":"Спрайт","gui.SpriteInfo.show":"Показати","gui.SpriteInfo.size":"Розмір","gui.spriteSelectorItem.contextMenuDuplicate":"дублювати","gui.spriteSelectorItem.contextMenuExport":"експорт","gui.spriteSelectorItem.contextMenuDelete":"вилучити","gui.spriteSelector.addSpriteFromLibrary":"Обрати спрайт","gui.spriteSelector.addSpriteFromPaint":"Малювати","gui.spriteSelector.addSpriteFromSurprise":"Сюрприз","gui.spriteSelector.addSpriteFromFile":"Вивантажити спрайт","gui.stageHeader.stageSizeLarge":"Перемкнути на велику сцену","gui.stageHeader.stageSizeSmall":"Перемкнути на малу сцену","gui.stageHeader.stageSizeFull":"Увімкнути повноекранний режим","gui.stageHeader.stageSizeUnFull":"Вийти з повноекранного режиму","gui.stageHeader.fullscreenControl":"Повноекранний режим","gui.spriteSelector.addBackdropFromLibrary":"Обрати тло","gui.stageSelector.addBackdropFromPaint":"Намалювати","gui.stageSelector.addBackdropFromSurprise":"Сюрприз","gui.stageSelector.addBackdropFromFile":"Вивантажити тло","gui.stageSelector.stage":"Сцена","gui.stageSelector.backdrops":"Тло","gui.telemetryOptIn.label":"Надсилайте статистику, щоб покращити Скретч","gui.telemetryOptIn.body1":"Розробники з Scratch Team завжди прагнуть краще зрозуміти, як Скретч використовується у всьому світі. Щоб допомогти підтримати ці зусилля, ви можете дозволити автоматично надсилати інформацію про використання в Scratch Team.","gui.telemetryOptIn.body2":"Інформація, яку ми збираємо, включає вибір мови, використання блоків та деякі події, такі як збереження, завантаження та вивантаження проєкту. Ми не збираємо особисту інформацію. Будь ласка, перегляньте {privacyPolicyLink} для отримання додаткової інформації.","gui.telemetryOptIn.privacyPolicyLink":"Політика конфіденційності","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"Режим турбо","gui.webglModal.label":"Ваш оглядач не підтримує WebGL","gui.webglModal.webgllink":"не підтримує WebGL","gui.costumeLibrary.chooseABackdrop":"Оберіть тло","gui.costumeLibrary.chooseACostume":"Обрати образ","gui.costumeTab.addBackdropFromLibrary":"Обрати тло","gui.costumeTab.addCostumeFromLibrary":"Обрати образ","gui.costumeTab.addBlankCostume":"Малювати","gui.costumeTab.addSurpriseCostume":"Сюрприз","gui.costumeTab.addFileBackdrop":"Вивантажити тло","gui.costumeTab.addFileCostume":"Вивантажити образ","gui.extensionLibrary.chooseAnExtension":"Оберіть розширення","gui.extensionLibrary.extensionUrl":"Введи URL розширення","gui.monitors.importListColumnPrompt":"Який стовпчик використовувати (1-{numberOfColumns})?","gui.recordingStep.alertMsg":"Не вдалось розпочати запис","gui.soundLibrary.chooseASound":"Оберіть звук","gui.soundTab.fileUploadSound":"Вивантажити звук","gui.soundTab.surpriseSound":"Сюрприз","gui.soundTab.recordSound":"Записати","gui.soundTab.addSoundFromLibrary":"Обрати звук","gui.spriteLibrary.chooseASprite":"Оберіть спрайт","gui.tipsLibrary.tutorials":"Обрати посібник","gui.alerts.createsuccess":"Новий проєкт створено.","gui.alerts.createcopysuccess":"Проєкт збережено як копію.","gui.alerts.createremixsuccess":"Проєкт збережено як ремікс.","gui.alerts.creating":"Створення нового...","gui.alerts.creatingCopy":"Копіювання проєкту...","gui.alerts.creatingRemix":"Реміксування проєкту...","gui.alerts.creatingError":"Не вдалося створити проєкт. Будь ласка спробуйте ще раз!","gui.alerts.savingError":"Проєкт не збережено.","gui.alerts.savesuccess":"Проєкт збережено.","gui.alerts.saving":"Збереження проєкту...","gui.alerts.cloudInfo":"Пам\'ятайте, що хмарні змінні можуть містити лише числа, але не літери чи символи. {learnMoreLink}","gui.alerts.cloudInfoLearnMore":"Дізнатись більше.","gui.alerts.importing":"Імпортування...","gui.defaultProject.variable":"моя змінна","gui.extension.music.name":"Музика","gui.extension.music.description":"Грати на інструментах та барабанах.","gui.extension.pen.name":"Олівець","gui.extension.pen.description":"Малювати за допомогою спрайтів.","gui.extension.videosensing.name":"Відеоспостереження","gui.extension.videosensing.description":"Визначити рух за допомогою камери.","gui.extension.text2speech.name":"Текст у мову","gui.extension.text2speech.description":"Розмови в ваших проєктах","gui.extension.translate.name":"Перекласти","gui.extension.translate.description":"Переклад тексту на різні мови.","gui.extension.makeymakey.description":"Зробити щось через клавіші-контакти","gui.extension.microbit.description":"Під\'єднати ваші проєкти до навколишнього світу","gui.extension.microbit.connectingMessage":"Під\'єднання","gui.extension.ev3.description":"Створити інтерактивних роботів і більше.","gui.extension.ev3.connectingMessage":"Під\'єднання. Переконайтеся, що пін на вашому EV3 встановлено на 1234.","gui.extension.boost.description":"Доведіть робототехнічні творіння до життя.","gui.extension.boost.connectingMessage":"З\'єднання","gui.extension.wedo2.description":"Працюємо з двигунами та сенсорами","gui.extension.wedo2.connectingMessage":"Під\'єднання","gui.extension.gdxfor.description":"Датчики поштовху, тяги, руху і обертання.","gui.extension.gdxfor.connectingMessage":"З\'єднання","gui.libraryTags.all":"Усі","gui.libraryTags.animals":"Тварини","gui.libraryTags.dance":"Танцювальна музика","gui.libraryTags.effects":"Ефекти","gui.libraryTags.fantasy":"Фантазії","gui.libraryTags.fashion":"Мода","gui.libraryTags.food":"Їжа","gui.libraryTags.indoors":"У приміщенні","gui.libraryTags.loops":"Фрагменти","gui.libraryTags.music":"Музика","gui.libraryTags.notes":"Примітки","gui.libraryTags.outdoors":"Поза приміщенням","gui.libraryTags.patterns":"Візерунки","gui.libraryTags.people":"Люди","gui.libraryTags.percussion":"Перкусія","gui.libraryTags.space":"Космос","gui.libraryTags.sports":"Спорт","gui.libraryTags.underwater":"Під водою","gui.libraryTags.voice":"Голос","gui.libraryTags.wacky":"Дивне","gui.libraryTags.animation":"Анімації","gui.libraryTags.art":"Арт","gui.libraryTags.games":"Ігри","gui.libraryTags.stories":"Історії","gui.libraryTags.letters":"Літери","gui.opcodeLabels.direction":"напрям","gui.opcodeLabels.xposition":"значення x","gui.opcodeLabels.yposition":"значення y","gui.opcodeLabels.size":"розмір","gui.opcodeLabels.costumename":"ім’я образу","gui.opcodeLabels.costumenumber":"образ #","gui.opcodeLabels.backdropname":"ім’я тла","gui.opcodeLabels.backdropnumber":"тло #","gui.opcodeLabels.volume":"гучність","gui.opcodeLabels.tempo":"темп","gui.opcodeLabels.answer":"відповідь","gui.opcodeLabels.loudness":"гучність","gui.opcodeLabels.username":"користувач","gui.opcodeLabels.year":"рік","gui.opcodeLabels.month":"місяць","gui.opcodeLabels.date":"дата","gui.opcodeLabels.dayofweek":"день тижня","gui.opcodeLabels.hour":"година","gui.opcodeLabels.minute":"хвилина ","gui.opcodeLabels.second":"секунда","gui.opcodeLabels.timer":"таймер","gui.sharedMessages.backdrop":"тло{index}","gui.sharedMessages.costume":"образ{index}","gui.sharedMessages.sprite":"Спрайт{index}","gui.sharedMessages.pop":"поп","gui.sharedMessages.replaceProjectWarning":"Замінити вміст поточного проєкту?","gui.sharedMessages.loadFromComputerTitle":"Завантажити з вашого комп’ютера","boost.color.any":"будь-який колір","boost.color.black":"чорний","boost.color.blue":"синій","boost.color.green":"зелений","boost.color.red":"червоний","boost.color.white":"білий","boost.color.yellow":"жовтий","boost.getMotorPosition":"позиція [MOTOR_REPORTER_ID]","boost.getTiltAngle":"кут нахилу [TILT_DIRECTION]","boost.motorDirection.backward":"за годинником","boost.motorDirection.forward":"проти годинника","boost.motorDirection.reverse":"обернути","boost.motorOff":"вимкнути [MOTOR_ID]","boost.motorOn":"увімкнути [MOTOR_ID]","boost.motorOnFor":"увімкнути [MOTOR_ID] на [DURATION] секунд","boost.motorOnForRotation":"увімкнути [MOTOR_ID] на [ROTATION] оборотів","boost.seeingColor":"бачить кубик кольору [COLOR] ?","boost.setLightHue":"встановити колір світла в [HUE]","boost.setMotorDirection":"встановити [MOTOR_ID] напрям [MOTOR_DIRECTION]","boost.setMotorPower":"встановити [MOTOR_ID] швидкість в [POWER] %","boost.tiltDirection.any":"будь-який","boost.tiltDirection.down":"вниз","boost.tiltDirection.left":"ліворуч","boost.tiltDirection.right":"праворуч","boost.tiltDirection.up":"вгору","boost.whenColor":"якщо бачить кубик кольору [COLOR] то","boost.whenTilted":"коли нахил [TILT_DIRECTION_ANY]","ev3.beepNote":"пищати [NOTE] [TIME] секунд","ev3.buttonPressed":"кнопку [PORT] натиснуто?","ev3.getBrightness":"яскравість","ev3.getDistance":"відстань","ev3.getMotorPosition":"позиція двигуна [PORT]","ev3.motorSetPower":"встановити потужність [PORT] в [POWER] %","ev3.motorTurnClockwise":"увімкнути двигун [PORT] у такому напрямі на [TIME] секунд","ev3.motorTurnCounterClockwise":"увімкнути двигун [PORT] у зворотньому напрямі на [TIME] секунд","ev3.whenBrightnessLessThan":"якщо яскравість < [DISTANCE]","ev3.whenButtonPressed":"якщо кнопку [PORT] натиснуто","ev3.whenDistanceLessThan":"якщо дистанція < [DISTANCE]","gdxfor.getAcceleration":"прискорення [DIRECTION]","gdxfor.getForce":"сила","gdxfor.getSpin":"швидкість обертання [DIRECTION]","gdxfor.getTilt":"кут нахилу [TILT]","gdxfor.isFreeFalling":"падає?","gdxfor.isTilted":"нахил [TILT]?","gdxfor.pulled":"виштовхнуто","gdxfor.pushed":"заштовхнуто","gdxfor.shaken":"струснуто","gdxfor.startedFalling":"початок падіння","gdxfor.tiltDirectionMenu.any":"будь-який","gdxfor.tiltDirectionMenu.back":"назад","gdxfor.tiltDirectionMenu.front":"вперед","gdxfor.tiltDirectionMenu.left":"ліворуч","gdxfor.tiltDirectionMenu.right":"праворуч","gdxfor.turnedFaceDown":"лицем донизу","gdxfor.turnedFaceUp":"лицем вверх","gdxfor.whenForcePushedOrPulled":"поки сенсор сили [PUSH_PULL]","gdxfor.whenGesture":"коли [GESTURE]","gdxfor.whenTilted":"коли нахилено [TILT]","makeymakey.downArrow":"стрілка вниз","makeymakey.downArrowShort":"вниз","makeymakey.leftArrow":"стрілка ліворуч","makeymakey.leftArrowShort":"ліворуч","makeymakey.rightArrow":"стрілка праворуч","makeymakey.rightArrowShort":"праворуч","makeymakey.spaceKey":"пропуск","makeymakey.upArrow":"стрілка вгору","makeymakey.upArrowShort":"вгору","makeymakey.whenKeyPressed":"поки клавішу [KEY] натиснуто","makeymakey.whenKeysPressedInOrder":"поки натиснуто по порядку [SEQUENCE]","microbit.buttonsMenu.any":"будь-який","microbit.clearDisplay":"очистити дисплей","microbit.defaultTextToDisplay":"Привіт!","microbit.displaySymbol":"показати [MATRIX]","microbit.displayText":"показати текст [TEXT]","microbit.gesturesMenu.jumped":"підкинуто","microbit.gesturesMenu.moved":"рухається","microbit.gesturesMenu.shaken":"струснуто","microbit.isButtonPressed":"кнопку [BTN] натиснуто?","microbit.isTilted":"нахил [DIRECTION]?","microbit.pinStateMenu.off":"Вимк","microbit.pinStateMenu.on":"Увімкн","microbit.tiltAngle":"кут нахилу [DIRECTION]","microbit.tiltDirectionMenu.any":"будь-який","microbit.tiltDirectionMenu.back":"назад","microbit.tiltDirectionMenu.front":"вперед","microbit.tiltDirectionMenu.left":"ліворуч","microbit.tiltDirectionMenu.right":"праворуч","microbit.whenButtonPressed":"коли кнопку [BTN] натиснуто","microbit.whenGesture":"коли [GESTURE]","microbit.whenPinConnected":"коли контакт [PIN] приєднано","microbit.whenTilted":"коли нахил [DIRECTION]","music.categoryName":"Музика","music.changeTempo":"змінити темп на [TEMPO]","music.drumBass":"(2) Великий басовий барабан","music.drumBongo":"(13) Бонго","music.drumCabasa":"(15) Кабаса","music.drumClaves":"(9) Клавесин","music.drumClosedHiHat":"(6) Закритий хет","music.drumConga":"(14) Конга","music.drumCowbell":"(11) Дзвіночок","music.drumCrashCymbal":"(4) Удар тарілок","music.drumCuica":"(18) Куїка","music.drumGuiro":"(16) Гуїро","music.drumHandClap":"(8) Плескіт долонь","music.drumOpenHiHat":"(5) Відкритий високий хет","music.drumSideStick":"(3) Удар по ободу","music.drumSnare":"(1) Малий барабан","music.drumTambourine":"(7) Тамбурин","music.drumTriangle":"(12) Трикутник","music.drumVibraslap":"(17) Вібруючий слеп","music.drumWoodBlock":"(10) Дерев’яна коробка","music.getTempo":"темп","music.instrumentBass":"(6) Бас","music.instrumentBassoon":"(14) Фагот","music.instrumentCello":"(8) Віолончель","music.instrumentChoir":"(15) Хор","music.instrumentClarinet":"(10) Кларнет","music.instrumentElectricGuitar":"(5) Електрогітара","music.instrumentElectricPiano":"(2) Електропіаніно","music.instrumentFlute":"(12) Флейта","music.instrumentGuitar":"(4) Гітара","music.instrumentMarimba":"(19) Марімба","music.instrumentMusicBox":"(17) Музична скринька","music.instrumentOrgan":"(3) Орган","music.instrumentPiano":"(1) Піаніно","music.instrumentPizzicato":"(7) Піцикато","music.instrumentSaxophone":"(11) Саксофон","music.instrumentSteelDrum":"(18) Стальний барабан","music.instrumentSynthLead":"(20) Ведучий синтезатор","music.instrumentSynthPad":"(21) Синтезатор Pad","music.instrumentTrombone":"(9) Тромбон","music.instrumentVibraphone":"(16) Вібрафон","music.instrumentWoodenFlute":"(13) Дерев’яна флейта","music.midiPlayDrumForBeats":"програти на барабані [DRUM] [BEATS] ударів","music.midiSetInstrument":"грати інструментом [INSTRUMENT]","music.playDrumForBeats":"програти на барабані [DRUM] [BEATS] ударів","music.playNoteForBeats":"програти ноту [NOTE] [BEATS] тактів","music.restForBeats":"пауза [BEATS] тактів","music.setInstrument":"грати інструментом [INSTRUMENT]","music.setTempo":"встановити темп в [TEMPO]","pen.categoryName":"Олівець","pen.changeColorParam":"змінити [COLOR_PARAM] олівця на [VALUE]","pen.changeHue":"змінити колір олівця на [HUE]","pen.changeShade":"змінити тінь олівця на [SHADE]","pen.changeSize":"змінити розмір олівця на [SIZE]","pen.clear":"очистити все","pen.colorMenu.brightness":"яскравість","pen.colorMenu.color":"колір","pen.colorMenu.saturation":"насиченість","pen.colorMenu.transparency":"прозорість","pen.penDown":"опустити олівець","pen.penUp":"підняти олівець","pen.setColor":"надати олівцю колір [COLOR]","pen.setColorParam":"надати [COLOR_PARAM] олівця значення [VALUE]","pen.setHue":"задати колір олівця [HUE]","pen.setShade":"задати тінь олівця [SHADE]","pen.setSize":"задати розмір олівця [SIZE]","pen.stamp":"штамп","text2speech.alto":"альт","text2speech.categoryName":"Текст-у-Мову","text2speech.defaultTextToSpeak":"привіт","text2speech.giant":"гігант","text2speech.kitten":"котик","text2speech.setLanguageBlock":"встановити мову [LANGUAGE]","text2speech.setVoiceBlock":"встановити голос як [VOICE]","text2speech.speakAndWaitBlock":"говорити [WORDS]","text2speech.squeak":"писк","text2speech.tenor":"тенор","translate.categoryName":"Перекласти","translate.defaultTextToTranslate":"привіт","translate.translateBlock":"перекласти [WORDS] на [LANGUAGE]","translate.viewerLanguage":"мова","videoSensing.categoryName":"Відеоспостереження","videoSensing.direction":"напрям","videoSensing.motion":"рух","videoSensing.off":"Вимк","videoSensing.on":"Увімкн","videoSensing.onFlipped":"перевернуто","videoSensing.setVideoTransparency":"встановити прозорість відео в [TRANSPARENCY]","videoSensing.sprite":"спрайт","videoSensing.stage":"сцена","videoSensing.videoOn":"відео [ATTRIBUTE] на [SUBJECT]","videoSensing.videoToggle":"перемкнути відео [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"коли рух відео > [REFERENCE]","wedo2.getDistance":"відстань","wedo2.getTiltAngle":"кут нахилу [TILT_DIRECTION]","wedo2.isTilted":"нахилено [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"за годинником","wedo2.motorDirection.forward":"проти годинника","wedo2.motorDirection.reverse":"обернути","wedo2.motorId.a":"двигун A","wedo2.motorId.all":"всі двигуни","wedo2.motorId.b":"двигун B","wedo2.motorId.default":"двигун","wedo2.motorOff":"[MOTOR_ID] вимкнути","wedo2.motorOn":"[MOTOR_ID] увімкнути","wedo2.motorOnFor":"увімкнути [MOTOR_ID] на [DURATION] секунд","wedo2.playNoteFor":"грати ноту [NOTE] [DURATION] секунд","wedo2.setLightHue":"встановити колір світла в [HUE]","wedo2.setMotorDirection":"встановити напрям [MOTOR_ID] [MOTOR_DIRECTION]","wedo2.startMotorPower":"встановити потужність [MOTOR_ID] [POWER]","wedo2.tiltDirection.any":"будь-який","wedo2.tiltDirection.down":"вниз","wedo2.tiltDirection.left":"ліворуч","wedo2.tiltDirection.right":"праворуч","wedo2.tiltDirection.up":"вгору","wedo2.whenDistance":"коли дистанція [OP] [REFERENCE]","wedo2.whenTilted":"коли нахил [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"Колір","paint.paintEditor.saturation":"Насиченість","paint.paintEditor.brightness":"Яскравість","paint.paintEditor.costume":"Образ","paint.paintEditor.group":"Групувати","paint.paintEditor.ungroup":"Розгрупувати","paint.paintEditor.undo":"Скасувати","paint.paintEditor.redo":"Повернути","paint.paintEditor.forward":"Вперед","paint.paintEditor.backward":"Назад","paint.paintEditor.front":"Попереду","paint.paintEditor.back":"Позаду","paint.paintEditor.more":"Більше","paint.modeTools.brushSize":"Розмір","paint.modeTools.eraserSize":"Розмір зтирачки","paint.modeTools.copy":"Копія","paint.modeTools.paste":"Вставити","paint.modeTools.delete":"Вилучити","paint.modeTools.curved":"Крива","paint.modeTools.pointed":"Кути","paint.modeTools.thickness":"Товщина","paint.modeTools.flipHorizontal":"Право-ліво","paint.modeTools.flipVertical":"Верх-низ","paint.modeTools.filled":"Заповнення","paint.modeTools.outlined":"Межа","paint.paintEditor.bitmap":"У растрове","paint.paintEditor.vector":"У векторне","paint.paintEditor.fill":"Заповнення","paint.paintEditor.stroke":"Межа","paint.brushMode.brush":"Пензель","paint.eraserMode.eraser":"Гумка","paint.fillMode.fill":"Заповнення","paint.lineMode.line":"Лінія","paint.ovalMode.oval":"Коло","paint.rectMode.rect":"Прямокутник","paint.reshapeMode.reshape":"Реформувати","paint.roundedRectMode.roundedRect":"Закруглений прямокутник","paint.selectMode.select":"Обрати","paint.textMode.text":"Текст","paint.colorPicker.swap":"Поміняти","tw.alerts.autosaving":"Створення точки відновлення...","tw.alerts.lostPeripheralConnection":"Втрачено зв\'язок з {extensionName}","tw.alerts.savedToDisk":"Збережено на ваш комп\'ютер.","tw.backpack.rename":"Нова назва:","tw.browserModal.desc":"Переконайтеся, що ви використовуєте останню версію Google Chrome, Mozilla Firefox, Microsoft Edge, або Apple Safari.","tw.cantUseCloud":"Хоча ви можете створювати хмарні змінні, вони не будуть працювати до тих пір, доки проект не буде завантажений на Scratch, або упакований за допомогою {packager}","tw.changeUsername.cannotChangeWhileRunning":"Неможливо змінити ім\'я користувача поки проект працює.","tw.cloudVariableBadge":"Цей проект використовує хмарні змінні. TurboWarp використовує свій сервер для хмарних змінних, не пов\'язаний зі Scratch. Зверніть увагу, що користувачі можуть бути не такими, як іх ім\'я. {learnMore}","tw.code":"Вихідний код","tw.confirmIncompatibleExtension":"Це розшрення несумісне зі Scratch. Проекти, створені за допомогою цього розширення, неможливо завантажити на Scratch. Ви дійсно хочете увімкнути це?","tw.customExtension.description":"Завантажити своє розширення за допомогою URL. Для розробників. Експерементальна функція.","tw.customExtension.name":"Користувальницьке розширення","tw.featuredProjectsStudio":"Переглянути студію на Scratch.","tw.feedback":"Зв\'язок з розробником та помилки","tw.feedbackButton":"Зворотній звязок","tw.footer.credits":"Подяки","tw.footer.disclaimer":"TurboWarp ніяк не пов\'язаний із Scratch, Командою Scratch або Фондом Scratch.","tw.footer.donate":"Пожертвувати","tw.footer.embed":"Вбудовування","tw.footer.fosshost":"Хостинг надається за Fosshost","tw.footer.parameters":"Параметри URL","tw.footer.translate":"Допомога перекласти TurboWarp","tw.fps":"{framerate}Кадрів у секунду","tw.gui.crashMessage.description":"Нам дуже шкода, але схоже що сторінка дала збій. Будь ласка, оновіть сторінку, щоб повторити спробу.","tw.gui.defaultProjectTitle":"Проєкт","tw.guiDefaultTitle":"Запускайте проекти Scratch швидше","tw.home.credit":"Замітки та Подяки","tw.home.description":"TurboWarp - це модифікація Scratch, що компілює проекти в JavaScript, щоб вони працювали швидше. Спробуйте ввести URL або ID проекту вище або виберіть з обраних проектів нище.","tw.home.instructions":"Інструкції","tw.input.tooltip":"Скопіюйте та вставте URL адресу Scratch проекту сюди!","tw.interpolationEnabled":"Інтерполяція","tw.invalidParameters.clones":"Параметр \\"clone\\" в URL некоректний","tw.invalidParameters.fps":"Параметр \\"fps\\" в URL некоректний","tw.loadError":"Не вийшло завантажити проект: {error}","tw.loader.assets.known":"Завантаження ресурсів ({complete}/{total}) ...","tw.loader.assets.unknown":"Завантаження ресурсів...","tw.loader.data":"Завантаження даних проєкту...","tw.loader.generic":"Завантаження проєкту...","tw.menuBar.60off":"Вимкнути режим 60 FPS","tw.menuBar.60on":"Увімкнути режим 60 FPS","tw.menuBar.addons":"Доповнення","tw.menuBar.advanced":"Додатково","tw.menuBar.changeUsername":"Змінити ім\'я користувача","tw.menuBar.cloudOff":"Вимкнути хмарні змінні","tw.menuBar.cloudOn":"Увімкнути хмарні змінні","tw.menuBar.cloudUnavailable":"Хмарні змінні недоступні","tw.menuBar.cloudUnavailableAlert":"Не вдається використати хмарні змінні, швидше за все, тому що ви відкрили редактор.","tw.menuBar.loadRestorePoint":"Завантажити точку відновлення","tw.menuBar.moreSettings":"Налаштування Доповнень","tw.menuBar.newFramerate":"Нова частота кадрів:","tw.menuBar.package":"Упакувати проект","tw.menuBar.reportError1":"Деякі скрипти не можуть бути скомпільовані.","tw.menuBar.reportError2":"Це помилка. Будь-ласка, повідомте нам про це.","tw.menuBar.saveAs":"Зберегти як {file}","tw.menuBar.seeInside":"Переглянути код","tw.mono":"Моно","tw.oldDownload":"Зберегти як окремий файл...","tw.openAdvanced":"Відкрити налаштування доповнень","tw.paint.alpha":"Непрозорість","tw.privacy":"Політика Конфіденсійності","tw.restorePoint.confirm":"Редактор автоматично записує одну точку відновлення, якщо щось піде не так, а ви забудете зберегти. Однак не варто покладатися на це, ми не можемо гарантувати, що це відновить ваш проект. Спробувати завантажити?","tw.restorePoint.loadFail":"Не вийшло завантажити точку відновлення: {error}","tw.saveAs":"Зберегти як...","tw.saveTo":"Зберегти як {file}","tw.scratchUnsafeCloud":"Якщо ви створите цю хмарну змінну, проект перевищить ліміт Scratch в {number} змінних, тому деякі змінні не працюватимуть, якщо завантажии проект на Scratch.","tw.settingsModal.customStageSize":"Користувальницький розмір сцени:","tw.settingsModal.customStageSizeHelp":"Змінює розмір сцени з 480x360 на щось інше. Спробуйте використати 640x360, щоб зробити сцену широкоекранною. Тільки деякі проекти будуть працювати правильно з цим налаштуванням.","tw.settingsModal.dangerZone":"Небезпечна зона","tw.settingsModal.disableCompiler":"Вимкнути компілятор","tw.settingsModal.disableCompilerHelp":"Вимикає компілятор TurboWarp. Рекомендуємо вмикати це налаштування коли ви редактуєте проект, щоб скрипти оновлювалися моментально. В інших випадках не вмикайте це.","tw.settingsModal.featured":"Обране","tw.settingsModal.fps":"60 FPS (Користувальницькі FPS)","tw.settingsModal.fpsHelp":"Виконує скрипти 60 раз в секунду замість 30. Більшість проектів не будуть працювати належним чином, коли цей параметр увімкнено. Якщо це так, спробуйте інтерполяцію з вимкненим режимом 60 FPS.{customFramerate}.","tw.settingsModal.fpsHelp.customFramerate":"Натисніть, щоб використати іншу частоту кадрів, ніж 30 або 60","tw.settingsModal.help":"Натисніть, щоб побачити подробиці","tw.settingsModal.highQualityPen":"Перо високої якості","tw.settingsModal.highQualityPenHelp":"Дозволяє виконувати візуалізацію пера з більш високою якістю, також вимикає деякі округлення координат в редакторі. Цей параметр корисний не для всіх проектів, і може вплинути на продуктивність.","tw.settingsModal.infiniteClones":"Безмежна кількість клонів","tw.settingsModal.infiniteClonesHelp":"Вимикає ліміт Scratch на 300 клонів.","tw.settingsModal.interpolation":"Інтерполяція","tw.settingsModal.interpolationHelp":"Інтерполює рухи спрайтів, роблячи проект більш плавним. Не використовуйте інтерполяцію в 3D проектах, проектах з трассуванням променів, проектах на основі пера та повільних проектах, оскільки інтерполяція не зробить їх більш плавними, і навіть негативно вплине на їх швидкість.","tw.settingsModal.largeStageWarning":"Використовувати настільки великий розмір сцени не рекомендується! Краще використовуйте сцену меншого розміру, але з таким самим співвідношенням сторін і дайте повноекранному режиму збільшити сцену так, щоб вона могла підійти по розміру до дисплею користувача.","tw.settingsModal.removeFencing":"Прибрати рамку","tw.settingsModal.removeFencingHelp":"Дозволяє спрайтам виходити за межі сцени, ставати настільки великими або маленькими, наскільки вони захочуть, та робить так, щоб блоки доторкань працювали за межами сцени.","tw.settingsModal.removeLimits":"Прибрати обмеження","tw.settingsModal.removeMiscLimits":"Прибрати різні обмеження","tw.settingsModal.removeMiscLimitsHelp":"Прибирає обмеження звукових еффектів та розміру пера.","tw.settingsModal.storeProjectOptions":"Зберегти налаштування у проєкті","tw.settingsModal.storeProjectOptionsHelp":"Зберігає вибрані налаштування в проекті щоб вони автоматично застосовувалися, коли проект відкривається TurboWarp\'ом. Warp Таймер і відключення компілятора не буде збережено. ","tw.settingsModal.title":"Розширені Налаштування","tw.settingsModal.warpTimer":"Warp Таймер","tw.settingsModal.warpTimerHelp":"Перевіряє, які скрипти застрягли в довгому, або безкінечному циклі та знижує часоту кадрів, замість того щоб він застиг, доки цикл не завершиться. Це виправляє велику частину критичних помилок, але це негативно впливає на швидкість проекту, тому за умовчанням цей параметр увімкнений тільки в редакторі.","tw.spriteSelectorItem.rename":"перейменувати","tw.stereo":"Стерео","tw.stereoAlert":"Редактування цого стерео звуку приведе до його конвертування в моно.","tw.studioview.authorAttribution":"від {author}","tw.studioview.error":"При завантаженні наступної сторінки проектів сталася помилка.","tw.studioview.hoverText":"{title} від {author}","tw.tooLarge":"Цей звук занадто великий для експорту в Scratch.","tw.twExtension.description":"Дивні нові блоки. Не сумісні зі Scratch.","tw.twExtension.name":"Блоки TurboWarp ","tw.unshared.1":"В деякий момент, в майбутньому проекти без відкритого доступу більше не будуть доступні через їх ID, в зв\'язку з майбутніми змінами Scratch API.","tw.unshared.2":"Перейдіть на {link}, щоб отримати більше інформації","tw.usernameModal.help":"Це значення буде зберігатися в пам\'яті вашого браузера. Воно буде використовуватися, коли ви взаємодієте з проектами, що містять хмарні змінні.","tw.usernameModal.help2":"Значення, які не відповідають дійсному обліковому запису Scratch, зазвичай відхиляються сервером хмарних змінних. Ми рекомендуємо залишити його як є або змінити його на своє ім\'я користувача в Scratch.","tw.usernameModal.mustChange":"Вибачте, сервер хмарних змінних вважає, що ваше ім\'я користувача неприйнятне, Будь-ласка змініть ім\'я користувача на щось інше або на {resetIt}","tw.usernameModal.mustChange.resetIt":"скинути його (рекомендовано)","tw.usernameModal.reset":"Скинути","tw.usernameModal.title":"Змінити ім\'я користувача","tw.viewFeaturedProjects":"Натисніть щоб переглянути обрані проекти.","tw.viewOnScratch":"Проглянути проєкт на Scratch","tw.webglModal.description":"На жаль, ваш браузер або ком\'пютер {webGlLink}. Ця технологія необхідна для роботи цього сайту. Спробуйте обновити браузер і драйвера або перезавантажте комп\'ютер."},"zh-cn":{"gui.alerts.tryAgain":"重试","gui.alerts.download":"下载","gui.connection.reconnect":"重新连接","gui.backpack.costumeLabel":"造型","gui.backpack.soundLabel":"声音","gui.backpack.scriptLabel":"脚本","gui.backpack.spriteLabel":"角色","gui.backpack.header":"书包","gui.backpack.errorBackpack":"载入书包时出错了","gui.backpack.loadingBackpack":"载入中……","gui.backpack.more":"更多","gui.backpack.emptyBackpack":"书包是空的","gui.unsupportedBrowser.label":"不支持当前浏览器","gui.cards.all-tutorials":"教程","gui.cards.shrink":"收起","gui.cards.expand":"展开","gui.cards.close":"关闭","gui.cards.more-things-to-try":"再试试这些!","gui.cards.see-more":"更多技巧","gui.comingSoon.message1":"别急,我们还在做这个 {emoji}","gui.comingSoon.message2":"即将启用...","gui.comingSoon.message3":"还在开发 {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"没有发现任何设备","gui.connection.auto-scanning.prescan":"把设备放在边上,然后开始搜索","gui.connection.auto-scanning.pressbutton":"按下设备上的按钮","gui.connection.auto-scanning.start-search":"开始搜索","gui.connection.connecting-searchbutton":"正在搜索……","gui.connection.auto-scanning.try-again":"重试","gui.connection.connected":"已连接","gui.connection.disconnect":"断开连接","gui.connection.go-to-editor":"返回编辑器","gui.connection.connecting-cancelbutton":"正在连接……","gui.connection.error.errorMessage":"呀,好像出错了。","gui.connection.error.tryagainbutton":"重试","gui.connection.error.helpbutton":"帮助","gui.connection.peripheral-name-label":"设备名称","gui.connection.connect":"连接","gui.connection.scanning.lookingforperipherals":"正在查找设备","gui.connection.scanning.noPeripheralsFound":"没有发现任何设备","gui.connection.scanning.instructions":"选择上面列出的设备。","gui.connection.search":"刷新","gui.connection.unavailable.installscratchlink":"确保Scratch Link已安装并正在运行","gui.connection.unavailable.enablebluetooth":"请检查蓝牙已经开启","gui.connection.unavailable.tryagainbutton":"重试","gui.connection.unavailable.helpbutton":"帮助","gui.controls.go":"运行","gui.controls.stop":"停止","gui.crashMessage.label":"呀,出错了。","gui.crashMessage.errorNumber":"该错误已记录,编号{errorId}","gui.crashMessage.reload":"重新载入","gui.customProcedures.myblockModalTitle":"制作新的积木","gui.customProcedures.addAnInputNumberText":"添加输入项","gui.customProcedures.numberTextType":"数字或文本","gui.customProcedures.addAnInputBoolean":"添加输入项","gui.customProcedures.booleanType":"布尔值","gui.customProcedures.addALabel":"添加文本标签:","gui.customProcedures.runWithoutScreenRefresh":"运行时不刷新屏幕","gui.customProcedures.cancel":"取消","gui.customProcedures.ok":"完成","gui.SpriteInfo.direction":"方向","gui.directionPicker.rotationStyles.allAround":"任意旋转","gui.directionPicker.rotationStyles.leftRight":"左右翻转","gui.directionPicker.rotationStyles.dontRotate":"不旋转","gui.gui.addExtension":"添加扩展","gui.gui.codeTab":"代码","gui.gui.backdropsTab":"背景","gui.gui.costumesTab":"造型","gui.gui.soundsTab":"声音","gui.extensionLibrary.comingSoon":"即将启用","gui.extensionLibrary.requires":"系统需求","gui.extensionLibrary.collaboration":"合作者","gui.library.filterPlaceholder":"搜索","gui.library.allTag":"所有","gui.loader.headline":"载入作品","gui.loader.creating":"新建作品","gui.authorInfo.byUser":"作者{username}","gui.menuBar.seeProjectPage":"查看作品页面","gui.menuBar.LanguageSelector":"语言菜单","gui.menuBar.tutorialsLibrary":"教程","gui.menuBar.restoreSprite":"复原删除的角色","gui.menuBar.restoreSound":"复原删除的声音","gui.menuBar.restoreCostume":"复原删除的造型","gui.menuBar.restore":"恢复","gui.menuBar.saveNow":"立即保存","gui.menuBar.saveAsCopy":"保存副本","gui.menuBar.remix":"改编","gui.menuBar.new":"新作品","gui.menuBar.file":"文件","gui.menuBar.downloadToComputer":"保存到电脑","gui.menuBar.edit":"编辑","gui.menuBar.turboModeOff":"关闭加速模式","gui.menuBar.turboModeOn":"打开加速模式","gui.gui.projectTitlePlaceholder":"在此填写作品标题","gui.menuBar.isShared":"已分享","gui.menuBar.share":"分享","gui.modal.help":"帮助","gui.modal.back":"返回","gui.monitor.listMonitor.empty":"(空)","gui.monitor.listMonitor.listLength":"长度{length}","gui.monitor.contextMenu.default":"正常显示","gui.monitor.contextMenu.large":"大字显示","gui.monitor.contextMenu.slider":"滑杆","gui.monitor.contextMenu.sliderRange":"改变滑块范围","gui.monitor.contextMenu.import":"导入","gui.monitor.contextMenu.export":"导出","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"播放","gui.playButton.stop":"停止","gui.gui.variableScopeOptionAllSprites":"适用于所有角色","gui.gui.variableScopeOptionSpriteOnly":"仅适用于当前角色","gui.gui.cloudVariableOption":"云变量 (存储在服务器上)","gui.gui.variablePromptAllSpritesMessage":"所有角色都可使用该变量。","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"取消","gui.prompt.ok":"确定","gui.playbackStep.stopMsg":"停止","gui.playbackStep.playMsg":"播放","gui.playbackStep.loadingMsg":"载入中……","gui.playbackStep.saveMsg":"保存","gui.playbackStep.reRecordMsg":"重新录制","gui.recordModal.title":"录制声音","gui.recordingStep.beginRecord":"点击下方的按钮开始录制","gui.recordingStep.permission":"{arrow}我们需要你的许可才能使用麦克风。","gui.recordingStep.stop":"停止录制","gui.recordingStep.record":"录制","gui.sliderModal.min":"最小值","gui.sliderModal.max":"最大值","gui.sliderModal.title":"改变滑块范围","gui.sliderPrompt.cancel":"取消","gui.sliderPrompt.ok":"确定","gui.soundEditor.sound":"声音","gui.soundEditor.play":"播放","gui.soundEditor.stop":"停止","gui.soundEditor.copy":"复制","gui.soundEditor.paste":"粘贴","gui.soundEditor.copyToNew":"新拷贝","gui.soundEditor.delete":"删除","gui.soundEditor.save":"保存","gui.soundEditor.undo":"撤销","gui.soundEditor.redo":"重做","gui.soundEditor.faster":"快一点","gui.soundEditor.slower":"慢一点","gui.soundEditor.echo":"回声","gui.soundEditor.robot":"机械化","gui.soundEditor.louder":"响一点","gui.soundEditor.softer":"轻一点","gui.soundEditor.reverse":"反转","gui.soundEditor.fadeOut":"渐弱","gui.soundEditor.fadeIn":"渐强","gui.soundEditor.mute":"静音","gui.SpriteInfo.spritePlaceholder":"名字","gui.SpriteInfo.sprite":"角色","gui.SpriteInfo.show":"显示","gui.SpriteInfo.size":"大小","gui.spriteSelectorItem.contextMenuDuplicate":"复制","gui.spriteSelectorItem.contextMenuExport":"导出","gui.spriteSelectorItem.contextMenuDelete":"删除","gui.spriteSelector.addSpriteFromLibrary":"选择一个角色","gui.spriteSelector.addSpriteFromPaint":"绘制","gui.spriteSelector.addSpriteFromSurprise":"随机","gui.spriteSelector.addSpriteFromFile":"上传角色","gui.stageHeader.stageSizeLarge":"放大舞台","gui.stageHeader.stageSizeSmall":"缩小舞台","gui.stageHeader.stageSizeFull":"进入全屏模式","gui.stageHeader.stageSizeUnFull":"退出全屏模式","gui.stageHeader.fullscreenControl":"全屏模式","gui.spriteSelector.addBackdropFromLibrary":"选择一个背景","gui.stageSelector.addBackdropFromPaint":"绘制","gui.stageSelector.addBackdropFromSurprise":"随机","gui.stageSelector.addBackdropFromFile":"上传背景","gui.stageSelector.stage":"舞台","gui.stageSelector.backdrops":"背景","gui.telemetryOptIn.label":"统计使用情况并发送给Scratch","gui.telemetryOptIn.body1":"允许Scratch自动发送使用情况信息给Scratch团队,帮助我们了解Scratch在全世界的使用情况。","gui.telemetryOptIn.body2":"我们收集的信息包括所选语言、积木使用情况以及诸如保存、加载和上传作品等功能的使用情况。我们不会收集任何个人信息。请查看我们的{privacyPolicyLink}了解更多信息。","gui.telemetryOptIn.privacyPolicyLink":"隐私政策","gui.telemetryOptIn.optInText":"与Scratch团队分享我的使用数据","gui.telemetryOptIn.optInTooltip":"发送统计信息","gui.telemetryOptIn.optOutText":"不要把我的使用数据分享给Scratch团队","gui.telemetryOptIn.optOutTooltip":"不发送统计信息","gui.telemetryOptIn.settingWasUpdated":"你的设置已更新","gui.telemetryOptIn.buttonClose":"关闭","gui.turboMode.active":"加速模式","gui.webglModal.label":"你的浏览器不支持WebGL","gui.webglModal.webgllink":"不支持WebGL","gui.costumeLibrary.chooseABackdrop":"选择一个背景","gui.costumeLibrary.chooseACostume":"选择一个造型","gui.costumeTab.addBackdropFromLibrary":"选择一个背景","gui.costumeTab.addCostumeFromLibrary":"选择一个造型","gui.costumeTab.addBlankCostume":"绘制","gui.costumeTab.addSurpriseCostume":"随机","gui.costumeTab.addFileBackdrop":"上传背景","gui.costumeTab.addFileCostume":"上传造型","gui.extensionLibrary.chooseAnExtension":"选择一个扩展","gui.extensionLibrary.extensionUrl":"键入扩展的URL","gui.monitors.importListColumnPrompt":"使用第几列(1-{numberOfColumns})?","gui.recordingStep.alertMsg":"无法启动录音","gui.soundLibrary.chooseASound":"选择一个声音","gui.soundTab.fileUploadSound":"上传声音","gui.soundTab.surpriseSound":"随机","gui.soundTab.recordSound":"录制","gui.soundTab.addSoundFromLibrary":"选择一个声音","gui.spriteLibrary.chooseASprite":"选择一个角色","gui.tipsLibrary.tutorials":"选择一个教程","gui.alerts.createsuccess":"作品已创建。","gui.alerts.createcopysuccess":"作品已保存为副本。","gui.alerts.createremixsuccess":"改编作品已保存。","gui.alerts.creating":"正在创建...","gui.alerts.creatingCopy":"正在复制作品……","gui.alerts.creatingRemix":"正在改编作品……","gui.alerts.creatingError":"无法创建作品。 请再试一次!","gui.alerts.savingError":"作品未能保存。","gui.alerts.savesuccess":"作品已保存。","gui.alerts.saving":"正在保存作品……","gui.alerts.cloudInfo":"请注意,云变量只支持数字,不能存放字母和符号。{learnMoreLink}","gui.alerts.cloudInfoLearnMore":"进一步了解。","gui.alerts.importing":"正在导入……","gui.defaultProject.variable":"我的变量","gui.extension.music.name":"音乐","gui.extension.music.description":"演奏乐器,敲锣打鼓。","gui.extension.pen.name":"画笔","gui.extension.pen.description":"绘制角色。","gui.extension.videosensing.name":"视频侦测","gui.extension.videosensing.description":"使用摄像头侦测运动。","gui.extension.text2speech.name":"文字朗读","gui.extension.text2speech.description":"让你的作品开口说话","gui.extension.translate.name":"翻译","gui.extension.translate.description":"把文字翻译成多种语言。","gui.extension.makeymakey.description":"把任何东西变成按键","gui.extension.microbit.description":"把作品连接到实体世界。","gui.extension.microbit.connectingMessage":"正在连接","gui.extension.ev3.description":"搭建交互机器人等。","gui.extension.ev3.connectingMessage":"正在连接。请确保EV3上的识别码(PIN)已经设置为1234。","gui.extension.boost.description":"生动有趣的机器人创作","gui.extension.boost.connectingMessage":"正在连接","gui.extension.wedo2.description":"支持马达和传感器。","gui.extension.wedo2.connectingMessage":"正在连接","gui.extension.gdxfor.description":"感受推拉动转。","gui.extension.gdxfor.connectingMessage":"正在连接","gui.libraryTags.all":"所有","gui.libraryTags.animals":"动物","gui.libraryTags.dance":"舞蹈","gui.libraryTags.effects":"效果","gui.libraryTags.fantasy":"奇幻","gui.libraryTags.fashion":"时尚","gui.libraryTags.food":"食物","gui.libraryTags.indoors":"室内","gui.libraryTags.loops":"可循环","gui.libraryTags.music":"音乐","gui.libraryTags.notes":"音符","gui.libraryTags.outdoors":"户外","gui.libraryTags.patterns":"图案","gui.libraryTags.people":"人物","gui.libraryTags.percussion":"打击乐器","gui.libraryTags.space":"太空","gui.libraryTags.sports":"运动","gui.libraryTags.underwater":"水下","gui.libraryTags.voice":"人声","gui.libraryTags.wacky":"古怪","gui.libraryTags.animation":"动画","gui.libraryTags.art":"艺术","gui.libraryTags.games":"游戏","gui.libraryTags.stories":"故事","gui.libraryTags.letters":"字母","gui.opcodeLabels.direction":"方向","gui.opcodeLabels.xposition":"x 坐标","gui.opcodeLabels.yposition":"y 坐标","gui.opcodeLabels.size":"大小","gui.opcodeLabels.costumename":"造型名称","gui.opcodeLabels.costumenumber":"造型编号","gui.opcodeLabels.backdropname":"背景名称","gui.opcodeLabels.backdropnumber":"背景编号","gui.opcodeLabels.volume":"音量","gui.opcodeLabels.tempo":"演奏速度","gui.opcodeLabels.answer":"回答","gui.opcodeLabels.loudness":"响度","gui.opcodeLabels.username":"用户名","gui.opcodeLabels.year":"年","gui.opcodeLabels.month":"月","gui.opcodeLabels.date":"日","gui.opcodeLabels.dayofweek":"星期","gui.opcodeLabels.hour":"时","gui.opcodeLabels.minute":"分","gui.opcodeLabels.second":"秒","gui.opcodeLabels.timer":"计时器","gui.sharedMessages.backdrop":"背景{index}","gui.sharedMessages.costume":"造型{index}","gui.sharedMessages.sprite":"角色{index}","gui.sharedMessages.pop":"啵","gui.sharedMessages.replaceProjectWarning":"是否丢弃当前作品中尚未保存的内容?","gui.sharedMessages.loadFromComputerTitle":"从电脑中打开","boost.color.any":"任何颜色","boost.color.black":"黑色","boost.color.blue":"蓝色","boost.color.green":"绿色","boost.color.red":"黄色","boost.color.white":"白色","boost.color.yellow":"黄色","boost.getMotorPosition":"马达 [MOTOR_REPORTER_ID] 位置","boost.getTiltAngle":"向[TILT_DIRECTION]倾角","boost.motorDirection.backward":"逆时针","boost.motorDirection.forward":"顺时针","boost.motorDirection.reverse":"反转","boost.motorOff":"关闭马达 [MOTOR_ID]","boost.motorOn":"开启马达 [MOTOR_ID]","boost.motorOnFor":"使马达 [MOTOR_ID]转动 [DURATION] 秒","boost.motorOnForRotation":"使马达 [MOTOR_ID]转动 [ROTATION] 圈","boost.seeingColor":"看到 [COLOR]积木 ?","boost.setLightHue":"将灯光颜色设为[HUE]","boost.setMotorDirection":"将马达[MOTOR_ID] 方向设为 [MOTOR_DIRECTION]","boost.setMotorPower":"将马达 [MOTOR_ID] 速度设为 [POWER]%","boost.tiltDirection.any":"任意方向","boost.tiltDirection.down":"下","boost.tiltDirection.left":"左","boost.tiltDirection.right":"右","boost.tiltDirection.up":"上","boost.whenColor":"当看到[COLOR]积木","boost.whenTilted":"当向[TILT_DIRECTION_ANY]倾斜","ev3.beepNote":"鸣笛[NOTE][TIME]秒","ev3.buttonPressed":"按下按钮[PORT]?","ev3.getBrightness":"亮度","ev3.getDistance":"距离","ev3.getMotorPosition":"马达[PORT]的位置","ev3.motorSetPower":"马达[PORT]功率设为[POWER]%","ev3.motorTurnClockwise":"马达[PORT]正转[TIME]秒","ev3.motorTurnCounterClockwise":"马达[PORT]反转[TIME]秒","ev3.whenBrightnessLessThan":"当亮度 < [DISTANCE]","ev3.whenButtonPressed":"当按下按钮[PORT]","ev3.whenDistanceLessThan":"当距离 < [DISTANCE]","gdxfor.getAcceleration":"向[DIRECTION]的加速度","gdxfor.getForce":"受力","gdxfor.getSpin":"向[DIRECTION]的旋转速度","gdxfor.getTilt":"向[TILT]倾角","gdxfor.isFreeFalling":"自由落体?","gdxfor.isTilted":"向[TILT]倾斜?","gdxfor.pulled":"拉扯","gdxfor.pushed":"挤压","gdxfor.shaken":"被晃动","gdxfor.startedFalling":"开始自由落体","gdxfor.tiltDirectionMenu.any":"任意方向","gdxfor.tiltDirectionMenu.back":"后","gdxfor.tiltDirectionMenu.front":"前","gdxfor.tiltDirectionMenu.left":"左","gdxfor.tiltDirectionMenu.right":"右","gdxfor.turnedFaceDown":"正面向下","gdxfor.turnedFaceUp":"正面向上","gdxfor.whenForcePushedOrPulled":"当力传感器被[PUSH_PULL]","gdxfor.whenGesture":"当传感器[GESTURE]","gdxfor.whenTilted":"当向[TILT]倾斜","makeymakey.downArrow":"↓","makeymakey.downArrowShort":"下","makeymakey.leftArrow":"←","makeymakey.leftArrowShort":"左","makeymakey.rightArrow":"→","makeymakey.rightArrowShort":"右","makeymakey.spaceKey":"空格","makeymakey.upArrow":"↑","makeymakey.upArrowShort":"上","makeymakey.whenKeyPressed":"当按下 [KEY] 键","makeymakey.whenKeysPressedInOrder":"当依次按下[SEQUENCE]键时","microbit.buttonsMenu.any":"任意","microbit.clearDisplay":"清空屏幕","microbit.defaultTextToDisplay":"Hello!","microbit.displaySymbol":"显示[MATRIX]","microbit.displayText":"显示文本[TEXT]","microbit.gesturesMenu.jumped":"抛起","microbit.gesturesMenu.moved":"移动","microbit.gesturesMenu.shaken":"晃动","microbit.isButtonPressed":"按下[BTN]按钮?","microbit.isTilted":"向[DIRECTION]倾斜?","microbit.pinStateMenu.off":"低电平","microbit.pinStateMenu.on":"高电平","microbit.tiltAngle":"向[DIRECTION]倾角","microbit.tiltDirectionMenu.any":"任意","microbit.tiltDirectionMenu.back":"后","microbit.tiltDirectionMenu.front":"前","microbit.tiltDirectionMenu.left":"左","microbit.tiltDirectionMenu.right":"右","microbit.whenButtonPressed":"当按下[BTN]按钮","microbit.whenGesture":"当被[GESTURE]","microbit.whenPinConnected":"当引脚[PIN]接地","microbit.whenTilted":"当向[DIRECTION]倾斜","music.categoryName":"音乐","music.changeTempo":"将演奏速度增加[TEMPO]","music.drumBass":"(2) 低音鼓","music.drumBongo":"(13) 邦戈鼓","music.drumCabasa":"(15) 卡巴萨","music.drumClaves":"(9) 音棒","music.drumClosedHiHat":"(6) 闭击踩镲","music.drumConga":"(14) 康加鼓","music.drumCowbell":"(11) 牛铃","music.drumCrashCymbal":"(4) 碎音钹","music.drumCuica":"(18) 锯加鼓","music.drumGuiro":"(16) 刮瓜","music.drumHandClap":"(8) 手掌","music.drumOpenHiHat":"(5) 开击踩镲","music.drumSideStick":"(3) 敲鼓边","music.drumSnare":"(1) 小军鼓","music.drumTambourine":"(7) 铃鼓","music.drumTriangle":"(12) 三角铁","music.drumVibraslap":"(17) 颤音器","music.drumWoodBlock":"(10) 木鱼","music.getTempo":"演奏速度","music.instrumentBass":"(6) 贝斯","music.instrumentBassoon":"(14) 巴松管","music.instrumentCello":"(8) 大提琴","music.instrumentChoir":"(15) 唱诗班","music.instrumentClarinet":"(10) 单簧管","music.instrumentElectricGuitar":"(5) 电吉他","music.instrumentElectricPiano":"(2) 电钢琴","music.instrumentFlute":"(12) 长笛","music.instrumentGuitar":"(4) 吉他","music.instrumentMarimba":"(19) 马林巴琴","music.instrumentMusicBox":"(17) 八音盒","music.instrumentOrgan":"(3) 风琴","music.instrumentPiano":"(1) 钢琴","music.instrumentPizzicato":"(7) 拨弦","music.instrumentSaxophone":"(11) 萨克斯管","music.instrumentSteelDrum":"(18) 钢鼓","music.instrumentSynthLead":"(20) 合成主音","music.instrumentSynthPad":"(21) 合成柔音","music.instrumentTrombone":"(9) 长号","music.instrumentVibraphone":"(16) 颤音琴","music.instrumentWoodenFlute":"(13) 木长笛","music.midiPlayDrumForBeats":"击打 [DRUM] [BEATS] 拍","music.midiSetInstrument":"将乐器设为 [INSTRUMENT]","music.playDrumForBeats":"击打 [DRUM] [BEATS] 拍","music.playNoteForBeats":"演奏音符[NOTE][BEATS]拍","music.restForBeats":"休止[BEATS]拍","music.setInstrument":"将乐器设为 [INSTRUMENT]","music.setTempo":"将演奏速度设定为[TEMPO]","pen.categoryName":"画笔","pen.changeColorParam":"将笔的 [COLOR_PARAM] 增加[VALUE]","pen.changeHue":"将笔的颜色增加[HUE]","pen.changeShade":"将笔的亮度增加[SHADE]","pen.changeSize":"将笔的粗细增加[SIZE]","pen.clear":"全部擦除","pen.colorMenu.brightness":"亮度","pen.colorMenu.color":"颜色","pen.colorMenu.saturation":"饱和度","pen.colorMenu.transparency":"透明度","pen.penDown":"落笔","pen.penUp":"抬笔","pen.setColor":"将笔的颜色设为[COLOR]","pen.setColorParam":"将笔的 [COLOR_PARAM] 设为[VALUE]","pen.setHue":"将笔的颜色设为[HUE]","pen.setShade":"将笔的亮度设为[SHADE]","pen.setSize":"将笔的粗细设为[SIZE]","pen.stamp":"图章","text2speech.alto":"中音","text2speech.categoryName":"文字朗读","text2speech.defaultTextToSpeak":"你好","text2speech.giant":"巨人","text2speech.kitten":"小猫","text2speech.setLanguageBlock":"将朗读语言设置为[LANGUAGE]","text2speech.setVoiceBlock":"使用 [VOICE] 嗓音","text2speech.speakAndWaitBlock":"朗读 [WORDS]","text2speech.squeak":"尖细","text2speech.tenor":"男高音","translate.categoryName":"翻译","translate.defaultTextToTranslate":"你好","translate.translateBlock":"将 [WORDS] 译为 [LANGUAGE]","translate.viewerLanguage":"访客语言","videoSensing.categoryName":"视频侦测","videoSensing.direction":"方向","videoSensing.motion":"运动","videoSensing.off":"关闭","videoSensing.on":"开启","videoSensing.onFlipped":"镜像开启","videoSensing.setVideoTransparency":"将视频透明度设为[TRANSPARENCY]","videoSensing.sprite":"角色","videoSensing.stage":"舞台","videoSensing.videoOn":"相对于[SUBJECT]的视频[ATTRIBUTE]","videoSensing.videoToggle":"[VIDEO_STATE]摄像头","videoSensing.whenMotionGreaterThan":"当视频运动 > [REFERENCE]","wedo2.getDistance":"距离","wedo2.getTiltAngle":"向[TILT_DIRECTION]倾角","wedo2.isTilted":"向[TILT_DIRECTION_ANY]倾斜?","wedo2.motorDirection.backward":"逆时针","wedo2.motorDirection.forward":"顺时针","wedo2.motorDirection.reverse":"反转","wedo2.motorId.a":"马达A","wedo2.motorId.all":"所有马达","wedo2.motorId.b":"马达B","wedo2.motorId.default":"马达","wedo2.motorOff":"关闭[MOTOR_ID]","wedo2.motorOn":"开启[MOTOR_ID]","wedo2.motorOnFor":"开启[MOTOR_ID][DURATION]秒","wedo2.playNoteFor":"演奏音符[NOTE][DURATION]秒","wedo2.setLightHue":"将灯光颜色设为[HUE]","wedo2.setMotorDirection":"将[MOTOR_ID]转向设为[MOTOR_DIRECTION]","wedo2.startMotorPower":"将[MOTOR_ID]功率设为[POWER]","wedo2.tiltDirection.any":"任意方向","wedo2.tiltDirection.down":"下","wedo2.tiltDirection.left":"左","wedo2.tiltDirection.right":"右","wedo2.tiltDirection.up":"上","wedo2.whenDistance":"当距离[OP][REFERENCE]","wedo2.whenTilted":"当向[TILT_DIRECTION_ANY]倾斜","paint.paintEditor.hue":"颜色","paint.paintEditor.saturation":"饱和度","paint.paintEditor.brightness":"亮度","paint.paintEditor.costume":"造型","paint.paintEditor.group":"组合","paint.paintEditor.ungroup":"拆散","paint.paintEditor.undo":"撤销","paint.paintEditor.redo":"重做","paint.paintEditor.forward":"往前放","paint.paintEditor.backward":"往后放","paint.paintEditor.front":"放最前面","paint.paintEditor.back":"放最后面","paint.paintEditor.more":"更多","paint.modeTools.brushSize":"粗细","paint.modeTools.eraserSize":"橡皮擦大小","paint.modeTools.copy":"复制","paint.modeTools.paste":"粘贴","paint.modeTools.delete":"删除","paint.modeTools.curved":"曲线","paint.modeTools.pointed":"折线","paint.modeTools.thickness":"粗细","paint.modeTools.flipHorizontal":"水平翻转","paint.modeTools.flipVertical":"垂直翻转","paint.modeTools.filled":"实心","paint.modeTools.outlined":"轮廓","paint.paintEditor.bitmap":"转换为位图","paint.paintEditor.vector":"转换为矢量图","paint.paintEditor.fill":"填充","paint.paintEditor.stroke":"轮廓","paint.brushMode.brush":"画笔","paint.eraserMode.eraser":"橡皮擦","paint.fillMode.fill":"填充","paint.lineMode.line":"线段","paint.ovalMode.oval":"圆","paint.rectMode.rect":"矩形","paint.reshapeMode.reshape":"变形","paint.roundedRectMode.roundedRect":"圆角矩形","paint.selectMode.select":"选择","paint.textMode.text":"文本","paint.colorPicker.swap":"交换","tw.alerts.autosaving":"新建还原点中...","tw.alerts.lostPeripheralConnection":"与 {extensionName} 的连接中断了。","tw.alerts.savedToDisk":"已保存至您的计算机。","tw.backpack.rename":"新名称:","tw.browserModal.desc":"确保你使用的是最新版本的 Google Chrome、Mozilla Firefox、Microsoft Edge 或 Apple Safari。","tw.cantUseCloud":"你创建的云变量仅在被上传到有云变量功能的网站或使用 {packager} 等工具转换时生效。","tw.changeUsername.cannotChangeWhileRunning":"作品运行时无法更改用户名。","tw.cloudVariableBadge":"此作品使用云变量。TurboWarp 使用独立于 Scratch 的云变量服务器。但请谨防用户冒充!因为所有人都可以任意更改他们的用户名。{learnMore}","tw.code":"源代码","tw.confirmIncompatibleExtension":"此扩展与 Scratch 不兼容。 用它制作的作品不能上传到 Scratch 网站。 您确定要启用它吗?","tw.customExtension.description":"通过网页链接加载自定义扩展,供开发者使用,实验性功能。","tw.customExtension.name":"自定义扩展","tw.featuredProjectsStudio":"在 Scratch 上查看工作室","tw.feedback":"反馈与漏洞提交","tw.feedbackButton":"TurboWarp 反馈","tw.footer.credits":"鸣谢","tw.footer.disclaimer":"TurboWarp 不属于 Scratch、Scratch 团队或 Scratch 基金会。","tw.footer.donate":"捐赠","tw.footer.embed":"将作品嵌入到网站","tw.footer.fosshost":"托管服务由 Fosshost 提供","tw.footer.parameters":"网址参数","tw.footer.translate":"帮助翻译 TurboWarp","tw.fps":"{framerate} 帧","tw.gui.crashMessage.description":"我们很抱歉,但页面似乎已崩溃。请刷新页面以重试。","tw.gui.defaultProjectTitle":"作品","tw.guiDefaultTitle":"加速运行 Scratch 作品","tw.home.credit":"备注与鸣谢","tw.home.description":"TurboWarp 是一款 Scratch 的修改版,它可以将作品编译成 JavaScript,使其运行速度非常快。试试在上面输入一个 Scratch 官网的作品 ID 或网页链接,或者在下面选择一个特色作品。","tw.home.instructions":"操作说明","tw.input.tooltip":"在这里粘贴一个 Scratch 作品的链接!","tw.interpolationEnabled":"补帧","tw.invalidParameters.clones":"克隆体参数不合法","tw.invalidParameters.fps":"“fps” URL 参数不合法","tw.loadError":"不能加载作品:{error}","tw.loader.assets.known":"下载素材中(第 {complete} 个,共 {total} 个)...","tw.loader.assets.unknown":"下载素材中...","tw.loader.data":"下载作品数据中...","tw.loader.generic":"加载作品中...","tw.menuBar.60off":"关闭 60 帧模式","tw.menuBar.60on":"打开 60 帧模式","tw.menuBar.addons":"插件","tw.menuBar.advanced":"高级","tw.menuBar.changeUsername":"更改用户名","tw.menuBar.cloudOff":"禁用云变量","tw.menuBar.cloudOn":"启用云变量","tw.menuBar.cloudUnavailable":"云变量不可用","tw.menuBar.cloudUnavailableAlert":"无法使用云变量,可能因为切换到编辑器模式了。","tw.menuBar.compileError":"{sprite}:{error}","tw.menuBar.loadRestorePoint":"加载还原点","tw.menuBar.moreSettings":"高级设置","tw.menuBar.newFramerate":"新帧率:","tw.menuBar.package":"打包作品","tw.menuBar.reportError1":"一些脚本不能被编译。","tw.menuBar.reportError2":"这是一个漏洞,请将它报告给开发团队。 ","tw.menuBar.saveAs":"另存为 {file}","tw.menuBar.seeInside":"转到源代码","tw.mono":"单声道","tw.oldDownload":"保存到文件","tw.openAdvanced":"高级设置","tw.paint.alpha":"不透明度","tw.privacy":"隐私政策","tw.restorePoint.confirm":"编辑器会自动记录一个还原点,以防出现问题而您忘记保存。您不应该依赖这个,我们不能保证它会恢复你的作品。是否尝试加载?","tw.restorePoint.loadFail":"无法加载还原点:{error}","tw.saveAs":"另存为","tw.saveTo":"保存到 {file}","tw.scratchUnsafeCloud":"如果你创建这个云变量,作品就会超过 Scratch 的 {number} 个变量的限制,如果你把作品上传到 Scratch,有些变量就不能正常工作。","tw.settingsModal.customStageSize":"自定义舞台大小:","tw.settingsModal.customStageSizeHelp":"改变 Scratch 的屏幕大小,原大小为 480x360。例如,将分辨率改为 640x360 可实现宽屏作品。但是很少有大佬能做出适合修改尺寸后能正常运行的作品。","tw.settingsModal.dangerZone":"危险功能","tw.settingsModal.disableCompiler":"不使用编译","tw.settingsModal.disableCompilerHelp":"禁用 TurboWarp 编译器。该选项适合在编辑作品实时更新时使用,否则请勿启用。","tw.settingsModal.featured":"特色","tw.settingsModal.fps":"60 帧(自定义帧率)","tw.settingsModal.fpsHelp":"每秒运行脚本 60 次,而不是 30 次。启用此选项后,大多数作品将无法正常工作。如果是这种情况,您应该尝试在禁用 60 帧模式的情况下使用补帧。{customFramerate}。","tw.settingsModal.fpsHelp.customFramerate":"点击设置 30 或 60 以外的帧率","tw.settingsModal.help":"点击查看帮助","tw.settingsModal.highQualityPen":"高清画笔","tw.settingsModal.highQualityPenHelp":"允许有画笔的作品以更高的分辨率渲染,并且避免编辑器中的一些坐标精度丢失。该功能可能会影响运行性能,且不是所有作品都适合该功能。","tw.settingsModal.infiniteClones":"无限克隆","tw.settingsModal.infiniteClonesHelp":"取消 Scratch 的 300 个克隆体限制。","tw.settingsModal.interpolation":"补帧","tw.settingsModal.interpolationHelp":"通过在角色的运动中插入帧使角色运动看起来更平滑。此功能不应该在 3D、光线追踪、纯画笔作品等运算量大的作品中使用。这会使它们运行得更慢而没有明显的平滑效果。","tw.settingsModal.largeStageWarning":"我们不推荐使用自定义舞台大小!请使用具有相同长宽比的较低尺寸,并让用户开启全屏模式将其放大以匹配显示器来代替它。","tw.settingsModal.removeFencing":"角色可穿过边缘","tw.settingsModal.removeFencingHelp":"允许角色移到屏幕之外,根据需要变大或变小,并使触摸块在屏幕外有效。","tw.settingsModal.removeLimits":"移除限制","tw.settingsModal.removeMiscLimits":"移除其他限制","tw.settingsModal.removeMiscLimitsHelp":"取消音效范围限制和画笔大小限制。","tw.settingsModal.storeProjectOptions":"在作品中保留设置","tw.settingsModal.storeProjectOptionsHelp":"在作品文件中储存已选择的设置,它们会在 TurboWarp 加载作品文件时自动被应用。循环计时器和不使用编译不会被保存。","tw.settingsModal.title":"高级设置","tw.settingsModal.warpTimer":"循环计时器","tw.settingsModal.warpTimerHelp":"让脚本检查它们是否卡在长循环或无限循环中,并以低帧率运行,从而阻止它们卡在循环中。这会解决大多数崩溃,但对性能有很大影响,所以它只在编辑器中默认启用。","tw.spriteSelectorItem.rename":"重命名","tw.stereo":"双声道","tw.stereoAlert":"编辑多声道音频会将音频转换成单声道!","tw.studioview.authorAttribution":"作者:{author}","tw.studioview.error":"加载下一页作品出错。","tw.studioview.hoverText":"{title} 作者:{author}","tw.tooLarge":"这个音频太大了,无法上传到Scratch。","tw.twExtension.description":"奇怪的新积木。不兼容 Scratch。","tw.twExtension.name":"TurboWarp 积木","tw.unshared.1":"由于未来 Scratch API 的变化,未共享的作品将不再能只使用其作品 ID 访问。","tw.unshared.2":"详见 {link}","tw.unshared.cache":"如果该项目是最近共享的,几分钟内可能会出现一些错误。","tw.usernameModal.help":"此变量将存储在浏览器中。当您与包含云变量的作品交互时,它可能会被记录。","tw.usernameModal.help2":"与有效的 Scratch 帐户不对应的值通常会被云变量服务器拒绝。我们建议保持原样或将其更改为您的 Scratch 用户名。","tw.usernameModal.mustChange":"抱歉,云变量服务器认为您的用户名可能不合适。请把它改成别的或 {resetIt}。","tw.usernameModal.mustChange.resetIt":"重置(推荐)","tw.usernameModal.reset":"重置","tw.usernameModal.title":"更改用户名","tw.viewFeaturedProjects":"点击以查看特色作品。","tw.viewOnScratch":"在 Scratch 网站上查看作品","tw.webglModal.description":"很抱歉,您的浏览器或电脑可能缺少 {webGlLink}。运行此网站需要此技术。请尝试更新浏览器和图形驱动程序或重启电脑。"},"zh-tw":{"gui.alerts.tryAgain":"再試一次","gui.alerts.download":"下載","gui.connection.reconnect":"重新連接","gui.backpack.costumeLabel":"造型","gui.backpack.soundLabel":"音效","gui.backpack.scriptLabel":"程式","gui.backpack.spriteLabel":"角色","gui.backpack.header":"背包","gui.backpack.errorBackpack":"載入背包時發生錯誤","gui.backpack.loadingBackpack":"正在載入…","gui.backpack.more":"更多資訊","gui.backpack.emptyBackpack":"背包空無一物","gui.unsupportedBrowser.label":"瀏覽器不支援","gui.cards.all-tutorials":"教程","gui.cards.shrink":"縮小","gui.cards.expand":"放大","gui.cards.close":"關閉","gui.cards.more-things-to-try":"試試其它東西!","gui.cards.see-more":"觀看更多","gui.comingSoon.message1":"別擔心,我們在做囉 {emoji}","gui.comingSoon.message2":"即將推出...","gui.comingSoon.message3":"我們在做囉 {emoji}","gui.connection.auto-scanning.noPeripheralsFound":"沒有找到裝置","gui.connection.auto-scanning.prescan":"把你的裝置放得近一些,然後再開始搜索。","gui.connection.auto-scanning.pressbutton":"按下裝置上的按鈕。","gui.connection.auto-scanning.start-search":"開始搜尋","gui.connection.connecting-searchbutton":"正在搜尋…","gui.connection.auto-scanning.try-again":"再試一次","gui.connection.connected":"裝置已連線","gui.connection.disconnect":"中斷裝置連線","gui.connection.go-to-editor":"回到編輯器","gui.connection.connecting-cancelbutton":"正在連線...","gui.connection.error.errorMessage":"喔,好像有什麼地方出錯了。","gui.connection.error.tryagainbutton":"再試一次","gui.connection.error.helpbutton":"幫助","gui.connection.peripheral-name-label":"裝置名稱","gui.connection.connect":"開始連線","gui.connection.scanning.lookingforperipherals":"正在尋找裝置","gui.connection.scanning.noPeripheralsFound":"沒有找到裝置","gui.connection.scanning.instructions":"在列表中選擇你的裝置","gui.connection.search":"重新整理","gui.connection.unavailable.installscratchlink":"確定你已經安裝並執行 Scratch Link","gui.connection.unavailable.enablebluetooth":"檢查藍牙是否開啟","gui.connection.unavailable.tryagainbutton":"再試一次","gui.connection.unavailable.helpbutton":"幫助","gui.controls.go":"開始","gui.controls.stop":"停止","gui.crashMessage.label":"哎呀!發生了一些錯誤。","gui.crashMessage.errorNumber":"錯誤已被紀錄,id 為 {errorId}","gui.crashMessage.reload":"重新載入","gui.customProcedures.myblockModalTitle":"建立一個積木","gui.customProcedures.addAnInputNumberText":"添加輸入方塊","gui.customProcedures.numberTextType":"數字或文字","gui.customProcedures.addAnInputBoolean":"添加輸入方塊","gui.customProcedures.booleanType":"布林值","gui.customProcedures.addALabel":"添加說明文字","gui.customProcedures.runWithoutScreenRefresh":"執行完畢再更新畫面","gui.customProcedures.cancel":"取消","gui.customProcedures.ok":"確定","gui.SpriteInfo.direction":"方向","gui.directionPicker.rotationStyles.allAround":"不設限","gui.directionPicker.rotationStyles.leftRight":"左-右","gui.directionPicker.rotationStyles.dontRotate":"不旋轉","gui.gui.addExtension":"添加擴展","gui.gui.codeTab":"程式","gui.gui.backdropsTab":"背景","gui.gui.costumesTab":"造型","gui.gui.soundsTab":"音效","gui.extensionLibrary.comingSoon":"即將推出","gui.extensionLibrary.requires":"需求","gui.extensionLibrary.collaboration":"合作者","gui.library.filterPlaceholder":"搜尋","gui.library.allTag":"全部","gui.loader.headline":"正在載入專案","gui.loader.creating":"正在創建專案","gui.authorInfo.byUser":"建立者 {username}","gui.menuBar.seeProjectPage":"切換到專案頁面","gui.menuBar.LanguageSelector":"語言選擇器","gui.menuBar.tutorialsLibrary":"教程","gui.menuBar.restoreSprite":"復原角色","gui.menuBar.restoreSound":"復原音效","gui.menuBar.restoreCostume":"復原造型","gui.menuBar.restore":"復原","gui.menuBar.saveNow":"儲存","gui.menuBar.saveAsCopy":"另存成複本","gui.menuBar.remix":"改編","gui.menuBar.new":"新建專案","gui.menuBar.file":"檔案","gui.menuBar.downloadToComputer":"下載到你的電腦","gui.menuBar.edit":"編輯","gui.menuBar.turboModeOff":"關閉加速模式","gui.menuBar.turboModeOn":"開啟加速模式","gui.gui.projectTitlePlaceholder":"在這輸入專案名稱","gui.menuBar.isShared":"已分享","gui.menuBar.share":"分享","gui.modal.help":"幫助","gui.modal.back":"返回","gui.monitor.listMonitor.empty":"(empty)","gui.monitor.listMonitor.listLength":"長度 {length}","gui.monitor.contextMenu.default":"一般顯示","gui.monitor.contextMenu.large":"大型顯示","gui.monitor.contextMenu.slider":"滑桿","gui.monitor.contextMenu.sliderRange":"變更滑桿數值範圍","gui.monitor.contextMenu.import":"匯入","gui.monitor.contextMenu.export":"匯出","gui.monitor.contextMenu.hide":"hide","gui.playButton.play":"播放","gui.playButton.stop":"停止","gui.gui.variableScopeOptionAllSprites":"適用於所有角色","gui.gui.variableScopeOptionSpriteOnly":"僅適用當前角色","gui.gui.cloudVariableOption":"雲端變數(儲存於伺服器)","gui.gui.variablePromptAllSpritesMessage":"這個變數適用於所有角色。","gui.gui.listPromptAllSpritesMessage":"This list will be available to all sprites.","gui.prompt.cancel":"取消","gui.prompt.ok":"確定","gui.playbackStep.stopMsg":"停止","gui.playbackStep.playMsg":"播放","gui.playbackStep.loadingMsg":"正在載入…","gui.playbackStep.saveMsg":"儲存","gui.playbackStep.reRecordMsg":"重新錄音","gui.recordModal.title":"錄音","gui.recordingStep.beginRecord":"點擊下方按鈕開始錄製","gui.recordingStep.permission":"{arrow} 我們需要你的允許才能使用麥克風","gui.recordingStep.stop":"停止錄製","gui.recordingStep.record":"錄製","gui.sliderModal.min":"最小值","gui.sliderModal.max":"最大值","gui.sliderModal.title":"變更滑桿數值範圍","gui.sliderPrompt.cancel":"取消","gui.sliderPrompt.ok":"確定","gui.soundEditor.sound":"音效","gui.soundEditor.play":"播放","gui.soundEditor.stop":"停止","gui.soundEditor.copy":"複製","gui.soundEditor.paste":"貼上","gui.soundEditor.copyToNew":"複製","gui.soundEditor.delete":"刪除","gui.soundEditor.save":"保存","gui.soundEditor.undo":"復原","gui.soundEditor.redo":"重做","gui.soundEditor.faster":"快播","gui.soundEditor.slower":"慢播","gui.soundEditor.echo":"回音","gui.soundEditor.robot":"機器","gui.soundEditor.louder":"響亮","gui.soundEditor.softer":"輕柔","gui.soundEditor.reverse":"反轉","gui.soundEditor.fadeOut":"淡出","gui.soundEditor.fadeIn":"淡入","gui.soundEditor.mute":"靜音","gui.SpriteInfo.spritePlaceholder":"名稱","gui.SpriteInfo.sprite":"角色","gui.SpriteInfo.show":"顯示","gui.SpriteInfo.size":"尺寸","gui.spriteSelectorItem.contextMenuDuplicate":"複製","gui.spriteSelectorItem.contextMenuExport":"匯出","gui.spriteSelectorItem.contextMenuDelete":"刪除","gui.spriteSelector.addSpriteFromLibrary":"選個角色","gui.spriteSelector.addSpriteFromPaint":"繪畫","gui.spriteSelector.addSpriteFromSurprise":"驚喜","gui.spriteSelector.addSpriteFromFile":"上傳","gui.stageHeader.stageSizeLarge":"模式切換 - 大舞台","gui.stageHeader.stageSizeSmall":"模式切換 - 小舞台","gui.stageHeader.stageSizeFull":"模式切換 - 全螢幕","gui.stageHeader.stageSizeUnFull":"離開全螢幕模式","gui.stageHeader.fullscreenControl":"顯示模式切換","gui.spriteSelector.addBackdropFromLibrary":"選個背景","gui.stageSelector.addBackdropFromPaint":"繪畫","gui.stageSelector.addBackdropFromSurprise":"驚喜","gui.stageSelector.addBackdropFromFile":"上傳","gui.stageSelector.stage":"舞台","gui.stageSelector.backdrops":"背景","gui.telemetryOptIn.label":"回報統計數據以協助改善 Scratch","gui.telemetryOptIn.body1":"Scratch 團隊希望能深入瞭解 Scratch 在世界各地的使用情況。如果可以的話,希望你能允許 Scratch 將你的使用情形紀錄下來並發送給 Scratch 團隊。","gui.telemetryOptIn.body2":"我們會蒐集的資訊包含了語言的選擇、積木的使用量,還有一些事件,像是儲存、載入、上傳專案。我們保證不會收集任何個人資訊。你可以觀看我們的 {privacyPolicyLink} 以進一步瞭解相關訊息。","gui.telemetryOptIn.privacyPolicyLink":"隱私政策","gui.telemetryOptIn.optInText":"Share my usage data with the Scratch Team","gui.telemetryOptIn.optInTooltip":"Enable telemetry","gui.telemetryOptIn.optOutText":"Do not share my usage data with the Scratch Team","gui.telemetryOptIn.optOutTooltip":"Disable telemetry","gui.telemetryOptIn.settingWasUpdated":"Your setting was updated.","gui.telemetryOptIn.buttonClose":"Close","gui.turboMode.active":"加速模式","gui.webglModal.label":"你的瀏覽器不支援 WebGL","gui.webglModal.webgllink":"不支援 WebGL","gui.costumeLibrary.chooseABackdrop":"範例背景","gui.costumeLibrary.chooseACostume":"範例造型","gui.costumeTab.addBackdropFromLibrary":"選個背景","gui.costumeTab.addCostumeFromLibrary":"選個造型","gui.costumeTab.addBlankCostume":"繪畫","gui.costumeTab.addSurpriseCostume":"驚喜","gui.costumeTab.addFileBackdrop":"上傳","gui.costumeTab.addFileCostume":"上傳","gui.extensionLibrary.chooseAnExtension":"選擇擴充功能","gui.extensionLibrary.extensionUrl":"輸入擴充功能的網址","gui.monitors.importListColumnPrompt":"該使用哪一欄(1-{numberOfColumns})?","gui.recordingStep.alertMsg":"無法開始錄製","gui.soundLibrary.chooseASound":"範例音效","gui.soundTab.fileUploadSound":"上傳","gui.soundTab.surpriseSound":"驚喜","gui.soundTab.recordSound":"錄製","gui.soundTab.addSoundFromLibrary":"選個音效","gui.spriteLibrary.chooseASprite":"範例角色","gui.tipsLibrary.tutorials":"選擇教程","gui.alerts.createsuccess":"專案創建成功。","gui.alerts.createcopysuccess":"已另存為複本。","gui.alerts.createremixsuccess":"已另存為改編本。","gui.alerts.creating":"正在創建新的專案…","gui.alerts.creatingCopy":"正在複製專案…","gui.alerts.creatingRemix":"正在改編專案…","gui.alerts.creatingError":"專案無法創建,麻煩再試一次!","gui.alerts.savingError":"專案無法儲存。","gui.alerts.savesuccess":"專案儲存成功。","gui.alerts.saving":"正在儲存專案…","gui.alerts.cloudInfo":"注意,雲端變數目前只支援數字,不能存取文字等其它符號。{learnMoreLink}","gui.alerts.cloudInfoLearnMore":"進一步瞭解","gui.alerts.importing":"正在匯入…","gui.defaultProject.variable":"my variable","gui.extension.music.name":"音樂","gui.extension.music.description":"演奏樂器與節拍。","gui.extension.pen.name":"畫筆","gui.extension.pen.description":"使用你的角色來畫圖。","gui.extension.videosensing.name":"視訊偵測","gui.extension.videosensing.description":"使用攝影機偵測動作。","gui.extension.text2speech.name":"文字轉語音","gui.extension.text2speech.description":"讓你的專案能夠說話","gui.extension.translate.name":"翻譯","gui.extension.translate.description":"將文字訊息翻譯為各國語言。","gui.extension.makeymakey.description":"把任何東西變成鑰匙。","gui.extension.microbit.description":"讓你的專案與實體世界連結。","gui.extension.microbit.connectingMessage":"正在連線","gui.extension.ev3.description":"創作互動機器人以及更多。","gui.extension.ev3.connectingMessage":"正在連接,請確定 EV3 主機上的 Pin 碼已設為 1234。","gui.extension.boost.description":"將機器人創造帶入現實生活。","gui.extension.boost.connectingMessage":"正在連線","gui.extension.wedo2.description":"運用馬達與感測器進行創作。","gui.extension.wedo2.connectingMessage":"正在連線","gui.extension.gdxfor.description":"Sense push, pull, motion, and spin.","gui.extension.gdxfor.connectingMessage":"正在連線","gui.libraryTags.all":"全部","gui.libraryTags.animals":"動物","gui.libraryTags.dance":"舞蹈","gui.libraryTags.effects":"效果","gui.libraryTags.fantasy":"魔幻","gui.libraryTags.fashion":"時尚","gui.libraryTags.food":"食物","gui.libraryTags.indoors":"室內","gui.libraryTags.loops":"循環","gui.libraryTags.music":"音樂","gui.libraryTags.notes":"音階","gui.libraryTags.outdoors":"戶外","gui.libraryTags.patterns":"圖案","gui.libraryTags.people":"人物","gui.libraryTags.percussion":"節奏","gui.libraryTags.space":"太空","gui.libraryTags.sports":"運動","gui.libraryTags.underwater":"水中","gui.libraryTags.voice":"人聲","gui.libraryTags.wacky":"滑稽","gui.libraryTags.animation":"動畫","gui.libraryTags.art":"藝術","gui.libraryTags.games":"遊戲","gui.libraryTags.stories":"故事","gui.libraryTags.letters":"字母","gui.opcodeLabels.direction":"方向","gui.opcodeLabels.xposition":"x 座標","gui.opcodeLabels.yposition":"y 座標","gui.opcodeLabels.size":"尺寸","gui.opcodeLabels.costumename":"造型名稱","gui.opcodeLabels.costumenumber":"造型編號","gui.opcodeLabels.backdropname":"背景名稱","gui.opcodeLabels.backdropnumber":"背景編號","gui.opcodeLabels.volume":"音量","gui.opcodeLabels.tempo":"演奏速度","gui.opcodeLabels.answer":"詢問的答案","gui.opcodeLabels.loudness":"聲音響度","gui.opcodeLabels.username":"用戶名稱","gui.opcodeLabels.year":"年","gui.opcodeLabels.month":"月","gui.opcodeLabels.date":"日","gui.opcodeLabels.dayofweek":"週","gui.opcodeLabels.hour":"時","gui.opcodeLabels.minute":"分","gui.opcodeLabels.second":"秒","gui.opcodeLabels.timer":"計時器","gui.sharedMessages.backdrop":"backdrop{index}","gui.sharedMessages.costume":"costume{index}","gui.sharedMessages.sprite":"Sprite{index}","gui.sharedMessages.pop":"pop","gui.sharedMessages.replaceProjectWarning":"是否取代現有專案?","gui.sharedMessages.loadFromComputerTitle":"從你的電腦挑選","boost.color.any":"任何顏色","boost.color.black":"黑色","boost.color.blue":"藍色","boost.color.green":"綠色","boost.color.red":"紅色","boost.color.white":"白色","boost.color.yellow":"黃色","boost.getMotorPosition":"[MOTOR_REPORTER_ID] 轉向角度","boost.getTiltAngle":"傾斜角度 [TILT_DIRECTION]","boost.motorDirection.backward":"逆時針","boost.motorDirection.forward":"順時針","boost.motorDirection.reverse":"相反","boost.motorOff":"[MOTOR_ID] 停止","boost.motorOn":"[MOTOR_ID] 啟動","boost.motorOnFor":"[MOTOR_ID] 啟動 持續 [DURATION] 秒","boost.motorOnForRotation":"[MOTOR_ID] 啟動 持續 [ROTATION] 圈","boost.seeingColor":"看到顏色 [COLOR]?","boost.setLightHue":"LED 顏色設為 [HUE]","boost.setMotorDirection":"[MOTOR_ID] 方向設為 [MOTOR_DIRECTION]","boost.setMotorPower":"[MOTOR_ID] 動力設為 [POWER] %","boost.tiltDirection.any":"任何","boost.tiltDirection.down":"向下","boost.tiltDirection.left":"向左","boost.tiltDirection.right":"向右","boost.tiltDirection.up":"向上","boost.whenColor":"當顏色 [COLOR]  被看到","boost.whenTilted":"當傾斜 [TILT_DIRECTION_ANY]","ev3.beepNote":"演奏音階 [NOTE] 持續 [TIME] 秒","ev3.buttonPressed":"按鈕 [PORT] 被按下?","ev3.getBrightness":"亮度","ev3.getDistance":"距離","ev3.getMotorPosition":"馬達 埠[PORT] 轉向角度","ev3.motorSetPower":"馬達 埠[PORT] 動力設為 [POWER] %","ev3.motorTurnClockwise":"馬達 埠[PORT] 順時針旋轉 [TIME] 秒","ev3.motorTurnCounterClockwise":"馬達 埠[PORT] 逆時針旋轉 [TIME] 秒","ev3.whenBrightnessLessThan":"當亮度 < [DISTANCE]","ev3.whenButtonPressed":"當按鈕 [PORT] 被按下","ev3.whenDistanceLessThan":"當距離 < [DISTANCE]","gdxfor.getAcceleration":"加速度 [DIRECTION]","gdxfor.getForce":"力量","gdxfor.getSpin":"旋轉速度 [DIRECTION]","gdxfor.getTilt":"傾斜角度 [TILT]","gdxfor.isFreeFalling":"自由掉落?","gdxfor.isTilted":"傾斜 [TILT]?","gdxfor.pulled":"向外拉","gdxfor.pushed":"向內推","gdxfor.shaken":"晃動","gdxfor.startedFalling":"開始掉落","gdxfor.tiltDirectionMenu.any":"任何","gdxfor.tiltDirectionMenu.back":"向下","gdxfor.tiltDirectionMenu.front":"向上","gdxfor.tiltDirectionMenu.left":"向左","gdxfor.tiltDirectionMenu.right":"向右","gdxfor.turnedFaceDown":"背面朝上","gdxfor.turnedFaceUp":"正面朝上","gdxfor.whenForcePushedOrPulled":"當重力感測器[PUSH_PULL]","gdxfor.whenGesture":"當 [GESTURE]","gdxfor.whenTilted":"當傾斜 [TILT]","makeymakey.downArrow":"向下","makeymakey.downArrowShort":"向下","makeymakey.leftArrow":"向左","makeymakey.leftArrowShort":"向左","makeymakey.rightArrow":"向右","makeymakey.rightArrowShort":"向右","makeymakey.spaceKey":"空白","makeymakey.upArrow":"向上","makeymakey.upArrowShort":"向上","makeymakey.whenKeyPressed":"當 [KEY] 按鈕被按下","makeymakey.whenKeysPressedInOrder":"當 [SEQUENCE] 按鈕被依序按下","microbit.buttonsMenu.any":"任何","microbit.clearDisplay":"清空畫面","microbit.defaultTextToDisplay":"Hello!","microbit.displaySymbol":"顯示圖示 [MATRIX]","microbit.displayText":"顯示文字 [TEXT]","microbit.gesturesMenu.jumped":"跳動","microbit.gesturesMenu.moved":"移動","microbit.gesturesMenu.shaken":"晃動","microbit.isButtonPressed":"按鈕 [BTN] 被按下?","microbit.isTilted":"傾斜 [DIRECTION]?","microbit.pinStateMenu.off":"關閉","microbit.pinStateMenu.on":"開啟","microbit.tiltAngle":"傾斜角度 [DIRECTION]","microbit.tiltDirectionMenu.any":"任何","microbit.tiltDirectionMenu.back":"向下","microbit.tiltDirectionMenu.front":"向上","microbit.tiltDirectionMenu.left":"向左","microbit.tiltDirectionMenu.right":"向右","microbit.whenButtonPressed":"當按鈕 [BTN] 被按下","microbit.whenGesture":"當 [GESTURE]","microbit.whenPinConnected":"當引腳 [PIN] 接地","microbit.whenTilted":"當傾斜 [DIRECTION]","music.categoryName":"音樂","music.changeTempo":"演奏速度改變 [TEMPO]","music.drumBass":"(2) 低音鼓","music.drumBongo":"(13) 邦加鼓","music.drumCabasa":"(15) 鐵沙鈴","music.drumClaves":"(9) 梆子","music.drumClosedHiHat":"(6) 合起的腳踏鈸","music.drumConga":"(14) 康加鼓","music.drumCowbell":"(11) 牛鈴","music.drumCrashCymbal":"(4) 碎音鈸","music.drumCuica":"(18) 庫加鼓","music.drumGuiro":"(16) 刮瓜","music.drumHandClap":"(8) 拍掌","music.drumOpenHiHat":"(5) 打開的腳踏鈸","music.drumSideStick":"(3) 鼓邊敲擊","music.drumSnare":"(1) 軍鼓","music.drumTambourine":"(7) 鈴鼓","music.drumTriangle":"(12) 三角鐵","music.drumVibraslap":"(17) 振盪器","music.drumWoodBlock":"(10) 木魚","music.getTempo":"演奏速度","music.instrumentBass":"(6) 貝斯","music.instrumentBassoon":"(14) 低音管","music.instrumentCello":"(8) 大提琴","music.instrumentChoir":"(15) 人聲合唱","music.instrumentClarinet":"(10) 單簧管","music.instrumentElectricGuitar":"(5) 電吉他","music.instrumentElectricPiano":"(2) 電子琴","music.instrumentFlute":"(12) 長笛","music.instrumentGuitar":"(4) 吉他","music.instrumentMarimba":"(19) 馬林巴","music.instrumentMusicBox":"(17) 音樂盒","music.instrumentOrgan":"(3) 風琴","music.instrumentPiano":"(1) 鋼琴","music.instrumentPizzicato":"(7) 撥奏","music.instrumentSaxophone":"(11) 薩克斯風","music.instrumentSteelDrum":"(18) 鋼鼓","music.instrumentSynthLead":"(20) 合成主音","music.instrumentSynthPad":"(21) 合成柔音","music.instrumentTrombone":"(9) 長號","music.instrumentVibraphone":"(16) 顫音琴","music.instrumentWoodenFlute":"(13) 木笛","music.midiPlayDrumForBeats":"演奏節拍 [DRUM] [BEATS] 拍","music.midiSetInstrument":"演奏樂器設為 [INSTRUMENT]","music.playDrumForBeats":"演奏節拍 [DRUM] [BEATS] 拍","music.playNoteForBeats":"演奏音階 [NOTE] [BEATS] 拍","music.restForBeats":"演奏休息 [BEATS] 拍","music.setInstrument":"演奏樂器設為 [INSTRUMENT]","music.setTempo":"演奏速度設為 [TEMPO]","pen.categoryName":"畫筆","pen.changeColorParam":"筆跡 [COLOR_PARAM] 改變 [VALUE]","pen.changeHue":"筆跡顏色改變 [HUE]","pen.changeShade":"筆跡亮度改變 [SHADE]","pen.changeSize":"筆跡寬度改變 [SIZE]","pen.clear":"筆跡全部清除","pen.colorMenu.brightness":"亮度","pen.colorMenu.color":"顏色","pen.colorMenu.saturation":"彩度","pen.colorMenu.transparency":"透明度","pen.penDown":"下筆","pen.penUp":"停筆","pen.setColor":"筆跡顏色設為 [COLOR]","pen.setColorParam":"筆跡 [COLOR_PARAM] 設為 [VALUE]","pen.setHue":"筆跡顏色設為 [HUE]","pen.setShade":"筆跡亮度設為 [SHADE]","pen.setSize":"筆跡寬度設為 [SIZE]","pen.stamp":"蓋章","text2speech.alto":"alto","text2speech.categoryName":"文字轉語音","text2speech.defaultTextToSpeak":"hello","text2speech.giant":"低沉","text2speech.kitten":"小貓","text2speech.setLanguageBlock":"語言設為 [LANGUAGE]","text2speech.setVoiceBlock":"語音設為 [VOICE]","text2speech.speakAndWaitBlock":"唸出 [WORDS]","text2speech.squeak":"尖細","text2speech.tenor":"tenor","translate.categoryName":"翻譯","translate.defaultTextToTranslate":"hello","translate.translateBlock":"文字 [WORDS] 翻譯成 [LANGUAGE]","translate.viewerLanguage":"瀏覽者的語言","videoSensing.categoryName":"視訊偵測","videoSensing.direction":"方向","videoSensing.motion":"動作","videoSensing.off":"關閉","videoSensing.on":"開啟","videoSensing.onFlipped":"翻轉","videoSensing.setVideoTransparency":"視訊透明度設為 [TRANSPARENCY]","videoSensing.sprite":"角色","videoSensing.stage":"舞台","videoSensing.videoOn":"[SUBJECT] 的視訊 [ATTRIBUTE]","videoSensing.videoToggle":"視訊設為 [VIDEO_STATE]","videoSensing.whenMotionGreaterThan":"當視訊動作 > [REFERENCE]","wedo2.getDistance":"距離","wedo2.getTiltAngle":"傾斜角度 [TILT_DIRECTION]","wedo2.isTilted":"傾斜 [TILT_DIRECTION_ANY]?","wedo2.motorDirection.backward":"逆時針","wedo2.motorDirection.forward":"順時針","wedo2.motorDirection.reverse":"相反","wedo2.motorId.a":"馬達 A","wedo2.motorId.all":"馬達 A 與 B","wedo2.motorId.b":"馬達 B","wedo2.motorId.default":"馬達","wedo2.motorOff":"[MOTOR_ID] 停止","wedo2.motorOn":"[MOTOR_ID] 啟動","wedo2.motorOnFor":"[MOTOR_ID] 啟動 持續 [DURATION] 秒","wedo2.playNoteFor":"演奏音階 [NOTE] 持續 [DURATION] 秒","wedo2.setLightHue":"LED 顏色設為 [HUE]","wedo2.setMotorDirection":"[MOTOR_ID] 方向設為 [MOTOR_DIRECTION]","wedo2.startMotorPower":"[MOTOR_ID] 動力設為 [POWER]","wedo2.tiltDirection.any":"任何","wedo2.tiltDirection.down":"向下","wedo2.tiltDirection.left":"向左","wedo2.tiltDirection.right":"向右","wedo2.tiltDirection.up":"向上","wedo2.whenDistance":"當距離 [OP] [REFERENCE]","wedo2.whenTilted":"當傾斜 [TILT_DIRECTION_ANY]","paint.paintEditor.hue":"顏色","paint.paintEditor.saturation":"彩度","paint.paintEditor.brightness":"亮度","paint.paintEditor.costume":"造型","paint.paintEditor.group":"建立群組","paint.paintEditor.ungroup":"解散群組","paint.paintEditor.undo":"復原","paint.paintEditor.redo":"重做","paint.paintEditor.forward":"上移一層","paint.paintEditor.backward":"下移一層","paint.paintEditor.front":"移到最上層","paint.paintEditor.back":"移到最下層","paint.paintEditor.more":"更多","paint.modeTools.brushSize":"尺寸","paint.modeTools.eraserSize":"擦子寬度","paint.modeTools.copy":"複製","paint.modeTools.paste":"貼上","paint.modeTools.delete":"刪除","paint.modeTools.curved":"圓弧","paint.modeTools.pointed":"尖角","paint.modeTools.thickness":"線條寬度","paint.modeTools.flipHorizontal":"橫向翻轉","paint.modeTools.flipVertical":"直向翻轉","paint.modeTools.filled":"填滿","paint.modeTools.outlined":"外框","paint.paintEditor.bitmap":"轉換成點陣圖","paint.paintEditor.vector":"轉換成向量圖","paint.paintEditor.fill":"填滿","paint.paintEditor.stroke":"外框","paint.brushMode.brush":"筆刷","paint.eraserMode.eraser":"擦子","paint.fillMode.fill":"填滿","paint.lineMode.line":"線條","paint.ovalMode.oval":"圓形","paint.rectMode.rect":"方形","paint.reshapeMode.reshape":"重新塑形","paint.roundedRectMode.roundedRect":"圓角方形","paint.selectMode.select":"選取","paint.textMode.text":"文字","paint.colorPicker.swap":"交換","tw.backpack.rename":"新名稱:","tw.browserModal.desc":"請確保你使用的是最新版本的 Chrome、Firefox、Edge 或 Safari。","tw.cloudVariableBadge":"這個專案使用到了雲端變數,TurboWarp 使用的是不同的雲端變數伺服器。謹防冒充,因為用戶名可隨意更改。{learnMore}","tw.code":"原始碼","tw.featuredProjectsStudio":"在 Scratch 查看該創作坊","tw.feedback":"回報建議及錯誤","tw.feedbackButton":"TurboWarp 回饋","tw.footer.credits":"感謝","tw.footer.disclaimer":"TurboWarp 並不隸屬於 Scratch、Scratch 團隊或 Scratch 基金會。","tw.footer.embed":"嵌入","tw.footer.fosshost":"託管服務由 Fosshost 提供","tw.footer.parameters":"網址參數","tw.footer.translate":"協助翻譯 TurboWarp","tw.guiDefaultTitle":"使 Scratch 專案跑得更快","tw.home.credit":"備註與謝誌","tw.home.instructions":"操作說明","tw.input.tooltip":"把 Scratch 專案連結貼在這裡!","tw.interpolationEnabled":"運動補償","tw.invalidParameters.clones":"無效的「分身」網址參數","tw.invalidParameters.fps":"無效的「影格率」網址參數","tw.loadError":"不能夠加載作品:{error}","tw.loader.assets.known":"下載素材中({complete}/{total})……","tw.loader.assets.unknown":"下載素材中……","tw.loader.data":"下載專案資料中……","tw.loader.generic":"載入專案中……","tw.menuBar.60off":"關閉 60 FPS模式","tw.menuBar.60on":"開啟 60 FPS模式","tw.menuBar.addons":"擴充功能","tw.menuBar.advanced":"進階","tw.menuBar.changeUsername":"更改用戶名稱","tw.menuBar.cloudOff":"禁用雲端變數","tw.menuBar.cloudOn":"啟用雲端變數","tw.menuBar.cloudUnavailable":"雲端變數不可用","tw.menuBar.compileError":"{sprite}:{error}","tw.menuBar.loadRestorePoint":"回溯至還原點","tw.menuBar.moreSettings":"進階設定","tw.menuBar.reportError1":"某些程式可能沒被編譯。","tw.menuBar.reportError2":"這是個錯誤,請回報。","tw.menuBar.saveAs":"儲存為 {file}","tw.menuBar.seeInside":"切換到程式頁面","tw.oldDownload":"存儲為獨立文件…","tw.paint.alpha":"不透明度","tw.privacy":"隱私權政策","tw.saveAs":"另存為…","tw.saveTo":"存儲為{file}","tw.settingsModal.customStageSize":"自訂舞臺大小:","tw.settingsModal.customStageSizeHelp":"更改 Scratch 的舞臺大小。你可以試試 640×360,比例會變成 16:9。僅有極少數的專案能在更改後正常運行。","tw.settingsModal.dangerZone":"危險","tw.settingsModal.disableCompiler":"停用編譯器","tw.settingsModal.disableCompilerHelp":"停用 TurboWarp 編譯器。請不要勾選此選項,除你欲使程式立即更新。","tw.settingsModal.featured":"精選","tw.settingsModal.fps":"60 FPS(自訂影格率)","tw.settingsModal.fpsHelp":"程式運行速度從每秒 30 次改為每秒 60 次,大多數專案都會無法正常運行,你應該試試運動補償。{customFramerate}。","tw.settingsModal.fpsHelp.customFramerate":"使用30或60以外的其他影格率","tw.settingsModal.help":"點擊查看幫助","tw.settingsModal.highQualityPen":"高品質畫筆","tw.settingsModal.highQualityPenHelp":"使畫筆精度提高,並在編輯器中關閉坐標四捨五入。不是所有專案都適合,且可能影響性能。","tw.settingsModal.infiniteClones":"無限分身","tw.settingsModal.infiniteClonesHelp":"移除 300 分身限制。","tw.settingsModal.interpolation":"運動補償","tw.settingsModal.interpolationHelp":"在角色移動中進行運動補償以提升流暢度。你不該在 3D 專案、光線追蹤專案、畫筆專案或運算量大的專案啟用它,不僅效果低下,還會影響效能。","tw.settingsModal.largeStageWarning":"不建議把舞臺調得這麼大!你應當使用同比例但較小的舞臺並讓用戶以全螢幕運行。","tw.settingsModal.removeFencing":"移除屏障","tw.settingsModal.removeLimits":"移除限制","tw.settingsModal.removeMiscLimits":"移除各類限制","tw.settingsModal.removeMiscLimitsHelp":"移除音效效果限制及畫筆大小限制。","tw.settingsModal.storeProjectOptions":"將設定存至專案內","tw.settingsModal.title":"進階設定","tw.settingsModal.warpTimer":"防卡死","tw.settingsModal.warpTimerHelp":"程式卡在迴圈裡時會以低幀率運行,以防止卡死。這可以防止崩潰,但會影響性能,僅在編輯器預設啟用。","tw.spriteSelectorItem.rename":"重新命名","tw.studioview.authorAttribution":"作者:{author}","tw.studioview.hoverText":"{title},作者:{author}","tw.twExtension.name":"TurboWarp積木塊","tw.usernameModal.reset":"重設","tw.usernameModal.title":"更改用戶名稱","tw.viewFeaturedProjects":"瀏覽精選專案","tw.viewOnScratch":"在 Scratch 查看該作品"}}')); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/index.js": /*!***********************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/index.js ***! \***********************************************************/ /*! exports provided: default, localeData, localeMap, isRtl */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony import */ var _locale_data_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./locale-data.js */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data.js"); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "localeData", function() { return _locale_data_js__WEBPACK_IMPORTED_MODULE_0__["default"]; }); /* harmony import */ var _supported_locales_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./supported-locales.js */ "./node_modules/@turbowarp/scratch-l10n/src/supported-locales.js"); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "default", function() { return _supported_locales_js__WEBPACK_IMPORTED_MODULE_1__["default"]; }); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "localeMap", function() { return _supported_locales_js__WEBPACK_IMPORTED_MODULE_1__["localeMap"]; }); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "isRtl", function() { return _supported_locales_js__WEBPACK_IMPORTED_MODULE_1__["isRtl"]; }); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data.js": /*!*****************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data.js ***! \*****************************************************************/ /*! exports provided: default */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return localeData; }); /* harmony import */ var _locale_data_en__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./locale-data/en */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/en.js"); /* harmony import */ var _locale_data_en__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_locale_data_en__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _locale_data_af__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./locale-data/af */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/af.js"); /* harmony import */ var _locale_data_af__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_locale_data_af__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _locale_data_am__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./locale-data/am */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/am.js"); /* harmony import */ var _locale_data_am__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_locale_data_am__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _locale_data_ar__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./locale-data/ar */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ar.js"); /* harmony import */ var _locale_data_ar__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_locale_data_ar__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _locale_data_ast__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./locale-data/ast */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ast.js"); /* harmony import */ var _locale_data_ast__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_locale_data_ast__WEBPACK_IMPORTED_MODULE_4__); /* harmony import */ var _locale_data_az__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./locale-data/az */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/az.js"); /* harmony import */ var _locale_data_az__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_locale_data_az__WEBPACK_IMPORTED_MODULE_5__); /* harmony import */ var _locale_data_be__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./locale-data/be */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/be.js"); /* harmony import */ var _locale_data_be__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_locale_data_be__WEBPACK_IMPORTED_MODULE_6__); /* harmony import */ var _locale_data_bn__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./locale-data/bn */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/bn.js"); /* harmony import */ var _locale_data_bn__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(_locale_data_bn__WEBPACK_IMPORTED_MODULE_7__); /* harmony import */ var _locale_data_bg__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./locale-data/bg */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/bg.js"); /* harmony import */ var _locale_data_bg__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(_locale_data_bg__WEBPACK_IMPORTED_MODULE_8__); /* harmony import */ var _locale_data_ca__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./locale-data/ca */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ca.js"); /* harmony import */ var _locale_data_ca__WEBPACK_IMPORTED_MODULE_9___default = /*#__PURE__*/__webpack_require__.n(_locale_data_ca__WEBPACK_IMPORTED_MODULE_9__); /* harmony import */ var _locale_data_ckb__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./locale-data/ckb */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ckb.js"); /* harmony import */ var _locale_data_ckb__WEBPACK_IMPORTED_MODULE_10___default = /*#__PURE__*/__webpack_require__.n(_locale_data_ckb__WEBPACK_IMPORTED_MODULE_10__); /* harmony import */ var _locale_data_cs__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./locale-data/cs */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/cs.js"); /* harmony import */ var _locale_data_cs__WEBPACK_IMPORTED_MODULE_11___default = /*#__PURE__*/__webpack_require__.n(_locale_data_cs__WEBPACK_IMPORTED_MODULE_11__); /* harmony import */ var _locale_data_cy__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./locale-data/cy */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/cy.js"); /* harmony import */ var _locale_data_cy__WEBPACK_IMPORTED_MODULE_12___default = /*#__PURE__*/__webpack_require__.n(_locale_data_cy__WEBPACK_IMPORTED_MODULE_12__); /* harmony import */ var _locale_data_da__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./locale-data/da */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/da.js"); /* harmony import */ var _locale_data_da__WEBPACK_IMPORTED_MODULE_13___default = /*#__PURE__*/__webpack_require__.n(_locale_data_da__WEBPACK_IMPORTED_MODULE_13__); /* harmony import */ var _locale_data_de__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./locale-data/de */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/de.js"); /* harmony import */ var _locale_data_de__WEBPACK_IMPORTED_MODULE_14___default = /*#__PURE__*/__webpack_require__.n(_locale_data_de__WEBPACK_IMPORTED_MODULE_14__); /* harmony import */ var _locale_data_el__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./locale-data/el */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/el.js"); /* harmony import */ var _locale_data_el__WEBPACK_IMPORTED_MODULE_15___default = /*#__PURE__*/__webpack_require__.n(_locale_data_el__WEBPACK_IMPORTED_MODULE_15__); /* harmony import */ var _locale_data_eo__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./locale-data/eo */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/eo.js"); /* harmony import */ var _locale_data_eo__WEBPACK_IMPORTED_MODULE_16___default = /*#__PURE__*/__webpack_require__.n(_locale_data_eo__WEBPACK_IMPORTED_MODULE_16__); /* harmony import */ var _locale_data_es__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./locale-data/es */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/es.js"); /* harmony import */ var _locale_data_es__WEBPACK_IMPORTED_MODULE_17___default = /*#__PURE__*/__webpack_require__.n(_locale_data_es__WEBPACK_IMPORTED_MODULE_17__); /* harmony import */ var _locale_data_et__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./locale-data/et */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/et.js"); /* harmony import */ var _locale_data_et__WEBPACK_IMPORTED_MODULE_18___default = /*#__PURE__*/__webpack_require__.n(_locale_data_et__WEBPACK_IMPORTED_MODULE_18__); /* harmony import */ var _locale_data_eu__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./locale-data/eu */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/eu.js"); /* harmony import */ var _locale_data_eu__WEBPACK_IMPORTED_MODULE_19___default = /*#__PURE__*/__webpack_require__.n(_locale_data_eu__WEBPACK_IMPORTED_MODULE_19__); /* harmony import */ var _locale_data_fa__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./locale-data/fa */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/fa.js"); /* harmony import */ var _locale_data_fa__WEBPACK_IMPORTED_MODULE_20___default = /*#__PURE__*/__webpack_require__.n(_locale_data_fa__WEBPACK_IMPORTED_MODULE_20__); /* harmony import */ var _locale_data_fi__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ./locale-data/fi */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/fi.js"); /* harmony import */ var _locale_data_fi__WEBPACK_IMPORTED_MODULE_21___default = /*#__PURE__*/__webpack_require__.n(_locale_data_fi__WEBPACK_IMPORTED_MODULE_21__); /* harmony import */ var _locale_data_fil__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ./locale-data/fil */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/fil.js"); /* harmony import */ var _locale_data_fil__WEBPACK_IMPORTED_MODULE_22___default = /*#__PURE__*/__webpack_require__.n(_locale_data_fil__WEBPACK_IMPORTED_MODULE_22__); /* harmony import */ var _locale_data_fr__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ./locale-data/fr */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/fr.js"); /* harmony import */ var _locale_data_fr__WEBPACK_IMPORTED_MODULE_23___default = /*#__PURE__*/__webpack_require__.n(_locale_data_fr__WEBPACK_IMPORTED_MODULE_23__); /* harmony import */ var _locale_data_fy__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! ./locale-data/fy */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/fy.js"); /* harmony import */ var _locale_data_fy__WEBPACK_IMPORTED_MODULE_24___default = /*#__PURE__*/__webpack_require__.n(_locale_data_fy__WEBPACK_IMPORTED_MODULE_24__); /* harmony import */ var _locale_data_ga__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! ./locale-data/ga */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ga.js"); /* harmony import */ var _locale_data_ga__WEBPACK_IMPORTED_MODULE_25___default = /*#__PURE__*/__webpack_require__.n(_locale_data_ga__WEBPACK_IMPORTED_MODULE_25__); /* harmony import */ var _locale_data_gd__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! ./locale-data/gd */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/gd.js"); /* harmony import */ var _locale_data_gd__WEBPACK_IMPORTED_MODULE_26___default = /*#__PURE__*/__webpack_require__.n(_locale_data_gd__WEBPACK_IMPORTED_MODULE_26__); /* harmony import */ var _locale_data_gl__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! ./locale-data/gl */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/gl.js"); /* harmony import */ var _locale_data_gl__WEBPACK_IMPORTED_MODULE_27___default = /*#__PURE__*/__webpack_require__.n(_locale_data_gl__WEBPACK_IMPORTED_MODULE_27__); /* harmony import */ var _locale_data_ha__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(/*! ./locale-data/ha */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ha.js"); /* harmony import */ var _locale_data_ha__WEBPACK_IMPORTED_MODULE_28___default = /*#__PURE__*/__webpack_require__.n(_locale_data_ha__WEBPACK_IMPORTED_MODULE_28__); /* harmony import */ var _locale_data_he__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(/*! ./locale-data/he */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/he.js"); /* harmony import */ var _locale_data_he__WEBPACK_IMPORTED_MODULE_29___default = /*#__PURE__*/__webpack_require__.n(_locale_data_he__WEBPACK_IMPORTED_MODULE_29__); /* harmony import */ var _locale_data_hu__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(/*! ./locale-data/hu */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/hu.js"); /* harmony import */ var _locale_data_hu__WEBPACK_IMPORTED_MODULE_30___default = /*#__PURE__*/__webpack_require__.n(_locale_data_hu__WEBPACK_IMPORTED_MODULE_30__); /* harmony import */ var _locale_data_hr__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(/*! ./locale-data/hr */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/hr.js"); /* harmony import */ var _locale_data_hr__WEBPACK_IMPORTED_MODULE_31___default = /*#__PURE__*/__webpack_require__.n(_locale_data_hr__WEBPACK_IMPORTED_MODULE_31__); /* harmony import */ var _locale_data_hy__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! ./locale-data/hy */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/hy.js"); /* harmony import */ var _locale_data_hy__WEBPACK_IMPORTED_MODULE_32___default = /*#__PURE__*/__webpack_require__.n(_locale_data_hy__WEBPACK_IMPORTED_MODULE_32__); /* harmony import */ var _locale_data_id__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(/*! ./locale-data/id */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/id.js"); /* harmony import */ var _locale_data_id__WEBPACK_IMPORTED_MODULE_33___default = /*#__PURE__*/__webpack_require__.n(_locale_data_id__WEBPACK_IMPORTED_MODULE_33__); /* harmony import */ var _locale_data_is__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(/*! ./locale-data/is */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/is.js"); /* harmony import */ var _locale_data_is__WEBPACK_IMPORTED_MODULE_34___default = /*#__PURE__*/__webpack_require__.n(_locale_data_is__WEBPACK_IMPORTED_MODULE_34__); /* harmony import */ var _locale_data_it__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(/*! ./locale-data/it */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/it.js"); /* harmony import */ var _locale_data_it__WEBPACK_IMPORTED_MODULE_35___default = /*#__PURE__*/__webpack_require__.n(_locale_data_it__WEBPACK_IMPORTED_MODULE_35__); /* harmony import */ var _locale_data_ja__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(/*! ./locale-data/ja */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ja.js"); /* harmony import */ var _locale_data_ja__WEBPACK_IMPORTED_MODULE_36___default = /*#__PURE__*/__webpack_require__.n(_locale_data_ja__WEBPACK_IMPORTED_MODULE_36__); /* harmony import */ var _locale_data_ka__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(/*! ./locale-data/ka */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ka.js"); /* harmony import */ var _locale_data_ka__WEBPACK_IMPORTED_MODULE_37___default = /*#__PURE__*/__webpack_require__.n(_locale_data_ka__WEBPACK_IMPORTED_MODULE_37__); /* harmony import */ var _locale_data_kk__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(/*! ./locale-data/kk */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/kk.js"); /* harmony import */ var _locale_data_kk__WEBPACK_IMPORTED_MODULE_38___default = /*#__PURE__*/__webpack_require__.n(_locale_data_kk__WEBPACK_IMPORTED_MODULE_38__); /* harmony import */ var _locale_data_ko__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(/*! ./locale-data/ko */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ko.js"); /* harmony import */ var _locale_data_ko__WEBPACK_IMPORTED_MODULE_39___default = /*#__PURE__*/__webpack_require__.n(_locale_data_ko__WEBPACK_IMPORTED_MODULE_39__); /* harmony import */ var _locale_data_km__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(/*! ./locale-data/km */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/km.js"); /* harmony import */ var _locale_data_km__WEBPACK_IMPORTED_MODULE_40___default = /*#__PURE__*/__webpack_require__.n(_locale_data_km__WEBPACK_IMPORTED_MODULE_40__); /* harmony import */ var _locale_data_ku__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(/*! ./locale-data/ku */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ku.js"); /* harmony import */ var _locale_data_ku__WEBPACK_IMPORTED_MODULE_41___default = /*#__PURE__*/__webpack_require__.n(_locale_data_ku__WEBPACK_IMPORTED_MODULE_41__); /* harmony import */ var _locale_data_lt__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(/*! ./locale-data/lt */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/lt.js"); /* harmony import */ var _locale_data_lt__WEBPACK_IMPORTED_MODULE_42___default = /*#__PURE__*/__webpack_require__.n(_locale_data_lt__WEBPACK_IMPORTED_MODULE_42__); /* harmony import */ var _locale_data_lv__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(/*! ./locale-data/lv */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/lv.js"); /* harmony import */ var _locale_data_lv__WEBPACK_IMPORTED_MODULE_43___default = /*#__PURE__*/__webpack_require__.n(_locale_data_lv__WEBPACK_IMPORTED_MODULE_43__); /* harmony import */ var _locale_data_mi__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(/*! ./locale-data/mi */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/mi.js"); /* harmony import */ var _locale_data_mi__WEBPACK_IMPORTED_MODULE_44___default = /*#__PURE__*/__webpack_require__.n(_locale_data_mi__WEBPACK_IMPORTED_MODULE_44__); /* harmony import */ var _locale_data_mn__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(/*! ./locale-data/mn */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/mn.js"); /* harmony import */ var _locale_data_mn__WEBPACK_IMPORTED_MODULE_45___default = /*#__PURE__*/__webpack_require__.n(_locale_data_mn__WEBPACK_IMPORTED_MODULE_45__); /* harmony import */ var _locale_data_nl__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(/*! ./locale-data/nl */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/nl.js"); /* harmony import */ var _locale_data_nl__WEBPACK_IMPORTED_MODULE_46___default = /*#__PURE__*/__webpack_require__.n(_locale_data_nl__WEBPACK_IMPORTED_MODULE_46__); /* harmony import */ var _locale_data_nb__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(/*! ./locale-data/nb */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/nb.js"); /* harmony import */ var _locale_data_nb__WEBPACK_IMPORTED_MODULE_47___default = /*#__PURE__*/__webpack_require__.n(_locale_data_nb__WEBPACK_IMPORTED_MODULE_47__); /* harmony import */ var _locale_data_nn__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(/*! ./locale-data/nn */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/nn.js"); /* harmony import */ var _locale_data_nn__WEBPACK_IMPORTED_MODULE_48___default = /*#__PURE__*/__webpack_require__.n(_locale_data_nn__WEBPACK_IMPORTED_MODULE_48__); /* harmony import */ var _locale_data_nso__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(/*! ./locale-data/nso */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/nso.js"); /* harmony import */ var _locale_data_nso__WEBPACK_IMPORTED_MODULE_49___default = /*#__PURE__*/__webpack_require__.n(_locale_data_nso__WEBPACK_IMPORTED_MODULE_49__); /* harmony import */ var _locale_data_or__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(/*! ./locale-data/or */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/or.js"); /* harmony import */ var _locale_data_or__WEBPACK_IMPORTED_MODULE_50___default = /*#__PURE__*/__webpack_require__.n(_locale_data_or__WEBPACK_IMPORTED_MODULE_50__); /* harmony import */ var _locale_data_pl__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(/*! ./locale-data/pl */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/pl.js"); /* harmony import */ var _locale_data_pl__WEBPACK_IMPORTED_MODULE_51___default = /*#__PURE__*/__webpack_require__.n(_locale_data_pl__WEBPACK_IMPORTED_MODULE_51__); /* harmony import */ var _locale_data_pt__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(/*! ./locale-data/pt */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/pt.js"); /* harmony import */ var _locale_data_pt__WEBPACK_IMPORTED_MODULE_52___default = /*#__PURE__*/__webpack_require__.n(_locale_data_pt__WEBPACK_IMPORTED_MODULE_52__); /* harmony import */ var _locale_data_qu__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(/*! ./locale-data/qu */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/qu.js"); /* harmony import */ var _locale_data_qu__WEBPACK_IMPORTED_MODULE_53___default = /*#__PURE__*/__webpack_require__.n(_locale_data_qu__WEBPACK_IMPORTED_MODULE_53__); /* harmony import */ var _locale_data_ro__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(/*! ./locale-data/ro */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ro.js"); /* harmony import */ var _locale_data_ro__WEBPACK_IMPORTED_MODULE_54___default = /*#__PURE__*/__webpack_require__.n(_locale_data_ro__WEBPACK_IMPORTED_MODULE_54__); /* harmony import */ var _locale_data_ru__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(/*! ./locale-data/ru */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ru.js"); /* harmony import */ var _locale_data_ru__WEBPACK_IMPORTED_MODULE_55___default = /*#__PURE__*/__webpack_require__.n(_locale_data_ru__WEBPACK_IMPORTED_MODULE_55__); /* harmony import */ var _locale_data_sl__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(/*! ./locale-data/sl */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/sl.js"); /* harmony import */ var _locale_data_sl__WEBPACK_IMPORTED_MODULE_56___default = /*#__PURE__*/__webpack_require__.n(_locale_data_sl__WEBPACK_IMPORTED_MODULE_56__); /* harmony import */ var _locale_data_sk__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(/*! ./locale-data/sk */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/sk.js"); /* harmony import */ var _locale_data_sk__WEBPACK_IMPORTED_MODULE_57___default = /*#__PURE__*/__webpack_require__.n(_locale_data_sk__WEBPACK_IMPORTED_MODULE_57__); /* harmony import */ var _locale_data_sr__WEBPACK_IMPORTED_MODULE_58__ = __webpack_require__(/*! ./locale-data/sr */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/sr.js"); /* harmony import */ var _locale_data_sr__WEBPACK_IMPORTED_MODULE_58___default = /*#__PURE__*/__webpack_require__.n(_locale_data_sr__WEBPACK_IMPORTED_MODULE_58__); /* harmony import */ var _locale_data_sv__WEBPACK_IMPORTED_MODULE_59__ = __webpack_require__(/*! ./locale-data/sv */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/sv.js"); /* harmony import */ var _locale_data_sv__WEBPACK_IMPORTED_MODULE_59___default = /*#__PURE__*/__webpack_require__.n(_locale_data_sv__WEBPACK_IMPORTED_MODULE_59__); /* harmony import */ var _locale_data_sw__WEBPACK_IMPORTED_MODULE_60__ = __webpack_require__(/*! ./locale-data/sw */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/sw.js"); /* harmony import */ var _locale_data_sw__WEBPACK_IMPORTED_MODULE_60___default = /*#__PURE__*/__webpack_require__.n(_locale_data_sw__WEBPACK_IMPORTED_MODULE_60__); /* harmony import */ var _locale_data_th__WEBPACK_IMPORTED_MODULE_61__ = __webpack_require__(/*! ./locale-data/th */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/th.js"); /* harmony import */ var _locale_data_th__WEBPACK_IMPORTED_MODULE_61___default = /*#__PURE__*/__webpack_require__.n(_locale_data_th__WEBPACK_IMPORTED_MODULE_61__); /* harmony import */ var _locale_data_tr__WEBPACK_IMPORTED_MODULE_62__ = __webpack_require__(/*! ./locale-data/tr */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/tr.js"); /* harmony import */ var _locale_data_tr__WEBPACK_IMPORTED_MODULE_62___default = /*#__PURE__*/__webpack_require__.n(_locale_data_tr__WEBPACK_IMPORTED_MODULE_62__); /* harmony import */ var _locale_data_tn__WEBPACK_IMPORTED_MODULE_63__ = __webpack_require__(/*! ./locale-data/tn */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/tn.js"); /* harmony import */ var _locale_data_tn__WEBPACK_IMPORTED_MODULE_63___default = /*#__PURE__*/__webpack_require__.n(_locale_data_tn__WEBPACK_IMPORTED_MODULE_63__); /* harmony import */ var _locale_data_uk__WEBPACK_IMPORTED_MODULE_64__ = __webpack_require__(/*! ./locale-data/uk */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/uk.js"); /* harmony import */ var _locale_data_uk__WEBPACK_IMPORTED_MODULE_64___default = /*#__PURE__*/__webpack_require__.n(_locale_data_uk__WEBPACK_IMPORTED_MODULE_64__); /* harmony import */ var _locale_data_uz__WEBPACK_IMPORTED_MODULE_65__ = __webpack_require__(/*! ./locale-data/uz */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/uz.js"); /* harmony import */ var _locale_data_uz__WEBPACK_IMPORTED_MODULE_65___default = /*#__PURE__*/__webpack_require__.n(_locale_data_uz__WEBPACK_IMPORTED_MODULE_65__); /* harmony import */ var _locale_data_vi__WEBPACK_IMPORTED_MODULE_66__ = __webpack_require__(/*! ./locale-data/vi */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/vi.js"); /* harmony import */ var _locale_data_vi__WEBPACK_IMPORTED_MODULE_66___default = /*#__PURE__*/__webpack_require__.n(_locale_data_vi__WEBPACK_IMPORTED_MODULE_66__); /* harmony import */ var _locale_data_xh__WEBPACK_IMPORTED_MODULE_67__ = __webpack_require__(/*! ./locale-data/xh */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/xh.js"); /* harmony import */ var _locale_data_xh__WEBPACK_IMPORTED_MODULE_67___default = /*#__PURE__*/__webpack_require__.n(_locale_data_xh__WEBPACK_IMPORTED_MODULE_67__); /* harmony import */ var _locale_data_zh__WEBPACK_IMPORTED_MODULE_68__ = __webpack_require__(/*! ./locale-data/zh */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/zh.js"); /* harmony import */ var _locale_data_zh__WEBPACK_IMPORTED_MODULE_68___default = /*#__PURE__*/__webpack_require__.n(_locale_data_zh__WEBPACK_IMPORTED_MODULE_68__); /* harmony import */ var _locale_data_zu__WEBPACK_IMPORTED_MODULE_69__ = __webpack_require__(/*! ./locale-data/zu */ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/zu.js"); /* harmony import */ var _locale_data_zu__WEBPACK_IMPORTED_MODULE_69___default = /*#__PURE__*/__webpack_require__.n(_locale_data_zu__WEBPACK_IMPORTED_MODULE_69__); /* harmony import */ var _supported_locales_js__WEBPACK_IMPORTED_MODULE_70__ = __webpack_require__(/*! ./supported-locales.js */ "./node_modules/@turbowarp/scratch-l10n/src/supported-locales.js"); // temporarily we have all the locale data in scratch-l10n let localeData = [].concat( _locale_data_en__WEBPACK_IMPORTED_MODULE_0___default.a, _locale_data_af__WEBPACK_IMPORTED_MODULE_1___default.a, _locale_data_am__WEBPACK_IMPORTED_MODULE_2___default.a, _locale_data_ar__WEBPACK_IMPORTED_MODULE_3___default.a, _locale_data_ast__WEBPACK_IMPORTED_MODULE_4___default.a, _locale_data_az__WEBPACK_IMPORTED_MODULE_5___default.a, _locale_data_be__WEBPACK_IMPORTED_MODULE_6___default.a, _locale_data_bg__WEBPACK_IMPORTED_MODULE_8___default.a, _locale_data_bn__WEBPACK_IMPORTED_MODULE_7___default.a, _locale_data_ca__WEBPACK_IMPORTED_MODULE_9___default.a, _locale_data_ckb__WEBPACK_IMPORTED_MODULE_10___default.a, _locale_data_cs__WEBPACK_IMPORTED_MODULE_11___default.a, _locale_data_cy__WEBPACK_IMPORTED_MODULE_12___default.a, _locale_data_da__WEBPACK_IMPORTED_MODULE_13___default.a, _locale_data_de__WEBPACK_IMPORTED_MODULE_14___default.a, _locale_data_el__WEBPACK_IMPORTED_MODULE_15___default.a, _locale_data_eo__WEBPACK_IMPORTED_MODULE_16___default.a, _locale_data_es__WEBPACK_IMPORTED_MODULE_17___default.a, _locale_data_et__WEBPACK_IMPORTED_MODULE_18___default.a, _locale_data_eu__WEBPACK_IMPORTED_MODULE_19___default.a, _locale_data_fa__WEBPACK_IMPORTED_MODULE_20___default.a, _locale_data_fi__WEBPACK_IMPORTED_MODULE_21___default.a, _locale_data_fil__WEBPACK_IMPORTED_MODULE_22___default.a, _locale_data_fr__WEBPACK_IMPORTED_MODULE_23___default.a, _locale_data_fy__WEBPACK_IMPORTED_MODULE_24___default.a, _locale_data_ga__WEBPACK_IMPORTED_MODULE_25___default.a, _locale_data_gd__WEBPACK_IMPORTED_MODULE_26___default.a, _locale_data_gl__WEBPACK_IMPORTED_MODULE_27___default.a, _locale_data_ha__WEBPACK_IMPORTED_MODULE_28___default.a, _locale_data_he__WEBPACK_IMPORTED_MODULE_29___default.a, _locale_data_hu__WEBPACK_IMPORTED_MODULE_30___default.a, _locale_data_hr__WEBPACK_IMPORTED_MODULE_31___default.a, _locale_data_hy__WEBPACK_IMPORTED_MODULE_32___default.a, _locale_data_id__WEBPACK_IMPORTED_MODULE_33___default.a, _locale_data_is__WEBPACK_IMPORTED_MODULE_34___default.a, _locale_data_it__WEBPACK_IMPORTED_MODULE_35___default.a, _locale_data_ja__WEBPACK_IMPORTED_MODULE_36___default.a, _locale_data_ka__WEBPACK_IMPORTED_MODULE_37___default.a, _locale_data_kk__WEBPACK_IMPORTED_MODULE_38___default.a, _locale_data_ko__WEBPACK_IMPORTED_MODULE_39___default.a, _locale_data_km__WEBPACK_IMPORTED_MODULE_40___default.a, _locale_data_ku__WEBPACK_IMPORTED_MODULE_41___default.a, _locale_data_lt__WEBPACK_IMPORTED_MODULE_42___default.a, _locale_data_lv__WEBPACK_IMPORTED_MODULE_43___default.a, _locale_data_mi__WEBPACK_IMPORTED_MODULE_44___default.a, _locale_data_mn__WEBPACK_IMPORTED_MODULE_45___default.a, _locale_data_nl__WEBPACK_IMPORTED_MODULE_46___default.a, _locale_data_nb__WEBPACK_IMPORTED_MODULE_47___default.a, _locale_data_nn__WEBPACK_IMPORTED_MODULE_48___default.a, _locale_data_nso__WEBPACK_IMPORTED_MODULE_49___default.a, _locale_data_or__WEBPACK_IMPORTED_MODULE_50___default.a, _locale_data_pl__WEBPACK_IMPORTED_MODULE_51___default.a, _locale_data_pt__WEBPACK_IMPORTED_MODULE_52___default.a, _locale_data_sl__WEBPACK_IMPORTED_MODULE_56___default.a, _locale_data_sk__WEBPACK_IMPORTED_MODULE_57___default.a, _locale_data_sr__WEBPACK_IMPORTED_MODULE_58___default.a, _locale_data_sv__WEBPACK_IMPORTED_MODULE_59___default.a, _locale_data_sw__WEBPACK_IMPORTED_MODULE_60___default.a, _locale_data_qu__WEBPACK_IMPORTED_MODULE_53___default.a, _locale_data_ro__WEBPACK_IMPORTED_MODULE_54___default.a, _locale_data_ru__WEBPACK_IMPORTED_MODULE_55___default.a, _locale_data_th__WEBPACK_IMPORTED_MODULE_61___default.a, _locale_data_tn__WEBPACK_IMPORTED_MODULE_63___default.a, _locale_data_tr__WEBPACK_IMPORTED_MODULE_62___default.a, _locale_data_uk__WEBPACK_IMPORTED_MODULE_64___default.a, _locale_data_uz__WEBPACK_IMPORTED_MODULE_65___default.a, _locale_data_vi__WEBPACK_IMPORTED_MODULE_66___default.a, _locale_data_xh__WEBPACK_IMPORTED_MODULE_67___default.a, _locale_data_zh__WEBPACK_IMPORTED_MODULE_68___default.a, _locale_data_zu__WEBPACK_IMPORTED_MODULE_69___default.a ); for (const lang in _supported_locales_js__WEBPACK_IMPORTED_MODULE_70__["customLocales"]) { localeData.push(_supported_locales_js__WEBPACK_IMPORTED_MODULE_70__["customLocales"][lang]); } /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/af.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/af.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,a){ true?module.exports=a():undefined}(this,function(){"use strict";return[{locale:"af",pluralRuleFunction:function(e,a){return a?"other":1==e?"one":"other"},fields:{year:{displayName:"jaar",relative:{0:"hierdie jaar",1:"volgende jaar","-1":"verlede jaar"},relativeTime:{future:{one:"oor {0} jaar",other:"oor {0} jaar"},past:{one:"{0} jaar gelede",other:"{0} jaar gelede"}}},"year-short":{displayName:"j.",relative:{0:"hierdie jaar",1:"volgende jaar","-1":"verlede jaar"},relativeTime:{future:{one:"oor {0} j.",other:"oor {0} j."},past:{one:"{0} j. gelede",other:"{0} j. gelede"}}},month:{displayName:"maand",relative:{0:"vandeesmaand",1:"volgende maand","-1":"verlede maand"},relativeTime:{future:{one:"oor {0} maand",other:"oor {0} maande"},past:{one:"{0} maand gelede",other:"{0} maande gelede"}}},"month-short":{displayName:"md.",relative:{0:"vandeesmaand",1:"volgende maand","-1":"verlede maand"},relativeTime:{future:{one:"oor {0} md.",other:"oor {0} md."},past:{one:"{0} md. gelede",other:"{0} md. gelede"}}},day:{displayName:"dag",relative:{0:"vandag",1:"môre",2:"oormôre","-2":"eergister","-1":"gister"},relativeTime:{future:{one:"oor {0} dag",other:"oor {0} dae"},past:{one:"{0} dag gelede",other:"{0} dae gelede"}}},"day-short":{displayName:"d.",relative:{0:"vandag",1:"môre",2:"oormôre","-2":"eergister","-1":"gister"},relativeTime:{future:{one:"oor {0} dag",other:"oor {0} dae"},past:{one:"{0} dag gelede",other:"{0} dae gelede"}}},hour:{displayName:"uur",relative:{0:"hierdie uur"},relativeTime:{future:{one:"oor {0} uur",other:"oor {0} uur"},past:{one:"{0} uur gelede",other:"{0} uur gelede"}}},"hour-short":{displayName:"u.",relative:{0:"hierdie uur"},relativeTime:{future:{one:"oor {0} u.",other:"oor {0} u."},past:{one:"{0} u. gelede",other:"{0} u. gelede"}}},minute:{displayName:"minuut",relative:{0:"hierdie minuut"},relativeTime:{future:{one:"oor {0} minuut",other:"oor {0} minute"},past:{one:"{0} minuut gelede",other:"{0} minute gelede"}}},"minute-short":{displayName:"min.",relative:{0:"hierdie minuut"},relativeTime:{future:{one:"oor {0} min.",other:"oor {0} min."},past:{one:"{0} min. gelede",other:"{0} min. gelede"}}},second:{displayName:"sekonde",relative:{0:"nou"},relativeTime:{future:{one:"oor {0} sekonde",other:"oor {0} sekondes"},past:{one:"{0} sekonde gelede",other:"{0} sekondes gelede"}}},"second-short":{displayName:"s.",relative:{0:"nou"},relativeTime:{future:{one:"oor {0} s.",other:"oor {0} s."},past:{one:"{0} s. gelede",other:"{0} s. gelede"}}}}},{locale:"af-NA",parentLocale:"af"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/am.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/am.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"am",pluralRuleFunction:function(e,t){return t?"other":e>=0&&e<=1?"one":"other"},fields:{year:{displayName:"ዓመት",relative:{0:"በዚህ ዓመት",1:"የሚቀጥለው ዓመት","-1":"ያለፈው ዓመት"},relativeTime:{future:{one:"በ{0} ዓመታት ውስጥ",other:"በ{0} ዓመታት ውስጥ"},past:{one:"ከ{0} ዓመት በፊት",other:"ከ{0} ዓመታት በፊት"}}},"year-short":{displayName:"ዓመት",relative:{0:"በዚህ ዓመት",1:"የሚቀጥለው ዓመት","-1":"ያለፈው ዓመት"},relativeTime:{future:{one:"በ{0} ዓመታት ውስጥ",other:"በ{0} ዓመታት ውስጥ"},past:{one:"ከ{0} ዓመታት በፊት",other:"ከ{0} ዓመታት በፊት"}}},month:{displayName:"ወር",relative:{0:"በዚህ ወር",1:"የሚቀጥለው ወር","-1":"ያለፈው ወር"},relativeTime:{future:{one:"በ{0} ወር ውስጥ",other:"በ{0} ወራት ውስጥ"},past:{one:"ከ{0} ወር በፊት",other:"ከ{0} ወራት በፊት"}}},"month-short":{displayName:"ወር",relative:{0:"በዚህ ወር",1:"የሚቀጥለው ወር","-1":"ያለፈው ወር"},relativeTime:{future:{one:"በ{0} ወራት ውስጥ",other:"በ{0} ወራት ውስጥ"},past:{one:"ከ{0} ወራት በፊት",other:"ከ{0} ወራት በፊት"}}},day:{displayName:"ቀን",relative:{0:"ዛሬ",1:"ነገ",2:"ከነገ ወዲያ","-2":"ከትናንት ወዲያ","-1":"ትናንት"},relativeTime:{future:{one:"በ{0} ቀን ውስጥ",other:"በ{0} ቀናት ውስጥ"},past:{one:"ከ{0} ቀን በፊት",other:"ከ{0} ቀናት በፊት"}}},"day-short":{displayName:"ቀን",relative:{0:"ዛሬ",1:"ነገ",2:"ከነገ ወዲያ","-2":"ከትናንት ወዲያ","-1":"ትላንትና"},relativeTime:{future:{one:"በ{0} ቀን ውስጥ",other:"በ{0} ቀኖች ውስጥ"},past:{one:"ከ {0} ቀን በፊት",other:"ከ{0} ቀኖች በፊት"}}},hour:{displayName:"ሰዓት",relative:{0:"ይህ ሰዓት"},relativeTime:{future:{one:"በ{0} ሰዓት ውስጥ",other:"በ{0} ሰዓቶች ውስጥ"},past:{one:"ከ{0} ሰዓት በፊት",other:"ከ{0} ሰዓቶች በፊት"}}},"hour-short":{displayName:"ሰዓት",relative:{0:"ይህ ሰዓት"},relativeTime:{future:{one:"በ{0} ሰዓት ውስጥ",other:"በ{0} ሰዓቶች ውስጥ"},past:{one:"ከ{0} ሰዓት በፊት",other:"ከ{0} ሰዓቶች በፊት"}}},minute:{displayName:"ደቂቃ",relative:{0:"ይህ ደቂቃ"},relativeTime:{future:{one:"በ{0} ደቂቃ ውስጥ",other:"በ{0} ደቂቃዎች ውስጥ"},past:{one:"ከ{0} ደቂቃ በፊት",other:"ከ{0} ደቂቃዎች በፊት"}}},"minute-short":{displayName:"ደቂቃ",relative:{0:"ይህ ደቂቃ"},relativeTime:{future:{one:"በ{0} ደቂቃ ውስጥ",other:"በ{0} ደቂቃዎች ውስጥ"},past:{one:"ከ{0} ደቂቃ በፊት",other:"ከ{0} ደቂቃዎች በፊት"}}},second:{displayName:"ሰከንድ",relative:{0:"አሁን"},relativeTime:{future:{one:"በ{0} ሰከንድ ውስጥ",other:"በ{0} ሰከንዶች ውስጥ"},past:{one:"ከ{0} ሰከንድ በፊት",other:"ከ{0} ሰከንዶች በፊት"}}},"second-short":{displayName:"ሰከንድ",relative:{0:"አሁን"},relativeTime:{future:{one:"በ{0} ሰከንድ ውስጥ",other:"በ{0} ሰከንዶች ውስጥ"},past:{one:"ከ{0} ሰከንድ በፊት",other:"ከ{0} ሰከንዶች በፊት"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ar.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/ar.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,a){ true?module.exports=a():undefined}(this,function(){"use strict";return[{locale:"ar",pluralRuleFunction:function(e,a){var o=String(e).split("."),r=Number(o[0])==e&&o[0].slice(-2);return a?"other":0==e?"zero":1==e?"one":2==e?"two":r>=3&&r<=10?"few":r>=11&&r<=99?"many":"other"},fields:{year:{displayName:"السنة",relative:{0:"السنة الحالية",1:"السنة القادمة","-1":"السنة الماضية"},relativeTime:{future:{zero:"خلال {0} سنة",one:"خلال سنة واحدة",two:"خلال سنتين",few:"خلال {0} سنوات",many:"خلال {0} سنة",other:"خلال {0} سنة"},past:{zero:"قبل {0} سنة",one:"قبل سنة واحدة",two:"قبل سنتين",few:"قبل {0} سنوات",many:"قبل {0} سنة",other:"قبل {0} سنة"}}},"year-short":{displayName:"السنة",relative:{0:"السنة الحالية",1:"السنة القادمة","-1":"السنة الماضية"},relativeTime:{future:{zero:"خلال {0} سنة",one:"خلال سنة واحدة",two:"خلال سنتين",few:"خلال {0} سنوات",many:"خلال {0} سنة",other:"خلال {0} سنة"},past:{zero:"قبل {0} سنة",one:"قبل سنة واحدة",two:"قبل سنتين",few:"قبل {0} سنوات",many:"قبل {0} سنة",other:"قبل {0} سنة"}}},month:{displayName:"الشهر",relative:{0:"هذا الشهر",1:"الشهر القادم","-1":"الشهر الماضي"},relativeTime:{future:{zero:"خلال {0} شهر",one:"خلال شهر واحد",two:"خلال شهرين",few:"خلال {0} أشهر",many:"خلال {0} شهرًا",other:"خلال {0} شهر"},past:{zero:"قبل {0} شهر",one:"قبل شهر واحد",two:"قبل شهرين",few:"قبل {0} أشهر",many:"قبل {0} شهرًا",other:"قبل {0} شهر"}}},"month-short":{displayName:"الشهر",relative:{0:"هذا الشهر",1:"الشهر القادم","-1":"الشهر الماضي"},relativeTime:{future:{zero:"خلال {0} شهر",one:"خلال شهر واحد",two:"خلال شهرين",few:"خلال {0} أشهر",many:"خلال {0} شهرًا",other:"خلال {0} شهر"},past:{zero:"قبل {0} شهر",one:"قبل شهر واحد",two:"قبل شهرين",few:"خلال {0} أشهر",many:"قبل {0} شهرًا",other:"قبل {0} شهر"}}},day:{displayName:"يوم",relative:{0:"اليوم",1:"غدًا",2:"بعد الغد","-2":"أول أمس","-1":"أمس"},relativeTime:{future:{zero:"خلال {0} يوم",one:"خلال يوم واحد",two:"خلال يومين",few:"خلال {0} أيام",many:"خلال {0} يومًا",other:"خلال {0} يوم"},past:{zero:"قبل {0} يوم",one:"قبل يوم واحد",two:"قبل يومين",few:"قبل {0} أيام",many:"قبل {0} يومًا",other:"قبل {0} يوم"}}},"day-short":{displayName:"يوم",relative:{0:"اليوم",1:"غدًا",2:"بعد الغد","-2":"أول أمس","-1":"أمس"},relativeTime:{future:{zero:"خلال {0} يوم",one:"خلال يوم واحد",two:"خلال يومين",few:"خلال {0} أيام",many:"خلال {0} يومًا",other:"خلال {0} يوم"},past:{zero:"قبل {0} يوم",one:"قبل يوم واحد",two:"قبل يومين",few:"قبل {0} أيام",many:"قبل {0} يومًا",other:"قبل {0} يوم"}}},hour:{displayName:"الساعات",relative:{0:"الساعة الحالية"},relativeTime:{future:{zero:"خلال {0} ساعة",one:"خلال ساعة واحدة",two:"خلال ساعتين",few:"خلال {0} ساعات",many:"خلال {0} ساعة",other:"خلال {0} ساعة"},past:{zero:"قبل {0} ساعة",one:"قبل ساعة واحدة",two:"قبل ساعتين",few:"قبل {0} ساعات",many:"قبل {0} ساعة",other:"قبل {0} ساعة"}}},"hour-short":{displayName:"الساعات",relative:{0:"الساعة الحالية"},relativeTime:{future:{zero:"خلال {0} ساعة",one:"خلال ساعة واحدة",two:"خلال ساعتين",few:"خلال {0} ساعات",many:"خلال {0} ساعة",other:"خلال {0} ساعة"},past:{zero:"قبل {0} ساعة",one:"قبل ساعة واحدة",two:"قبل ساعتين",few:"قبل {0} ساعات",many:"قبل {0} ساعة",other:"قبل {0} ساعة"}}},minute:{displayName:"الدقائق",relative:{0:"هذه الدقيقة"},relativeTime:{future:{zero:"خلال {0} دقيقة",one:"خلال دقيقة واحدة",two:"خلال دقيقتين",few:"خلال {0} دقائق",many:"خلال {0} دقيقة",other:"خلال {0} دقيقة"},past:{zero:"قبل {0} دقيقة",one:"قبل دقيقة واحدة",two:"قبل دقيقتين",few:"قبل {0} دقائق",many:"قبل {0} دقيقة",other:"قبل {0} دقيقة"}}},"minute-short":{displayName:"الدقائق",relative:{0:"هذه الدقيقة"},relativeTime:{future:{zero:"خلال {0} دقيقة",one:"خلال دقيقة واحدة",two:"خلال دقيقتين",few:"خلال {0} دقائق",many:"خلال {0} دقيقة",other:"خلال {0} دقيقة"},past:{zero:"قبل {0} دقيقة",one:"قبل دقيقة واحدة",two:"قبل دقيقتين",few:"قبل {0} دقائق",many:"قبل {0} دقيقة",other:"قبل {0} دقيقة"}}},second:{displayName:"الثواني",relative:{0:"الآن"},relativeTime:{future:{zero:"خلال {0} ثانية",one:"خلال ثانية واحدة",two:"خلال ثانيتين",few:"خلال {0} ثوانٍ",many:"خلال {0} ثانية",other:"خلال {0} ثانية"},past:{zero:"قبل {0} ثانية",one:"قبل ثانية واحدة",two:"قبل ثانيتين",few:"قبل {0} ثوانِ",many:"قبل {0} ثانية",other:"قبل {0} ثانية"}}},"second-short":{displayName:"الثواني",relative:{0:"الآن"},relativeTime:{future:{zero:"خلال {0} ثانية",one:"خلال ثانية واحدة",two:"خلال ثانيتين",few:"خلال {0} ثوانٍ",many:"خلال {0} ثانية",other:"خلال {0} ثانية"},past:{zero:"قبل {0} ثانية",one:"قبل ثانية واحدة",two:"قبل ثانيتين",few:"قبل {0} ثوانٍ",many:"قبل {0} ثانية",other:"قبل {0} ثانية"}}}}},{locale:"ar-AE",parentLocale:"ar",fields:{year:{displayName:"السنة",relative:{0:"هذه السنة",1:"السنة التالية","-1":"السنة الماضية"},relativeTime:{future:{zero:"خلال {0} سنة",one:"خلال سنة واحدة",two:"خلال سنتين",few:"خلال {0} سنوات",many:"خلال {0} سنة",other:"خلال {0} سنة"},past:{zero:"قبل {0} سنة",one:"قبل سنة واحدة",two:"قبل سنتين",few:"قبل {0} سنوات",many:"قبل {0} سنة",other:"قبل {0} سنة"}}},"year-short":{displayName:"السنة",relative:{0:"هذه السنة",1:"السنة التالية","-1":"السنة الماضية"},relativeTime:{future:{zero:"خلال {0} سنة",one:"خلال سنة واحدة",two:"خلال سنتين",few:"خلال {0} سنوات",many:"خلال {0} سنة",other:"خلال {0} سنة"},past:{zero:"قبل {0} سنة",one:"قبل سنة واحدة",two:"قبل سنتين",few:"قبل {0} سنوات",many:"قبل {0} سنة",other:"قبل {0} سنة"}}},month:{displayName:"الشهر",relative:{0:"هذا الشهر",1:"الشهر القادم","-1":"الشهر الماضي"},relativeTime:{future:{zero:"خلال {0} شهر",one:"خلال شهر واحد",two:"خلال شهرين",few:"خلال {0} أشهر",many:"خلال {0} شهرًا",other:"خلال {0} شهر"},past:{zero:"قبل {0} شهر",one:"قبل شهر واحد",two:"قبل شهرين",few:"قبل {0} أشهر",many:"قبل {0} شهرًا",other:"قبل {0} شهر"}}},"month-short":{displayName:"الشهر",relative:{0:"هذا الشهر",1:"الشهر القادم","-1":"الشهر الماضي"},relativeTime:{future:{zero:"خلال {0} شهر",one:"خلال شهر واحد",two:"خلال شهرين",few:"خلال {0} أشهر",many:"خلال {0} شهرًا",other:"خلال {0} شهر"},past:{zero:"قبل {0} شهر",one:"قبل شهر واحد",two:"قبل شهرين",few:"خلال {0} أشهر",many:"قبل {0} شهرًا",other:"قبل {0} شهر"}}},day:{displayName:"يوم",relative:{0:"اليوم",1:"غدًا",2:"بعد الغد","-2":"أول أمس","-1":"أمس"},relativeTime:{future:{zero:"خلال {0} يوم",one:"خلال يوم واحد",two:"خلال يومين",few:"خلال {0} أيام",many:"خلال {0} يومًا",other:"خلال {0} يوم"},past:{zero:"قبل {0} يوم",one:"قبل يوم واحد",two:"قبل يومين",few:"قبل {0} أيام",many:"قبل {0} يومًا",other:"قبل {0} يوم"}}},"day-short":{displayName:"يوم",relative:{0:"اليوم",1:"غدًا",2:"بعد الغد","-2":"أول أمس","-1":"أمس"},relativeTime:{future:{zero:"خلال {0} يوم",one:"خلال يوم واحد",two:"خلال يومين",few:"خلال {0} أيام",many:"خلال {0} يومًا",other:"خلال {0} يوم"},past:{zero:"قبل {0} يوم",one:"قبل يوم واحد",two:"قبل يومين",few:"قبل {0} أيام",many:"قبل {0} يومًا",other:"قبل {0} يوم"}}},hour:{displayName:"الساعات",relative:{0:"الساعة الحالية"},relativeTime:{future:{zero:"خلال {0} ساعة",one:"خلال ساعة واحدة",two:"خلال ساعتين",few:"خلال {0} ساعات",many:"خلال {0} ساعة",other:"خلال {0} ساعة"},past:{zero:"قبل {0} ساعة",one:"قبل ساعة واحدة",two:"قبل ساعتين",few:"قبل {0} ساعات",many:"قبل {0} ساعة",other:"قبل {0} ساعة"}}},"hour-short":{displayName:"الساعات",relative:{0:"الساعة الحالية"},relativeTime:{future:{zero:"خلال {0} ساعة",one:"خلال ساعة واحدة",two:"خلال ساعتين",few:"خلال {0} ساعات",many:"خلال {0} ساعة",other:"خلال {0} ساعة"},past:{zero:"قبل {0} ساعة",one:"قبل ساعة واحدة",two:"قبل ساعتين",few:"قبل {0} ساعات",many:"قبل {0} ساعة",other:"قبل {0} ساعة"}}},minute:{displayName:"الدقائق",relative:{0:"هذه الدقيقة"},relativeTime:{future:{zero:"خلال {0} دقيقة",one:"خلال دقيقة واحدة",two:"خلال دقيقتين",few:"خلال {0} دقائق",many:"خلال {0} دقيقة",other:"خلال {0} دقيقة"},past:{zero:"قبل {0} دقيقة",one:"قبل دقيقة واحدة",two:"قبل دقيقتين",few:"قبل {0} دقائق",many:"قبل {0} دقيقة",other:"قبل {0} دقيقة"}}},"minute-short":{displayName:"الدقائق",relative:{0:"هذه الدقيقة"},relativeTime:{future:{zero:"خلال {0} دقيقة",one:"خلال دقيقة واحدة",two:"خلال دقيقتين",few:"خلال {0} دقائق",many:"خلال {0} دقيقة",other:"خلال {0} دقيقة"},past:{zero:"قبل {0} دقيقة",one:"قبل دقيقة واحدة",two:"قبل دقيقتين",few:"قبل {0} دقائق",many:"قبل {0} دقيقة",other:"قبل {0} دقيقة"}}},second:{displayName:"الثواني",relative:{0:"الآن"},relativeTime:{future:{zero:"خلال {0} ثانية",one:"خلال ثانية واحدة",two:"خلال ثانيتين",few:"خلال {0} ثوانٍ",many:"خلال {0} ثانية",other:"خلال {0} ثانية"},past:{zero:"قبل {0} ثانية",one:"قبل ثانية واحدة",two:"قبل ثانيتين",few:"قبل {0} ثوانِ",many:"قبل {0} ثانية",other:"قبل {0} ثانية"}}},"second-short":{displayName:"الثواني",relative:{0:"الآن"},relativeTime:{future:{zero:"خلال {0} ثانية",one:"خلال ثانية واحدة",two:"خلال ثانيتين",few:"خلال {0} ثوانٍ",many:"خلال {0} ثانية",other:"خلال {0} ثانية"},past:{zero:"قبل {0} ثانية",one:"قبل ثانية واحدة",two:"قبل ثانيتين",few:"قبل {0} ثوانٍ",many:"قبل {0} ثانية",other:"قبل {0} ثانية"}}}}},{locale:"ar-BH",parentLocale:"ar"},{locale:"ar-DJ",parentLocale:"ar"},{locale:"ar-DZ",parentLocale:"ar"},{locale:"ar-EG",parentLocale:"ar"},{locale:"ar-EH",parentLocale:"ar"},{locale:"ar-ER",parentLocale:"ar"},{locale:"ar-IL",parentLocale:"ar"},{locale:"ar-IQ",parentLocale:"ar"},{locale:"ar-JO",parentLocale:"ar"},{locale:"ar-KM",parentLocale:"ar"},{locale:"ar-KW",parentLocale:"ar"},{locale:"ar-LB",parentLocale:"ar"},{locale:"ar-LY",parentLocale:"ar"},{locale:"ar-MA",parentLocale:"ar"},{locale:"ar-MR",parentLocale:"ar"},{locale:"ar-OM",parentLocale:"ar"},{locale:"ar-PS",parentLocale:"ar"},{locale:"ar-QA",parentLocale:"ar"},{locale:"ar-SA",parentLocale:"ar"},{locale:"ar-SD",parentLocale:"ar"},{locale:"ar-SO",parentLocale:"ar"},{locale:"ar-SS",parentLocale:"ar"},{locale:"ar-SY",parentLocale:"ar"},{locale:"ar-TD",parentLocale:"ar"},{locale:"ar-TN",parentLocale:"ar"},{locale:"ar-YE",parentLocale:"ar"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ast.js": /*!*********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/ast.js ***! \*********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,a){ true?module.exports=a():undefined}(this,function(){"use strict";return[{locale:"ast",pluralRuleFunction:function(e,a){var t=!String(e).split(".")[1];return a?"other":1==e&&t?"one":"other"},fields:{year:{displayName:"añu",relative:{0:"esti añu",1:"l’añu viniente","-1":"l’añu pasáu"},relativeTime:{future:{one:"en {0} añu",other:"en {0} años"},past:{one:"hai {0} añu",other:"hai {0} años"}}},"year-short":{displayName:"añu",relative:{0:"esti añu",1:"l’añu vin.","-1":"l’añu pas."},relativeTime:{future:{one:"en {0} añu",other:"en {0} años"},past:{one:"hai {0} añu",other:"hai {0} años"}}},month:{displayName:"mes",relative:{0:"esti mes",1:"el mes viniente","-1":"el mes pasáu"},relativeTime:{future:{one:"en {0} mes",other:"en {0} meses"},past:{one:"hai {0} mes",other:"hai {0} meses"}}},"month-short":{displayName:"mes",relative:{0:"esti mes",1:"mes vin.","-1":"mes pas."},relativeTime:{future:{one:"en {0} mes",other:"en {0} meses"},past:{one:"hai {0} mes",other:"hai {0} meses"}}},day:{displayName:"día",relative:{0:"güei",1:"mañana",2:"pasao mañana","-2":"antayeri","-1":"ayeri"},relativeTime:{future:{one:"en {0} día",other:"en {0} díes"},past:{one:"hai {0} día",other:"hai {0} díes"}}},"day-short":{displayName:"día",relative:{0:"güei",1:"mañana",2:"pasao mañana","-2":"antayeri","-1":"ayeri"},relativeTime:{future:{one:"en {0} día",other:"en {0} díes"},past:{one:"hai {0} día",other:"hai {0} díes"}}},hour:{displayName:"hora",relative:{0:"esta hora"},relativeTime:{future:{one:"en {0} hora",other:"en {0} hores"},past:{one:"hai {0} hora",other:"hai {0} hores"}}},"hour-short":{displayName:"h.",relative:{0:"esta hora"},relativeTime:{future:{one:"en {0} h.",other:"en {0} h."},past:{one:"hai {0} h.",other:"hai {0} h."}}},minute:{displayName:"minutu",relative:{0:"esti minutu"},relativeTime:{future:{one:"en {0} minutu",other:"en {0} minutos"},past:{one:"hai {0} minutu",other:"hai {0} minutos"}}},"minute-short":{displayName:"min.",relative:{0:"esti min."},relativeTime:{future:{one:"en {0} min.",other:"en {0} min."},past:{one:"hai {0} min.",other:"hai {0} min."}}},second:{displayName:"segundu",relative:{0:"agora"},relativeTime:{future:{one:"en {0} segundu",other:"en {0} segundos"},past:{one:"hai {0} segundu",other:"hai {0} segundos"}}},"second-short":{displayName:"s.",relative:{0:"agora"},relativeTime:{future:{one:"en {0} seg.",other:"en {0} seg."},past:{one:"hai {0} seg.",other:"hai {0} seg."}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/az.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/az.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"az",pluralRuleFunction:function(e,t){var a=String(e).split(".")[0],r=a.slice(-1),i=a.slice(-2),o=a.slice(-3);return t?1==r||2==r||5==r||7==r||8==r||20==i||50==i||70==i||80==i?"one":3==r||4==r||100==o||200==o||300==o||400==o||500==o||600==o||700==o||800==o||900==o?"few":0==a||6==r||40==i||60==i||90==i?"many":"other":1==e?"one":"other"},fields:{year:{displayName:"İl",relative:{0:"bu il",1:"gələn il","-1":"keçən il"},relativeTime:{future:{one:"{0} il ərzində",other:"{0} il ərzində"},past:{one:"{0} il öncə",other:"{0} il öncə"}}},"year-short":{displayName:"il",relative:{0:"bu il",1:"gələn il","-1":"keçən il"},relativeTime:{future:{one:"{0} il ərzində",other:"{0} il ərzində"},past:{one:"{0} il öncə",other:"{0} il öncə"}}},month:{displayName:"Ay",relative:{0:"bu ay",1:"gələn ay","-1":"keçən ay"},relativeTime:{future:{one:"{0} ay ərzində",other:"{0} ay ərzində"},past:{one:"{0} ay öncə",other:"{0} ay öncə"}}},"month-short":{displayName:"ay",relative:{0:"bu ay",1:"gələn ay","-1":"keçən ay"},relativeTime:{future:{one:"{0} ay ərzində",other:"{0} ay ərzində"},past:{one:"{0} ay öncə",other:"{0} ay öncə"}}},day:{displayName:"Gün",relative:{0:"bu gün",1:"sabah","-1":"dünən"},relativeTime:{future:{one:"{0} gün ərzində",other:"{0} gün ərzində"},past:{one:"{0} gün öncə",other:"{0} gün öncə"}}},"day-short":{displayName:"Gün",relative:{0:"bu gün",1:"sabah","-1":"dünən"},relativeTime:{future:{one:"{0} gün ərzində",other:"{0} gün ərzində"},past:{one:"{0} gün öncə",other:"{0} gün öncə"}}},hour:{displayName:"Saat",relative:{0:"bu saat"},relativeTime:{future:{one:"{0} saat ərzində",other:"{0} saat ərzində"},past:{one:"{0} saat öncə",other:"{0} saat öncə"}}},"hour-short":{displayName:"saat",relative:{0:"bu saat"},relativeTime:{future:{one:"{0} saat ərzində",other:"{0} saat ərzində"},past:{one:"{0} saat öncə",other:"{0} saat öncə"}}},minute:{displayName:"Dəqiqə",relative:{0:"bu dəqiqə"},relativeTime:{future:{one:"{0} dəqiqə ərzində",other:"{0} dəqiqə ərzində"},past:{one:"{0} dəqiqə öncə",other:"{0} dəqiqə öncə"}}},"minute-short":{displayName:"dəq.",relative:{0:"bu dəqiqə"},relativeTime:{future:{one:"{0} dəqiqə ərzində",other:"{0} dəqiqə ərzində"},past:{one:"{0} dəqiqə öncə",other:"{0} dəqiqə öncə"}}},second:{displayName:"Saniyə",relative:{0:"indi"},relativeTime:{future:{one:"{0} saniyə ərzində",other:"{0} saniyə ərzində"},past:{one:"{0} saniyə öncə",other:"{0} saniyə öncə"}}},"second-short":{displayName:"san.",relative:{0:"indi"},relativeTime:{future:{one:"{0} saniyə ərzində",other:"{0} saniyə ərzində"},past:{one:"{0} saniyə öncə",other:"{0} saniyə öncə"}}}}},{locale:"az-Arab",pluralRuleFunction:function(e,t){return"other"},fields:{year:{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},"year-short":{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},month:{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},"month-short":{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},day:{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},"day-short":{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},hour:{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},"hour-short":{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},minute:{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},"minute-short":{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},second:{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}},"second-short":{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}}}},{locale:"az-Cyrl",pluralRuleFunction:function(e,t){return"other"},fields:{year:{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},"year-short":{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},month:{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},"month-short":{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},day:{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},"day-short":{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},hour:{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},"hour-short":{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},minute:{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},"minute-short":{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},second:{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}},"second-short":{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}}}},{locale:"az-Latn",parentLocale:"az"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/be.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/be.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"be",pluralRuleFunction:function(e,t){var a=String(e).split("."),r=Number(a[0])==e,o=r&&a[0].slice(-1),n=r&&a[0].slice(-2);return t?2!=o&&3!=o||12==n||13==n?"other":"few":1==o&&11!=n?"one":o>=2&&o<=4&&(n<12||n>14)?"few":r&&0==o||o>=5&&o<=9||n>=11&&n<=14?"many":"other"},fields:{year:{displayName:"год",relative:{0:"у гэтым годзе",1:"у наступным годзе","-1":"у мінулым годзе"},relativeTime:{future:{one:"праз {0} год",few:"праз {0} гады",many:"праз {0} гадоў",other:"праз {0} года"},past:{one:"{0} год таму",few:"{0} гады таму",many:"{0} гадоў таму",other:"{0} года таму"}}},"year-short":{displayName:"г.",relative:{0:"у гэтым годзе",1:"у наступным годзе","-1":"у мінулым годзе"},relativeTime:{future:{one:"праз {0} г.",few:"праз {0} г.",many:"праз {0} г.",other:"праз {0} г."},past:{one:"{0} г. таму",few:"{0} г. таму",many:"{0} г. таму",other:"{0} г. таму"}}},month:{displayName:"месяц",relative:{0:"у гэтым месяцы",1:"у наступным месяцы","-1":"у мінулым месяцы"},relativeTime:{future:{one:"праз {0} месяц",few:"праз {0} месяцы",many:"праз {0} месяцаў",other:"праз {0} месяца"},past:{one:"{0} месяц таму",few:"{0} месяцы таму",many:"{0} месяцаў таму",other:"{0} месяца таму"}}},"month-short":{displayName:"мес.",relative:{0:"у гэтым месяцы",1:"у наступным месяцы","-1":"у мінулым месяцы"},relativeTime:{future:{one:"праз {0} мес.",few:"праз {0} мес.",many:"праз {0} мес.",other:"праз {0} мес."},past:{one:"{0} мес. таму",few:"{0} мес. таму",many:"{0} мес. таму",other:"{0} мес. таму"}}},day:{displayName:"дзень",relative:{0:"сёння",1:"заўтра",2:"паслязаўтра","-2":"пазаўчора","-1":"учора"},relativeTime:{future:{one:"праз {0} дзень",few:"праз {0} дні",many:"праз {0} дзён",other:"праз {0} дня"},past:{one:"{0} дзень таму",few:"{0} дні таму",many:"{0} дзён таму",other:"{0} дня таму"}}},"day-short":{displayName:"дзень",relative:{0:"сёння",1:"заўтра",2:"паслязаўтра","-2":"пазаўчора","-1":"учора"},relativeTime:{future:{one:"праз {0} дзень",few:"праз {0} дні",many:"праз {0} дзён",other:"праз {0} дня"},past:{one:"{0} дзень таму",few:"{0} дні таму",many:"{0} дзён таму",other:"{0} дня таму"}}},hour:{displayName:"гадзіна",relative:{0:"у гэту гадзіну"},relativeTime:{future:{one:"праз {0} гадзіну",few:"праз {0} гадзіны",many:"праз {0} гадзін",other:"праз {0} гадзіны"},past:{one:"{0} гадзіну таму",few:"{0} гадзіны таму",many:"{0} гадзін таму",other:"{0} гадзіны таму"}}},"hour-short":{displayName:"гадз",relative:{0:"у гэту гадзіну"},relativeTime:{future:{one:"праз {0} гадз",few:"праз {0} гадз",many:"праз {0} гадз",other:"праз {0} гадз"},past:{one:"{0} гадз таму",few:"{0} гадз таму",many:"{0} гадз таму",other:"{0} гадз таму"}}},minute:{displayName:"хвіліна",relative:{0:"у гэту хвіліну"},relativeTime:{future:{one:"праз {0} хвіліну",few:"праз {0} хвіліны",many:"праз {0} хвілін",other:"праз {0} хвіліны"},past:{one:"{0} хвіліну таму",few:"{0} хвіліны таму",many:"{0} хвілін таму",other:"{0} хвіліны таму"}}},"minute-short":{displayName:"хв",relative:{0:"у гэту хвіліну"},relativeTime:{future:{one:"праз {0} хв",few:"праз {0} хв",many:"праз {0} хв",other:"праз {0} хв"},past:{one:"{0} хв таму",few:"{0} хв таму",many:"{0} хв таму",other:"{0} хв таму"}}},second:{displayName:"секунда",relative:{0:"цяпер"},relativeTime:{future:{one:"праз {0} секунду",few:"праз {0} секунды",many:"праз {0} секунд",other:"праз {0} секунды"},past:{one:"{0} секунду таму",few:"{0} секунды таму",many:"{0} секунд таму",other:"{0} секунды таму"}}},"second-short":{displayName:"с",relative:{0:"цяпер"},relativeTime:{future:{one:"праз {0} с",few:"праз {0} с",many:"праз {0} с",other:"праз {0} с"},past:{one:"{0} с таму",few:"{0} с таму",many:"{0} с таму",other:"{0} с таму"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/bg.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/bg.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"bg",pluralRuleFunction:function(e,t){return t?"other":1==e?"one":"other"},fields:{year:{displayName:"година",relative:{0:"тази година",1:"следващата година","-1":"миналата година"},relativeTime:{future:{one:"след {0} година",other:"след {0} години"},past:{one:"преди {0} година",other:"преди {0} години"}}},"year-short":{displayName:"г.",relative:{0:"т. г.",1:"следв. г.","-1":"мин. г."},relativeTime:{future:{one:"след {0} г.",other:"след {0} г."},past:{one:"преди {0} г.",other:"преди {0} г."}}},month:{displayName:"месец",relative:{0:"този месец",1:"следващ месец","-1":"предходен месец"},relativeTime:{future:{one:"след {0} месец",other:"след {0} месеца"},past:{one:"преди {0} месец",other:"преди {0} месеца"}}},"month-short":{displayName:"мес.",relative:{0:"този мес.",1:"следв. мес.","-1":"мин. мес."},relativeTime:{future:{one:"след {0} м.",other:"след {0} м."},past:{one:"преди {0} м.",other:"преди {0} м."}}},day:{displayName:"ден",relative:{0:"днес",1:"утре",2:"вдругиден","-2":"онзи ден","-1":"вчера"},relativeTime:{future:{one:"след {0} ден",other:"след {0} дни"},past:{one:"преди {0} ден",other:"преди {0} дни"}}},"day-short":{displayName:"д",relative:{0:"днес",1:"утре",2:"вдругиден","-2":"онзи ден","-1":"вчера"},relativeTime:{future:{one:"след {0} ден",other:"след {0} дни"},past:{one:"преди {0} ден",other:"преди {0} дни"}}},hour:{displayName:"час",relative:{0:"в този час"},relativeTime:{future:{one:"след {0} час",other:"след {0} часа"},past:{one:"преди {0} час",other:"преди {0} часа"}}},"hour-short":{displayName:"ч",relative:{0:"в този час"},relativeTime:{future:{one:"след {0} ч",other:"след {0} ч"},past:{one:"преди {0} ч",other:"преди {0} ч"}}},minute:{displayName:"минута",relative:{0:"в тази минута"},relativeTime:{future:{one:"след {0} минута",other:"след {0} минути"},past:{one:"преди {0} минута",other:"преди {0} минути"}}},"minute-short":{displayName:"мин",relative:{0:"в тази минута"},relativeTime:{future:{one:"след {0} мин",other:"след {0} мин"},past:{one:"преди {0} мин",other:"преди {0} мин"}}},second:{displayName:"секунда",relative:{0:"сега"},relativeTime:{future:{one:"след {0} секунда",other:"след {0} секунди"},past:{one:"преди {0} секунда",other:"преди {0} секунди"}}},"second-short":{displayName:"сек",relative:{0:"сега"},relativeTime:{future:{one:"след {0} сек",other:"след {0} сек"},past:{one:"преди {0} сек",other:"преди {0} сек"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/bn.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/bn.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"bn",pluralRuleFunction:function(e,t){return t?1==e||5==e||7==e||8==e||9==e||10==e?"one":2==e||3==e?"two":4==e?"few":6==e?"many":"other":e>=0&&e<=1?"one":"other"},fields:{year:{displayName:"বছর",relative:{0:"এই বছর",1:"পরের বছর","-1":"গত বছর"},relativeTime:{future:{one:"{0} বছরে",other:"{0} বছরে"},past:{one:"{0} বছর পূর্বে",other:"{0} বছর পূর্বে"}}},"year-short":{displayName:"বছর",relative:{0:"এই বছর",1:"পরের বছর","-1":"গত বছর"},relativeTime:{future:{one:"{0} বছরে",other:"{0} বছরে"},past:{one:"{0} বছর পূর্বে",other:"{0} বছর পূর্বে"}}},month:{displayName:"মাস",relative:{0:"এই মাস",1:"পরের মাস","-1":"গত মাস"},relativeTime:{future:{one:"{0} মাসে",other:"{0} মাসে"},past:{one:"{0} মাস আগে",other:"{0} মাস আগে"}}},"month-short":{displayName:"মাস",relative:{0:"এই মাস",1:"পরের মাস","-1":"গত মাস"},relativeTime:{future:{one:"{0} মাসে",other:"{0} মাসে"},past:{one:"{0} মাস আগে",other:"{0} মাস আগে"}}},day:{displayName:"দিন",relative:{0:"আজ",1:"আগামীকাল",2:"আগামী পরশু","-2":"গত পরশু","-1":"গতকাল"},relativeTime:{future:{one:"{0} দিনের মধ্যে",other:"{0} দিনের মধ্যে"},past:{one:"{0} দিন আগে",other:"{0} দিন আগে"}}},"day-short":{displayName:"দিন",relative:{0:"আজ",1:"আগামীকাল",2:"আগামী পরশু","-2":"গত পরশু","-1":"গতকাল"},relativeTime:{future:{one:"{0} দিনের মধ্যে",other:"{0} দিনের মধ্যে"},past:{one:"{0} দিন আগে",other:"{0} দিন আগে"}}},hour:{displayName:"ঘণ্টা",relative:{0:"এই ঘণ্টায়"},relativeTime:{future:{one:"{0} ঘন্টায়",other:"{0} ঘন্টায়"},past:{one:"{0} ঘন্টা আগে",other:"{0} ঘন্টা আগে"}}},"hour-short":{displayName:"ঘণ্টা",relative:{0:"এই ঘণ্টায়"},relativeTime:{future:{one:"{0} ঘন্টায়",other:"{0} ঘন্টায়"},past:{one:"{0} ঘন্টা আগে",other:"{0} ঘন্টা আগে"}}},minute:{displayName:"মিনিট",relative:{0:"এই মিনিট"},relativeTime:{future:{one:"{0} মিনিটে",other:"{0} মিনিটে"},past:{one:"{0} মিনিট আগে",other:"{0} মিনিট আগে"}}},"minute-short":{displayName:"মিনিট",relative:{0:"এই মিনিট"},relativeTime:{future:{one:"{0} মিনিটে",other:"{0} মিনিটে"},past:{one:"{0} মিনিট আগে",other:"{0} মিনিট আগে"}}},second:{displayName:"সেকেন্ড",relative:{0:"এখন"},relativeTime:{future:{one:"{0} সেকেন্ডে",other:"{0} সেকেন্ডে"},past:{one:"{0} সেকেন্ড পূর্বে",other:"{0} সেকেন্ড পূর্বে"}}},"second-short":{displayName:"সেকেন্ড",relative:{0:"এখন"},relativeTime:{future:{one:"{0} সেকেন্ডে",other:"{0} সেকেন্ডে"},past:{one:"{0} সেকেন্ড পূর্বে",other:"{0} সেকেন্ড পূর্বে"}}}}},{locale:"bn-IN",parentLocale:"bn"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ca.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/ca.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(a,e){ true?module.exports=e():undefined}(this,function(){"use strict";return[{locale:"ca",pluralRuleFunction:function(a,e){var t=!String(a).split(".")[1];return e?1==a||3==a?"one":2==a?"two":4==a?"few":"other":1==a&&t?"one":"other"},fields:{year:{displayName:"any",relative:{0:"enguany",1:"l’any que ve","-1":"l’any passat"},relativeTime:{future:{one:"d’aquí a {0} any",other:"d’aquí a {0} anys"},past:{one:"fa {0} any",other:"fa {0} anys"}}},"year-short":{displayName:"any",relative:{0:"enguany",1:"l’any que ve","-1":"l’any passat"},relativeTime:{future:{one:"d’aquí a {0} any",other:"d’aquí a {0} anys"},past:{one:"fa {0} any",other:"fa {0} anys"}}},month:{displayName:"mes",relative:{0:"aquest mes",1:"el mes que ve","-1":"el mes passat"},relativeTime:{future:{one:"d’aquí a {0} mes",other:"d’aquí a {0} mesos"},past:{one:"fa {0} mes",other:"fa {0} mesos"}}},"month-short":{displayName:"mes",relative:{0:"aquest mes",1:"el mes que ve","-1":"el mes passat"},relativeTime:{future:{one:"d’aquí a {0} mes",other:"d’aquí a {0} mesos"},past:{one:"fa {0} mes",other:"fa {0} mesos"}}},day:{displayName:"dia",relative:{0:"avui",1:"demà",2:"demà passat","-2":"abans-d’ahir","-1":"ahir"},relativeTime:{future:{one:"d’aquí a {0} dia",other:"d’aquí a {0} dies"},past:{one:"fa {0} dia",other:"fa {0} dies"}}},"day-short":{displayName:"dia",relative:{0:"avui",1:"demà",2:"demà passat","-2":"abans-d’ahir","-1":"ahir"},relativeTime:{future:{one:"d’aquí a {0} dia",other:"d’aquí a {0} dies"},past:{one:"fa {0} dia",other:"fa {0} dies"}}},hour:{displayName:"hora",relative:{0:"aquesta hora"},relativeTime:{future:{one:"d’aquí a {0} hora",other:"d’aquí a {0} hores"},past:{one:"fa {0} hora",other:"fa {0} hores"}}},"hour-short":{displayName:"h",relative:{0:"aquesta hora"},relativeTime:{future:{one:"d’aquí a {0} h",other:"d’aquí a {0} h"},past:{one:"fa {0} h",other:"fa {0} h"}}},minute:{displayName:"minut",relative:{0:"aquest minut"},relativeTime:{future:{one:"d’aquí a {0} minut",other:"d’aquí a {0} minuts"},past:{one:"fa {0} minut",other:"fa {0} minuts"}}},"minute-short":{displayName:"min",relative:{0:"aquest minut"},relativeTime:{future:{one:"d’aquí a {0} min",other:"d’aquí a {0} min"},past:{one:"fa {0} min",other:"fa {0} min"}}},second:{displayName:"segon",relative:{0:"ara"},relativeTime:{future:{one:"d’aquí a {0} segon",other:"d’aquí a {0} segons"},past:{one:"fa {0} segon",other:"fa {0} segons"}}},"second-short":{displayName:"s",relative:{0:"ara"},relativeTime:{future:{one:"d’aquí a {0} s",other:"d’aquí a {0} s"},past:{one:"fa {0} s",other:"fa {0} s"}}}}},{locale:"ca-AD",parentLocale:"ca"},{locale:"ca-ES-VALENCIA",parentLocale:"ca-ES",fields:{year:{displayName:"any",relative:{0:"enguany",1:"l’any que ve","-1":"l’any passat"},relativeTime:{future:{one:"d’aquí a {0} any",other:"d’aquí a {0} anys"},past:{one:"fa {0} any",other:"fa {0} anys"}}},"year-short":{displayName:"any",relative:{0:"enguany",1:"l’any que ve","-1":"l’any passat"},relativeTime:{future:{one:"d’aquí a {0} any",other:"d’aquí a {0} anys"},past:{one:"fa {0} any",other:"fa {0} anys"}}},month:{displayName:"mes",relative:{0:"aquest mes",1:"el mes que ve","-1":"el mes passat"},relativeTime:{future:{one:"d’aquí a {0} mes",other:"d’aquí a {0} mesos"},past:{one:"fa {0} mes",other:"fa {0} mesos"}}},"month-short":{displayName:"mes",relative:{0:"aquest mes",1:"el mes que ve","-1":"el mes passat"},relativeTime:{future:{one:"d’aquí a {0} mes",other:"d’aquí a {0} mesos"},past:{one:"fa {0} mes",other:"fa {0} mesos"}}},day:{displayName:"dia",relative:{0:"avui",1:"demà",2:"demà passat","-2":"abans-d’ahir","-1":"ahir"},relativeTime:{future:{one:"d’aquí a {0} dia",other:"d’aquí a {0} dies"},past:{one:"fa {0} dia",other:"fa {0} dies"}}},"day-short":{displayName:"dia",relative:{0:"avui",1:"demà",2:"demà passat","-2":"abans-d’ahir","-1":"ahir"},relativeTime:{future:{one:"d’aquí a {0} dia",other:"d’aquí a {0} dies"},past:{one:"fa {0} dia",other:"fa {0} dies"}}},hour:{displayName:"hora",relative:{0:"aquesta hora"},relativeTime:{future:{one:"d’aquí a {0} hora",other:"d’aquí a {0} hores"},past:{one:"fa {0} hora",other:"fa {0} hores"}}},"hour-short":{displayName:"h",relative:{0:"aquesta hora"},relativeTime:{future:{one:"d’aquí a {0} h",other:"d’aquí a {0} h"},past:{one:"fa {0} h",other:"fa {0} h"}}},minute:{displayName:"minut",relative:{0:"aquest minut"},relativeTime:{future:{one:"d’aquí a {0} minut",other:"d’aquí a {0} minuts"},past:{one:"fa {0} minut",other:"fa {0} minuts"}}},"minute-short":{displayName:"min",relative:{0:"aquest minut"},relativeTime:{future:{one:"d’aquí a {0} min",other:"d’aquí a {0} min"},past:{one:"fa {0} min",other:"fa {0} min"}}},second:{displayName:"segon",relative:{0:"ara"},relativeTime:{future:{one:"d’aquí a {0} segon",other:"d’aquí a {0} segons"},past:{one:"fa {0} segon",other:"fa {0} segons"}}},"second-short":{displayName:"s",relative:{0:"ara"},relativeTime:{future:{one:"d’aquí a {0} s",other:"d’aquí a {0} s"},past:{one:"fa {0} s",other:"fa {0} s"}}}}},{locale:"ca-ES",parentLocale:"ca"},{locale:"ca-FR",parentLocale:"ca"},{locale:"ca-IT",parentLocale:"ca"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ckb.js": /*!*********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/ckb.js ***! \*********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"ckb",pluralRuleFunction:function(e,t){return t?"other":1==e?"one":"other"},fields:{year:{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},"year-short":{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},month:{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},"month-short":{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},day:{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},"day-short":{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},hour:{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},"hour-short":{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},minute:{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},"minute-short":{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},second:{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}},"second-short":{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}}}},{locale:"ckb-IR",parentLocale:"ckb"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/cs.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/cs.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,a){ true?module.exports=a():undefined}(this,function(){"use strict";return[{locale:"cs",pluralRuleFunction:function(e,a){var n=String(e).split("."),t=n[0],m=!n[1];return a?"other":1==e&&m?"one":t>=2&&t<=4&&m?"few":m?"other":"many"},fields:{year:{displayName:"rok",relative:{0:"tento rok",1:"příští rok","-1":"minulý rok"},relativeTime:{future:{one:"za {0} rok",few:"za {0} roky",many:"za {0} roku",other:"za {0} let"},past:{one:"před {0} rokem",few:"před {0} lety",many:"před {0} roku",other:"před {0} lety"}}},"year-short":{displayName:"r.",relative:{0:"tento rok",1:"příští rok","-1":"minulý rok"},relativeTime:{future:{one:"za {0} r.",few:"za {0} r.",many:"za {0} r.",other:"za {0} l."},past:{one:"před {0} r.",few:"před {0} r.",many:"před {0} r.",other:"před {0} l."}}},month:{displayName:"měsíc",relative:{0:"tento měsíc",1:"příští měsíc","-1":"minulý měsíc"},relativeTime:{future:{one:"za {0} měsíc",few:"za {0} měsíce",many:"za {0} měsíce",other:"za {0} měsíců"},past:{one:"před {0} měsícem",few:"před {0} měsíci",many:"před {0} měsíce",other:"před {0} měsíci"}}},"month-short":{displayName:"měs.",relative:{0:"tento měs.",1:"příští měs.","-1":"minulý měs."},relativeTime:{future:{one:"za {0} měs.",few:"za {0} měs.",many:"za {0} měs.",other:"za {0} měs."},past:{one:"před {0} měs.",few:"před {0} měs.",many:"před {0} měs.",other:"před {0} měs."}}},day:{displayName:"den",relative:{0:"dnes",1:"zítra",2:"pozítří","-2":"předevčírem","-1":"včera"},relativeTime:{future:{one:"za {0} den",few:"za {0} dny",many:"za {0} dne",other:"za {0} dní"},past:{one:"před {0} dnem",few:"před {0} dny",many:"před {0} dne",other:"před {0} dny"}}},"day-short":{displayName:"den",relative:{0:"dnes",1:"zítra",2:"pozítří","-2":"předevčírem","-1":"včera"},relativeTime:{future:{one:"za {0} den",few:"za {0} dny",many:"za {0} dne",other:"za {0} dní"},past:{one:"před {0} dnem",few:"před {0} dny",many:"před {0} dne",other:"před {0} dny"}}},hour:{displayName:"hodina",relative:{0:"tuto hodinu"},relativeTime:{future:{one:"za {0} hodinu",few:"za {0} hodiny",many:"za {0} hodiny",other:"za {0} hodin"},past:{one:"před {0} hodinou",few:"před {0} hodinami",many:"před {0} hodiny",other:"před {0} hodinami"}}},"hour-short":{displayName:"h",relative:{0:"tuto hodinu"},relativeTime:{future:{one:"za {0} h",few:"za {0} h",many:"za {0} h",other:"za {0} h"},past:{one:"před {0} h",few:"před {0} h",many:"před {0} h",other:"před {0} h"}}},minute:{displayName:"minuta",relative:{0:"tuto minutu"},relativeTime:{future:{one:"za {0} minutu",few:"za {0} minuty",many:"za {0} minuty",other:"za {0} minut"},past:{one:"před {0} minutou",few:"před {0} minutami",many:"před {0} minuty",other:"před {0} minutami"}}},"minute-short":{displayName:"min",relative:{0:"tuto minutu"},relativeTime:{future:{one:"za {0} min",few:"za {0} min",many:"za {0} min",other:"za {0} min"},past:{one:"před {0} min",few:"před {0} min",many:"před {0} min",other:"před {0} min"}}},second:{displayName:"sekunda",relative:{0:"nyní"},relativeTime:{future:{one:"za {0} sekundu",few:"za {0} sekundy",many:"za {0} sekundy",other:"za {0} sekund"},past:{one:"před {0} sekundou",few:"před {0} sekundami",many:"před {0} sekundy",other:"před {0} sekundami"}}},"second-short":{displayName:"s",relative:{0:"nyní"},relativeTime:{future:{one:"za {0} s",few:"za {0} s",many:"za {0} s",other:"za {0} s"},past:{one:"před {0} s",few:"před {0} s",many:"před {0} s",other:"před {0} s"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/cy.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/cy.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,n){ true?module.exports=n():undefined}(this,function(){"use strict";return[{locale:"cy",pluralRuleFunction:function(e,n){return n?0==e||7==e||8==e||9==e?"zero":1==e?"one":2==e?"two":3==e||4==e?"few":5==e||6==e?"many":"other":0==e?"zero":1==e?"one":2==e?"two":3==e?"few":6==e?"many":"other"},fields:{year:{displayName:"blwyddyn",relative:{0:"eleni",1:"blwyddyn nesaf","-1":"llynedd"},relativeTime:{future:{zero:"ymhen {0} mlynedd",one:"ymhen blwyddyn",two:"ymhen {0} flynedd",few:"ymhen {0} blynedd",many:"ymhen {0} blynedd",other:"ymhen {0} mlynedd"},past:{zero:"{0} o flynyddoedd yn ôl",one:"blwyddyn yn ôl",two:"{0} flynedd yn ôl",few:"{0} blynedd yn ôl",many:"{0} blynedd yn ôl",other:"{0} o flynyddoedd yn ôl"}}},"year-short":{displayName:"bl.",relative:{0:"eleni",1:"blwyddyn nesaf","-1":"llynedd"},relativeTime:{future:{zero:"ymhen {0} mlynedd",one:"ymhen blwyddyn",two:"ymhen {0} flynedd",few:"ymhen {0} blynedd",many:"ymhen {0} blynedd",other:"ymhen {0} mlynedd"},past:{zero:"{0} o flynyddoedd yn ôl",one:"blwyddyn yn ôl",two:"{0} flynedd yn ôl",few:"{0} blynedd yn ôl",many:"{0} blynedd yn ôl",other:"{0} o flynyddoedd yn ôl"}}},month:{displayName:"mis",relative:{0:"y mis hwn",1:"mis nesaf","-1":"mis diwethaf"},relativeTime:{future:{zero:"ymhen {0} mis",one:"ymhen mis",two:"ymhen deufis",few:"ymhen {0} mis",many:"ymhen {0} mis",other:"ymhen {0} mis"},past:{zero:"{0} mis yn ôl",one:"{0} mis yn ôl",two:"{0} fis yn ôl",few:"{0} mis yn ôl",many:"{0} mis yn ôl",other:"{0} mis yn ôl"}}},"month-short":{displayName:"mis",relative:{0:"y mis hwn",1:"mis nesaf","-1":"mis diwethaf"},relativeTime:{future:{zero:"ymhen {0} mis",one:"ymhen mis",two:"ymhen deufis",few:"ymhen {0} mis",many:"ymhen {0} mis",other:"ymhen {0} mis"},past:{zero:"{0} mis yn ôl",one:"{0} mis yn ôl",two:"deufis yn ôl",few:"{0} mis yn ôl",many:"{0} mis yn ôl",other:"{0} mis yn ôl"}}},day:{displayName:"diwrnod",relative:{0:"heddiw",1:"yfory",2:"drennydd","-2":"echdoe","-1":"ddoe"},relativeTime:{future:{zero:"ymhen {0} diwrnod",one:"ymhen diwrnod",two:"ymhen deuddydd",few:"ymhen {0} diwrnod",many:"ymhen {0} diwrnod",other:"ymhen {0} diwrnod"},past:{zero:"{0} diwrnod yn ôl",one:"{0} diwrnod yn ôl",two:"{0} ddiwrnod yn ôl",few:"{0} diwrnod yn ôl",many:"{0} diwrnod yn ôl",other:"{0} diwrnod yn ôl"}}},"day-short":{displayName:"diwrnod",relative:{0:"heddiw",1:"yfory",2:"drennydd","-2":"echdoe","-1":"ddoe"},relativeTime:{future:{zero:"ymhen {0} diwrnod",one:"ymhen diwrnod",two:"ymhen deuddydd",few:"ymhen {0} diwrnod",many:"ymhen {0} diwrnod",other:"ymhen {0} diwrnod"},past:{zero:"{0} diwrnod yn ôl",one:"{0} diwrnod yn ôl",two:"{0} ddiwrnod yn ôl",few:"{0} diwrnod yn ôl",many:"{0} diwrnod yn ôl",other:"{0} diwrnod yn ôl"}}},hour:{displayName:"awr",relative:{0:"yr awr hon"},relativeTime:{future:{zero:"ymhen {0} awr",one:"ymhen awr",two:"ymhen {0} awr",few:"ymhen {0} awr",many:"ymhen {0} awr",other:"ymhen {0} awr"},past:{zero:"{0} awr yn ôl",one:"{0} awr yn ôl",two:"{0} awr yn ôl",few:"{0} awr yn ôl",many:"{0} awr yn ôl",other:"{0} awr yn ôl"}}},"hour-short":{displayName:"awr",relative:{0:"yr awr hon"},relativeTime:{future:{zero:"ymhen {0} awr",one:"ymhen awr",two:"ymhen {0} awr",few:"ymhen {0} awr",many:"ymhen {0} awr",other:"ymhen {0} awr"},past:{zero:"{0} awr yn ôl",one:"awr yn ôl",two:"{0} awr yn ôl",few:"{0} awr yn ôl",many:"{0} awr yn ôl",other:"{0} awr yn ôl"}}},minute:{displayName:"munud",relative:{0:"y funud hon"},relativeTime:{future:{zero:"ymhen {0} munud",one:"ymhen {0} munud",two:"ymhen {0} munud",few:"ymhen {0} munud",many:"ymhen {0} munud",other:"ymhen {0} munud"},past:{zero:"{0} munud yn ôl",one:"{0} munud yn ôl",two:"{0} munud yn ôl",few:"{0} munud yn ôl",many:"{0} munud yn ôl",other:"{0} munud yn ôl"}}},"minute-short":{displayName:"mun.",relative:{0:"y funud hon"},relativeTime:{future:{zero:"ymhen {0} munud",one:"ymhen {0} mun.",two:"ymhen {0} fun.",few:"ymhen {0} munud",many:"ymhen {0} munud",other:"ymhen {0} munud"},past:{zero:"{0} munud yn ôl",one:"{0} munud yn ôl",two:"{0} fun. yn ôl",few:"{0} munud yn ôl",many:"{0} munud yn ôl",other:"{0} munud yn ôl"}}},second:{displayName:"eiliad",relative:{0:"nawr"},relativeTime:{future:{zero:"ymhen {0} eiliad",one:"ymhen {0} eiliad",two:"ymhen {0} eiliad",few:"ymhen {0} eiliad",many:"ymhen {0} eiliad",other:"ymhen {0} eiliad"},past:{zero:"{0} eiliad yn ôl",one:"{0} eiliad yn ôl",two:"{0} eiliad yn ôl",few:"{0} eiliad yn ôl",many:"{0} eiliad yn ôl",other:"{0} eiliad yn ôl"}}},"second-short":{displayName:"eiliad",relative:{0:"nawr"},relativeTime:{future:{zero:"ymhen {0} eiliad",one:"ymhen {0} eiliad",two:"ymhen {0} eiliad",few:"ymhen {0} eiliad",many:"ymhen {0} eiliad",other:"ymhen {0} eiliad"},past:{zero:"{0} eiliad yn ôl",one:"{0} eiliad yn ôl",two:"{0} eiliad yn ôl",few:"{0} eiliad yn ôl",many:"{0} eiliad yn ôl",other:"{0} eiliad yn ôl"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/da.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/da.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,r){ true?module.exports=r():undefined}(this,function(){"use strict";return[{locale:"da",pluralRuleFunction:function(e,r){var t=String(e).split("."),o=t[0],i=Number(t[0])==e;return r?"other":1!=e&&(i||0!=o&&1!=o)?"other":"one"},fields:{year:{displayName:"år",relative:{0:"i år",1:"næste år","-1":"sidste år"},relativeTime:{future:{one:"om {0} år",other:"om {0} år"},past:{one:"for {0} år siden",other:"for {0} år siden"}}},"year-short":{displayName:"år",relative:{0:"i år",1:"næste år","-1":"sidste år"},relativeTime:{future:{one:"om {0} år",other:"om {0} år"},past:{one:"for {0} år siden",other:"for {0} år siden"}}},month:{displayName:"måned",relative:{0:"denne måned",1:"næste måned","-1":"sidste måned"},relativeTime:{future:{one:"om {0} måned",other:"om {0} måneder"},past:{one:"for {0} måned siden",other:"for {0} måneder siden"}}},"month-short":{displayName:"md.",relative:{0:"denne md.",1:"næste md.","-1":"sidste md."},relativeTime:{future:{one:"om {0} md.",other:"om {0} mdr."},past:{one:"for {0} md. siden",other:"for {0} mdr. siden"}}},day:{displayName:"dag",relative:{0:"i dag",1:"i morgen",2:"i overmorgen","-2":"i forgårs","-1":"i går"},relativeTime:{future:{one:"om {0} dag",other:"om {0} dage"},past:{one:"for {0} dag siden",other:"for {0} dage siden"}}},"day-short":{displayName:"dag",relative:{0:"i dag",1:"i morgen",2:"i overmorgen","-2":"i forgårs","-1":"i går"},relativeTime:{future:{one:"om {0} dag",other:"om {0} dage"},past:{one:"for {0} dag siden",other:"for {0} dage siden"}}},hour:{displayName:"time",relative:{0:"i den kommende time"},relativeTime:{future:{one:"om {0} time",other:"om {0} timer"},past:{one:"for {0} time siden",other:"for {0} timer siden"}}},"hour-short":{displayName:"t.",relative:{0:"i den kommende time"},relativeTime:{future:{one:"om {0} time",other:"om {0} timer"},past:{one:"for {0} time siden",other:"for {0} timer siden"}}},minute:{displayName:"minut",relative:{0:"i det kommende minut"},relativeTime:{future:{one:"om {0} minut",other:"om {0} minutter"},past:{one:"for {0} minut siden",other:"for {0} minutter siden"}}},"minute-short":{displayName:"min.",relative:{0:"i det kommende minut"},relativeTime:{future:{one:"om {0} min.",other:"om {0} min."},past:{one:"for {0} min. siden",other:"for {0} min. siden"}}},second:{displayName:"sekund",relative:{0:"nu"},relativeTime:{future:{one:"om {0} sekund",other:"om {0} sekunder"},past:{one:"for {0} sekund siden",other:"for {0} sekunder siden"}}},"second-short":{displayName:"sek.",relative:{0:"nu"},relativeTime:{future:{one:"om {0} sek.",other:"om {0} sek."},past:{one:"for {0} sek. siden",other:"for {0} sek. siden"}}}}},{locale:"da-GL",parentLocale:"da"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/de.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/de.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"de",pluralRuleFunction:function(e,t){var n=!String(e).split(".")[1];return t?"other":1==e&&n?"one":"other"},fields:{year:{displayName:"Jahr",relative:{0:"dieses Jahr",1:"nächstes Jahr","-1":"letztes Jahr"},relativeTime:{future:{one:"in {0} Jahr",other:"in {0} Jahren"},past:{one:"vor {0} Jahr",other:"vor {0} Jahren"}}},"year-short":{displayName:"Jahr",relative:{0:"dieses Jahr",1:"nächstes Jahr","-1":"letztes Jahr"},relativeTime:{future:{one:"in {0} Jahr",other:"in {0} Jahren"},past:{one:"vor {0} Jahr",other:"vor {0} Jahren"}}},month:{displayName:"Monat",relative:{0:"diesen Monat",1:"nächsten Monat","-1":"letzten Monat"},relativeTime:{future:{one:"in {0} Monat",other:"in {0} Monaten"},past:{one:"vor {0} Monat",other:"vor {0} Monaten"}}},"month-short":{displayName:"Monat",relative:{0:"diesen Monat",1:"nächsten Monat","-1":"letzten Monat"},relativeTime:{future:{one:"in {0} Monat",other:"in {0} Monaten"},past:{one:"vor {0} Monat",other:"vor {0} Monaten"}}},day:{displayName:"Tag",relative:{0:"heute",1:"morgen",2:"übermorgen","-2":"vorgestern","-1":"gestern"},relativeTime:{future:{one:"in {0} Tag",other:"in {0} Tagen"},past:{one:"vor {0} Tag",other:"vor {0} Tagen"}}},"day-short":{displayName:"Tag",relative:{0:"heute",1:"morgen",2:"übermorgen","-2":"vorgestern","-1":"gestern"},relativeTime:{future:{one:"in {0} Tag",other:"in {0} Tagen"},past:{one:"vor {0} Tag",other:"vor {0} Tagen"}}},hour:{displayName:"Stunde",relative:{0:"in dieser Stunde"},relativeTime:{future:{one:"in {0} Stunde",other:"in {0} Stunden"},past:{one:"vor {0} Stunde",other:"vor {0} Stunden"}}},"hour-short":{displayName:"Std.",relative:{0:"in dieser Stunde"},relativeTime:{future:{one:"in {0} Std.",other:"in {0} Std."},past:{one:"vor {0} Std.",other:"vor {0} Std."}}},minute:{displayName:"Minute",relative:{0:"in dieser Minute"},relativeTime:{future:{one:"in {0} Minute",other:"in {0} Minuten"},past:{one:"vor {0} Minute",other:"vor {0} Minuten"}}},"minute-short":{displayName:"Min.",relative:{0:"in dieser Minute"},relativeTime:{future:{one:"in {0} Min.",other:"in {0} Min."},past:{one:"vor {0} Min.",other:"vor {0} Min."}}},second:{displayName:"Sekunde",relative:{0:"jetzt"},relativeTime:{future:{one:"in {0} Sekunde",other:"in {0} Sekunden"},past:{one:"vor {0} Sekunde",other:"vor {0} Sekunden"}}},"second-short":{displayName:"Sek.",relative:{0:"jetzt"},relativeTime:{future:{one:"in {0} Sek.",other:"in {0} Sek."},past:{one:"vor {0} Sek.",other:"vor {0} Sek."}}}}},{locale:"de-AT",parentLocale:"de"},{locale:"de-BE",parentLocale:"de"},{locale:"de-CH",parentLocale:"de"},{locale:"de-IT",parentLocale:"de"},{locale:"de-LI",parentLocale:"de"},{locale:"de-LU",parentLocale:"de"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/el.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/el.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"el",pluralRuleFunction:function(e,t){return t?"other":1==e?"one":"other"},fields:{year:{displayName:"έτος",relative:{0:"φέτος",1:"επόμενο έτος","-1":"πέρσι"},relativeTime:{future:{one:"σε {0} έτος",other:"σε {0} έτη"},past:{one:"πριν από {0} έτος",other:"πριν από {0} έτη"}}},"year-short":{displayName:"έτ.",relative:{0:"φέτος",1:"επόμενο έτος","-1":"πέρσι"},relativeTime:{future:{one:"σε {0} έτος",other:"σε {0} έτη"},past:{one:"πριν από {0} έτος",other:"πριν από {0} έτη"}}},month:{displayName:"μήνας",relative:{0:"τρέχων μήνας",1:"επόμενος μήνας","-1":"προηγούμενος μήνας"},relativeTime:{future:{one:"σε {0} μήνα",other:"σε {0} μήνες"},past:{one:"πριν από {0} μήνα",other:"πριν από {0} μήνες"}}},"month-short":{displayName:"μήν.",relative:{0:"τρέχων μήνας",1:"επόμενος μήνας","-1":"προηγούμενος μήνας"},relativeTime:{future:{one:"σε {0} μήνα",other:"σε {0} μήνες"},past:{one:"πριν από {0} μήνα",other:"πριν από {0} μήνες"}}},day:{displayName:"ημέρα",relative:{0:"σήμερα",1:"αύριο",2:"μεθαύριο","-2":"προχθές","-1":"χθες"},relativeTime:{future:{one:"σε {0} ημέρα",other:"σε {0} ημέρες"},past:{one:"πριν από {0} ημέρα",other:"πριν από {0} ημέρες"}}},"day-short":{displayName:"ημ.",relative:{0:"σήμερα",1:"αύριο",2:"μεθαύριο","-2":"προχθές","-1":"χθες"},relativeTime:{future:{one:"σε {0} ημ.",other:"σε {0} ημ."},past:{one:"πριν από {0} ημ.",other:"πριν από {0} ημ."}}},hour:{displayName:"ώρα",relative:{0:"τρέχουσα ώρα"},relativeTime:{future:{one:"σε {0} ώρα",other:"σε {0} ώρες"},past:{one:"πριν από {0} ώρα",other:"πριν από {0} ώρες"}}},"hour-short":{displayName:"ώ.",relative:{0:"τρέχουσα ώρα"},relativeTime:{future:{one:"σε {0} ώ.",other:"σε {0} ώ."},past:{one:"πριν από {0} ώ.",other:"πριν από {0} ώ."}}},minute:{displayName:"λεπτό",relative:{0:"τρέχον λεπτό"},relativeTime:{future:{one:"σε {0} λεπτό",other:"σε {0} λεπτά"},past:{one:"πριν από {0} λεπτό",other:"πριν από {0} λεπτά"}}},"minute-short":{displayName:"λεπ.",relative:{0:"τρέχον λεπτό"},relativeTime:{future:{one:"σε {0} λεπ.",other:"σε {0} λεπ."},past:{one:"πριν από {0} λεπ.",other:"πριν από {0} λεπ."}}},second:{displayName:"δευτερόλεπτο",relative:{0:"τώρα"},relativeTime:{future:{one:"σε {0} δευτερόλεπτο",other:"σε {0} δευτερόλεπτα"},past:{one:"πριν από {0} δευτερόλεπτο",other:"πριν από {0} δευτερόλεπτα"}}},"second-short":{displayName:"δευτ.",relative:{0:"τώρα"},relativeTime:{future:{one:"σε {0} δευτ.",other:"σε {0} δευτ."},past:{one:"πριν από {0} δευτ.",other:"πριν από {0} δευτ."}}}}},{locale:"el-CY",parentLocale:"el"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/en.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/en.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,a){ true?module.exports=a():undefined}(this,function(){"use strict";return[{locale:"en",pluralRuleFunction:function(e,a){var t=String(e).split("."),o=!t[1],n=Number(t[0])==e,r=n&&t[0].slice(-1),i=n&&t[0].slice(-2);return a?1==r&&11!=i?"one":2==r&&12!=i?"two":3==r&&13!=i?"few":"other":1==e&&o?"one":"other"},fields:{year:{displayName:"year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{one:"in {0} year",other:"in {0} years"},past:{one:"{0} year ago",other:"{0} years ago"}}},"year-short":{displayName:"yr.",relative:{0:"this yr.",1:"next yr.","-1":"last yr."},relativeTime:{future:{one:"in {0} yr.",other:"in {0} yr."},past:{one:"{0} yr. ago",other:"{0} yr. ago"}}},month:{displayName:"month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{one:"in {0} month",other:"in {0} months"},past:{one:"{0} month ago",other:"{0} months ago"}}},"month-short":{displayName:"mo.",relative:{0:"this mo.",1:"next mo.","-1":"last mo."},relativeTime:{future:{one:"in {0} mo.",other:"in {0} mo."},past:{one:"{0} mo. ago",other:"{0} mo. ago"}}},day:{displayName:"day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{one:"in {0} day",other:"in {0} days"},past:{one:"{0} day ago",other:"{0} days ago"}}},"day-short":{displayName:"day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{one:"in {0} day",other:"in {0} days"},past:{one:"{0} day ago",other:"{0} days ago"}}},hour:{displayName:"hour",relative:{0:"this hour"},relativeTime:{future:{one:"in {0} hour",other:"in {0} hours"},past:{one:"{0} hour ago",other:"{0} hours ago"}}},"hour-short":{displayName:"hr.",relative:{0:"this hour"},relativeTime:{future:{one:"in {0} hr.",other:"in {0} hr."},past:{one:"{0} hr. ago",other:"{0} hr. ago"}}},minute:{displayName:"minute",relative:{0:"this minute"},relativeTime:{future:{one:"in {0} minute",other:"in {0} minutes"},past:{one:"{0} minute ago",other:"{0} minutes ago"}}},"minute-short":{displayName:"min.",relative:{0:"this minute"},relativeTime:{future:{one:"in {0} min.",other:"in {0} min."},past:{one:"{0} min. ago",other:"{0} min. ago"}}},second:{displayName:"second",relative:{0:"now"},relativeTime:{future:{one:"in {0} second",other:"in {0} seconds"},past:{one:"{0} second ago",other:"{0} seconds ago"}}},"second-short":{displayName:"sec.",relative:{0:"now"},relativeTime:{future:{one:"in {0} sec.",other:"in {0} sec."},past:{one:"{0} sec. ago",other:"{0} sec. ago"}}}}},{locale:"en-001",parentLocale:"en",fields:{year:{displayName:"year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{one:"in {0} year",other:"in {0} years"},past:{one:"{0} year ago",other:"{0} years ago"}}},"year-short":{displayName:"yr",relative:{0:"this yr.",1:"next yr.","-1":"last yr."},relativeTime:{future:{one:"in {0} yr",other:"in {0} yr"},past:{one:"{0} yr ago",other:"{0} yr ago"}}},month:{displayName:"month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{one:"in {0} month",other:"in {0} months"},past:{one:"{0} month ago",other:"{0} months ago"}}},"month-short":{displayName:"mo",relative:{0:"this mo.",1:"next mo.","-1":"last mo."},relativeTime:{future:{one:"in {0} mo",other:"in {0} mo"},past:{one:"{0} mo ago",other:"{0} mo ago"}}},day:{displayName:"day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{one:"in {0} day",other:"in {0} days"},past:{one:"{0} day ago",other:"{0} days ago"}}},"day-short":{displayName:"day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{one:"in {0} day",other:"in {0} days"},past:{one:"{0} day ago",other:"{0} days ago"}}},hour:{displayName:"hour",relative:{0:"this hour"},relativeTime:{future:{one:"in {0} hour",other:"in {0} hours"},past:{one:"{0} hour ago",other:"{0} hours ago"}}},"hour-short":{displayName:"hr",relative:{0:"this hour"},relativeTime:{future:{one:"in {0} hr",other:"in {0} hr"},past:{one:"{0} hr ago",other:"{0} hr ago"}}},minute:{displayName:"minute",relative:{0:"this minute"},relativeTime:{future:{one:"in {0} minute",other:"in {0} minutes"},past:{one:"{0} minute ago",other:"{0} minutes ago"}}},"minute-short":{displayName:"min",relative:{0:"this minute"},relativeTime:{future:{one:"in {0} min",other:"in {0} min"},past:{one:"{0} min ago",other:"{0} min ago"}}},second:{displayName:"second",relative:{0:"now"},relativeTime:{future:{one:"in {0} second",other:"in {0} seconds"},past:{one:"{0} second ago",other:"{0} seconds ago"}}},"second-short":{displayName:"sec",relative:{0:"now"},relativeTime:{future:{one:"in {0} sec",other:"in {0} sec"},past:{one:"{0} sec ago",other:"{0} sec ago"}}}}},{locale:"en-150",parentLocale:"en-001"},{locale:"en-AG",parentLocale:"en-001"},{locale:"en-AI",parentLocale:"en-001"},{locale:"en-AS",parentLocale:"en"},{locale:"en-AT",parentLocale:"en-150"},{locale:"en-AU",parentLocale:"en-001",fields:{year:{displayName:"year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{one:"in {0} year",other:"in {0} years"},past:{one:"{0} year ago",other:"{0} years ago"}}},"year-short":{displayName:"yr",relative:{0:"this yr.",1:"next yr.","-1":"last yr."},relativeTime:{future:{one:"in {0} yr",other:"in {0} yrs"},past:{one:"{0} yr ago",other:"{0} yrs ago"}}},month:{displayName:"month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{one:"in {0} month",other:"in {0} months"},past:{one:"{0} month ago",other:"{0} months ago"}}},"month-short":{displayName:"mo.",relative:{0:"this mo.",1:"next mo.","-1":"last mo."},relativeTime:{future:{one:"in {0} mo.",other:"in {0} mo."},past:{one:"{0} mo. ago",other:"{0} mo. ago"}}},day:{displayName:"day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{one:"in {0} day",other:"in {0} days"},past:{one:"{0} day ago",other:"{0} days ago"}}},"day-short":{displayName:"day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{one:"in {0} day",other:"in {0} days"},past:{one:"{0} day ago",other:"{0} days ago"}}},hour:{displayName:"hour",relative:{0:"this hour"},relativeTime:{future:{one:"in {0} hour",other:"in {0} hours"},past:{one:"{0} hour ago",other:"{0} hours ago"}}},"hour-short":{displayName:"h",relative:{0:"this hour"},relativeTime:{future:{one:"in {0} hr",other:"in {0} hrs"},past:{one:"{0} hr ago",other:"{0} hrs ago"}}},minute:{displayName:"minute",relative:{0:"this minute"},relativeTime:{future:{one:"in {0} minute",other:"in {0} minutes"},past:{one:"{0} minute ago",other:"{0} minutes ago"}}},"minute-short":{displayName:"min.",relative:{0:"this minute"},relativeTime:{future:{one:"in {0} min.",other:"in {0} mins"},past:{one:"{0} min. ago",other:"{0} mins ago"}}},second:{displayName:"second",relative:{0:"now"},relativeTime:{future:{one:"in {0} second",other:"in {0} seconds"},past:{one:"{0} second ago",other:"{0} seconds ago"}}},"second-short":{displayName:"sec.",relative:{0:"now"},relativeTime:{future:{one:"in {0} sec.",other:"in {0} secs"},past:{one:"{0} sec. ago",other:"{0} secs ago"}}}}},{locale:"en-BB",parentLocale:"en-001"},{locale:"en-BE",parentLocale:"en-001"},{locale:"en-BI",parentLocale:"en"},{locale:"en-BM",parentLocale:"en-001"},{locale:"en-BS",parentLocale:"en-001"},{locale:"en-BW",parentLocale:"en-001"},{locale:"en-BZ",parentLocale:"en-001"},{locale:"en-CA",parentLocale:"en-001",fields:{year:{displayName:"year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{one:"in {0} year",other:"in {0} years"},past:{one:"{0} year ago",other:"{0} years ago"}}},"year-short":{displayName:"yr.",relative:{0:"this yr.",1:"next yr.","-1":"last yr."},relativeTime:{future:{one:"in {0} yr.",other:"in {0} yrs."},past:{one:"{0} yr. ago",other:"{0} yrs. ago"}}},month:{displayName:"month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{one:"in {0} month",other:"in {0} months"},past:{one:"{0} month ago",other:"{0} months ago"}}},"month-short":{displayName:"mo.",relative:{0:"this mo.",1:"next mo.","-1":"last mo."},relativeTime:{future:{one:"in {0} mo.",other:"in {0} mos."},past:{one:"{0} mo. ago",other:"{0} mos. ago"}}},day:{displayName:"day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{one:"in {0} day",other:"in {0} days"},past:{one:"{0} day ago",other:"{0} days ago"}}},"day-short":{displayName:"day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{one:"in {0} day",other:"in {0} days"},past:{one:"{0} day ago",other:"{0} days ago"}}},hour:{displayName:"hour",relative:{0:"this hour"},relativeTime:{future:{one:"in {0} hour",other:"in {0} hours"},past:{one:"{0} hour ago",other:"{0} hours ago"}}},"hour-short":{displayName:"hr.",relative:{0:"this hour"},relativeTime:{future:{one:"in {0} hr.",other:"in {0} hrs."},past:{one:"{0} hr. ago",other:"{0} hrs. ago"}}},minute:{displayName:"minute",relative:{0:"this minute"},relativeTime:{future:{one:"in {0} minute",other:"in {0} minutes"},past:{one:"{0} minute ago",other:"{0} minutes ago"}}},"minute-short":{displayName:"min.",relative:{0:"this minute"},relativeTime:{future:{one:"in {0} min.",other:"in {0} mins."},past:{one:"{0} min. ago",other:"{0} mins. ago"}}},second:{displayName:"second",relative:{0:"now"},relativeTime:{future:{one:"in {0} second",other:"in {0} seconds"},past:{one:"{0} second ago",other:"{0} seconds ago"}}},"second-short":{displayName:"sec.",relative:{0:"now"},relativeTime:{future:{one:"in {0} sec.",other:"in {0} secs."},past:{one:"{0} sec. ago",other:"{0} secs. ago"}}}}},{locale:"en-CC",parentLocale:"en-001"},{locale:"en-CH",parentLocale:"en-150"},{locale:"en-CK",parentLocale:"en-001"},{locale:"en-CM",parentLocale:"en-001"},{locale:"en-CX",parentLocale:"en-001"},{locale:"en-CY",parentLocale:"en-001"},{locale:"en-DE",parentLocale:"en-150"},{locale:"en-DG",parentLocale:"en-001"},{locale:"en-DK",parentLocale:"en-150"},{locale:"en-DM",parentLocale:"en-001"},{locale:"en-Dsrt",pluralRuleFunction:function(e,a){return"other"},fields:{year:{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},"year-short":{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},month:{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},"month-short":{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},day:{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},"day-short":{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},hour:{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},"hour-short":{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},minute:{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},"minute-short":{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},second:{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}},"second-short":{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}}}},{locale:"en-ER",parentLocale:"en-001"},{locale:"en-FI",parentLocale:"en-150"},{locale:"en-FJ",parentLocale:"en-001"},{locale:"en-FK",parentLocale:"en-001"},{locale:"en-FM",parentLocale:"en-001"},{locale:"en-GB",parentLocale:"en-001"},{locale:"en-GD",parentLocale:"en-001"},{locale:"en-GG",parentLocale:"en-001"},{locale:"en-GH",parentLocale:"en-001"},{locale:"en-GI",parentLocale:"en-001"},{locale:"en-GM",parentLocale:"en-001"},{locale:"en-GU",parentLocale:"en"},{locale:"en-GY",parentLocale:"en-001"},{locale:"en-HK",parentLocale:"en-001"},{locale:"en-IE",parentLocale:"en-001"},{locale:"en-IL",parentLocale:"en-001"},{locale:"en-IM",parentLocale:"en-001"},{locale:"en-IN",parentLocale:"en-001"},{locale:"en-IO",parentLocale:"en-001"},{locale:"en-JE",parentLocale:"en-001"},{locale:"en-JM",parentLocale:"en-001"},{locale:"en-KE",parentLocale:"en-001"},{locale:"en-KI",parentLocale:"en-001"},{locale:"en-KN",parentLocale:"en-001"},{locale:"en-KY",parentLocale:"en-001"},{locale:"en-LC",parentLocale:"en-001"},{locale:"en-LR",parentLocale:"en-001"},{locale:"en-LS",parentLocale:"en-001"},{locale:"en-MG",parentLocale:"en-001"},{locale:"en-MH",parentLocale:"en"},{locale:"en-MO",parentLocale:"en-001"},{locale:"en-MP",parentLocale:"en"},{locale:"en-MS",parentLocale:"en-001"},{locale:"en-MT",parentLocale:"en-001"},{locale:"en-MU",parentLocale:"en-001"},{locale:"en-MW",parentLocale:"en-001"},{locale:"en-MY",parentLocale:"en-001"},{locale:"en-NA",parentLocale:"en-001"},{locale:"en-NF",parentLocale:"en-001"},{locale:"en-NG",parentLocale:"en-001"},{locale:"en-NL",parentLocale:"en-150"},{locale:"en-NR",parentLocale:"en-001"},{locale:"en-NU",parentLocale:"en-001"},{locale:"en-NZ",parentLocale:"en-001"},{locale:"en-PG",parentLocale:"en-001"},{locale:"en-PH",parentLocale:"en-001"},{locale:"en-PK",parentLocale:"en-001"},{locale:"en-PN",parentLocale:"en-001"},{locale:"en-PR",parentLocale:"en"},{locale:"en-PW",parentLocale:"en-001"},{locale:"en-RW",parentLocale:"en-001"},{locale:"en-SB",parentLocale:"en-001"},{locale:"en-SC",parentLocale:"en-001"},{locale:"en-SD",parentLocale:"en-001"},{locale:"en-SE",parentLocale:"en-150"},{locale:"en-SG",parentLocale:"en-001",fields:{year:{displayName:"year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{one:"in {0} year",other:"in {0} years"},past:{one:"{0} year ago",other:"{0} years ago"}}},"year-short":{displayName:"yr",relative:{0:"this yr",1:"next yr","-1":"last yr"},relativeTime:{future:{one:"in {0} yr",other:"in {0} yr"},past:{one:"{0} yr ago",other:"{0} yr ago"}}},month:{displayName:"month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{one:"in {0} month",other:"in {0} months"},past:{one:"{0} month ago",other:"{0} months ago"}}},"month-short":{displayName:"mth",relative:{0:"this mth",1:"next mth","-1":"last mth"},relativeTime:{future:{one:"in {0} mth",other:"in {0} mth"},past:{one:"{0} mth ago",other:"{0} mth ago"}}},day:{displayName:"day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{one:"in {0} day",other:"in {0} days"},past:{one:"{0} day ago",other:"{0} days ago"}}},"day-short":{displayName:"day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{one:"in {0} day",other:"in {0} days"},past:{one:"{0} day ago",other:"{0} days ago"}}},hour:{displayName:"hour",relative:{0:"this hour"},relativeTime:{future:{one:"in {0} hour",other:"in {0} hours"},past:{one:"{0} hour ago",other:"{0} hours ago"}}},"hour-short":{displayName:"hr",relative:{0:"this hour"},relativeTime:{future:{one:"in {0} hr",other:"in {0} hr"},past:{one:"{0} hr ago",other:"{0} hr ago"}}},minute:{displayName:"minute",relative:{0:"this minute"},relativeTime:{future:{one:"in {0} minute",other:"in {0} minutes"},past:{one:"{0} minute ago",other:"{0} minutes ago"}}},"minute-short":{displayName:"min",relative:{0:"this minute"},relativeTime:{future:{one:"in {0} min",other:"in {0} min"},past:{one:"{0} min ago",other:"{0} min ago"}}},second:{displayName:"second",relative:{0:"now"},relativeTime:{future:{one:"in {0} second",other:"in {0} seconds"},past:{one:"{0} second ago",other:"{0} seconds ago"}}},"second-short":{displayName:"sec",relative:{0:"now"},relativeTime:{future:{one:"in {0} sec",other:"in {0} sec"},past:{one:"{0} sec ago",other:"{0} sec ago"}}}}},{locale:"en-SH",parentLocale:"en-001"},{locale:"en-SI",parentLocale:"en-150"},{locale:"en-SL",parentLocale:"en-001"},{locale:"en-SS",parentLocale:"en-001"},{locale:"en-SX",parentLocale:"en-001"},{locale:"en-SZ",parentLocale:"en-001"},{locale:"en-Shaw",pluralRuleFunction:function(e,a){return"other"},fields:{year:{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},"year-short":{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},month:{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},"month-short":{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},day:{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},"day-short":{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},hour:{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},"hour-short":{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},minute:{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},"minute-short":{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},second:{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}},"second-short":{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}}}},{locale:"en-TC",parentLocale:"en-001"},{locale:"en-TK",parentLocale:"en-001"},{locale:"en-TO",parentLocale:"en-001"},{locale:"en-TT",parentLocale:"en-001"},{locale:"en-TV",parentLocale:"en-001"},{locale:"en-TZ",parentLocale:"en-001"},{locale:"en-UG",parentLocale:"en-001"},{locale:"en-UM",parentLocale:"en"},{locale:"en-US",parentLocale:"en"},{locale:"en-VC",parentLocale:"en-001"},{locale:"en-VG",parentLocale:"en-001"},{locale:"en-VI",parentLocale:"en"},{locale:"en-VU",parentLocale:"en-001"},{locale:"en-WS",parentLocale:"en-001"},{locale:"en-ZA",parentLocale:"en-001"},{locale:"en-ZM",parentLocale:"en-001"},{locale:"en-ZW",parentLocale:"en-001"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/eo.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/eo.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"eo",pluralRuleFunction:function(e,t){return t?"other":1==e?"one":"other"},fields:{year:{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},"year-short":{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},month:{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},"month-short":{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},day:{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},"day-short":{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},hour:{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},"hour-short":{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},minute:{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},"minute-short":{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},second:{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}},"second-short":{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/es.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/es.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,a){ true?module.exports=a():undefined}(this,function(){"use strict";return[{locale:"es",pluralRuleFunction:function(e,a){return a?"other":1==e?"one":"other"},fields:{year:{displayName:"año",relative:{0:"este año",1:"el próximo año","-1":"el año pasado"},relativeTime:{future:{one:"dentro de {0} año",other:"dentro de {0} años"},past:{one:"hace {0} año",other:"hace {0} años"}}},"year-short":{displayName:"a",relative:{0:"este año",1:"el próximo año","-1":"el año pasado"},relativeTime:{future:{one:"dentro de {0} a",other:"dentro de {0} a"},past:{one:"hace {0} a",other:"hace {0} a"}}},month:{displayName:"mes",relative:{0:"este mes",1:"el próximo mes","-1":"el mes pasado"},relativeTime:{future:{one:"dentro de {0} mes",other:"dentro de {0} meses"},past:{one:"hace {0} mes",other:"hace {0} meses"}}},"month-short":{displayName:"m",relative:{0:"este mes",1:"el próximo mes","-1":"el mes pasado"},relativeTime:{future:{one:"dentro de {0} m",other:"dentro de {0} m"},past:{one:"hace {0} m",other:"hace {0} m"}}},day:{displayName:"día",relative:{0:"hoy",1:"mañana",2:"pasado mañana","-2":"anteayer","-1":"ayer"},relativeTime:{future:{one:"dentro de {0} día",other:"dentro de {0} días"},past:{one:"hace {0} día",other:"hace {0} días"}}},"day-short":{displayName:"d",relative:{0:"hoy",1:"mañana",2:"pasado mañana","-2":"anteayer","-1":"ayer"},relativeTime:{future:{one:"dentro de {0} día",other:"dentro de {0} días"},past:{one:"hace {0} día",other:"hace {0} días"}}},hour:{displayName:"hora",relative:{0:"esta hora"},relativeTime:{future:{one:"dentro de {0} hora",other:"dentro de {0} horas"},past:{one:"hace {0} hora",other:"hace {0} horas"}}},"hour-short":{displayName:"h",relative:{0:"esta hora"},relativeTime:{future:{one:"dentro de {0} h",other:"dentro de {0} h"},past:{one:"hace {0} h",other:"hace {0} h"}}},minute:{displayName:"minuto",relative:{0:"este minuto"},relativeTime:{future:{one:"dentro de {0} minuto",other:"dentro de {0} minutos"},past:{one:"hace {0} minuto",other:"hace {0} minutos"}}},"minute-short":{displayName:"min",relative:{0:"este minuto"},relativeTime:{future:{one:"dentro de {0} min",other:"dentro de {0} min"},past:{one:"hace {0} min",other:"hace {0} min"}}},second:{displayName:"segundo",relative:{0:"ahora"},relativeTime:{future:{one:"dentro de {0} segundo",other:"dentro de {0} segundos"},past:{one:"hace {0} segundo",other:"hace {0} segundos"}}},"second-short":{displayName:"s",relative:{0:"ahora"},relativeTime:{future:{one:"dentro de {0} s",other:"dentro de {0} s"},past:{one:"hace {0} s",other:"hace {0} s"}}}}},{locale:"es-419",parentLocale:"es"},{locale:"es-AR",parentLocale:"es-419",fields:{year:{displayName:"año",relative:{0:"este año",1:"el próximo año","-1":"el año pasado"},relativeTime:{future:{one:"dentro de {0} año",other:"dentro de {0} años"},past:{one:"hace {0} año",other:"hace {0} años"}}},"year-short":{displayName:"a",relative:{0:"este año",1:"el próximo año","-1":"el año pasado"},relativeTime:{future:{one:"dentro de {0} a",other:"dentro de {0} a"},past:{one:"hace {0} a",other:"hace {0} a"}}},month:{displayName:"mes",relative:{0:"este mes",1:"el próximo mes","-1":"el mes pasado"},relativeTime:{future:{one:"dentro de {0} mes",other:"dentro de {0} meses"},past:{one:"hace {0} mes",other:"hace {0} meses"}}},"month-short":{displayName:"m",relative:{0:"este mes",1:"el próximo mes","-1":"el mes pasado"},relativeTime:{future:{one:"dentro de {0} m",other:"dentro de {0} m"},past:{one:"hace {0} m",other:"hace {0} m"}}},day:{displayName:"día",relative:{0:"hoy",1:"mañana",2:"pasado mañana","-2":"anteayer","-1":"ayer"},relativeTime:{future:{one:"dentro de {0} día",other:"dentro de {0} días"},past:{one:"hace {0} día",other:"hace {0} días"}}},"day-short":{displayName:"d",relative:{0:"hoy",1:"mañana",2:"pasado mañana","-2":"anteayer","-1":"ayer"},relativeTime:{future:{one:"dentro de {0} días",other:"dentro de {0} días"},past:{one:"hace {0} días",other:"hace {0} días"}}},hour:{displayName:"hora",relative:{0:"esta hora"},relativeTime:{future:{one:"dentro de {0} hora",other:"dentro de {0} horas"},past:{one:"hace {0} hora",other:"hace {0} horas"}}},"hour-short":{displayName:"h",relative:{0:"esta hora"},relativeTime:{future:{one:"dentro de {0} h",other:"dentro de {0} h"},past:{one:"hace {0} h",other:"hace {0} h"}}},minute:{displayName:"minuto",relative:{0:"este minuto"},relativeTime:{future:{one:"dentro de {0} minuto",other:"dentro de {0} minutos"},past:{one:"hace {0} minuto",other:"hace {0} minutos"}}},"minute-short":{displayName:"min",relative:{0:"este minuto"},relativeTime:{future:{one:"dentro de {0} min",other:"dentro de {0} min"},past:{one:"hace {0} min",other:"hace {0} min"}}},second:{displayName:"segundo",relative:{0:"ahora"},relativeTime:{future:{one:"dentro de {0} segundo",other:"dentro de {0} segundos"},past:{one:"hace {0} segundo",other:"hace {0} segundos"}}},"second-short":{displayName:"seg.",relative:{0:"ahora"},relativeTime:{future:{one:"dentro de {0} seg.",other:"dentro de {0} seg."},past:{one:"hace {0} seg.",other:"hace {0} seg."}}}}},{locale:"es-BO",parentLocale:"es-419"},{locale:"es-BR",parentLocale:"es-419"},{locale:"es-BZ",parentLocale:"es-419"},{locale:"es-CL",parentLocale:"es-419"},{locale:"es-CO",parentLocale:"es-419"},{locale:"es-CR",parentLocale:"es-419"},{locale:"es-CU",parentLocale:"es-419"},{locale:"es-DO",parentLocale:"es-419",fields:{year:{displayName:"Año",relative:{0:"este año",1:"el próximo año","-1":"el año pasado"},relativeTime:{future:{one:"dentro de {0} año",other:"dentro de {0} años"},past:{one:"hace {0} año",other:"hace {0} años"}}},"year-short":{displayName:"a",relative:{0:"este año",1:"el próximo año","-1":"el año pasado"},relativeTime:{future:{one:"dentro de {0} a",other:"dentro de {0} a"},past:{one:"hace {0} a",other:"hace {0} a"}}},month:{displayName:"Mes",relative:{0:"este mes",1:"el próximo mes","-1":"el mes pasado"},relativeTime:{future:{one:"dentro de {0} mes",other:"dentro de {0} meses"},past:{one:"hace {0} mes",other:"hace {0} meses"}}},"month-short":{displayName:"m",relative:{0:"este mes",1:"el próximo mes","-1":"el mes pasado"},relativeTime:{future:{one:"dentro de {0} m",other:"dentro de {0} m"},past:{one:"hace {0} m",other:"hace {0} m"}}},day:{displayName:"Día",relative:{0:"hoy",1:"mañana",2:"pasado mañana","-2":"anteayer","-1":"ayer"},relativeTime:{future:{one:"dentro de {0} día",other:"dentro de {0} días"},past:{one:"hace {0} día",other:"hace {0} días"}}},"day-short":{displayName:"d",relative:{0:"hoy",1:"mañana",2:"pasado mañana","-2":"anteayer","-1":"ayer"},relativeTime:{future:{one:"dentro de {0} día",other:"dentro de {0} días"},past:{one:"hace {0} día",other:"hace {0} días"}}},hour:{displayName:"hora",relative:{0:"esta hora"},relativeTime:{future:{one:"dentro de {0} hora",other:"dentro de {0} horas"},past:{one:"hace {0} hora",other:"hace {0} horas"}}},"hour-short":{displayName:"h",relative:{0:"esta hora"},relativeTime:{future:{one:"dentro de {0} h",other:"dentro de {0} h"},past:{one:"hace {0} h",other:"hace {0} h"}}},minute:{displayName:"Minuto",relative:{0:"este minuto"},relativeTime:{future:{one:"dentro de {0} minuto",other:"dentro de {0} minutos"},past:{one:"hace {0} minuto",other:"hace {0} minutos"}}},"minute-short":{displayName:"min",relative:{0:"este minuto"},relativeTime:{future:{one:"dentro de {0} min",other:"dentro de {0} min"},past:{one:"hace {0} min",other:"hace {0} min"}}},second:{displayName:"Segundo",relative:{0:"ahora"},relativeTime:{future:{one:"dentro de {0} segundo",other:"dentro de {0} segundos"},past:{one:"hace {0} segundo",other:"hace {0} segundos"}}},"second-short":{displayName:"s",relative:{0:"ahora"},relativeTime:{future:{one:"dentro de {0} s",other:"dentro de {0} s"},past:{one:"hace {0} s",other:"hace {0} s"}}}}},{locale:"es-EA",parentLocale:"es"},{locale:"es-EC",parentLocale:"es-419"},{locale:"es-GQ",parentLocale:"es"},{locale:"es-GT",parentLocale:"es-419"},{locale:"es-HN",parentLocale:"es-419"},{locale:"es-IC",parentLocale:"es"},{locale:"es-MX",parentLocale:"es-419",fields:{year:{displayName:"año",relative:{0:"este año",1:"el año próximo","-1":"el año pasado"},relativeTime:{future:{one:"dentro de {0} año",other:"dentro de {0} años"},past:{one:"hace {0} año",other:"hace {0} años"}}},"year-short":{displayName:"a",relative:{0:"este año",1:"el próximo año","-1":"el año pasado"},relativeTime:{future:{one:"en {0} a",other:"en {0} a"},past:{one:"hace {0} a",other:"hace {0} a"}}},month:{displayName:"mes",relative:{0:"este mes",1:"el mes próximo","-1":"el mes pasado"},relativeTime:{future:{one:"en {0} mes",other:"en {0} meses"},past:{one:"hace {0} mes",other:"hace {0} meses"}}},"month-short":{displayName:"m",relative:{0:"este mes",1:"el próximo mes","-1":"el mes pasado"},relativeTime:{future:{one:"en {0} m",other:"en {0} m"},past:{one:"hace {0} m",other:"hace {0} m"}}},day:{displayName:"día",relative:{0:"hoy",1:"mañana",2:"pasado mañana","-2":"anteayer","-1":"ayer"},relativeTime:{future:{one:"dentro de {0} día",other:"dentro de {0} días"},past:{one:"hace {0} día",other:"hace {0} días"}}},"day-short":{displayName:"d",relative:{0:"hoy",1:"mañana",2:"pasado mañana","-2":"anteayer","-1":"ayer"},relativeTime:{future:{one:"en {0} día",other:"en {0} días"},past:{one:"hace {0} día",other:"hace {0} días"}}},hour:{displayName:"hora",relative:{0:"esta hora"},relativeTime:{future:{one:"dentro de {0} hora",other:"dentro de {0} horas"},past:{one:"hace {0} hora",other:"hace {0} horas"}}},"hour-short":{displayName:"h",relative:{0:"esta hora"},relativeTime:{future:{one:"en {0} h",other:"en {0} n"},past:{one:"hace {0} h",other:"hace {0} h"}}},minute:{displayName:"minuto",relative:{0:"este minuto"},relativeTime:{future:{one:"dentro de {0} minuto",other:"dentro de {0} minutos"},past:{one:"hace {0} minuto",other:"hace {0} minutos"}}},"minute-short":{displayName:"min",relative:{0:"este minuto"},relativeTime:{future:{one:"en {0} min",other:"en {0} min"},past:{one:"hace {0} min",other:"hace {0} min"}}},second:{displayName:"segundo",relative:{0:"ahora"},relativeTime:{future:{one:"dentro de {0} segundo",other:"dentro de {0} segundos"},past:{one:"hace {0} segundo",other:"hace {0} segundos"}}},"second-short":{displayName:"s",relative:{0:"ahora"},relativeTime:{future:{one:"en {0} s",other:"en {0} s"},past:{one:"hace {0} s",other:"hace {0} s"}}}}},{locale:"es-NI",parentLocale:"es-419"},{locale:"es-PA",parentLocale:"es-419"},{locale:"es-PE",parentLocale:"es-419"},{locale:"es-PH",parentLocale:"es"},{locale:"es-PR",parentLocale:"es-419"},{locale:"es-PY",parentLocale:"es-419",fields:{year:{displayName:"año",relative:{0:"este año",1:"el próximo año","-1":"el año pasado"},relativeTime:{future:{one:"dentro de {0} año",other:"dentro de {0} años"},past:{one:"hace {0} año",other:"hace {0} años"}}},"year-short":{displayName:"a",relative:{0:"este año",1:"el próximo año","-1":"el año pasado"},relativeTime:{future:{one:"dentro de {0} a",other:"dentro de {0} a"},past:{one:"hace {0} a",other:"hace {0} a"}}},month:{displayName:"mes",relative:{0:"este mes",1:"el próximo mes","-1":"el mes pasado"},relativeTime:{future:{one:"dentro de {0} mes",other:"dentro de {0} meses"},past:{one:"hace {0} mes",other:"hace {0} meses"}}},"month-short":{displayName:"m",relative:{0:"este mes",1:"el próximo mes","-1":"el mes pasado"},relativeTime:{future:{one:"dentro de {0} m",other:"dentro de {0} m"},past:{one:"hace {0} m",other:"hace {0} m"}}},day:{displayName:"día",relative:{0:"hoy",1:"mañana",2:"pasado mañana","-2":"anteayer","-1":"ayer"},relativeTime:{future:{one:"dentro de {0} día",other:"dentro de {0} días"},past:{one:"hace {0} día",other:"hace {0} días"}}},"day-short":{displayName:"d",relative:{0:"hoy",1:"mañana",2:"pasado mañana","-2":"anteayer","-1":"ayer"},relativeTime:{future:{one:"dentro de {0} día",other:"dentro de {0} días"},past:{one:"hace {0} día",other:"hace {0} días"}}},hour:{displayName:"hora",relative:{0:"esta hora"},relativeTime:{future:{one:"dentro de {0} hora",other:"dentro de {0} horas"},past:{one:"hace {0} hora",other:"hace {0} horas"}}},"hour-short":{displayName:"h",relative:{0:"esta hora"},relativeTime:{future:{one:"dentro de {0} h",other:"dentro de {0} h"},past:{one:"hace {0} h",other:"hace {0} h"}}},minute:{displayName:"minuto",relative:{0:"este minuto"},relativeTime:{future:{one:"dentro de {0} minuto",other:"dentro de {0} minutos"},past:{one:"hace {0} minuto",other:"hace {0} minutos"}}},"minute-short":{displayName:"min",relative:{0:"este minuto"},relativeTime:{future:{one:"dentro de {0} min",other:"dentro de {0} min"},past:{one:"hace {0} min",other:"hace {0} min"}}},second:{displayName:"segundo",relative:{0:"ahora"},relativeTime:{future:{one:"dentro de {0} segundo",other:"dentro de {0} segundos"},past:{one:"hace {0} segundo",other:"hace {0} segundos"}}},"second-short":{displayName:"seg.",relative:{0:"ahora"},relativeTime:{future:{one:"dentro de {0} seg.",other:"dentro de {0} seg."},past:{one:"hace {0} seg.",other:"hace {0} seg."}}}}},{locale:"es-SV",parentLocale:"es-419",fields:{year:{displayName:"año",relative:{0:"este año",1:"el próximo año","-1":"el año pasado"},relativeTime:{future:{one:"dentro de {0} año",other:"dentro de {0} años"},past:{one:"hace {0} año",other:"hace {0} años"}}},"year-short":{displayName:"a",relative:{0:"este año",1:"el próximo año","-1":"el año pasado"},relativeTime:{future:{one:"dentro de {0} a",other:"dentro de {0} a"},past:{one:"hace {0} a",other:"hace {0} a"}}},month:{displayName:"mes",relative:{0:"este mes",1:"el próximo mes","-1":"el mes pasado"},relativeTime:{future:{one:"dentro de {0} mes",other:"dentro de {0} meses"},past:{one:"hace {0} mes",other:"hace {0} meses"}}},"month-short":{displayName:"m",relative:{0:"este mes",1:"el próximo mes","-1":"el mes pasado"},relativeTime:{future:{one:"dentro de {0} m",other:"dentro de {0} m"},past:{one:"hace {0} m",other:"hace {0} m"}}},day:{displayName:"día",relative:{0:"hoy",1:"mañana",2:"pasado mañana","-2":"antier","-1":"ayer"},relativeTime:{future:{one:"dentro de {0} día",other:"dentro de {0} días"},past:{one:"hace {0} día",other:"hace {0} días"}}},"day-short":{displayName:"d",relative:{0:"hoy",1:"mañana",2:"pasado mañana","-2":"anteayer","-1":"ayer"},relativeTime:{future:{one:"dentro de {0} día",other:"dentro de {0} días"},past:{one:"hace {0} día",other:"hace {0} días"}}},hour:{displayName:"hora",relative:{0:"esta hora"},relativeTime:{future:{one:"dentro de {0} hora",other:"dentro de {0} horas"},past:{one:"hace {0} hora",other:"hace {0} horas"}}},"hour-short":{displayName:"h",relative:{0:"esta hora"},relativeTime:{future:{one:"dentro de {0} h",other:"dentro de {0} h"},past:{one:"hace {0} h",other:"hace {0} h"}}},minute:{displayName:"minuto",relative:{0:"este minuto"},relativeTime:{future:{one:"dentro de {0} minuto",other:"dentro de {0} minutos"},past:{one:"hace {0} minuto",other:"hace {0} minutos"}}},"minute-short":{displayName:"min",relative:{0:"este minuto"},relativeTime:{future:{one:"dentro de {0} min",other:"dentro de {0} min"},past:{one:"hace {0} min",other:"hace {0} min"}}},second:{displayName:"segundo",relative:{0:"ahora"},relativeTime:{future:{one:"dentro de {0} segundo",other:"dentro de {0} segundos"},past:{one:"hace {0} segundo",other:"hace {0} segundos"}}},"second-short":{displayName:"s",relative:{0:"ahora"},relativeTime:{future:{one:"dentro de {0} s",other:"dentro de {0} s"},past:{one:"hace {0} s",other:"hace {0} s"}}}}},{locale:"es-US",parentLocale:"es-419",fields:{year:{displayName:"año",relative:{0:"este año",1:"el año próximo","-1":"el año pasado"},relativeTime:{future:{one:"dentro de {0} año",other:"dentro de {0} años"},past:{one:"hace {0} año",other:"hace {0} años"}}},"year-short":{displayName:"a",relative:{0:"este año",1:"el próximo año","-1":"el año pasado"},relativeTime:{future:{one:"dentro de {0} a",other:"dentro de {0} a"},past:{one:"hace {0} a",other:"hace {0} a"}}},month:{displayName:"mes",relative:{0:"este mes",1:"el mes próximo","-1":"el mes pasado"},relativeTime:{future:{one:"dentro de {0} mes",other:"dentro de {0} meses"},past:{one:"hace {0} mes",other:"hace {0} meses"}}},"month-short":{displayName:"m",relative:{0:"este mes",1:"el próximo mes","-1":"el mes pasado"},relativeTime:{future:{one:"dentro de {0} m",other:"dentro de {0} m"},past:{one:"hace {0} m",other:"hace {0} m"}}},day:{displayName:"día",relative:{0:"hoy",1:"mañana",2:"pasado mañana","-2":"anteayer","-1":"ayer"},relativeTime:{future:{one:"dentro de {0} día",other:"dentro de {0} días"},past:{one:"hace {0} día",other:"hace {0} días"}}},"day-short":{displayName:"d",relative:{0:"hoy",1:"mañana",2:"pasado mañana","-2":"anteayer","-1":"ayer"},relativeTime:{future:{one:"dentro de {0} día",other:"dentro de {0} días"},past:{one:"hace {0} día",other:"hace {0} días"}}},hour:{displayName:"hora",relative:{0:"esta hora"},relativeTime:{future:{one:"dentro de {0} hora",other:"dentro de {0} horas"},past:{one:"hace {0} hora",other:"hace {0} horas"}}},"hour-short":{displayName:"h",relative:{0:"esta hora"},relativeTime:{future:{one:"dentro de {0} h",other:"dentro de {0} h"},past:{one:"hace {0} h",other:"hace {0} h"}}},minute:{displayName:"minuto",relative:{0:"este minuto"},relativeTime:{future:{one:"dentro de {0} minuto",other:"dentro de {0} minutos"},past:{one:"hace {0} minuto",other:"hace {0} minutos"}}},"minute-short":{displayName:"min",relative:{0:"este minuto"},relativeTime:{future:{one:"dentro de {0} min",other:"dentro de {0} min"},past:{one:"hace {0} min",other:"hace {0} min"}}},second:{displayName:"segundo",relative:{0:"ahora"},relativeTime:{future:{one:"dentro de {0} segundo",other:"dentro de {0} segundos"},past:{one:"hace {0} segundo",other:"hace {0} segundos"}}},"second-short":{displayName:"s",relative:{0:"ahora"},relativeTime:{future:{one:"dentro de {0} s",other:"dentro de {0} s"},past:{one:"hace {0} s",other:"hace {0} s"}}}}},{locale:"es-UY",parentLocale:"es-419"},{locale:"es-VE",parentLocale:"es-419"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/et.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/et.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"et",pluralRuleFunction:function(e,t){var a=!String(e).split(".")[1];return t?"other":1==e&&a?"one":"other"},fields:{year:{displayName:"aasta",relative:{0:"käesolev aasta",1:"järgmine aasta","-1":"eelmine aasta"},relativeTime:{future:{one:"{0} aasta pärast",other:"{0} aasta pärast"},past:{one:"{0} aasta eest",other:"{0} aasta eest"}}},"year-short":{displayName:"a",relative:{0:"käesolev aasta",1:"järgmine aasta","-1":"eelmine aasta"},relativeTime:{future:{one:"{0} a pärast",other:"{0} a pärast"},past:{one:"{0} a eest",other:"{0} a eest"}}},month:{displayName:"kuu",relative:{0:"käesolev kuu",1:"järgmine kuu","-1":"eelmine kuu"},relativeTime:{future:{one:"{0} kuu pärast",other:"{0} kuu pärast"},past:{one:"{0} kuu eest",other:"{0} kuu eest"}}},"month-short":{displayName:"k",relative:{0:"käesolev kuu",1:"järgmine kuu","-1":"eelmine kuu"},relativeTime:{future:{one:"{0} kuu pärast",other:"{0} kuu pärast"},past:{one:"{0} kuu eest",other:"{0} kuu eest"}}},day:{displayName:"päev",relative:{0:"täna",1:"homme",2:"ülehomme","-2":"üleeile","-1":"eile"},relativeTime:{future:{one:"{0} päeva pärast",other:"{0} päeva pärast"},past:{one:"{0} päeva eest",other:"{0} päeva eest"}}},"day-short":{displayName:"p",relative:{0:"täna",1:"homme",2:"ülehomme","-2":"üleeile","-1":"eile"},relativeTime:{future:{one:"{0} p pärast",other:"{0} p pärast"},past:{one:"{0} p eest",other:"{0} p eest"}}},hour:{displayName:"tund",relative:{0:"praegusel tunnil"},relativeTime:{future:{one:"{0} tunni pärast",other:"{0} tunni pärast"},past:{one:"{0} tunni eest",other:"{0} tunni eest"}}},"hour-short":{displayName:"t",relative:{0:"praegusel tunnil"},relativeTime:{future:{one:"{0} t pärast",other:"{0} t pärast"},past:{one:"{0} t eest",other:"{0} t eest"}}},minute:{displayName:"minut",relative:{0:"praegusel minutil"},relativeTime:{future:{one:"{0} minuti pärast",other:"{0} minuti pärast"},past:{one:"{0} minuti eest",other:"{0} minuti eest"}}},"minute-short":{displayName:"min",relative:{0:"praegusel minutil"},relativeTime:{future:{one:"{0} min pärast",other:"{0} min pärast"},past:{one:"{0} min eest",other:"{0} min eest"}}},second:{displayName:"sekund",relative:{0:"nüüd"},relativeTime:{future:{one:"{0} sekundi pärast",other:"{0} sekundi pärast"},past:{one:"{0} sekundi eest",other:"{0} sekundi eest"}}},"second-short":{displayName:"sek",relative:{0:"nüüd"},relativeTime:{future:{one:"{0} sek pärast",other:"{0} sek pärast"},past:{one:"{0} sek eest",other:"{0} sek eest"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/eu.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/eu.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,a){ true?module.exports=a():undefined}(this,function(){"use strict";return[{locale:"eu",pluralRuleFunction:function(e,a){return a?"other":1==e?"one":"other"},fields:{year:{displayName:"urtea",relative:{0:"aurten",1:"hurrengo urtean","-1":"iaz"},relativeTime:{future:{one:"{0} urte barru",other:"{0} urte barru"},past:{one:"Duela {0} urte",other:"Duela {0} urte"}}},"year-short":{displayName:"urtea",relative:{0:"aurten",1:"hurrengo urtea","-1":"aurreko urtea"},relativeTime:{future:{one:"{0} urte barru",other:"{0} urte barru"},past:{one:"Duela {0} urte",other:"Duela {0} urte"}}},month:{displayName:"hilabetea",relative:{0:"hilabete honetan",1:"hurrengo hilabetean","-1":"aurreko hilabetean"},relativeTime:{future:{one:"{0} hilabete barru",other:"{0} hilabete barru"},past:{one:"Duela {0} hilabete",other:"Duela {0} hilabete"}}},"month-short":{displayName:"hil.",relative:{0:"hilabete honetan",1:"hurrengo hilabetean","-1":"aurreko hilabetean"},relativeTime:{future:{one:"{0} hilabete barru",other:"{0} hilabete barru"},past:{one:"Duela {0} hilabete",other:"Duela {0} hilabete"}}},day:{displayName:"eguna",relative:{0:"gaur",1:"bihar",2:"etzi","-2":"herenegun","-1":"atzo"},relativeTime:{future:{one:"{0} egun barru",other:"{0} egun barru"},past:{one:"Duela {0} egun",other:"Duela {0} egun"}}},"day-short":{displayName:"eg.",relative:{0:"gaur",1:"bihar",2:"etzi","-2":"herenegun","-1":"atzo"},relativeTime:{future:{one:"{0} egun barru",other:"{0} egun barru"},past:{one:"Duela {0} egun",other:"Duela {0} egun"}}},hour:{displayName:"ordua",relative:{0:"ordu honetan"},relativeTime:{future:{one:"{0} ordu barru",other:"{0} ordu barru"},past:{one:"Duela {0} ordu",other:"Duela {0} ordu"}}},"hour-short":{displayName:"h",relative:{0:"ordu honetan"},relativeTime:{future:{one:"{0} ordu barru",other:"{0} ordu barru"},past:{one:"Duela {0} ordu",other:"Duela {0} ordu"}}},minute:{displayName:"minutua",relative:{0:"minutu honetan"},relativeTime:{future:{one:"{0} minutu barru",other:"{0} minutu barru"},past:{one:"Duela {0} minutu",other:"Duela {0} minutu"}}},"minute-short":{displayName:"min",relative:{0:"minutu honetan"},relativeTime:{future:{one:"{0} minutu barru",other:"{0} minutu barru"},past:{one:"Duela {0} minutu",other:"Duela {0} minutu"}}},second:{displayName:"segundoa",relative:{0:"orain"},relativeTime:{future:{one:"{0} segundo barru",other:"{0} segundo barru"},past:{one:"Duela {0} segundo",other:"Duela {0} segundo"}}},"second-short":{displayName:"s",relative:{0:"orain"},relativeTime:{future:{one:"{0} segundo barru",other:"{0} segundo barru"},past:{one:"Duela {0} segundo",other:"Duela {0} segundo"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/fa.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/fa.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"fa",pluralRuleFunction:function(e,t){return t?"other":e>=0&&e<=1?"one":"other"},fields:{year:{displayName:"سال",relative:{0:"امسال",1:"سال آینده","-1":"سال گذشته"},relativeTime:{future:{one:"{0} سال بعد",other:"{0} سال بعد"},past:{one:"{0} سال پیش",other:"{0} سال پیش"}}},"year-short":{displayName:"سال",relative:{0:"امسال",1:"سال آینده","-1":"سال گذشته"},relativeTime:{future:{one:"{0} سال بعد",other:"{0} سال بعد"},past:{one:"{0} سال پیش",other:"{0} سال پیش"}}},month:{displayName:"ماه",relative:{0:"این ماه",1:"ماه آینده","-1":"ماه گذشته"},relativeTime:{future:{one:"{0} ماه بعد",other:"{0} ماه بعد"},past:{one:"{0} ماه پیش",other:"{0} ماه پیش"}}},"month-short":{displayName:"ماه",relative:{0:"این ماه",1:"ماه آینده","-1":"ماه پیش"},relativeTime:{future:{one:"{0} ماه بعد",other:"{0} ماه بعد"},past:{one:"{0} ماه پیش",other:"{0} ماه پیش"}}},day:{displayName:"روز",relative:{0:"امروز",1:"فردا",2:"پس‌فردا","-2":"پریروز","-1":"دیروز"},relativeTime:{future:{one:"{0} روز بعد",other:"{0} روز بعد"},past:{one:"{0} روز پیش",other:"{0} روز پیش"}}},"day-short":{displayName:"روز",relative:{0:"امروز",1:"فردا",2:"پس‌فردا","-2":"پریروز","-1":"دیروز"},relativeTime:{future:{one:"{0} روز بعد",other:"{0} روز بعد"},past:{one:"{0} روز پیش",other:"{0} روز پیش"}}},hour:{displayName:"ساعت",relative:{0:"همین ساعت"},relativeTime:{future:{one:"{0} ساعت بعد",other:"{0} ساعت بعد"},past:{one:"{0} ساعت پیش",other:"{0} ساعت پیش"}}},"hour-short":{displayName:"ساعت",relative:{0:"همین ساعت"},relativeTime:{future:{one:"{0} ساعت بعد",other:"{0} ساعت بعد"},past:{one:"{0} ساعت پیش",other:"{0} ساعت پیش"}}},minute:{displayName:"دقیقه",relative:{0:"همین دقیقه"},relativeTime:{future:{one:"{0} دقیقه بعد",other:"{0} دقیقه بعد"},past:{one:"{0} دقیقه پیش",other:"{0} دقیقه پیش"}}},"minute-short":{displayName:"دقیقه",relative:{0:"همین دقیقه"},relativeTime:{future:{one:"{0} دقیقه بعد",other:"{0} دقیقه بعد"},past:{one:"{0} دقیقه پیش",other:"{0} دقیقه پیش"}}},second:{displayName:"ثانیه",relative:{0:"اکنون"},relativeTime:{future:{one:"{0} ثانیه بعد",other:"{0} ثانیه بعد"},past:{one:"{0} ثانیه پیش",other:"{0} ثانیه پیش"}}},"second-short":{displayName:"ثانیه",relative:{0:"اکنون"},relativeTime:{future:{one:"{0} ثانیه بعد",other:"{0} ثانیه بعد"},past:{one:"{0} ثانیه پیش",other:"{0} ثانیه پیش"}}}}},{locale:"fa-AF",parentLocale:"fa"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/fi.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/fi.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(t,e){ true?module.exports=e():undefined}(this,function(){"use strict";return[{locale:"fi",pluralRuleFunction:function(t,e){var i=!String(t).split(".")[1];return e?"other":1==t&&i?"one":"other"},fields:{year:{displayName:"vuosi",relative:{0:"tänä vuonna",1:"ensi vuonna","-1":"viime vuonna"},relativeTime:{future:{one:"{0} vuoden päästä",other:"{0} vuoden päästä"},past:{one:"{0} vuosi sitten",other:"{0} vuotta sitten"}}},"year-short":{displayName:"v",relative:{0:"tänä v",1:"ensi v","-1":"viime v"},relativeTime:{future:{one:"{0} v päästä",other:"{0} v päästä"},past:{one:"{0} v sitten",other:"{0} v sitten"}}},month:{displayName:"kuukausi",relative:{0:"tässä kuussa",1:"ensi kuussa","-1":"viime kuussa"},relativeTime:{future:{one:"{0} kuukauden päästä",other:"{0} kuukauden päästä"},past:{one:"{0} kuukausi sitten",other:"{0} kuukautta sitten"}}},"month-short":{displayName:"kk",relative:{0:"tässä kk",1:"ensi kk","-1":"viime kk"},relativeTime:{future:{one:"{0} kk päästä",other:"{0} kk päästä"},past:{one:"{0} kk sitten",other:"{0} kk sitten"}}},day:{displayName:"päivä",relative:{0:"tänään",1:"huomenna",2:"ylihuomenna","-2":"toissa päivänä","-1":"eilen"},relativeTime:{future:{one:"{0} päivän päästä",other:"{0} päivän päästä"},past:{one:"{0} päivä sitten",other:"{0} päivää sitten"}}},"day-short":{displayName:"pv",relative:{0:"tänään",1:"huom.",2:"ylihuom.","-2":"toissap.","-1":"eilen"},relativeTime:{future:{one:"{0} pv päästä",other:"{0} pv päästä"},past:{one:"{0} pv sitten",other:"{0} pv sitten"}}},hour:{displayName:"tunti",relative:{0:"tämän tunnin aikana"},relativeTime:{future:{one:"{0} tunnin päästä",other:"{0} tunnin päästä"},past:{one:"{0} tunti sitten",other:"{0} tuntia sitten"}}},"hour-short":{displayName:"t",relative:{0:"tunnin sisällä"},relativeTime:{future:{one:"{0} t päästä",other:"{0} t päästä"},past:{one:"{0} t sitten",other:"{0} t sitten"}}},minute:{displayName:"minuutti",relative:{0:"tämän minuutin aikana"},relativeTime:{future:{one:"{0} minuutin päästä",other:"{0} minuutin päästä"},past:{one:"{0} minuutti sitten",other:"{0} minuuttia sitten"}}},"minute-short":{displayName:"min",relative:{0:"minuutin sisällä"},relativeTime:{future:{one:"{0} min päästä",other:"{0} min päästä"},past:{one:"{0} min sitten",other:"{0} min sitten"}}},second:{displayName:"sekunti",relative:{0:"nyt"},relativeTime:{future:{one:"{0} sekunnin päästä",other:"{0} sekunnin päästä"},past:{one:"{0} sekunti sitten",other:"{0} sekuntia sitten"}}},"second-short":{displayName:"s",relative:{0:"nyt"},relativeTime:{future:{one:"{0} s päästä",other:"{0} s päästä"},past:{one:"{0} s sitten",other:"{0} s sitten"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/fil.js": /*!*********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/fil.js ***! \*********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(a,n){ true?module.exports=n():undefined}(this,function(){"use strict";return[{locale:"fil",pluralRuleFunction:function(a,n){var e=String(a).split("."),o=e[0],t=e[1]||"",s=!e[1],r=o.slice(-1),i=t.slice(-1);return n?1==a?"one":"other":s&&(1==o||2==o||3==o)||s&&4!=r&&6!=r&&9!=r||!s&&4!=i&&6!=i&&9!=i?"one":"other"},fields:{year:{displayName:"taon",relative:{0:"ngayong taon",1:"susunod na taon","-1":"nakaraang taon"},relativeTime:{future:{one:"sa {0} taon",other:"sa {0} (na) taon"},past:{one:"{0} taon ang nakalipas",other:"{0} (na) taon ang nakalipas"}}},"year-short":{displayName:"taon",relative:{0:"ngayong taon",1:"susunod na taon","-1":"nakaraang taon"},relativeTime:{future:{one:"sa {0} taon",other:"sa {0} (na) taon"},past:{one:"{0} taon ang nakalipas",other:"{0} (na) taon ang nakalipas"}}},month:{displayName:"buwan",relative:{0:"ngayong buwan",1:"susunod na buwan","-1":"nakaraang buwan"},relativeTime:{future:{one:"sa {0} buwan",other:"sa {0} (na) buwan"},past:{one:"{0} buwan ang nakalipas",other:"{0} (na) buwan ang nakalipas"}}},"month-short":{displayName:"buwan",relative:{0:"ngayong buwan",1:"susunod na buwan","-1":"nakaraang buwan"},relativeTime:{future:{one:"sa {0} buwan",other:"sa {0} (na) buwan"},past:{one:"{0} buwan ang nakalipas",other:"{0} (na) buwan ang nakalipas"}}},day:{displayName:"araw",relative:{0:"ngayong araw",1:"bukas",2:"Samakalawa","-2":"Araw bago ang kahapon","-1":"kahapon"},relativeTime:{future:{one:"sa {0} araw",other:"sa {0} (na) araw"},past:{one:"{0} araw ang nakalipas",other:"{0} (na) araw ang nakalipas"}}},"day-short":{displayName:"araw",relative:{0:"ngayong araw",1:"bukas",2:"Samakalawa","-2":"Araw bago ang kahapon","-1":"kahapon"},relativeTime:{future:{one:"sa {0} (na) araw",other:"sa {0} (na) araw"},past:{one:"{0} (na) araw ang nakalipas",other:"{0} (na) araw ang nakalipas"}}},hour:{displayName:"oras",relative:{0:"ngayong oras"},relativeTime:{future:{one:"sa {0} oras",other:"sa {0} (na) oras"},past:{one:"{0} oras ang nakalipas",other:"{0} (na) oras ang nakalipas"}}},"hour-short":{displayName:"oras",relative:{0:"ngayong oras"},relativeTime:{future:{one:"sa {0} oras",other:"sa {0} (na) oras"},past:{one:"{0} oras ang nakalipas",other:"{0} (na) oras ang nakalipas"}}},minute:{displayName:"minuto",relative:{0:"sa minutong ito"},relativeTime:{future:{one:"sa {0} minuto",other:"sa {0} (na) minuto"},past:{one:"{0} minuto ang nakalipas",other:"{0} (na) minuto ang nakalipas"}}},"minute-short":{displayName:"min.",relative:{0:"sa minutong ito"},relativeTime:{future:{one:"sa {0} min.",other:"sa {0} (na) min."},past:{one:"{0} min. ang nakalipas",other:"{0} (na) min. ang nakalipas"}}},second:{displayName:"segundo",relative:{0:"ngayon"},relativeTime:{future:{one:"sa {0} segundo",other:"sa {0} (na) segundo"},past:{one:"{0} segundo ang nakalipas",other:"{0} (na) segundo ang nakalipas"}}},"second-short":{displayName:"seg.",relative:{0:"ngayon"},relativeTime:{future:{one:"sa {0} seg.",other:"sa {0} (na) seg."},past:{one:"{0} seg. ang nakalipas",other:"{0} (na) seg. nakalipas"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/fr.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/fr.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,a){ true?module.exports=a():undefined}(this,function(){"use strict";return[{locale:"fr",pluralRuleFunction:function(e,a){return a?1==e?"one":"other":e>=0&&e<2?"one":"other"},fields:{year:{displayName:"année",relative:{0:"cette année",1:"l’année prochaine","-1":"l’année dernière"},relativeTime:{future:{one:"dans {0} an",other:"dans {0} ans"},past:{one:"il y a {0} an",other:"il y a {0} ans"}}},"year-short":{displayName:"an",relative:{0:"cette année",1:"l’année prochaine","-1":"l’année dernière"},relativeTime:{future:{one:"dans {0} a",other:"dans {0} a"},past:{one:"il y a {0} a",other:"il y a {0} a"}}},month:{displayName:"mois",relative:{0:"ce mois-ci",1:"le mois prochain","-1":"le mois dernier"},relativeTime:{future:{one:"dans {0} mois",other:"dans {0} mois"},past:{one:"il y a {0} mois",other:"il y a {0} mois"}}},"month-short":{displayName:"m.",relative:{0:"ce mois-ci",1:"le mois prochain","-1":"le mois dernier"},relativeTime:{future:{one:"dans {0} m.",other:"dans {0} m."},past:{one:"il y a {0} m.",other:"il y a {0} m."}}},day:{displayName:"jour",relative:{0:"aujourd’hui",1:"demain",2:"après-demain","-2":"avant-hier","-1":"hier"},relativeTime:{future:{one:"dans {0} jour",other:"dans {0} jours"},past:{one:"il y a {0} jour",other:"il y a {0} jours"}}},"day-short":{displayName:"j",relative:{0:"aujourd’hui",1:"demain",2:"après-demain","-2":"avant-hier","-1":"hier"},relativeTime:{future:{one:"dans {0} j",other:"dans {0} j"},past:{one:"il y a {0} j",other:"il y a {0} j"}}},hour:{displayName:"heure",relative:{0:"cette heure-ci"},relativeTime:{future:{one:"dans {0} heure",other:"dans {0} heures"},past:{one:"il y a {0} heure",other:"il y a {0} heures"}}},"hour-short":{displayName:"h",relative:{0:"cette heure-ci"},relativeTime:{future:{one:"dans {0} h",other:"dans {0} h"},past:{one:"il y a {0} h",other:"il y a {0} h"}}},minute:{displayName:"minute",relative:{0:"cette minute-ci"},relativeTime:{future:{one:"dans {0} minute",other:"dans {0} minutes"},past:{one:"il y a {0} minute",other:"il y a {0} minutes"}}},"minute-short":{displayName:"min",relative:{0:"cette minute-ci"},relativeTime:{future:{one:"dans {0} min",other:"dans {0} min"},past:{one:"il y a {0} min",other:"il y a {0} min"}}},second:{displayName:"seconde",relative:{0:"maintenant"},relativeTime:{future:{one:"dans {0} seconde",other:"dans {0} secondes"},past:{one:"il y a {0} seconde",other:"il y a {0} secondes"}}},"second-short":{displayName:"s",relative:{0:"maintenant"},relativeTime:{future:{one:"dans {0} s",other:"dans {0} s"},past:{one:"il y a {0} s",other:"il y a {0} s"}}}}},{locale:"fr-BE",parentLocale:"fr"},{locale:"fr-BF",parentLocale:"fr"},{locale:"fr-BI",parentLocale:"fr"},{locale:"fr-BJ",parentLocale:"fr"},{locale:"fr-BL",parentLocale:"fr"},{locale:"fr-CA",parentLocale:"fr",fields:{year:{displayName:"année",relative:{0:"cette année",1:"l’année prochaine","-1":"l’année dernière"},relativeTime:{future:{one:"Dans {0} an",other:"Dans {0} ans"},past:{one:"Il y a {0} an",other:"Il y a {0} ans"}}},"year-short":{displayName:"a",relative:{0:"cette année",1:"l’année prochaine","-1":"l’année dernière"},relativeTime:{future:{one:"dans {0} a",other:"dans {0} a"},past:{one:"il y a {0} a",other:"il y a {0} a"}}},month:{displayName:"mois",relative:{0:"ce mois-ci",1:"le mois prochain","-1":"le mois dernier"},relativeTime:{future:{one:"dans {0} mois",other:"dans {0} mois"},past:{one:"il y a {0} mois",other:"il y a {0} mois"}}},"month-short":{displayName:"m.",relative:{0:"ce mois-ci",1:"le mois prochain","-1":"le mois dernier"},relativeTime:{future:{one:"dans {0} m.",other:"dans {0} m."},past:{one:"il y a {0} m.",other:"il y a {0} m."}}},day:{displayName:"jour",relative:{0:"aujourd’hui",1:"demain",2:"après-demain","-2":"avant-hier","-1":"hier"},relativeTime:{future:{one:"dans {0} jour",other:"dans {0} jours"},past:{one:"il y a {0} jour",other:"il y a {0} jours"}}},"day-short":{displayName:"j",relative:{0:"aujourd’hui",1:"demain",2:"après-demain","-2":"avant-hier","-1":"hier"},relativeTime:{future:{one:"dans {0} j",other:"dans {0} j"},past:{one:"il y a {0} j",other:"il y a {0} j"}}},hour:{displayName:"heure",relative:{0:"cette heure-ci"},relativeTime:{future:{one:"dans {0} heure",other:"dans {0} heures"},past:{one:"il y a {0} heure",other:"il y a {0} heures"}}},"hour-short":{displayName:"h",relative:{0:"cette heure-ci"},relativeTime:{future:{one:"dans {0} h",other:"dans {0} h"},past:{one:"il y a {0} h",other:"il y a {0} h"}}},minute:{displayName:"minute",relative:{0:"cette minute-ci"},relativeTime:{future:{one:"dans {0} minute",other:"dans {0} minutes"},past:{one:"il y a {0} minute",other:"il y a {0} minutes"}}},"minute-short":{displayName:"min",relative:{0:"cette minute-ci"},relativeTime:{future:{one:"dans {0} min",other:"dans {0} min"},past:{one:"il y a {0} min",other:"il y a {0} min"}}},second:{displayName:"seconde",relative:{0:"maintenant"},relativeTime:{future:{one:"dans {0} seconde",other:"dans {0} secondes"},past:{one:"il y a {0} seconde",other:"il y a {0} secondes"}}},"second-short":{displayName:"s",relative:{0:"maintenant"},relativeTime:{future:{one:"dans {0} s",other:"dans {0} s"},past:{one:"il y a {0} s",other:"il y a {0} s"}}}}},{locale:"fr-CD",parentLocale:"fr"},{locale:"fr-CF",parentLocale:"fr"},{locale:"fr-CG",parentLocale:"fr"},{locale:"fr-CH",parentLocale:"fr"},{locale:"fr-CI",parentLocale:"fr"},{locale:"fr-CM",parentLocale:"fr"},{locale:"fr-DJ",parentLocale:"fr"},{locale:"fr-DZ",parentLocale:"fr"},{locale:"fr-GA",parentLocale:"fr"},{locale:"fr-GF",parentLocale:"fr"},{locale:"fr-GN",parentLocale:"fr"},{locale:"fr-GP",parentLocale:"fr"},{locale:"fr-GQ",parentLocale:"fr"},{locale:"fr-HT",parentLocale:"fr",fields:{year:{displayName:"année",relative:{0:"cette année",1:"l’année prochaine","-1":"l’année dernière"},relativeTime:{future:{one:"dans {0} an",other:"dans {0} ans"},past:{one:"il y a {0} an",other:"il y a {0} ans"}}},"year-short":{displayName:"an",relative:{0:"cette année",1:"l’année prochaine","-1":"l’année dernière"},relativeTime:{future:{one:"dans {0} a",other:"dans {0} a"},past:{one:"il y a {0} a",other:"il y a {0} a"}}},month:{displayName:"mois",relative:{0:"ce mois-ci",1:"le mois prochain","-1":"le mois dernier"},relativeTime:{future:{one:"dans {0} mois",other:"dans {0} mois"},past:{one:"il y a {0} mois",other:"il y a {0} mois"}}},"month-short":{displayName:"m.",relative:{0:"ce mois-ci",1:"le mois prochain","-1":"le mois dernier"},relativeTime:{future:{one:"dans {0} m.",other:"dans {0} m."},past:{one:"il y a {0} m.",other:"il y a {0} m."}}},day:{displayName:"jour",relative:{0:"aujourd’hui",1:"demain",2:"après-demain","-2":"avant-hier","-1":"hier"},relativeTime:{future:{one:"dans {0} jour",other:"dans {0} jours"},past:{one:"il y a {0} jour",other:"il y a {0} jours"}}},"day-short":{displayName:"jr.",relative:{0:"aujourd’hui",1:"demain",2:"après-demain","-2":"avant-hier","-1":"hier"},relativeTime:{future:{one:"dans {0} j",other:"dans {0} j"},past:{one:"il y a {0} j",other:"il y a {0} j"}}},hour:{displayName:"heure",relative:{0:"cette heure-ci"},relativeTime:{future:{one:"dans {0} heure",other:"dans {0} heures"},past:{one:"il y a {0} heure",other:"il y a {0} heures"}}},"hour-short":{displayName:"hr",relative:{0:"cette heure-ci"},relativeTime:{future:{one:"dans {0} h",other:"dans {0} h"},past:{one:"il y a {0} h",other:"il y a {0} h"}}},minute:{displayName:"minute",relative:{0:"cette minute-ci"},relativeTime:{future:{one:"dans {0} minute",other:"dans {0} minutes"},past:{one:"il y a {0} minute",other:"il y a {0} minutes"}}},"minute-short":{displayName:"min.",relative:{0:"cette minute-ci"},relativeTime:{future:{one:"dans {0} min",other:"dans {0} min"},past:{one:"il y a {0} min",other:"il y a {0} min"}}},second:{displayName:"seconde",relative:{0:"maintenant"},relativeTime:{future:{one:"dans {0} seconde",other:"dans {0} secondes"},past:{one:"il y a {0} seconde",other:"il y a {0} secondes"}}},"second-short":{displayName:"s",relative:{0:"maintenant"},relativeTime:{future:{one:"dans {0} s",other:"dans {0} s"},past:{one:"il y a {0} s",other:"il y a {0} s"}}}}},{locale:"fr-KM",parentLocale:"fr"},{locale:"fr-LU",parentLocale:"fr"},{locale:"fr-MA",parentLocale:"fr"},{locale:"fr-MC",parentLocale:"fr"},{locale:"fr-MF",parentLocale:"fr"},{locale:"fr-MG",parentLocale:"fr"},{locale:"fr-ML",parentLocale:"fr"},{locale:"fr-MQ",parentLocale:"fr"},{locale:"fr-MR",parentLocale:"fr"},{locale:"fr-MU",parentLocale:"fr"},{locale:"fr-NC",parentLocale:"fr"},{locale:"fr-NE",parentLocale:"fr"},{locale:"fr-PF",parentLocale:"fr"},{locale:"fr-PM",parentLocale:"fr"},{locale:"fr-RE",parentLocale:"fr"},{locale:"fr-RW",parentLocale:"fr"},{locale:"fr-SC",parentLocale:"fr"},{locale:"fr-SN",parentLocale:"fr"},{locale:"fr-SY",parentLocale:"fr"},{locale:"fr-TD",parentLocale:"fr"},{locale:"fr-TG",parentLocale:"fr"},{locale:"fr-TN",parentLocale:"fr"},{locale:"fr-VU",parentLocale:"fr"},{locale:"fr-WF",parentLocale:"fr"},{locale:"fr-YT",parentLocale:"fr"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/fy.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/fy.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,n){ true?module.exports=n():undefined}(this,function(){"use strict";return[{locale:"fy",pluralRuleFunction:function(e,n){var r=!String(e).split(".")[1];return n?"other":1==e&&r?"one":"other"},fields:{year:{displayName:"Jier",relative:{0:"dit jier",1:"folgjend jier","-1":"foarich jier"},relativeTime:{future:{one:"Oer {0} jier",other:"Oer {0} jier"},past:{one:"{0} jier lyn",other:"{0} jier lyn"}}},"year-short":{displayName:"Jier",relative:{0:"dit jier",1:"folgjend jier","-1":"foarich jier"},relativeTime:{future:{one:"Oer {0} jier",other:"Oer {0} jier"},past:{one:"{0} jier lyn",other:"{0} jier lyn"}}},month:{displayName:"Moanne",relative:{0:"dizze moanne",1:"folgjende moanne","-1":"foarige moanne"},relativeTime:{future:{one:"Oer {0} moanne",other:"Oer {0} moannen"},past:{one:"{0} moanne lyn",other:"{0} moannen lyn"}}},"month-short":{displayName:"Moanne",relative:{0:"dizze moanne",1:"folgjende moanne","-1":"foarige moanne"},relativeTime:{future:{one:"Oer {0} moanne",other:"Oer {0} moannen"},past:{one:"{0} moanne lyn",other:"{0} moannen lyn"}}},day:{displayName:"dei",relative:{0:"vandaag",1:"morgen",2:"Oermorgen","-2":"eergisteren","-1":"gisteren"},relativeTime:{future:{one:"Oer {0} dei",other:"Oer {0} deien"},past:{one:"{0} dei lyn",other:"{0} deien lyn"}}},"day-short":{displayName:"dei",relative:{0:"vandaag",1:"morgen",2:"Oermorgen","-2":"eergisteren","-1":"gisteren"},relativeTime:{future:{one:"Oer {0} dei",other:"Oer {0} deien"},past:{one:"{0} dei lyn",other:"{0} deien lyn"}}},hour:{displayName:"oere",relative:{0:"this hour"},relativeTime:{future:{one:"Oer {0} oere",other:"Oer {0} oere"},past:{one:"{0} oere lyn",other:"{0} oere lyn"}}},"hour-short":{displayName:"oere",relative:{0:"this hour"},relativeTime:{future:{one:"Oer {0} oere",other:"Oer {0} oere"},past:{one:"{0} oere lyn",other:"{0} oere lyn"}}},minute:{displayName:"Minút",relative:{0:"this minute"},relativeTime:{future:{one:"Oer {0} minút",other:"Oer {0} minuten"},past:{one:"{0} minút lyn",other:"{0} minuten lyn"}}},"minute-short":{displayName:"Minút",relative:{0:"this minute"},relativeTime:{future:{one:"Oer {0} minút",other:"Oer {0} minuten"},past:{one:"{0} minút lyn",other:"{0} minuten lyn"}}},second:{displayName:"Sekonde",relative:{0:"nu"},relativeTime:{future:{one:"Oer {0} sekonde",other:"Oer {0} sekonden"},past:{one:"{0} sekonde lyn",other:"{0} sekonden lyn"}}},"second-short":{displayName:"Sekonde",relative:{0:"nu"},relativeTime:{future:{one:"Oer {0} sekonde",other:"Oer {0} sekonden"},past:{one:"{0} sekonde lyn",other:"{0} sekonden lyn"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ga.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/ga.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(n,i){ true?module.exports=i():undefined}(this,function(){"use strict";return[{locale:"ga",pluralRuleFunction:function(n,i){var e=String(n).split("."),a=Number(e[0])==n;return i?1==n?"one":"other":1==n?"one":2==n?"two":a&&n>=3&&n<=6?"few":a&&n>=7&&n<=10?"many":"other"},fields:{year:{displayName:"Bliain",relative:{0:"an bhliain seo",1:"an bhliain seo chugainn","-1":"anuraidh"},relativeTime:{future:{one:"i gceann {0} bhliain",two:"i gceann {0} bhliain",few:"i gceann {0} bliana",many:"i gceann {0} mbliana",other:"i gceann {0} bliain"},past:{one:"{0} bhliain ó shin",two:"{0} bhliain ó shin",few:"{0} bliana ó shin",many:"{0} mbliana ó shin",other:"{0} bliain ó shin"}}},"year-short":{displayName:"bl.",relative:{0:"an bhl. seo",1:"an bhl. seo chugainn","-1":"anuraidh"},relativeTime:{future:{one:"i gceann {0} bl.",two:"i gceann {0} bhl.",few:"i gceann {0} bl.",many:"i gceann {0} mbl.",other:"i gceann {0} bl."},past:{one:"{0} bhl. ó shin",two:"{0} bhl. ó shin",few:"{0} bl. ó shin",many:"{0} mbl. ó shin",other:"{0} bl. ó shin"}}},month:{displayName:"Mí",relative:{0:"an mhí seo",1:"an mhí seo chugainn","-1":"an mhí seo caite"},relativeTime:{future:{one:"i gceann {0} mhí",two:"i gceann {0} mhí",few:"i gceann {0} mhí",many:"i gceann {0} mí",other:"i gceann {0} mí"},past:{one:"{0} mhí ó shin",two:"{0} mhí ó shin",few:"{0} mhí ó shin",many:"{0} mí ó shin",other:"{0} mí ó shin"}}},"month-short":{displayName:"mí",relative:{0:"an mhí seo",1:"an mhí seo chugainn","-1":"an mhí seo caite"},relativeTime:{future:{one:"i gceann {0} mhí",two:"i gceann {0} mhí",few:"i gceann {0} mhí",many:"i gceann {0} mí",other:"i gceann {0} mí"},past:{one:"{0} mhí ó shin",two:"{0} mhí ó shin",few:"{0} mhí ó shin",many:"{0} mí ó shin",other:"{0} mí ó shin"}}},day:{displayName:"Lá",relative:{0:"inniu",1:"amárach",2:"arú amárach","-2":"arú inné","-1":"inné"},relativeTime:{future:{one:"i gceann {0} lá",two:"i gceann {0} lá",few:"i gceann {0} lá",many:"i gceann {0} lá",other:"i gceann {0} lá"},past:{one:"{0} lá ó shin",two:"{0} lá ó shin",few:"{0} lá ó shin",many:"{0} lá ó shin",other:"{0} lá ó shin"}}},"day-short":{displayName:"Lá",relative:{0:"inniu",1:"amárach",2:"arú amárach","-2":"arú inné","-1":"inné"},relativeTime:{future:{one:"i gceann {0} lá",two:"i gceann {0} lá",few:"i gceann {0} lá",many:"i gceann {0} lá",other:"i gceann {0} lá"},past:{one:"{0} lá ó shin",two:"{0} lá ó shin",few:"{0} lá ó shin",many:"{0} lá ó shin",other:"{0} lá ó shin"}}},hour:{displayName:"Uair",relative:{0:"an uair seo"},relativeTime:{future:{one:"i gceann {0} uair an chloig",two:"i gceann {0} uair an chloig",few:"i gceann {0} huaire an chloig",many:"i gceann {0} n-uaire an chloig",other:"i gceann {0} uair an chloig"},past:{one:"{0} uair an chloig ó shin",two:"{0} uair an chloig ó shin",few:"{0} huaire an chloig ó shin",many:"{0} n-uaire an chloig ó shin",other:"{0} uair an chloig ó shin"}}},"hour-short":{displayName:"uair",relative:{0:"an uair seo"},relativeTime:{future:{one:"i gceann {0} uair",two:"i gceann {0} uair",few:"i gceann {0} huaire",many:"i gceann {0} n-uaire",other:"i gceann {0} uair"},past:{one:"{0} uair ó shin",two:"{0} uair ó shin",few:"{0} huaire ó shin",many:"{0} n-uaire ó shin",other:"{0} uair ó shin"}}},minute:{displayName:"Nóiméad",relative:{0:"an nóiméad seo"},relativeTime:{future:{one:"i gceann {0} nóiméad",two:"i gceann {0} nóiméad",few:"i gceann {0} nóiméad",many:"i gceann {0} nóiméad",other:"i gceann {0} nóiméad"},past:{one:"{0} nóiméad ó shin",two:"{0} nóiméad ó shin",few:"{0} nóiméad ó shin",many:"{0} nóiméad ó shin",other:"{0} nóiméad ó shin"}}},"minute-short":{displayName:"nóim.",relative:{0:"an nóiméad seo"},relativeTime:{future:{one:"i gceann {0} nóim.",two:"i gceann {0} nóim.",few:"i gceann {0} nóim.",many:"i gceann {0} nóim.",other:"i gceann {0} nóim."},past:{one:"{0} nóim. ó shin",two:"{0} nóim. ó shin",few:"{0} nóim. ó shin",many:"{0} nóim. ó shin",other:"{0} nóim. ó shin"}}},second:{displayName:"Soicind",relative:{0:"anois"},relativeTime:{future:{one:"i gceann {0} soicind",two:"i gceann {0} shoicind",few:"i gceann {0} shoicind",many:"i gceann {0} soicind",other:"i gceann {0} soicind"},past:{one:"{0} soicind ó shin",two:"{0} shoicind ó shin",few:"{0} shoicind ó shin",many:"{0} soicind ó shin",other:"{0} soicind ó shin"}}},"second-short":{displayName:"soic.",relative:{0:"anois"},relativeTime:{future:{one:"i gceann {0} soic.",two:"i gceann {0} shoic.",few:"i gceann {0} shoic.",many:"i gceann {0} soic.",other:"i gceann {0} soic."},past:{one:"{0} soic. ó shin",two:"{0} shoic. ó shin",few:"{0} shoic. ó shin",many:"{0} soic. ó shin",other:"{0} soic. ó shin"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/gd.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/gd.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(a,e){ true?module.exports=e():undefined}(this,function(){"use strict";return[{locale:"gd",pluralRuleFunction:function(a,e){var i=String(a).split("."),n=Number(i[0])==a;return e?1==a||11==a?"one":2==a||12==a?"two":3==a||13==a?"few":"other":1==a||11==a?"one":2==a||12==a?"two":n&&a>=3&&a<=10||n&&a>=13&&a<=19?"few":"other"},fields:{year:{displayName:"bliadhna",relative:{0:"am bliadhna",1:"an ath-bhliadhna","-2":"a-bhòn-uiridh","-1":"an-uiridh"},relativeTime:{future:{one:"an ceann {0} bhliadhna",two:"an ceann {0} bhliadhna",few:"an ceann {0} bliadhnaichean",other:"an ceann {0} bliadhna"},past:{one:"{0} bhliadhna air ais",two:"{0} bhliadhna air ais",few:"{0} bhliadhnaichean air ais",other:"{0} bliadhna air ais"}}},"year-short":{displayName:"blia.",relative:{0:"am bliadhna",1:"an ath-bhliadhna","-2":"a-bhòn-uiridh","-1":"an-uiridh"},relativeTime:{future:{one:"an {0} bhlia.",two:"an {0} bhlia.",few:"an {0} blia.",other:"an {0} blia."},past:{one:"o {0} bhlia.",two:"o {0} bhlia.",few:"o {0} blia.",other:"o {0} blia."}}},month:{displayName:"mìos",relative:{0:"am mìos seo",1:"an ath-mhìos","-1":"am mìos seo chaidh"},relativeTime:{future:{one:"an ceann {0} mhìosa",two:"an ceann {0} mhìosa",few:"an ceann {0} mìosan",other:"an ceann {0} mìosa"},past:{one:"{0} mhìos air ais",two:"{0} mhìos air ais",few:"{0} mìosan air ais",other:"{0} mìos air ais"}}},"month-short":{displayName:"mìos",relative:{0:"am mìos seo",1:"an ath-mhìos","-1":"am mìos sa chaidh"},relativeTime:{future:{one:"an {0} mhìos.",two:"an {0} mhìos.",few:"an {0} mìos.",other:"an {0} mìos."},past:{one:"o {0} mhìos.",two:"o {0} mhìos.",few:"o {0} mìos.",other:"o {0} mìos."}}},day:{displayName:"latha",relative:{0:"an-diugh",1:"a-màireach",2:"an-earar",3:"an-eararais","-2":"a-bhòin-dè","-1":"an-dè"},relativeTime:{future:{one:"an ceann {0} latha",two:"an ceann {0} latha",few:"an ceann {0} làithean",other:"an ceann {0} latha"},past:{one:"{0} latha air ais",two:"{0} latha air ais",few:"{0} làithean air ais",other:"{0} latha air ais"}}},"day-short":{displayName:"là",relative:{0:"an-diugh",1:"a-màireach",2:"an-earar",3:"an-eararais","-2":"a-bhòin-dè","-1":"an-dè"},relativeTime:{future:{one:"an {0} là",two:"an {0} là",few:"an {0} là.",other:"an {0} là"},past:{one:"o {0} là",two:"o {0} là",few:"o {0} là.",other:"o {0} là"}}},hour:{displayName:"uair a thìde",relative:{0:"am broinn uair a thìde"},relativeTime:{future:{one:"an ceann {0} uair a thìde",two:"an ceann {0} uair a thìde",few:"an ceann {0} uairean a thìde",other:"an ceann {0} uair a thìde"},past:{one:"{0} uair a thìde air ais",two:"{0} uair a thìde air ais",few:"{0} uairean a thìde air ais",other:"{0} uair a thìde air ais"}}},"hour-short":{displayName:"uair",relative:{0:"am broinn uair"},relativeTime:{future:{one:"an {0} uair",two:"an {0} uair",few:"an {0} uair.",other:"an {0} uair"},past:{one:"o {0} uair",two:"o {0} uair",few:"o {0} uair.",other:"o {0} uair"}}},minute:{displayName:"mionaid",relative:{0:"am broinn mionaid"},relativeTime:{future:{one:"an ceann {0} mhionaid",two:"an ceann {0} mhionaid",few:"an ceann {0} mionaidean",other:"an ceann {0} mionaid"},past:{one:"{0} mhionaid air ais",two:"{0} mhionaid air ais",few:"{0} mionaidean air ais",other:"{0} mionaid air ais"}}},"minute-short":{displayName:"mion.",relative:{0:"am broinn mion."},relativeTime:{future:{one:"an {0} mhion.",two:"an {0} mhion.",few:"an {0} mion.",other:"an {0} mion."},past:{one:"o {0} mhion.",two:"o {0} mhion.",few:"o {0} mion.",other:"o {0} mion."}}},second:{displayName:"diog",relative:{0:"an-dràsta"},relativeTime:{future:{one:"an ceann {0} diog",two:"an ceann {0} dhiog",few:"an ceann {0} diogan",other:"an ceann {0} diog"},past:{one:"{0} diog air ais",two:"{0} dhiog air ais",few:"{0} diogan air ais",other:"{0} diog air ais"}}},"second-short":{displayName:"diog",relative:{0:"an-dràsta"},relativeTime:{future:{one:"an {0} diog",two:"an {0} dhiog",few:"an {0} diog.",other:"an {0} diog"},past:{one:"o {0} diog",two:"o {0} dhiog",few:"o {0} diog.",other:"o {0} diog"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/gl.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/gl.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,a){ true?module.exports=a():undefined}(this,function(){"use strict";return[{locale:"gl",pluralRuleFunction:function(e,a){var o=!String(e).split(".")[1];return a?"other":1==e&&o?"one":"other"},fields:{year:{displayName:"ano",relative:{0:"este ano",1:"o próximo ano","-1":"o ano pasado"},relativeTime:{future:{one:"en {0} ano",other:"en {0} anos"},past:{one:"hai {0} ano",other:"hai {0} anos"}}},"year-short":{displayName:"ano",relative:{0:"este ano",1:"seguinte ano","-1":"ano pasado"},relativeTime:{future:{one:"en {0} ano",other:"en {0} anos"},past:{one:"hai {0} ano",other:"hai {0} anos"}}},month:{displayName:"mes",relative:{0:"este mes",1:"o próximo mes","-1":"o mes pasado"},relativeTime:{future:{one:"en {0} mes",other:"en {0} meses"},past:{one:"hai {0} mes",other:"hai {0} meses"}}},"month-short":{displayName:"mes",relative:{0:"este m.",1:"m. seguinte","-1":"m. pasado"},relativeTime:{future:{one:"en {0} mes",other:"en {0} meses"},past:{one:"hai {0} mes",other:"hai {0} meses"}}},day:{displayName:"día",relative:{0:"hoxe",1:"mañá",2:"pasadomañá","-2":"antonte","-1":"onte"},relativeTime:{future:{one:"en {0} día",other:"en {0} días"},past:{one:"hai {0} día",other:"hai {0} días"}}},"day-short":{displayName:"día",relative:{0:"hoxe",1:"mañá",2:"pasadomañá","-2":"antonte","-1":"onte"},relativeTime:{future:{one:"en {0} día",other:"en {0} días"},past:{one:"hai {0} día",other:"hai {0} días"}}},hour:{displayName:"hora",relative:{0:"esta hora"},relativeTime:{future:{one:"en {0} hora",other:"en {0} horas"},past:{one:"hai {0} hora",other:"hai {0} horas"}}},"hour-short":{displayName:"h",relative:{0:"esta hora"},relativeTime:{future:{one:"en {0} h",other:"en {0} h"},past:{one:"hai {0} h",other:"hai {0} h"}}},minute:{displayName:"minuto",relative:{0:"este minuto"},relativeTime:{future:{one:"en {0} minuto",other:"en {0} minutos"},past:{one:"hai {0} minuto",other:"hai {0} minutos"}}},"minute-short":{displayName:"min",relative:{0:"este minuto"},relativeTime:{future:{one:"en {0} min",other:"en {0} min"},past:{one:"hai {0} min",other:"hai {0} min"}}},second:{displayName:"segundo",relative:{0:"agora"},relativeTime:{future:{one:"en {0} segundo",other:"en {0} segundos"},past:{one:"hai {0} segundo",other:"hai {0} segundos"}}},"second-short":{displayName:"s",relative:{0:"agora"},relativeTime:{future:{one:"en {0} s",other:"en {0} s"},past:{one:"hai {0} s",other:"hai {0} s"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ha.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/ha.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"ha",pluralRuleFunction:function(e,t){return t?"other":1==e?"one":"other"},fields:{year:{displayName:"Shekara",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},"year-short":{displayName:"Shekara",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},month:{displayName:"Wata",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},"month-short":{displayName:"Wata",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},day:{displayName:"Kwana",relative:{0:"Yau",1:"Gobe","-1":"Jiya"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},"day-short":{displayName:"Kwana",relative:{0:"Yau",1:"Gobe","-1":"Jiya"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},hour:{displayName:"Awa",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},"hour-short":{displayName:"Awa",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},minute:{displayName:"Minti",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},"minute-short":{displayName:"Minti",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},second:{displayName:"Daƙiƙa",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}},"second-short":{displayName:"Daƙiƙa",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}}}},{locale:"ha-Arab",pluralRuleFunction:function(e,t){return"other"},fields:{year:{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},"year-short":{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},month:{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},"month-short":{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},day:{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},"day-short":{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},hour:{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},"hour-short":{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},minute:{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},"minute-short":{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},second:{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}},"second-short":{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}}}},{locale:"ha-GH",parentLocale:"ha"},{locale:"ha-NE",parentLocale:"ha"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/he.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/he.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"he",pluralRuleFunction:function(e,t){var a=String(e).split("."),o=a[0],r=!a[1],n=Number(a[0])==e,i=n&&a[0].slice(-1);return t?"other":1==e&&r?"one":2==o&&r?"two":r&&(e<0||e>10)&&n&&0==i?"many":"other"},fields:{year:{displayName:"שנה",relative:{0:"השנה",1:"השנה הבאה","-1":"השנה שעברה"},relativeTime:{future:{one:"בעוד שנה",two:"בעוד שנתיים",many:"בעוד {0} שנה",other:"בעוד {0} שנים"},past:{one:"לפני שנה",two:"לפני שנתיים",many:"לפני {0} שנה",other:"לפני {0} שנים"}}},"year-short":{displayName:"שנ׳",relative:{0:"השנה",1:"השנה הבאה","-1":"השנה שעברה"},relativeTime:{future:{one:"בעוד שנה",two:"בעוד שנתיים",many:"בעוד {0} שנה",other:"בעוד {0} שנים"},past:{one:"לפני שנה",two:"לפני שנתיים",many:"לפני {0} שנה",other:"לפני {0} שנים"}}},month:{displayName:"חודש",relative:{0:"החודש",1:"החודש הבא","-1":"החודש שעבר"},relativeTime:{future:{one:"בעוד חודש",two:"בעוד חודשיים",many:"בעוד {0} חודשים",other:"בעוד {0} חודשים"},past:{one:"לפני חודש",two:"לפני חודשיים",many:"לפני {0} חודשים",other:"לפני {0} חודשים"}}},"month-short":{displayName:"חו׳",relative:{0:"החודש",1:"החודש הבא","-1":"החודש שעבר"},relativeTime:{future:{one:"בעוד חודש",two:"בעוד חודשיים",many:"בעוד {0} חודשים",other:"בעוד {0} חודשים"},past:{one:"לפני חודש",two:"לפני חודשיים",many:"לפני {0} חודשים",other:"לפני {0} חודשים"}}},day:{displayName:"יום",relative:{0:"היום",1:"מחר",2:"מחרתיים","-2":"שלשום","-1":"אתמול"},relativeTime:{future:{one:"בעוד יום {0}",two:"בעוד יומיים",many:"בעוד {0} ימים",other:"בעוד {0} ימים"},past:{one:"לפני יום {0}",two:"לפני יומיים",many:"לפני {0} ימים",other:"לפני {0} ימים"}}},"day-short":{displayName:"יום",relative:{0:"היום",1:"מחר",2:"מחרתיים","-2":"שלשום","-1":"אתמול"},relativeTime:{future:{one:"מחר",two:"בעוד יומיים",many:"בעוד {0} ימים",other:"בעוד {0} ימים"},past:{one:"אתמול",two:"לפני יומיים",many:"לפני {0} ימים",other:"לפני {0} ימים"}}},hour:{displayName:"שעה",relative:{0:"בשעה זו"},relativeTime:{future:{one:"בעוד שעה",two:"בעוד שעתיים",many:"בעוד {0} שעות",other:"בעוד {0} שעות"},past:{one:"לפני שעה",two:"לפני שעתיים",many:"לפני {0} שעות",other:"לפני {0} שעות"}}},"hour-short":{displayName:"שעה",relative:{0:"בשעה זו"},relativeTime:{future:{one:"בעוד שעה",two:"בעוד שעתיים",many:"בעוד {0} שע׳",other:"בעוד {0} שע׳"},past:{one:"לפני שעה",two:"לפני שעתיים",many:"לפני {0} שע׳",other:"לפני {0} שע׳"}}},minute:{displayName:"דקה",relative:{0:"בדקה זו"},relativeTime:{future:{one:"בעוד דקה",two:"בעוד שתי דקות",many:"בעוד {0} דקות",other:"בעוד {0} דקות"},past:{one:"לפני דקה",two:"לפני שתי דקות",many:"לפני {0} דקות",other:"לפני {0} דקות"}}},"minute-short":{displayName:"דק׳",relative:{0:"בדקה זו"},relativeTime:{future:{one:"בעוד דקה",two:"בעוד שתי דק׳",many:"בעוד {0} דק׳",other:"בעוד {0} דק׳"},past:{one:"לפני דקה",two:"לפני {0} דק׳",many:"לפני {0} דק׳",other:"לפני {0} דק׳"}}},second:{displayName:"שנייה",relative:{0:"עכשיו"},relativeTime:{future:{one:"בעוד שנייה",two:"בעוד שתי שניות",many:"בעוד {0} שניות",other:"בעוד {0} שניות"},past:{one:"לפני שנייה",two:"לפני שתי שניות",many:"לפני {0} שניות",other:"לפני {0} שניות"}}},"second-short":{displayName:"שנ׳",relative:{0:"עכשיו"},relativeTime:{future:{one:"בעוד שנ׳",two:"בעוד שתי שנ׳",many:"בעוד {0} שנ׳",other:"בעוד {0} שנ׳"},past:{one:"לפני שנ׳",two:"לפני שתי שנ׳",many:"לפני {0} שנ׳",other:"לפני {0} שנ׳"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/hr.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/hr.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,a){ true?module.exports=a():undefined}(this,function(){"use strict";return[{locale:"hr",pluralRuleFunction:function(e,a){var i=String(e).split("."),r=i[0],t=i[1]||"",o=!i[1],n=r.slice(-1),s=r.slice(-2),p=t.slice(-1),u=t.slice(-2);return a?"other":o&&1==n&&11!=s||1==p&&11!=u?"one":o&&n>=2&&n<=4&&(s<12||s>14)||p>=2&&p<=4&&(u<12||u>14)?"few":"other"},fields:{year:{displayName:"godina",relative:{0:"ove godine",1:"sljedeće godine","-1":"prošle godine"},relativeTime:{future:{one:"za {0} godinu",few:"za {0} godine",other:"za {0} godina"},past:{one:"prije {0} godinu",few:"prije {0} godine",other:"prije {0} godina"}}},"year-short":{displayName:"g.",relative:{0:"ove god.",1:"sljedeće god.","-1":"prošle god."},relativeTime:{future:{one:"za {0} g.",few:"za {0} g.",other:"za {0} g."},past:{one:"prije {0} g.",few:"prije {0} g.",other:"prije {0} g."}}},month:{displayName:"mjesec",relative:{0:"ovaj mjesec",1:"sljedeći mjesec","-1":"prošli mjesec"},relativeTime:{future:{one:"za {0} mjesec",few:"za {0} mjeseca",other:"za {0} mjeseci"},past:{one:"prije {0} mjesec",few:"prije {0} mjeseca",other:"prije {0} mjeseci"}}},"month-short":{displayName:"mj.",relative:{0:"ovaj mj.",1:"sljedeći mj.","-1":"prošli mj."},relativeTime:{future:{one:"za {0} mj.",few:"za {0} mj.",other:"za {0} mj."},past:{one:"prije {0} mj.",few:"prije {0} mj.",other:"prije {0} mj."}}},day:{displayName:"dan",relative:{0:"danas",1:"sutra",2:"prekosutra","-2":"prekjučer","-1":"jučer"},relativeTime:{future:{one:"za {0} dan",few:"za {0} dana",other:"za {0} dana"},past:{one:"prije {0} dan",few:"prije {0} dana",other:"prije {0} dana"}}},"day-short":{displayName:"d.",relative:{0:"danas",1:"sutra",2:"prekosutra","-2":"prekjučer","-1":"jučer"},relativeTime:{future:{one:"za {0} dan",few:"za {0} dana",other:"za {0} dana"},past:{one:"prije {0} dan",few:"prije {0} dana",other:"prije {0} dana"}}},hour:{displayName:"sat",relative:{0:"ovaj sat"},relativeTime:{future:{one:"za {0} sat",few:"za {0} sata",other:"za {0} sati"},past:{one:"prije {0} sat",few:"prije {0} sata",other:"prije {0} sati"}}},"hour-short":{displayName:"h",relative:{0:"ovaj sat"},relativeTime:{future:{one:"za {0} h",few:"za {0} h",other:"za {0} h"},past:{one:"prije {0} h",few:"prije {0} h",other:"prije {0} h"}}},minute:{displayName:"minuta",relative:{0:"ova minuta"},relativeTime:{future:{one:"za {0} minutu",few:"za {0} minute",other:"za {0} minuta"},past:{one:"prije {0} minutu",few:"prije {0} minute",other:"prije {0} minuta"}}},"minute-short":{displayName:"min",relative:{0:"ova minuta"},relativeTime:{future:{one:"za {0} min",few:"za {0} min",other:"za {0} min"},past:{one:"prije {0} min",few:"prije {0} min",other:"prije {0} min"}}},second:{displayName:"sekunda",relative:{0:"sad"},relativeTime:{future:{one:"za {0} sekundu",few:"za {0} sekunde",other:"za {0} sekundi"},past:{one:"prije {0} sekundu",few:"prije {0} sekunde",other:"prije {0} sekundi"}}},"second-short":{displayName:"s",relative:{0:"sad"},relativeTime:{future:{one:"za {0} s",few:"za {0} s",other:"za {0} s"},past:{one:"prije {0} s",few:"prije {0} s",other:"prije {0} s"}}}}},{locale:"hr-BA",parentLocale:"hr"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/hu.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/hu.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"hu",pluralRuleFunction:function(e,t){return t?1==e||5==e?"one":"other":1==e?"one":"other"},fields:{year:{displayName:"év",relative:{0:"ez az év",1:"következő év","-1":"előző év"},relativeTime:{future:{one:"{0} év múlva",other:"{0} év múlva"},past:{one:"{0} évvel ezelőtt",other:"{0} évvel ezelőtt"}}},"year-short":{displayName:"év",relative:{0:"ez az év",1:"következő év","-1":"előző év"},relativeTime:{future:{one:"{0} év múlva",other:"{0} év múlva"},past:{one:"{0} évvel ezelőtt",other:"{0} évvel ezelőtt"}}},month:{displayName:"hónap",relative:{0:"ez a hónap",1:"következő hónap","-1":"előző hónap"},relativeTime:{future:{one:"{0} hónap múlva",other:"{0} hónap múlva"},past:{one:"{0} hónappal ezelőtt",other:"{0} hónappal ezelőtt"}}},"month-short":{displayName:"hónap",relative:{0:"ez a hónap",1:"következő hónap","-1":"előző hónap"},relativeTime:{future:{one:"{0} hónap múlva",other:"{0} hónap múlva"},past:{one:"{0} hónappal ezelőtt",other:"{0} hónappal ezelőtt"}}},day:{displayName:"nap",relative:{0:"ma",1:"holnap",2:"holnapután","-2":"tegnapelőtt","-1":"tegnap"},relativeTime:{future:{one:"{0} nap múlva",other:"{0} nap múlva"},past:{one:"{0} nappal ezelőtt",other:"{0} nappal ezelőtt"}}},"day-short":{displayName:"nap",relative:{0:"ma",1:"holnap",2:"holnapután","-2":"tegnapelőtt","-1":"tegnap"},relativeTime:{future:{one:"{0} nap múlva",other:"{0} nap múlva"},past:{one:"{0} napja",other:"{0} napja"}}},hour:{displayName:"óra",relative:{0:"ebben az órában"},relativeTime:{future:{one:"{0} óra múlva",other:"{0} óra múlva"},past:{one:"{0} órával ezelőtt",other:"{0} órával ezelőtt"}}},"hour-short":{displayName:"óra",relative:{0:"ebben az órában"},relativeTime:{future:{one:"{0} óra múlva",other:"{0} óra múlva"},past:{one:"{0} órával ezelőtt",other:"{0} órával ezelőtt"}}},minute:{displayName:"perc",relative:{0:"ebben a percben"},relativeTime:{future:{one:"{0} perc múlva",other:"{0} perc múlva"},past:{one:"{0} perccel ezelőtt",other:"{0} perccel ezelőtt"}}},"minute-short":{displayName:"perc",relative:{0:"ebben a percben"},relativeTime:{future:{one:"{0} perc múlva",other:"{0} perc múlva"},past:{one:"{0} perccel ezelőtt",other:"{0} perccel ezelőtt"}}},second:{displayName:"másodperc",relative:{0:"most"},relativeTime:{future:{one:"{0} másodperc múlva",other:"{0} másodperc múlva"},past:{one:"{0} másodperccel ezelőtt",other:"{0} másodperccel ezelőtt"}}},"second-short":{displayName:"másodperc",relative:{0:"most"},relativeTime:{future:{one:"{0} másodperc múlva",other:"{0} másodperc múlva"},past:{one:"{0} másodperccel ezelőtt",other:"{0} másodperccel ezelőtt"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/hy.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/hy.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"hy",pluralRuleFunction:function(e,t){return t?1==e?"one":"other":e>=0&&e<2?"one":"other"},fields:{year:{displayName:"տարի",relative:{0:"այս տարի",1:"հաջորդ տարի","-1":"նախորդ տարի"},relativeTime:{future:{one:"{0} տարուց",other:"{0} տարուց"},past:{one:"{0} տարի առաջ",other:"{0} տարի առաջ"}}},"year-short":{displayName:"տ",relative:{0:"այս տարի",1:"հաջորդ տարի","-1":"նախորդ տարի"},relativeTime:{future:{one:"{0} տարուց",other:"{0} տարուց"},past:{one:"{0} տ առաջ",other:"{0} տ առաջ"}}},month:{displayName:"ամիս",relative:{0:"այս ամիս",1:"հաջորդ ամիս","-1":"նախորդ ամիս"},relativeTime:{future:{one:"{0} ամսից",other:"{0} ամսից"},past:{one:"{0} ամիս առաջ",other:"{0} ամիս առաջ"}}},"month-short":{displayName:"ամս",relative:{0:"այս ամիս",1:"հաջորդ ամիս","-1":"անցյալ ամիս"},relativeTime:{future:{one:"{0} ամսից",other:"{0} ամսից"},past:{one:"{0} ամիս առաջ",other:"{0} ամիս առաջ"}}},day:{displayName:"օր",relative:{0:"այսօր",1:"վաղը",2:"վաղը չէ մյուս օրը","-2":"երեկ չէ առաջի օրը","-1":"երեկ"},relativeTime:{future:{one:"{0} օրից",other:"{0} օրից"},past:{one:"{0} օր առաջ",other:"{0} օր առաջ"}}},"day-short":{displayName:"օր",relative:{0:"այսօր",1:"վաղը",2:"վաղը չէ մյուս օրը","-2":"երեկ չէ առաջի օրը","-1":"երեկ"},relativeTime:{future:{one:"{0} օրից",other:"{0} օրից"},past:{one:"{0} օր առաջ",other:"{0} օր առաջ"}}},hour:{displayName:"ժամ",relative:{0:"այս ժամին"},relativeTime:{future:{one:"{0} ժամից",other:"{0} ժամից"},past:{one:"{0} ժամ առաջ",other:"{0} ժամ առաջ"}}},"hour-short":{displayName:"ժ",relative:{0:"այս ժամին"},relativeTime:{future:{one:"{0} ժ-ից",other:"{0} ժ-ից"},past:{one:"{0} ժ առաջ",other:"{0} ժ առաջ"}}},minute:{displayName:"րոպե",relative:{0:"այս րոպեին"},relativeTime:{future:{one:"{0} րոպեից",other:"{0} րոպեից"},past:{one:"{0} րոպե առաջ",other:"{0} րոպե առաջ"}}},"minute-short":{displayName:"ր",relative:{0:"այս րոպեին"},relativeTime:{future:{one:"{0} ր-ից",other:"{0} ր-ից"},past:{one:"{0} ր առաջ",other:"{0} ր առաջ"}}},second:{displayName:"վայրկյան",relative:{0:"հիմա"},relativeTime:{future:{one:"{0} վայրկյանից",other:"{0} վայրկյանից"},past:{one:"{0} վայրկյան առաջ",other:"{0} վայրկյան առաջ"}}},"second-short":{displayName:"վ",relative:{0:"հիմա"},relativeTime:{future:{one:"{0} վրկ-ից",other:"{0} վրկ-ից"},past:{one:"{0} վրկ առաջ",other:"{0} վրկ առաջ"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/id.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/id.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,a){ true?module.exports=a():undefined}(this,function(){"use strict";return[{locale:"id",pluralRuleFunction:function(e,a){return"other"},fields:{year:{displayName:"tahun",relative:{0:"tahun ini",1:"tahun depan","-1":"tahun lalu"},relativeTime:{future:{other:"dalam {0} tahun"},past:{other:"{0} tahun yang lalu"}}},"year-short":{displayName:"thn.",relative:{0:"tahun ini",1:"tahun depan","-1":"tahun lalu"},relativeTime:{future:{other:"dlm {0} thn"},past:{other:"{0} thn lalu"}}},month:{displayName:"bulan",relative:{0:"bulan ini",1:"bulan berikutnya","-1":"bulan lalu"},relativeTime:{future:{other:"dalam {0} bulan"},past:{other:"{0} bulan yang lalu"}}},"month-short":{displayName:"bln.",relative:{0:"bulan ini",1:"bulan berikutnya","-1":"bulan lalu"},relativeTime:{future:{other:"dlm {0} bln"},past:{other:"{0} bln lalu"}}},day:{displayName:"hari",relative:{0:"hari ini",1:"besok",2:"lusa","-2":"kemarin dulu","-1":"kemarin"},relativeTime:{future:{other:"dalam {0} hari"},past:{other:"{0} hari yang lalu"}}},"day-short":{displayName:"h",relative:{0:"hari ini",1:"besok",2:"lusa","-2":"kemarin dulu","-1":"kemarin"},relativeTime:{future:{other:"dalam {0} h"},past:{other:"{0} h lalu"}}},hour:{displayName:"Jam",relative:{0:"jam ini"},relativeTime:{future:{other:"dalam {0} jam"},past:{other:"{0} jam yang lalu"}}},"hour-short":{displayName:"jam",relative:{0:"jam ini"},relativeTime:{future:{other:"dalam {0} jam"},past:{other:"{0} jam lalu"}}},minute:{displayName:"menit",relative:{0:"menit ini"},relativeTime:{future:{other:"dalam {0} menit"},past:{other:"{0} menit yang lalu"}}},"minute-short":{displayName:"mnt.",relative:{0:"menit ini"},relativeTime:{future:{other:"dlm {0} mnt"},past:{other:"{0} mnt lalu"}}},second:{displayName:"detik",relative:{0:"sekarang"},relativeTime:{future:{other:"dalam {0} detik"},past:{other:"{0} detik yang lalu"}}},"second-short":{displayName:"dtk.",relative:{0:"sekarang"},relativeTime:{future:{other:"dlm {0} dtk"},past:{other:"{0} dtk lalu"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/is.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/is.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,r){ true?module.exports=r():undefined}(this,function(){"use strict";return[{locale:"is",pluralRuleFunction:function(e,r){var t=String(e).split("."),i=t[0],a=Number(t[0])==e,n=i.slice(-1),s=i.slice(-2);return r?"other":a&&1==n&&11!=s||!a?"one":"other"},fields:{year:{displayName:"ár",relative:{0:"á þessu ári",1:"á næsta ári","-1":"á síðasta ári"},relativeTime:{future:{one:"eftir {0} ár",other:"eftir {0} ár"},past:{one:"fyrir {0} ári",other:"fyrir {0} árum"}}},"year-short":{displayName:"ár",relative:{0:"á þessu ári",1:"á næsta ári","-1":"á síðasta ári"},relativeTime:{future:{one:"eftir {0} ár",other:"eftir {0} ár"},past:{one:"fyrir {0} ári",other:"fyrir {0} árum"}}},month:{displayName:"mánuður",relative:{0:"í þessum mánuði",1:"í næsta mánuði","-1":"í síðasta mánuði"},relativeTime:{future:{one:"eftir {0} mánuð",other:"eftir {0} mánuði"},past:{one:"fyrir {0} mánuði",other:"fyrir {0} mánuðum"}}},"month-short":{displayName:"mán.",relative:{0:"í þessum mán.",1:"í næsta mán.","-1":"í síðasta mán."},relativeTime:{future:{one:"eftir {0} mán.",other:"eftir {0} mán."},past:{one:"fyrir {0} mán.",other:"fyrir {0} mán."}}},day:{displayName:"dagur",relative:{0:"í dag",1:"á morgun",2:"eftir tvo daga","-2":"í fyrradag","-1":"í gær"},relativeTime:{future:{one:"eftir {0} dag",other:"eftir {0} daga"},past:{one:"fyrir {0} degi",other:"fyrir {0} dögum"}}},"day-short":{displayName:"dagur",relative:{0:"í dag",1:"á morgun",2:"eftir tvo daga","-2":"í fyrradag","-1":"í gær"},relativeTime:{future:{one:"eftir {0} dag",other:"eftir {0} daga"},past:{one:"fyrir {0} degi",other:"fyrir {0} dögum"}}},hour:{displayName:"klukkustund",relative:{0:"þessa stundina"},relativeTime:{future:{one:"eftir {0} klukkustund",other:"eftir {0} klukkustundir"},past:{one:"fyrir {0} klukkustund",other:"fyrir {0} klukkustundum"}}},"hour-short":{displayName:"klst.",relative:{0:"þessa stundina"},relativeTime:{future:{one:"eftir {0} klst.",other:"eftir {0} klst."},past:{one:"fyrir {0} klst.",other:"fyrir {0} klst."}}},minute:{displayName:"mínúta",relative:{0:"á þessari mínútu"},relativeTime:{future:{one:"eftir {0} mínútu",other:"eftir {0} mínútur"},past:{one:"fyrir {0} mínútu",other:"fyrir {0} mínútum"}}},"minute-short":{displayName:"mín.",relative:{0:"á þessari mínútu"},relativeTime:{future:{one:"eftir {0} mín.",other:"eftir {0} mín."},past:{one:"fyrir {0} mín.",other:"fyrir {0} mín."}}},second:{displayName:"sekúnda",relative:{0:"núna"},relativeTime:{future:{one:"eftir {0} sekúndu",other:"eftir {0} sekúndur"},past:{one:"fyrir {0} sekúndu",other:"fyrir {0} sekúndum"}}},"second-short":{displayName:"sek.",relative:{0:"núna"},relativeTime:{future:{one:"eftir {0} sek.",other:"eftir {0} sek."},past:{one:"fyrir {0} sek.",other:"fyrir {0} sek."}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/it.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/it.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,a){ true?module.exports=a():undefined}(this,function(){"use strict";return[{locale:"it",pluralRuleFunction:function(e,a){var t=!String(e).split(".")[1];return a?11==e||8==e||80==e||800==e?"many":"other":1==e&&t?"one":"other"},fields:{year:{displayName:"anno",relative:{0:"quest’anno",1:"anno prossimo","-1":"anno scorso"},relativeTime:{future:{one:"tra {0} anno",other:"tra {0} anni"},past:{one:"{0} anno fa",other:"{0} anni fa"}}},"year-short":{displayName:"anno",relative:{0:"quest’anno",1:"anno prossimo","-1":"anno scorso"},relativeTime:{future:{one:"tra {0} anno",other:"tra {0} anni"},past:{one:"{0} anno fa",other:"{0} anni fa"}}},month:{displayName:"mese",relative:{0:"questo mese",1:"mese prossimo","-1":"mese scorso"},relativeTime:{future:{one:"tra {0} mese",other:"tra {0} mesi"},past:{one:"{0} mese fa",other:"{0} mesi fa"}}},"month-short":{displayName:"mese",relative:{0:"questo mese",1:"mese prossimo","-1":"mese scorso"},relativeTime:{future:{one:"tra {0} mese",other:"tra {0} mesi"},past:{one:"{0} mese fa",other:"{0} mesi fa"}}},day:{displayName:"giorno",relative:{0:"oggi",1:"domani",2:"dopodomani","-2":"l’altro ieri","-1":"ieri"},relativeTime:{future:{one:"tra {0} giorno",other:"tra {0} giorni"},past:{one:"{0} giorno fa",other:"{0} giorni fa"}}},"day-short":{displayName:"g",relative:{0:"oggi",1:"domani",2:"dopodomani","-2":"l’altro ieri","-1":"ieri"},relativeTime:{future:{one:"tra {0} g",other:"tra {0} gg"},past:{one:"{0} g fa",other:"{0} gg fa"}}},hour:{displayName:"ora",relative:{0:"quest’ora"},relativeTime:{future:{one:"tra {0} ora",other:"tra {0} ore"},past:{one:"{0} ora fa",other:"{0} ore fa"}}},"hour-short":{displayName:"h.",relative:{0:"quest’ora"},relativeTime:{future:{one:"tra {0} h",other:"tra {0} h"},past:{one:"{0} h fa",other:"{0} h fa"}}},minute:{displayName:"minuto",relative:{0:"questo minuto"},relativeTime:{future:{one:"tra {0} minuto",other:"tra {0} minuti"},past:{one:"{0} minuto fa",other:"{0} minuti fa"}}},"minute-short":{displayName:"min",relative:{0:"questo minuto"},relativeTime:{future:{one:"tra {0} min",other:"tra {0} min"},past:{one:"{0} min fa",other:"{0} min fa"}}},second:{displayName:"secondo",relative:{0:"ora"},relativeTime:{future:{one:"tra {0} secondo",other:"tra {0} secondi"},past:{one:"{0} secondo fa",other:"{0} secondi fa"}}},"second-short":{displayName:"s",relative:{0:"ora"},relativeTime:{future:{one:"tra {0} s",other:"tra {0} sec."},past:{one:"{0} s fa",other:"{0} sec. fa"}}}}},{locale:"it-CH",parentLocale:"it"},{locale:"it-SM",parentLocale:"it"},{locale:"it-VA",parentLocale:"it"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ja.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/ja.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"ja",pluralRuleFunction:function(e,t){return"other"},fields:{year:{displayName:"年",relative:{0:"今年",1:"翌年","-1":"昨年"},relativeTime:{future:{other:"{0} 年後"},past:{other:"{0} 年前"}}},"year-short":{displayName:"年",relative:{0:"今年",1:"翌年","-1":"昨年"},relativeTime:{future:{other:"{0} 年後"},past:{other:"{0} 年前"}}},month:{displayName:"月",relative:{0:"今月",1:"翌月","-1":"先月"},relativeTime:{future:{other:"{0} か月後"},past:{other:"{0} か月前"}}},"month-short":{displayName:"月",relative:{0:"今月",1:"翌月","-1":"先月"},relativeTime:{future:{other:"{0} か月後"},past:{other:"{0} か月前"}}},day:{displayName:"日",relative:{0:"今日",1:"明日",2:"明後日","-2":"一昨日","-1":"昨日"},relativeTime:{future:{other:"{0} 日後"},past:{other:"{0} 日前"}}},"day-short":{displayName:"日",relative:{0:"今日",1:"明日",2:"明後日","-2":"一昨日","-1":"昨日"},relativeTime:{future:{other:"{0} 日後"},past:{other:"{0} 日前"}}},hour:{displayName:"時",relative:{0:"1 時間以内"},relativeTime:{future:{other:"{0} 時間後"},past:{other:"{0} 時間前"}}},"hour-short":{displayName:"時",relative:{0:"1 時間以内"},relativeTime:{future:{other:"{0} 時間後"},past:{other:"{0} 時間前"}}},minute:{displayName:"分",relative:{0:"1 分以内"},relativeTime:{future:{other:"{0} 分後"},past:{other:"{0} 分前"}}},"minute-short":{displayName:"分",relative:{0:"1 分以内"},relativeTime:{future:{other:"{0} 分後"},past:{other:"{0} 分前"}}},second:{displayName:"秒",relative:{0:"今"},relativeTime:{future:{other:"{0} 秒後"},past:{other:"{0} 秒前"}}},"second-short":{displayName:"秒",relative:{0:"今"},relativeTime:{future:{other:"{0} 秒後"},past:{other:"{0} 秒前"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ka.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/ka.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"ka",pluralRuleFunction:function(e,t){var a=String(e).split(".")[0],r=a.slice(-2);return t?1==a?"one":0==a||r>=2&&r<=20||40==r||60==r||80==r?"many":"other":1==e?"one":"other"},fields:{year:{displayName:"წელი",relative:{0:"ამ წელს",1:"მომავალ წელს","-1":"გასულ წელს"},relativeTime:{future:{one:"{0} წელიწადში",other:"{0} წელიწადში"},past:{one:"{0} წლის წინ",other:"{0} წლის წინ"}}},"year-short":{displayName:"წ.",relative:{0:"ამ წელს",1:"მომავალ წელს","-1":"გასულ წელს"},relativeTime:{future:{one:"{0} წელში",other:"{0} წელში"},past:{one:"{0} წლის წინ",other:"{0} წლის წინ"}}},month:{displayName:"თვე",relative:{0:"ამ თვეში",1:"მომავალ თვეს","-1":"გასულ თვეს"},relativeTime:{future:{one:"{0} თვეში",other:"{0} თვეში"},past:{one:"{0} თვის წინ",other:"{0} თვის წინ"}}},"month-short":{displayName:"თვე",relative:{0:"ამ თვეში",1:"მომავალ თვეს","-1":"გასულ თვეს"},relativeTime:{future:{one:"{0} თვეში",other:"{0} თვეში"},past:{one:"{0} თვის წინ",other:"{0} თვის წინ"}}},day:{displayName:"დღე",relative:{0:"დღეს",1:"ხვალ",2:"ზეგ","-2":"გუშინწინ","-1":"გუშინ"},relativeTime:{future:{one:"{0} დღეში",other:"{0} დღეში"},past:{one:"{0} დღის წინ",other:"{0} დღის წინ"}}},"day-short":{displayName:"დღე",relative:{0:"დღეს",1:"ხვალ",2:"ზეგ","-2":"გუშინწინ","-1":"გუშინ"},relativeTime:{future:{one:"{0} დღეში",other:"{0} დღეში"},past:{one:"{0} დღის წინ",other:"{0} დღის წინ"}}},hour:{displayName:"საათი",relative:{0:"ამ საათში"},relativeTime:{future:{one:"{0} საათში",other:"{0} საათში"},past:{one:"{0} საათის წინ",other:"{0} საათის წინ"}}},"hour-short":{displayName:"სთ.",relative:{0:"ამ საათში"},relativeTime:{future:{one:"{0} საათში",other:"{0} საათში"},past:{one:"{0} სთ წინ",other:"{0} სთ წინ"}}},minute:{displayName:"წუთი",relative:{0:"ამ წუთში"},relativeTime:{future:{one:"{0} წუთში",other:"{0} წუთში"},past:{one:"{0} წუთის წინ",other:"{0} წუთის წინ"}}},"minute-short":{displayName:"წთ.",relative:{0:"ამ წუთში"},relativeTime:{future:{one:"{0} წუთში",other:"{0} წუთში"},past:{one:"{0} წთ წინ",other:"{0} წთ წინ"}}},second:{displayName:"წამი",relative:{0:"ახლა"},relativeTime:{future:{one:"{0} წამში",other:"{0} წამში"},past:{one:"{0} წამის წინ",other:"{0} წამის წინ"}}},"second-short":{displayName:"წმ.",relative:{0:"ახლა"},relativeTime:{future:{one:"{0} წამში",other:"{0} წამში"},past:{one:"{0} წმ წინ",other:"{0} წმ წინ"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/kk.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/kk.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"kk",pluralRuleFunction:function(e,t){var r=String(e).split("."),a=Number(r[0])==e,o=a&&r[0].slice(-1);return t?6==o||9==o||a&&0==o&&0!=e?"many":"other":1==e?"one":"other"},fields:{year:{displayName:"жыл",relative:{0:"биылғы жыл",1:"келесі жыл","-1":"былтырғы жыл"},relativeTime:{future:{one:"{0} жылдан кейін",other:"{0} жылдан кейін"},past:{one:"{0} жыл бұрын",other:"{0} жыл бұрын"}}},"year-short":{displayName:"ж.",relative:{0:"биылғы жыл",1:"келесі жыл","-1":"былтырғы жыл"},relativeTime:{future:{one:"{0} ж. кейін",other:"{0} ж. кейін"},past:{one:"{0} ж. бұрын",other:"{0} ж. бұрын"}}},month:{displayName:"ай",relative:{0:"осы ай",1:"келесі ай","-1":"өткен ай"},relativeTime:{future:{one:"{0} айдан кейін",other:"{0} айдан кейін"},past:{one:"{0} ай бұрын",other:"{0} ай бұрын"}}},"month-short":{displayName:"ай",relative:{0:"осы ай",1:"келесі ай","-1":"өткен ай"},relativeTime:{future:{one:"{0} айдан кейін",other:"{0} айдан кейін"},past:{one:"{0} ай бұрын",other:"{0} ай бұрын"}}},day:{displayName:"күн",relative:{0:"бүгін",1:"ертең",2:"бүрсігүні","-2":"алдыңгүні","-1":"кеше"},relativeTime:{future:{one:"{0} күннен кейін",other:"{0} күннен кейін"},past:{one:"{0} күн бұрын",other:"{0} күн бұрын"}}},"day-short":{displayName:"күн",relative:{0:"бүгін",1:"ертең",2:"бүрсігүні","-2":"алдыңғы күні","-1":"кеше"},relativeTime:{future:{one:"{0} күннен кейін",other:"{0} күннен кейін"},past:{one:"{0} күн бұрын",other:"{0} күн бұрын"}}},hour:{displayName:"сағат",relative:{0:"осы сағат"},relativeTime:{future:{one:"{0} сағаттан кейін",other:"{0} сағаттан кейін"},past:{one:"{0} сағат бұрын",other:"{0} сағат бұрын"}}},"hour-short":{displayName:"сағ",relative:{0:"осы сағат"},relativeTime:{future:{one:"{0} сағ. кейін",other:"{0} сағ. кейін"},past:{one:"{0} сағ. бұрын",other:"{0} сағ. бұрын"}}},minute:{displayName:"минут",relative:{0:"осы минут"},relativeTime:{future:{one:"{0} минуттан кейін",other:"{0} минуттан кейін"},past:{one:"{0} минут бұрын",other:"{0} минут бұрын"}}},"minute-short":{displayName:"мин",relative:{0:"осы минут"},relativeTime:{future:{one:"{0} мин. кейін",other:"{0} мин. кейін"},past:{one:"{0} мин. бұрын",other:"{0} мин. бұрын"}}},second:{displayName:"секунд",relative:{0:"қазір"},relativeTime:{future:{one:"{0} секундтан кейін",other:"{0} секундтан кейін"},past:{one:"{0} секунд бұрын",other:"{0} секунд бұрын"}}},"second-short":{displayName:"с",relative:{0:"қазір"},relativeTime:{future:{one:"{0} сек. кейін",other:"{0} сек. кейін"},past:{one:"{0} сек. бұрын",other:"{0} сек. бұрын"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/km.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/km.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"km",pluralRuleFunction:function(e,t){return"other"},fields:{year:{displayName:"ឆ្នាំ",relative:{0:"ឆ្នាំ​នេះ",1:"ឆ្នាំ​ក្រោយ","-1":"ឆ្នាំ​មុន"},relativeTime:{future:{other:"{0} ឆ្នាំទៀត"},past:{other:"{0} ឆ្នាំ​មុន"}}},"year-short":{displayName:"ឆ្នាំ",relative:{0:"ឆ្នាំ​នេះ",1:"ឆ្នាំ​ក្រោយ","-1":"ឆ្នាំ​មុន"},relativeTime:{future:{other:"{0} ឆ្នាំទៀត"},past:{other:"{0} ឆ្នាំ​មុន"}}},month:{displayName:"ខែ",relative:{0:"ខែ​នេះ",1:"ខែ​ក្រោយ","-1":"ខែ​មុន"},relativeTime:{future:{other:"{0} ខែទៀត"},past:{other:"{0} ខែមុន"}}},"month-short":{displayName:"ខែ",relative:{0:"ខែ​នេះ",1:"ខែ​ក្រោយ","-1":"ខែ​មុន"},relativeTime:{future:{other:"{0} ខែទៀត"},past:{other:"{0} ខែមុន"}}},day:{displayName:"ថ្ងៃ",relative:{0:"ថ្ងៃ​នេះ",1:"ថ្ងៃ​ស្អែក",2:"​ខាន​ស្អែក","-2":"ម្សិល​ម៉្ងៃ","-1":"ម្សិលមិញ"},relativeTime:{future:{other:"{0} ថ្ងៃទៀត"},past:{other:"{0} ថ្ងៃ​មុន"}}},"day-short":{displayName:"ថ្ងៃ",relative:{0:"ថ្ងៃ​នេះ",1:"ថ្ងៃស្អែក",2:"​ខាន​ស្អែក","-2":"ម្សិល​ម៉្ងៃ","-1":"ម្សិលមិញ"},relativeTime:{future:{other:"{0} ថ្ងៃទៀត"},past:{other:"{0} ថ្ងៃ​​មុន"}}},hour:{displayName:"ម៉ោង",relative:{0:"ម៉ោងនេះ"},relativeTime:{future:{other:"ក្នុង​រយៈ​ពេល {0} ម៉ោង"},past:{other:"{0} ម៉ោង​មុន"}}},"hour-short":{displayName:"ម៉ោង",relative:{0:"ម៉ោងនេះ"},relativeTime:{future:{other:"{0} ម៉ោងទៀត"},past:{other:"{0} ម៉ោង​មុន"}}},minute:{displayName:"នាទី",relative:{0:"នាទីនេះ"},relativeTime:{future:{other:"{0} នាទីទៀត"},past:{other:"{0} នាទី​មុន"}}},"minute-short":{displayName:"នាទី",relative:{0:"នាទីនេះ"},relativeTime:{future:{other:"{0} នាទីទៀត"},past:{other:"{0} នាទី​​មុន"}}},second:{displayName:"វិនាទី",relative:{0:"ឥឡូវ"},relativeTime:{future:{other:"{0} វិនាទីទៀត"},past:{other:"{0} វិនាទី​មុន"}}},"second-short":{displayName:"វិនាទី",relative:{0:"ឥឡូវ"},relativeTime:{future:{other:"{0} វិនាទីទៀត"},past:{other:"{0} វិនាទី​មុន"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ko.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/ko.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"ko",pluralRuleFunction:function(e,t){return"other"},fields:{year:{displayName:"년",relative:{0:"올해",1:"내년","-1":"작년"},relativeTime:{future:{other:"{0}년 후"},past:{other:"{0}년 전"}}},"year-short":{displayName:"년",relative:{0:"올해",1:"내년","-1":"작년"},relativeTime:{future:{other:"{0}년 후"},past:{other:"{0}년 전"}}},month:{displayName:"월",relative:{0:"이번 달",1:"다음 달","-1":"지난달"},relativeTime:{future:{other:"{0}개월 후"},past:{other:"{0}개월 전"}}},"month-short":{displayName:"월",relative:{0:"이번 달",1:"다음 달","-1":"지난달"},relativeTime:{future:{other:"{0}개월 후"},past:{other:"{0}개월 전"}}},day:{displayName:"일",relative:{0:"오늘",1:"내일",2:"모레","-2":"그저께","-1":"어제"},relativeTime:{future:{other:"{0}일 후"},past:{other:"{0}일 전"}}},"day-short":{displayName:"일",relative:{0:"오늘",1:"내일",2:"모레","-2":"그저께","-1":"어제"},relativeTime:{future:{other:"{0}일 후"},past:{other:"{0}일 전"}}},hour:{displayName:"시",relative:{0:"현재 시간"},relativeTime:{future:{other:"{0}시간 후"},past:{other:"{0}시간 전"}}},"hour-short":{displayName:"시",relative:{0:"현재 시간"},relativeTime:{future:{other:"{0}시간 후"},past:{other:"{0}시간 전"}}},minute:{displayName:"분",relative:{0:"현재 분"},relativeTime:{future:{other:"{0}분 후"},past:{other:"{0}분 전"}}},"minute-short":{displayName:"분",relative:{0:"현재 분"},relativeTime:{future:{other:"{0}분 후"},past:{other:"{0}분 전"}}},second:{displayName:"초",relative:{0:"지금"},relativeTime:{future:{other:"{0}초 후"},past:{other:"{0}초 전"}}},"second-short":{displayName:"초",relative:{0:"지금"},relativeTime:{future:{other:"{0}초 후"},past:{other:"{0}초 전"}}}}},{locale:"ko-KP",parentLocale:"ko"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ku.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/ku.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"ku",pluralRuleFunction:function(e,t){return t?"other":1==e?"one":"other"},fields:{year:{displayName:"sal",relative:{0:"îsal",1:"sala piştî","-1":"par"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},"year-short":{displayName:"sal",relative:{0:"îsal",1:"sala piştî","-1":"par"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},month:{displayName:"meh",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},"month-short":{displayName:"m.",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},day:{displayName:"roj",relative:{0:"îro",1:"sibe","-1":"duh"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},"day-short":{displayName:"r.",relative:{0:"îro",1:"sibe","-1":"duh"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},hour:{displayName:"saet",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},"hour-short":{displayName:"st.",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},minute:{displayName:"deqîqe",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},"minute-short":{displayName:"d.",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},second:{displayName:"saniye",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}},"second-short":{displayName:"s.",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/lt.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/lt.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,i){ true?module.exports=i():undefined}(this,function(){"use strict";return[{locale:"lt",pluralRuleFunction:function(e,i){var a=String(e).split("."),n=a[1]||"",r=Number(a[0])==e,t=r&&a[0].slice(-1),o=r&&a[0].slice(-2);return i?"other":1==t&&(o<11||o>19)?"one":t>=2&&t<=9&&(o<11||o>19)?"few":0!=n?"many":"other"},fields:{year:{displayName:"metai",relative:{0:"šiais metais",1:"kitais metais","-1":"praėjusiais metais"},relativeTime:{future:{one:"po {0} metų",few:"po {0} metų",many:"po {0} metų",other:"po {0} metų"},past:{one:"prieš {0} metus",few:"prieš {0} metus",many:"prieš {0} metų",other:"prieš {0} metų"}}},"year-short":{displayName:"m.",relative:{0:"šiais metais",1:"kitais metais","-1":"praėjusiais metais"},relativeTime:{future:{one:"po {0} m.",few:"po {0} m.",many:"po {0} m.",other:"po {0} m."},past:{one:"prieš {0} m.",few:"prieš {0} m.",many:"prieš {0} m.",other:"prieš {0} m."}}},month:{displayName:"mėnuo",relative:{0:"šį mėnesį",1:"kitą mėnesį","-1":"praėjusį mėnesį"},relativeTime:{future:{one:"po {0} mėnesio",few:"po {0} mėnesių",many:"po {0} mėnesio",other:"po {0} mėnesių"},past:{one:"prieš {0} mėnesį",few:"prieš {0} mėnesius",many:"prieš {0} mėnesio",other:"prieš {0} mėnesių"}}},"month-short":{displayName:"mėn.",relative:{0:"šį mėnesį",1:"kitą mėnesį","-1":"praėjusį mėnesį"},relativeTime:{future:{one:"po {0} mėn.",few:"po {0} mėn.",many:"po {0} mėn.",other:"po {0} mėn."},past:{one:"prieš {0} mėn.",few:"prieš {0} mėn.",many:"prieš {0} mėn.",other:"prieš {0} mėn."}}},day:{displayName:"diena",relative:{0:"šiandien",1:"rytoj",2:"poryt","-2":"užvakar","-1":"vakar"},relativeTime:{future:{one:"po {0} dienos",few:"po {0} dienų",many:"po {0} dienos",other:"po {0} dienų"},past:{one:"prieš {0} dieną",few:"prieš {0} dienas",many:"prieš {0} dienos",other:"prieš {0} dienų"}}},"day-short":{displayName:"d.",relative:{0:"šiandien",1:"rytoj",2:"poryt","-2":"užvakar","-1":"vakar"},relativeTime:{future:{one:"po {0} d.",few:"po {0} d.",many:"po {0} d.",other:"po {0} d."},past:{one:"prieš {0} d.",few:"prieš {0} d.",many:"prieš {0} d.",other:"prieš {0} d."}}},hour:{displayName:"valanda",relative:{0:"šią valandą"},relativeTime:{future:{one:"po {0} valandos",few:"po {0} valandų",many:"po {0} valandos",other:"po {0} valandų"},past:{one:"prieš {0} valandą",few:"prieš {0} valandas",many:"prieš {0} valandos",other:"prieš {0} valandų"}}},"hour-short":{displayName:"val.",relative:{0:"šią valandą"},relativeTime:{future:{one:"po {0} val.",few:"po {0} val.",many:"po {0} val.",other:"po {0} val."},past:{one:"prieš {0} val.",few:"prieš {0} val.",many:"prieš {0} val.",other:"prieš {0} val."}}},minute:{displayName:"minutė",relative:{0:"šią minutę"},relativeTime:{future:{one:"po {0} minutės",few:"po {0} minučių",many:"po {0} minutės",other:"po {0} minučių"},past:{one:"prieš {0} minutę",few:"prieš {0} minutes",many:"prieš {0} minutės",other:"prieš {0} minučių"}}},"minute-short":{displayName:"min.",relative:{0:"šią minutę"},relativeTime:{future:{one:"po {0} min.",few:"po {0} min.",many:"po {0} min.",other:"po {0} min."},past:{one:"prieš {0} min.",few:"prieš {0} min.",many:"prieš {0} min.",other:"prieš {0} min."}}},second:{displayName:"sekundė",relative:{0:"dabar"},relativeTime:{future:{one:"po {0} sekundės",few:"po {0} sekundžių",many:"po {0} sekundės",other:"po {0} sekundžių"},past:{one:"prieš {0} sekundę",few:"prieš {0} sekundes",many:"prieš {0} sekundės",other:"prieš {0} sekundžių"}}},"second-short":{displayName:"sek.",relative:{0:"dabar"},relativeTime:{future:{one:"po {0} sek.",few:"po {0} sek.",many:"po {0} sek.",other:"po {0} sek."},past:{one:"prieš {0} sek.",few:"prieš {0} sek.",many:"prieš {0} sek.",other:"prieš {0} sek."}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/lv.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/lv.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,r){ true?module.exports=r():undefined}(this,function(){"use strict";return[{locale:"lv",pluralRuleFunction:function(e,r){var a=String(e).split("."),t=a[1]||"",i=t.length,m=Number(a[0])==e,s=m&&a[0].slice(-1),n=m&&a[0].slice(-2),p=t.slice(-2),o=t.slice(-1);return r?"other":m&&0==s||n>=11&&n<=19||2==i&&p>=11&&p<=19?"zero":1==s&&11!=n||2==i&&1==o&&11!=p||2!=i&&1==o?"one":"other"},fields:{year:{displayName:"gads",relative:{0:"šajā gadā",1:"nākamajā gadā","-1":"pagājušajā gadā"},relativeTime:{future:{zero:"pēc {0} gadiem",one:"pēc {0} gada",other:"pēc {0} gadiem"},past:{zero:"pirms {0} gadiem",one:"pirms {0} gada",other:"pirms {0} gadiem"}}},"year-short":{displayName:"g.",relative:{0:"šajā gadā",1:"nākamajā gadā","-1":"pagājušajā gadā"},relativeTime:{future:{zero:"pēc {0} g.",one:"pēc {0} g.",other:"pēc {0} g."},past:{zero:"pirms {0} g.",one:"pirms {0} g.",other:"pirms {0} g."}}},month:{displayName:"mēnesis",relative:{0:"šajā mēnesī",1:"nākamajā mēnesī","-1":"pagājušajā mēnesī"},relativeTime:{future:{zero:"pēc {0} mēnešiem",one:"pēc {0} mēneša",other:"pēc {0} mēnešiem"},past:{zero:"pirms {0} mēnešiem",one:"pirms {0} mēneša",other:"pirms {0} mēnešiem"}}},"month-short":{displayName:"mēn.",relative:{0:"šajā mēnesī",1:"nākamajā mēnesī","-1":"pagājušajā mēnesī"},relativeTime:{future:{zero:"pēc {0} mēn.",one:"pēc {0} mēn.",other:"pēc {0} mēn."},past:{zero:"pirms {0} mēn.",one:"pirms {0} mēn.",other:"pirms {0} mēn."}}},day:{displayName:"diena",relative:{0:"šodien",1:"rīt",2:"parīt","-2":"aizvakar","-1":"vakar"},relativeTime:{future:{zero:"pēc {0} dienām",one:"pēc {0} dienas",other:"pēc {0} dienām"},past:{zero:"pirms {0} dienām",one:"pirms {0} dienas",other:"pirms {0} dienām"}}},"day-short":{displayName:"d.",relative:{0:"šodien",1:"rīt",2:"parīt","-2":"aizvakar","-1":"vakar"},relativeTime:{future:{zero:"pēc {0} d.",one:"pēc {0} d.",other:"pēc {0} d."},past:{zero:"pirms {0} d.",one:"pirms {0} d.",other:"pirms {0} d."}}},hour:{displayName:"stundas",relative:{0:"šajā stundā"},relativeTime:{future:{zero:"pēc {0} stundām",one:"pēc {0} stundas",other:"pēc {0} stundām"},past:{zero:"pirms {0} stundām",one:"pirms {0} stundas",other:"pirms {0} stundām"}}},"hour-short":{displayName:"st.",relative:{0:"šajā stundā"},relativeTime:{future:{zero:"pēc {0} st.",one:"pēc {0} st.",other:"pēc {0} st."},past:{zero:"pirms {0} st.",one:"pirms {0} st.",other:"pirms {0} st."}}},minute:{displayName:"minūtes",relative:{0:"šajā minūtē"},relativeTime:{future:{zero:"pēc {0} minūtēm",one:"pēc {0} minūtes",other:"pēc {0} minūtēm"},past:{zero:"pirms {0} minūtēm",one:"pirms {0} minūtes",other:"pirms {0} minūtēm"}}},"minute-short":{displayName:"min.",relative:{0:"šajā minūtē"},relativeTime:{future:{zero:"pēc {0} min.",one:"pēc {0} min.",other:"pēc {0} min."},past:{zero:"pirms {0} min.",one:"pirms {0} min.",other:"pirms {0} min."}}},second:{displayName:"sekundes",relative:{0:"tagad"},relativeTime:{future:{zero:"pēc {0} sekundēm",one:"pēc {0} sekundes",other:"pēc {0} sekundēm"},past:{zero:"pirms {0} sekundēm",one:"pirms {0} sekundes",other:"pirms {0} sekundēm"}}},"second-short":{displayName:"sek.",relative:{0:"tagad"},relativeTime:{future:{zero:"pēc {0} sek.",one:"pēc {0} sek.",other:"pēc {0} sek."},past:{zero:"pirms {0} sek.",one:"pirms {0} sek.",other:"pirms {0} sek."}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/mi.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/mi.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"mi",pluralRuleFunction:function(e,t){return"other"},fields:{year:{displayName:"tau",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},"year-short":{displayName:"t",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},month:{displayName:"marama",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},"month-short":{displayName:"m",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},day:{displayName:"rā",relative:{0:"āianei",1:"āpōpō","-1":"inanahi"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},"day-short":{displayName:"rā",relative:{0:"āianei",1:"āpōpō","-1":"inanahi"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},hour:{displayName:"hāora",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},"hour-short":{displayName:"hr",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},minute:{displayName:"meneti",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},"minute-short":{displayName:"men",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},second:{displayName:"hēkona",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}},"second-short":{displayName:"hēk",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/mn.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/mn.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"mn",pluralRuleFunction:function(e,t){return t?"other":1==e?"one":"other"},fields:{year:{displayName:"жил",relative:{0:"энэ жил",1:"ирэх жил","-1":"өнгөрсөн жил"},relativeTime:{future:{one:"{0} жилийн дараа",other:"{0} жилийн дараа"},past:{one:"{0} жилийн өмнө",other:"{0} жилийн өмнө"}}},"year-short":{displayName:"жил",relative:{0:"энэ жил",1:"ирэх жил","-1":"өнгөрсөн жил"},relativeTime:{future:{one:"{0} жилийн дараа",other:"{0} жилийн дараа"},past:{one:"{0} жилийн өмнө",other:"{0} жилийн өмнө"}}},month:{displayName:"сар",relative:{0:"энэ сар",1:"ирэх сар","-1":"өнгөрсөн сар"},relativeTime:{future:{one:"{0} сарын дараа",other:"{0} сарын дараа"},past:{one:"{0} сарын өмнө",other:"{0} сарын өмнө"}}},"month-short":{displayName:"сар",relative:{0:"энэ сар",1:"ирэх сар","-1":"өнгөрсөн сар"},relativeTime:{future:{one:"{0} сарын дараа",other:"{0} сарын дараа"},past:{one:"{0} сарын өмнө",other:"{0} сарын өмнө"}}},day:{displayName:"өдөр",relative:{0:"өнөөдөр",1:"маргааш",2:"нөгөөдөр","-2":"уржигдар","-1":"өчигдөр"},relativeTime:{future:{one:"{0} өдрийн дараа",other:"{0} өдрийн дараа"},past:{one:"{0} өдрийн өмнө",other:"{0} өдрийн өмнө"}}},"day-short":{displayName:"өдөр",relative:{0:"өнөөдөр",1:"маргааш",2:"нөгөөдөр","-2":"уржигдар","-1":"өчигдөр"},relativeTime:{future:{one:"{0} өдрийн дараа",other:"{0} өдрийн дараа"},past:{one:"{0} өдрийн өмнө",other:"{0} өдрийн өмнө"}}},hour:{displayName:"цаг",relative:{0:"энэ цаг"},relativeTime:{future:{one:"{0} цагийн дараа",other:"{0} цагийн дараа"},past:{one:"{0} цагийн өмнө",other:"{0} цагийн өмнө"}}},"hour-short":{displayName:"ц",relative:{0:"энэ цаг"},relativeTime:{future:{one:"{0} ц дараа",other:"{0} ц дараа"},past:{one:"{0} ц өмнө",other:"{0} ц өмнө"}}},minute:{displayName:"минут",relative:{0:"энэ минут"},relativeTime:{future:{one:"{0} минутын дараа",other:"{0} минутын дараа"},past:{one:"{0} минутын өмнө",other:"{0} минутын өмнө"}}},"minute-short":{displayName:"мин",relative:{0:"энэ минут"},relativeTime:{future:{one:"{0} мин дараа",other:"{0} мин дараа"},past:{one:"{0} мин өмнө",other:"{0} мин өмнө"}}},second:{displayName:"секунд",relative:{0:"одоо"},relativeTime:{future:{one:"{0} секундын дараа",other:"{0} секундын дараа"},past:{one:"{0} секундын өмнө",other:"{0} секундын өмнө"}}},"second-short":{displayName:"сек",relative:{0:"одоо"},relativeTime:{future:{one:"{0} сек дараа",other:"{0} сек дараа"},past:{one:"{0} сек өмнө",other:"{0} сек өмнө"}}}}},{locale:"mn-Mong",pluralRuleFunction:function(e,t){return"other"},fields:{year:{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},"year-short":{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},month:{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},"month-short":{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},day:{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},"day-short":{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},hour:{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},"hour-short":{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},minute:{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},"minute-short":{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},second:{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}},"second-short":{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/nb.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/nb.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"nb",pluralRuleFunction:function(e,t){return t?"other":1==e?"one":"other"},fields:{year:{displayName:"år",relative:{0:"i år",1:"neste år","-1":"i fjor"},relativeTime:{future:{one:"om {0} år",other:"om {0} år"},past:{one:"for {0} år siden",other:"for {0} år siden"}}},"year-short":{displayName:"år",relative:{0:"i år",1:"neste år","-1":"i fjor"},relativeTime:{future:{one:"om {0} år",other:"om {0} år"},past:{one:"for {0} år siden",other:"for {0} år siden"}}},month:{displayName:"måned",relative:{0:"denne måneden",1:"neste måned","-1":"forrige måned"},relativeTime:{future:{one:"om {0} måned",other:"om {0} måneder"},past:{one:"for {0} måned siden",other:"for {0} måneder siden"}}},"month-short":{displayName:"mnd.",relative:{0:"denne md.",1:"neste md.","-1":"forrige md."},relativeTime:{future:{one:"om {0} md.",other:"om {0} md."},past:{one:"for {0} md. siden",other:"for {0} md. siden"}}},day:{displayName:"dag",relative:{0:"i dag",1:"i morgen",2:"i overmorgen","-2":"i forgårs","-1":"i går"},relativeTime:{future:{one:"om {0} døgn",other:"om {0} døgn"},past:{one:"for {0} døgn siden",other:"for {0} døgn siden"}}},"day-short":{displayName:"dag",relative:{0:"i dag",1:"i morgen",2:"i overmorgen","-2":"i forgårs","-1":"i går"},relativeTime:{future:{one:"om {0} d.",other:"om {0} d."},past:{one:"for {0} d. siden",other:"for {0} d. siden"}}},hour:{displayName:"time",relative:{0:"denne timen"},relativeTime:{future:{one:"om {0} time",other:"om {0} timer"},past:{one:"for {0} time siden",other:"for {0} timer siden"}}},"hour-short":{displayName:"t",relative:{0:"denne timen"},relativeTime:{future:{one:"om {0} t",other:"om {0} t"},past:{one:"for {0} t siden",other:"for {0} t siden"}}},minute:{displayName:"minutt",relative:{0:"dette minuttet"},relativeTime:{future:{one:"om {0} minutt",other:"om {0} minutter"},past:{one:"for {0} minutt siden",other:"for {0} minutter siden"}}},"minute-short":{displayName:"min",relative:{0:"dette minuttet"},relativeTime:{future:{one:"om {0} min",other:"om {0} min"},past:{one:"for {0} min siden",other:"for {0} min siden"}}},second:{displayName:"sekund",relative:{0:"nå"},relativeTime:{future:{one:"om {0} sekund",other:"om {0} sekunder"},past:{one:"for {0} sekund siden",other:"for {0} sekunder siden"}}},"second-short":{displayName:"sek",relative:{0:"nå"},relativeTime:{future:{one:"om {0} sek",other:"om {0} sek"},past:{one:"for {0} sek siden",other:"for {0} sek siden"}}}}},{locale:"nb-SJ",parentLocale:"nb"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/nl.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/nl.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,n){ true?module.exports=n():undefined}(this,function(){"use strict";return[{locale:"nl",pluralRuleFunction:function(e,n){var a=!String(e).split(".")[1];return n?"other":1==e&&a?"one":"other"},fields:{year:{displayName:"jaar",relative:{0:"dit jaar",1:"volgend jaar","-1":"vorig jaar"},relativeTime:{future:{one:"over {0} jaar",other:"over {0} jaar"},past:{one:"{0} jaar geleden",other:"{0} jaar geleden"}}},"year-short":{displayName:"jr",relative:{0:"dit jaar",1:"volgend jaar","-1":"vorig jaar"},relativeTime:{future:{one:"over {0} jaar",other:"over {0} jaar"},past:{one:"{0} jaar geleden",other:"{0} jaar geleden"}}},month:{displayName:"maand",relative:{0:"deze maand",1:"volgende maand","-1":"vorige maand"},relativeTime:{future:{one:"over {0} maand",other:"over {0} maanden"},past:{one:"{0} maand geleden",other:"{0} maanden geleden"}}},"month-short":{displayName:"mnd",relative:{0:"deze maand",1:"volgende maand","-1":"vorige maand"},relativeTime:{future:{one:"over {0} maand",other:"over {0} maanden"},past:{one:"{0} maand geleden",other:"{0} maanden geleden"}}},day:{displayName:"dag",relative:{0:"vandaag",1:"morgen",2:"overmorgen","-2":"eergisteren","-1":"gisteren"},relativeTime:{future:{one:"over {0} dag",other:"over {0} dagen"},past:{one:"{0} dag geleden",other:"{0} dagen geleden"}}},"day-short":{displayName:"dag",relative:{0:"vandaag",1:"morgen",2:"overmorgen","-2":"eergisteren","-1":"gisteren"},relativeTime:{future:{one:"over {0} dag",other:"over {0} dgn"},past:{one:"{0} dag geleden",other:"{0} dgn geleden"}}},hour:{displayName:"uur",relative:{0:"binnen een uur"},relativeTime:{future:{one:"over {0} uur",other:"over {0} uur"},past:{one:"{0} uur geleden",other:"{0} uur geleden"}}},"hour-short":{displayName:"uur",relative:{0:"binnen een uur"},relativeTime:{future:{one:"over {0} uur",other:"over {0} uur"},past:{one:"{0} uur geleden",other:"{0} uur geleden"}}},minute:{displayName:"minuut",relative:{0:"binnen een minuut"},relativeTime:{future:{one:"over {0} minuut",other:"over {0} minuten"},past:{one:"{0} minuut geleden",other:"{0} minuten geleden"}}},"minute-short":{displayName:"min",relative:{0:"binnen een minuut"},relativeTime:{future:{one:"over {0} min.",other:"over {0} min."},past:{one:"{0} min. geleden",other:"{0} min. geleden"}}},second:{displayName:"seconde",relative:{0:"nu"},relativeTime:{future:{one:"over {0} seconde",other:"over {0} seconden"},past:{one:"{0} seconde geleden",other:"{0} seconden geleden"}}},"second-short":{displayName:"sec",relative:{0:"nu"},relativeTime:{future:{one:"over {0} sec.",other:"over {0} sec."},past:{one:"{0} sec. geleden",other:"{0} sec. geleden"}}}}},{locale:"nl-AW",parentLocale:"nl"},{locale:"nl-BE",parentLocale:"nl"},{locale:"nl-BQ",parentLocale:"nl"},{locale:"nl-CW",parentLocale:"nl"},{locale:"nl-SR",parentLocale:"nl"},{locale:"nl-SX",parentLocale:"nl"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/nn.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/nn.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"nn",pluralRuleFunction:function(e,t){return t?"other":1==e?"one":"other"},fields:{year:{displayName:"år",relative:{0:"i år",1:"neste år","-1":"i fjor"},relativeTime:{future:{one:"om {0} år",other:"om {0} år"},past:{one:"for {0} år sidan",other:"for {0} år sidan"}}},"year-short":{displayName:"år",relative:{0:"i år",1:"neste år","-1":"i fjor"},relativeTime:{future:{one:"om {0} år",other:"om {0} år"},past:{one:"for {0} år sidan",other:"for {0} år sidan"}}},month:{displayName:"månad",relative:{0:"denne månaden",1:"neste månad","-1":"førre månad"},relativeTime:{future:{one:"om {0} månad",other:"om {0} månadar"},past:{one:"for {0} månad sidan",other:"for {0} månadar sidan"}}},"month-short":{displayName:"mnd.",relative:{0:"denne månaden",1:"neste månad","-1":"førre månad"},relativeTime:{future:{one:"om {0} md.",other:"om {0} md."},past:{one:"for {0} md. sidan",other:"for {0} md. sidan"}}},day:{displayName:"dag",relative:{0:"i dag",1:"i morgon",2:"i overmorgon","-2":"i førgår","-1":"i går"},relativeTime:{future:{one:"om {0} døgn",other:"om {0} døgn"},past:{one:"for {0} døgn sidan",other:"for {0} døgn sidan"}}},"day-short":{displayName:"dag",relative:{0:"i dag",1:"i morgon",2:"i overmorgon","-2":"i førgår","-1":"i går"},relativeTime:{future:{one:"om {0} d.",other:"om {0} d."},past:{one:"for {0} d. sidan",other:"for {0} d. sidan"}}},hour:{displayName:"time",relative:{0:"denne timen"},relativeTime:{future:{one:"om {0} time",other:"om {0} timar"},past:{one:"for {0} time sidan",other:"for {0} timar sidan"}}},"hour-short":{displayName:"t",relative:{0:"denne timen"},relativeTime:{future:{one:"om {0} t",other:"om {0} t"},past:{one:"for {0} t sidan",other:"for {0} t sidan"}}},minute:{displayName:"minutt",relative:{0:"dette minuttet"},relativeTime:{future:{one:"om {0} minutt",other:"om {0} minutt"},past:{one:"for {0} minutt sidan",other:"for {0} minutt sidan"}}},"minute-short":{displayName:"min",relative:{0:"dette minuttet"},relativeTime:{future:{one:"om {0} min",other:"om {0} min"},past:{one:"for {0} min sidan",other:"for {0} min sidan"}}},second:{displayName:"sekund",relative:{0:"no"},relativeTime:{future:{one:"om {0} sekund",other:"om {0} sekund"},past:{one:"for {0} sekund sidan",other:"for {0} sekund sidan"}}},"second-short":{displayName:"sek",relative:{0:"no"},relativeTime:{future:{one:"om {0} sek",other:"om {0} sek"},past:{one:"for {0} sek sidan",other:"for {0} sek sidan"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/nso.js": /*!*********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/nso.js ***! \*********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"nso",pluralRuleFunction:function(e,t){return t?"other":0==e||1==e?"one":"other"},fields:{year:{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},"year-short":{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},month:{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},"month-short":{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},day:{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},"day-short":{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},hour:{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},"hour-short":{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},minute:{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},"minute-short":{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},second:{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}},"second-short":{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/or.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/or.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"or",pluralRuleFunction:function(e,t){var r=String(e).split("."),o=Number(r[0])==e;return t?1==e||5==e||o&&e>=7&&e<=9?"one":2==e||3==e?"two":4==e?"few":6==e?"many":"other":1==e?"one":"other"},fields:{year:{displayName:"ବର୍ଷ",relative:{0:"ଏହି ବର୍ଷ",1:"ଆଗାମୀ ବର୍ଷ","-1":"ଗତ ବର୍ଷ"},relativeTime:{future:{one:"{0} ବର୍ଷରେ",other:"{0} ବର୍ଷରେ"},past:{one:"{0} ବର୍ଷ ପୂର୍ବେ",other:"{0} ବର୍ଷ ପୂର୍ବେ"}}},"year-short":{displayName:"ବ.",relative:{0:"ଏହି ବର୍ଷ",1:"ଆଗାମୀ ବର୍ଷ","-1":"ଗତ ବର୍ଷ"},relativeTime:{future:{one:"{0} ବ. ରେ",other:"{0} ବ. ରେ"},past:{one:"{0} ବ. ପୂର୍ବେ",other:"{0} ବ. ପୂର୍ବେ"}}},month:{displayName:"ମାସ",relative:{0:"ଏହି ମାସ",1:"ଆଗାମୀ ମାସ","-1":"ଗତ ମାସ"},relativeTime:{future:{one:"{0} ମାସରେ",other:"{0} ମାସରେ"},past:{one:"{0} ମାସ ପୂର୍ବେ",other:"{0} ମାସ ପୂର୍ବେ"}}},"month-short":{displayName:"ମା.",relative:{0:"ଏହି ମାସ",1:"ଆଗାମୀ ମାସ","-1":"ଗତ ମାସ"},relativeTime:{future:{one:"{0} ମା. ରେ",other:"{0} ମା. ରେ"},past:{one:"{0} ମା. ପୂର୍ବେ",other:"{0} ମା. ପୂର୍ବେ"}}},day:{displayName:"ଦିନ",relative:{0:"ଆଜି",1:"ଆସନ୍ତାକାଲି","-1":"ଗତକାଲି"},relativeTime:{future:{one:"{0} ଦିନରେ",other:"{0} ଦିନରେ"},past:{one:"{0} ଦିନ ପୂର୍ବେ",other:"{0} ଦିନ ପୂର୍ବେ"}}},"day-short":{displayName:"ଦିନ",relative:{0:"ଆଜି",1:"ଆସନ୍ତାକାଲି","-1":"ଗତକାଲି"},relativeTime:{future:{one:"{0} ଦିନରେ",other:"{0} ଦିନରେ"},past:{one:"{0} ଦିନ ପୂର୍ବେ",other:"{0} ଦିନ ପୂର୍ବେ"}}},hour:{displayName:"ଘଣ୍ଟା",relative:{0:"ଏହି ଘଣ୍ଟା"},relativeTime:{future:{one:"{0} ଘଣ୍ଟାରେ",other:"{0} ଘଣ୍ଟାରେ"},past:{one:"{0} ଘଣ୍ଟା ପୂର୍ବେ",other:"{0} ଘଣ୍ଟା ପୂର୍ବେ"}}},"hour-short":{displayName:"ଘ.",relative:{0:"ଏହି ଘଣ୍ଟା"},relativeTime:{future:{one:"{0} ଘ. ରେ",other:"{0} ଘ. ରେ"},past:{one:"{0} ଘ. ପୂର୍ବେ",other:"{0} ଘ. ପୂର୍ବେ"}}},minute:{displayName:"ମିନିଟ୍",relative:{0:"ଏହି ମିନିଟ୍"},relativeTime:{future:{one:"{0} ମିନିଟ୍‌‌ରେ",other:"{0} ମିନିଟ୍‌‌ରେ"},past:{one:"{0} ମିନିଟ୍ ପୂର୍ବେ",other:"{0} ମିନିଟ୍ ପୂର୍ବେ"}}},"minute-short":{displayName:"ମି.",relative:{0:"ଏହି ମିନିଟ୍"},relativeTime:{future:{one:"{0} ମି. ରେ",other:"{0} ମି. ରେ"},past:{one:"{0} ମି. ପୂର୍ବେ",other:"{0} ମି. ପୂର୍ବେ"}}},second:{displayName:"ସେକେଣ୍ଡ୍",relative:{0:"ବର୍ତ୍ତମାନ"},relativeTime:{future:{one:"{0} ସେକେଣ୍ଡରେ",other:"{0} ସେକେଣ୍ଡରେ"},past:{one:"{0} ସେକେଣ୍ଡ ପୂର୍ବେ",other:"{0} ସେକେଣ୍ଡ ପୂର୍ବେ"}}},"second-short":{displayName:"ସେକେଣ୍ଡ୍",relative:{0:"ବର୍ତ୍ତମାନ"},relativeTime:{future:{one:"{0} ସେ. ରେ",other:"{0} ସେ. ରେ"},past:{one:"{0} ସେ. ପୂର୍ବେ",other:"{0} ସେ. ପୂର୍ବେ"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/pl.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/pl.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"pl",pluralRuleFunction:function(e,t){var a=String(e).split("."),m=a[0],i=!a[1],n=m.slice(-1),u=m.slice(-2);return t?"other":1==e&&i?"one":i&&n>=2&&n<=4&&(u<12||u>14)?"few":i&&1!=m&&(0==n||1==n)||i&&n>=5&&n<=9||i&&u>=12&&u<=14?"many":"other"},fields:{year:{displayName:"rok",relative:{0:"w tym roku",1:"w przyszłym roku","-1":"w zeszłym roku"},relativeTime:{future:{one:"za {0} rok",few:"za {0} lata",many:"za {0} lat",other:"za {0} roku"},past:{one:"{0} rok temu",few:"{0} lata temu",many:"{0} lat temu",other:"{0} roku temu"}}},"year-short":{displayName:"r.",relative:{0:"w tym roku",1:"w przyszłym roku","-1":"w zeszłym roku"},relativeTime:{future:{one:"za {0} rok",few:"za {0} lata",many:"za {0} lat",other:"za {0} roku"},past:{one:"{0} rok temu",few:"{0} lata temu",many:"{0} lat temu",other:"{0} roku temu"}}},month:{displayName:"miesiąc",relative:{0:"w tym miesiącu",1:"w przyszłym miesiącu","-1":"w zeszłym miesiącu"},relativeTime:{future:{one:"za {0} miesiąc",few:"za {0} miesiące",many:"za {0} miesięcy",other:"za {0} miesiąca"},past:{one:"{0} miesiąc temu",few:"{0} miesiące temu",many:"{0} miesięcy temu",other:"{0} miesiąca temu"}}},"month-short":{displayName:"mies.",relative:{0:"w tym miesiącu",1:"w przyszłym miesiącu","-1":"w zeszłym miesiącu"},relativeTime:{future:{one:"za {0} mies.",few:"za {0} mies.",many:"za {0} mies.",other:"za {0} mies."},past:{one:"{0} mies. temu",few:"{0} mies. temu",many:"{0} mies. temu",other:"{0} mies. temu"}}},day:{displayName:"dzień",relative:{0:"dzisiaj",1:"jutro",2:"pojutrze","-2":"przedwczoraj","-1":"wczoraj"},relativeTime:{future:{one:"za {0} dzień",few:"za {0} dni",many:"za {0} dni",other:"za {0} dnia"},past:{one:"{0} dzień temu",few:"{0} dni temu",many:"{0} dni temu",other:"{0} dnia temu"}}},"day-short":{displayName:"dzień",relative:{0:"dzisiaj",1:"jutro",2:"pojutrze","-2":"przedwczoraj","-1":"wczoraj"},relativeTime:{future:{one:"za {0} dzień",few:"za {0} dni",many:"za {0} dni",other:"za {0} dnia"},past:{one:"{0} dzień temu",few:"{0} dni temu",many:"{0} dni temu",other:"{0} dnia temu"}}},hour:{displayName:"godzina",relative:{0:"ta godzina"},relativeTime:{future:{one:"za {0} godzinę",few:"za {0} godziny",many:"za {0} godzin",other:"za {0} godziny"},past:{one:"{0} godzinę temu",few:"{0} godziny temu",many:"{0} godzin temu",other:"{0} godziny temu"}}},"hour-short":{displayName:"godz.",relative:{0:"ta godzina"},relativeTime:{future:{one:"za {0} godz.",few:"za {0} godz.",many:"za {0} godz.",other:"za {0} godz."},past:{one:"{0} godz. temu",few:"{0} godz. temu",many:"{0} godz. temu",other:"{0} godz. temu"}}},minute:{displayName:"minuta",relative:{0:"ta minuta"},relativeTime:{future:{one:"za {0} minutę",few:"za {0} minuty",many:"za {0} minut",other:"za {0} minuty"},past:{one:"{0} minutę temu",few:"{0} minuty temu",many:"{0} minut temu",other:"{0} minuty temu"}}},"minute-short":{displayName:"min",relative:{0:"ta minuta"},relativeTime:{future:{one:"za {0} min",few:"za {0} min",many:"za {0} min",other:"za {0} min"},past:{one:"{0} min temu",few:"{0} min temu",many:"{0} min temu",other:"{0} min temu"}}},second:{displayName:"sekunda",relative:{0:"teraz"},relativeTime:{future:{one:"za {0} sekundę",few:"za {0} sekundy",many:"za {0} sekund",other:"za {0} sekundy"},past:{one:"{0} sekundę temu",few:"{0} sekundy temu",many:"{0} sekund temu",other:"{0} sekundy temu"}}},"second-short":{displayName:"sek.",relative:{0:"teraz"},relativeTime:{future:{one:"za {0} sek.",few:"za {0} sek.",many:"za {0} sek.",other:"za {0} sek."},past:{one:"{0} sek. temu",few:"{0} sek. temu",many:"{0} sek. temu",other:"{0} sek. temu"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/pt.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/pt.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"pt",pluralRuleFunction:function(e,t){var o=String(e).split(".")[0];return t?"other":0==o||1==o?"one":"other"},fields:{year:{displayName:"ano",relative:{0:"este ano",1:"próximo ano","-1":"ano passado"},relativeTime:{future:{one:"em {0} ano",other:"em {0} anos"},past:{one:"há {0} ano",other:"há {0} anos"}}},"year-short":{displayName:"ano",relative:{0:"este ano",1:"próximo ano","-1":"ano passado"},relativeTime:{future:{one:"em {0} ano",other:"em {0} anos"},past:{one:"há {0} ano",other:"há {0} anos"}}},month:{displayName:"mês",relative:{0:"este mês",1:"próximo mês","-1":"mês passado"},relativeTime:{future:{one:"em {0} mês",other:"em {0} meses"},past:{one:"há {0} mês",other:"há {0} meses"}}},"month-short":{displayName:"mês",relative:{0:"este mês",1:"próximo mês","-1":"mês passado"},relativeTime:{future:{one:"em {0} mês",other:"em {0} meses"},past:{one:"há {0} mês",other:"há {0} meses"}}},day:{displayName:"dia",relative:{0:"hoje",1:"amanhã",2:"depois de amanhã","-2":"anteontem","-1":"ontem"},relativeTime:{future:{one:"em {0} dia",other:"em {0} dias"},past:{one:"há {0} dia",other:"há {0} dias"}}},"day-short":{displayName:"dia",relative:{0:"hoje",1:"amanhã",2:"depois de amanhã","-2":"anteontem","-1":"ontem"},relativeTime:{future:{one:"em {0} dia",other:"em {0} dias"},past:{one:"há {0} dia",other:"há {0} dias"}}},hour:{displayName:"hora",relative:{0:"esta hora"},relativeTime:{future:{one:"em {0} hora",other:"em {0} horas"},past:{one:"há {0} hora",other:"há {0} horas"}}},"hour-short":{displayName:"h",relative:{0:"esta hora"},relativeTime:{future:{one:"em {0} h",other:"em {0} h"},past:{one:"há {0} h",other:"há {0} h"}}},minute:{displayName:"minuto",relative:{0:"este minuto"},relativeTime:{future:{one:"em {0} minuto",other:"em {0} minutos"},past:{one:"há {0} minuto",other:"há {0} minutos"}}},"minute-short":{displayName:"min.",relative:{0:"este minuto"},relativeTime:{future:{one:"em {0} min.",other:"em {0} min."},past:{one:"há {0} min.",other:"há {0} min."}}},second:{displayName:"segundo",relative:{0:"agora"},relativeTime:{future:{one:"em {0} segundo",other:"em {0} segundos"},past:{one:"há {0} segundo",other:"há {0} segundos"}}},"second-short":{displayName:"seg.",relative:{0:"agora"},relativeTime:{future:{one:"em {0} seg.",other:"em {0} seg."},past:{one:"há {0} seg.",other:"há {0} seg."}}}}},{locale:"pt-AO",parentLocale:"pt-PT"},{locale:"pt-PT",parentLocale:"pt",pluralRuleFunction:function(e,t){var o=!String(e).split(".")[1];return t?"other":1==e&&o?"one":"other"},fields:{year:{displayName:"ano",relative:{0:"este ano",1:"próximo ano","-1":"ano passado"},relativeTime:{future:{one:"dentro de {0} ano",other:"dentro de {0} anos"},past:{one:"há {0} ano",other:"há {0} anos"}}},"year-short":{displayName:"ano",relative:{0:"este ano",1:"próximo ano","-1":"ano passado"},relativeTime:{future:{one:"dentro de {0} ano",other:"dentro de {0} anos"},past:{one:"há {0} ano",other:"há {0} anos"}}},month:{displayName:"mês",relative:{0:"este mês",1:"próximo mês","-1":"mês passado"},relativeTime:{future:{one:"dentro de {0} mês",other:"dentro de {0} meses"},past:{one:"há {0} mês",other:"há {0} meses"}}},"month-short":{displayName:"mês",relative:{0:"este mês",1:"próximo mês","-1":"mês passado"},relativeTime:{future:{one:"dentro de {0} mês",other:"dentro de {0} meses"},past:{one:"há {0} mês",other:"há {0} meses"}}},day:{displayName:"dia",relative:{0:"hoje",1:"amanhã",2:"depois de amanhã","-2":"anteontem","-1":"ontem"},relativeTime:{future:{one:"dentro de {0} dia",other:"dentro de {0} dias"},past:{one:"há {0} dia",other:"há {0} dias"}}},"day-short":{displayName:"dia",relative:{0:"hoje",1:"amanhã",2:"depois de amanhã","-2":"anteontem","-1":"ontem"},relativeTime:{future:{one:"dentro de {0} dia",other:"dentro de {0} dias"},past:{one:"há {0} dia",other:"há {0} dias"}}},hour:{displayName:"hora",relative:{0:"esta hora"},relativeTime:{future:{one:"dentro de {0} hora",other:"dentro de {0} horas"},past:{one:"há {0} hora",other:"há {0} horas"}}},"hour-short":{displayName:"h",relative:{0:"esta hora"},relativeTime:{future:{one:"dentro de {0} h",other:"dentro de {0} h"},past:{one:"há {0} h",other:"há {0} h"}}},minute:{displayName:"minuto",relative:{0:"este minuto"},relativeTime:{future:{one:"dentro de {0} minuto",other:"dentro de {0} minutos"},past:{one:"há {0} minuto",other:"há {0} minutos"}}},"minute-short":{displayName:"min",relative:{0:"este minuto"},relativeTime:{future:{one:"dentro de {0} min",other:"dentro de {0} min"},past:{one:"há {0} min",other:"há {0} min"}}},second:{displayName:"segundo",relative:{0:"agora"},relativeTime:{future:{one:"dentro de {0} segundo",other:"dentro de {0} segundos"},past:{one:"há {0} segundo",other:"há {0} segundos"}}},"second-short":{displayName:"s",relative:{0:"agora"},relativeTime:{future:{one:"dentro de {0} s",other:"dentro de {0} s"},past:{one:"há {0} s",other:"há {0} s"}}}}},{locale:"pt-CH",parentLocale:"pt-PT"},{locale:"pt-CV",parentLocale:"pt-PT"},{locale:"pt-GQ",parentLocale:"pt-PT"},{locale:"pt-GW",parentLocale:"pt-PT"},{locale:"pt-LU",parentLocale:"pt-PT"},{locale:"pt-MO",parentLocale:"pt-PT"},{locale:"pt-MZ",parentLocale:"pt-PT"},{locale:"pt-ST",parentLocale:"pt-PT"},{locale:"pt-TL",parentLocale:"pt-PT"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/qu.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/qu.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,a){ true?module.exports=a():undefined}(this,function(){"use strict";return[{locale:"qu",pluralRuleFunction:function(e,a){return"other"},fields:{year:{displayName:"Year",relative:{0:"kunan wata",1:"hamuq wata","-1":"qayna wata"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},"year-short":{displayName:"Year",relative:{0:"kunan wata",1:"hamuq wata","-1":"qayna wata"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},month:{displayName:"Month",relative:{0:"kunan killa",1:"hamuq killa","-1":"qayna killa"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},"month-short":{displayName:"Month",relative:{0:"kunan killa",1:"hamuq killa","-1":"qayna killa"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},day:{displayName:"Day",relative:{0:"kunan punchaw",1:"paqarin","-1":"qayna punchaw"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},"day-short":{displayName:"Day",relative:{0:"kunan punchaw",1:"paqarin","-1":"qayna punchaw"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},hour:{displayName:"Hour",relative:{0:"kay hora"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},"hour-short":{displayName:"Hour",relative:{0:"kay hora"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},minute:{displayName:"Minute",relative:{0:"kay minuto"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},"minute-short":{displayName:"Minute",relative:{0:"kay minuto"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},second:{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}},"second-short":{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}}}},{locale:"qu-BO",parentLocale:"qu"},{locale:"qu-EC",parentLocale:"qu"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ro.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/ro.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"ro",pluralRuleFunction:function(e,t){var a=String(e).split("."),i=!a[1],u=Number(a[0])==e&&a[0].slice(-2);return t?1==e?"one":"other":1==e&&i?"one":!i||0==e||1!=e&&u>=1&&u<=19?"few":"other"},fields:{year:{displayName:"an",relative:{0:"anul acesta",1:"anul viitor","-1":"anul trecut"},relativeTime:{future:{one:"peste {0} an",few:"peste {0} ani",other:"peste {0} de ani"},past:{one:"acum {0} an",few:"acum {0} ani",other:"acum {0} de ani"}}},"year-short":{displayName:"an",relative:{0:"anul acesta",1:"anul viitor","-1":"anul trecut"},relativeTime:{future:{one:"peste {0} an",few:"peste {0} ani",other:"peste {0} de ani"},past:{one:"acum {0} an",few:"acum {0} ani",other:"acum {0} de ani"}}},month:{displayName:"lună",relative:{0:"luna aceasta",1:"luna viitoare","-1":"luna trecută"},relativeTime:{future:{one:"peste {0} lună",few:"peste {0} luni",other:"peste {0} de luni"},past:{one:"acum {0} lună",few:"acum {0} luni",other:"acum {0} de luni"}}},"month-short":{displayName:"lună",relative:{0:"luna aceasta",1:"luna viitoare","-1":"luna trecută"},relativeTime:{future:{one:"peste {0} lună",few:"peste {0} luni",other:"peste {0} luni"},past:{one:"acum {0} lună",few:"acum {0} luni",other:"acum {0} luni"}}},day:{displayName:"zi",relative:{0:"azi",1:"mâine",2:"poimâine","-2":"alaltăieri","-1":"ieri"},relativeTime:{future:{one:"peste {0} zi",few:"peste {0} zile",other:"peste {0} de zile"},past:{one:"acum {0} zi",few:"acum {0} zile",other:"acum {0} de zile"}}},"day-short":{displayName:"zi",relative:{0:"azi",1:"mâine",2:"poimâine","-2":"alaltăieri","-1":"ieri"},relativeTime:{future:{one:"peste {0} zi",few:"peste {0} zile",other:"peste {0} de zile"},past:{one:"acum {0} zi",few:"acum {0} zile",other:"acum {0} de zile"}}},hour:{displayName:"oră",relative:{0:"ora aceasta"},relativeTime:{future:{one:"peste {0} oră",few:"peste {0} ore",other:"peste {0} de ore"},past:{one:"acum {0} oră",few:"acum {0} ore",other:"acum {0} de ore"}}},"hour-short":{displayName:"h",relative:{0:"ora aceasta"},relativeTime:{future:{one:"peste {0} h",few:"peste {0} h",other:"peste {0} h"},past:{one:"acum {0} h",few:"acum {0} h",other:"acum {0} h"}}},minute:{displayName:"minut",relative:{0:"minutul acesta"},relativeTime:{future:{one:"peste {0} minut",few:"peste {0} minute",other:"peste {0} de minute"},past:{one:"acum {0} minut",few:"acum {0} minute",other:"acum {0} de minute"}}},"minute-short":{displayName:"min.",relative:{0:"minutul acesta"},relativeTime:{future:{one:"peste {0} min.",few:"peste {0} min.",other:"peste {0} min."},past:{one:"acum {0} min.",few:"acum {0} min.",other:"acum {0} min."}}},second:{displayName:"secundă",relative:{0:"acum"},relativeTime:{future:{one:"peste {0} secundă",few:"peste {0} secunde",other:"peste {0} de secunde"},past:{one:"acum {0} secundă",few:"acum {0} secunde",other:"acum {0} de secunde"}}},"second-short":{displayName:"sec.",relative:{0:"acum"},relativeTime:{future:{one:"peste {0} sec.",few:"peste {0} sec.",other:"peste {0} sec."},past:{one:"acum {0} sec.",few:"acum {0} sec.",other:"acum {0} sec."}}}}},{locale:"ro-MD",parentLocale:"ro"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/ru.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/ru.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,a){ true?module.exports=a():undefined}(this,function(){"use strict";return[{locale:"ru",pluralRuleFunction:function(e,a){var t=String(e).split("."),r=t[0],o=!t[1],n=r.slice(-1),l=r.slice(-2);return a?"other":o&&1==n&&11!=l?"one":o&&n>=2&&n<=4&&(l<12||l>14)?"few":o&&0==n||o&&n>=5&&n<=9||o&&l>=11&&l<=14?"many":"other"},fields:{year:{displayName:"год",relative:{0:"в этом году",1:"в следующем году","-1":"в прошлом году"},relativeTime:{future:{one:"через {0} год",few:"через {0} года",many:"через {0} лет",other:"через {0} года"},past:{one:"{0} год назад",few:"{0} года назад",many:"{0} лет назад",other:"{0} года назад"}}},"year-short":{displayName:"г.",relative:{0:"в этом г.",1:"в след. г.","-1":"в прошлом г."},relativeTime:{future:{one:"через {0} г.",few:"через {0} г.",many:"через {0} л.",other:"через {0} г."},past:{one:"{0} г. назад",few:"{0} г. назад",many:"{0} л. назад",other:"{0} г. назад"}}},month:{displayName:"месяц",relative:{0:"в этом месяце",1:"в следующем месяце","-1":"в прошлом месяце"},relativeTime:{future:{one:"через {0} месяц",few:"через {0} месяца",many:"через {0} месяцев",other:"через {0} месяца"},past:{one:"{0} месяц назад",few:"{0} месяца назад",many:"{0} месяцев назад",other:"{0} месяца назад"}}},"month-short":{displayName:"мес.",relative:{0:"в этом мес.",1:"в следующем мес.","-1":"в прошлом мес."},relativeTime:{future:{one:"через {0} мес.",few:"через {0} мес.",many:"через {0} мес.",other:"через {0} мес."},past:{one:"{0} мес. назад",few:"{0} мес. назад",many:"{0} мес. назад",other:"{0} мес. назад"}}},day:{displayName:"день",relative:{0:"сегодня",1:"завтра",2:"послезавтра","-2":"позавчера","-1":"вчера"},relativeTime:{future:{one:"через {0} день",few:"через {0} дня",many:"через {0} дней",other:"через {0} дня"},past:{one:"{0} день назад",few:"{0} дня назад",many:"{0} дней назад",other:"{0} дня назад"}}},"day-short":{displayName:"дн.",relative:{0:"сегодня",1:"завтра",2:"послезавтра","-2":"позавчера","-1":"вчера"},relativeTime:{future:{one:"через {0} дн.",few:"через {0} дн.",many:"через {0} дн.",other:"через {0} дн."},past:{one:"{0} дн. назад",few:"{0} дн. назад",many:"{0} дн. назад",other:"{0} дн. назад"}}},hour:{displayName:"час",relative:{0:"в этот час"},relativeTime:{future:{one:"через {0} час",few:"через {0} часа",many:"через {0} часов",other:"через {0} часа"},past:{one:"{0} час назад",few:"{0} часа назад",many:"{0} часов назад",other:"{0} часа назад"}}},"hour-short":{displayName:"ч",relative:{0:"в этот час"},relativeTime:{future:{one:"через {0} ч.",few:"через {0} ч.",many:"через {0} ч.",other:"через {0} ч."},past:{one:"{0} ч. назад",few:"{0} ч. назад",many:"{0} ч. назад",other:"{0} ч. назад"}}},minute:{displayName:"минута",relative:{0:"в эту минуту"},relativeTime:{future:{one:"через {0} минуту",few:"через {0} минуты",many:"через {0} минут",other:"через {0} минуты"},past:{one:"{0} минуту назад",few:"{0} минуты назад",many:"{0} минут назад",other:"{0} минуты назад"}}},"minute-short":{displayName:"мин.",relative:{0:"в эту минуту"},relativeTime:{future:{one:"через {0} мин.",few:"через {0} мин.",many:"через {0} мин.",other:"через {0} мин."},past:{one:"{0} мин. назад",few:"{0} мин. назад",many:"{0} мин. назад",other:"{0} мин. назад"}}},second:{displayName:"секунда",relative:{0:"сейчас"},relativeTime:{future:{one:"через {0} секунду",few:"через {0} секунды",many:"через {0} секунд",other:"через {0} секунды"},past:{one:"{0} секунду назад",few:"{0} секунды назад",many:"{0} секунд назад",other:"{0} секунды назад"}}},"second-short":{displayName:"сек.",relative:{0:"сейчас"},relativeTime:{future:{one:"через {0} сек.",few:"через {0} сек.",many:"через {0} сек.",other:"через {0} сек."},past:{one:"{0} сек. назад",few:"{0} сек. назад",many:"{0} сек. назад",other:"{0} сек. назад"}}}}},{locale:"ru-BY",parentLocale:"ru"},{locale:"ru-KG",parentLocale:"ru"},{locale:"ru-KZ",parentLocale:"ru"},{locale:"ru-MD",parentLocale:"ru"},{locale:"ru-UA",parentLocale:"ru"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/sk.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/sk.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,o){ true?module.exports=o():undefined}(this,function(){"use strict";return[{locale:"sk",pluralRuleFunction:function(e,o){var r=String(e).split("."),a=r[0],t=!r[1];return o?"other":1==e&&t?"one":a>=2&&a<=4&&t?"few":t?"other":"many"},fields:{year:{displayName:"rok",relative:{0:"tento rok",1:"budúci rok","-1":"minulý rok"},relativeTime:{future:{one:"o {0} rok",few:"o {0} roky",many:"o {0} roka",other:"o {0} rokov"},past:{one:"pred {0} rokom",few:"pred {0} rokmi",many:"pred {0} roka",other:"pred {0} rokmi"}}},"year-short":{displayName:"r.",relative:{0:"tento rok",1:"budúci rok","-1":"minulý rok"},relativeTime:{future:{one:"o {0} r.",few:"o {0} r.",many:"o {0} r.",other:"o {0} r."},past:{one:"pred {0} r.",few:"pred {0} r.",many:"pred {0} r.",other:"pred {0} r."}}},month:{displayName:"mesiac",relative:{0:"tento mesiac",1:"budúci mesiac","-1":"minulý mesiac"},relativeTime:{future:{one:"o {0} mesiac",few:"o {0} mesiace",many:"o {0} mesiaca",other:"o {0} mesiacov"},past:{one:"pred {0} mesiacom",few:"pred {0} mesiacmi",many:"pred {0} mesiaca",other:"pred {0} mesiacmi"}}},"month-short":{displayName:"mes.",relative:{0:"tento mes.",1:"budúci mes.","-1":"minulý mes."},relativeTime:{future:{one:"o {0} mes.",few:"o {0} mes.",many:"o {0} mes.",other:"o {0} mes."},past:{one:"pred {0} mes.",few:"pred {0} mes.",many:"pred {0} mes.",other:"pred {0} mes."}}},day:{displayName:"deň",relative:{0:"dnes",1:"zajtra",2:"pozajtra","-2":"predvčerom","-1":"včera"},relativeTime:{future:{one:"o {0} deň",few:"o {0} dni",many:"o {0} dňa",other:"o {0} dní"},past:{one:"pred {0} dňom",few:"pred {0} dňami",many:"pred {0} dňa",other:"pred {0} dňami"}}},"day-short":{displayName:"d.",relative:{0:"dnes",1:"zajtra",2:"pozajtra","-2":"predvčerom","-1":"včera"},relativeTime:{future:{one:"o {0} d.",few:"o {0} d.",many:"o {0} d.",other:"o {0} d."},past:{one:"pred {0} d.",few:"pred {0} d.",many:"pred {0} d.",other:"pred {0} d."}}},hour:{displayName:"hodina",relative:{0:"v tejto hodine"},relativeTime:{future:{one:"o {0} hodinu",few:"o {0} hodiny",many:"o {0} hodiny",other:"o {0} hodín"},past:{one:"pred {0} hodinou",few:"pred {0} hodinami",many:"pred {0} hodinou",other:"pred {0} hodinami"}}},"hour-short":{displayName:"h",relative:{0:"v tejto hodine"},relativeTime:{future:{one:"o {0} h",few:"o {0} h",many:"o {0} h",other:"o {0} h"},past:{one:"pred {0} h",few:"pred {0} h",many:"pred {0} h",other:"pred {0} h"}}},minute:{displayName:"minúta",relative:{0:"v tejto minúte"},relativeTime:{future:{one:"o {0} minútu",few:"o {0} minúty",many:"o {0} minúty",other:"o {0} minút"},past:{one:"pred {0} minútou",few:"pred {0} minútami",many:"pred {0} minúty",other:"pred {0} minútami"}}},"minute-short":{displayName:"min",relative:{0:"v tejto minúte"},relativeTime:{future:{one:"o {0} min",few:"o {0} min",many:"o {0} min",other:"o {0} min"},past:{one:"pred {0} min",few:"pred {0} min",many:"pred {0} min",other:"pred {0} min"}}},second:{displayName:"sekunda",relative:{0:"teraz"},relativeTime:{future:{one:"o {0} sekundu",few:"o {0} sekundy",many:"o {0} sekundy",other:"o {0} sekúnd"},past:{one:"pred {0} sekundou",few:"pred {0} sekundami",many:"pred {0} sekundy",other:"pred {0} sekundami"}}},"second-short":{displayName:"s",relative:{0:"teraz"},relativeTime:{future:{one:"o {0} s",few:"o {0} s",many:"o {0} s",other:"o {0} s"},past:{one:"pred {0} s",few:"pred {0} s",many:"pred {0} s",other:"pred {0} s"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/sl.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/sl.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"sl",pluralRuleFunction:function(e,t){var r=String(e).split("."),o=r[0],a=!r[1],i=o.slice(-2);return t?"other":a&&1==i?"one":a&&2==i?"two":a&&(3==i||4==i)||!a?"few":"other"},fields:{year:{displayName:"leto",relative:{0:"letos",1:"naslednje leto","-1":"lani"},relativeTime:{future:{one:"čez {0} leto",two:"čez {0} leti",few:"čez {0} leta",other:"čez {0} let"},past:{one:"pred {0} letom",two:"pred {0} letoma",few:"pred {0} leti",other:"pred {0} leti"}}},"year-short":{displayName:"leto",relative:{0:"letos",1:"naslednje leto","-1":"lani"},relativeTime:{future:{one:"čez {0} leto",two:"čez {0} leti",few:"čez {0} leta",other:"čez {0} let"},past:{one:"pred {0} letom",two:"pred {0} letoma",few:"pred {0} leti",other:"pred {0} leti"}}},month:{displayName:"mesec",relative:{0:"ta mesec",1:"naslednji mesec","-1":"prejšnji mesec"},relativeTime:{future:{one:"čez {0} mesec",two:"čez {0} meseca",few:"čez {0} mesece",other:"čez {0} mesecev"},past:{one:"pred {0} mesecem",two:"pred {0} mesecema",few:"pred {0} meseci",other:"pred {0} meseci"}}},"month-short":{displayName:"mes.",relative:{0:"ta mesec",1:"naslednji mesec","-1":"prejšnji mesec"},relativeTime:{future:{one:"čez {0} mes.",two:"čez {0} mes.",few:"čez {0} mes.",other:"čez {0} mes."},past:{one:"pred {0} mes.",two:"pred {0} mes.",few:"pred {0} mes.",other:"pred {0} mes."}}},day:{displayName:"dan",relative:{0:"danes",1:"jutri",2:"pojutrišnjem","-2":"predvčerajšnjim","-1":"včeraj"},relativeTime:{future:{one:"čez {0} dan",two:"čez {0} dneva",few:"čez {0} dni",other:"čez {0} dni"},past:{one:"pred {0} dnevom",two:"pred {0} dnevoma",few:"pred {0} dnevi",other:"pred {0} dnevi"}}},"day-short":{displayName:"dan",relative:{0:"danes",1:"jutri",2:"pojutrišnjem","-2":"predvčerajšnjim","-1":"včeraj"},relativeTime:{future:{one:"čez {0} dan",two:"čez {0} dneva",few:"čez {0} dni",other:"čez {0} dni"},past:{one:"pred {0} dnevom",two:"pred {0} dnevoma",few:"pred {0} dnevi",other:"pred {0} dnevi"}}},hour:{displayName:"ura",relative:{0:"v tej uri"},relativeTime:{future:{one:"čez {0} uro",two:"čez {0} uri",few:"čez {0} ure",other:"čez {0} ur"},past:{one:"pred {0} uro",two:"pred {0} urama",few:"pred {0} urami",other:"pred {0} urami"}}},"hour-short":{displayName:"ura",relative:{0:"v tej uri"},relativeTime:{future:{one:"čez {0} uro",two:"čez {0} uri",few:"čez {0} ure",other:"čez {0} ur"},past:{one:"pred {0} uro",two:"pred {0} urama",few:"pred {0} urami",other:"pred {0} urami"}}},minute:{displayName:"minuta",relative:{0:"to minuto"},relativeTime:{future:{one:"čez {0} minuto",two:"čez {0} minuti",few:"čez {0} minute",other:"čez {0} minut"},past:{one:"pred {0} minuto",two:"pred {0} minutama",few:"pred {0} minutami",other:"pred {0} minutami"}}},"minute-short":{displayName:"min.",relative:{0:"to minuto"},relativeTime:{future:{one:"čez {0} min.",two:"čez {0} min.",few:"čez {0} min.",other:"čez {0} min."},past:{one:"pred {0} min.",two:"pred {0} min.",few:"pred {0} min.",other:"pred {0} min."}}},second:{displayName:"sekunda",relative:{0:"zdaj"},relativeTime:{future:{one:"čez {0} sekundo",two:"čez {0} sekundi",few:"čez {0} sekunde",other:"čez {0} sekund"},past:{one:"pred {0} sekundo",two:"pred {0} sekundama",few:"pred {0} sekundami",other:"pred {0} sekundami"}}},"second-short":{displayName:"sek.",relative:{0:"zdaj"},relativeTime:{future:{one:"čez {0} s",two:"čez {0} s",few:"čez {0} s",other:"čez {0} s"},past:{one:"pred {0} s",two:"pred {0} s",few:"pred {0} s",other:"pred {0} s"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/sr.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/sr.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,a){ true?module.exports=a():undefined}(this,function(){"use strict";return[{locale:"sr",pluralRuleFunction:function(e,a){var r=String(e).split("."),t=r[0],o=r[1]||"",i=!r[1],s=t.slice(-1),n=t.slice(-2),l=o.slice(-1),p=o.slice(-2);return a?"other":i&&1==s&&11!=n||1==l&&11!=p?"one":i&&s>=2&&s<=4&&(n<12||n>14)||l>=2&&l<=4&&(p<12||p>14)?"few":"other"},fields:{year:{displayName:"година",relative:{0:"ове године",1:"следеће године","-1":"прошле године"},relativeTime:{future:{one:"за {0} годину",few:"за {0} године",other:"за {0} година"},past:{one:"пре {0} године",few:"пре {0} године",other:"пре {0} година"}}},"year-short":{displayName:"год.",relative:{0:"ове год.",1:"следеће год.","-1":"прошле год."},relativeTime:{future:{one:"за {0} год.",few:"за {0} год.",other:"за {0} год."},past:{one:"пре {0} год.",few:"пре {0} год.",other:"пре {0} год."}}},month:{displayName:"месец",relative:{0:"овог месеца",1:"следећег месеца","-1":"прошлог месеца"},relativeTime:{future:{one:"за {0} месец",few:"за {0} месеца",other:"за {0} месеци"},past:{one:"пре {0} месеца",few:"пре {0} месеца",other:"пре {0} месеци"}}},"month-short":{displayName:"мес.",relative:{0:"овог мес.",1:"следећег мес.","-1":"прошлог мес."},relativeTime:{future:{one:"за {0} мес.",few:"за {0} мес.",other:"за {0} мес."},past:{one:"пре {0} мес.",few:"пре {0} мес.",other:"пре {0} мес."}}},day:{displayName:"дан",relative:{0:"данас",1:"сутра",2:"прекосутра","-2":"прекјуче","-1":"јуче"},relativeTime:{future:{one:"за {0} дан",few:"за {0} дана",other:"за {0} дана"},past:{one:"пре {0} дана",few:"пре {0} дана",other:"пре {0} дана"}}},"day-short":{displayName:"д.",relative:{0:"данас",1:"сутра",2:"прекосутра","-2":"прекјуче","-1":"јуче"},relativeTime:{future:{one:"за {0} д.",few:"за {0} д.",other:"за {0} д."},past:{one:"пре {0} д.",few:"пре {0} д.",other:"пре {0} д."}}},hour:{displayName:"сат",relative:{0:"овог сата"},relativeTime:{future:{one:"за {0} сат",few:"за {0} сата",other:"за {0} сати"},past:{one:"пре {0} сата",few:"пре {0} сата",other:"пре {0} сати"}}},"hour-short":{displayName:"ч.",relative:{0:"овог сата"},relativeTime:{future:{one:"за {0} ч.",few:"за {0} ч.",other:"за {0} ч."},past:{one:"пре {0} ч.",few:"пре {0} ч.",other:"пре {0} ч."}}},minute:{displayName:"минут",relative:{0:"овог минута"},relativeTime:{future:{one:"за {0} минут",few:"за {0} минута",other:"за {0} минута"},past:{one:"пре {0} минута",few:"пре {0} минута",other:"пре {0} минута"}}},"minute-short":{displayName:"мин.",relative:{0:"овог минута"},relativeTime:{future:{one:"за {0} мин.",few:"за {0} мин.",other:"за {0} мин."},past:{one:"пре {0} мин.",few:"пре {0} мин.",other:"пре {0} мин."}}},second:{displayName:"секунд",relative:{0:"сада"},relativeTime:{future:{one:"за {0} секунду",few:"за {0} секунде",other:"за {0} секунди"},past:{one:"пре {0} секунде",few:"пре {0} секунде",other:"пре {0} секунди"}}},"second-short":{displayName:"сек.",relative:{0:"сада"},relativeTime:{future:{one:"за {0} сек.",few:"за {0} сек.",other:"за {0} сек."},past:{one:"пре {0} сек.",few:"пре {0} сек.",other:"пре {0} сек."}}}}},{locale:"sr-Cyrl",parentLocale:"sr"},{locale:"sr-Cyrl-BA",parentLocale:"sr-Cyrl"},{locale:"sr-Cyrl-ME",parentLocale:"sr-Cyrl"},{locale:"sr-Cyrl-XK",parentLocale:"sr-Cyrl"},{locale:"sr-Latn",pluralRuleFunction:function(e,a){return"other"},fields:{year:{displayName:"godina",relative:{0:"ove godine",1:"sledeće godine","-1":"prošle godine"},relativeTime:{future:{one:"za {0} godinu",few:"za {0} godine",other:"za {0} godina"},past:{one:"pre {0} godine",few:"pre {0} godine",other:"pre {0} godina"}}},"year-short":{displayName:"god.",relative:{0:"ove god.",1:"sledeće god.","-1":"prošle god."},relativeTime:{future:{one:"za {0} god.",few:"za {0} god.",other:"za {0} god."},past:{one:"pre {0} god.",few:"pre {0} god.",other:"pre {0} god."}}},month:{displayName:"mesec",relative:{0:"ovog meseca",1:"sledećeg meseca","-1":"prošlog meseca"},relativeTime:{future:{one:"za {0} mesec",few:"za {0} meseca",other:"za {0} meseci"},past:{one:"pre {0} meseca",few:"pre {0} meseca",other:"pre {0} meseci"}}},"month-short":{displayName:"mes.",relative:{0:"ovog mes.",1:"sledećeg mes.","-1":"prošlog mes."},relativeTime:{future:{one:"za {0} mes.",few:"za {0} mes.",other:"za {0} mes."},past:{one:"pre {0} mes.",few:"pre {0} mes.",other:"pre {0} mes."}}},day:{displayName:"dan",relative:{0:"danas",1:"sutra",2:"prekosutra","-2":"prekjuče","-1":"juče"},relativeTime:{future:{one:"za {0} dan",few:"za {0} dana",other:"za {0} dana"},past:{one:"pre {0} dana",few:"pre {0} dana",other:"pre {0} dana"}}},"day-short":{displayName:"d.",relative:{0:"danas",1:"sutra",2:"prekosutra","-2":"prekjuče","-1":"juče"},relativeTime:{future:{one:"za {0} d.",few:"za {0} d.",other:"za {0} d."},past:{one:"pre {0} d.",few:"pre {0} d.",other:"pre {0} d."}}},hour:{displayName:"sat",relative:{0:"ovog sata"},relativeTime:{future:{one:"za {0} sat",few:"za {0} sata",other:"za {0} sati"},past:{one:"pre {0} sata",few:"pre {0} sata",other:"pre {0} sati"}}},"hour-short":{displayName:"č.",relative:{0:"ovog sata"},relativeTime:{future:{one:"za {0} č.",few:"za {0} č.",other:"za {0} č."},past:{one:"pre {0} č.",few:"pre {0} č.",other:"pre {0} č."}}},minute:{displayName:"minut",relative:{0:"ovog minuta"},relativeTime:{future:{one:"za {0} minut",few:"za {0} minuta",other:"za {0} minuta"},past:{one:"pre {0} minuta",few:"pre {0} minuta",other:"pre {0} minuta"}}},"minute-short":{displayName:"min.",relative:{0:"ovog minuta"},relativeTime:{future:{one:"za {0} min.",few:"za {0} min.",other:"za {0} min."},past:{one:"pre {0} min.",few:"pre {0} min.",other:"pre {0} min."}}},second:{displayName:"sekund",relative:{0:"sada"},relativeTime:{future:{one:"za {0} sekundu",few:"za {0} sekunde",other:"za {0} sekundi"},past:{one:"pre {0} sekunde",few:"pre {0} sekunde",other:"pre {0} sekundi"}}},"second-short":{displayName:"sek.",relative:{0:"sada"},relativeTime:{future:{one:"za {0} sek.",few:"za {0} sek.",other:"za {0} sek."},past:{one:"pre {0} sek.",few:"pre {0} sek.",other:"pre {0} sek."}}}}},{locale:"sr-Latn-BA",parentLocale:"sr-Latn"},{locale:"sr-Latn-ME",parentLocale:"sr-Latn"},{locale:"sr-Latn-XK",parentLocale:"sr-Latn"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/sv.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/sv.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,r){ true?module.exports=r():undefined}(this,function(){"use strict";return[{locale:"sv",pluralRuleFunction:function(e,r){var t=String(e).split("."),a=!t[1],n=Number(t[0])==e,o=n&&t[0].slice(-1),m=n&&t[0].slice(-2);return r?1!=o&&2!=o||11==m||12==m?"other":"one":1==e&&a?"one":"other"},fields:{year:{displayName:"år",relative:{0:"i år",1:"nästa år","-1":"i fjol"},relativeTime:{future:{one:"om {0} år",other:"om {0} år"},past:{one:"för {0} år sedan",other:"för {0} år sedan"}}},"year-short":{displayName:"år",relative:{0:"i år",1:"nästa år","-1":"i fjol"},relativeTime:{future:{one:"om {0} år",other:"om {0} år"},past:{one:"för {0} år sen",other:"för {0} år sen"}}},month:{displayName:"månad",relative:{0:"denna månad",1:"nästa månad","-1":"förra månaden"},relativeTime:{future:{one:"om {0} månad",other:"om {0} månader"},past:{one:"för {0} månad sedan",other:"för {0} månader sedan"}}},"month-short":{displayName:"m",relative:{0:"denna mån.",1:"nästa mån.","-1":"förra mån."},relativeTime:{future:{one:"om {0} mån.",other:"om {0} mån."},past:{one:"för {0} mån. sen",other:"för {0} mån. sen"}}},day:{displayName:"dag",relative:{0:"i dag",1:"i morgon",2:"i övermorgon","-2":"i förrgår","-1":"i går"},relativeTime:{future:{one:"om {0} dag",other:"om {0} dagar"},past:{one:"för {0} dag sedan",other:"för {0} dagar sedan"}}},"day-short":{displayName:"dag",relative:{0:"i dag",1:"i morgon",2:"i övermorgon","-2":"i förrgår","-1":"i går"},relativeTime:{future:{one:"om {0} d",other:"om {0} d"},past:{one:"för {0} d sedan",other:"för {0} d sedan"}}},hour:{displayName:"timme",relative:{0:"denna timme"},relativeTime:{future:{one:"om {0} timme",other:"om {0} timmar"},past:{one:"för {0} timme sedan",other:"för {0} timmar sedan"}}},"hour-short":{displayName:"tim",relative:{0:"denna timme"},relativeTime:{future:{one:"om {0} tim",other:"om {0} tim"},past:{one:"för {0} tim sedan",other:"för {0} tim sedan"}}},minute:{displayName:"minut",relative:{0:"denna minut"},relativeTime:{future:{one:"om {0} minut",other:"om {0} minuter"},past:{one:"för {0} minut sedan",other:"för {0} minuter sedan"}}},"minute-short":{displayName:"min",relative:{0:"denna minut"},relativeTime:{future:{one:"om {0} min",other:"om {0} min"},past:{one:"för {0} min sen",other:"för {0} min sen"}}},second:{displayName:"sekund",relative:{0:"nu"},relativeTime:{future:{one:"om {0} sekund",other:"om {0} sekunder"},past:{one:"för {0} sekund sedan",other:"för {0} sekunder sedan"}}},"second-short":{displayName:"sek",relative:{0:"nu"},relativeTime:{future:{one:"om {0} sek",other:"om {0} sek"},past:{one:"för {0} s sen",other:"för {0} s sen"}}}}},{locale:"sv-AX",parentLocale:"sv"},{locale:"sv-FI",parentLocale:"sv"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/sw.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/sw.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(a,e){ true?module.exports=e():undefined}(this,function(){"use strict";return[{locale:"sw",pluralRuleFunction:function(a,e){var i=!String(a).split(".")[1];return e?"other":1==a&&i?"one":"other"},fields:{year:{displayName:"mwaka",relative:{0:"mwaka huu",1:"mwaka ujao","-1":"mwaka uliopita"},relativeTime:{future:{one:"baada ya mwaka {0}",other:"baada ya miaka {0}"},past:{one:"mwaka {0} uliopita",other:"miaka {0} iliyopita"}}},"year-short":{displayName:"mwaka",relative:{0:"mwaka huu",1:"mwaka ujao","-1":"mwaka uliopita"},relativeTime:{future:{one:"baada ya mwaka {0}",other:"baada ya miaka {0}"},past:{one:"mwaka {0} uliopita",other:"miaka {0} iliyopita"}}},month:{displayName:"mwezi",relative:{0:"mwezi huu",1:"mwezi ujao","-1":"mwezi uliopita"},relativeTime:{future:{one:"baada ya mwezi {0}",other:"baada ya miezi {0}"},past:{one:"mwezi {0} uliopita",other:"miezi {0} iliyopita"}}},"month-short":{displayName:"mwezi",relative:{0:"mwezi huu",1:"mwezi ujao","-1":"mwezi uliopita"},relativeTime:{future:{one:"baada ya mwezi {0}",other:"baada ya miezi {0}"},past:{one:"mwezi {0} uliopita",other:"miezi {0} iliyopita"}}},day:{displayName:"siku",relative:{0:"leo",1:"kesho",2:"kesho kutwa","-2":"juzi","-1":"jana"},relativeTime:{future:{one:"baada ya siku {0}",other:"baada ya siku {0}"},past:{one:"siku {0} iliyopita",other:"siku {0} zilizopita"}}},"day-short":{displayName:"siku",relative:{0:"leo",1:"kesho",2:"kesho kutwa","-2":"juzi","-1":"jana"},relativeTime:{future:{one:"baada ya siku {0}",other:"baada ya siku {0}"},past:{one:"siku {0} iliyopita",other:"siku {0} zilizopita"}}},hour:{displayName:"saa",relative:{0:"saa hii"},relativeTime:{future:{one:"baada ya saa {0}",other:"baada ya saa {0}"},past:{one:"saa {0} iliyopita",other:"saa {0} zilizopita"}}},"hour-short":{displayName:"saa",relative:{0:"saa hii"},relativeTime:{future:{one:"baada ya saa {0}",other:"baada ya saa {0}"},past:{one:"saa {0} iliyopita",other:"saa {0} zilizopita"}}},minute:{displayName:"dakika",relative:{0:"dakika hii"},relativeTime:{future:{one:"baada ya dakika {0}",other:"baada ya dakika {0}"},past:{one:"dakika {0} iliyopita",other:"dakika {0} zilizopita"}}},"minute-short":{displayName:"dak",relative:{0:"dakika hii"},relativeTime:{future:{one:"baada ya dakika {0}",other:"baada ya dakika {0}"},past:{one:"dakika {0} iliyopita",other:"dakika {0} zilizopita"}}},second:{displayName:"sekunde",relative:{0:"sasa hivi"},relativeTime:{future:{one:"baada ya sekunde {0}",other:"baada ya sekunde {0}"},past:{one:"Sekunde {0} iliyopita",other:"Sekunde {0} zilizopita"}}},"second-short":{displayName:"sek",relative:{0:"sasa hivi"},relativeTime:{future:{one:"baada ya sekunde {0}",other:"baada ya sekunde {0}"},past:{one:"sekunde {0} iliyopita",other:"sekunde {0} zilizopita"}}}}},{locale:"sw-CD",parentLocale:"sw"},{locale:"sw-KE",parentLocale:"sw"},{locale:"sw-UG",parentLocale:"sw"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/th.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/th.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"th",pluralRuleFunction:function(e,t){return"other"},fields:{year:{displayName:"ปี",relative:{0:"ปีนี้",1:"ปีหน้า","-1":"ปีที่แล้ว"},relativeTime:{future:{other:"ในอีก {0} ปี"},past:{other:"{0} ปีที่แล้ว"}}},"year-short":{displayName:"ปี",relative:{0:"ปีนี้",1:"ปีหน้า","-1":"ปีที่แล้ว"},relativeTime:{future:{other:"ใน {0} ปี"},past:{other:"{0} ปีที่แล้ว"}}},month:{displayName:"เดือน",relative:{0:"เดือนนี้",1:"เดือนหน้า","-1":"เดือนที่แล้ว"},relativeTime:{future:{other:"ในอีก {0} เดือน"},past:{other:"{0} เดือนที่ผ่านมา"}}},"month-short":{displayName:"เดือน",relative:{0:"เดือนนี้",1:"เดือนหน้า","-1":"เดือนที่แล้ว"},relativeTime:{future:{other:"ใน {0} เดือน"},past:{other:"{0} เดือนที่แล้ว"}}},day:{displayName:"วัน",relative:{0:"วันนี้",1:"พรุ่งนี้",2:"มะรืนนี้","-2":"เมื่อวานซืน","-1":"เมื่อวาน"},relativeTime:{future:{other:"ในอีก {0} วัน"},past:{other:"{0} วันที่ผ่านมา"}}},"day-short":{displayName:"วัน",relative:{0:"วันนี้",1:"พรุ่งนี้",2:"มะรืนนี้","-2":"เมื่อวานซืน","-1":"เมื่อวาน"},relativeTime:{future:{other:"ใน {0} วัน"},past:{other:"{0} วันที่แล้ว"}}},hour:{displayName:"ชั่วโมง",relative:{0:"ชั่วโมงนี้"},relativeTime:{future:{other:"ในอีก {0} ชั่วโมง"},past:{other:"{0} ชั่วโมงที่ผ่านมา"}}},"hour-short":{displayName:"ชม.",relative:{0:"ชั่วโมงนี้"},relativeTime:{future:{other:"ใน {0} ชม."},past:{other:"{0} ชม. ที่แล้ว"}}},minute:{displayName:"นาที",relative:{0:"นาทีนี้"},relativeTime:{future:{other:"ในอีก {0} นาที"},past:{other:"{0} นาทีที่ผ่านมา"}}},"minute-short":{displayName:"น.",relative:{0:"นาทีนี้"},relativeTime:{future:{other:"ใน {0} นาที"},past:{other:"{0} นาทีที่แล้ว"}}},second:{displayName:"วินาที",relative:{0:"ขณะนี้"},relativeTime:{future:{other:"ในอีก {0} วินาที"},past:{other:"{0} วินาทีที่ผ่านมา"}}},"second-short":{displayName:"วิ",relative:{0:"ขณะนี้"},relativeTime:{future:{other:"ใน {0} วินาที"},past:{other:"{0} วินาทีที่แล้ว"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/tn.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/tn.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"tn",pluralRuleFunction:function(e,t){return t?"other":1==e?"one":"other"},fields:{year:{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},"year-short":{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},month:{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},"month-short":{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},day:{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},"day-short":{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},hour:{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},"hour-short":{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},minute:{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},"minute-short":{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},second:{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}},"second-short":{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/tr.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/tr.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,a){ true?module.exports=a():undefined}(this,function(){"use strict";return[{locale:"tr",pluralRuleFunction:function(e,a){return a?"other":1==e?"one":"other"},fields:{year:{displayName:"yıl",relative:{0:"bu yıl",1:"gelecek yıl","-1":"geçen yıl"},relativeTime:{future:{one:"{0} yıl sonra",other:"{0} yıl sonra"},past:{one:"{0} yıl önce",other:"{0} yıl önce"}}},"year-short":{displayName:"yıl",relative:{0:"bu yıl",1:"gelecek yıl","-1":"geçen yıl"},relativeTime:{future:{one:"{0} yıl sonra",other:"{0} yıl sonra"},past:{one:"{0} yıl önce",other:"{0} yıl önce"}}},month:{displayName:"ay",relative:{0:"bu ay",1:"gelecek ay","-1":"geçen ay"},relativeTime:{future:{one:"{0} ay sonra",other:"{0} ay sonra"},past:{one:"{0} ay önce",other:"{0} ay önce"}}},"month-short":{displayName:"ay",relative:{0:"bu ay",1:"gelecek ay","-1":"geçen ay"},relativeTime:{future:{one:"{0} ay sonra",other:"{0} ay sonra"},past:{one:"{0} ay önce",other:"{0} ay önce"}}},day:{displayName:"gün",relative:{0:"bugün",1:"yarın",2:"öbür gün","-2":"evvelsi gün","-1":"dün"},relativeTime:{future:{one:"{0} gün sonra",other:"{0} gün sonra"},past:{one:"{0} gün önce",other:"{0} gün önce"}}},"day-short":{displayName:"gün",relative:{0:"bugün",1:"yarın",2:"öbür gün","-2":"evvelsi gün","-1":"dün"},relativeTime:{future:{one:"{0} gün sonra",other:"{0} gün sonra"},past:{one:"{0} gün önce",other:"{0} gün önce"}}},hour:{displayName:"saat",relative:{0:"bu saat"},relativeTime:{future:{one:"{0} saat sonra",other:"{0} saat sonra"},past:{one:"{0} saat önce",other:"{0} saat önce"}}},"hour-short":{displayName:"sa.",relative:{0:"bu saat"},relativeTime:{future:{one:"{0} sa. sonra",other:"{0} sa. sonra"},past:{one:"{0} sa. önce",other:"{0} sa. önce"}}},minute:{displayName:"dakika",relative:{0:"bu dakika"},relativeTime:{future:{one:"{0} dakika sonra",other:"{0} dakika sonra"},past:{one:"{0} dakika önce",other:"{0} dakika önce"}}},"minute-short":{displayName:"dk.",relative:{0:"bu dakika"},relativeTime:{future:{one:"{0} dk. sonra",other:"{0} dk. sonra"},past:{one:"{0} dk. önce",other:"{0} dk. önce"}}},second:{displayName:"saniye",relative:{0:"şimdi"},relativeTime:{future:{one:"{0} saniye sonra",other:"{0} saniye sonra"},past:{one:"{0} saniye önce",other:"{0} saniye önce"}}},"second-short":{displayName:"sn.",relative:{0:"şimdi"},relativeTime:{future:{one:"{0} sn. sonra",other:"{0} sn. sonra"},past:{one:"{0} sn. önce",other:"{0} sn. önce"}}}}},{locale:"tr-CY",parentLocale:"tr"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/uk.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/uk.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"uk",pluralRuleFunction:function(e,t){var a=String(e).split("."),r=a[0],o=!a[1],n=Number(a[0])==e,i=n&&a[0].slice(-1),m=n&&a[0].slice(-2),l=r.slice(-1),f=r.slice(-2);return t?3==i&&13!=m?"few":"other":o&&1==l&&11!=f?"one":o&&l>=2&&l<=4&&(f<12||f>14)?"few":o&&0==l||o&&l>=5&&l<=9||o&&f>=11&&f<=14?"many":"other"},fields:{year:{displayName:"рік",relative:{0:"цього року",1:"наступного року","-1":"торік"},relativeTime:{future:{one:"через {0} рік",few:"через {0} роки",many:"через {0} років",other:"через {0} року"},past:{one:"{0} рік тому",few:"{0} роки тому",many:"{0} років тому",other:"{0} року тому"}}},"year-short":{displayName:"р.",relative:{0:"цього року",1:"наступного року","-1":"торік"},relativeTime:{future:{one:"через {0} р.",few:"через {0} р.",many:"через {0} р.",other:"через {0} р."},past:{one:"{0} р. тому",few:"{0} р. тому",many:"{0} р. тому",other:"{0} р. тому"}}},month:{displayName:"місяць",relative:{0:"цього місяця",1:"наступного місяця","-1":"минулого місяця"},relativeTime:{future:{one:"через {0} місяць",few:"через {0} місяці",many:"через {0} місяців",other:"через {0} місяця"},past:{one:"{0} місяць тому",few:"{0} місяці тому",many:"{0} місяців тому",other:"{0} місяця тому"}}},"month-short":{displayName:"міс.",relative:{0:"цього місяця",1:"наступного місяця","-1":"минулого місяця"},relativeTime:{future:{one:"через {0} міс.",few:"через {0} міс.",many:"через {0} міс.",other:"через {0} міс."},past:{one:"{0} міс. тому",few:"{0} міс. тому",many:"{0} міс. тому",other:"{0} міс. тому"}}},day:{displayName:"день",relative:{0:"сьогодні",1:"завтра",2:"післязавтра","-2":"позавчора","-1":"учора"},relativeTime:{future:{one:"через {0} день",few:"через {0} дні",many:"через {0} днів",other:"через {0} дня"},past:{one:"{0} день тому",few:"{0} дні тому",many:"{0} днів тому",other:"{0} дня тому"}}},"day-short":{displayName:"д.",relative:{0:"сьогодні",1:"завтра",2:"післязавтра","-2":"позавчора","-1":"учора"},relativeTime:{future:{one:"через {0} дн.",few:"через {0} дн.",many:"через {0} дн.",other:"через {0} дн."},past:{one:"{0} дн. тому",few:"{0} дн. тому",many:"{0} дн. тому",other:"{0} дн. тому"}}},hour:{displayName:"година",relative:{0:"цієї години"},relativeTime:{future:{one:"через {0} годину",few:"через {0} години",many:"через {0} годин",other:"через {0} години"},past:{one:"{0} годину тому",few:"{0} години тому",many:"{0} годин тому",other:"{0} години тому"}}},"hour-short":{displayName:"год.",relative:{0:"цієї години"},relativeTime:{future:{one:"через {0} год",few:"через {0} год",many:"через {0} год",other:"через {0} год"},past:{one:"{0} год тому",few:"{0} год тому",many:"{0} год тому",other:"{0} год тому"}}},minute:{displayName:"хвилина",relative:{0:"цієї хвилини"},relativeTime:{future:{one:"через {0} хвилину",few:"через {0} хвилини",many:"через {0} хвилин",other:"через {0} хвилини"},past:{one:"{0} хвилину тому",few:"{0} хвилини тому",many:"{0} хвилин тому",other:"{0} хвилини тому"}}},"minute-short":{displayName:"хв.",relative:{0:"цієї хвилини"},relativeTime:{future:{one:"через {0} хв",few:"через {0} хв",many:"через {0} хв",other:"через {0} хв"},past:{one:"{0} хв тому",few:"{0} хв тому",many:"{0} хв тому",other:"{0} хв тому"}}},second:{displayName:"секунда",relative:{0:"зараз"},relativeTime:{future:{one:"через {0} секунду",few:"через {0} секунди",many:"через {0} секунд",other:"через {0} секунди"},past:{one:"{0} секунду тому",few:"{0} секунди тому",many:"{0} секунд тому",other:"{0} секунди тому"}}},"second-short":{displayName:"с",relative:{0:"зараз"},relativeTime:{future:{one:"через {0} с",few:"через {0} с",many:"через {0} с",other:"через {0} с"},past:{one:"{0} с тому",few:"{0} с тому",many:"{0} с тому",other:"{0} с тому"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/uz.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/uz.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"uz",pluralRuleFunction:function(e,t){return t?"other":1==e?"one":"other"},fields:{year:{displayName:"yil",relative:{0:"shu yil",1:"keyingi yil","-1":"o‘tgan yil"},relativeTime:{future:{one:"{0} yildan keyin",other:"{0} yildan keyin"},past:{one:"{0} yil oldin",other:"{0} yil oldin"}}},"year-short":{displayName:"yil",relative:{0:"bu yil",1:"keyingi yil","-1":"oʻtgan yil"},relativeTime:{future:{one:"{0} yildan keyin",other:"{0} yildan keyin"},past:{one:"{0} yil oldin",other:"{0} yil oldin"}}},month:{displayName:"oy",relative:{0:"shu oy",1:"keyingi oy","-1":"o‘tgan oy"},relativeTime:{future:{one:"{0} oydan keyin",other:"{0} oydan keyin"},past:{one:"{0} oy oldin",other:"{0} oy oldin"}}},"month-short":{displayName:"oy",relative:{0:"shu oy",1:"keyingi oy","-1":"o‘tgan oy"},relativeTime:{future:{one:"{0} oydan keyin",other:"{0} oydan keyin"},past:{one:"{0} oy oldin",other:"{0} oy oldin"}}},day:{displayName:"kun",relative:{0:"bugun",1:"ertaga","-1":"kecha"},relativeTime:{future:{one:"{0} kundan keyin",other:"{0} kundan keyin"},past:{one:"{0} kun oldin",other:"{0} kun oldin"}}},"day-short":{displayName:"kun",relative:{0:"bugun",1:"ertaga","-1":"kecha"},relativeTime:{future:{one:"{0} kundan keyin",other:"{0} kundan keyin"},past:{one:"{0} kun oldin",other:"{0} kun oldin"}}},hour:{displayName:"soat",relative:{0:"shu soatda"},relativeTime:{future:{one:"{0} soatdan keyin",other:"{0} soatdan keyin"},past:{one:"{0} soat oldin",other:"{0} soat oldin"}}},"hour-short":{displayName:"soat",relative:{0:"shu soatda"},relativeTime:{future:{one:"{0} soatdan keyin",other:"{0} soatdan keyin"},past:{one:"{0} soat oldin",other:"{0} soat oldin"}}},minute:{displayName:"daqiqa",relative:{0:"shu daqiqada"},relativeTime:{future:{one:"{0} daqiqadan keyin",other:"{0} daqiqadan keyin"},past:{one:"{0} daqiqa oldin",other:"{0} daqiqa oldin"}}},"minute-short":{displayName:"daq.",relative:{0:"shu daqiqada"},relativeTime:{future:{one:"{0} daqiqadan keyin",other:"{0} daqiqadan keyin"},past:{one:"{0} daqiqa oldin",other:"{0} daqiqa oldin"}}},second:{displayName:"soniya",relative:{0:"hozir"},relativeTime:{future:{one:"{0} soniyadan keyin",other:"{0} soniyadan keyin"},past:{one:"{0} soniya oldin",other:"{0} soniya oldin"}}},"second-short":{displayName:"son.",relative:{0:"hozir"},relativeTime:{future:{one:"{0} soniyadan keyin",other:"{0} soniyadan keyin"},past:{one:"{0} soniya oldin",other:"{0} soniya oldin"}}}}},{locale:"uz-Arab",pluralRuleFunction:function(e,t){return"other"},fields:{year:{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},"year-short":{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},month:{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},"month-short":{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},day:{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},"day-short":{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},hour:{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},"hour-short":{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},minute:{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},"minute-short":{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},second:{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}},"second-short":{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}}}},{locale:"uz-Cyrl",pluralRuleFunction:function(e,t){return"other"},fields:{year:{displayName:"Йил",relative:{0:"бу йил",1:"кейинги йил","-1":"ўтган йил"},relativeTime:{future:{one:"{0} йилдан сўнг",other:"{0} йилдан сўнг"},past:{one:"{0} йил аввал",other:"{0} йил аввал"}}},"year-short":{displayName:"Йил",relative:{0:"бу йил",1:"кейинги йил","-1":"ўтган йил"},relativeTime:{future:{one:"{0} йилдан сўнг",other:"{0} йилдан сўнг"},past:{one:"{0} йил аввал",other:"{0} йил аввал"}}},month:{displayName:"Ой",relative:{0:"бу ой",1:"кейинги ой","-1":"ўтган ой"},relativeTime:{future:{one:"{0} ойдан сўнг",other:"{0} ойдан сўнг"},past:{one:"{0} ой аввал",other:"{0} ой аввал"}}},"month-short":{displayName:"Ой",relative:{0:"бу ой",1:"кейинги ой","-1":"ўтган ой"},relativeTime:{future:{one:"{0} ойдан сўнг",other:"{0} ойдан сўнг"},past:{one:"{0} ой аввал",other:"{0} ой аввал"}}},day:{displayName:"Кун",relative:{0:"бугун",1:"эртага","-1":"кеча"},relativeTime:{future:{one:"{0} кундан сўнг",other:"{0} кундан сўнг"},past:{one:"{0} кун олдин",other:"{0} кун олдин"}}},"day-short":{displayName:"Кун",relative:{0:"бугун",1:"эртага","-1":"кеча"},relativeTime:{future:{one:"{0} кундан сўнг",other:"{0} кундан сўнг"},past:{one:"{0} кун олдин",other:"{0} кун олдин"}}},hour:{displayName:"Соат",relative:{0:"this hour"},relativeTime:{future:{one:"{0} соатдан сўнг",other:"{0} соатдан сўнг"},past:{one:"{0} соат олдин",other:"{0} соат олдин"}}},"hour-short":{displayName:"Соат",relative:{0:"this hour"},relativeTime:{future:{one:"{0} соатдан сўнг",other:"{0} соатдан сўнг"},past:{one:"{0} соат олдин",other:"{0} соат олдин"}}},minute:{displayName:"Дақиқа",relative:{0:"this minute"},relativeTime:{future:{one:"{0} дақиқадан сўнг",other:"{0} дақиқадан сўнг"},past:{one:"{0} дақиқа олдин",other:"{0} дақиқа олдин"}}},"minute-short":{displayName:"Дақиқа",relative:{0:"this minute"},relativeTime:{future:{one:"{0} дақиқадан сўнг",other:"{0} дақиқадан сўнг"},past:{one:"{0} дақиқа олдин",other:"{0} дақиқа олдин"}}},second:{displayName:"Сония",relative:{0:"ҳозир"},relativeTime:{future:{one:"{0} сониядан сўнг",other:"{0} сониядан сўнг"},past:{one:"{0} сония олдин",other:"{0} сония олдин"}}},"second-short":{displayName:"Сония",relative:{0:"ҳозир"},relativeTime:{future:{one:"{0} сониядан сўнг",other:"{0} сониядан сўнг"},past:{one:"{0} сония олдин",other:"{0} сония олдин"}}}}},{locale:"uz-Latn",parentLocale:"uz"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/vi.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/vi.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"vi",pluralRuleFunction:function(e,t){return t&&1==e?"one":"other"},fields:{year:{displayName:"Năm",relative:{0:"năm nay",1:"năm sau","-1":"năm ngoái"},relativeTime:{future:{other:"sau {0} năm nữa"},past:{other:"{0} năm trước"}}},"year-short":{displayName:"Năm",relative:{0:"năm nay",1:"năm sau","-1":"năm ngoái"},relativeTime:{future:{other:"sau {0} năm nữa"},past:{other:"{0} năm trước"}}},month:{displayName:"Tháng",relative:{0:"tháng này",1:"tháng sau","-1":"tháng trước"},relativeTime:{future:{other:"sau {0} tháng nữa"},past:{other:"{0} tháng trước"}}},"month-short":{displayName:"Tháng",relative:{0:"tháng này",1:"tháng sau","-1":"tháng trước"},relativeTime:{future:{other:"sau {0} tháng nữa"},past:{other:"{0} tháng trước"}}},day:{displayName:"Ngày",relative:{0:"Hôm nay",1:"Ngày mai",2:"Ngày kia","-2":"Hôm kia","-1":"Hôm qua"},relativeTime:{future:{other:"sau {0} ngày nữa"},past:{other:"{0} ngày trước"}}},"day-short":{displayName:"Ngày",relative:{0:"Hôm nay",1:"Ngày mai",2:"Ngày kia","-2":"Hôm kia","-1":"Hôm qua"},relativeTime:{future:{other:"sau {0} ngày nữa"},past:{other:"{0} ngày trước"}}},hour:{displayName:"Giờ",relative:{0:"giờ này"},relativeTime:{future:{other:"sau {0} giờ nữa"},past:{other:"{0} giờ trước"}}},"hour-short":{displayName:"Giờ",relative:{0:"giờ này"},relativeTime:{future:{other:"sau {0} giờ nữa"},past:{other:"{0} giờ trước"}}},minute:{displayName:"Phút",relative:{0:"phút này"},relativeTime:{future:{other:"sau {0} phút nữa"},past:{other:"{0} phút trước"}}},"minute-short":{displayName:"Phút",relative:{0:"phút này"},relativeTime:{future:{other:"sau {0} phút nữa"},past:{other:"{0} phút trước"}}},second:{displayName:"Giây",relative:{0:"bây giờ"},relativeTime:{future:{other:"sau {0} giây nữa"},past:{other:"{0} giây trước"}}},"second-short":{displayName:"Giây",relative:{0:"bây giờ"},relativeTime:{future:{other:"sau {0} giây nữa"},past:{other:"{0} giây trước"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/xh.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/xh.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"xh",pluralRuleFunction:function(e,t){return t?"other":1==e?"one":"other"},fields:{year:{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},"year-short":{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{other:"+{0} y"},past:{other:"-{0} y"}}},month:{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},"month-short":{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{other:"+{0} m"},past:{other:"-{0} m"}}},day:{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},"day-short":{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{other:"+{0} d"},past:{other:"-{0} d"}}},hour:{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},"hour-short":{displayName:"Hour",relative:{0:"this hour"},relativeTime:{future:{other:"+{0} h"},past:{other:"-{0} h"}}},minute:{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},"minute-short":{displayName:"Minute",relative:{0:"this minute"},relativeTime:{future:{other:"+{0} min"},past:{other:"-{0} min"}}},second:{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}},"second-short":{displayName:"Second",relative:{0:"now"},relativeTime:{future:{other:"+{0} s"},past:{other:"-{0} s"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/zh.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/zh.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,t){ true?module.exports=t():undefined}(this,function(){"use strict";return[{locale:"zh",pluralRuleFunction:function(e,t){return"other"},fields:{year:{displayName:"年",relative:{0:"今年",1:"明年","-1":"去年"},relativeTime:{future:{other:"{0}年后"},past:{other:"{0}年前"}}},"year-short":{displayName:"年",relative:{0:"今年",1:"明年","-1":"去年"},relativeTime:{future:{other:"{0}年后"},past:{other:"{0}年前"}}},month:{displayName:"月",relative:{0:"本月",1:"下个月","-1":"上个月"},relativeTime:{future:{other:"{0}个月后"},past:{other:"{0}个月前"}}},"month-short":{displayName:"月",relative:{0:"本月",1:"下个月","-1":"上个月"},relativeTime:{future:{other:"{0}个月后"},past:{other:"{0}个月前"}}},day:{displayName:"日",relative:{0:"今天",1:"明天",2:"后天","-2":"前天","-1":"昨天"},relativeTime:{future:{other:"{0}天后"},past:{other:"{0}天前"}}},"day-short":{displayName:"日",relative:{0:"今天",1:"明天",2:"后天","-2":"前天","-1":"昨天"},relativeTime:{future:{other:"{0}天后"},past:{other:"{0}天前"}}},hour:{displayName:"小时",relative:{0:"这一时间 / 此时"},relativeTime:{future:{other:"{0}小时后"},past:{other:"{0}小时前"}}},"hour-short":{displayName:"小时",relative:{0:"这一时间 / 此时"},relativeTime:{future:{other:"{0}小时后"},past:{other:"{0}小时前"}}},minute:{displayName:"分钟",relative:{0:"此刻"},relativeTime:{future:{other:"{0}分钟后"},past:{other:"{0}分钟前"}}},"minute-short":{displayName:"分",relative:{0:"此刻"},relativeTime:{future:{other:"{0}分钟后"},past:{other:"{0}分钟前"}}},second:{displayName:"秒",relative:{0:"现在"},relativeTime:{future:{other:"{0}秒钟后"},past:{other:"{0}秒钟前"}}},"second-short":{displayName:"秒",relative:{0:"现在"},relativeTime:{future:{other:"{0}秒后"},past:{other:"{0}秒前"}}}}},{locale:"zh-Hans",parentLocale:"zh"},{locale:"zh-Hans-HK",parentLocale:"zh-Hans",fields:{year:{displayName:"年",relative:{0:"今年",1:"明年","-1":"去年"},relativeTime:{future:{other:"{0}年后"},past:{other:"{0}年前"}}},"year-short":{displayName:"年",relative:{0:"今年",1:"明年","-1":"去年"},relativeTime:{future:{other:"{0}年后"},past:{other:"{0}年前"}}},month:{displayName:"月",relative:{0:"本月",1:"下个月","-1":"上个月"},relativeTime:{future:{other:"{0}个月后"},past:{other:"{0}个月前"}}},"month-short":{displayName:"月",relative:{0:"本月",1:"下个月","-1":"上个月"},relativeTime:{future:{other:"{0}个月后"},past:{other:"{0}个月前"}}},day:{displayName:"日",relative:{0:"今天",1:"明天",2:"后天","-2":"前天","-1":"昨天"},relativeTime:{future:{other:"{0}天后"},past:{other:"{0}天前"}}},"day-short":{displayName:"日",relative:{0:"今天",1:"明天",2:"后天","-2":"前天","-1":"昨天"},relativeTime:{future:{other:"{0}天后"},past:{other:"{0}天前"}}},hour:{displayName:"小时",relative:{0:"这一时间 / 此时"},relativeTime:{future:{other:"{0}小时后"},past:{other:"{0}小时前"}}},"hour-short":{displayName:"小时",relative:{0:"这一时间 / 此时"},relativeTime:{future:{other:"{0}小时后"},past:{other:"{0}小时前"}}},minute:{displayName:"分钟",relative:{0:"此刻"},relativeTime:{future:{other:"{0}分钟后"},past:{other:"{0}分钟前"}}},"minute-short":{displayName:"分",relative:{0:"此刻"},relativeTime:{future:{other:"{0}分钟后"},past:{other:"{0}分钟前"}}},second:{displayName:"秒",relative:{0:"现在"},relativeTime:{future:{other:"{0}秒后"},past:{other:"{0}秒前"}}},"second-short":{displayName:"秒",relative:{0:"现在"},relativeTime:{future:{other:"{0}秒后"},past:{other:"{0}秒前"}}}}},{locale:"zh-Hans-MO",parentLocale:"zh-Hans",fields:{year:{displayName:"年",relative:{0:"今年",1:"明年","-1":"去年"},relativeTime:{future:{other:"{0}年后"},past:{other:"{0}年前"}}},"year-short":{displayName:"年",relative:{0:"今年",1:"明年","-1":"去年"},relativeTime:{future:{other:"{0}年后"},past:{other:"{0}年前"}}},month:{displayName:"月",relative:{0:"本月",1:"下个月","-1":"上个月"},relativeTime:{future:{other:"{0}个月后"},past:{other:"{0}个月前"}}},"month-short":{displayName:"月",relative:{0:"本月",1:"下个月","-1":"上个月"},relativeTime:{future:{other:"{0}个月后"},past:{other:"{0}个月前"}}},day:{displayName:"日",relative:{0:"今天",1:"明天",2:"后天","-2":"前天","-1":"昨天"},relativeTime:{future:{other:"{0}天后"},past:{other:"{0}天前"}}},"day-short":{displayName:"日",relative:{0:"今天",1:"明天",2:"后天","-2":"前天","-1":"昨天"},relativeTime:{future:{other:"{0}天后"},past:{other:"{0}天前"}}},hour:{displayName:"小时",relative:{0:"这一时间 / 此时"},relativeTime:{future:{other:"{0}小时后"},past:{other:"{0}小时前"}}},"hour-short":{displayName:"小时",relative:{0:"这一时间 / 此时"},relativeTime:{future:{other:"{0}小时后"},past:{other:"{0}小时前"}}},minute:{displayName:"分钟",relative:{0:"此刻"},relativeTime:{future:{other:"{0}分钟后"},past:{other:"{0}分钟前"}}},"minute-short":{displayName:"分",relative:{0:"此刻"},relativeTime:{future:{other:"{0}分钟后"},past:{other:"{0}分钟前"}}},second:{displayName:"秒",relative:{0:"现在"},relativeTime:{future:{other:"{0}秒后"},past:{other:"{0}秒前"}}},"second-short":{displayName:"秒",relative:{0:"现在"},relativeTime:{future:{other:"{0}秒后"},past:{other:"{0}秒前"}}}}},{locale:"zh-Hans-SG",parentLocale:"zh-Hans",fields:{year:{displayName:"年",relative:{0:"今年",1:"明年","-1":"去年"},relativeTime:{future:{other:"{0}年后"},past:{other:"{0}年前"}}},"year-short":{displayName:"年",relative:{0:"今年",1:"明年","-1":"去年"},relativeTime:{future:{other:"{0}年后"},past:{other:"{0}年前"}}},month:{displayName:"月",relative:{0:"本月",1:"下个月","-1":"上个月"},relativeTime:{future:{other:"{0}个月后"},past:{other:"{0}个月前"}}},"month-short":{displayName:"月",relative:{0:"本月",1:"下个月","-1":"上个月"},relativeTime:{future:{other:"{0}个月后"},past:{other:"{0}个月前"}}},day:{displayName:"日",relative:{0:"今天",1:"明天",2:"后天","-2":"前天","-1":"昨天"},relativeTime:{future:{other:"{0}天后"},past:{other:"{0}天前"}}},"day-short":{displayName:"日",relative:{0:"今天",1:"明天",2:"后天","-2":"前天","-1":"昨天"},relativeTime:{future:{other:"{0}天后"},past:{other:"{0}天前"}}},hour:{displayName:"小时",relative:{0:"这一时间 / 此时"},relativeTime:{future:{other:"{0}小时后"},past:{other:"{0}小时前"}}},"hour-short":{displayName:"小时",relative:{0:"这一时间 / 此时"},relativeTime:{future:{other:"{0}小时后"},past:{other:"{0}小时前"}}},minute:{displayName:"分钟",relative:{0:"此刻"},relativeTime:{future:{other:"{0}分钟后"},past:{other:"{0}分钟前"}}},"minute-short":{displayName:"分",relative:{0:"此刻"},relativeTime:{future:{other:"{0}分钟后"},past:{other:"{0}分钟前"}}},second:{displayName:"秒",relative:{0:"现在"},relativeTime:{future:{other:"{0}秒后"},past:{other:"{0}秒前"}}},"second-short":{displayName:"秒",relative:{0:"现在"},relativeTime:{future:{other:"{0}秒后"},past:{other:"{0}秒前"}}}}},{locale:"zh-Hant",pluralRuleFunction:function(e,t){return"other"},fields:{year:{displayName:"年",relative:{0:"今年",1:"明年","-1":"去年"},relativeTime:{future:{other:"{0} 年後"},past:{other:"{0} 年前"}}},"year-short":{displayName:"年",relative:{0:"今年",1:"明年","-1":"去年"},relativeTime:{future:{other:"{0} 年後"},past:{other:"{0} 年前"}}},month:{displayName:"月",relative:{0:"本月",1:"下個月","-1":"上個月"},relativeTime:{future:{other:"{0} 個月後"},past:{other:"{0} 個月前"}}},"month-short":{displayName:"月",relative:{0:"本月",1:"下個月","-1":"上個月"},relativeTime:{future:{other:"{0} 個月後"},past:{other:"{0} 個月前"}}},day:{displayName:"日",relative:{0:"今天",1:"明天",2:"後天","-2":"前天","-1":"昨天"},relativeTime:{future:{other:"{0} 天後"},past:{other:"{0} 天前"}}},"day-short":{displayName:"日",relative:{0:"今天",1:"明天",2:"後天","-2":"前天","-1":"昨天"},relativeTime:{future:{other:"{0} 天後"},past:{other:"{0} 天前"}}},hour:{displayName:"小時",relative:{0:"這一小時"},relativeTime:{future:{other:"{0} 小時後"},past:{other:"{0} 小時前"}}},"hour-short":{displayName:"小時",relative:{0:"這一小時"},relativeTime:{future:{other:"{0} 小時後"},past:{other:"{0} 小時前"}}},minute:{displayName:"分鐘",relative:{0:"這一分鐘"},relativeTime:{future:{other:"{0} 分鐘後"},past:{other:"{0} 分鐘前"}}},"minute-short":{displayName:"分鐘",relative:{0:"這一分鐘"},relativeTime:{future:{other:"{0} 分鐘後"},past:{other:"{0} 分鐘前"}}},second:{displayName:"秒",relative:{0:"現在"},relativeTime:{future:{other:"{0} 秒後"},past:{other:"{0} 秒前"}}},"second-short":{displayName:"秒",relative:{0:"現在"},relativeTime:{future:{other:"{0} 秒後"},past:{other:"{0} 秒前"}}}}},{locale:"zh-Hant-HK",parentLocale:"zh-Hant",fields:{year:{displayName:"年",relative:{0:"今年",1:"下年","-1":"上年"},relativeTime:{future:{other:"{0} 年後"},past:{other:"{0} 年前"}}},"year-short":{displayName:"年",relative:{0:"今年",1:"下年","-1":"上年"},relativeTime:{future:{other:"{0} 年後"},past:{other:"{0} 年前"}}},month:{displayName:"月",relative:{0:"本月",1:"下個月","-1":"上個月"},relativeTime:{future:{other:"{0} 個月後"},past:{other:"{0} 個月前"}}},"month-short":{displayName:"月",relative:{0:"本月",1:"下個月","-1":"上個月"},relativeTime:{future:{other:"{0} 個月後"},past:{other:"{0} 個月前"}}},day:{displayName:"日",relative:{0:"今日",1:"明日",2:"後日","-2":"前日","-1":"昨日"},relativeTime:{future:{other:"{0} 日後"},past:{other:"{0} 日前"}}},"day-short":{displayName:"日",relative:{0:"今日",1:"明日",2:"後日","-2":"前日","-1":"昨日"},relativeTime:{future:{other:"{0} 日後"},past:{other:"{0} 日前"}}},hour:{displayName:"小時",relative:{0:"這個小時"},relativeTime:{future:{other:"{0} 小時後"},past:{other:"{0} 小時前"}}},"hour-short":{displayName:"小時",relative:{0:"這個小時"},relativeTime:{future:{other:"{0} 小時後"},past:{other:"{0} 小時前"}}},minute:{displayName:"分鐘",relative:{0:"這分鐘"},relativeTime:{future:{other:"{0} 分鐘後"},past:{other:"{0} 分鐘前"}}},"minute-short":{displayName:"分鐘",relative:{0:"這分鐘"},relativeTime:{future:{other:"{0} 分鐘後"},past:{other:"{0} 分鐘前"}}},second:{displayName:"秒",relative:{0:"現在"},relativeTime:{future:{other:"{0} 秒後"},past:{other:"{0} 秒前"}}},"second-short":{displayName:"秒",relative:{0:"現在"},relativeTime:{future:{other:"{0} 秒後"},past:{other:"{0} 秒前"}}}}},{locale:"zh-Hant-MO",parentLocale:"zh-Hant-HK"}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/locale-data/zu.js": /*!********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/locale-data/zu.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { !function(e,a){ true?module.exports=a():undefined}(this,function(){"use strict";return[{locale:"zu",pluralRuleFunction:function(e,a){return a?"other":e>=0&&e<=1?"one":"other"},fields:{year:{displayName:"Unyaka",relative:{0:"kulo nyaka",1:"unyaka ozayo","-1":"onyakeni odlule"},relativeTime:{future:{one:"onyakeni ongu-{0} ozayo",other:"eminyakeni engu-{0} ezayo"},past:{one:"{0} unyaka odlule",other:"{0} iminyaka edlule"}}},"year-short":{displayName:"Unyaka",relative:{0:"kulo nyaka",1:"unyaka ozayo","-1":"onyakeni odlule"},relativeTime:{future:{one:"onyakeni ongu-{0} ozayo",other:"eminyakeni engu-{0} ezayo"},past:{one:"{0} unyaka odlule",other:"{0} unyaka odlule"}}},month:{displayName:"Inyanga",relative:{0:"le nyanga",1:"inyanga ezayo","-1":"inyanga edlule"},relativeTime:{future:{one:"enyangeni engu-{0}",other:"ezinyangeni ezingu-{0} ezizayo"},past:{one:"{0} inyanga edlule",other:"{0} izinyanga ezedlule"}}},"month-short":{displayName:"Inyanga",relative:{0:"le nyanga",1:"inyanga ezayo","-1":"inyanga edlule"},relativeTime:{future:{one:"ezinyangeni ezingu-{0} ezizayo",other:"ezinyangeni ezingu-{0} ezizayo"},past:{one:"{0} izinyanga ezedlule",other:"{0} izinyanga ezedlule"}}},day:{displayName:"Usuku",relative:{0:"namhlanje",1:"kusasa",2:"usuku olulandela olwakusasa","-2":"usuku olwandulela olwayizolo","-1":"izolo"},relativeTime:{future:{one:"osukwini olungu-{0} oluzayo",other:"ezinsukwini ezingu-{0} ezizayo"},past:{one:"osukwini olungu-{0} olwedlule",other:"ezinsukwini ezingu-{0} ezedlule."}}},"day-short":{displayName:"Usuku",relative:{0:"namhlanje",1:"kusasa",2:"usuku olulandela olwakusasa","-2":"usuku olwandulela olwayizolo","-1":"izolo"},relativeTime:{future:{one:"osukwini olungu-{0} oluzayo",other:"ezinsukwini ezingu-{0} ezizayo"},past:{one:"{0} usuku olwedlule",other:"{0} izinsuku ezedlule"}}},hour:{displayName:"Ihora",relative:{0:"leli hora"},relativeTime:{future:{one:"ehoreni elingu-{0} elizayo",other:"emahoreni angu-{0} ezayo"},past:{one:"{0} ihora eledlule",other:"emahoreni angu-{0} edlule"}}},"hour-short":{displayName:"Ihora",relative:{0:"leli hora"},relativeTime:{future:{one:"ehoreni elingu-{0} elizayo",other:"emahoreni angu-{0} ezayo"},past:{one:"{0} ihora eledlule",other:"emahoreni angu-{0} edlule"}}},minute:{displayName:"Iminithi",relative:{0:"leli minithi"},relativeTime:{future:{one:"kuminithi elingu-{0} elizayo",other:"kumaminithi angu-{0} ezayo"},past:{one:"{0} iminithi eledlule",other:"{0} amaminithi edlule"}}},"minute-short":{displayName:"Iminithi",relative:{0:"leli minithi"},relativeTime:{future:{one:"kuminithi elingu-{0} elizayo",other:"kumaminithi angu-{0} ezayo"},past:{one:"{0} iminithi eledlule",other:"{0} amaminithi edlule"}}},second:{displayName:"Isekhondi",relative:{0:"manje"},relativeTime:{future:{one:"kusekhondi elingu-{0} elizayo",other:"kumasekhondi angu-{0} ezayo"},past:{one:"{0} isekhondi eledlule",other:"{0} amasekhondi edlule"}}},"second-short":{displayName:"Isekhondi",relative:{0:"manje"},relativeTime:{future:{one:"kusekhondi elingu-{0} elizayo",other:"kumasekhondi angu-{0} ezayo"},past:{one:"{0} isekhondi eledlule",other:"{0} amasekhondi edlule"}}}}}]}); /***/ }), /***/ "./node_modules/@turbowarp/scratch-l10n/src/supported-locales.js": /*!***********************************************************************!*\ !*** ./node_modules/@turbowarp/scratch-l10n/src/supported-locales.js ***! \***********************************************************************/ /*! exports provided: default, customLocales, localeMap, isRtl */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return locales; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "customLocales", function() { return customLocales; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "localeMap", function() { return localeMap; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isRtl", function() { return isRtl; }); /** * Currently supported locales for the Scratch Project * @type {Object} Key Value pairs of locale code: Language name written in the language */ const locales = { 'ab': {name: 'Аҧсшәа'}, 'af': {name: 'Afrikaans'}, 'ar': {name: 'العربية'}, 'am': {name: 'አማርኛ'}, 'an': {name: 'Aragonés'}, 'ast': {name: 'Asturianu'}, 'az': {name: 'Azeri'}, 'id': {name: 'Bahasa Indonesia'}, 'bn': {name: 'বাংলা'}, 'be': {name: 'Беларуская'}, 'bg': {name: 'Български'}, 'ca': {name: 'Català'}, 'cs': {name: 'Česky'}, 'cy': {name: 'Cymraeg'}, 'da': {name: 'Dansk'}, 'de': {name: 'Deutsch'}, 'et': {name: 'Eesti'}, 'el': {name: 'Ελληνικά'}, 'en': {name: 'English'}, 'es': {name: 'Español (España)'}, 'es-419': {name: 'Español Latinoamericano'}, 'eo': {name: 'Esperanto'}, 'eu': {name: 'Euskara'}, 'fa': {name: 'فارسی'}, 'fil': {name: 'Filipino'}, 'fr': {name: 'Français'}, 'fy': {name: 'Frysk'}, 'ga': {name: 'Gaeilge'}, 'gd': {name: 'Gàidhlig'}, 'gl': {name: 'Galego'}, 'ko': {name: '한국어'}, 'ha': {name: 'Hausa'}, 'hy': {name: 'Հայերեն'}, 'he': {name: 'עִבְרִית'}, 'hr': {name: 'Hrvatski'}, 'xh': {name: 'isiXhosa'}, 'zu': {name: 'isiZulu'}, 'is': {name: 'Íslenska'}, 'it': {name: 'Italiano'}, 'ka': {name: 'ქართული ენა'}, 'kk': {name: 'қазақша'}, 'qu': {name: 'Kichwa'}, 'sw': {name: 'Kiswahili'}, 'ht': {name: 'Kreyòl ayisyen'}, 'ku': {name: 'Kurdî'}, 'ckb': {name: 'کوردیی ناوەندی'}, 'lv': {name: 'Latviešu'}, 'lt': {name: 'Lietuvių'}, 'hu': {name: 'Magyar'}, 'mi': {name: 'Māori'}, 'mn': {name: 'Монгол хэл'}, 'nl': {name: 'Nederlands'}, 'ja': {name: '日本語'}, 'ja-Hira': {name: 'にほんご'}, 'nb': {name: 'Norsk Bokmål'}, 'nn': {name: 'Norsk Nynorsk'}, 'oc': {name: 'Occitan'}, 'or': {name: 'ଓଡ଼ିଆ'}, 'uz': {name: 'Oʻzbekcha'}, 'th': {name: 'ไทย'}, 'km': {name: 'ភាសាខ្មែរ'}, 'pl': {name: 'Polski'}, 'pt': {name: 'Português'}, 'pt-br': {name: 'Português Brasileiro'}, 'rap': {name: 'Rapa Nui'}, 'ro': {name: 'Română'}, 'ru': {name: 'Русский'}, 'nso': {name: 'Sepedi'}, 'tn': {name: 'Setswana'}, 'sk': {name: 'Slovenčina'}, 'sl': {name: 'Slovenščina'}, 'sr': {name: 'Српски'}, 'fi': {name: 'Suomi'}, 'sv': {name: 'Svenska'}, 'vi': {name: 'Tiếng Việt'}, 'tr': {name: 'Türkçe'}, 'uk': {name: 'Українська'}, 'zh-cn': {name: '简体中文'}, 'zh-tw': {name: '繁體中文'} }; const customLocales = { 'ab': { locale: 'ab', parentLocale: 'ru' }, // Aragonese is not in the locale data, using es for Spain 'an': { locale: 'an', parentLocale: 'es' }, // haitian creole is not in locale-langData 'ht': { locale: 'ht', parentLocale: 'fr' }, 'oc': { locale: 'oc', parentLocale: 'fr' }, 'rap': { locale: 'rap', parentLocale: 'es' }, // TODO: replace zh-cn, zh-tw with zh-Hans and zh-Hant then customLocales is unnecessary 'zh-cn': { locale: 'zh-cn', parentLocale: 'zh' }, 'zh-tw': { locale: 'zh-tw', parentLocale: 'zh' } }; const localeMap = { 'aa-dj': 'aa_DJ', 'es-419': 'es_419', // ja-Hira: no map - it's 'ja-Hira' on transifex 'pt-br': 'pt_BR', 'zh-cn': 'zh_CN', 'zh-tw': 'zh_TW' }; // list of RTL locales supported, and a function to check whether a locale is RTL const rtlLocales = [ 'ar', 'ckb', 'fa', 'he' ]; const isRtl = locale => { return rtlLocales.indexOf(locale) !== -1; }; /***/ }), /***/ "./node_modules/@vernier/godirect/dist/godirect.min.umd.js": /*!*****************************************************************!*\ !*** ./node_modules/@vernier/godirect/dist/godirect.min.umd.js ***! \*****************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /** * Copyright (c) 2019 Vernier Software. All rights reserved. * This code may only be used under the BSD 3-Clause license found at * https://raw.githubusercontent.com/VernierST/godirect-js/master/LICENSE */ !function (e, t) { true ? module.exports = t() : undefined; }(this, function () { "use strict"; function e(e, t, n, r, i, a, o) { try { var s = e[a](o), u = s.value; } catch (e) { return void n(e); } s.done ? t(u) : Promise.resolve(u).then(r, i); } function t(t) { return function () { var n = this, r = arguments; return new Promise(function (i, a) { var o = t.apply(n, r); function s(t) { e(o, i, a, s, u, "next", t); } function u(t) { e(o, i, a, s, u, "throw", t); } s(void 0); }); }; } function n(e, t) { if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function"); } function r(e, t) { for (var n = 0; n < t.length; n++) { var r = t[n]; r.enumerable = r.enumerable || !1, r.configurable = !0, "value" in r && (r.writable = !0), Object.defineProperty(e, r.key, r); } } function i(e, t, n) { return t && r(e.prototype, t), n && r(e, n), e; } function a(e, t) { if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function"); e.prototype = Object.create(t && t.prototype, { constructor: { value: e, writable: !0, configurable: !0 } }), t && s(e, t); } function o(e) { return (o = Object.setPrototypeOf ? Object.getPrototypeOf : function (e) { return e.__proto__ || Object.getPrototypeOf(e); })(e); } function s(e, t) { return (s = Object.setPrototypeOf || function (e, t) { return e.__proto__ = t, e; })(e, t); } function u(e, t) { return !t || "object" != typeof t && "function" != typeof t ? function (e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; }(e) : t; } !function (e) { var t, n = Object.prototype, r = n.hasOwnProperty, i = "function" == typeof Symbol ? Symbol : {}, a = i.iterator || "@@iterator", o = i.asyncIterator || "@@asyncIterator", s = i.toStringTag || "@@toStringTag", u = "object" == typeof module, c = e.regeneratorRuntime; if (c) u && (module.exports = c);else { (c = e.regeneratorRuntime = u ? module.exports : {}).wrap = b; var f = "suspendedStart", h = "suspendedYield", l = "executing", p = "completed", d = {}, m = {}; m[a] = function () { return this; }; var v = Object.getPrototypeOf, g = v && v(v(C([]))); g && g !== n && r.call(g, a) && (m = g); var y = x.prototype = _.prototype = Object.create(m); k.prototype = y.constructor = x, x.constructor = k, x[s] = k.displayName = "GeneratorFunction", c.isGeneratorFunction = function (e) { var t = "function" == typeof e && e.constructor; return !!t && (t === k || "GeneratorFunction" === (t.displayName || t.name)); }, c.mark = function (e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, x) : (e.__proto__ = x, s in e || (e[s] = "GeneratorFunction")), e.prototype = Object.create(y), e; }, c.awrap = function (e) { return { __await: e }; }, E(S.prototype), S.prototype[o] = function () { return this; }, c.AsyncIterator = S, c.async = function (e, t, n, r) { var i = new S(b(e, t, n, r)); return c.isGeneratorFunction(t) ? i : i.next().then(function (e) { return e.done ? e.value : i.next(); }); }, E(y), y[s] = "Generator", y[a] = function () { return this; }, y.toString = function () { return "[object Generator]"; }, c.keys = function (e) { var t = []; for (var n in e) t.push(n); return t.reverse(), function n() { for (; t.length;) { var r = t.pop(); if (r in e) return n.value = r, n.done = !1, n; } return n.done = !0, n; }; }, c.values = C, A.prototype = { constructor: A, reset: function reset(e) { if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(M), !e) for (var n in this) "t" === n.charAt(0) && r.call(this, n) && !isNaN(+n.slice(1)) && (this[n] = t); }, stop: function stop() { this.done = !0; var e = this.tryEntries[0].completion; if ("throw" === e.type) throw e.arg; return this.rval; }, dispatchException: function dispatchException(e) { if (this.done) throw e; var n = this; function i(r, i) { return s.type = "throw", s.arg = e, n.next = r, i && (n.method = "next", n.arg = t), !!i; } for (var a = this.tryEntries.length - 1; a >= 0; --a) { var o = this.tryEntries[a], s = o.completion; if ("root" === o.tryLoc) return i("end"); if (o.tryLoc <= this.prev) { var u = r.call(o, "catchLoc"), c = r.call(o, "finallyLoc"); if (u && c) { if (this.prev < o.catchLoc) return i(o.catchLoc, !0); if (this.prev < o.finallyLoc) return i(o.finallyLoc); } else if (u) { if (this.prev < o.catchLoc) return i(o.catchLoc, !0); } else { if (!c) throw new Error("try statement without catch or finally"); if (this.prev < o.finallyLoc) return i(o.finallyLoc); } } } }, abrupt: function abrupt(e, t) { for (var n = this.tryEntries.length - 1; n >= 0; --n) { var i = this.tryEntries[n]; if (i.tryLoc <= this.prev && r.call(i, "finallyLoc") && this.prev < i.finallyLoc) { var a = i; break; } } a && ("break" === e || "continue" === e) && a.tryLoc <= t && t <= a.finallyLoc && (a = null); var o = a ? a.completion : {}; return o.type = e, o.arg = t, a ? (this.method = "next", this.next = a.finallyLoc, d) : this.complete(o); }, complete: function complete(e, t) { if ("throw" === e.type) throw e.arg; return "break" === e.type || "continue" === e.type ? this.next = e.arg : "return" === e.type ? (this.rval = this.arg = e.arg, this.method = "return", this.next = "end") : "normal" === e.type && t && (this.next = t), d; }, finish: function finish(e) { for (var t = this.tryEntries.length - 1; t >= 0; --t) { var n = this.tryEntries[t]; if (n.finallyLoc === e) return this.complete(n.completion, n.afterLoc), M(n), d; } }, catch: function _catch(e) { for (var t = this.tryEntries.length - 1; t >= 0; --t) { var n = this.tryEntries[t]; if (n.tryLoc === e) { var r = n.completion; if ("throw" === r.type) { var i = r.arg; M(n); } return i; } } throw new Error("illegal catch attempt"); }, delegateYield: function delegateYield(e, n, r) { return this.delegate = { iterator: C(e), resultName: n, nextLoc: r }, "next" === this.method && (this.arg = t), d; } }; } function b(e, t, n, r) { var i = t && t.prototype instanceof _ ? t : _, a = Object.create(i.prototype), o = new A(r || []); return a._invoke = function (e, t, n) { var r = f; return function (i, a) { if (r === l) throw new Error("Generator is already running"); if (r === p) { if ("throw" === i) throw a; return L(); } for (n.method = i, n.arg = a;;) { var o = n.delegate; if (o) { var s = R(o, n); if (s) { if (s === d) continue; return s; } } if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) { if (r === f) throw r = p, n.arg; n.dispatchException(n.arg); } else "return" === n.method && n.abrupt("return", n.arg); r = l; var u = w(e, t, n); if ("normal" === u.type) { if (r = n.done ? p : h, u.arg === d) continue; return { value: u.arg, done: n.done }; } "throw" === u.type && (r = p, n.method = "throw", n.arg = u.arg); } }; }(e, n, o), a; } function w(e, t, n) { try { return { type: "normal", arg: e.call(t, n) }; } catch (e) { return { type: "throw", arg: e }; } } function _() {} function k() {} function x() {} function E(e) { ["next", "throw", "return"].forEach(function (t) { e[t] = function (e) { return this._invoke(t, e); }; }); } function S(e) { var t; this._invoke = function (n, i) { function a() { return new Promise(function (t, a) { !function t(n, i, a, o) { var s = w(e[n], e, i); if ("throw" !== s.type) { var u = s.arg, c = u.value; return c && "object" == typeof c && r.call(c, "__await") ? Promise.resolve(c.__await).then(function (e) { t("next", e, a, o); }, function (e) { t("throw", e, a, o); }) : Promise.resolve(c).then(function (e) { u.value = e, a(u); }, function (e) { return t("throw", e, a, o); }); } o(s.arg); }(n, i, t, a); }); } return t = t ? t.then(a, a) : a(); }; } function R(e, n) { var r = e.iterator[n.method]; if (r === t) { if (n.delegate = null, "throw" === n.method) { if (e.iterator.return && (n.method = "return", n.arg = t, R(e, n), "throw" === n.method)) return d; n.method = "throw", n.arg = new TypeError("The iterator does not provide a 'throw' method"); } return d; } var i = w(r, e.iterator, n.arg); if ("throw" === i.type) return n.method = "throw", n.arg = i.arg, n.delegate = null, d; var a = i.arg; return a ? a.done ? (n[e.resultName] = a.value, n.next = e.nextLoc, "return" !== n.method && (n.method = "next", n.arg = t), n.delegate = null, d) : a : (n.method = "throw", n.arg = new TypeError("iterator result is not an object"), n.delegate = null, d); } function U(e) { var t = { tryLoc: e[0] }; 1 in e && (t.catchLoc = e[1]), 2 in e && (t.finallyLoc = e[2], t.afterLoc = e[3]), this.tryEntries.push(t); } function M(e) { var t = e.completion || {}; t.type = "normal", delete t.arg, e.completion = t; } function A(e) { this.tryEntries = [{ tryLoc: "root" }], e.forEach(U, this), this.reset(!0); } function C(e) { if (e) { var n = e[a]; if (n) return n.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) { var i = -1, o = function n() { for (; ++i < e.length;) if (r.call(e, i)) return n.value = e[i], n.done = !1, n; return n.value = t, n.done = !0, n; }; return o.next = o; } } return { next: L }; } function L() { return { value: t, done: !0 }; } }(function () { return this || "object" == typeof self && self; }() || Function("return this")()); var c = new Uint8Array([88, 0, 0, 0]), f = new Uint8Array([26, 165, 74, 6, 73, 7, 72, 8, 71, 9, 70, 10, 69, 11, 68, 12, 67, 13, 66, 14, 65]), h = new Uint8Array([24, 255, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), l = new Uint8Array([25, 255, 0, 255, 255, 255, 255]), p = new Uint8Array([27, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0]), d = { HEADER: c, INIT: f, DISCONNECT: new Uint8Array([84]), START_MEASUREMENTS: h, STOP_MEASUREMENTS: l, SET_MEASUREMENT_PERIOD: p, GET_INFO: new Uint8Array([85]), GET_STATUS: new Uint8Array([16]), GET_SENSOR_IDS: new Uint8Array([81]), GET_SENSOR_INFO: new Uint8Array([80, 0]), GET_DEFAULT_SENSORS_MASK: new Uint8Array([86]) }, m = 6, v = 7, g = 10, y = 8, b = 9, w = 11, _ = 12, k = 13, x = 14, E = 32, S = function S(e) { return 0 !== e; }, R = function () { function e() { n(this, e), this._listenerMap = new Map(); } return i(e, [{ key: "on", value: function value(e, t) { this._listenerMap.has(e) || this._listenerMap.set(e, []), this._listenerMap.get(e).push(t); } }, { key: "off", value: function value(e, t) { var n = this._listenerMap.get(e); if (n && n.length) { var r = n.reduce(function (e, n, r) { return "function" == typeof n && n === t ? e = r : e; }, -1); if (r > -1) return n.splice(r, 1), this._listenerMap.set(e, n), !0; } return !1; } }, { key: "unbind", value: function value() { this._listenerMap.clear(); } }, { key: "emit", value: function value(e) { for (var t = arguments.length, n = new Array(t > 1 ? t - 1 : 0), r = 1; r < t; r++) n[r - 1] = arguments[r]; var i = this._listenerMap.get(e); return !(!i || !i.length) && (i.forEach(function (e) { e.apply(void 0, n); }), !0); } }]), e; }(), U = function U() {}, M = function M() {}; function A(e) { return Array.from(new Uint8Array(e)).map(function (e) { return e.toString(16).padStart(2, "0"); }).join(" "); } var C, L = function e() { var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; n(this, e), this.type = t.type, this.mode = t.mode, this.minValue = t.minValue, this.maxValue = t.maxValue, this.uncertainty = t.uncertainty, this.minPeriod = t.minPeriod, this.maxPeriod = t.maxPeriod, this.typicalPeriod = t.typicalPeriod, this.granularity = t.granularity; }, P = function e() { var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; n(this, e), this.number = t.number, this.name = t.name, this.unit = t.unit, this.id = t.id, this.mutalExclusionMask = t.mutalExclusionMask, this.measurementInfo = t.measurementInfo; }, T = function (e) { function t(e) { var r; return n(this, t), (r = u(this, o(t).call(this))).number = e.number, r.name = e.name, r.unit = e.unit, r.specs = e, r.enabled = !1, r.values = [], r.value = null, r; } return a(t, R), i(t, [{ key: "clear", value: function value() { this.value = null, this.values = []; } }, { key: "setValue", value: function value(e, t) { this.value = e, t && this.values.push(this.value), this.emit("value-changed", this); } }, { key: "setEnabled", value: function value(e) { this.enabled !== e && (this.enabled = e, this.emit("state-changed", this)); } }]), t; }(), N = function (e) { function r(e) { var t; if (n(this, r), t = u(this, o(r).call(this)), "undefined" == typeof TextDecoder) { var i = __webpack_require__(/*! text-encoding */ "./src/lib/tw-text-encoder.js"); C = i.TextDecoder; } else C = TextDecoder; return t.device = e, t.sensors = [], t.opened = !1, t.rollingCounter = 0, t.collecting = !1, t.measurementPeriod = 10, t.response = null, t.remainingResponseLength = 0, t.defaultSensorsMask = 0, t.keepValues = !0, t.minMeasurementPeriod = 10, t.serialNumber = "", t.orderCode = "", t.name = "", t; } return a(r, R), i(r, [{ key: "getBatteryLevel", value: function () { var e = t(regeneratorRuntime.mark(function e() { var t; return regeneratorRuntime.wrap(function (e) { for (;;) switch (e.prev = e.next) { case 0: return e.next = 2, this._getStatus(); case 2: return t = e.sent, e.abrupt("return", t.battery); case 4: case "end": return e.stop(); } }, e, this); })); return function () { return e.apply(this, arguments); }; }() }, { key: "getChargingState", value: function () { var e = t(regeneratorRuntime.mark(function e() { var t; return regeneratorRuntime.wrap(function (e) { for (;;) switch (e.prev = e.next) { case 0: return e.next = 2, this._getStatus(); case 2: return t = e.sent, e.abrupt("return", t.chargingStatus); case 4: case "end": return e.stop(); } }, e, this); })); return function () { return e.apply(this, arguments); }; }() }, { key: "open", value: function () { var e = t(regeneratorRuntime.mark(function e() { var t, n = arguments; return regeneratorRuntime.wrap(function (e) { for (;;) switch (e.prev = e.next) { case 0: return t = n.length > 0 && void 0 !== n[0] && n[0], e.prev = 1, e.next = 4, this._connect(); case 4: return e.next = 6, this._init(); case 6: return e.next = 8, this._getStatus(); case 8: return e.next = 10, this._getDeviceInfo(); case 10: return e.next = 12, this._getDefaultSensorsMask(); case 12: return e.next = 14, this._getAvailableSensors(); case 14: this._onOpened(), t && this.start(), e.next = 21; break; case 18: e.prev = 18, e.t0 = e.catch(1), console.error(e.t0); case 21: case "end": return e.stop(); } }, e, this, [[1, 18]]); })); return function () { return e.apply(this, arguments); }; }() }, { key: "close", value: function () { var e = t(regeneratorRuntime.mark(function e() { return regeneratorRuntime.wrap(function (e) { for (;;) switch (e.prev = e.next) { case 0: return e.next = 2, this._stopMeasurements(); case 2: return e.next = 4, this._sendCommand(d.DISCONNECT); case 4: return e.abrupt("return", this._disconnect()); case 5: case "end": return e.stop(); } }, e, this); })); return function () { return e.apply(this, arguments); }; }() }, { key: "enableDefaultSensors", value: function value() { for (var e = 1, t = 0; t < 32; ++t) { if ((this.defaultSensorsMask & e) === e) { var n = this.getSensor(t); n && n.setEnabled(!0); } e <<= 1; } } }, { key: "start", value: function value() { var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : null, t = this.sensors.filter(function (e) { return e.enabled; }); 0 === t.length && (this.enableDefaultSensors(), t = this.sensors.filter(function (e) { return e.enabled; })), t.forEach(function (e) { return e.clear(); }), e && (this.measurementPeriod = e), this._startMeasurements(); } }, { key: "stop", value: function value() { this._stopMeasurements(); } }, { key: "getSensor", value: function value(e) { return this.sensors.find(function (t) { return t.number === e; }); } }, { key: "_connect", value: function () { var e = t(regeneratorRuntime.mark(function e() { var t = this; return regeneratorRuntime.wrap(function (e) { for (;;) switch (e.prev = e.next) { case 0: return e.abrupt("return", this.device.setup({ onClosed: function onClosed() { return t._onClosed(); }, onResponse: function onResponse(e) { return t._handleResponse(e); } })); case 1: case "end": return e.stop(); } }, e, this); })); return function () { return e.apply(this, arguments); }; }() }, { key: "_disconnect", value: function () { var e = t(regeneratorRuntime.mark(function e() { return regeneratorRuntime.wrap(function (e) { for (;;) switch (e.prev = e.next) { case 0: return e.abrupt("return", this.device.close()); case 1: case "end": return e.stop(); } }, e, this); })); return function () { return e.apply(this, arguments); }; }() }, { key: "_init", value: function value() { return this.collecting = !1, this.rollingCounter = 255, this.writeQueue = [], this._sendCommand(d.INIT); } }, { key: "_handleResponse", value: function value(e) { if (U("command notified: ".concat(A(e.buffer))), this.remainingResponseLegnth > 0) { if (this.remainingResponseLegnth -= e.buffer.byteLength, this.response = new DataView((t = this.response.buffer, n = e.buffer.slice(0), (r = new Uint8Array(t.byteLength + n.byteLength)).set(new Uint8Array(t), 0), r.set(new Uint8Array(n), t.byteLength), r.buffer)), this.remainingResponseLegnth > 0) return; } else this.response = e; var t, n, r, i = this.response.getUint8(1); if (i > this.response.buffer.byteLength) this.remainingResponseLegnth = i - this.response.buffer.byteLength;else switch (U("handle command: ".concat(A(this.response.buffer))), this.response.getUint8(0)) { case E: this._processMeasurements(this.response); break; default: var a = this.response.getUint8(4), o = this.response.getUint8(5), s = new DataView(this.response.buffer, 6); this._resolveWriteCommand(a, o, s), this.remainingResponseLegnth = 0, this.response = null; } } }, { key: "_getSensorsWithMask", value: function value(e) { for (var t = [], n = 1, r = 0; r < 32; ++r) { if ((e & n) === n) { var i = this.getSensor(r); i && (t.push(i), U("available: [".concat(e, "] ").concat(t[t.length - 1].number))); } n <<= 1; } return t; } }, { key: "_processMeasurements", value: function value(e) { var t = [], n = !0, r = 0, i = 0, a = e.getUint8(4); switch (a) { case m: t = this._getSensorsWithMask(e.getUint16(5, !0)), r = e.getUint8(7, !0), i = 9; break; case v: t = this._getSensorsWithMask(e.getUint32(5, !0)), r = e.getUint8(9, !0), i = 11; break; case g: case y: t[0] = this.getSensor(e.getUint8(6)), r = e.getUint8(7, !0), i = 8; break; case w: case b: t[0] = this.getSensor(e.getUint8(6)), r = e.getUint8(7, !0), i = 8, n = !1; break; case _: case k: case x: U("Purposely Ignoring packet type: ".concat(a)); break; default: U("Unknown packet type: ".concat(a)); } for (var o = 0; o < r; ++o) for (var s = 0; s < t.length; ++s) n ? t[s].setValue(e.getFloat32(i, !0), this.keepValues) : t[s].setValue(e.getInt32(i, !0), this.keepValues), i += 4; } }, { key: "_resolveWriteCommand", value: function value(e, t, n) { var r = this.writeQueue.find(function (n) { return n.command === e && n.rollingCounter === t; }); r && (r.resolve(n), this.writeQueue = this.writeQueue.filter(function (e) { return e !== r; })); } }, { key: "_onOpened", value: function value() { U("opened"), this.opened = !0, this.emit("device-opened"); } }, { key: "_onClosed", value: function value() { U("closed"), this.opened = !1, this.emit("device-closed"); } }, { key: "_decRollingCounter", value: function value() { return this.rollingCounter -= 1, this.rollingCounter; } }, { key: "_calculateChecksum", value: function value(e) { for (var t = e[1], n = -1 * e[3], r = 0; r < t; ++r) n += e[r], n &= 255; return n < 0 || n > 255 ? (U("Checksum failed!"), 0) : n; } }, { key: "_sendCommand", value: function value(e) { var t = new Uint8Array(d.HEADER.byteLength + e.byteLength); return t.set(new Uint8Array(d.HEADER), 0), t.set(new Uint8Array(e), d.HEADER.byteLength), t[1] = t.length, t[2] = this._decRollingCounter(), t[3] = this._calculateChecksum(t), this._queueWriteCommand(t, 0, t.length); } }, { key: "_writeCommand", value: function () { var e = t(regeneratorRuntime.mark(function e(t, n, r) { var i; return regeneratorRuntime.wrap(function (e) { for (;;) switch (e.prev = e.next) { case 0: if (!(r > 0)) { e.next = 12; break; } return e.prev = 1, r > 20 ? (i = t.subarray(n, n + 20), r -= 20, n += 20) : (i = t.subarray(n, n + r), r = 0), e.next = 5, this.device.writeCommand(i); case 5: e.next = 10; break; case 7: e.prev = 7, e.t0 = e.catch(1), U("Write Failure: ".concat(e.t0)); case 10: e.next = 0; break; case 12: case "end": return e.stop(); } }, e, this, [[1, 7]]); })); return function (t, n, r) { return e.apply(this, arguments); }; }() }, { key: "_queueWriteCommand", value: function value(e, t, n) { var r = this; U("command queued: ".concat(A(e))); var i = new Promise(function (t, n) { r.writeQueue.push({ command: e[4], rollingCounter: e[2], resolve: t, reject: n }), setTimeout(function () { r.writeQueue = r.writeQueue.filter(function (t) { return t.command === e[4] && t.rollingCounter !== e[2]; }), n(new Error("write command timed out after 5s. Command: ".concat(e[4].toString(16), " Rolling Counter: ").concat(e[2].toString(16)))); }, 1e4); }); return this._writeCommand(e, t, n), i; } }, { key: "_getStatus", value: function () { var e = t(regeneratorRuntime.mark(function e() { var t, n; return regeneratorRuntime.wrap(function (e) { for (;;) switch (e.prev = e.next) { case 0: return e.next = 2, this._sendCommand(d.GET_STATUS); case 2: return t = e.sent, n = { masterFirmwareVersion: "".concat(t.getUint8(2), ".").concat(t.getUint8(3)), bleFirmwareVersion: "".concat(t.getUint8(6), ".").concat(t.getUint8(9)), battery: t.getUint8(10), chargingStatus: "".concat(t.getUint8(11)) }, e.abrupt("return", n); case 5: case "end": return e.stop(); } }, e, this); })); return function () { return e.apply(this, arguments); }; }() }, { key: "_getAvailableSensors", value: function () { var e = t(regeneratorRuntime.mark(function e() { var t, n, r = this; return regeneratorRuntime.wrap(function (e) { for (;;) switch (e.prev = e.next) { case 0: return e.next = 2, this._sendCommand(d.GET_SENSOR_IDS).then(function (e) { r.availableSensors = e.getUint32(0, !0), U("Get Available Sensors Returned ".concat(r.availableSensors)); }); case 2: t = 1, n = 0; case 4: if (!(n < 31)) { e.next = 12; break; } if ((this.availableSensors & t) !== t) { e.next = 8; break; } return e.next = 8, this._getSensorInfo(n); case 8: t <<= 1; case 9: ++n, e.next = 4; break; case 12: case "end": return e.stop(); } }, e, this); })); return function () { return e.apply(this, arguments); }; }() }, { key: "_getDefaultSensorsMask", value: function value() { var e = this; return this._sendCommand(d.GET_DEFAULT_SENSORS_MASK).then(function (t) { e.defaultSensorsMask = t.getUint32(0, !0), U("Default Sensors:"), M(e); }); } }, { key: "_getDeviceInfo", value: function value() { var e = this; return this._sendCommand(d.GET_INFO).then(function (t) { var n = new C("utf-8"); e.orderCode = n.decode(new Uint8Array(t.buffer, 6, 16).filter(S)), e.serialNumber = n.decode(new Uint8Array(t.buffer, 22, 16).filter(S)), e.name = n.decode(new Uint8Array(t.buffer, 38, 32).filter(S)), U("Device Info:"), M(e); }); } }, { key: "_getSensorInfo", value: function () { var e = t(regeneratorRuntime.mark(function e(t) { var n, r = this; return regeneratorRuntime.wrap(function (e) { for (;;) switch (e.prev = e.next) { case 0: return (n = new Uint8Array(d.GET_SENSOR_INFO))[1] = t, e.abrupt("return", this._sendCommand(n).then(function (e) { var t = e.getUint32(2, !0); if (t > 0) { var n = new C("utf-8"), i = new L({ type: e.getUint8(6), mode: e.getUint8(7), minValue: e.getFloat64(108, !0), maxValue: e.getFloat64(116, !0), uncertainty: e.getFloat64(100, !0), minPeriod: e.getUint32(124, !0) / 1e3, maxPeriod: ((e.getUint32(132, !0) << 32) + e.getUint32(128, !0)) / 1e3, typicalPeriod: e.getUint32(136, !0) / 1e3, granularity: e.getUint32(140, !0) / 1e3 }), a = new P({ number: e.getUint8(0), name: n.decode(new Uint8Array(e.buffer, 14, 60).filter(S)), unit: n.decode(new Uint8Array(e.buffer, 74, 32).filter(S)), mutalExclusiveMask: e.getUint32(144, !0), measurementInfo: i, sensorId: t }), o = new T(a); U("Get Sensor Info Returned"), M(o), r.sensors.push(o), o.on("state-changed", function () { U("Sensor Restart: ".concat(o.number)), o.enabled && (r.measurementPeriod = o.specs.measurementInfo.typicalPeriod, r.sensors.forEach(function (e) { if (o.number !== e.number && e.enabled) { var t = 1 << e.number; (t & o.specs.mutalExclusiveMask) === t ? e.enabled = !1 : e.specs.measurementInfo.typicalPeriod > r.measurementPeriod && (r.measurementPeriod = e.specs.measurementInfo.typicalPeriod); } })), r._restartMeasurements(); }); } })); case 3: case "end": return e.stop(); } }, e, this); })); return function (t) { return e.apply(this, arguments); }; }() }, { key: "_restartMeasurements", value: function () { var e = t(regeneratorRuntime.mark(function e() { var t; return regeneratorRuntime.wrap(function (e) { for (;;) switch (e.prev = e.next) { case 0: if (t = this.collecting, !this.collecting) { e.next = 10; break; } return e.prev = 2, e.next = 5, this._stopMeasurements(); case 5: e.next = 10; break; case 7: e.prev = 7, e.t0 = e.catch(2), console.error(e.t0); case 10: if (this.collecting || !t) { e.next = 19; break; } return e.prev = 11, e.next = 14, this._startMeasurements(); case 14: e.next = 19; break; case 16: e.prev = 16, e.t1 = e.catch(11), console.error(e.t1); case 19: case "end": return e.stop(); } }, e, this, [[2, 7], [11, 16]]); })); return function () { return e.apply(this, arguments); }; }() }, { key: "_setMeasurementPeriod", value: function value(e) { var t = new Uint8Array(d.SET_MEASUREMENT_PERIOD), n = 1e3 * this.minMeasurementPeriod; return e < n && (e = n), U("MeasurementPeriod: ".concat(e)), t[3] = e >> 0 & 255, t[4] = e >> 8 & 255, t[5] = e >> 16 & 255, t[6] = e >> 24 & 255, this._sendCommand(t); } }, { key: "_getEnabledChannelMask", value: function value() { var e = 0; return this.sensors.filter(function (e) { return e.enabled; }).forEach(function (t) { e += 1 << t.number; }), e; } }, { key: "_startMeasurements", value: function value() { var e = this; return this._setMeasurementPeriod(1e3 * this.measurementPeriod).then(function () { var t = e._getEnabledChannelMask(); U("ChannelMask: ".concat(t)); var n = new Uint8Array(d.START_MEASUREMENTS); return n[3] = t >> 0 & 255, n[4] = t >> 8 & 255, n[5] = t >> 16 & 255, n[6] = t >> 24 & 255, e._sendCommand(n).then(function (t) { 0 === t.getUint8(0) && (e.collecting = !0, e.emit("measurements-started")); }); }); } }, { key: "_stopMeasurements", value: function value() { var e = this; return this._sendCommand(d.STOP_MEASUREMENTS).then(function (t) { 0 === t.getUint8(0) && (e.collecting = !1, e.emit("measurements-stopped")); }); } }]), r; }(), O = function () { function e(t) { n(this, e), this.webBluetoothNativeDevice = t, this.deviceCommand = null, this.deviceResponse = null; } return i(e, [{ key: "writeCommand", value: function () { var e = t(regeneratorRuntime.mark(function e(t) { return regeneratorRuntime.wrap(function (e) { for (;;) switch (e.prev = e.next) { case 0: return e.abrupt("return", this.deviceCommand.writeValue(t)); case 1: case "end": return e.stop(); } }, e, this); })); return function (t) { return e.apply(this, arguments); }; }() }, { key: "setup", value: function () { var e = t(regeneratorRuntime.mark(function e(t) { var n, r, i, a, o = this; return regeneratorRuntime.wrap(function (e) { for (;;) switch (e.prev = e.next) { case 0: return n = t.onClosed, r = t.onResponse, this.webBluetoothNativeDevice.addEventListener("gattserverdisconnected", n), e.prev = 2, e.next = 5, this.webBluetoothNativeDevice.gatt.connect(); case 5: return i = e.sent, e.next = 8, i.getPrimaryService("d91714ef-28b9-4f91-ba16-f0d9a604f112"); case 8: return a = e.sent, e.next = 11, a.getCharacteristics(); case 11: e.sent.forEach(function (e) { switch (e.uuid) { case "f4bf14a6-c7d5-4b6d-8aa8-df1a7c83adcb": o.deviceCommand = e; break; case "b41e6675-a329-40e0-aa01-44d2f444babe": o.deviceResponse = e, o.deviceResponse.addEventListener("characteristicvaluechanged", function (e) { var t = e.target.value; r(t); }), o.deviceResponse.startNotifications(); break; default: U("No case found for ".concat(e.uuid)); } }), e.next = 18; break; case 15: e.prev = 15, e.t0 = e.catch(2), console.error(e.t0); case 18: if (this.deviceCommand && this.deviceResponse) { e.next = 20; break; } throw new Error("Expected command and response characteristics not found."); case 20: case "end": return e.stop(); } }, e, this, [[2, 15]]); })); return function (t) { return e.apply(this, arguments); }; }() }, { key: "close", value: function () { var e = t(regeneratorRuntime.mark(function e() { return regeneratorRuntime.wrap(function (e) { for (;;) switch (e.prev = e.next) { case 0: return e.abrupt("return", this.webBluetoothNativeDevice.gatt.disconnect()); case 1: case "end": return e.stop(); } }, e, this); })); return function () { return e.apply(this, arguments); }; }() }, { key: "godirectAdapter", get: function get() { return !0; } }]), e; }(), D = { createDevice: function () { var e = t(regeneratorRuntime.mark(function e(t) { var n, r, i, a, o, s, u, c = arguments; return regeneratorRuntime.wrap(function (e) { for (;;) switch (e.prev = e.next) { case 0: if (n = c.length > 1 && void 0 !== c[1] ? c[1] : {}, r = n.open, i = void 0 === r || r, a = n.startMeasurements, o = void 0 === a || a, (s = t).godirectAdapter || (s = new O(t)), u = new N(s), !i) { e.next = 14; break; } return e.prev = 5, e.next = 8, u.open(o); case 8: e.next = 14; break; case 10: throw e.prev = 10, e.t0 = e.catch(5), console.error(e.t0), e.t0; case 14: return e.abrupt("return", u); case 15: case "end": return e.stop(); } }, e, this, [[5, 10]]); })); return function (t) { return e.apply(this, arguments); }; }(), selectDevice: function () { var e = t(regeneratorRuntime.mark(function e() { var t; return regeneratorRuntime.wrap(function (e) { for (;;) switch (e.prev = e.next) { case 0: if (navigator.bluetooth) { e.next = 2; break; } return e.abrupt("return", Promise.reject(new Error("No Web Bluetooth support."))); case 2: return e.next = 4, navigator.bluetooth.requestDevice({ filters: [{ namePrefix: "GDX" }], optionalServices: ["d91714ef-28b9-4f91-ba16-f0d9a604f112"] }); case 4: return t = e.sent, e.abrupt("return", D.createDevice(t)); case 6: case "end": return e.stop(); } }, e, this); })); return function () { return e.apply(this, arguments); }; }() }; return D; }); /***/ }), /***/ "./node_modules/acorn/dist/acorn.mjs": /*!*******************************************!*\ !*** ./node_modules/acorn/dist/acorn.mjs ***! \*******************************************/ /*! exports provided: Node, Parser, Position, SourceLocation, TokContext, Token, TokenType, defaultOptions, getLineInfo, isIdentifierChar, isIdentifierStart, isNewLine, keywordTypes, lineBreak, lineBreakG, nonASCIIwhitespace, parse, parseExpressionAt, tokContexts, tokTypes, tokenizer, version */ /***/ (function(__webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Node", function() { return Node; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Parser", function() { return Parser; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Position", function() { return Position; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SourceLocation", function() { return SourceLocation; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TokContext", function() { return TokContext; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Token", function() { return Token; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TokenType", function() { return TokenType; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "defaultOptions", function() { return defaultOptions; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getLineInfo", function() { return getLineInfo; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isIdentifierChar", function() { return isIdentifierChar; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isIdentifierStart", function() { return isIdentifierStart; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isNewLine", function() { return isNewLine; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "keywordTypes", function() { return keywords$1; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "lineBreak", function() { return lineBreak; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "lineBreakG", function() { return lineBreakG; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "nonASCIIwhitespace", function() { return nonASCIIwhitespace; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "parse", function() { return parse; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "parseExpressionAt", function() { return parseExpressionAt; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "tokContexts", function() { return types$1; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "tokTypes", function() { return types; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "tokenizer", function() { return tokenizer; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "version", function() { return version; }); // Reserved word lists for various dialects of the language var reservedWords = { 3: "abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile", 5: "class enum extends super const export import", 6: "enum", strict: "implements interface let package private protected public static yield", strictBind: "eval arguments" }; // And the keywords var ecma5AndLessKeywords = "break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this"; var keywords = { 5: ecma5AndLessKeywords, "5module": ecma5AndLessKeywords + " export import", 6: ecma5AndLessKeywords + " const class extends export import super" }; var keywordRelationalOperator = /^in(stanceof)?$/; // ## Character categories // Big ugly regular expressions that match characters in the // whitespace, identifier, and identifier-start categories. These // are only applied when a character is found to actually have a // code point above 128. // Generated by `bin/generate-identifier-regex.js`. var nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0560-\u0588\u05d0-\u05ea\u05ef-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0860-\u086a\u08a0-\u08b4\u08b6-\u08bd\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u09fc\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e86-\u0e8a\u0e8c-\u0ea3\u0ea5\u0ea7-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1878\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c88\u1c90-\u1cba\u1cbd-\u1cbf\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u1cfa\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312f\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fef\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7bf\ua7c2-\ua7c6\ua7f7-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua8fe\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab67\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc"; var nonASCIIidentifierChars = "\u200c\u200d\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u07fd\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08d3-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u09fe\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0afa-\u0aff\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c04\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d00-\u0d03\u0d3b\u0d3c\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf4\u1cf7-\u1cf9\u1dc0-\u1df9\u1dfb-\u1dff\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua8ff-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f"; var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]"); var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]"); nonASCIIidentifierStartChars = nonASCIIidentifierChars = null; // These are a run-length and offset encoded representation of the // >0xffff code points that are a valid part of identifiers. The // offset starts at 0x10000, and each pair of numbers represents an // offset to the next range, and then a size of the range. They were // generated by bin/generate-identifier-regex.js // eslint-disable-next-line comma-spacing var astralIdentifierStartCodes = [0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,14,29,6,37,11,29,3,35,5,7,2,4,43,157,19,35,5,35,5,39,9,51,157,310,10,21,11,7,153,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,66,18,2,1,11,21,11,25,71,55,7,1,65,0,16,3,2,2,2,28,43,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,56,50,14,50,14,35,477,28,11,0,9,21,155,22,13,52,76,44,33,24,27,35,30,0,12,34,4,0,13,47,15,3,22,0,2,0,36,17,2,24,85,6,2,0,2,3,2,14,2,9,8,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,19,0,13,4,159,52,19,3,21,0,33,47,21,1,2,0,185,46,42,3,37,47,21,0,60,42,14,0,72,26,230,43,117,63,32,0,161,7,3,38,17,0,2,0,29,0,11,39,8,0,22,0,12,45,20,0,35,56,264,8,2,36,18,0,50,29,113,6,2,1,2,37,22,0,26,5,2,1,2,31,15,0,328,18,270,921,103,110,18,195,2749,1070,4050,582,8634,568,8,30,114,29,19,47,17,3,32,20,6,18,689,63,129,74,6,0,67,12,65,1,2,0,29,6135,9,754,9486,286,50,2,18,3,9,395,2309,106,6,12,4,8,8,9,5991,84,2,70,2,1,3,0,3,1,3,3,2,11,2,0,2,6,2,64,2,3,3,7,2,6,2,27,2,3,2,4,2,0,4,6,2,339,3,24,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,7,2357,44,11,6,17,0,370,43,1301,196,60,67,8,0,1205,3,2,26,2,1,2,0,3,0,2,9,2,3,2,0,2,0,7,0,5,0,2,0,2,0,2,2,2,1,2,0,3,0,2,0,2,0,2,0,2,0,2,1,2,0,3,3,2,6,2,3,2,3,2,0,2,9,2,16,6,2,2,4,2,16,4421,42710,42,4148,12,221,3,5761,15,7472,3104,541]; // eslint-disable-next-line comma-spacing var astralIdentifierCodes = [509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,574,3,9,9,525,10,176,2,54,14,32,9,16,3,46,10,54,9,7,2,37,13,2,9,6,1,45,0,13,2,49,13,9,3,4,9,83,11,7,0,161,11,6,9,7,3,56,1,2,6,3,1,3,2,10,0,11,1,3,6,4,4,193,17,10,9,5,0,82,19,13,9,214,6,3,8,28,1,83,16,16,9,82,12,9,9,84,14,5,9,243,14,166,9,232,6,3,6,4,0,29,9,41,6,2,3,9,0,10,10,47,15,406,7,2,7,17,9,57,21,2,13,123,5,4,0,2,1,2,6,2,0,9,9,49,4,2,1,2,4,9,9,330,3,19306,9,135,4,60,6,26,9,1014,0,2,54,8,3,19723,1,5319,4,4,5,9,7,3,6,31,3,149,2,1418,49,513,54,5,49,9,0,15,0,23,4,2,14,1361,6,2,16,3,6,2,1,2,4,262,6,10,9,419,13,1495,6,110,6,6,9,792487,239]; // This has a complexity linear to the value of the code. The // assumption is that looking up astral identifier characters is // rare. function isInAstralSet(code, set) { var pos = 0x10000; for (var i = 0; i < set.length; i += 2) { pos += set[i]; if (pos > code) { return false } pos += set[i + 1]; if (pos >= code) { return true } } } // Test whether a given character code starts an identifier. function isIdentifierStart(code, astral) { if (code < 65) { return code === 36 } if (code < 91) { return true } if (code < 97) { return code === 95 } if (code < 123) { return true } if (code <= 0xffff) { return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code)) } if (astral === false) { return false } return isInAstralSet(code, astralIdentifierStartCodes) } // Test whether a given character is part of an identifier. function isIdentifierChar(code, astral) { if (code < 48) { return code === 36 } if (code < 58) { return true } if (code < 65) { return false } if (code < 91) { return true } if (code < 97) { return code === 95 } if (code < 123) { return true } if (code <= 0xffff) { return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code)) } if (astral === false) { return false } return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes) } // ## Token types // The assignment of fine-grained, information-carrying type objects // allows the tokenizer to store the information it has about a // token in a way that is very cheap for the parser to look up. // All token type variables start with an underscore, to make them // easy to recognize. // The `beforeExpr` property is used to disambiguate between regular // expressions and divisions. It is set on all token types that can // be followed by an expression (thus, a slash after them would be a // regular expression). // // The `startsExpr` property is used to check if the token ends a // `yield` expression. It is set on all token types that either can // directly start an expression (like a quotation mark) or can // continue an expression (like the body of a string). // // `isLoop` marks a keyword as starting a loop, which is important // to know when parsing a label, in order to allow or disallow // continue jumps to that label. var TokenType = function TokenType(label, conf) { if ( conf === void 0 ) conf = {}; this.label = label; this.keyword = conf.keyword; this.beforeExpr = !!conf.beforeExpr; this.startsExpr = !!conf.startsExpr; this.isLoop = !!conf.isLoop; this.isAssign = !!conf.isAssign; this.prefix = !!conf.prefix; this.postfix = !!conf.postfix; this.binop = conf.binop || null; this.updateContext = null; }; function binop(name, prec) { return new TokenType(name, {beforeExpr: true, binop: prec}) } var beforeExpr = {beforeExpr: true}, startsExpr = {startsExpr: true}; // Map keyword names to token types. var keywords$1 = {}; // Succinct definitions of keyword token types function kw(name, options) { if ( options === void 0 ) options = {}; options.keyword = name; return keywords$1[name] = new TokenType(name, options) } var types = { num: new TokenType("num", startsExpr), regexp: new TokenType("regexp", startsExpr), string: new TokenType("string", startsExpr), name: new TokenType("name", startsExpr), eof: new TokenType("eof"), // Punctuation token types. bracketL: new TokenType("[", {beforeExpr: true, startsExpr: true}), bracketR: new TokenType("]"), braceL: new TokenType("{", {beforeExpr: true, startsExpr: true}), braceR: new TokenType("}"), parenL: new TokenType("(", {beforeExpr: true, startsExpr: true}), parenR: new TokenType(")"), comma: new TokenType(",", beforeExpr), semi: new TokenType(";", beforeExpr), colon: new TokenType(":", beforeExpr), dot: new TokenType("."), question: new TokenType("?", beforeExpr), arrow: new TokenType("=>", beforeExpr), template: new TokenType("template"), invalidTemplate: new TokenType("invalidTemplate"), ellipsis: new TokenType("...", beforeExpr), backQuote: new TokenType("`", startsExpr), dollarBraceL: new TokenType("${", {beforeExpr: true, startsExpr: true}), // Operators. These carry several kinds of properties to help the // parser use them properly (the presence of these properties is // what categorizes them as operators). // // `binop`, when present, specifies that this operator is a binary // operator, and will refer to its precedence. // // `prefix` and `postfix` mark the operator as a prefix or postfix // unary operator. // // `isAssign` marks all of `=`, `+=`, `-=` etcetera, which act as // binary operators with a very low precedence, that should result // in AssignmentExpression nodes. eq: new TokenType("=", {beforeExpr: true, isAssign: true}), assign: new TokenType("_=", {beforeExpr: true, isAssign: true}), incDec: new TokenType("++/--", {prefix: true, postfix: true, startsExpr: true}), prefix: new TokenType("!/~", {beforeExpr: true, prefix: true, startsExpr: true}), logicalOR: binop("||", 1), logicalAND: binop("&&", 2), bitwiseOR: binop("|", 3), bitwiseXOR: binop("^", 4), bitwiseAND: binop("&", 5), equality: binop("==/!=/===/!==", 6), relational: binop("/<=/>=", 7), bitShift: binop("<>/>>>", 8), plusMin: new TokenType("+/-", {beforeExpr: true, binop: 9, prefix: true, startsExpr: true}), modulo: binop("%", 10), star: binop("*", 10), slash: binop("/", 10), starstar: new TokenType("**", {beforeExpr: true}), // Keyword token types. _break: kw("break"), _case: kw("case", beforeExpr), _catch: kw("catch"), _continue: kw("continue"), _debugger: kw("debugger"), _default: kw("default", beforeExpr), _do: kw("do", {isLoop: true, beforeExpr: true}), _else: kw("else", beforeExpr), _finally: kw("finally"), _for: kw("for", {isLoop: true}), _function: kw("function", startsExpr), _if: kw("if"), _return: kw("return", beforeExpr), _switch: kw("switch"), _throw: kw("throw", beforeExpr), _try: kw("try"), _var: kw("var"), _const: kw("const"), _while: kw("while", {isLoop: true}), _with: kw("with"), _new: kw("new", {beforeExpr: true, startsExpr: true}), _this: kw("this", startsExpr), _super: kw("super", startsExpr), _class: kw("class", startsExpr), _extends: kw("extends", beforeExpr), _export: kw("export"), _import: kw("import", startsExpr), _null: kw("null", startsExpr), _true: kw("true", startsExpr), _false: kw("false", startsExpr), _in: kw("in", {beforeExpr: true, binop: 7}), _instanceof: kw("instanceof", {beforeExpr: true, binop: 7}), _typeof: kw("typeof", {beforeExpr: true, prefix: true, startsExpr: true}), _void: kw("void", {beforeExpr: true, prefix: true, startsExpr: true}), _delete: kw("delete", {beforeExpr: true, prefix: true, startsExpr: true}) }; // Matches a whole line break (where CRLF is considered a single // line break). Used to count lines. var lineBreak = /\r\n?|\n|\u2028|\u2029/; var lineBreakG = new RegExp(lineBreak.source, "g"); function isNewLine(code, ecma2019String) { return code === 10 || code === 13 || (!ecma2019String && (code === 0x2028 || code === 0x2029)) } var nonASCIIwhitespace = /[\u1680\u2000-\u200a\u202f\u205f\u3000\ufeff]/; var skipWhiteSpace = /(?:\s|\/\/.*|\/\*[^]*?\*\/)*/g; var ref = Object.prototype; var hasOwnProperty = ref.hasOwnProperty; var toString = ref.toString; // Checks if an object has a property. function has(obj, propName) { return hasOwnProperty.call(obj, propName) } var isArray = Array.isArray || (function (obj) { return ( toString.call(obj) === "[object Array]" ); }); function wordsRegexp(words) { return new RegExp("^(?:" + words.replace(/ /g, "|") + ")$") } // These are used when `options.locations` is on, for the // `startLoc` and `endLoc` properties. var Position = function Position(line, col) { this.line = line; this.column = col; }; Position.prototype.offset = function offset (n) { return new Position(this.line, this.column + n) }; var SourceLocation = function SourceLocation(p, start, end) { this.start = start; this.end = end; if (p.sourceFile !== null) { this.source = p.sourceFile; } }; // The `getLineInfo` function is mostly useful when the // `locations` option is off (for performance reasons) and you // want to find the line/column position for a given character // offset. `input` should be the code string that the offset refers // into. function getLineInfo(input, offset) { for (var line = 1, cur = 0;;) { lineBreakG.lastIndex = cur; var match = lineBreakG.exec(input); if (match && match.index < offset) { ++line; cur = match.index + match[0].length; } else { return new Position(line, offset - cur) } } } // A second optional argument can be given to further configure // the parser process. These options are recognized: var defaultOptions = { // `ecmaVersion` indicates the ECMAScript version to parse. Must be // either 3, 5, 6 (2015), 7 (2016), 8 (2017), 9 (2018), or 10 // (2019). This influences support for strict mode, the set of // reserved words, and support for new syntax features. The default // is 9. ecmaVersion: 9, // `sourceType` indicates the mode the code should be parsed in. // Can be either `"script"` or `"module"`. This influences global // strict mode and parsing of `import` and `export` declarations. sourceType: "script", // `onInsertedSemicolon` can be a callback that will be called // when a semicolon is automatically inserted. It will be passed // the position of the comma as an offset, and if `locations` is // enabled, it is given the location as a `{line, column}` object // as second argument. onInsertedSemicolon: null, // `onTrailingComma` is similar to `onInsertedSemicolon`, but for // trailing commas. onTrailingComma: null, // By default, reserved words are only enforced if ecmaVersion >= 5. // Set `allowReserved` to a boolean value to explicitly turn this on // an off. When this option has the value "never", reserved words // and keywords can also not be used as property names. allowReserved: null, // When enabled, a return at the top level is not considered an // error. allowReturnOutsideFunction: false, // When enabled, import/export statements are not constrained to // appearing at the top of the program. allowImportExportEverywhere: false, // When enabled, await identifiers are allowed to appear at the top-level scope, // but they are still not allowed in non-async functions. allowAwaitOutsideFunction: false, // When enabled, hashbang directive in the beginning of file // is allowed and treated as a line comment. allowHashBang: false, // When `locations` is on, `loc` properties holding objects with // `start` and `end` properties in `{line, column}` form (with // line being 1-based and column 0-based) will be attached to the // nodes. locations: false, // A function can be passed as `onToken` option, which will // cause Acorn to call that function with object in the same // format as tokens returned from `tokenizer().getToken()`. Note // that you are not allowed to call the parser from the // callback—that will corrupt its internal state. onToken: null, // A function can be passed as `onComment` option, which will // cause Acorn to call that function with `(block, text, start, // end)` parameters whenever a comment is skipped. `block` is a // boolean indicating whether this is a block (`/* */`) comment, // `text` is the content of the comment, and `start` and `end` are // character offsets that denote the start and end of the comment. // When the `locations` option is on, two more parameters are // passed, the full `{line, column}` locations of the start and // end of the comments. Note that you are not allowed to call the // parser from the callback—that will corrupt its internal state. onComment: null, // Nodes have their start and end characters offsets recorded in // `start` and `end` properties (directly on the node, rather than // the `loc` object, which holds line/column data. To also add a // [semi-standardized][range] `range` property holding a `[start, // end]` array with the same numbers, set the `ranges` option to // `true`. // // [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678 ranges: false, // It is possible to parse multiple files into a single AST by // passing the tree produced by parsing the first file as // `program` option in subsequent parses. This will add the // toplevel forms of the parsed file to the `Program` (top) node // of an existing parse tree. program: null, // When `locations` is on, you can pass this to record the source // file in every node's `loc` object. sourceFile: null, // This value, if given, is stored in every node, whether // `locations` is on or off. directSourceFile: null, // When enabled, parenthesized expressions are represented by // (non-standard) ParenthesizedExpression nodes preserveParens: false }; // Interpret and default an options object function getOptions(opts) { var options = {}; for (var opt in defaultOptions) { options[opt] = opts && has(opts, opt) ? opts[opt] : defaultOptions[opt]; } if (options.ecmaVersion >= 2015) { options.ecmaVersion -= 2009; } if (options.allowReserved == null) { options.allowReserved = options.ecmaVersion < 5; } if (isArray(options.onToken)) { var tokens = options.onToken; options.onToken = function (token) { return tokens.push(token); }; } if (isArray(options.onComment)) { options.onComment = pushComment(options, options.onComment); } return options } function pushComment(options, array) { return function(block, text, start, end, startLoc, endLoc) { var comment = { type: block ? "Block" : "Line", value: text, start: start, end: end }; if (options.locations) { comment.loc = new SourceLocation(this, startLoc, endLoc); } if (options.ranges) { comment.range = [start, end]; } array.push(comment); } } // Each scope gets a bitset that may contain these flags var SCOPE_TOP = 1, SCOPE_FUNCTION = 2, SCOPE_VAR = SCOPE_TOP | SCOPE_FUNCTION, SCOPE_ASYNC = 4, SCOPE_GENERATOR = 8, SCOPE_ARROW = 16, SCOPE_SIMPLE_CATCH = 32, SCOPE_SUPER = 64, SCOPE_DIRECT_SUPER = 128; function functionFlags(async, generator) { return SCOPE_FUNCTION | (async ? SCOPE_ASYNC : 0) | (generator ? SCOPE_GENERATOR : 0) } // Used in checkLVal and declareName to determine the type of a binding var BIND_NONE = 0, // Not a binding BIND_VAR = 1, // Var-style binding BIND_LEXICAL = 2, // Let- or const-style binding BIND_FUNCTION = 3, // Function declaration BIND_SIMPLE_CATCH = 4, // Simple (identifier pattern) catch binding BIND_OUTSIDE = 5; // Special case for function names as bound inside the function var Parser = function Parser(options, input, startPos) { this.options = options = getOptions(options); this.sourceFile = options.sourceFile; this.keywords = wordsRegexp(keywords[options.ecmaVersion >= 6 ? 6 : options.sourceType === "module" ? "5module" : 5]); var reserved = ""; if (options.allowReserved !== true) { for (var v = options.ecmaVersion;; v--) { if (reserved = reservedWords[v]) { break } } if (options.sourceType === "module") { reserved += " await"; } } this.reservedWords = wordsRegexp(reserved); var reservedStrict = (reserved ? reserved + " " : "") + reservedWords.strict; this.reservedWordsStrict = wordsRegexp(reservedStrict); this.reservedWordsStrictBind = wordsRegexp(reservedStrict + " " + reservedWords.strictBind); this.input = String(input); // Used to signal to callers of `readWord1` whether the word // contained any escape sequences. This is needed because words with // escape sequences must not be interpreted as keywords. this.containsEsc = false; // Set up token state // The current position of the tokenizer in the input. if (startPos) { this.pos = startPos; this.lineStart = this.input.lastIndexOf("\n", startPos - 1) + 1; this.curLine = this.input.slice(0, this.lineStart).split(lineBreak).length; } else { this.pos = this.lineStart = 0; this.curLine = 1; } // Properties of the current token: // Its type this.type = types.eof; // For tokens that include more information than their type, the value this.value = null; // Its start and end offset this.start = this.end = this.pos; // And, if locations are used, the {line, column} object // corresponding to those offsets this.startLoc = this.endLoc = this.curPosition(); // Position information for the previous token this.lastTokEndLoc = this.lastTokStartLoc = null; this.lastTokStart = this.lastTokEnd = this.pos; // The context stack is used to superficially track syntactic // context to predict whether a regular expression is allowed in a // given position. this.context = this.initialContext(); this.exprAllowed = true; // Figure out if it's a module code. this.inModule = options.sourceType === "module"; this.strict = this.inModule || this.strictDirective(this.pos); // Used to signify the start of a potential arrow function this.potentialArrowAt = -1; // Positions to delayed-check that yield/await does not exist in default parameters. this.yieldPos = this.awaitPos = this.awaitIdentPos = 0; // Labels in scope. this.labels = []; // Thus-far undefined exports. this.undefinedExports = {}; // If enabled, skip leading hashbang line. if (this.pos === 0 && options.allowHashBang && this.input.slice(0, 2) === "#!") { this.skipLineComment(2); } // Scope tracking for duplicate variable names (see scope.js) this.scopeStack = []; this.enterScope(SCOPE_TOP); // For RegExp validation this.regexpState = null; }; var prototypeAccessors = { inFunction: { configurable: true },inGenerator: { configurable: true },inAsync: { configurable: true },allowSuper: { configurable: true },allowDirectSuper: { configurable: true },treatFunctionsAsVar: { configurable: true } }; Parser.prototype.parse = function parse () { var node = this.options.program || this.startNode(); this.nextToken(); return this.parseTopLevel(node) }; prototypeAccessors.inFunction.get = function () { return (this.currentVarScope().flags & SCOPE_FUNCTION) > 0 }; prototypeAccessors.inGenerator.get = function () { return (this.currentVarScope().flags & SCOPE_GENERATOR) > 0 }; prototypeAccessors.inAsync.get = function () { return (this.currentVarScope().flags & SCOPE_ASYNC) > 0 }; prototypeAccessors.allowSuper.get = function () { return (this.currentThisScope().flags & SCOPE_SUPER) > 0 }; prototypeAccessors.allowDirectSuper.get = function () { return (this.currentThisScope().flags & SCOPE_DIRECT_SUPER) > 0 }; prototypeAccessors.treatFunctionsAsVar.get = function () { return this.treatFunctionsAsVarInScope(this.currentScope()) }; // Switch to a getter for 7.0.0. Parser.prototype.inNonArrowFunction = function inNonArrowFunction () { return (this.currentThisScope().flags & SCOPE_FUNCTION) > 0 }; Parser.extend = function extend () { var plugins = [], len = arguments.length; while ( len-- ) plugins[ len ] = arguments[ len ]; var cls = this; for (var i = 0; i < plugins.length; i++) { cls = plugins[i](cls); } return cls }; Parser.parse = function parse (input, options) { return new this(options, input).parse() }; Parser.parseExpressionAt = function parseExpressionAt (input, pos, options) { var parser = new this(options, input, pos); parser.nextToken(); return parser.parseExpression() }; Parser.tokenizer = function tokenizer (input, options) { return new this(options, input) }; Object.defineProperties( Parser.prototype, prototypeAccessors ); var pp = Parser.prototype; // ## Parser utilities var literal = /^(?:'((?:\\.|[^'])*?)'|"((?:\\.|[^"])*?)")/; pp.strictDirective = function(start) { for (;;) { // Try to find string literal. skipWhiteSpace.lastIndex = start; start += skipWhiteSpace.exec(this.input)[0].length; var match = literal.exec(this.input.slice(start)); if (!match) { return false } if ((match[1] || match[2]) === "use strict") { return true } start += match[0].length; // Skip semicolon, if any. skipWhiteSpace.lastIndex = start; start += skipWhiteSpace.exec(this.input)[0].length; if (this.input[start] === ";") { start++; } } }; // Predicate that tests whether the next token is of the given // type, and if yes, consumes it as a side effect. pp.eat = function(type) { if (this.type === type) { this.next(); return true } else { return false } }; // Tests whether parsed token is a contextual keyword. pp.isContextual = function(name) { return this.type === types.name && this.value === name && !this.containsEsc }; // Consumes contextual keyword if possible. pp.eatContextual = function(name) { if (!this.isContextual(name)) { return false } this.next(); return true }; // Asserts that following token is given contextual keyword. pp.expectContextual = function(name) { if (!this.eatContextual(name)) { this.unexpected(); } }; // Test whether a semicolon can be inserted at the current position. pp.canInsertSemicolon = function() { return this.type === types.eof || this.type === types.braceR || lineBreak.test(this.input.slice(this.lastTokEnd, this.start)) }; pp.insertSemicolon = function() { if (this.canInsertSemicolon()) { if (this.options.onInsertedSemicolon) { this.options.onInsertedSemicolon(this.lastTokEnd, this.lastTokEndLoc); } return true } }; // Consume a semicolon, or, failing that, see if we are allowed to // pretend that there is a semicolon at this position. pp.semicolon = function() { if (!this.eat(types.semi) && !this.insertSemicolon()) { this.unexpected(); } }; pp.afterTrailingComma = function(tokType, notNext) { if (this.type === tokType) { if (this.options.onTrailingComma) { this.options.onTrailingComma(this.lastTokStart, this.lastTokStartLoc); } if (!notNext) { this.next(); } return true } }; // Expect a token of a given type. If found, consume it, otherwise, // raise an unexpected token error. pp.expect = function(type) { this.eat(type) || this.unexpected(); }; // Raise an unexpected token error. pp.unexpected = function(pos) { this.raise(pos != null ? pos : this.start, "Unexpected token"); }; function DestructuringErrors() { this.shorthandAssign = this.trailingComma = this.parenthesizedAssign = this.parenthesizedBind = this.doubleProto = -1; } pp.checkPatternErrors = function(refDestructuringErrors, isAssign) { if (!refDestructuringErrors) { return } if (refDestructuringErrors.trailingComma > -1) { this.raiseRecoverable(refDestructuringErrors.trailingComma, "Comma is not permitted after the rest element"); } var parens = isAssign ? refDestructuringErrors.parenthesizedAssign : refDestructuringErrors.parenthesizedBind; if (parens > -1) { this.raiseRecoverable(parens, "Parenthesized pattern"); } }; pp.checkExpressionErrors = function(refDestructuringErrors, andThrow) { if (!refDestructuringErrors) { return false } var shorthandAssign = refDestructuringErrors.shorthandAssign; var doubleProto = refDestructuringErrors.doubleProto; if (!andThrow) { return shorthandAssign >= 0 || doubleProto >= 0 } if (shorthandAssign >= 0) { this.raise(shorthandAssign, "Shorthand property assignments are valid only in destructuring patterns"); } if (doubleProto >= 0) { this.raiseRecoverable(doubleProto, "Redefinition of __proto__ property"); } }; pp.checkYieldAwaitInDefaultParams = function() { if (this.yieldPos && (!this.awaitPos || this.yieldPos < this.awaitPos)) { this.raise(this.yieldPos, "Yield expression cannot be a default value"); } if (this.awaitPos) { this.raise(this.awaitPos, "Await expression cannot be a default value"); } }; pp.isSimpleAssignTarget = function(expr) { if (expr.type === "ParenthesizedExpression") { return this.isSimpleAssignTarget(expr.expression) } return expr.type === "Identifier" || expr.type === "MemberExpression" }; var pp$1 = Parser.prototype; // ### Statement parsing // Parse a program. Initializes the parser, reads any number of // statements, and wraps them in a Program node. Optionally takes a // `program` argument. If present, the statements will be appended // to its body instead of creating a new node. pp$1.parseTopLevel = function(node) { var exports = {}; if (!node.body) { node.body = []; } while (this.type !== types.eof) { var stmt = this.parseStatement(null, true, exports); node.body.push(stmt); } if (this.inModule) { for (var i = 0, list = Object.keys(this.undefinedExports); i < list.length; i += 1) { var name = list[i]; this.raiseRecoverable(this.undefinedExports[name].start, ("Export '" + name + "' is not defined")); } } this.adaptDirectivePrologue(node.body); this.next(); node.sourceType = this.options.sourceType; return this.finishNode(node, "Program") }; var loopLabel = {kind: "loop"}, switchLabel = {kind: "switch"}; pp$1.isLet = function(context) { if (this.options.ecmaVersion < 6 || !this.isContextual("let")) { return false } skipWhiteSpace.lastIndex = this.pos; var skip = skipWhiteSpace.exec(this.input); var next = this.pos + skip[0].length, nextCh = this.input.charCodeAt(next); // For ambiguous cases, determine if a LexicalDeclaration (or only a // Statement) is allowed here. If context is not empty then only a Statement // is allowed. However, `let [` is an explicit negative lookahead for // ExpressionStatement, so special-case it first. if (nextCh === 91) { return true } // '[' if (context) { return false } if (nextCh === 123) { return true } // '{' if (isIdentifierStart(nextCh, true)) { var pos = next + 1; while (isIdentifierChar(this.input.charCodeAt(pos), true)) { ++pos; } var ident = this.input.slice(next, pos); if (!keywordRelationalOperator.test(ident)) { return true } } return false }; // check 'async [no LineTerminator here] function' // - 'async /*foo*/ function' is OK. // - 'async /*\n*/ function' is invalid. pp$1.isAsyncFunction = function() { if (this.options.ecmaVersion < 8 || !this.isContextual("async")) { return false } skipWhiteSpace.lastIndex = this.pos; var skip = skipWhiteSpace.exec(this.input); var next = this.pos + skip[0].length; return !lineBreak.test(this.input.slice(this.pos, next)) && this.input.slice(next, next + 8) === "function" && (next + 8 === this.input.length || !isIdentifierChar(this.input.charAt(next + 8))) }; // Parse a single statement. // // If expecting a statement and finding a slash operator, parse a // regular expression literal. This is to handle cases like // `if (foo) /blah/.exec(foo)`, where looking at the previous token // does not help. pp$1.parseStatement = function(context, topLevel, exports) { var starttype = this.type, node = this.startNode(), kind; if (this.isLet(context)) { starttype = types._var; kind = "let"; } // Most types of statements are recognized by the keyword they // start with. Many are trivial to parse, some require a bit of // complexity. switch (starttype) { case types._break: case types._continue: return this.parseBreakContinueStatement(node, starttype.keyword) case types._debugger: return this.parseDebuggerStatement(node) case types._do: return this.parseDoStatement(node) case types._for: return this.parseForStatement(node) case types._function: // Function as sole body of either an if statement or a labeled statement // works, but not when it is part of a labeled statement that is the sole // body of an if statement. if ((context && (this.strict || context !== "if" && context !== "label")) && this.options.ecmaVersion >= 6) { this.unexpected(); } return this.parseFunctionStatement(node, false, !context) case types._class: if (context) { this.unexpected(); } return this.parseClass(node, true) case types._if: return this.parseIfStatement(node) case types._return: return this.parseReturnStatement(node) case types._switch: return this.parseSwitchStatement(node) case types._throw: return this.parseThrowStatement(node) case types._try: return this.parseTryStatement(node) case types._const: case types._var: kind = kind || this.value; if (context && kind !== "var") { this.unexpected(); } return this.parseVarStatement(node, kind) case types._while: return this.parseWhileStatement(node) case types._with: return this.parseWithStatement(node) case types.braceL: return this.parseBlock(true, node) case types.semi: return this.parseEmptyStatement(node) case types._export: case types._import: if (this.options.ecmaVersion > 10 && starttype === types._import) { skipWhiteSpace.lastIndex = this.pos; var skip = skipWhiteSpace.exec(this.input); var next = this.pos + skip[0].length, nextCh = this.input.charCodeAt(next); if (nextCh === 40) // '(' { return this.parseExpressionStatement(node, this.parseExpression()) } } if (!this.options.allowImportExportEverywhere) { if (!topLevel) { this.raise(this.start, "'import' and 'export' may only appear at the top level"); } if (!this.inModule) { this.raise(this.start, "'import' and 'export' may appear only with 'sourceType: module'"); } } return starttype === types._import ? this.parseImport(node) : this.parseExport(node, exports) // If the statement does not start with a statement keyword or a // brace, it's an ExpressionStatement or LabeledStatement. We // simply start parsing an expression, and afterwards, if the // next token is a colon and the expression was a simple // Identifier node, we switch to interpreting it as a label. default: if (this.isAsyncFunction()) { if (context) { this.unexpected(); } this.next(); return this.parseFunctionStatement(node, true, !context) } var maybeName = this.value, expr = this.parseExpression(); if (starttype === types.name && expr.type === "Identifier" && this.eat(types.colon)) { return this.parseLabeledStatement(node, maybeName, expr, context) } else { return this.parseExpressionStatement(node, expr) } } }; pp$1.parseBreakContinueStatement = function(node, keyword) { var isBreak = keyword === "break"; this.next(); if (this.eat(types.semi) || this.insertSemicolon()) { node.label = null; } else if (this.type !== types.name) { this.unexpected(); } else { node.label = this.parseIdent(); this.semicolon(); } // Verify that there is an actual destination to break or // continue to. var i = 0; for (; i < this.labels.length; ++i) { var lab = this.labels[i]; if (node.label == null || lab.name === node.label.name) { if (lab.kind != null && (isBreak || lab.kind === "loop")) { break } if (node.label && isBreak) { break } } } if (i === this.labels.length) { this.raise(node.start, "Unsyntactic " + keyword); } return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement") }; pp$1.parseDebuggerStatement = function(node) { this.next(); this.semicolon(); return this.finishNode(node, "DebuggerStatement") }; pp$1.parseDoStatement = function(node) { this.next(); this.labels.push(loopLabel); node.body = this.parseStatement("do"); this.labels.pop(); this.expect(types._while); node.test = this.parseParenExpression(); if (this.options.ecmaVersion >= 6) { this.eat(types.semi); } else { this.semicolon(); } return this.finishNode(node, "DoWhileStatement") }; // Disambiguating between a `for` and a `for`/`in` or `for`/`of` // loop is non-trivial. Basically, we have to parse the init `var` // statement or expression, disallowing the `in` operator (see // the second parameter to `parseExpression`), and then check // whether the next token is `in` or `of`. When there is no init // part (semicolon immediately after the opening parenthesis), it // is a regular `for` loop. pp$1.parseForStatement = function(node) { this.next(); var awaitAt = (this.options.ecmaVersion >= 9 && (this.inAsync || (!this.inFunction && this.options.allowAwaitOutsideFunction)) && this.eatContextual("await")) ? this.lastTokStart : -1; this.labels.push(loopLabel); this.enterScope(0); this.expect(types.parenL); if (this.type === types.semi) { if (awaitAt > -1) { this.unexpected(awaitAt); } return this.parseFor(node, null) } var isLet = this.isLet(); if (this.type === types._var || this.type === types._const || isLet) { var init$1 = this.startNode(), kind = isLet ? "let" : this.value; this.next(); this.parseVar(init$1, true, kind); this.finishNode(init$1, "VariableDeclaration"); if ((this.type === types._in || (this.options.ecmaVersion >= 6 && this.isContextual("of"))) && init$1.declarations.length === 1) { if (this.options.ecmaVersion >= 9) { if (this.type === types._in) { if (awaitAt > -1) { this.unexpected(awaitAt); } } else { node.await = awaitAt > -1; } } return this.parseForIn(node, init$1) } if (awaitAt > -1) { this.unexpected(awaitAt); } return this.parseFor(node, init$1) } var refDestructuringErrors = new DestructuringErrors; var init = this.parseExpression(true, refDestructuringErrors); if (this.type === types._in || (this.options.ecmaVersion >= 6 && this.isContextual("of"))) { if (this.options.ecmaVersion >= 9) { if (this.type === types._in) { if (awaitAt > -1) { this.unexpected(awaitAt); } } else { node.await = awaitAt > -1; } } this.toAssignable(init, false, refDestructuringErrors); this.checkLVal(init); return this.parseForIn(node, init) } else { this.checkExpressionErrors(refDestructuringErrors, true); } if (awaitAt > -1) { this.unexpected(awaitAt); } return this.parseFor(node, init) }; pp$1.parseFunctionStatement = function(node, isAsync, declarationPosition) { this.next(); return this.parseFunction(node, FUNC_STATEMENT | (declarationPosition ? 0 : FUNC_HANGING_STATEMENT), false, isAsync) }; pp$1.parseIfStatement = function(node) { this.next(); node.test = this.parseParenExpression(); // allow function declarations in branches, but only in non-strict mode node.consequent = this.parseStatement("if"); node.alternate = this.eat(types._else) ? this.parseStatement("if") : null; return this.finishNode(node, "IfStatement") }; pp$1.parseReturnStatement = function(node) { if (!this.inFunction && !this.options.allowReturnOutsideFunction) { this.raise(this.start, "'return' outside of function"); } this.next(); // In `return` (and `break`/`continue`), the keywords with // optional arguments, we eagerly look for a semicolon or the // possibility to insert one. if (this.eat(types.semi) || this.insertSemicolon()) { node.argument = null; } else { node.argument = this.parseExpression(); this.semicolon(); } return this.finishNode(node, "ReturnStatement") }; pp$1.parseSwitchStatement = function(node) { this.next(); node.discriminant = this.parseParenExpression(); node.cases = []; this.expect(types.braceL); this.labels.push(switchLabel); this.enterScope(0); // Statements under must be grouped (by label) in SwitchCase // nodes. `cur` is used to keep the node that we are currently // adding statements to. var cur; for (var sawDefault = false; this.type !== types.braceR;) { if (this.type === types._case || this.type === types._default) { var isCase = this.type === types._case; if (cur) { this.finishNode(cur, "SwitchCase"); } node.cases.push(cur = this.startNode()); cur.consequent = []; this.next(); if (isCase) { cur.test = this.parseExpression(); } else { if (sawDefault) { this.raiseRecoverable(this.lastTokStart, "Multiple default clauses"); } sawDefault = true; cur.test = null; } this.expect(types.colon); } else { if (!cur) { this.unexpected(); } cur.consequent.push(this.parseStatement(null)); } } this.exitScope(); if (cur) { this.finishNode(cur, "SwitchCase"); } this.next(); // Closing brace this.labels.pop(); return this.finishNode(node, "SwitchStatement") }; pp$1.parseThrowStatement = function(node) { this.next(); if (lineBreak.test(this.input.slice(this.lastTokEnd, this.start))) { this.raise(this.lastTokEnd, "Illegal newline after throw"); } node.argument = this.parseExpression(); this.semicolon(); return this.finishNode(node, "ThrowStatement") }; // Reused empty array added for node fields that are always empty. var empty = []; pp$1.parseTryStatement = function(node) { this.next(); node.block = this.parseBlock(); node.handler = null; if (this.type === types._catch) { var clause = this.startNode(); this.next(); if (this.eat(types.parenL)) { clause.param = this.parseBindingAtom(); var simple = clause.param.type === "Identifier"; this.enterScope(simple ? SCOPE_SIMPLE_CATCH : 0); this.checkLVal(clause.param, simple ? BIND_SIMPLE_CATCH : BIND_LEXICAL); this.expect(types.parenR); } else { if (this.options.ecmaVersion < 10) { this.unexpected(); } clause.param = null; this.enterScope(0); } clause.body = this.parseBlock(false); this.exitScope(); node.handler = this.finishNode(clause, "CatchClause"); } node.finalizer = this.eat(types._finally) ? this.parseBlock() : null; if (!node.handler && !node.finalizer) { this.raise(node.start, "Missing catch or finally clause"); } return this.finishNode(node, "TryStatement") }; pp$1.parseVarStatement = function(node, kind) { this.next(); this.parseVar(node, false, kind); this.semicolon(); return this.finishNode(node, "VariableDeclaration") }; pp$1.parseWhileStatement = function(node) { this.next(); node.test = this.parseParenExpression(); this.labels.push(loopLabel); node.body = this.parseStatement("while"); this.labels.pop(); return this.finishNode(node, "WhileStatement") }; pp$1.parseWithStatement = function(node) { if (this.strict) { this.raise(this.start, "'with' in strict mode"); } this.next(); node.object = this.parseParenExpression(); node.body = this.parseStatement("with"); return this.finishNode(node, "WithStatement") }; pp$1.parseEmptyStatement = function(node) { this.next(); return this.finishNode(node, "EmptyStatement") }; pp$1.parseLabeledStatement = function(node, maybeName, expr, context) { for (var i$1 = 0, list = this.labels; i$1 < list.length; i$1 += 1) { var label = list[i$1]; if (label.name === maybeName) { this.raise(expr.start, "Label '" + maybeName + "' is already declared"); } } var kind = this.type.isLoop ? "loop" : this.type === types._switch ? "switch" : null; for (var i = this.labels.length - 1; i >= 0; i--) { var label$1 = this.labels[i]; if (label$1.statementStart === node.start) { // Update information about previous labels on this node label$1.statementStart = this.start; label$1.kind = kind; } else { break } } this.labels.push({name: maybeName, kind: kind, statementStart: this.start}); node.body = this.parseStatement(context ? context.indexOf("label") === -1 ? context + "label" : context : "label"); this.labels.pop(); node.label = expr; return this.finishNode(node, "LabeledStatement") }; pp$1.parseExpressionStatement = function(node, expr) { node.expression = expr; this.semicolon(); return this.finishNode(node, "ExpressionStatement") }; // Parse a semicolon-enclosed block of statements, handling `"use // strict"` declarations when `allowStrict` is true (used for // function bodies). pp$1.parseBlock = function(createNewLexicalScope, node) { if ( createNewLexicalScope === void 0 ) createNewLexicalScope = true; if ( node === void 0 ) node = this.startNode(); node.body = []; this.expect(types.braceL); if (createNewLexicalScope) { this.enterScope(0); } while (!this.eat(types.braceR)) { var stmt = this.parseStatement(null); node.body.push(stmt); } if (createNewLexicalScope) { this.exitScope(); } return this.finishNode(node, "BlockStatement") }; // Parse a regular `for` loop. The disambiguation code in // `parseStatement` will already have parsed the init statement or // expression. pp$1.parseFor = function(node, init) { node.init = init; this.expect(types.semi); node.test = this.type === types.semi ? null : this.parseExpression(); this.expect(types.semi); node.update = this.type === types.parenR ? null : this.parseExpression(); this.expect(types.parenR); node.body = this.parseStatement("for"); this.exitScope(); this.labels.pop(); return this.finishNode(node, "ForStatement") }; // Parse a `for`/`in` and `for`/`of` loop, which are almost // same from parser's perspective. pp$1.parseForIn = function(node, init) { var isForIn = this.type === types._in; this.next(); if ( init.type === "VariableDeclaration" && init.declarations[0].init != null && ( !isForIn || this.options.ecmaVersion < 8 || this.strict || init.kind !== "var" || init.declarations[0].id.type !== "Identifier" ) ) { this.raise( init.start, ((isForIn ? "for-in" : "for-of") + " loop variable declaration may not have an initializer") ); } else if (init.type === "AssignmentPattern") { this.raise(init.start, "Invalid left-hand side in for-loop"); } node.left = init; node.right = isForIn ? this.parseExpression() : this.parseMaybeAssign(); this.expect(types.parenR); node.body = this.parseStatement("for"); this.exitScope(); this.labels.pop(); return this.finishNode(node, isForIn ? "ForInStatement" : "ForOfStatement") }; // Parse a list of variable declarations. pp$1.parseVar = function(node, isFor, kind) { node.declarations = []; node.kind = kind; for (;;) { var decl = this.startNode(); this.parseVarId(decl, kind); if (this.eat(types.eq)) { decl.init = this.parseMaybeAssign(isFor); } else if (kind === "const" && !(this.type === types._in || (this.options.ecmaVersion >= 6 && this.isContextual("of")))) { this.unexpected(); } else if (decl.id.type !== "Identifier" && !(isFor && (this.type === types._in || this.isContextual("of")))) { this.raise(this.lastTokEnd, "Complex binding patterns require an initialization value"); } else { decl.init = null; } node.declarations.push(this.finishNode(decl, "VariableDeclarator")); if (!this.eat(types.comma)) { break } } return node }; pp$1.parseVarId = function(decl, kind) { decl.id = this.parseBindingAtom(); this.checkLVal(decl.id, kind === "var" ? BIND_VAR : BIND_LEXICAL, false); }; var FUNC_STATEMENT = 1, FUNC_HANGING_STATEMENT = 2, FUNC_NULLABLE_ID = 4; // Parse a function declaration or literal (depending on the // `statement & FUNC_STATEMENT`). // Remove `allowExpressionBody` for 7.0.0, as it is only called with false pp$1.parseFunction = function(node, statement, allowExpressionBody, isAsync) { this.initFunction(node); if (this.options.ecmaVersion >= 9 || this.options.ecmaVersion >= 6 && !isAsync) { if (this.type === types.star && (statement & FUNC_HANGING_STATEMENT)) { this.unexpected(); } node.generator = this.eat(types.star); } if (this.options.ecmaVersion >= 8) { node.async = !!isAsync; } if (statement & FUNC_STATEMENT) { node.id = (statement & FUNC_NULLABLE_ID) && this.type !== types.name ? null : this.parseIdent(); if (node.id && !(statement & FUNC_HANGING_STATEMENT)) // If it is a regular function declaration in sloppy mode, then it is // subject to Annex B semantics (BIND_FUNCTION). Otherwise, the binding // mode depends on properties of the current scope (see // treatFunctionsAsVar). { this.checkLVal(node.id, (this.strict || node.generator || node.async) ? this.treatFunctionsAsVar ? BIND_VAR : BIND_LEXICAL : BIND_FUNCTION); } } var oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldAwaitIdentPos = this.awaitIdentPos; this.yieldPos = 0; this.awaitPos = 0; this.awaitIdentPos = 0; this.enterScope(functionFlags(node.async, node.generator)); if (!(statement & FUNC_STATEMENT)) { node.id = this.type === types.name ? this.parseIdent() : null; } this.parseFunctionParams(node); this.parseFunctionBody(node, allowExpressionBody, false); this.yieldPos = oldYieldPos; this.awaitPos = oldAwaitPos; this.awaitIdentPos = oldAwaitIdentPos; return this.finishNode(node, (statement & FUNC_STATEMENT) ? "FunctionDeclaration" : "FunctionExpression") }; pp$1.parseFunctionParams = function(node) { this.expect(types.parenL); node.params = this.parseBindingList(types.parenR, false, this.options.ecmaVersion >= 8); this.checkYieldAwaitInDefaultParams(); }; // Parse a class declaration or literal (depending on the // `isStatement` parameter). pp$1.parseClass = function(node, isStatement) { this.next(); // ecma-262 14.6 Class Definitions // A class definition is always strict mode code. var oldStrict = this.strict; this.strict = true; this.parseClassId(node, isStatement); this.parseClassSuper(node); var classBody = this.startNode(); var hadConstructor = false; classBody.body = []; this.expect(types.braceL); while (!this.eat(types.braceR)) { var element = this.parseClassElement(node.superClass !== null); if (element) { classBody.body.push(element); if (element.type === "MethodDefinition" && element.kind === "constructor") { if (hadConstructor) { this.raise(element.start, "Duplicate constructor in the same class"); } hadConstructor = true; } } } node.body = this.finishNode(classBody, "ClassBody"); this.strict = oldStrict; return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression") }; pp$1.parseClassElement = function(constructorAllowsSuper) { var this$1 = this; if (this.eat(types.semi)) { return null } var method = this.startNode(); var tryContextual = function (k, noLineBreak) { if ( noLineBreak === void 0 ) noLineBreak = false; var start = this$1.start, startLoc = this$1.startLoc; if (!this$1.eatContextual(k)) { return false } if (this$1.type !== types.parenL && (!noLineBreak || !this$1.canInsertSemicolon())) { return true } if (method.key) { this$1.unexpected(); } method.computed = false; method.key = this$1.startNodeAt(start, startLoc); method.key.name = k; this$1.finishNode(method.key, "Identifier"); return false }; method.kind = "method"; method.static = tryContextual("static"); var isGenerator = this.eat(types.star); var isAsync = false; if (!isGenerator) { if (this.options.ecmaVersion >= 8 && tryContextual("async", true)) { isAsync = true; isGenerator = this.options.ecmaVersion >= 9 && this.eat(types.star); } else if (tryContextual("get")) { method.kind = "get"; } else if (tryContextual("set")) { method.kind = "set"; } } if (!method.key) { this.parsePropertyName(method); } var key = method.key; var allowsDirectSuper = false; if (!method.computed && !method.static && (key.type === "Identifier" && key.name === "constructor" || key.type === "Literal" && key.value === "constructor")) { if (method.kind !== "method") { this.raise(key.start, "Constructor can't have get/set modifier"); } if (isGenerator) { this.raise(key.start, "Constructor can't be a generator"); } if (isAsync) { this.raise(key.start, "Constructor can't be an async method"); } method.kind = "constructor"; allowsDirectSuper = constructorAllowsSuper; } else if (method.static && key.type === "Identifier" && key.name === "prototype") { this.raise(key.start, "Classes may not have a static property named prototype"); } this.parseClassMethod(method, isGenerator, isAsync, allowsDirectSuper); if (method.kind === "get" && method.value.params.length !== 0) { this.raiseRecoverable(method.value.start, "getter should have no params"); } if (method.kind === "set" && method.value.params.length !== 1) { this.raiseRecoverable(method.value.start, "setter should have exactly one param"); } if (method.kind === "set" && method.value.params[0].type === "RestElement") { this.raiseRecoverable(method.value.params[0].start, "Setter cannot use rest params"); } return method }; pp$1.parseClassMethod = function(method, isGenerator, isAsync, allowsDirectSuper) { method.value = this.parseMethod(isGenerator, isAsync, allowsDirectSuper); return this.finishNode(method, "MethodDefinition") }; pp$1.parseClassId = function(node, isStatement) { if (this.type === types.name) { node.id = this.parseIdent(); if (isStatement) { this.checkLVal(node.id, BIND_LEXICAL, false); } } else { if (isStatement === true) { this.unexpected(); } node.id = null; } }; pp$1.parseClassSuper = function(node) { node.superClass = this.eat(types._extends) ? this.parseExprSubscripts() : null; }; // Parses module export declaration. pp$1.parseExport = function(node, exports) { this.next(); // export * from '...' if (this.eat(types.star)) { this.expectContextual("from"); if (this.type !== types.string) { this.unexpected(); } node.source = this.parseExprAtom(); this.semicolon(); return this.finishNode(node, "ExportAllDeclaration") } if (this.eat(types._default)) { // export default ... this.checkExport(exports, "default", this.lastTokStart); var isAsync; if (this.type === types._function || (isAsync = this.isAsyncFunction())) { var fNode = this.startNode(); this.next(); if (isAsync) { this.next(); } node.declaration = this.parseFunction(fNode, FUNC_STATEMENT | FUNC_NULLABLE_ID, false, isAsync); } else if (this.type === types._class) { var cNode = this.startNode(); node.declaration = this.parseClass(cNode, "nullableID"); } else { node.declaration = this.parseMaybeAssign(); this.semicolon(); } return this.finishNode(node, "ExportDefaultDeclaration") } // export var|const|let|function|class ... if (this.shouldParseExportStatement()) { node.declaration = this.parseStatement(null); if (node.declaration.type === "VariableDeclaration") { this.checkVariableExport(exports, node.declaration.declarations); } else { this.checkExport(exports, node.declaration.id.name, node.declaration.id.start); } node.specifiers = []; node.source = null; } else { // export { x, y as z } [from '...'] node.declaration = null; node.specifiers = this.parseExportSpecifiers(exports); if (this.eatContextual("from")) { if (this.type !== types.string) { this.unexpected(); } node.source = this.parseExprAtom(); } else { for (var i = 0, list = node.specifiers; i < list.length; i += 1) { // check for keywords used as local names var spec = list[i]; this.checkUnreserved(spec.local); // check if export is defined this.checkLocalExport(spec.local); } node.source = null; } this.semicolon(); } return this.finishNode(node, "ExportNamedDeclaration") }; pp$1.checkExport = function(exports, name, pos) { if (!exports) { return } if (has(exports, name)) { this.raiseRecoverable(pos, "Duplicate export '" + name + "'"); } exports[name] = true; }; pp$1.checkPatternExport = function(exports, pat) { var type = pat.type; if (type === "Identifier") { this.checkExport(exports, pat.name, pat.start); } else if (type === "ObjectPattern") { for (var i = 0, list = pat.properties; i < list.length; i += 1) { var prop = list[i]; this.checkPatternExport(exports, prop); } } else if (type === "ArrayPattern") { for (var i$1 = 0, list$1 = pat.elements; i$1 < list$1.length; i$1 += 1) { var elt = list$1[i$1]; if (elt) { this.checkPatternExport(exports, elt); } } } else if (type === "Property") { this.checkPatternExport(exports, pat.value); } else if (type === "AssignmentPattern") { this.checkPatternExport(exports, pat.left); } else if (type === "RestElement") { this.checkPatternExport(exports, pat.argument); } else if (type === "ParenthesizedExpression") { this.checkPatternExport(exports, pat.expression); } }; pp$1.checkVariableExport = function(exports, decls) { if (!exports) { return } for (var i = 0, list = decls; i < list.length; i += 1) { var decl = list[i]; this.checkPatternExport(exports, decl.id); } }; pp$1.shouldParseExportStatement = function() { return this.type.keyword === "var" || this.type.keyword === "const" || this.type.keyword === "class" || this.type.keyword === "function" || this.isLet() || this.isAsyncFunction() }; // Parses a comma-separated list of module exports. pp$1.parseExportSpecifiers = function(exports) { var nodes = [], first = true; // export { x, y as z } [from '...'] this.expect(types.braceL); while (!this.eat(types.braceR)) { if (!first) { this.expect(types.comma); if (this.afterTrailingComma(types.braceR)) { break } } else { first = false; } var node = this.startNode(); node.local = this.parseIdent(true); node.exported = this.eatContextual("as") ? this.parseIdent(true) : node.local; this.checkExport(exports, node.exported.name, node.exported.start); nodes.push(this.finishNode(node, "ExportSpecifier")); } return nodes }; // Parses import declaration. pp$1.parseImport = function(node) { this.next(); // import '...' if (this.type === types.string) { node.specifiers = empty; node.source = this.parseExprAtom(); } else { node.specifiers = this.parseImportSpecifiers(); this.expectContextual("from"); node.source = this.type === types.string ? this.parseExprAtom() : this.unexpected(); } this.semicolon(); return this.finishNode(node, "ImportDeclaration") }; // Parses a comma-separated list of module imports. pp$1.parseImportSpecifiers = function() { var nodes = [], first = true; if (this.type === types.name) { // import defaultObj, { x, y as z } from '...' var node = this.startNode(); node.local = this.parseIdent(); this.checkLVal(node.local, BIND_LEXICAL); nodes.push(this.finishNode(node, "ImportDefaultSpecifier")); if (!this.eat(types.comma)) { return nodes } } if (this.type === types.star) { var node$1 = this.startNode(); this.next(); this.expectContextual("as"); node$1.local = this.parseIdent(); this.checkLVal(node$1.local, BIND_LEXICAL); nodes.push(this.finishNode(node$1, "ImportNamespaceSpecifier")); return nodes } this.expect(types.braceL); while (!this.eat(types.braceR)) { if (!first) { this.expect(types.comma); if (this.afterTrailingComma(types.braceR)) { break } } else { first = false; } var node$2 = this.startNode(); node$2.imported = this.parseIdent(true); if (this.eatContextual("as")) { node$2.local = this.parseIdent(); } else { this.checkUnreserved(node$2.imported); node$2.local = node$2.imported; } this.checkLVal(node$2.local, BIND_LEXICAL); nodes.push(this.finishNode(node$2, "ImportSpecifier")); } return nodes }; // Set `ExpressionStatement#directive` property for directive prologues. pp$1.adaptDirectivePrologue = function(statements) { for (var i = 0; i < statements.length && this.isDirectiveCandidate(statements[i]); ++i) { statements[i].directive = statements[i].expression.raw.slice(1, -1); } }; pp$1.isDirectiveCandidate = function(statement) { return ( statement.type === "ExpressionStatement" && statement.expression.type === "Literal" && typeof statement.expression.value === "string" && // Reject parenthesized strings. (this.input[statement.start] === "\"" || this.input[statement.start] === "'") ) }; var pp$2 = Parser.prototype; // Convert existing expression atom to assignable pattern // if possible. pp$2.toAssignable = function(node, isBinding, refDestructuringErrors) { if (this.options.ecmaVersion >= 6 && node) { switch (node.type) { case "Identifier": if (this.inAsync && node.name === "await") { this.raise(node.start, "Cannot use 'await' as identifier inside an async function"); } break case "ObjectPattern": case "ArrayPattern": case "RestElement": break case "ObjectExpression": node.type = "ObjectPattern"; if (refDestructuringErrors) { this.checkPatternErrors(refDestructuringErrors, true); } for (var i = 0, list = node.properties; i < list.length; i += 1) { var prop = list[i]; this.toAssignable(prop, isBinding); // Early error: // AssignmentRestProperty[Yield, Await] : // `...` DestructuringAssignmentTarget[Yield, Await] // // It is a Syntax Error if |DestructuringAssignmentTarget| is an |ArrayLiteral| or an |ObjectLiteral|. if ( prop.type === "RestElement" && (prop.argument.type === "ArrayPattern" || prop.argument.type === "ObjectPattern") ) { this.raise(prop.argument.start, "Unexpected token"); } } break case "Property": // AssignmentProperty has type === "Property" if (node.kind !== "init") { this.raise(node.key.start, "Object pattern can't contain getter or setter"); } this.toAssignable(node.value, isBinding); break case "ArrayExpression": node.type = "ArrayPattern"; if (refDestructuringErrors) { this.checkPatternErrors(refDestructuringErrors, true); } this.toAssignableList(node.elements, isBinding); break case "SpreadElement": node.type = "RestElement"; this.toAssignable(node.argument, isBinding); if (node.argument.type === "AssignmentPattern") { this.raise(node.argument.start, "Rest elements cannot have a default value"); } break case "AssignmentExpression": if (node.operator !== "=") { this.raise(node.left.end, "Only '=' operator can be used for specifying default value."); } node.type = "AssignmentPattern"; delete node.operator; this.toAssignable(node.left, isBinding); // falls through to AssignmentPattern case "AssignmentPattern": break case "ParenthesizedExpression": this.toAssignable(node.expression, isBinding, refDestructuringErrors); break case "MemberExpression": if (!isBinding) { break } default: this.raise(node.start, "Assigning to rvalue"); } } else if (refDestructuringErrors) { this.checkPatternErrors(refDestructuringErrors, true); } return node }; // Convert list of expression atoms to binding list. pp$2.toAssignableList = function(exprList, isBinding) { var end = exprList.length; for (var i = 0; i < end; i++) { var elt = exprList[i]; if (elt) { this.toAssignable(elt, isBinding); } } if (end) { var last = exprList[end - 1]; if (this.options.ecmaVersion === 6 && isBinding && last && last.type === "RestElement" && last.argument.type !== "Identifier") { this.unexpected(last.argument.start); } } return exprList }; // Parses spread element. pp$2.parseSpread = function(refDestructuringErrors) { var node = this.startNode(); this.next(); node.argument = this.parseMaybeAssign(false, refDestructuringErrors); return this.finishNode(node, "SpreadElement") }; pp$2.parseRestBinding = function() { var node = this.startNode(); this.next(); // RestElement inside of a function parameter must be an identifier if (this.options.ecmaVersion === 6 && this.type !== types.name) { this.unexpected(); } node.argument = this.parseBindingAtom(); return this.finishNode(node, "RestElement") }; // Parses lvalue (assignable) atom. pp$2.parseBindingAtom = function() { if (this.options.ecmaVersion >= 6) { switch (this.type) { case types.bracketL: var node = this.startNode(); this.next(); node.elements = this.parseBindingList(types.bracketR, true, true); return this.finishNode(node, "ArrayPattern") case types.braceL: return this.parseObj(true) } } return this.parseIdent() }; pp$2.parseBindingList = function(close, allowEmpty, allowTrailingComma) { var elts = [], first = true; while (!this.eat(close)) { if (first) { first = false; } else { this.expect(types.comma); } if (allowEmpty && this.type === types.comma) { elts.push(null); } else if (allowTrailingComma && this.afterTrailingComma(close)) { break } else if (this.type === types.ellipsis) { var rest = this.parseRestBinding(); this.parseBindingListItem(rest); elts.push(rest); if (this.type === types.comma) { this.raise(this.start, "Comma is not permitted after the rest element"); } this.expect(close); break } else { var elem = this.parseMaybeDefault(this.start, this.startLoc); this.parseBindingListItem(elem); elts.push(elem); } } return elts }; pp$2.parseBindingListItem = function(param) { return param }; // Parses assignment pattern around given atom if possible. pp$2.parseMaybeDefault = function(startPos, startLoc, left) { left = left || this.parseBindingAtom(); if (this.options.ecmaVersion < 6 || !this.eat(types.eq)) { return left } var node = this.startNodeAt(startPos, startLoc); node.left = left; node.right = this.parseMaybeAssign(); return this.finishNode(node, "AssignmentPattern") }; // Verify that a node is an lval — something that can be assigned // to. // bindingType can be either: // 'var' indicating that the lval creates a 'var' binding // 'let' indicating that the lval creates a lexical ('let' or 'const') binding // 'none' indicating that the binding should be checked for illegal identifiers, but not for duplicate references pp$2.checkLVal = function(expr, bindingType, checkClashes) { if ( bindingType === void 0 ) bindingType = BIND_NONE; switch (expr.type) { case "Identifier": if (bindingType === BIND_LEXICAL && expr.name === "let") { this.raiseRecoverable(expr.start, "let is disallowed as a lexically bound name"); } if (this.strict && this.reservedWordsStrictBind.test(expr.name)) { this.raiseRecoverable(expr.start, (bindingType ? "Binding " : "Assigning to ") + expr.name + " in strict mode"); } if (checkClashes) { if (has(checkClashes, expr.name)) { this.raiseRecoverable(expr.start, "Argument name clash"); } checkClashes[expr.name] = true; } if (bindingType !== BIND_NONE && bindingType !== BIND_OUTSIDE) { this.declareName(expr.name, bindingType, expr.start); } break case "MemberExpression": if (bindingType) { this.raiseRecoverable(expr.start, "Binding member expression"); } break case "ObjectPattern": for (var i = 0, list = expr.properties; i < list.length; i += 1) { var prop = list[i]; this.checkLVal(prop, bindingType, checkClashes); } break case "Property": // AssignmentProperty has type === "Property" this.checkLVal(expr.value, bindingType, checkClashes); break case "ArrayPattern": for (var i$1 = 0, list$1 = expr.elements; i$1 < list$1.length; i$1 += 1) { var elem = list$1[i$1]; if (elem) { this.checkLVal(elem, bindingType, checkClashes); } } break case "AssignmentPattern": this.checkLVal(expr.left, bindingType, checkClashes); break case "RestElement": this.checkLVal(expr.argument, bindingType, checkClashes); break case "ParenthesizedExpression": this.checkLVal(expr.expression, bindingType, checkClashes); break default: this.raise(expr.start, (bindingType ? "Binding" : "Assigning to") + " rvalue"); } }; // A recursive descent parser operates by defining functions for all var pp$3 = Parser.prototype; // Check if property name clashes with already added. // Object/class getters and setters are not allowed to clash — // either with each other or with an init property — and in // strict mode, init properties are also not allowed to be repeated. pp$3.checkPropClash = function(prop, propHash, refDestructuringErrors) { if (this.options.ecmaVersion >= 9 && prop.type === "SpreadElement") { return } if (this.options.ecmaVersion >= 6 && (prop.computed || prop.method || prop.shorthand)) { return } var key = prop.key; var name; switch (key.type) { case "Identifier": name = key.name; break case "Literal": name = String(key.value); break default: return } var kind = prop.kind; if (this.options.ecmaVersion >= 6) { if (name === "__proto__" && kind === "init") { if (propHash.proto) { if (refDestructuringErrors && refDestructuringErrors.doubleProto < 0) { refDestructuringErrors.doubleProto = key.start; } // Backwards-compat kludge. Can be removed in version 6.0 else { this.raiseRecoverable(key.start, "Redefinition of __proto__ property"); } } propHash.proto = true; } return } name = "$" + name; var other = propHash[name]; if (other) { var redefinition; if (kind === "init") { redefinition = this.strict && other.init || other.get || other.set; } else { redefinition = other.init || other[kind]; } if (redefinition) { this.raiseRecoverable(key.start, "Redefinition of property"); } } else { other = propHash[name] = { init: false, get: false, set: false }; } other[kind] = true; }; // ### Expression parsing // These nest, from the most general expression type at the top to // 'atomic', nondivisible expression types at the bottom. Most of // the functions will simply let the function(s) below them parse, // and, *if* the syntactic construct they handle is present, wrap // the AST node that the inner parser gave them in another node. // Parse a full expression. The optional arguments are used to // forbid the `in` operator (in for loops initalization expressions) // and provide reference for storing '=' operator inside shorthand // property assignment in contexts where both object expression // and object pattern might appear (so it's possible to raise // delayed syntax error at correct position). pp$3.parseExpression = function(noIn, refDestructuringErrors) { var startPos = this.start, startLoc = this.startLoc; var expr = this.parseMaybeAssign(noIn, refDestructuringErrors); if (this.type === types.comma) { var node = this.startNodeAt(startPos, startLoc); node.expressions = [expr]; while (this.eat(types.comma)) { node.expressions.push(this.parseMaybeAssign(noIn, refDestructuringErrors)); } return this.finishNode(node, "SequenceExpression") } return expr }; // Parse an assignment expression. This includes applications of // operators like `+=`. pp$3.parseMaybeAssign = function(noIn, refDestructuringErrors, afterLeftParse) { if (this.isContextual("yield")) { if (this.inGenerator) { return this.parseYield(noIn) } // The tokenizer will assume an expression is allowed after // `yield`, but this isn't that kind of yield else { this.exprAllowed = false; } } var ownDestructuringErrors = false, oldParenAssign = -1, oldTrailingComma = -1, oldShorthandAssign = -1; if (refDestructuringErrors) { oldParenAssign = refDestructuringErrors.parenthesizedAssign; oldTrailingComma = refDestructuringErrors.trailingComma; oldShorthandAssign = refDestructuringErrors.shorthandAssign; refDestructuringErrors.parenthesizedAssign = refDestructuringErrors.trailingComma = refDestructuringErrors.shorthandAssign = -1; } else { refDestructuringErrors = new DestructuringErrors; ownDestructuringErrors = true; } var startPos = this.start, startLoc = this.startLoc; if (this.type === types.parenL || this.type === types.name) { this.potentialArrowAt = this.start; } var left = this.parseMaybeConditional(noIn, refDestructuringErrors); if (afterLeftParse) { left = afterLeftParse.call(this, left, startPos, startLoc); } if (this.type.isAssign) { var node = this.startNodeAt(startPos, startLoc); node.operator = this.value; node.left = this.type === types.eq ? this.toAssignable(left, false, refDestructuringErrors) : left; if (!ownDestructuringErrors) { DestructuringErrors.call(refDestructuringErrors); } refDestructuringErrors.shorthandAssign = -1; // reset because shorthand default was used correctly this.checkLVal(left); this.next(); node.right = this.parseMaybeAssign(noIn); return this.finishNode(node, "AssignmentExpression") } else { if (ownDestructuringErrors) { this.checkExpressionErrors(refDestructuringErrors, true); } } if (oldParenAssign > -1) { refDestructuringErrors.parenthesizedAssign = oldParenAssign; } if (oldTrailingComma > -1) { refDestructuringErrors.trailingComma = oldTrailingComma; } if (oldShorthandAssign > -1) { refDestructuringErrors.shorthandAssign = oldShorthandAssign; } return left }; // Parse a ternary conditional (`?:`) operator. pp$3.parseMaybeConditional = function(noIn, refDestructuringErrors) { var startPos = this.start, startLoc = this.startLoc; var expr = this.parseExprOps(noIn, refDestructuringErrors); if (this.checkExpressionErrors(refDestructuringErrors)) { return expr } if (this.eat(types.question)) { var node = this.startNodeAt(startPos, startLoc); node.test = expr; node.consequent = this.parseMaybeAssign(); this.expect(types.colon); node.alternate = this.parseMaybeAssign(noIn); return this.finishNode(node, "ConditionalExpression") } return expr }; // Start the precedence parser. pp$3.parseExprOps = function(noIn, refDestructuringErrors) { var startPos = this.start, startLoc = this.startLoc; var expr = this.parseMaybeUnary(refDestructuringErrors, false); if (this.checkExpressionErrors(refDestructuringErrors)) { return expr } return expr.start === startPos && expr.type === "ArrowFunctionExpression" ? expr : this.parseExprOp(expr, startPos, startLoc, -1, noIn) }; // Parse binary operators with the operator precedence parsing // algorithm. `left` is the left-hand side of the operator. // `minPrec` provides context that allows the function to stop and // defer further parser to one of its callers when it encounters an // operator that has a lower precedence than the set it is parsing. pp$3.parseExprOp = function(left, leftStartPos, leftStartLoc, minPrec, noIn) { var prec = this.type.binop; if (prec != null && (!noIn || this.type !== types._in)) { if (prec > minPrec) { var logical = this.type === types.logicalOR || this.type === types.logicalAND; var op = this.value; this.next(); var startPos = this.start, startLoc = this.startLoc; var right = this.parseExprOp(this.parseMaybeUnary(null, false), startPos, startLoc, prec, noIn); var node = this.buildBinary(leftStartPos, leftStartLoc, left, right, op, logical); return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, noIn) } } return left }; pp$3.buildBinary = function(startPos, startLoc, left, right, op, logical) { var node = this.startNodeAt(startPos, startLoc); node.left = left; node.operator = op; node.right = right; return this.finishNode(node, logical ? "LogicalExpression" : "BinaryExpression") }; // Parse unary operators, both prefix and postfix. pp$3.parseMaybeUnary = function(refDestructuringErrors, sawUnary) { var startPos = this.start, startLoc = this.startLoc, expr; if (this.isContextual("await") && (this.inAsync || (!this.inFunction && this.options.allowAwaitOutsideFunction))) { expr = this.parseAwait(); sawUnary = true; } else if (this.type.prefix) { var node = this.startNode(), update = this.type === types.incDec; node.operator = this.value; node.prefix = true; this.next(); node.argument = this.parseMaybeUnary(null, true); this.checkExpressionErrors(refDestructuringErrors, true); if (update) { this.checkLVal(node.argument); } else if (this.strict && node.operator === "delete" && node.argument.type === "Identifier") { this.raiseRecoverable(node.start, "Deleting local variable in strict mode"); } else { sawUnary = true; } expr = this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression"); } else { expr = this.parseExprSubscripts(refDestructuringErrors); if (this.checkExpressionErrors(refDestructuringErrors)) { return expr } while (this.type.postfix && !this.canInsertSemicolon()) { var node$1 = this.startNodeAt(startPos, startLoc); node$1.operator = this.value; node$1.prefix = false; node$1.argument = expr; this.checkLVal(expr); this.next(); expr = this.finishNode(node$1, "UpdateExpression"); } } if (!sawUnary && this.eat(types.starstar)) { return this.buildBinary(startPos, startLoc, expr, this.parseMaybeUnary(null, false), "**", false) } else { return expr } }; // Parse call, dot, and `[]`-subscript expressions. pp$3.parseExprSubscripts = function(refDestructuringErrors) { var startPos = this.start, startLoc = this.startLoc; var expr = this.parseExprAtom(refDestructuringErrors); var skipArrowSubscripts = expr.type === "ArrowFunctionExpression" && this.input.slice(this.lastTokStart, this.lastTokEnd) !== ")"; if (this.checkExpressionErrors(refDestructuringErrors) || skipArrowSubscripts) { return expr } var result = this.parseSubscripts(expr, startPos, startLoc); if (refDestructuringErrors && result.type === "MemberExpression") { if (refDestructuringErrors.parenthesizedAssign >= result.start) { refDestructuringErrors.parenthesizedAssign = -1; } if (refDestructuringErrors.parenthesizedBind >= result.start) { refDestructuringErrors.parenthesizedBind = -1; } } return result }; pp$3.parseSubscripts = function(base, startPos, startLoc, noCalls) { var maybeAsyncArrow = this.options.ecmaVersion >= 8 && base.type === "Identifier" && base.name === "async" && this.lastTokEnd === base.end && !this.canInsertSemicolon() && this.input.slice(base.start, base.end) === "async"; while (true) { var element = this.parseSubscript(base, startPos, startLoc, noCalls, maybeAsyncArrow); if (element === base || element.type === "ArrowFunctionExpression") { return element } base = element; } }; pp$3.parseSubscript = function(base, startPos, startLoc, noCalls, maybeAsyncArrow) { var computed = this.eat(types.bracketL); if (computed || this.eat(types.dot)) { var node = this.startNodeAt(startPos, startLoc); node.object = base; node.property = computed ? this.parseExpression() : this.parseIdent(this.options.allowReserved !== "never"); node.computed = !!computed; if (computed) { this.expect(types.bracketR); } base = this.finishNode(node, "MemberExpression"); } else if (!noCalls && this.eat(types.parenL)) { var refDestructuringErrors = new DestructuringErrors, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldAwaitIdentPos = this.awaitIdentPos; this.yieldPos = 0; this.awaitPos = 0; this.awaitIdentPos = 0; var exprList = this.parseExprList(types.parenR, this.options.ecmaVersion >= 8 && base.type !== "Import", false, refDestructuringErrors); if (maybeAsyncArrow && !this.canInsertSemicolon() && this.eat(types.arrow)) { this.checkPatternErrors(refDestructuringErrors, false); this.checkYieldAwaitInDefaultParams(); if (this.awaitIdentPos > 0) { this.raise(this.awaitIdentPos, "Cannot use 'await' as identifier inside an async function"); } this.yieldPos = oldYieldPos; this.awaitPos = oldAwaitPos; this.awaitIdentPos = oldAwaitIdentPos; return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList, true) } this.checkExpressionErrors(refDestructuringErrors, true); this.yieldPos = oldYieldPos || this.yieldPos; this.awaitPos = oldAwaitPos || this.awaitPos; this.awaitIdentPos = oldAwaitIdentPos || this.awaitIdentPos; var node$1 = this.startNodeAt(startPos, startLoc); node$1.callee = base; node$1.arguments = exprList; if (node$1.callee.type === "Import") { if (node$1.arguments.length !== 1) { this.raise(node$1.start, "import() requires exactly one argument"); } var importArg = node$1.arguments[0]; if (importArg && importArg.type === "SpreadElement") { this.raise(importArg.start, "... is not allowed in import()"); } } base = this.finishNode(node$1, "CallExpression"); } else if (this.type === types.backQuote) { var node$2 = this.startNodeAt(startPos, startLoc); node$2.tag = base; node$2.quasi = this.parseTemplate({isTagged: true}); base = this.finishNode(node$2, "TaggedTemplateExpression"); } return base }; // Parse an atomic expression — either a single token that is an // expression, an expression started by a keyword like `function` or // `new`, or an expression wrapped in punctuation like `()`, `[]`, // or `{}`. pp$3.parseExprAtom = function(refDestructuringErrors) { // If a division operator appears in an expression position, the // tokenizer got confused, and we force it to read a regexp instead. if (this.type === types.slash) { this.readRegexp(); } var node, canBeArrow = this.potentialArrowAt === this.start; switch (this.type) { case types._super: if (!this.allowSuper) { this.raise(this.start, "'super' keyword outside a method"); } node = this.startNode(); this.next(); if (this.type === types.parenL && !this.allowDirectSuper) { this.raise(node.start, "super() call outside constructor of a subclass"); } // The `super` keyword can appear at below: // SuperProperty: // super [ Expression ] // super . IdentifierName // SuperCall: // super Arguments if (this.type !== types.dot && this.type !== types.bracketL && this.type !== types.parenL) { this.unexpected(); } return this.finishNode(node, "Super") case types._this: node = this.startNode(); this.next(); return this.finishNode(node, "ThisExpression") case types.name: var startPos = this.start, startLoc = this.startLoc, containsEsc = this.containsEsc; var id = this.parseIdent(false); if (this.options.ecmaVersion >= 8 && !containsEsc && id.name === "async" && !this.canInsertSemicolon() && this.eat(types._function)) { return this.parseFunction(this.startNodeAt(startPos, startLoc), 0, false, true) } if (canBeArrow && !this.canInsertSemicolon()) { if (this.eat(types.arrow)) { return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id], false) } if (this.options.ecmaVersion >= 8 && id.name === "async" && this.type === types.name && !containsEsc) { id = this.parseIdent(false); if (this.canInsertSemicolon() || !this.eat(types.arrow)) { this.unexpected(); } return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id], true) } } return id case types.regexp: var value = this.value; node = this.parseLiteral(value.value); node.regex = {pattern: value.pattern, flags: value.flags}; return node case types.num: case types.string: return this.parseLiteral(this.value) case types._null: case types._true: case types._false: node = this.startNode(); node.value = this.type === types._null ? null : this.type === types._true; node.raw = this.type.keyword; this.next(); return this.finishNode(node, "Literal") case types.parenL: var start = this.start, expr = this.parseParenAndDistinguishExpression(canBeArrow); if (refDestructuringErrors) { if (refDestructuringErrors.parenthesizedAssign < 0 && !this.isSimpleAssignTarget(expr)) { refDestructuringErrors.parenthesizedAssign = start; } if (refDestructuringErrors.parenthesizedBind < 0) { refDestructuringErrors.parenthesizedBind = start; } } return expr case types.bracketL: node = this.startNode(); this.next(); node.elements = this.parseExprList(types.bracketR, true, true, refDestructuringErrors); return this.finishNode(node, "ArrayExpression") case types.braceL: return this.parseObj(false, refDestructuringErrors) case types._function: node = this.startNode(); this.next(); return this.parseFunction(node, 0) case types._class: return this.parseClass(this.startNode(), false) case types._new: return this.parseNew() case types.backQuote: return this.parseTemplate() case types._import: if (this.options.ecmaVersion > 10) { return this.parseDynamicImport() } else { return this.unexpected() } default: this.unexpected(); } }; pp$3.parseDynamicImport = function() { var node = this.startNode(); this.next(); if (this.type !== types.parenL) { this.unexpected(); } return this.finishNode(node, "Import") }; pp$3.parseLiteral = function(value) { var node = this.startNode(); node.value = value; node.raw = this.input.slice(this.start, this.end); if (node.raw.charCodeAt(node.raw.length - 1) === 110) { node.bigint = node.raw.slice(0, -1); } this.next(); return this.finishNode(node, "Literal") }; pp$3.parseParenExpression = function() { this.expect(types.parenL); var val = this.parseExpression(); this.expect(types.parenR); return val }; pp$3.parseParenAndDistinguishExpression = function(canBeArrow) { var startPos = this.start, startLoc = this.startLoc, val, allowTrailingComma = this.options.ecmaVersion >= 8; if (this.options.ecmaVersion >= 6) { this.next(); var innerStartPos = this.start, innerStartLoc = this.startLoc; var exprList = [], first = true, lastIsComma = false; var refDestructuringErrors = new DestructuringErrors, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, spreadStart; this.yieldPos = 0; this.awaitPos = 0; // Do not save awaitIdentPos to allow checking awaits nested in parameters while (this.type !== types.parenR) { first ? first = false : this.expect(types.comma); if (allowTrailingComma && this.afterTrailingComma(types.parenR, true)) { lastIsComma = true; break } else if (this.type === types.ellipsis) { spreadStart = this.start; exprList.push(this.parseParenItem(this.parseRestBinding())); if (this.type === types.comma) { this.raise(this.start, "Comma is not permitted after the rest element"); } break } else { exprList.push(this.parseMaybeAssign(false, refDestructuringErrors, this.parseParenItem)); } } var innerEndPos = this.start, innerEndLoc = this.startLoc; this.expect(types.parenR); if (canBeArrow && !this.canInsertSemicolon() && this.eat(types.arrow)) { this.checkPatternErrors(refDestructuringErrors, false); this.checkYieldAwaitInDefaultParams(); this.yieldPos = oldYieldPos; this.awaitPos = oldAwaitPos; return this.parseParenArrowList(startPos, startLoc, exprList) } if (!exprList.length || lastIsComma) { this.unexpected(this.lastTokStart); } if (spreadStart) { this.unexpected(spreadStart); } this.checkExpressionErrors(refDestructuringErrors, true); this.yieldPos = oldYieldPos || this.yieldPos; this.awaitPos = oldAwaitPos || this.awaitPos; if (exprList.length > 1) { val = this.startNodeAt(innerStartPos, innerStartLoc); val.expressions = exprList; this.finishNodeAt(val, "SequenceExpression", innerEndPos, innerEndLoc); } else { val = exprList[0]; } } else { val = this.parseParenExpression(); } if (this.options.preserveParens) { var par = this.startNodeAt(startPos, startLoc); par.expression = val; return this.finishNode(par, "ParenthesizedExpression") } else { return val } }; pp$3.parseParenItem = function(item) { return item }; pp$3.parseParenArrowList = function(startPos, startLoc, exprList) { return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList) }; // New's precedence is slightly tricky. It must allow its argument to // be a `[]` or dot subscript expression, but not a call — at least, // not without wrapping it in parentheses. Thus, it uses the noCalls // argument to parseSubscripts to prevent it from consuming the // argument list. var empty$1 = []; pp$3.parseNew = function() { var node = this.startNode(); var meta = this.parseIdent(true); if (this.options.ecmaVersion >= 6 && this.eat(types.dot)) { node.meta = meta; var containsEsc = this.containsEsc; node.property = this.parseIdent(true); if (node.property.name !== "target" || containsEsc) { this.raiseRecoverable(node.property.start, "The only valid meta property for new is new.target"); } if (!this.inNonArrowFunction()) { this.raiseRecoverable(node.start, "new.target can only be used in functions"); } return this.finishNode(node, "MetaProperty") } var startPos = this.start, startLoc = this.startLoc; node.callee = this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true); if (this.options.ecmaVersion > 10 && node.callee.type === "Import") { this.raise(node.callee.start, "Cannot use new with import(...)"); } if (this.eat(types.parenL)) { node.arguments = this.parseExprList(types.parenR, this.options.ecmaVersion >= 8 && node.callee.type !== "Import", false); } else { node.arguments = empty$1; } return this.finishNode(node, "NewExpression") }; // Parse template expression. pp$3.parseTemplateElement = function(ref) { var isTagged = ref.isTagged; var elem = this.startNode(); if (this.type === types.invalidTemplate) { if (!isTagged) { this.raiseRecoverable(this.start, "Bad escape sequence in untagged template literal"); } elem.value = { raw: this.value, cooked: null }; } else { elem.value = { raw: this.input.slice(this.start, this.end).replace(/\r\n?/g, "\n"), cooked: this.value }; } this.next(); elem.tail = this.type === types.backQuote; return this.finishNode(elem, "TemplateElement") }; pp$3.parseTemplate = function(ref) { if ( ref === void 0 ) ref = {}; var isTagged = ref.isTagged; if ( isTagged === void 0 ) isTagged = false; var node = this.startNode(); this.next(); node.expressions = []; var curElt = this.parseTemplateElement({isTagged: isTagged}); node.quasis = [curElt]; while (!curElt.tail) { if (this.type === types.eof) { this.raise(this.pos, "Unterminated template literal"); } this.expect(types.dollarBraceL); node.expressions.push(this.parseExpression()); this.expect(types.braceR); node.quasis.push(curElt = this.parseTemplateElement({isTagged: isTagged})); } this.next(); return this.finishNode(node, "TemplateLiteral") }; pp$3.isAsyncProp = function(prop) { return !prop.computed && prop.key.type === "Identifier" && prop.key.name === "async" && (this.type === types.name || this.type === types.num || this.type === types.string || this.type === types.bracketL || this.type.keyword || (this.options.ecmaVersion >= 9 && this.type === types.star)) && !lineBreak.test(this.input.slice(this.lastTokEnd, this.start)) }; // Parse an object literal or binding pattern. pp$3.parseObj = function(isPattern, refDestructuringErrors) { var node = this.startNode(), first = true, propHash = {}; node.properties = []; this.next(); while (!this.eat(types.braceR)) { if (!first) { this.expect(types.comma); if (this.afterTrailingComma(types.braceR)) { break } } else { first = false; } var prop = this.parseProperty(isPattern, refDestructuringErrors); if (!isPattern) { this.checkPropClash(prop, propHash, refDestructuringErrors); } node.properties.push(prop); } return this.finishNode(node, isPattern ? "ObjectPattern" : "ObjectExpression") }; pp$3.parseProperty = function(isPattern, refDestructuringErrors) { var prop = this.startNode(), isGenerator, isAsync, startPos, startLoc; if (this.options.ecmaVersion >= 9 && this.eat(types.ellipsis)) { if (isPattern) { prop.argument = this.parseIdent(false); if (this.type === types.comma) { this.raise(this.start, "Comma is not permitted after the rest element"); } return this.finishNode(prop, "RestElement") } // To disallow parenthesized identifier via `this.toAssignable()`. if (this.type === types.parenL && refDestructuringErrors) { if (refDestructuringErrors.parenthesizedAssign < 0) { refDestructuringErrors.parenthesizedAssign = this.start; } if (refDestructuringErrors.parenthesizedBind < 0) { refDestructuringErrors.parenthesizedBind = this.start; } } // Parse argument. prop.argument = this.parseMaybeAssign(false, refDestructuringErrors); // To disallow trailing comma via `this.toAssignable()`. if (this.type === types.comma && refDestructuringErrors && refDestructuringErrors.trailingComma < 0) { refDestructuringErrors.trailingComma = this.start; } // Finish return this.finishNode(prop, "SpreadElement") } if (this.options.ecmaVersion >= 6) { prop.method = false; prop.shorthand = false; if (isPattern || refDestructuringErrors) { startPos = this.start; startLoc = this.startLoc; } if (!isPattern) { isGenerator = this.eat(types.star); } } var containsEsc = this.containsEsc; this.parsePropertyName(prop); if (!isPattern && !containsEsc && this.options.ecmaVersion >= 8 && !isGenerator && this.isAsyncProp(prop)) { isAsync = true; isGenerator = this.options.ecmaVersion >= 9 && this.eat(types.star); this.parsePropertyName(prop, refDestructuringErrors); } else { isAsync = false; } this.parsePropertyValue(prop, isPattern, isGenerator, isAsync, startPos, startLoc, refDestructuringErrors, containsEsc); return this.finishNode(prop, "Property") }; pp$3.parsePropertyValue = function(prop, isPattern, isGenerator, isAsync, startPos, startLoc, refDestructuringErrors, containsEsc) { if ((isGenerator || isAsync) && this.type === types.colon) { this.unexpected(); } if (this.eat(types.colon)) { prop.value = isPattern ? this.parseMaybeDefault(this.start, this.startLoc) : this.parseMaybeAssign(false, refDestructuringErrors); prop.kind = "init"; } else if (this.options.ecmaVersion >= 6 && this.type === types.parenL) { if (isPattern) { this.unexpected(); } prop.kind = "init"; prop.method = true; prop.value = this.parseMethod(isGenerator, isAsync); } else if (!isPattern && !containsEsc && this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === "Identifier" && (prop.key.name === "get" || prop.key.name === "set") && (this.type !== types.comma && this.type !== types.braceR)) { if (isGenerator || isAsync) { this.unexpected(); } prop.kind = prop.key.name; this.parsePropertyName(prop); prop.value = this.parseMethod(false); var paramCount = prop.kind === "get" ? 0 : 1; if (prop.value.params.length !== paramCount) { var start = prop.value.start; if (prop.kind === "get") { this.raiseRecoverable(start, "getter should have no params"); } else { this.raiseRecoverable(start, "setter should have exactly one param"); } } else { if (prop.kind === "set" && prop.value.params[0].type === "RestElement") { this.raiseRecoverable(prop.value.params[0].start, "Setter cannot use rest params"); } } } else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") { if (isGenerator || isAsync) { this.unexpected(); } this.checkUnreserved(prop.key); if (prop.key.name === "await" && !this.awaitIdentPos) { this.awaitIdentPos = startPos; } prop.kind = "init"; if (isPattern) { prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key); } else if (this.type === types.eq && refDestructuringErrors) { if (refDestructuringErrors.shorthandAssign < 0) { refDestructuringErrors.shorthandAssign = this.start; } prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key); } else { prop.value = prop.key; } prop.shorthand = true; } else { this.unexpected(); } }; pp$3.parsePropertyName = function(prop) { if (this.options.ecmaVersion >= 6) { if (this.eat(types.bracketL)) { prop.computed = true; prop.key = this.parseMaybeAssign(); this.expect(types.bracketR); return prop.key } else { prop.computed = false; } } return prop.key = this.type === types.num || this.type === types.string ? this.parseExprAtom() : this.parseIdent(this.options.allowReserved !== "never") }; // Initialize empty function node. pp$3.initFunction = function(node) { node.id = null; if (this.options.ecmaVersion >= 6) { node.generator = node.expression = false; } if (this.options.ecmaVersion >= 8) { node.async = false; } }; // Parse object or class method. pp$3.parseMethod = function(isGenerator, isAsync, allowDirectSuper) { var node = this.startNode(), oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldAwaitIdentPos = this.awaitIdentPos; this.initFunction(node); if (this.options.ecmaVersion >= 6) { node.generator = isGenerator; } if (this.options.ecmaVersion >= 8) { node.async = !!isAsync; } this.yieldPos = 0; this.awaitPos = 0; this.awaitIdentPos = 0; this.enterScope(functionFlags(isAsync, node.generator) | SCOPE_SUPER | (allowDirectSuper ? SCOPE_DIRECT_SUPER : 0)); this.expect(types.parenL); node.params = this.parseBindingList(types.parenR, false, this.options.ecmaVersion >= 8); this.checkYieldAwaitInDefaultParams(); this.parseFunctionBody(node, false, true); this.yieldPos = oldYieldPos; this.awaitPos = oldAwaitPos; this.awaitIdentPos = oldAwaitIdentPos; return this.finishNode(node, "FunctionExpression") }; // Parse arrow function expression with given parameters. pp$3.parseArrowExpression = function(node, params, isAsync) { var oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldAwaitIdentPos = this.awaitIdentPos; this.enterScope(functionFlags(isAsync, false) | SCOPE_ARROW); this.initFunction(node); if (this.options.ecmaVersion >= 8) { node.async = !!isAsync; } this.yieldPos = 0; this.awaitPos = 0; this.awaitIdentPos = 0; node.params = this.toAssignableList(params, true); this.parseFunctionBody(node, true, false); this.yieldPos = oldYieldPos; this.awaitPos = oldAwaitPos; this.awaitIdentPos = oldAwaitIdentPos; return this.finishNode(node, "ArrowFunctionExpression") }; // Parse function body and check parameters. pp$3.parseFunctionBody = function(node, isArrowFunction, isMethod) { var isExpression = isArrowFunction && this.type !== types.braceL; var oldStrict = this.strict, useStrict = false; if (isExpression) { node.body = this.parseMaybeAssign(); node.expression = true; this.checkParams(node, false); } else { var nonSimple = this.options.ecmaVersion >= 7 && !this.isSimpleParamList(node.params); if (!oldStrict || nonSimple) { useStrict = this.strictDirective(this.end); // If this is a strict mode function, verify that argument names // are not repeated, and it does not try to bind the words `eval` // or `arguments`. if (useStrict && nonSimple) { this.raiseRecoverable(node.start, "Illegal 'use strict' directive in function with non-simple parameter list"); } } // Start a new scope with regard to labels and the `inFunction` // flag (restore them to their old value afterwards). var oldLabels = this.labels; this.labels = []; if (useStrict) { this.strict = true; } // Add the params to varDeclaredNames to ensure that an error is thrown // if a let/const declaration in the function clashes with one of the params. this.checkParams(node, !oldStrict && !useStrict && !isArrowFunction && !isMethod && this.isSimpleParamList(node.params)); node.body = this.parseBlock(false); node.expression = false; this.adaptDirectivePrologue(node.body.body); this.labels = oldLabels; } this.exitScope(); // Ensure the function name isn't a forbidden identifier in strict mode, e.g. 'eval' if (this.strict && node.id) { this.checkLVal(node.id, BIND_OUTSIDE); } this.strict = oldStrict; }; pp$3.isSimpleParamList = function(params) { for (var i = 0, list = params; i < list.length; i += 1) { var param = list[i]; if (param.type !== "Identifier") { return false } } return true }; // Checks function params for various disallowed patterns such as using "eval" // or "arguments" and duplicate parameters. pp$3.checkParams = function(node, allowDuplicates) { var nameHash = {}; for (var i = 0, list = node.params; i < list.length; i += 1) { var param = list[i]; this.checkLVal(param, BIND_VAR, allowDuplicates ? null : nameHash); } }; // Parses a comma-separated list of expressions, and returns them as // an array. `close` is the token type that ends the list, and // `allowEmpty` can be turned on to allow subsequent commas with // nothing in between them to be parsed as `null` (which is needed // for array literals). pp$3.parseExprList = function(close, allowTrailingComma, allowEmpty, refDestructuringErrors) { var elts = [], first = true; while (!this.eat(close)) { if (!first) { this.expect(types.comma); if (allowTrailingComma && this.afterTrailingComma(close)) { break } } else { first = false; } var elt = (void 0); if (allowEmpty && this.type === types.comma) { elt = null; } else if (this.type === types.ellipsis) { elt = this.parseSpread(refDestructuringErrors); if (refDestructuringErrors && this.type === types.comma && refDestructuringErrors.trailingComma < 0) { refDestructuringErrors.trailingComma = this.start; } } else { elt = this.parseMaybeAssign(false, refDestructuringErrors); } elts.push(elt); } return elts }; pp$3.checkUnreserved = function(ref) { var start = ref.start; var end = ref.end; var name = ref.name; if (this.inGenerator && name === "yield") { this.raiseRecoverable(start, "Cannot use 'yield' as identifier inside a generator"); } if (this.inAsync && name === "await") { this.raiseRecoverable(start, "Cannot use 'await' as identifier inside an async function"); } if (this.keywords.test(name)) { this.raise(start, ("Unexpected keyword '" + name + "'")); } if (this.options.ecmaVersion < 6 && this.input.slice(start, end).indexOf("\\") !== -1) { return } var re = this.strict ? this.reservedWordsStrict : this.reservedWords; if (re.test(name)) { if (!this.inAsync && name === "await") { this.raiseRecoverable(start, "Cannot use keyword 'await' outside an async function"); } this.raiseRecoverable(start, ("The keyword '" + name + "' is reserved")); } }; // Parse the next token as an identifier. If `liberal` is true (used // when parsing properties), it will also convert keywords into // identifiers. pp$3.parseIdent = function(liberal, isBinding) { var node = this.startNode(); if (this.type === types.name) { node.name = this.value; } else if (this.type.keyword) { node.name = this.type.keyword; // To fix https://github.com/acornjs/acorn/issues/575 // `class` and `function` keywords push new context into this.context. // But there is no chance to pop the context if the keyword is consumed as an identifier such as a property name. // If the previous token is a dot, this does not apply because the context-managing code already ignored the keyword if ((node.name === "class" || node.name === "function") && (this.lastTokEnd !== this.lastTokStart + 1 || this.input.charCodeAt(this.lastTokStart) !== 46)) { this.context.pop(); } } else { this.unexpected(); } this.next(); this.finishNode(node, "Identifier"); if (!liberal) { this.checkUnreserved(node); if (node.name === "await" && !this.awaitIdentPos) { this.awaitIdentPos = node.start; } } return node }; // Parses yield expression inside generator. pp$3.parseYield = function(noIn) { if (!this.yieldPos) { this.yieldPos = this.start; } var node = this.startNode(); this.next(); if (this.type === types.semi || this.canInsertSemicolon() || (this.type !== types.star && !this.type.startsExpr)) { node.delegate = false; node.argument = null; } else { node.delegate = this.eat(types.star); node.argument = this.parseMaybeAssign(noIn); } return this.finishNode(node, "YieldExpression") }; pp$3.parseAwait = function() { if (!this.awaitPos) { this.awaitPos = this.start; } var node = this.startNode(); this.next(); node.argument = this.parseMaybeUnary(null, true); return this.finishNode(node, "AwaitExpression") }; var pp$4 = Parser.prototype; // This function is used to raise exceptions on parse errors. It // takes an offset integer (into the current `input`) to indicate // the location of the error, attaches the position to the end // of the error message, and then raises a `SyntaxError` with that // message. pp$4.raise = function(pos, message) { var loc = getLineInfo(this.input, pos); message += " (" + loc.line + ":" + loc.column + ")"; var err = new SyntaxError(message); err.pos = pos; err.loc = loc; err.raisedAt = this.pos; throw err }; pp$4.raiseRecoverable = pp$4.raise; pp$4.curPosition = function() { if (this.options.locations) { return new Position(this.curLine, this.pos - this.lineStart) } }; var pp$5 = Parser.prototype; var Scope = function Scope(flags) { this.flags = flags; // A list of var-declared names in the current lexical scope this.var = []; // A list of lexically-declared names in the current lexical scope this.lexical = []; // A list of lexically-declared FunctionDeclaration names in the current lexical scope this.functions = []; }; // The functions in this module keep track of declared variables in the current scope in order to detect duplicate variable names. pp$5.enterScope = function(flags) { this.scopeStack.push(new Scope(flags)); }; pp$5.exitScope = function() { this.scopeStack.pop(); }; // The spec says: // > At the top level of a function, or script, function declarations are // > treated like var declarations rather than like lexical declarations. pp$5.treatFunctionsAsVarInScope = function(scope) { return (scope.flags & SCOPE_FUNCTION) || !this.inModule && (scope.flags & SCOPE_TOP) }; pp$5.declareName = function(name, bindingType, pos) { var redeclared = false; if (bindingType === BIND_LEXICAL) { var scope = this.currentScope(); redeclared = scope.lexical.indexOf(name) > -1 || scope.functions.indexOf(name) > -1 || scope.var.indexOf(name) > -1; scope.lexical.push(name); if (this.inModule && (scope.flags & SCOPE_TOP)) { delete this.undefinedExports[name]; } } else if (bindingType === BIND_SIMPLE_CATCH) { var scope$1 = this.currentScope(); scope$1.lexical.push(name); } else if (bindingType === BIND_FUNCTION) { var scope$2 = this.currentScope(); if (this.treatFunctionsAsVar) { redeclared = scope$2.lexical.indexOf(name) > -1; } else { redeclared = scope$2.lexical.indexOf(name) > -1 || scope$2.var.indexOf(name) > -1; } scope$2.functions.push(name); } else { for (var i = this.scopeStack.length - 1; i >= 0; --i) { var scope$3 = this.scopeStack[i]; if (scope$3.lexical.indexOf(name) > -1 && !((scope$3.flags & SCOPE_SIMPLE_CATCH) && scope$3.lexical[0] === name) || !this.treatFunctionsAsVarInScope(scope$3) && scope$3.functions.indexOf(name) > -1) { redeclared = true; break } scope$3.var.push(name); if (this.inModule && (scope$3.flags & SCOPE_TOP)) { delete this.undefinedExports[name]; } if (scope$3.flags & SCOPE_VAR) { break } } } if (redeclared) { this.raiseRecoverable(pos, ("Identifier '" + name + "' has already been declared")); } }; pp$5.checkLocalExport = function(id) { // scope.functions must be empty as Module code is always strict. if (this.scopeStack[0].lexical.indexOf(id.name) === -1 && this.scopeStack[0].var.indexOf(id.name) === -1) { this.undefinedExports[id.name] = id; } }; pp$5.currentScope = function() { return this.scopeStack[this.scopeStack.length - 1] }; pp$5.currentVarScope = function() { for (var i = this.scopeStack.length - 1;; i--) { var scope = this.scopeStack[i]; if (scope.flags & SCOPE_VAR) { return scope } } }; // Could be useful for `this`, `new.target`, `super()`, `super.property`, and `super[property]`. pp$5.currentThisScope = function() { for (var i = this.scopeStack.length - 1;; i--) { var scope = this.scopeStack[i]; if (scope.flags & SCOPE_VAR && !(scope.flags & SCOPE_ARROW)) { return scope } } }; var Node = function Node(parser, pos, loc) { this.type = ""; this.start = pos; this.end = 0; if (parser.options.locations) { this.loc = new SourceLocation(parser, loc); } if (parser.options.directSourceFile) { this.sourceFile = parser.options.directSourceFile; } if (parser.options.ranges) { this.range = [pos, 0]; } }; // Start an AST node, attaching a start offset. var pp$6 = Parser.prototype; pp$6.startNode = function() { return new Node(this, this.start, this.startLoc) }; pp$6.startNodeAt = function(pos, loc) { return new Node(this, pos, loc) }; // Finish an AST node, adding `type` and `end` properties. function finishNodeAt(node, type, pos, loc) { node.type = type; node.end = pos; if (this.options.locations) { node.loc.end = loc; } if (this.options.ranges) { node.range[1] = pos; } return node } pp$6.finishNode = function(node, type) { return finishNodeAt.call(this, node, type, this.lastTokEnd, this.lastTokEndLoc) }; // Finish node at given position pp$6.finishNodeAt = function(node, type, pos, loc) { return finishNodeAt.call(this, node, type, pos, loc) }; // The algorithm used to determine whether a regexp can appear at a var TokContext = function TokContext(token, isExpr, preserveSpace, override, generator) { this.token = token; this.isExpr = !!isExpr; this.preserveSpace = !!preserveSpace; this.override = override; this.generator = !!generator; }; var types$1 = { b_stat: new TokContext("{", false), b_expr: new TokContext("{", true), b_tmpl: new TokContext("${", false), p_stat: new TokContext("(", false), p_expr: new TokContext("(", true), q_tmpl: new TokContext("`", true, true, function (p) { return p.tryReadTemplateToken(); }), f_stat: new TokContext("function", false), f_expr: new TokContext("function", true), f_expr_gen: new TokContext("function", true, false, null, true), f_gen: new TokContext("function", false, false, null, true) }; var pp$7 = Parser.prototype; pp$7.initialContext = function() { return [types$1.b_stat] }; pp$7.braceIsBlock = function(prevType) { var parent = this.curContext(); if (parent === types$1.f_expr || parent === types$1.f_stat) { return true } if (prevType === types.colon && (parent === types$1.b_stat || parent === types$1.b_expr)) { return !parent.isExpr } // The check for `tt.name && exprAllowed` detects whether we are // after a `yield` or `of` construct. See the `updateContext` for // `tt.name`. if (prevType === types._return || prevType === types.name && this.exprAllowed) { return lineBreak.test(this.input.slice(this.lastTokEnd, this.start)) } if (prevType === types._else || prevType === types.semi || prevType === types.eof || prevType === types.parenR || prevType === types.arrow) { return true } if (prevType === types.braceL) { return parent === types$1.b_stat } if (prevType === types._var || prevType === types._const || prevType === types.name) { return false } return !this.exprAllowed }; pp$7.inGeneratorContext = function() { for (var i = this.context.length - 1; i >= 1; i--) { var context = this.context[i]; if (context.token === "function") { return context.generator } } return false }; pp$7.updateContext = function(prevType) { var update, type = this.type; if (type.keyword && prevType === types.dot) { this.exprAllowed = false; } else if (update = type.updateContext) { update.call(this, prevType); } else { this.exprAllowed = type.beforeExpr; } }; // Token-specific context update code types.parenR.updateContext = types.braceR.updateContext = function() { if (this.context.length === 1) { this.exprAllowed = true; return } var out = this.context.pop(); if (out === types$1.b_stat && this.curContext().token === "function") { out = this.context.pop(); } this.exprAllowed = !out.isExpr; }; types.braceL.updateContext = function(prevType) { this.context.push(this.braceIsBlock(prevType) ? types$1.b_stat : types$1.b_expr); this.exprAllowed = true; }; types.dollarBraceL.updateContext = function() { this.context.push(types$1.b_tmpl); this.exprAllowed = true; }; types.parenL.updateContext = function(prevType) { var statementParens = prevType === types._if || prevType === types._for || prevType === types._with || prevType === types._while; this.context.push(statementParens ? types$1.p_stat : types$1.p_expr); this.exprAllowed = true; }; types.incDec.updateContext = function() { // tokExprAllowed stays unchanged }; types._function.updateContext = types._class.updateContext = function(prevType) { if (prevType.beforeExpr && prevType !== types.semi && prevType !== types._else && !(prevType === types._return && lineBreak.test(this.input.slice(this.lastTokEnd, this.start))) && !((prevType === types.colon || prevType === types.braceL) && this.curContext() === types$1.b_stat)) { this.context.push(types$1.f_expr); } else { this.context.push(types$1.f_stat); } this.exprAllowed = false; }; types.backQuote.updateContext = function() { if (this.curContext() === types$1.q_tmpl) { this.context.pop(); } else { this.context.push(types$1.q_tmpl); } this.exprAllowed = false; }; types.star.updateContext = function(prevType) { if (prevType === types._function) { var index = this.context.length - 1; if (this.context[index] === types$1.f_expr) { this.context[index] = types$1.f_expr_gen; } else { this.context[index] = types$1.f_gen; } } this.exprAllowed = true; }; types.name.updateContext = function(prevType) { var allowed = false; if (this.options.ecmaVersion >= 6 && prevType !== types.dot) { if (this.value === "of" && !this.exprAllowed || this.value === "yield" && this.inGeneratorContext()) { allowed = true; } } this.exprAllowed = allowed; }; // This file contains Unicode properties extracted from the ECMAScript // specification. The lists are extracted like so: // $$('#table-binary-unicode-properties > figure > table > tbody > tr > td:nth-child(1) code').map(el => el.innerText) // #table-binary-unicode-properties var ecma9BinaryProperties = "ASCII ASCII_Hex_Digit AHex Alphabetic Alpha Any Assigned Bidi_Control Bidi_C Bidi_Mirrored Bidi_M Case_Ignorable CI Cased Changes_When_Casefolded CWCF Changes_When_Casemapped CWCM Changes_When_Lowercased CWL Changes_When_NFKC_Casefolded CWKCF Changes_When_Titlecased CWT Changes_When_Uppercased CWU Dash Default_Ignorable_Code_Point DI Deprecated Dep Diacritic Dia Emoji Emoji_Component Emoji_Modifier Emoji_Modifier_Base Emoji_Presentation Extender Ext Grapheme_Base Gr_Base Grapheme_Extend Gr_Ext Hex_Digit Hex IDS_Binary_Operator IDSB IDS_Trinary_Operator IDST ID_Continue IDC ID_Start IDS Ideographic Ideo Join_Control Join_C Logical_Order_Exception LOE Lowercase Lower Math Noncharacter_Code_Point NChar Pattern_Syntax Pat_Syn Pattern_White_Space Pat_WS Quotation_Mark QMark Radical Regional_Indicator RI Sentence_Terminal STerm Soft_Dotted SD Terminal_Punctuation Term Unified_Ideograph UIdeo Uppercase Upper Variation_Selector VS White_Space space XID_Continue XIDC XID_Start XIDS"; var ecma10BinaryProperties = ecma9BinaryProperties + " Extended_Pictographic"; var ecma11BinaryProperties = ecma10BinaryProperties; var unicodeBinaryProperties = { 9: ecma9BinaryProperties, 10: ecma10BinaryProperties, 11: ecma11BinaryProperties }; // #table-unicode-general-category-values var unicodeGeneralCategoryValues = "Cased_Letter LC Close_Punctuation Pe Connector_Punctuation Pc Control Cc cntrl Currency_Symbol Sc Dash_Punctuation Pd Decimal_Number Nd digit Enclosing_Mark Me Final_Punctuation Pf Format Cf Initial_Punctuation Pi Letter L Letter_Number Nl Line_Separator Zl Lowercase_Letter Ll Mark M Combining_Mark Math_Symbol Sm Modifier_Letter Lm Modifier_Symbol Sk Nonspacing_Mark Mn Number N Open_Punctuation Ps Other C Other_Letter Lo Other_Number No Other_Punctuation Po Other_Symbol So Paragraph_Separator Zp Private_Use Co Punctuation P punct Separator Z Space_Separator Zs Spacing_Mark Mc Surrogate Cs Symbol S Titlecase_Letter Lt Unassigned Cn Uppercase_Letter Lu"; // #table-unicode-script-values var ecma9ScriptValues = "Adlam Adlm Ahom Ahom Anatolian_Hieroglyphs Hluw Arabic Arab Armenian Armn Avestan Avst Balinese Bali Bamum Bamu Bassa_Vah Bass Batak Batk Bengali Beng Bhaiksuki Bhks Bopomofo Bopo Brahmi Brah Braille Brai Buginese Bugi Buhid Buhd Canadian_Aboriginal Cans Carian Cari Caucasian_Albanian Aghb Chakma Cakm Cham Cham Cherokee Cher Common Zyyy Coptic Copt Qaac Cuneiform Xsux Cypriot Cprt Cyrillic Cyrl Deseret Dsrt Devanagari Deva Duployan Dupl Egyptian_Hieroglyphs Egyp Elbasan Elba Ethiopic Ethi Georgian Geor Glagolitic Glag Gothic Goth Grantha Gran Greek Grek Gujarati Gujr Gurmukhi Guru Han Hani Hangul Hang Hanunoo Hano Hatran Hatr Hebrew Hebr Hiragana Hira Imperial_Aramaic Armi Inherited Zinh Qaai Inscriptional_Pahlavi Phli Inscriptional_Parthian Prti Javanese Java Kaithi Kthi Kannada Knda Katakana Kana Kayah_Li Kali Kharoshthi Khar Khmer Khmr Khojki Khoj Khudawadi Sind Lao Laoo Latin Latn Lepcha Lepc Limbu Limb Linear_A Lina Linear_B Linb Lisu Lisu Lycian Lyci Lydian Lydi Mahajani Mahj Malayalam Mlym Mandaic Mand Manichaean Mani Marchen Marc Masaram_Gondi Gonm Meetei_Mayek Mtei Mende_Kikakui Mend Meroitic_Cursive Merc Meroitic_Hieroglyphs Mero Miao Plrd Modi Modi Mongolian Mong Mro Mroo Multani Mult Myanmar Mymr Nabataean Nbat New_Tai_Lue Talu Newa Newa Nko Nkoo Nushu Nshu Ogham Ogam Ol_Chiki Olck Old_Hungarian Hung Old_Italic Ital Old_North_Arabian Narb Old_Permic Perm Old_Persian Xpeo Old_South_Arabian Sarb Old_Turkic Orkh Oriya Orya Osage Osge Osmanya Osma Pahawh_Hmong Hmng Palmyrene Palm Pau_Cin_Hau Pauc Phags_Pa Phag Phoenician Phnx Psalter_Pahlavi Phlp Rejang Rjng Runic Runr Samaritan Samr Saurashtra Saur Sharada Shrd Shavian Shaw Siddham Sidd SignWriting Sgnw Sinhala Sinh Sora_Sompeng Sora Soyombo Soyo Sundanese Sund Syloti_Nagri Sylo Syriac Syrc Tagalog Tglg Tagbanwa Tagb Tai_Le Tale Tai_Tham Lana Tai_Viet Tavt Takri Takr Tamil Taml Tangut Tang Telugu Telu Thaana Thaa Thai Thai Tibetan Tibt Tifinagh Tfng Tirhuta Tirh Ugaritic Ugar Vai Vaii Warang_Citi Wara Yi Yiii Zanabazar_Square Zanb"; var ecma10ScriptValues = ecma9ScriptValues + " Dogra Dogr Gunjala_Gondi Gong Hanifi_Rohingya Rohg Makasar Maka Medefaidrin Medf Old_Sogdian Sogo Sogdian Sogd"; var ecma11ScriptValues = ecma10ScriptValues + " Elymaic Elym Nandinagari Nand Nyiakeng_Puachue_Hmong Hmnp Wancho Wcho"; var unicodeScriptValues = { 9: ecma9ScriptValues, 10: ecma10ScriptValues, 11: ecma11ScriptValues }; var data = {}; function buildUnicodeData(ecmaVersion) { var d = data[ecmaVersion] = { binary: wordsRegexp(unicodeBinaryProperties[ecmaVersion] + " " + unicodeGeneralCategoryValues), nonBinary: { General_Category: wordsRegexp(unicodeGeneralCategoryValues), Script: wordsRegexp(unicodeScriptValues[ecmaVersion]) } }; d.nonBinary.Script_Extensions = d.nonBinary.Script; d.nonBinary.gc = d.nonBinary.General_Category; d.nonBinary.sc = d.nonBinary.Script; d.nonBinary.scx = d.nonBinary.Script_Extensions; } buildUnicodeData(9); buildUnicodeData(10); buildUnicodeData(11); var pp$8 = Parser.prototype; var RegExpValidationState = function RegExpValidationState(parser) { this.parser = parser; this.validFlags = "gim" + (parser.options.ecmaVersion >= 6 ? "uy" : "") + (parser.options.ecmaVersion >= 9 ? "s" : ""); this.unicodeProperties = data[parser.options.ecmaVersion >= 11 ? 11 : parser.options.ecmaVersion]; this.source = ""; this.flags = ""; this.start = 0; this.switchU = false; this.switchN = false; this.pos = 0; this.lastIntValue = 0; this.lastStringValue = ""; this.lastAssertionIsQuantifiable = false; this.numCapturingParens = 0; this.maxBackReference = 0; this.groupNames = []; this.backReferenceNames = []; }; RegExpValidationState.prototype.reset = function reset (start, pattern, flags) { var unicode = flags.indexOf("u") !== -1; this.start = start | 0; this.source = pattern + ""; this.flags = flags; this.switchU = unicode && this.parser.options.ecmaVersion >= 6; this.switchN = unicode && this.parser.options.ecmaVersion >= 9; }; RegExpValidationState.prototype.raise = function raise (message) { this.parser.raiseRecoverable(this.start, ("Invalid regular expression: /" + (this.source) + "/: " + message)); }; // If u flag is given, this returns the code point at the index (it combines a surrogate pair). // Otherwise, this returns the code unit of the index (can be a part of a surrogate pair). RegExpValidationState.prototype.at = function at (i) { var s = this.source; var l = s.length; if (i >= l) { return -1 } var c = s.charCodeAt(i); if (!this.switchU || c <= 0xD7FF || c >= 0xE000 || i + 1 >= l) { return c } return (c << 10) + s.charCodeAt(i + 1) - 0x35FDC00 }; RegExpValidationState.prototype.nextIndex = function nextIndex (i) { var s = this.source; var l = s.length; if (i >= l) { return l } var c = s.charCodeAt(i); if (!this.switchU || c <= 0xD7FF || c >= 0xE000 || i + 1 >= l) { return i + 1 } return i + 2 }; RegExpValidationState.prototype.current = function current () { return this.at(this.pos) }; RegExpValidationState.prototype.lookahead = function lookahead () { return this.at(this.nextIndex(this.pos)) }; RegExpValidationState.prototype.advance = function advance () { this.pos = this.nextIndex(this.pos); }; RegExpValidationState.prototype.eat = function eat (ch) { if (this.current() === ch) { this.advance(); return true } return false }; function codePointToString(ch) { if (ch <= 0xFFFF) { return String.fromCharCode(ch) } ch -= 0x10000; return String.fromCharCode((ch >> 10) + 0xD800, (ch & 0x03FF) + 0xDC00) } /** * Validate the flags part of a given RegExpLiteral. * * @param {RegExpValidationState} state The state to validate RegExp. * @returns {void} */ pp$8.validateRegExpFlags = function(state) { var validFlags = state.validFlags; var flags = state.flags; for (var i = 0; i < flags.length; i++) { var flag = flags.charAt(i); if (validFlags.indexOf(flag) === -1) { this.raise(state.start, "Invalid regular expression flag"); } if (flags.indexOf(flag, i + 1) > -1) { this.raise(state.start, "Duplicate regular expression flag"); } } }; /** * Validate the pattern part of a given RegExpLiteral. * * @param {RegExpValidationState} state The state to validate RegExp. * @returns {void} */ pp$8.validateRegExpPattern = function(state) { this.regexp_pattern(state); // The goal symbol for the parse is |Pattern[~U, ~N]|. If the result of // parsing contains a |GroupName|, reparse with the goal symbol // |Pattern[~U, +N]| and use this result instead. Throw a *SyntaxError* // exception if _P_ did not conform to the grammar, if any elements of _P_ // were not matched by the parse, or if any Early Error conditions exist. if (!state.switchN && this.options.ecmaVersion >= 9 && state.groupNames.length > 0) { state.switchN = true; this.regexp_pattern(state); } }; // https://www.ecma-international.org/ecma-262/8.0/#prod-Pattern pp$8.regexp_pattern = function(state) { state.pos = 0; state.lastIntValue = 0; state.lastStringValue = ""; state.lastAssertionIsQuantifiable = false; state.numCapturingParens = 0; state.maxBackReference = 0; state.groupNames.length = 0; state.backReferenceNames.length = 0; this.regexp_disjunction(state); if (state.pos !== state.source.length) { // Make the same messages as V8. if (state.eat(0x29 /* ) */)) { state.raise("Unmatched ')'"); } if (state.eat(0x5D /* [ */) || state.eat(0x7D /* } */)) { state.raise("Lone quantifier brackets"); } } if (state.maxBackReference > state.numCapturingParens) { state.raise("Invalid escape"); } for (var i = 0, list = state.backReferenceNames; i < list.length; i += 1) { var name = list[i]; if (state.groupNames.indexOf(name) === -1) { state.raise("Invalid named capture referenced"); } } }; // https://www.ecma-international.org/ecma-262/8.0/#prod-Disjunction pp$8.regexp_disjunction = function(state) { this.regexp_alternative(state); while (state.eat(0x7C /* | */)) { this.regexp_alternative(state); } // Make the same message as V8. if (this.regexp_eatQuantifier(state, true)) { state.raise("Nothing to repeat"); } if (state.eat(0x7B /* { */)) { state.raise("Lone quantifier brackets"); } }; // https://www.ecma-international.org/ecma-262/8.0/#prod-Alternative pp$8.regexp_alternative = function(state) { while (state.pos < state.source.length && this.regexp_eatTerm(state)) { } }; // https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-Term pp$8.regexp_eatTerm = function(state) { if (this.regexp_eatAssertion(state)) { // Handle `QuantifiableAssertion Quantifier` alternative. // `state.lastAssertionIsQuantifiable` is true if the last eaten Assertion // is a QuantifiableAssertion. if (state.lastAssertionIsQuantifiable && this.regexp_eatQuantifier(state)) { // Make the same message as V8. if (state.switchU) { state.raise("Invalid quantifier"); } } return true } if (state.switchU ? this.regexp_eatAtom(state) : this.regexp_eatExtendedAtom(state)) { this.regexp_eatQuantifier(state); return true } return false }; // https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-Assertion pp$8.regexp_eatAssertion = function(state) { var start = state.pos; state.lastAssertionIsQuantifiable = false; // ^, $ if (state.eat(0x5E /* ^ */) || state.eat(0x24 /* $ */)) { return true } // \b \B if (state.eat(0x5C /* \ */)) { if (state.eat(0x42 /* B */) || state.eat(0x62 /* b */)) { return true } state.pos = start; } // Lookahead / Lookbehind if (state.eat(0x28 /* ( */) && state.eat(0x3F /* ? */)) { var lookbehind = false; if (this.options.ecmaVersion >= 9) { lookbehind = state.eat(0x3C /* < */); } if (state.eat(0x3D /* = */) || state.eat(0x21 /* ! */)) { this.regexp_disjunction(state); if (!state.eat(0x29 /* ) */)) { state.raise("Unterminated group"); } state.lastAssertionIsQuantifiable = !lookbehind; return true } } state.pos = start; return false }; // https://www.ecma-international.org/ecma-262/8.0/#prod-Quantifier pp$8.regexp_eatQuantifier = function(state, noError) { if ( noError === void 0 ) noError = false; if (this.regexp_eatQuantifierPrefix(state, noError)) { state.eat(0x3F /* ? */); return true } return false }; // https://www.ecma-international.org/ecma-262/8.0/#prod-QuantifierPrefix pp$8.regexp_eatQuantifierPrefix = function(state, noError) { return ( state.eat(0x2A /* * */) || state.eat(0x2B /* + */) || state.eat(0x3F /* ? */) || this.regexp_eatBracedQuantifier(state, noError) ) }; pp$8.regexp_eatBracedQuantifier = function(state, noError) { var start = state.pos; if (state.eat(0x7B /* { */)) { var min = 0, max = -1; if (this.regexp_eatDecimalDigits(state)) { min = state.lastIntValue; if (state.eat(0x2C /* , */) && this.regexp_eatDecimalDigits(state)) { max = state.lastIntValue; } if (state.eat(0x7D /* } */)) { // SyntaxError in https://www.ecma-international.org/ecma-262/8.0/#sec-term if (max !== -1 && max < min && !noError) { state.raise("numbers out of order in {} quantifier"); } return true } } if (state.switchU && !noError) { state.raise("Incomplete quantifier"); } state.pos = start; } return false }; // https://www.ecma-international.org/ecma-262/8.0/#prod-Atom pp$8.regexp_eatAtom = function(state) { return ( this.regexp_eatPatternCharacters(state) || state.eat(0x2E /* . */) || this.regexp_eatReverseSolidusAtomEscape(state) || this.regexp_eatCharacterClass(state) || this.regexp_eatUncapturingGroup(state) || this.regexp_eatCapturingGroup(state) ) }; pp$8.regexp_eatReverseSolidusAtomEscape = function(state) { var start = state.pos; if (state.eat(0x5C /* \ */)) { if (this.regexp_eatAtomEscape(state)) { return true } state.pos = start; } return false }; pp$8.regexp_eatUncapturingGroup = function(state) { var start = state.pos; if (state.eat(0x28 /* ( */)) { if (state.eat(0x3F /* ? */) && state.eat(0x3A /* : */)) { this.regexp_disjunction(state); if (state.eat(0x29 /* ) */)) { return true } state.raise("Unterminated group"); } state.pos = start; } return false }; pp$8.regexp_eatCapturingGroup = function(state) { if (state.eat(0x28 /* ( */)) { if (this.options.ecmaVersion >= 9) { this.regexp_groupSpecifier(state); } else if (state.current() === 0x3F /* ? */) { state.raise("Invalid group"); } this.regexp_disjunction(state); if (state.eat(0x29 /* ) */)) { state.numCapturingParens += 1; return true } state.raise("Unterminated group"); } return false }; // https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-ExtendedAtom pp$8.regexp_eatExtendedAtom = function(state) { return ( state.eat(0x2E /* . */) || this.regexp_eatReverseSolidusAtomEscape(state) || this.regexp_eatCharacterClass(state) || this.regexp_eatUncapturingGroup(state) || this.regexp_eatCapturingGroup(state) || this.regexp_eatInvalidBracedQuantifier(state) || this.regexp_eatExtendedPatternCharacter(state) ) }; // https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-InvalidBracedQuantifier pp$8.regexp_eatInvalidBracedQuantifier = function(state) { if (this.regexp_eatBracedQuantifier(state, true)) { state.raise("Nothing to repeat"); } return false }; // https://www.ecma-international.org/ecma-262/8.0/#prod-SyntaxCharacter pp$8.regexp_eatSyntaxCharacter = function(state) { var ch = state.current(); if (isSyntaxCharacter(ch)) { state.lastIntValue = ch; state.advance(); return true } return false }; function isSyntaxCharacter(ch) { return ( ch === 0x24 /* $ */ || ch >= 0x28 /* ( */ && ch <= 0x2B /* + */ || ch === 0x2E /* . */ || ch === 0x3F /* ? */ || ch >= 0x5B /* [ */ && ch <= 0x5E /* ^ */ || ch >= 0x7B /* { */ && ch <= 0x7D /* } */ ) } // https://www.ecma-international.org/ecma-262/8.0/#prod-PatternCharacter // But eat eager. pp$8.regexp_eatPatternCharacters = function(state) { var start = state.pos; var ch = 0; while ((ch = state.current()) !== -1 && !isSyntaxCharacter(ch)) { state.advance(); } return state.pos !== start }; // https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-ExtendedPatternCharacter pp$8.regexp_eatExtendedPatternCharacter = function(state) { var ch = state.current(); if ( ch !== -1 && ch !== 0x24 /* $ */ && !(ch >= 0x28 /* ( */ && ch <= 0x2B /* + */) && ch !== 0x2E /* . */ && ch !== 0x3F /* ? */ && ch !== 0x5B /* [ */ && ch !== 0x5E /* ^ */ && ch !== 0x7C /* | */ ) { state.advance(); return true } return false }; // GroupSpecifier[U] :: // [empty] // `?` GroupName[?U] pp$8.regexp_groupSpecifier = function(state) { if (state.eat(0x3F /* ? */)) { if (this.regexp_eatGroupName(state)) { if (state.groupNames.indexOf(state.lastStringValue) !== -1) { state.raise("Duplicate capture group name"); } state.groupNames.push(state.lastStringValue); return } state.raise("Invalid group"); } }; // GroupName[U] :: // `<` RegExpIdentifierName[?U] `>` // Note: this updates `state.lastStringValue` property with the eaten name. pp$8.regexp_eatGroupName = function(state) { state.lastStringValue = ""; if (state.eat(0x3C /* < */)) { if (this.regexp_eatRegExpIdentifierName(state) && state.eat(0x3E /* > */)) { return true } state.raise("Invalid capture group name"); } return false }; // RegExpIdentifierName[U] :: // RegExpIdentifierStart[?U] // RegExpIdentifierName[?U] RegExpIdentifierPart[?U] // Note: this updates `state.lastStringValue` property with the eaten name. pp$8.regexp_eatRegExpIdentifierName = function(state) { state.lastStringValue = ""; if (this.regexp_eatRegExpIdentifierStart(state)) { state.lastStringValue += codePointToString(state.lastIntValue); while (this.regexp_eatRegExpIdentifierPart(state)) { state.lastStringValue += codePointToString(state.lastIntValue); } return true } return false }; // RegExpIdentifierStart[U] :: // UnicodeIDStart // `$` // `_` // `\` RegExpUnicodeEscapeSequence[?U] pp$8.regexp_eatRegExpIdentifierStart = function(state) { var start = state.pos; var ch = state.current(); state.advance(); if (ch === 0x5C /* \ */ && this.regexp_eatRegExpUnicodeEscapeSequence(state)) { ch = state.lastIntValue; } if (isRegExpIdentifierStart(ch)) { state.lastIntValue = ch; return true } state.pos = start; return false }; function isRegExpIdentifierStart(ch) { return isIdentifierStart(ch, true) || ch === 0x24 /* $ */ || ch === 0x5F /* _ */ } // RegExpIdentifierPart[U] :: // UnicodeIDContinue // `$` // `_` // `\` RegExpUnicodeEscapeSequence[?U] // // pp$8.regexp_eatRegExpIdentifierPart = function(state) { var start = state.pos; var ch = state.current(); state.advance(); if (ch === 0x5C /* \ */ && this.regexp_eatRegExpUnicodeEscapeSequence(state)) { ch = state.lastIntValue; } if (isRegExpIdentifierPart(ch)) { state.lastIntValue = ch; return true } state.pos = start; return false }; function isRegExpIdentifierPart(ch) { return isIdentifierChar(ch, true) || ch === 0x24 /* $ */ || ch === 0x5F /* _ */ || ch === 0x200C /* */ || ch === 0x200D /* */ } // https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-AtomEscape pp$8.regexp_eatAtomEscape = function(state) { if ( this.regexp_eatBackReference(state) || this.regexp_eatCharacterClassEscape(state) || this.regexp_eatCharacterEscape(state) || (state.switchN && this.regexp_eatKGroupName(state)) ) { return true } if (state.switchU) { // Make the same message as V8. if (state.current() === 0x63 /* c */) { state.raise("Invalid unicode escape"); } state.raise("Invalid escape"); } return false }; pp$8.regexp_eatBackReference = function(state) { var start = state.pos; if (this.regexp_eatDecimalEscape(state)) { var n = state.lastIntValue; if (state.switchU) { // For SyntaxError in https://www.ecma-international.org/ecma-262/8.0/#sec-atomescape if (n > state.maxBackReference) { state.maxBackReference = n; } return true } if (n <= state.numCapturingParens) { return true } state.pos = start; } return false }; pp$8.regexp_eatKGroupName = function(state) { if (state.eat(0x6B /* k */)) { if (this.regexp_eatGroupName(state)) { state.backReferenceNames.push(state.lastStringValue); return true } state.raise("Invalid named reference"); } return false }; // https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-CharacterEscape pp$8.regexp_eatCharacterEscape = function(state) { return ( this.regexp_eatControlEscape(state) || this.regexp_eatCControlLetter(state) || this.regexp_eatZero(state) || this.regexp_eatHexEscapeSequence(state) || this.regexp_eatRegExpUnicodeEscapeSequence(state) || (!state.switchU && this.regexp_eatLegacyOctalEscapeSequence(state)) || this.regexp_eatIdentityEscape(state) ) }; pp$8.regexp_eatCControlLetter = function(state) { var start = state.pos; if (state.eat(0x63 /* c */)) { if (this.regexp_eatControlLetter(state)) { return true } state.pos = start; } return false }; pp$8.regexp_eatZero = function(state) { if (state.current() === 0x30 /* 0 */ && !isDecimalDigit(state.lookahead())) { state.lastIntValue = 0; state.advance(); return true } return false }; // https://www.ecma-international.org/ecma-262/8.0/#prod-ControlEscape pp$8.regexp_eatControlEscape = function(state) { var ch = state.current(); if (ch === 0x74 /* t */) { state.lastIntValue = 0x09; /* \t */ state.advance(); return true } if (ch === 0x6E /* n */) { state.lastIntValue = 0x0A; /* \n */ state.advance(); return true } if (ch === 0x76 /* v */) { state.lastIntValue = 0x0B; /* \v */ state.advance(); return true } if (ch === 0x66 /* f */) { state.lastIntValue = 0x0C; /* \f */ state.advance(); return true } if (ch === 0x72 /* r */) { state.lastIntValue = 0x0D; /* \r */ state.advance(); return true } return false }; // https://www.ecma-international.org/ecma-262/8.0/#prod-ControlLetter pp$8.regexp_eatControlLetter = function(state) { var ch = state.current(); if (isControlLetter(ch)) { state.lastIntValue = ch % 0x20; state.advance(); return true } return false }; function isControlLetter(ch) { return ( (ch >= 0x41 /* A */ && ch <= 0x5A /* Z */) || (ch >= 0x61 /* a */ && ch <= 0x7A /* z */) ) } // https://www.ecma-international.org/ecma-262/8.0/#prod-RegExpUnicodeEscapeSequence pp$8.regexp_eatRegExpUnicodeEscapeSequence = function(state) { var start = state.pos; if (state.eat(0x75 /* u */)) { if (this.regexp_eatFixedHexDigits(state, 4)) { var lead = state.lastIntValue; if (state.switchU && lead >= 0xD800 && lead <= 0xDBFF) { var leadSurrogateEnd = state.pos; if (state.eat(0x5C /* \ */) && state.eat(0x75 /* u */) && this.regexp_eatFixedHexDigits(state, 4)) { var trail = state.lastIntValue; if (trail >= 0xDC00 && trail <= 0xDFFF) { state.lastIntValue = (lead - 0xD800) * 0x400 + (trail - 0xDC00) + 0x10000; return true } } state.pos = leadSurrogateEnd; state.lastIntValue = lead; } return true } if ( state.switchU && state.eat(0x7B /* { */) && this.regexp_eatHexDigits(state) && state.eat(0x7D /* } */) && isValidUnicode(state.lastIntValue) ) { return true } if (state.switchU) { state.raise("Invalid unicode escape"); } state.pos = start; } return false }; function isValidUnicode(ch) { return ch >= 0 && ch <= 0x10FFFF } // https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-IdentityEscape pp$8.regexp_eatIdentityEscape = function(state) { if (state.switchU) { if (this.regexp_eatSyntaxCharacter(state)) { return true } if (state.eat(0x2F /* / */)) { state.lastIntValue = 0x2F; /* / */ return true } return false } var ch = state.current(); if (ch !== 0x63 /* c */ && (!state.switchN || ch !== 0x6B /* k */)) { state.lastIntValue = ch; state.advance(); return true } return false }; // https://www.ecma-international.org/ecma-262/8.0/#prod-DecimalEscape pp$8.regexp_eatDecimalEscape = function(state) { state.lastIntValue = 0; var ch = state.current(); if (ch >= 0x31 /* 1 */ && ch <= 0x39 /* 9 */) { do { state.lastIntValue = 10 * state.lastIntValue + (ch - 0x30 /* 0 */); state.advance(); } while ((ch = state.current()) >= 0x30 /* 0 */ && ch <= 0x39 /* 9 */) return true } return false }; // https://www.ecma-international.org/ecma-262/8.0/#prod-CharacterClassEscape pp$8.regexp_eatCharacterClassEscape = function(state) { var ch = state.current(); if (isCharacterClassEscape(ch)) { state.lastIntValue = -1; state.advance(); return true } if ( state.switchU && this.options.ecmaVersion >= 9 && (ch === 0x50 /* P */ || ch === 0x70 /* p */) ) { state.lastIntValue = -1; state.advance(); if ( state.eat(0x7B /* { */) && this.regexp_eatUnicodePropertyValueExpression(state) && state.eat(0x7D /* } */) ) { return true } state.raise("Invalid property name"); } return false }; function isCharacterClassEscape(ch) { return ( ch === 0x64 /* d */ || ch === 0x44 /* D */ || ch === 0x73 /* s */ || ch === 0x53 /* S */ || ch === 0x77 /* w */ || ch === 0x57 /* W */ ) } // UnicodePropertyValueExpression :: // UnicodePropertyName `=` UnicodePropertyValue // LoneUnicodePropertyNameOrValue pp$8.regexp_eatUnicodePropertyValueExpression = function(state) { var start = state.pos; // UnicodePropertyName `=` UnicodePropertyValue if (this.regexp_eatUnicodePropertyName(state) && state.eat(0x3D /* = */)) { var name = state.lastStringValue; if (this.regexp_eatUnicodePropertyValue(state)) { var value = state.lastStringValue; this.regexp_validateUnicodePropertyNameAndValue(state, name, value); return true } } state.pos = start; // LoneUnicodePropertyNameOrValue if (this.regexp_eatLoneUnicodePropertyNameOrValue(state)) { var nameOrValue = state.lastStringValue; this.regexp_validateUnicodePropertyNameOrValue(state, nameOrValue); return true } return false }; pp$8.regexp_validateUnicodePropertyNameAndValue = function(state, name, value) { if (!has(state.unicodeProperties.nonBinary, name)) { state.raise("Invalid property name"); } if (!state.unicodeProperties.nonBinary[name].test(value)) { state.raise("Invalid property value"); } }; pp$8.regexp_validateUnicodePropertyNameOrValue = function(state, nameOrValue) { if (!state.unicodeProperties.binary.test(nameOrValue)) { state.raise("Invalid property name"); } }; // UnicodePropertyName :: // UnicodePropertyNameCharacters pp$8.regexp_eatUnicodePropertyName = function(state) { var ch = 0; state.lastStringValue = ""; while (isUnicodePropertyNameCharacter(ch = state.current())) { state.lastStringValue += codePointToString(ch); state.advance(); } return state.lastStringValue !== "" }; function isUnicodePropertyNameCharacter(ch) { return isControlLetter(ch) || ch === 0x5F /* _ */ } // UnicodePropertyValue :: // UnicodePropertyValueCharacters pp$8.regexp_eatUnicodePropertyValue = function(state) { var ch = 0; state.lastStringValue = ""; while (isUnicodePropertyValueCharacter(ch = state.current())) { state.lastStringValue += codePointToString(ch); state.advance(); } return state.lastStringValue !== "" }; function isUnicodePropertyValueCharacter(ch) { return isUnicodePropertyNameCharacter(ch) || isDecimalDigit(ch) } // LoneUnicodePropertyNameOrValue :: // UnicodePropertyValueCharacters pp$8.regexp_eatLoneUnicodePropertyNameOrValue = function(state) { return this.regexp_eatUnicodePropertyValue(state) }; // https://www.ecma-international.org/ecma-262/8.0/#prod-CharacterClass pp$8.regexp_eatCharacterClass = function(state) { if (state.eat(0x5B /* [ */)) { state.eat(0x5E /* ^ */); this.regexp_classRanges(state); if (state.eat(0x5D /* [ */)) { return true } // Unreachable since it threw "unterminated regular expression" error before. state.raise("Unterminated character class"); } return false }; // https://www.ecma-international.org/ecma-262/8.0/#prod-ClassRanges // https://www.ecma-international.org/ecma-262/8.0/#prod-NonemptyClassRanges // https://www.ecma-international.org/ecma-262/8.0/#prod-NonemptyClassRangesNoDash pp$8.regexp_classRanges = function(state) { while (this.regexp_eatClassAtom(state)) { var left = state.lastIntValue; if (state.eat(0x2D /* - */) && this.regexp_eatClassAtom(state)) { var right = state.lastIntValue; if (state.switchU && (left === -1 || right === -1)) { state.raise("Invalid character class"); } if (left !== -1 && right !== -1 && left > right) { state.raise("Range out of order in character class"); } } } }; // https://www.ecma-international.org/ecma-262/8.0/#prod-ClassAtom // https://www.ecma-international.org/ecma-262/8.0/#prod-ClassAtomNoDash pp$8.regexp_eatClassAtom = function(state) { var start = state.pos; if (state.eat(0x5C /* \ */)) { if (this.regexp_eatClassEscape(state)) { return true } if (state.switchU) { // Make the same message as V8. var ch$1 = state.current(); if (ch$1 === 0x63 /* c */ || isOctalDigit(ch$1)) { state.raise("Invalid class escape"); } state.raise("Invalid escape"); } state.pos = start; } var ch = state.current(); if (ch !== 0x5D /* [ */) { state.lastIntValue = ch; state.advance(); return true } return false }; // https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-ClassEscape pp$8.regexp_eatClassEscape = function(state) { var start = state.pos; if (state.eat(0x62 /* b */)) { state.lastIntValue = 0x08; /* */ return true } if (state.switchU && state.eat(0x2D /* - */)) { state.lastIntValue = 0x2D; /* - */ return true } if (!state.switchU && state.eat(0x63 /* c */)) { if (this.regexp_eatClassControlLetter(state)) { return true } state.pos = start; } return ( this.regexp_eatCharacterClassEscape(state) || this.regexp_eatCharacterEscape(state) ) }; // https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-ClassControlLetter pp$8.regexp_eatClassControlLetter = function(state) { var ch = state.current(); if (isDecimalDigit(ch) || ch === 0x5F /* _ */) { state.lastIntValue = ch % 0x20; state.advance(); return true } return false }; // https://www.ecma-international.org/ecma-262/8.0/#prod-HexEscapeSequence pp$8.regexp_eatHexEscapeSequence = function(state) { var start = state.pos; if (state.eat(0x78 /* x */)) { if (this.regexp_eatFixedHexDigits(state, 2)) { return true } if (state.switchU) { state.raise("Invalid escape"); } state.pos = start; } return false }; // https://www.ecma-international.org/ecma-262/8.0/#prod-DecimalDigits pp$8.regexp_eatDecimalDigits = function(state) { var start = state.pos; var ch = 0; state.lastIntValue = 0; while (isDecimalDigit(ch = state.current())) { state.lastIntValue = 10 * state.lastIntValue + (ch - 0x30 /* 0 */); state.advance(); } return state.pos !== start }; function isDecimalDigit(ch) { return ch >= 0x30 /* 0 */ && ch <= 0x39 /* 9 */ } // https://www.ecma-international.org/ecma-262/8.0/#prod-HexDigits pp$8.regexp_eatHexDigits = function(state) { var start = state.pos; var ch = 0; state.lastIntValue = 0; while (isHexDigit(ch = state.current())) { state.lastIntValue = 16 * state.lastIntValue + hexToInt(ch); state.advance(); } return state.pos !== start }; function isHexDigit(ch) { return ( (ch >= 0x30 /* 0 */ && ch <= 0x39 /* 9 */) || (ch >= 0x41 /* A */ && ch <= 0x46 /* F */) || (ch >= 0x61 /* a */ && ch <= 0x66 /* f */) ) } function hexToInt(ch) { if (ch >= 0x41 /* A */ && ch <= 0x46 /* F */) { return 10 + (ch - 0x41 /* A */) } if (ch >= 0x61 /* a */ && ch <= 0x66 /* f */) { return 10 + (ch - 0x61 /* a */) } return ch - 0x30 /* 0 */ } // https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-LegacyOctalEscapeSequence // Allows only 0-377(octal) i.e. 0-255(decimal). pp$8.regexp_eatLegacyOctalEscapeSequence = function(state) { if (this.regexp_eatOctalDigit(state)) { var n1 = state.lastIntValue; if (this.regexp_eatOctalDigit(state)) { var n2 = state.lastIntValue; if (n1 <= 3 && this.regexp_eatOctalDigit(state)) { state.lastIntValue = n1 * 64 + n2 * 8 + state.lastIntValue; } else { state.lastIntValue = n1 * 8 + n2; } } else { state.lastIntValue = n1; } return true } return false }; // https://www.ecma-international.org/ecma-262/8.0/#prod-OctalDigit pp$8.regexp_eatOctalDigit = function(state) { var ch = state.current(); if (isOctalDigit(ch)) { state.lastIntValue = ch - 0x30; /* 0 */ state.advance(); return true } state.lastIntValue = 0; return false }; function isOctalDigit(ch) { return ch >= 0x30 /* 0 */ && ch <= 0x37 /* 7 */ } // https://www.ecma-international.org/ecma-262/8.0/#prod-Hex4Digits // https://www.ecma-international.org/ecma-262/8.0/#prod-HexDigit // And HexDigit HexDigit in https://www.ecma-international.org/ecma-262/8.0/#prod-HexEscapeSequence pp$8.regexp_eatFixedHexDigits = function(state, length) { var start = state.pos; state.lastIntValue = 0; for (var i = 0; i < length; ++i) { var ch = state.current(); if (!isHexDigit(ch)) { state.pos = start; return false } state.lastIntValue = 16 * state.lastIntValue + hexToInt(ch); state.advance(); } return true }; // Object type used to represent tokens. Note that normally, tokens // simply exist as properties on the parser object. This is only // used for the onToken callback and the external tokenizer. var Token = function Token(p) { this.type = p.type; this.value = p.value; this.start = p.start; this.end = p.end; if (p.options.locations) { this.loc = new SourceLocation(p, p.startLoc, p.endLoc); } if (p.options.ranges) { this.range = [p.start, p.end]; } }; // ## Tokenizer var pp$9 = Parser.prototype; // Move to the next token pp$9.next = function() { if (this.options.onToken) { this.options.onToken(new Token(this)); } this.lastTokEnd = this.end; this.lastTokStart = this.start; this.lastTokEndLoc = this.endLoc; this.lastTokStartLoc = this.startLoc; this.nextToken(); }; pp$9.getToken = function() { this.next(); return new Token(this) }; // If we're in an ES6 environment, make parsers iterable if (typeof Symbol !== "undefined") { pp$9[Symbol.iterator] = function() { var this$1 = this; return { next: function () { var token = this$1.getToken(); return { done: token.type === types.eof, value: token } } } }; } // Toggle strict mode. Re-reads the next number or string to please // pedantic tests (`"use strict"; 010;` should fail). pp$9.curContext = function() { return this.context[this.context.length - 1] }; // Read a single token, updating the parser object's token-related // properties. pp$9.nextToken = function() { var curContext = this.curContext(); if (!curContext || !curContext.preserveSpace) { this.skipSpace(); } this.start = this.pos; if (this.options.locations) { this.startLoc = this.curPosition(); } if (this.pos >= this.input.length) { return this.finishToken(types.eof) } if (curContext.override) { return curContext.override(this) } else { this.readToken(this.fullCharCodeAtPos()); } }; pp$9.readToken = function(code) { // Identifier or keyword. '\uXXXX' sequences are allowed in // identifiers, so '\' also dispatches to that. if (isIdentifierStart(code, this.options.ecmaVersion >= 6) || code === 92 /* '\' */) { return this.readWord() } return this.getTokenFromCode(code) }; pp$9.fullCharCodeAtPos = function() { var code = this.input.charCodeAt(this.pos); if (code <= 0xd7ff || code >= 0xe000) { return code } var next = this.input.charCodeAt(this.pos + 1); return (code << 10) + next - 0x35fdc00 }; pp$9.skipBlockComment = function() { var startLoc = this.options.onComment && this.curPosition(); var start = this.pos, end = this.input.indexOf("*/", this.pos += 2); if (end === -1) { this.raise(this.pos - 2, "Unterminated comment"); } this.pos = end + 2; if (this.options.locations) { lineBreakG.lastIndex = start; var match; while ((match = lineBreakG.exec(this.input)) && match.index < this.pos) { ++this.curLine; this.lineStart = match.index + match[0].length; } } if (this.options.onComment) { this.options.onComment(true, this.input.slice(start + 2, end), start, this.pos, startLoc, this.curPosition()); } }; pp$9.skipLineComment = function(startSkip) { var start = this.pos; var startLoc = this.options.onComment && this.curPosition(); var ch = this.input.charCodeAt(this.pos += startSkip); while (this.pos < this.input.length && !isNewLine(ch)) { ch = this.input.charCodeAt(++this.pos); } if (this.options.onComment) { this.options.onComment(false, this.input.slice(start + startSkip, this.pos), start, this.pos, startLoc, this.curPosition()); } }; // Called at the start of the parse and after every token. Skips // whitespace and comments, and. pp$9.skipSpace = function() { loop: while (this.pos < this.input.length) { var ch = this.input.charCodeAt(this.pos); switch (ch) { case 32: case 160: // ' ' ++this.pos; break case 13: if (this.input.charCodeAt(this.pos + 1) === 10) { ++this.pos; } case 10: case 8232: case 8233: ++this.pos; if (this.options.locations) { ++this.curLine; this.lineStart = this.pos; } break case 47: // '/' switch (this.input.charCodeAt(this.pos + 1)) { case 42: // '*' this.skipBlockComment(); break case 47: this.skipLineComment(2); break default: break loop } break default: if (ch > 8 && ch < 14 || ch >= 5760 && nonASCIIwhitespace.test(String.fromCharCode(ch))) { ++this.pos; } else { break loop } } } }; // Called at the end of every token. Sets `end`, `val`, and // maintains `context` and `exprAllowed`, and skips the space after // the token, so that the next one's `start` will point at the // right position. pp$9.finishToken = function(type, val) { this.end = this.pos; if (this.options.locations) { this.endLoc = this.curPosition(); } var prevType = this.type; this.type = type; this.value = val; this.updateContext(prevType); }; // ### Token reading // This is the function that is called to fetch the next token. It // is somewhat obscure, because it works in character codes rather // than characters, and because operator parsing has been inlined // into it. // // All in the name of speed. // pp$9.readToken_dot = function() { var next = this.input.charCodeAt(this.pos + 1); if (next >= 48 && next <= 57) { return this.readNumber(true) } var next2 = this.input.charCodeAt(this.pos + 2); if (this.options.ecmaVersion >= 6 && next === 46 && next2 === 46) { // 46 = dot '.' this.pos += 3; return this.finishToken(types.ellipsis) } else { ++this.pos; return this.finishToken(types.dot) } }; pp$9.readToken_slash = function() { // '/' var next = this.input.charCodeAt(this.pos + 1); if (this.exprAllowed) { ++this.pos; return this.readRegexp() } if (next === 61) { return this.finishOp(types.assign, 2) } return this.finishOp(types.slash, 1) }; pp$9.readToken_mult_modulo_exp = function(code) { // '%*' var next = this.input.charCodeAt(this.pos + 1); var size = 1; var tokentype = code === 42 ? types.star : types.modulo; // exponentiation operator ** and **= if (this.options.ecmaVersion >= 7 && code === 42 && next === 42) { ++size; tokentype = types.starstar; next = this.input.charCodeAt(this.pos + 2); } if (next === 61) { return this.finishOp(types.assign, size + 1) } return this.finishOp(tokentype, size) }; pp$9.readToken_pipe_amp = function(code) { // '|&' var next = this.input.charCodeAt(this.pos + 1); if (next === code) { return this.finishOp(code === 124 ? types.logicalOR : types.logicalAND, 2) } if (next === 61) { return this.finishOp(types.assign, 2) } return this.finishOp(code === 124 ? types.bitwiseOR : types.bitwiseAND, 1) }; pp$9.readToken_caret = function() { // '^' var next = this.input.charCodeAt(this.pos + 1); if (next === 61) { return this.finishOp(types.assign, 2) } return this.finishOp(types.bitwiseXOR, 1) }; pp$9.readToken_plus_min = function(code) { // '+-' var next = this.input.charCodeAt(this.pos + 1); if (next === code) { if (next === 45 && !this.inModule && this.input.charCodeAt(this.pos + 2) === 62 && (this.lastTokEnd === 0 || lineBreak.test(this.input.slice(this.lastTokEnd, this.pos)))) { // A `-->` line comment this.skipLineComment(3); this.skipSpace(); return this.nextToken() } return this.finishOp(types.incDec, 2) } if (next === 61) { return this.finishOp(types.assign, 2) } return this.finishOp(types.plusMin, 1) }; pp$9.readToken_lt_gt = function(code) { // '<>' var next = this.input.charCodeAt(this.pos + 1); var size = 1; if (next === code) { size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2; if (this.input.charCodeAt(this.pos + size) === 61) { return this.finishOp(types.assign, size + 1) } return this.finishOp(types.bitShift, size) } if (next === 33 && code === 60 && !this.inModule && this.input.charCodeAt(this.pos + 2) === 45 && this.input.charCodeAt(this.pos + 3) === 45) { // `'; } /***/ }), /***/ "./node_modules/domelementtype/index.js": /*!**********************************************!*\ !*** ./node_modules/domelementtype/index.js ***! \**********************************************/ /*! no static exports found */ /***/ (function(module, exports) { //Types of elements found in the DOM module.exports = { Text: "text", //Text Directive: "directive", // Comment: "comment", // Script: "script", //'); return svgString; }; /***/ }), /***/ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/font-converter.js": /*!*********************************************************************************************!*\ !*** ./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/font-converter.js ***! \*********************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /** * @fileOverview Convert 2.0 fonts to 3.0 fonts. */ /** * Given an SVG, replace Scratch 2.0 fonts with new 3.0 fonts. Add defaults where there are none. * @param {SVGElement} svgTag The SVG dom object * @return {void} */ const convertFonts = function convertFonts(svgTag) { // Collect all text elements into a list. const textElements = []; const collectText = domElement => { if (domElement.localName === 'text') { textElements.push(domElement); } for (let i = 0; i < domElement.childNodes.length; i++) { collectText(domElement.childNodes[i]); } }; collectText(svgTag); // If there's an old font-family, switch to the new one. for (const textElement of textElements) { // If there's no font-family provided, provide one. if (!textElement.getAttribute('font-family') || textElement.getAttribute('font-family') === 'Helvetica') { textElement.setAttribute('font-family', 'Sans Serif'); } else if (textElement.getAttribute('font-family') === 'Mystery') { textElement.setAttribute('font-family', 'Curly'); } else if (textElement.getAttribute('font-family') === 'Gloria') { textElement.setAttribute('font-family', 'Handwriting'); } else if (textElement.getAttribute('font-family') === 'Donegal') { textElement.setAttribute('font-family', 'Serif'); } } }; module.exports = convertFonts; /***/ }), /***/ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/font-inliner.js": /*!*******************************************************************************************!*\ !*** ./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/font-inliner.js ***! \*******************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /** * @fileOverview Import bitmap data into Scratch 3.0, resizing image as necessary. */ const getFonts = __webpack_require__(/*! scratch-render-fonts */ "./src/lib/tw-scratch-render-fonts/index.js"); /** * Given SVG data, inline the fonts. This allows them to be rendered correctly when set * as the source of an HTMLImageElement. Here is a note from tmickel: * // Inject fonts that are needed. * // It would be nice if there were another way to get the SVG-in-canvas * // to render the correct font family, but I couldn't find any other way. * // Other things I tried: * // Just injecting the font-family into the document: no effect. * // External stylesheet linked to by SVG: no effect. * // Using a or to link to font-family * // injected into the document: no effect. * @param {string} svgString The string representation of the svg to modify * @return {string} The svg with any needed fonts inlined */ const inlineSvgFonts = function inlineSvgFonts(svgString) { const FONTS = getFonts(); // Make it clear that this function only operates on strings. // If we don't explicitly throw this here, the function silently fails. if (typeof svgString !== 'string') { throw new Error('SVG to be inlined is not a string'); } // Collect fonts that need injection. const fontsNeeded = new Set(); const fontRegex = /font-family="([^"]*)"/g; let matches = fontRegex.exec(svgString); while (matches) { fontsNeeded.add(matches[1]); matches = fontRegex.exec(svgString); } if (fontsNeeded.size > 0) { let str = ''; svgString = svgString.replace(/]*>/, "$&".concat(str)); return svgString; } return svgString; }; module.exports = inlineSvgFonts; /***/ }), /***/ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/index.js": /*!************************************************************************************!*\ !*** ./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/index.js ***! \************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const SVGRenderer = __webpack_require__(/*! ./svg-renderer */ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/svg-renderer.js"); const BitmapAdapter = __webpack_require__(/*! ./bitmap-adapter */ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/bitmap-adapter.js"); const inlineSvgFonts = __webpack_require__(/*! ./font-inliner */ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/font-inliner.js"); const loadSvgString = __webpack_require__(/*! ./load-svg-string */ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/load-svg-string.js"); const serializeSvgToString = __webpack_require__(/*! ./serialize-svg-to-string */ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/serialize-svg-to-string.js"); const SvgElement = __webpack_require__(/*! ./svg-element */ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/svg-element.js"); const convertFonts = __webpack_require__(/*! ./font-converter */ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/font-converter.js"); // /** // * Export for NPM & Node.js // * @type {RenderWebGL} // */ module.exports = { BitmapAdapter: BitmapAdapter, convertFonts: convertFonts, inlineSvgFonts: inlineSvgFonts, loadSvgString: loadSvgString, serializeSvgToString: serializeSvgToString, SvgElement: SvgElement, SVGRenderer: SVGRenderer }; /***/ }), /***/ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/load-svg-string.js": /*!**********************************************************************************************!*\ !*** ./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/load-svg-string.js ***! \**********************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const DOMPurify = __webpack_require__(/*! dompurify */ "./node_modules/dompurify/dist/purify.js"); const SvgElement = __webpack_require__(/*! ./svg-element */ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/svg-element.js"); const convertFonts = __webpack_require__(/*! ./font-converter */ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/font-converter.js"); const fixupSvgString = __webpack_require__(/*! ./fixup-svg-string */ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/fixup-svg-string.js"); const transformStrokeWidths = __webpack_require__(/*! ./transform-applier */ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/transform-applier.js"); /** * @param {SVGElement} svgTag the tag to search within * @param {string} [tagName] svg tag to search for (or collect all elements if not given) * @return {Array} a list of elements with the given tagname */ const collectElements = (svgTag, tagName) => { const elts = []; const collectElementsInner = domElement => { if ((domElement.localName === tagName || typeof tagName === 'undefined') && domElement.getAttribute) { elts.push(domElement); } for (let i = 0; i < domElement.childNodes.length; i++) { collectElementsInner(domElement.childNodes[i]); } }; collectElementsInner(svgTag); return elts; }; /** * Fix SVGs to comply with SVG spec. Scratch 2 defaults to x2 = 0 when x2 is missing, but * SVG defaults to x2 = 1 when missing. * @param {SVGSVGElement} svgTag the SVG tag to apply the transformation to */ const transformGradients = svgTag => { const linearGradientElements = collectElements(svgTag, 'linearGradient'); // For each gradient element, supply x2 if necessary. for (const gradientElement of linearGradientElements) { if (!gradientElement.getAttribute('x2')) { gradientElement.setAttribute('x2', '0'); } } }; /** * Fix SVGs to match appearance in Scratch 2, which used nearest neighbor scaling for bitmaps * within SVGs. * @param {SVGSVGElement} svgTag the SVG tag to apply the transformation to */ const transformImages = svgTag => { const imageElements = collectElements(svgTag, 'image'); // For each image element, set image rendering to pixelated const pixelatedImages = 'image-rendering: optimizespeed; image-rendering: pixelated;'; for (const elt of imageElements) { if (elt.getAttribute('style')) { elt.setAttribute('style', "".concat(pixelatedImages, " ").concat(elt.getAttribute('style'))); } else { elt.setAttribute('style', pixelatedImages); } } }; /** * Transforms an SVG's text elements for Scratch 2.0 quirks. * These quirks include: * 1. `x` and `y` properties are removed/ignored. * 2. Alignment is set to `text-before-edge`. * 3. Line-breaks are converted to explicit elements. * 4. Any required fonts are injected. * @param {SVGSVGElement} svgTag the SVG tag to apply the transformation to */ const transformText = svgTag => { // Collect all text elements into a list. const textElements = []; const collectText = domElement => { if (domElement.localName === 'text') { textElements.push(domElement); } for (let i = 0; i < domElement.childNodes.length; i++) { collectText(domElement.childNodes[i]); } }; collectText(svgTag); convertFonts(svgTag); // For each text element, apply quirks. for (const textElement of textElements) { // Remove x and y attributes - they are not used in Scratch. textElement.removeAttribute('x'); textElement.removeAttribute('y'); // Set text-before-edge alignment: // Scratch renders all text like this. textElement.setAttribute('alignment-baseline', 'text-before-edge'); textElement.setAttribute('xml:space', 'preserve'); // If there's no font size provided, provide one. if (!textElement.getAttribute('font-size')) { textElement.setAttribute('font-size', '18'); } let text = textElement.textContent; // Fix line breaks in text, which are not natively supported by SVG. // Only fix if text does not have child tspans. // @todo this will not work for font sizes with units such as em, percent // However, text made in scratch 2 should only ever export size 22 font. const fontSize = parseFloat(textElement.getAttribute('font-size')); const tx = 2; let ty = 0; let spacing = 1.2; // Try to match the position and spacing of Scratch 2.0's fonts. // Different fonts seem to use different line spacing. // Scratch 2 always uses alignment-baseline=text-before-edge // However, most SVG readers don't support this attribute // or don't support it alongside use of tspan, so the translations // here are to make up for that. if (textElement.getAttribute('font-family') === 'Handwriting') { spacing = 2; ty = -11 * fontSize / 22; } else if (textElement.getAttribute('font-family') === 'Scratch') { spacing = 0.89; ty = -3 * fontSize / 22; } else if (textElement.getAttribute('font-family') === 'Curly') { spacing = 1.38; ty = -6 * fontSize / 22; } else if (textElement.getAttribute('font-family') === 'Marker') { spacing = 1.45; ty = -6 * fontSize / 22; } else if (textElement.getAttribute('font-family') === 'Sans Serif') { spacing = 1.13; ty = -3 * fontSize / 22; } else if (textElement.getAttribute('font-family') === 'Serif') { spacing = 1.25; ty = -4 * fontSize / 22; } if (textElement.transform.baseVal.numberOfItems === 0) { const transform = svgTag.createSVGTransform(); textElement.transform.baseVal.appendItem(transform); } // Right multiply matrix by a translation of (tx, ty) const mtx = textElement.transform.baseVal.getItem(0).matrix; mtx.e += mtx.a * tx + mtx.c * ty; mtx.f += mtx.b * tx + mtx.d * ty; if (text && textElement.childElementCount === 0) { textElement.textContent = ''; const lines = text.split('\n'); text = ''; for (const line of lines) { const tspanNode = SvgElement.create('tspan'); tspanNode.setAttribute('x', '0'); tspanNode.setAttribute('style', 'white-space: pre'); tspanNode.setAttribute('dy', "".concat(spacing, "em")); tspanNode.textContent = line ? line : ' '; textElement.appendChild(tspanNode); } } } }; /** * Find the largest stroke width in the svg. If a shape has no * `stroke` property, it has a stroke-width of 0. If it has a `stroke`, * it is by default a stroke-width of 1. * This is used to enlarge the computed bounding box, which doesn't take * stroke width into account. * @param {SVGSVGElement} rootNode The root SVG node to traverse. * @return {number} The largest stroke width in the SVG. */ const findLargestStrokeWidth = rootNode => { let largestStrokeWidth = 0; const collectStrokeWidths = domElement => { if (domElement.getAttribute) { if (domElement.getAttribute('stroke')) { largestStrokeWidth = Math.max(largestStrokeWidth, 1); } if (domElement.getAttribute('stroke-width')) { largestStrokeWidth = Math.max(largestStrokeWidth, Number(domElement.getAttribute('stroke-width')) || 0); } } for (let i = 0; i < domElement.childNodes.length; i++) { collectStrokeWidths(domElement.childNodes[i]); } }; collectStrokeWidths(rootNode); return largestStrokeWidth; }; /** * Transform the measurements of the SVG. * In Scratch 2.0, SVGs are drawn without respect to the width, * height, and viewBox attribute on the tag. The exporter * does output these properties - but they appear to be incorrect often. * To address the incorrect measurements, we append the DOM to the * document, and then use SVG's native `getBBox` to find the real * drawn dimensions. This ensures things drawn in negative dimensions, * outside the given viewBox, etc., are all eventually drawn to the canvas. * I tried to do this several other ways: stripping the width/height/viewBox * attributes and then drawing (Firefox won't draw anything), * or inflating them and then measuring a canvas. But this seems to be * a natural and performant way. * @param {SVGSVGElement} svgTag the SVG tag to apply the transformation to */ const transformMeasurements = svgTag => { // Append the SVG dom to the document. // This allows us to use `getBBox` on the page, // which returns the full bounding-box of all drawn SVG // elements, similar to how Scratch 2.0 did measurement. const svgSpot = document.createElement('span'); // Since we're adding user-provided SVG to document.body, // sanitizing is required. This should not affect bounding box calculation. // outerHTML is attribute of Element (and not HTMLElement), so use it instead of // calling serializer or toString() // NOTE: svgTag remains untouched! const rawValue = svgTag.outerHTML; const sanitizedValue = DOMPurify.sanitize(rawValue, { // Use SVG profile (no HTML elements) USE_PROFILES: { svg: true }, // Remove some tags that Scratch does not use. FORBID_TAGS: ['a', 'audio', 'canvas', 'video'], // Allow data URI in image tags (e.g. SVGs converted from bitmap) ADD_DATA_URI_TAGS: ['image'] }); let bbox; try { // Insert sanitized value. svgSpot.innerHTML = sanitizedValue; document.body.appendChild(svgSpot); // Take the bounding box. We have to get elements via svgSpot // because we added it via innerHTML. bbox = svgSpot.children[0].getBBox(); } finally { // Always destroy the element, even if, for example, getBBox throws. document.body.removeChild(svgSpot); } // Enlarge the bbox from the largest found stroke width // This may have false-positives, but at least the bbox will always // contain the full graphic including strokes. // If the width or height is zero however, don't enlarge since // they won't have a stroke width that needs to be enlarged. let halfStrokeWidth; if (bbox.width === 0 || bbox.height === 0) { halfStrokeWidth = 0; } else { halfStrokeWidth = findLargestStrokeWidth(svgTag) / 2; } const width = bbox.width + halfStrokeWidth * 2; const height = bbox.height + halfStrokeWidth * 2; const x = bbox.x - halfStrokeWidth; const y = bbox.y - halfStrokeWidth; // Set the correct measurements on the SVG tag svgTag.setAttribute('width', width); svgTag.setAttribute('height', height); svgTag.setAttribute('viewBox', "".concat(x, " ").concat(y, " ").concat(width, " ").concat(height)); }; /** * Find all instances of a URL-referenced `stroke` in the svg. In 2.0, all gradient strokes * have a round `stroke-linejoin` and `stroke-linecap`... for some reason. * @param {SVGSVGElement} svgTag the SVG tag to apply the transformation to */ const setGradientStrokeRoundedness = svgTag => { const elements = collectElements(svgTag); for (const elt of elements) { if (!elt.style) continue; const stroke = elt.style.stroke || elt.getAttribute('stroke'); if (stroke && stroke.match(/^url\(#.*\)$/)) { elt.style['stroke-linejoin'] = 'round'; elt.style['stroke-linecap'] = 'round'; } } }; /** * In-place, convert passed SVG to something consistent that will be rendered the way we want them to be. * @param {SVGSvgElement} svgTag root SVG node to operate upon * @param {boolean} [fromVersion2] True if we should perform conversion from version 2 to version 3 svg. */ const normalizeSvg = (svgTag, fromVersion2) => { if (fromVersion2) { // Fix gradients. Scratch 2 exports no x2 when x2 = 0, but // SVG default is that x2 is 1. This must be done before // transformStrokeWidths since transformStrokeWidths affects // gradients. transformGradients(svgTag); } transformStrokeWidths(svgTag, window); transformImages(svgTag); if (fromVersion2) { // Transform all text elements. transformText(svgTag); // Transform measurements. transformMeasurements(svgTag); // Fix stroke roundedness. setGradientStrokeRoundedness(svgTag); } else if (!svgTag.getAttribute('viewBox')) { // Renderer expects a view box. transformMeasurements(svgTag); } else if (!svgTag.getAttribute('width') || !svgTag.getAttribute('height')) { svgTag.setAttribute('width', svgTag.viewBox.baseVal.width); svgTag.setAttribute('height', svgTag.viewBox.baseVal.height); } }; /** * Load an SVG string and normalize it. All the steps before drawing/measuring. * Currently, this will normalize stroke widths (see transform-applier.js) and render all embedded images pixelated. * The returned SVG will be guaranteed to always have a `width`, `height` and `viewBox`. * In addition, if the `fromVersion2` parameter is `true`, several "quirks-mode" transformations will be applied which * mimic Scratch 2.0's SVG rendering. * @param {!string} svgString String of SVG data to draw in quirks-mode. * @param {boolean} [fromVersion2] True if we should perform conversion from version 2 to version 3 svg. * @return {SVGSVGElement} The normalized SVG element. */ const loadSvgString = (svgString, fromVersion2) => { // Parse string into SVG XML. const parser = new DOMParser(); svgString = fixupSvgString(svgString); const svgDom = parser.parseFromString(svgString, 'text/xml'); if (svgDom.childNodes.length < 1 || svgDom.documentElement.localName !== 'svg') { throw new Error('Document does not appear to be SVG.'); } const svgTag = svgDom.documentElement; normalizeSvg(svgTag, fromVersion2); return svgTag; }; module.exports = loadSvgString; /***/ }), /***/ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/serialize-svg-to-string.js": /*!******************************************************************************************************!*\ !*** ./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/serialize-svg-to-string.js ***! \******************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const inlineSvgFonts = __webpack_require__(/*! ./font-inliner */ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/font-inliner.js"); /** * Serialize a given SVG DOM to a string. * @param {SVGSVGElement} svgTag The SVG element to serialize. * @param {?boolean} shouldInjectFonts True if fonts should be included in the SVG as * base64 data. * @returns {string} String representing current SVG data. */ const serializeSvgToString = (svgTag, shouldInjectFonts) => { const serializer = new XMLSerializer(); let string = serializer.serializeToString(svgTag); if (shouldInjectFonts) { string = inlineSvgFonts(string); } return string; }; module.exports = serializeSvgToString; /***/ }), /***/ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/svg-element.js": /*!******************************************************************************************!*\ !*** ./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/svg-element.js ***! \******************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /* Adapted from * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey * http://scratchdisk.com/ & http://jonathanpuckey.com/ * * Distributed under the MIT license. See LICENSE file for details. * * All rights reserved. */ /** * @name SvgElement * @namespace * @private */ class SvgElement { // SVG related namespaces static get svg() { return 'http://www.w3.org/2000/svg'; } static get xmlns() { return 'http://www.w3.org/2000/xmlns'; } static get xlink() { return 'http://www.w3.org/1999/xlink'; } // Mapping of attribute names to required namespaces: static attributeNamespace() { return { 'href': SvgElement.xlink, 'xlink': SvgElement.xmlns, // Only the xmlns attribute needs the trailing slash. See #984 'xmlns': "".concat(SvgElement.xmlns, "/"), // IE needs the xmlns namespace when setting 'xmlns:xlink'. See #984 'xmlns:xlink': "".concat(SvgElement.xmlns, "/") }; } static create(tag, attributes, formatter) { return SvgElement.set(document.createElementNS(SvgElement.svg, tag), attributes, formatter); } static get(node, name) { const namespace = SvgElement.attributeNamespace[name]; const value = namespace ? node.getAttributeNS(namespace, name) : node.getAttribute(name); return value === 'null' ? null : value; } static set(node, attributes, formatter) { for (const name in attributes) { let value = attributes[name]; const namespace = SvgElement.attributeNamespace[name]; if (typeof value === 'number' && formatter) { value = formatter.number(value); } if (namespace) { node.setAttributeNS(namespace, name, value); } else { node.setAttribute(name, value); } } return node; } } module.exports = SvgElement; /***/ }), /***/ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/svg-renderer.js": /*!*******************************************************************************************!*\ !*** ./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/svg-renderer.js ***! \*******************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const loadSvgString = __webpack_require__(/*! ./load-svg-string */ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/load-svg-string.js"); const serializeSvgToString = __webpack_require__(/*! ./serialize-svg-to-string */ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/serialize-svg-to-string.js"); /** * Main quirks-mode SVG rendering code. * @deprecated Call into individual methods exported from this library instead. */ class SvgRenderer { /** * Create a quirks-mode SVG renderer for a particular canvas. * @param {HTMLCanvasElement} [canvas] An optional canvas element to draw to. If this is not provided, the renderer * will create a new canvas. * @constructor */ constructor(canvas) { /** * The canvas that this SVG renderer will render to. * @type {HTMLCanvasElement} * @private */ this._canvas = canvas || document.createElement('canvas'); this._context = this._canvas.getContext('2d'); /** * A measured SVG "viewbox" * @typedef {object} SvgRenderer#SvgMeasurements * @property {number} x - The left edge of the SVG viewbox. * @property {number} y - The top edge of the SVG viewbox. * @property {number} width - The width of the SVG viewbox. * @property {number} height - The height of the SVG viewbox. */ /** * The measurement box of the currently loaded SVG. * @type {SvgRenderer#SvgMeasurements} * @private */ this._measurements = { x: 0, y: 0, width: 0, height: 0 }; /** * The `` element with the contents of the currently loaded SVG. * @type {?HTMLImageElement} * @private */ this._cachedImage = null; /** * True if this renderer's current SVG is loaded and can be rendered to the canvas. * @type {boolean} */ this.loaded = false; } /** * @returns {!HTMLCanvasElement} this renderer's target canvas. */ get canvas() { return this._canvas; } /** * @return {Array} the natural size, in Scratch units, of this SVG. */ get size() { return [this._measurements.width, this._measurements.height]; } /** * @return {Array} the offset (upper left corner) of the SVG's view box. */ get viewOffset() { return [this._measurements.x, this._measurements.y]; } /** * Load an SVG string and normalize it. All the steps before drawing/measuring. * @param {!string} svgString String of SVG data to draw in quirks-mode. * @param {?boolean} fromVersion2 True if we should perform conversion from * version 2 to version 3 svg. */ loadString(svgString, fromVersion2) { // New svg string invalidates the cached image this._cachedImage = null; const svgTag = loadSvgString(svgString, fromVersion2); this._svgTag = svgTag; this._measurements = { width: svgTag.viewBox.baseVal.width, height: svgTag.viewBox.baseVal.height, x: svgTag.viewBox.baseVal.x, y: svgTag.viewBox.baseVal.y }; } /** * Load an SVG string, normalize it, and prepare it for (synchronous) rendering. * @param {!string} svgString String of SVG data to draw in quirks-mode. * @param {?boolean} fromVersion2 True if we should perform conversion from version 2 to version 3 svg. * @param {Function} [onFinish] - An optional callback to call when the SVG is loaded and can be rendered. */ loadSVG(svgString, fromVersion2, onFinish) { this.loadString(svgString, fromVersion2); this._createSVGImage(onFinish); } /** * Creates an element for the currently loaded SVG string, then calls the callback once it's loaded. * @param {Function} [onFinish] - An optional callback to call when the has loaded. */ _createSVGImage(onFinish) { if (this._cachedImage === null) this._cachedImage = new Image(); const img = this._cachedImage; img.onload = () => { this.loaded = true; if (onFinish) onFinish(); }; const svgText = this.toString(true /* shouldInjectFonts */ ); img.src = "data:image/svg+xml;utf8,".concat(encodeURIComponent(svgText)); this.loaded = false; } /** * Serialize the active SVG DOM to a string. * @param {?boolean} shouldInjectFonts True if fonts should be included in the SVG as * base64 data. * @returns {string} String representing current SVG data. * @deprecated Use the standalone `serializeSvgToString` export instead. */ toString(shouldInjectFonts) { return serializeSvgToString(this._svgTag, shouldInjectFonts); } /** * Synchronously draw the loaded SVG to this renderer's `canvas`. * @param {number} [scale] - Optionally, also scale the image by this factor. */ draw(scale) { if (!this.loaded) throw new Error('SVG image has not finished loading'); this._drawFromImage(scale); } /** * Draw to the canvas from a loaded image element. * @param {number} [scale] - Optionally, also scale the image by this factor. **/ _drawFromImage(scale) { if (this._cachedImage === null) return; const ratio = Number.isFinite(scale) ? scale : 1; const bbox = this._measurements; this._canvas.width = bbox.width * ratio; this._canvas.height = bbox.height * ratio; // Even if the canvas at the current scale has a nonzero size, the image's dimensions are floored pre-scaling. // e.g. if an image has a width of 0.4 and is being rendered at 3x scale, the canvas will have a width of 1, but // the image's width will be rounded down to 0 on some browsers (Firefox) prior to being drawn at that scale. if (this._canvas.width <= 0 || this._canvas.height <= 0 || this._cachedImage.naturalWidth <= 0 || this._cachedImage.naturalHeight <= 0) return; this._context.clearRect(0, 0, this._canvas.width, this._canvas.height); this._context.setTransform(ratio, 0, 0, ratio, 0, 0); this._context.drawImage(this._cachedImage, 0, 0); } } module.exports = SvgRenderer; /***/ }), /***/ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/transform-applier.js": /*!************************************************************************************************!*\ !*** ./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/transform-applier.js ***! \************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const Matrix = __webpack_require__(/*! transformation-matrix */ "./node_modules/transformation-matrix/build-umd/transformation-matrix.min.js"); const SvgElement = __webpack_require__(/*! ./svg-element */ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/svg-element.js"); const log = __webpack_require__(/*! ./util/log */ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/util/log.js"); /** * @fileOverview Apply transforms to match stroke width appearance in 2.0 and 3.0 */ // Adapted from paper.js's Path.applyTransform const _parseTransform = function _parseTransform(domElement) { let matrix = Matrix.identity(); const string = domElement.attributes && domElement.attributes.transform && domElement.attributes.transform.value; if (!string) return matrix; // https://www.w3.org/TR/SVG/types.html#DataTypeTransformList // Parse SVG transform string. First we split at /)\s*/, to separate // commands const transforms = string.split(/\)\s*/g); for (const transform of transforms) { if (!transform) break; // Command come before the '(', values after const parts = transform.split(/\(\s*/); const command = parts[0].trim(); const v = parts[1].split(/[\s,]+/g); // Convert values to floats for (let j = 0; j < v.length; j++) { v[j] = parseFloat(v[j]); } switch (command) { case 'matrix': matrix = Matrix.compose(matrix, { a: v[0], b: v[1], c: v[2], d: v[3], e: v[4], f: v[5] }); break; case 'rotate': matrix = Matrix.compose(matrix, Matrix.rotateDEG(v[0], v[1] || 0, v[2] || 0)); break; case 'translate': matrix = Matrix.compose(matrix, Matrix.translate(v[0], v[1] || 0)); break; case 'scale': matrix = Matrix.compose(matrix, Matrix.scale(v[0], v[1] || v[0])); break; case 'skewX': matrix = Matrix.compose(matrix, Matrix.skewDEG(v[0], 0)); break; case 'skewY': matrix = Matrix.compose(matrix, Matrix.skewDEG(0, v[0])); break; default: log.error("Couldn't parse: ".concat(command)); } } return matrix; }; // Adapted from paper.js's Matrix.decompose // Given a matrix, return the x and y scale factors of the matrix const _getScaleFactor = function _getScaleFactor(matrix) { const a = matrix.a; const b = matrix.b; const c = matrix.c; const d = matrix.d; const det = a * d - b * c; if (a !== 0 || b !== 0) { const r = Math.sqrt(a * a + b * b); return { x: r, y: det / r }; } if (c !== 0 || d !== 0) { const s = Math.sqrt(c * c + d * d); return { x: det / s, y: s }; } // a = b = c = d = 0 return { x: 0, y: 0 }; }; // Returns null if matrix is not invertible. Otherwise returns given ellipse // transformed by transform, an object {radiusX, radiusY, rotation}. const _calculateTransformedEllipse = function _calculateTransformedEllipse(radiusX, radiusY, theta, transform) { theta = -theta * Math.PI / 180; const a = transform.a; const b = -transform.c; const c = -transform.b; const d = transform.d; // Since other parameters determine the translation of the ellipse in SVG, we do not need to worry // about what e and f are. const det = a * d - b * c; // Non-invertible matrix if (det === 0) return null; // rotA, rotB, and rotC represent Ax^2 + Bxy + Cy^2 = 1 coefficients for a rotated ellipse formula const sinT = Math.sin(theta); const cosT = Math.cos(theta); const sin2T = Math.sin(2 * theta); const rotA = cosT * cosT / radiusX / radiusX + sinT * sinT / radiusY / radiusY; const rotB = sin2T / radiusX / radiusX - sin2T / radiusY / radiusY; const rotC = sinT * sinT / radiusX / radiusX + cosT * cosT / radiusY / radiusY; // Calculate the ellipse formula of the transformed ellipse // A, B, and C represent Ax^2 + Bxy + Cy^2 = 1 / det / det coefficients in a transformed ellipse formula // scaled by inverse det squared (to preserve accuracy) const A = rotA * d * d - rotB * d * c + rotC * c * c; const B = -2 * rotA * b * d + rotB * a * d + rotB * b * c - 2 * rotC * a * c; const C = rotA * b * b - rotB * a * b + rotC * a * a; // Derive new radii and theta from the transformed ellipse formula const newRadiusXOverDet = Math.sqrt(2) * Math.sqrt((A + C - Math.sqrt(A * A + B * B - 2 * A * C + C * C)) / (-B * B + 4 * A * C)); const newRadiusYOverDet = 1 / Math.sqrt(A + C - 1 / newRadiusXOverDet / newRadiusXOverDet); let temp = (A - 1 / newRadiusXOverDet / newRadiusXOverDet) / (1 / newRadiusYOverDet / newRadiusYOverDet - 1 / newRadiusXOverDet / newRadiusXOverDet); if (temp < 0 && Math.abs(temp) < 1e-8) temp = 0; // Fix floating point issue temp = Math.sqrt(temp); if (Math.abs(1 - temp) < 1e-8) temp = 1; // Fix floating point issue // Solve for which of the two possible thetas is correct let newTheta = Math.asin(temp); temp = B / (1 / newRadiusXOverDet / newRadiusXOverDet - 1 / newRadiusYOverDet / newRadiusYOverDet); const newTheta2 = -newTheta; if (Math.abs(Math.sin(2 * newTheta2) - temp) < Math.abs(Math.sin(2 * newTheta) - temp)) { newTheta = newTheta2; } return { radiusX: newRadiusXOverDet * det, radiusY: newRadiusYOverDet * det, rotation: -newTheta * 180 / Math.PI }; }; // Adapted from paper.js's PathItem.setPathData const _transformPath = function _transformPath(pathString, transform) { if (!transform || Matrix.toString(transform) === Matrix.toString(Matrix.identity())) return pathString; // First split the path data into parts of command-coordinates pairs // Commands are any of these characters: mzlhvcsqta const parts = pathString && pathString.match(/[mlhvcsqtaz][^mlhvcsqtaz]*/ig); let coords; let relative = false; let previous; let control; let current = { x: 0, y: 0 }; let start = { x: 0, y: 0 }; let result = ''; const getCoord = function getCoord(index, coord) { let val = +coords[index]; if (relative) { val += current[coord]; } return val; }; const getPoint = function getPoint(index) { return { x: getCoord(index, 'x'), y: getCoord(index + 1, 'y') }; }; const roundTo4Places = function roundTo4Places(num) { return Number(num.toFixed(4)); }; // Returns the transformed point as a string const getString = function getString(point) { const transformed = Matrix.applyToPoint(transform, point); return "".concat(roundTo4Places(transformed.x), " ").concat(roundTo4Places(transformed.y), " "); }; for (let i = 0, l = parts && parts.length; i < l; i++) { const part = parts[i]; const command = part[0]; const lower = command.toLowerCase(); // Match all coordinate values coords = part.match(/[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g); const length = coords && coords.length; relative = command === lower; // Fix issues with z in the middle of SVG path data, not followed by // a m command, see paper.js#413: if (previous === 'z' && !/[mz]/.test(lower)) { result += "M ".concat(current.x, " ").concat(current.y, " "); } switch (lower) { case 'm': // Move to case 'l': // Line to { let move = lower === 'm'; for (let j = 0; j < length; j += 2) { result += move ? 'M ' : 'L '; current = getPoint(j); result += getString(current); if (move) { start = current; move = false; } } control = current; break; } case 'h': // Horizontal line case 'v': // Vertical line { const coord = lower === 'h' ? 'x' : 'y'; current = { x: current.x, y: current.y }; // Clone as we're going to modify it. for (let j = 0; j < length; j++) { current[coord] = getCoord(j, coord); result += "L ".concat(getString(current)); } control = current; break; } case 'c': // Cubic Bezier curve for (let j = 0; j < length; j += 6) { const handle1 = getPoint(j); control = getPoint(j + 2); current = getPoint(j + 4); result += "C ".concat(getString(handle1)).concat(getString(control)).concat(getString(current)); } break; case 's': // Smooth cubic Bezier curve for (let j = 0; j < length; j += 4) { const handle1 = /[cs]/.test(previous) ? { x: current.x * 2 - control.x, y: current.y * 2 - control.y } : current; control = getPoint(j); current = getPoint(j + 2); result += "C ".concat(getString(handle1)).concat(getString(control)).concat(getString(current)); previous = lower; } break; case 'q': // Quadratic Bezier curve for (let j = 0; j < length; j += 4) { control = getPoint(j); current = getPoint(j + 2); result += "Q ".concat(getString(control)).concat(getString(current)); } break; case 't': // Smooth quadratic Bezier curve for (let j = 0; j < length; j += 2) { control = /[qt]/.test(previous) ? { x: current.x * 2 - control.x, y: current.y * 2 - control.y } : current; current = getPoint(j); result += "Q ".concat(getString(control)).concat(getString(current)); previous = lower; } break; case 'a': // Elliptical arc curve for (let j = 0; j < length; j += 7) { current = getPoint(j + 5); const rx = +coords[j]; const ry = +coords[j + 1]; const rotation = +coords[j + 2]; const largeArcFlag = +coords[j + 3]; let clockwiseFlag = +coords[j + 4]; const newEllipse = _calculateTransformedEllipse(rx, ry, rotation, transform); const matrixScale = _getScaleFactor(transform); if (newEllipse) { if (matrixScale.x > 0 && matrixScale.y < 0 || matrixScale.x < 0 && matrixScale.y > 0) { clockwiseFlag = clockwiseFlag ^ 1; } result += "A ".concat(roundTo4Places(Math.abs(newEllipse.radiusX)), " ") + "".concat(roundTo4Places(Math.abs(newEllipse.radiusY)), " ") + "".concat(roundTo4Places(newEllipse.rotation), " ").concat(largeArcFlag, " ") + "".concat(clockwiseFlag, " ").concat(getString(current)); } else { result += "L ".concat(getString(current)); } } break; case 'z': // Close path result += "Z "; // Correctly handle relative m commands, see paper.js#1101: current = start; break; } previous = lower; } return result; }; const GRAPHICS_ELEMENTS = ['circle', 'ellipse', 'image', 'line', 'path', 'polygon', 'polyline', 'rect', 'text', 'use']; const CONTAINER_ELEMENTS = ['a', 'defs', 'g', 'marker', 'glyph', 'missing-glyph', 'pattern', 'svg', 'switch', 'symbol']; const _isContainerElement = function _isContainerElement(element) { return element.tagName && CONTAINER_ELEMENTS.includes(element.tagName.toLowerCase()); }; const _isGraphicsElement = function _isGraphicsElement(element) { return element.tagName && GRAPHICS_ELEMENTS.includes(element.tagName.toLowerCase()); }; const _isPathWithTransformAndStroke = function _isPathWithTransformAndStroke(element, strokeWidth) { if (!element.attributes) return false; strokeWidth = element.attributes['stroke-width'] ? Number(element.attributes['stroke-width'].value) : Number(strokeWidth); return strokeWidth && element.tagName && element.tagName.toLowerCase() === 'path' && element.attributes.d && element.attributes.d.value; }; const _quadraticMean = function _quadraticMean(a, b) { return Math.sqrt((a * a + b * b) / 2); }; const _createGradient = function _createGradient(gradientId, svgTag, bbox, matrix) { // Adapted from Paper.js's SvgImport.getValue const getValue = function getValue(node, name, isString, allowNull, allowPercent, defaultValue) { // Interpret value as number. Never return NaN, but 0 instead. // If the value is a sequence of numbers, parseFloat will // return the first occurring number, which is enough for now. let value = SvgElement.get(node, name); let res; if (value === null) { if (defaultValue) { res = defaultValue; if (/%\s*$/.test(res)) { value = defaultValue; res = parseFloat(value); } } else if (allowNull) { res = null; } else if (isString) { res = ''; } else { res = 0; } } else if (isString) { res = value; } else { res = parseFloat(value); } // Support for dimensions in percentage of the root size. If root-size // is not set (e.g. during ), just scale the percentage value to // 0..1, as required by gradients with gradientUnits="objectBoundingBox" if (/%\s*$/.test(value)) { const size = allowPercent ? 1 : bbox[/x|^width/.test(name) ? 'width' : 'height']; return res / 100 * size; } return res; }; const getPoint = function getPoint(node, x, y, allowNull, allowPercent, defaultX, defaultY) { x = getValue(node, x || 'x', false, allowNull, allowPercent, defaultX); y = getValue(node, y || 'y', false, allowNull, allowPercent, defaultY); return allowNull && (x === null || y === null) ? null : { x, y }; }; let defs = svgTag.getElementsByTagName('defs'); if (defs.length === 0) { defs = SvgElement.create('defs'); svgTag.appendChild(defs); } else { defs = defs[0]; } // Clone the old gradient. We'll make a new one, since the gradient might be reused elsewhere // with different transform matrix const oldGradient = svgTag.getElementById(gradientId); if (!oldGradient) return; const radial = oldGradient.tagName.toLowerCase() === 'radialgradient'; const newGradient = svgTag.getElementById(gradientId).cloneNode(true /* deep */ ); // Give the new gradient a new ID let matrixString = Matrix.toString(matrix); matrixString = matrixString.substring(8, matrixString.length - 1); const newGradientId = "".concat(gradientId, "-").concat(matrixString); newGradient.setAttribute('id', newGradientId); // This gradient already exists and was transformed before. Just reuse the already-transformed one. if (svgTag.getElementById(newGradientId)) { // This is the same code as in the end of the function, but I don't feel like wrapping the next 80 lines // in an `if (!svgTag.getElementById(newGradientId))` block return "url(#".concat(newGradientId, ")"); } const scaleToBounds = getValue(newGradient, 'gradientUnits', true) !== 'userSpaceOnUse'; let origin; let destination; let radius; let focal; if (radial) { origin = getPoint(newGradient, 'cx', 'cy', false, scaleToBounds, '50%', '50%'); radius = getValue(newGradient, 'r', false, false, scaleToBounds, '50%'); focal = getPoint(newGradient, 'fx', 'fy', true, scaleToBounds); } else { origin = getPoint(newGradient, 'x1', 'y1', false, scaleToBounds); destination = getPoint(newGradient, 'x2', 'y2', false, scaleToBounds, '1'); if (origin.x === destination.x && origin.y === destination.y) { // If it's degenerate, use the color of the last stop, as described by // https://www.w3.org/TR/SVG/pservers.html#LinearGradientNotes const stops = newGradient.getElementsByTagName('stop'); if (!stops.length || !stops[stops.length - 1].attributes || !stops[stops.length - 1].attributes['stop-color']) { return null; } return stops[stops.length - 1].attributes['stop-color'].value; } } // Transform points // Emulate SVG's gradientUnits="objectBoundingBox" if (scaleToBounds) { const boundsMatrix = Matrix.compose(Matrix.translate(bbox.x, bbox.y), Matrix.scale(bbox.width, bbox.height)); origin = Matrix.applyToPoint(boundsMatrix, origin); if (destination) destination = Matrix.applyToPoint(boundsMatrix, destination); if (radius) { radius = _quadraticMean(bbox.width, bbox.height) * radius; } if (focal) focal = Matrix.applyToPoint(boundsMatrix, focal); } if (radial) { origin = Matrix.applyToPoint(matrix, origin); const matrixScale = _getScaleFactor(matrix); radius = _quadraticMean(matrixScale.x, matrixScale.y) * radius; if (focal) focal = Matrix.applyToPoint(matrix, focal); } else { const dot = (a, b) => a.x * b.x + a.y * b.y; const multiply = (coefficient, v) => ({ x: coefficient * v.x, y: coefficient * v.y }); const add = (a, b) => ({ x: a.x + b.x, y: a.y + b.y }); const subtract = (a, b) => ({ x: a.x - b.x, y: a.y - b.y }); // The line through origin and gradientPerpendicular is the line at which the gradient starts let gradientPerpendicular = Math.abs(origin.x - destination.x) < 1e-8 ? add(origin, { x: 1, y: (origin.x - destination.x) / (destination.y - origin.y) }) : add(origin, { x: (destination.y - origin.y) / (origin.x - destination.x), y: 1 }); // Transform points gradientPerpendicular = Matrix.applyToPoint(matrix, gradientPerpendicular); origin = Matrix.applyToPoint(matrix, origin); destination = Matrix.applyToPoint(matrix, destination); // Calculate the direction that the gradient has changed to const originToPerpendicular = subtract(gradientPerpendicular, origin); const originToDestination = subtract(destination, origin); const gradientDirection = Math.abs(originToPerpendicular.x) < 1e-8 ? { x: 1, y: -originToPerpendicular.x / originToPerpendicular.y } : { x: -originToPerpendicular.y / originToPerpendicular.x, y: 1 }; // Set the destination so that the gradient moves in the correct direction, by projecting the destination vector // onto the gradient direction vector const projectionCoeff = dot(originToDestination, gradientDirection) / dot(gradientDirection, gradientDirection); const projection = multiply(projectionCoeff, gradientDirection); destination = { x: origin.x + projection.x, y: origin.y + projection.y }; } // Put values back into svg if (radial) { newGradient.setAttribute('cx', Number(origin.x.toFixed(4))); newGradient.setAttribute('cy', Number(origin.y.toFixed(4))); newGradient.setAttribute('r', Number(radius.toFixed(4))); if (focal) { newGradient.setAttribute('fx', Number(focal.x.toFixed(4))); newGradient.setAttribute('fy', Number(focal.y.toFixed(4))); } } else { newGradient.setAttribute('x1', Number(origin.x.toFixed(4))); newGradient.setAttribute('y1', Number(origin.y.toFixed(4))); newGradient.setAttribute('x2', Number(destination.x.toFixed(4))); newGradient.setAttribute('y2', Number(destination.y.toFixed(4))); } newGradient.setAttribute('gradientUnits', 'userSpaceOnUse'); defs.appendChild(newGradient); return "url(#".concat(newGradientId, ")"); }; // Adapted from paper.js's SvgImport.getDefinition const _parseUrl = (value, windowRef) => { // When url() comes from a style property, '#'' seems to be missing on // WebKit. We also get variations of quotes or no quotes, single or // double, so handle it all with one regular expression: const match = value && value.match(/\((?:["'#]*)([^"')]+)/); const name = match && match[1]; const res = name && windowRef ? // This is required by Firefox, which can produce absolute // urls for local gradients, see paperjs#1001: name.replace("".concat(windowRef.location.href.split('#')[0], "#"), '') : name; return res; }; /** * Scratch 2.0 displays stroke widths in a "normalized" way, that is, * if a shape with a stroke width has a transform applied, it will be * rendered with a stroke that is the same width all the way around, * instead of stretched looking. * * The vector paint editor also prefers to normalize the stroke width, * rather than keep track of transforms at the group level, as this * simplifies editing (e.g. stroke width 3 always means the same thickness) * * This function performs that normalization process, pushing transforms * on groups down to the leaf level and averaging out the stroke width * around the shapes. Note that this doens't just change stroke widths, it * changes path data and attributes throughout the SVG. * * @param {SVGElement} svgTag The SVG dom object * @param {Window} windowRef The window to use. Need to pass in for * tests to work, as they get angry at even the mention of window. * @param {object} bboxForTesting The bounds to use. Need to pass in for * tests only, because getBBox doesn't work in Node. This should * be the bounds of the svgTag without including stroke width or transforms. * @return {void} */ const transformStrokeWidths = function transformStrokeWidths(svgTag, windowRef, bboxForTesting) { const inherited = Matrix.identity(); const applyTransforms = (element, matrix, strokeWidth, fill, stroke) => { if (_isContainerElement(element)) { // Push fills and stroke width down to leaves if (element.attributes['stroke-width']) { strokeWidth = element.attributes['stroke-width'].value; } if (element.attributes) { if (element.attributes.fill) fill = element.attributes.fill.value; if (element.attributes.stroke) stroke = element.attributes.stroke.value; } // If any child nodes don't take attributes, leave the attributes // at the parent level. for (let i = 0; i < element.childNodes.length; i++) { applyTransforms(element.childNodes[i], Matrix.compose(matrix, _parseTransform(element)), strokeWidth, fill, stroke); } element.removeAttribute('transform'); element.removeAttribute('stroke-width'); element.removeAttribute('fill'); element.removeAttribute('stroke'); } else if (_isPathWithTransformAndStroke(element, strokeWidth)) { if (element.attributes['stroke-width']) { strokeWidth = element.attributes['stroke-width'].value; } if (element.attributes.fill) fill = element.attributes.fill.value; if (element.attributes.stroke) stroke = element.attributes.stroke.value; matrix = Matrix.compose(matrix, _parseTransform(element)); if (Matrix.toString(matrix) === Matrix.toString(Matrix.identity())) { element.removeAttribute('transform'); element.setAttribute('stroke-width', strokeWidth); if (fill) element.setAttribute('fill', fill); if (stroke) element.setAttribute('stroke', stroke); return; } // Transform gradient const fillGradientId = _parseUrl(fill, windowRef); const strokeGradientId = _parseUrl(stroke, windowRef); if (fillGradientId || strokeGradientId) { const doc = windowRef.document; // Need path bounds to transform gradient const svgSpot = doc.createElement('span'); let bbox; if (bboxForTesting) { bbox = bboxForTesting; } else { try { doc.body.appendChild(svgSpot); const svg = SvgElement.set(doc.createElementNS(SvgElement.svg, 'svg')); const path = SvgElement.set(doc.createElementNS(SvgElement.svg, 'path')); path.setAttribute('d', element.attributes.d.value); svg.appendChild(path); svgSpot.appendChild(svg); // Take the bounding box. bbox = svg.getBBox(); } finally { // Always destroy the element, even if, for example, getBBox throws. doc.body.removeChild(svgSpot); } } if (fillGradientId) { const newFillRef = _createGradient(fillGradientId, svgTag, bbox, matrix); if (newFillRef) fill = newFillRef; } if (strokeGradientId) { const newStrokeRef = _createGradient(strokeGradientId, svgTag, bbox, matrix); if (newStrokeRef) stroke = newStrokeRef; } } // Transform path data element.setAttribute('d', _transformPath(element.attributes.d.value, matrix)); element.removeAttribute('transform'); // Transform stroke width const matrixScale = _getScaleFactor(matrix); element.setAttribute('stroke-width', _quadraticMean(matrixScale.x, matrixScale.y) * strokeWidth); if (fill) element.setAttribute('fill', fill); if (stroke) element.setAttribute('stroke', stroke); } else if (_isGraphicsElement(element)) { // Push stroke width, fill, and stroke down to leaves if (strokeWidth && !element.attributes['stroke-width']) { element.setAttribute('stroke-width', strokeWidth); } if (fill && !element.attributes.fill) { element.setAttribute('fill', fill); } if (stroke && !element.attributes.stroke) { element.setAttribute('stroke', stroke); } // Push transform down to leaves matrix = Matrix.compose(matrix, _parseTransform(element)); if (Matrix.toString(matrix) === Matrix.toString(Matrix.identity())) { element.removeAttribute('transform'); } else { element.setAttribute('transform', Matrix.toString(matrix)); } } }; applyTransforms(svgTag, inherited, 1 /* default SVG stroke width */ ); }; module.exports = transformStrokeWidths; /***/ }), /***/ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/util/log.js": /*!***************************************************************************************!*\ !*** ./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/util/log.js ***! \***************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const minilog = __webpack_require__(/*! minilog */ "./node_modules/minilog/lib/web/index.js"); minilog.enable(); module.exports = minilog('scratch-svg-render'); /***/ }), /***/ "./node_modules/scratch-render/src/BitmapSkin.js": /*!*******************************************************!*\ !*** ./node_modules/scratch-render/src/BitmapSkin.js ***! \*******************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const twgl = __webpack_require__(/*! twgl.js */ "./node_modules/twgl.js/dist/4.x/twgl-full.js"); const Skin = __webpack_require__(/*! ./Skin */ "./node_modules/scratch-render/src/Skin.js"); class BitmapSkin extends Skin { /** * Create a new Bitmap Skin. * @extends Skin * @param {!int} id - The ID for this Skin. * @param {!RenderWebGL} renderer - The renderer which will use this skin. */ constructor(id, renderer) { super(id, renderer); /** @type {!int} */ this._costumeResolution = 1; /** @type {Array} */ this._textureSize = [0, 0]; } /** * Dispose of this object. Do not use it after calling this method. */ dispose() { if (this._texture) { this._renderer.gl.deleteTexture(this._texture); this._texture = null; } super.dispose(); } /** * @return {Array} the "native" size, in texels, of this skin. */ get size() { return [this._textureSize[0] / this._costumeResolution, this._textureSize[1] / this._costumeResolution]; } /** * @param {Array} scale - The scaling factors to be used. * @return {WebGLTexture} The GL texture representation of this skin when drawing at the given scale. */ // eslint-disable-next-line no-unused-vars getTexture(scale) { return this._texture || super.getTexture(); } /** * Set the contents of this skin to a snapshot of the provided bitmap data. * @param {ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} bitmapData - new contents for this skin. * @param {int} [costumeResolution=1] - The resolution to use for this bitmap. * @param {Array} [rotationCenter] - Optional rotation center for the bitmap. If not supplied, it will be * calculated from the bounding box * @fires Skin.event:WasAltered */ setBitmap(bitmapData, costumeResolution, rotationCenter) { if (!bitmapData.width || !bitmapData.height) { super.setEmptyImageData(); return; } const gl = this._renderer.gl; // TW: We want to use as-is because reading ImageData wastes memory. // However, vanilla LLK/scratch-vm will reuse any canvas that we get here for other costumes, // which will cause bugs when Silhouette lazily reads the canvas data. // TurboWarp/scratch-vm does not reuse canvases and will set canvas.reusable = false. let textureData = bitmapData; if (bitmapData instanceof HTMLCanvasElement && bitmapData.reusable !== false) { const context = bitmapData.getContext('2d'); textureData = context.getImageData(0, 0, bitmapData.width, bitmapData.height); } if (this._texture === null) { const textureOptions = { auto: false, wrap: gl.CLAMP_TO_EDGE }; this._texture = twgl.createTexture(gl, textureOptions); } this._setTexture(textureData); // Do these last in case any of the above throws an exception this._costumeResolution = costumeResolution || 2; this._textureSize = BitmapSkin._getBitmapSize(bitmapData); if (typeof rotationCenter === 'undefined') rotationCenter = this.calculateRotationCenter(); this._rotationCenter[0] = rotationCenter[0]; this._rotationCenter[1] = rotationCenter[1]; this.emitWasAltered(); } /** * @param {ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} bitmapData - bitmap data to inspect. * @returns {Array} the width and height of the bitmap data, in pixels. * @private */ static _getBitmapSize(bitmapData) { if (bitmapData instanceof HTMLImageElement) { return [bitmapData.naturalWidth || bitmapData.width, bitmapData.naturalHeight || bitmapData.height]; } if (bitmapData instanceof HTMLVideoElement) { return [bitmapData.videoWidth || bitmapData.width, bitmapData.videoHeight || bitmapData.height]; } // ImageData or HTMLCanvasElement return [bitmapData.width, bitmapData.height]; } } module.exports = BitmapSkin; /***/ }), /***/ "./node_modules/scratch-render/src/Drawable.js": /*!*****************************************************!*\ !*** ./node_modules/scratch-render/src/Drawable.js ***! \*****************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const twgl = __webpack_require__(/*! twgl.js */ "./node_modules/twgl.js/dist/4.x/twgl-full.js"); const Rectangle = __webpack_require__(/*! ./Rectangle */ "./node_modules/scratch-render/src/Rectangle.js"); const RenderConstants = __webpack_require__(/*! ./RenderConstants */ "./node_modules/scratch-render/src/RenderConstants.js"); const ShaderManager = __webpack_require__(/*! ./ShaderManager */ "./node_modules/scratch-render/src/ShaderManager.js"); const EffectTransform = __webpack_require__(/*! ./EffectTransform */ "./node_modules/scratch-render/src/EffectTransform.js"); const log = __webpack_require__(/*! ./util/log */ "./node_modules/scratch-render/src/util/log.js"); /** * An internal workspace for calculating texture locations from world vectors * this is REUSED for memory conservation reasons * @type {twgl.v3} */ const __isTouchingPosition = twgl.v3.create(); const FLOATING_POINT_ERROR_ALLOWANCE = 1e-6; /** * Convert a scratch space location into a texture space float. Uses the * internal __isTouchingPosition as a return value, so this should be copied * if you ever need to get two local positions and store both. Requires that * the drawable inverseMatrix is up to date. * * @param {Drawable} drawable The drawable to get the inverse matrix and uniforms from * @param {twgl.v3} vec [x,y] scratch space vector * @return {twgl.v3} [x,y] texture space float vector - transformed by effects and matrix */ const getLocalPosition = (drawable, vec) => { // Transfrom from world coordinates to Drawable coordinates. const localPosition = __isTouchingPosition; const v0 = vec[0]; const v1 = vec[1]; const m = drawable._inverseMatrix; // var v2 = v[2]; const d = v0 * m[3] + v1 * m[7] + m[15]; // The RenderWebGL quad flips the texture's X axis. So rendered bottom // left is 1, 0 and the top right is 0, 1. Flip the X axis so // localPosition matches that transformation. localPosition[0] = 0.5 - (v0 * m[0] + v1 * m[4] + m[12]) / d; localPosition[1] = (v0 * m[1] + v1 * m[5] + m[13]) / d + 0.5; // Fix floating point issues near 0. Filed https://github.com/LLK/scratch-render/issues/688 that // they're happening in the first place. // TODO: Check if this can be removed after render pull 479 is merged if (Math.abs(localPosition[0]) < FLOATING_POINT_ERROR_ALLOWANCE) localPosition[0] = 0; if (Math.abs(localPosition[1]) < FLOATING_POINT_ERROR_ALLOWANCE) localPosition[1] = 0; // Apply texture effect transform if the localPosition is within the drawable's space, // and any effects are currently active. if (drawable.enabledEffects !== 0 && localPosition[0] >= 0 && localPosition[0] < 1 && localPosition[1] >= 0 && localPosition[1] < 1) { EffectTransform.transformPoint(drawable, localPosition, localPosition); } return localPosition; }; class Drawable { /** * An object which can be drawn by the renderer. * @todo double-buffer all rendering state (position, skin, effects, etc.) * @param {!int} id - This Drawable's unique ID. * @param {!RenderWebGL} renderer - The renderer that created this Drawable * @constructor */ constructor(id, renderer) { /** @type {!int} */ this._id = id; this._renderer = renderer; /** * The uniforms to be used by the vertex and pixel shaders. * Some of these are used by other parts of the renderer as well. * @type {Object.} * @private */ this._uniforms = { /** * The model matrix, to concat with projection at draw time. * @type {module:twgl/m4.Mat4} */ u_modelMatrix: twgl.m4.identity(), /** * The color to use in the silhouette draw mode. * @type {Array} */ u_silhouetteColor: Drawable.color4fFromID(this._id) }; // Effect values are uniforms too const numEffects = ShaderManager.EFFECTS.length; for (let index = 0; index < numEffects; ++index) { const effectName = ShaderManager.EFFECTS[index]; const effectInfo = ShaderManager.EFFECT_INFO[effectName]; const converter = effectInfo.converter; this._uniforms[effectInfo.uniformName] = converter(0); } this._position = twgl.v3.create(0, 0); this._scale = twgl.v3.create(100, 100); this._direction = 90; this._transformDirty = true; this._rotationMatrix = twgl.m4.identity(); this._rotationTransformDirty = true; this._rotationAdjusted = twgl.v3.create(); this._rotationCenterDirty = true; this._skinScale = twgl.v3.create(0, 0, 0); this._skinScaleDirty = true; this._inverseMatrix = twgl.m4.identity(); this._inverseTransformDirty = true; this._visible = true; /** A bitmask identifying which effects are currently in use. * @readonly * @type {int} */ this.enabledEffects = 0; /** @todo move convex hull functionality, maybe bounds functionality overall, to Skin classes */ this._convexHullPoints = null; this._convexHullDirty = true; // The precise bounding box will be from the transformed convex hull points, // so initialize the array of transformed hull points in setConvexHullPoints. // Initializing it once per convex hull recalculation avoids unnecessary creation of twgl.v3 objects. this._transformedHullPoints = null; this._transformedHullDirty = true; this._skinWasAltered = this._skinWasAltered.bind(this); this.isTouching = this._isTouchingNever; this._highQuality = false; } setHighQuality(highQuality) { this._highQuality = highQuality; } /** * Dispose of this Drawable. Do not use it after calling this method. */ dispose() { // Use the setter: disconnect events this.skin = null; } /** * Mark this Drawable's transform as dirty. * It will be recalculated next time it's needed. */ setTransformDirty() { this._transformDirty = true; this._inverseTransformDirty = true; this._transformedHullDirty = true; } /** * @returns {number} The ID for this Drawable. */ get id() { return this._id; } /** * @returns {Skin} the current skin for this Drawable. */ get skin() { return this._skin; } /** * @param {Skin} newSkin - A new Skin for this Drawable. */ set skin(newSkin) { if (this._skin !== newSkin) { this._skin = newSkin; this._skinWasAltered(); } } /** * @returns {Array} the current scaling percentages applied to this Drawable. [100,100] is normal size. */ get scale() { return [this._scale[0], this._scale[1]]; } /** * @returns {object.} the shader uniforms to be used when rendering this Drawable. */ getUniforms() { if (this._transformDirty) { this._calculateTransform(); } return this._uniforms; } /** * @returns {boolean} whether this Drawable is visible. */ getVisible() { return this._visible; } /** * Update the position if it is different. Marks the transform as dirty. * @param {Array.} position A new position. */ updatePosition(position) { if (this._position[0] !== position[0] || this._position[1] !== position[1]) { if (this._highQuality) { this._position[0] = position[0]; this._position[1] = position[1]; } else { this._position[0] = Math.round(position[0]); this._position[1] = Math.round(position[1]); } this._renderer.dirty = true; this.setTransformDirty(); } } /** * Update the direction if it is different. Marks the transform as dirty. * @param {number} direction A new direction. */ updateDirection(direction) { if (this._direction !== direction) { this._direction = direction; this._renderer.dirty = true; this._rotationTransformDirty = true; this.setTransformDirty(); } } /** * Update the scale if it is different. Marks the transform as dirty. * @param {Array.} scale A new scale. */ updateScale(scale) { if (this._scale[0] !== scale[0] || this._scale[1] !== scale[1]) { this._scale[0] = scale[0]; this._scale[1] = scale[1]; this._renderer.dirty = true; this._rotationCenterDirty = true; this._skinScaleDirty = true; this.setTransformDirty(); } } /** * Update visibility if it is different. Marks the convex hull as dirty. * @param {boolean} visible A new visibility state. */ updateVisible(visible) { if (this._visible !== visible) { this._visible = visible; this._renderer.dirty = true; this.setConvexHullDirty(); } } /** * Update an effect. Marks the convex hull as dirty if the effect changes shape. * @param {string} effectName The name of the effect. * @param {number} rawValue A new effect value. */ updateEffect(effectName, rawValue) { this._renderer.dirty = true; const effectInfo = ShaderManager.EFFECT_INFO[effectName]; if (rawValue) { this.enabledEffects |= effectInfo.mask; } else { this.enabledEffects &= ~effectInfo.mask; } const converter = effectInfo.converter; this._uniforms[effectInfo.uniformName] = converter(rawValue); if (effectInfo.shapeChanges) { this.setConvexHullDirty(); } } /** * Update the position, direction, scale, or effect properties of this Drawable. * @deprecated Use specific update* methods instead. * @param {object.} properties The new property values to set. */ updateProperties(properties) { if ('position' in properties) { this.updatePosition(properties.position); } if ('direction' in properties) { this.updateDirection(properties.direction); } if ('scale' in properties) { this.updateScale(properties.scale); } if ('visible' in properties) { this.updateVisible(properties.visible); } const numEffects = ShaderManager.EFFECTS.length; for (let index = 0; index < numEffects; ++index) { const effectName = ShaderManager.EFFECTS[index]; if (effectName in properties) { this.updateEffect(effectName, properties[effectName]); } } } /** * Calculate the transform to use when rendering this Drawable. * @private */ _calculateTransform() { if (this._rotationTransformDirty) { const rotation = (270 - this._direction) * Math.PI / 180; // Calling rotationZ sets the destination matrix to a rotation // around the Z axis setting matrix components 0, 1, 4 and 5 with // cosine and sine values of the rotation. // twgl.m4.rotationZ(rotation, this._rotationMatrix); // twgl assumes the last value set to the matrix was anything. // Drawable knows, it was another rotationZ matrix, so we can skip // assigning the values that will never change. const c = Math.cos(rotation); const s = Math.sin(rotation); this._rotationMatrix[0] = c; this._rotationMatrix[1] = s; // this._rotationMatrix[2] = 0; // this._rotationMatrix[3] = 0; this._rotationMatrix[4] = -s; this._rotationMatrix[5] = c; // this._rotationMatrix[6] = 0; // this._rotationMatrix[7] = 0; // this._rotationMatrix[8] = 0; // this._rotationMatrix[9] = 0; // this._rotationMatrix[10] = 1; // this._rotationMatrix[11] = 0; // this._rotationMatrix[12] = 0; // this._rotationMatrix[13] = 0; // this._rotationMatrix[14] = 0; // this._rotationMatrix[15] = 1; this._rotationTransformDirty = false; } // Adjust rotation center relative to the skin. if (this._rotationCenterDirty && this.skin !== null) { // twgl version of the following in function work. // let rotationAdjusted = twgl.v3.subtract( // this.skin.rotationCenter, // twgl.v3.divScalar(this.skin.size, 2, this._rotationAdjusted), // this._rotationAdjusted // ); // rotationAdjusted = twgl.v3.multiply( // rotationAdjusted, this._scale, rotationAdjusted // ); // rotationAdjusted = twgl.v3.divScalar( // rotationAdjusted, 100, rotationAdjusted // ); // rotationAdjusted[1] *= -1; // Y flipped to Scratch coordinate. // rotationAdjusted[2] = 0; // Z coordinate is 0. // Locally assign rotationCenter and skinSize to keep from having // the Skin getter properties called twice while locally assigning // their components for readability. const rotationCenter = this.skin.rotationCenter; const skinSize = this.skin.size; const center0 = rotationCenter[0]; const center1 = rotationCenter[1]; const skinSize0 = skinSize[0]; const skinSize1 = skinSize[1]; const scale0 = this._scale[0]; const scale1 = this._scale[1]; const rotationAdjusted = this._rotationAdjusted; rotationAdjusted[0] = (center0 - skinSize0 / 2) * scale0 / 100; rotationAdjusted[1] = (center1 - skinSize1 / 2) * scale1 / 100 * -1; // rotationAdjusted[2] = 0; this._rotationCenterDirty = false; } if (this._skinScaleDirty && this.skin !== null) { // twgl version of the following in function work. // const scaledSize = twgl.v3.divScalar( // twgl.v3.multiply(this.skin.size, this._scale), // 100 // ); // // was NaN because the vectors have only 2 components. // scaledSize[2] = 0; // Locally assign skinSize to keep from having the Skin getter // properties called twice. const skinSize = this.skin.size; const scaledSize = this._skinScale; scaledSize[0] = skinSize[0] * this._scale[0] / 100; scaledSize[1] = skinSize[1] * this._scale[1] / 100; // scaledSize[2] = 0; this._skinScaleDirty = false; } const modelMatrix = this._uniforms.u_modelMatrix; // twgl version of the following in function work. // twgl.m4.identity(modelMatrix); // twgl.m4.translate(modelMatrix, this._position, modelMatrix); // twgl.m4.multiply(modelMatrix, this._rotationMatrix, modelMatrix); // twgl.m4.translate(modelMatrix, this._rotationAdjusted, modelMatrix); // twgl.m4.scale(modelMatrix, scaledSize, modelMatrix); // Drawable configures a 3D matrix for drawing in WebGL, but most values // will never be set because the inputs are on the X and Y position axis // and the Z rotation axis. Drawable can bring the work inside // _calculateTransform and greatly reduce the ammount of math and array // assignments needed. const scale0 = this._skinScale[0]; const scale1 = this._skinScale[1]; const rotation00 = this._rotationMatrix[0]; const rotation01 = this._rotationMatrix[1]; const rotation10 = this._rotationMatrix[4]; const rotation11 = this._rotationMatrix[5]; const adjusted0 = this._rotationAdjusted[0]; const adjusted1 = this._rotationAdjusted[1]; const position0 = this._position[0]; const position1 = this._position[1]; // Commented assignments show what the values are when the matrix was // instantiated. Those values will never change so they do not need to // be reassigned. modelMatrix[0] = scale0 * rotation00; modelMatrix[1] = scale0 * rotation01; // modelMatrix[2] = 0; // modelMatrix[3] = 0; modelMatrix[4] = scale1 * rotation10; modelMatrix[5] = scale1 * rotation11; // modelMatrix[6] = 0; // modelMatrix[7] = 0; // modelMatrix[8] = 0; // modelMatrix[9] = 0; // modelMatrix[10] = 1; // modelMatrix[11] = 0; modelMatrix[12] = rotation00 * adjusted0 + rotation10 * adjusted1 + position0; modelMatrix[13] = rotation01 * adjusted0 + rotation11 * adjusted1 + position1; // modelMatrix[14] = 0; // modelMatrix[15] = 1; this._transformDirty = false; } /** * Whether the Drawable needs convex hull points provided by the renderer. * @return {boolean} True when no convex hull known, or it's dirty. */ needsConvexHullPoints() { return !this._convexHullPoints || this._convexHullDirty || this._convexHullPoints.length === 0; } /** * Set the convex hull to be dirty. * Do this whenever the Drawable's shape has possibly changed. */ setConvexHullDirty() { this._convexHullDirty = true; } /** * Set the convex hull points for the Drawable. * @param {Array>} points Convex hull points, as [[x, y], ...] */ setConvexHullPoints(points) { this._convexHullPoints = points; this._convexHullDirty = false; // Re-create the "transformed hull points" array. // We only do this when the hull points change to avoid unnecessary allocations and GC. this._transformedHullPoints = []; for (let i = 0; i < points.length; i++) { this._transformedHullPoints.push(twgl.v3.create()); } this._transformedHullDirty = true; } /** * @function * @name isTouching * Check if the world position touches the skin. * The caller is responsible for ensuring this drawable's inverse matrix & its skin's silhouette are up-to-date. * @see updateCPURenderAttributes * @param {twgl.v3} vec World coordinate vector. * @return {boolean} True if the world position touches the skin. */ // `updateCPURenderAttributes` sets this Drawable instance's `isTouching` method // to one of the following three functions: // If this drawable has no skin, set it to `_isTouchingNever`. // Otherwise, if this drawable uses nearest-neighbor scaling at its current scale, set it to `_isTouchingNearest`. // Otherwise, set it to `_isTouchingLinear`. // This allows several checks to be moved from the `isTouching` function to `updateCPURenderAttributes`. // eslint-disable-next-line no-unused-vars _isTouchingNever(vec) { return false; } _isTouchingNearest(vec) { return this.skin.isTouchingNearest(getLocalPosition(this, vec)); } _isTouchingLinear(vec) { return this.skin.isTouchingLinear(getLocalPosition(this, vec)); } /** * Get the precise bounds for a Drawable. * This function applies the transform matrix to the known convex hull, * and then finds the minimum box along the axes. * Before calling this, ensure the renderer has updated convex hull points. * @param {?Rectangle} result optional destination for bounds calculation * @return {!Rectangle} Bounds for a tight box around the Drawable. */ getBounds(result) { if (this.needsConvexHullPoints()) { throw new Error('Needs updated convex hull points before bounds calculation.'); } if (this._transformDirty) { this._calculateTransform(); } const transformedHullPoints = this._getTransformedHullPoints(); // Search through transformed points to generate box on axes. result = result || new Rectangle(); result.initFromPointsAABB(transformedHullPoints); return result; } /** * Get the precise bounds for the upper 8px slice of the Drawable. * Used for calculating where to position a text bubble. * Before calling this, ensure the renderer has updated convex hull points. * @param {?Rectangle} result optional destination for bounds calculation * @return {!Rectangle} Bounds for a tight box around a slice of the Drawable. */ getBoundsForBubble(result) { if (this.needsConvexHullPoints()) { throw new Error('Needs updated convex hull points before bubble bounds calculation.'); } if (this._transformDirty) { this._calculateTransform(); } const slice = 8; // px, how tall the top slice to measure should be. const transformedHullPoints = this._getTransformedHullPoints(); const maxY = Math.max.apply(null, transformedHullPoints.map(p => p[1])); const filteredHullPoints = transformedHullPoints.filter(p => p[1] > maxY - slice); // Search through filtered points to generate box on axes. result = result || new Rectangle(); result.initFromPointsAABB(filteredHullPoints); return result; } /** * Get the rough axis-aligned bounding box for the Drawable. * Calculated by transforming the skin's bounds. * Note that this is less precise than the box returned by `getBounds`, * which is tightly snapped to account for a Drawable's transparent regions. * `getAABB` returns a much less accurate bounding box, but will be much * faster to calculate so may be desired for quick checks/optimizations. * @param {?Rectangle} result optional destination for bounds calculation * @return {!Rectangle} Rough axis-aligned bounding box for Drawable. */ getAABB(result) { if (this._transformDirty) { this._calculateTransform(); } const tm = this._uniforms.u_modelMatrix; result = result || new Rectangle(); result.initFromModelMatrix(tm); return result; } /** * Return the best Drawable bounds possible without performing graphics queries. * I.e., returns the tight bounding box when the convex hull points are already * known, but otherwise return the rough AABB of the Drawable. * @param {?Rectangle} result optional destination for bounds calculation * @return {!Rectangle} Bounds for the Drawable. */ getFastBounds(result) { if (!this.needsConvexHullPoints()) { return this.getBounds(result); } return this.getAABB(result); } /** * Transform all the convex hull points by the current Drawable's * transform. This allows us to skip recalculating the convex hull * for many Drawable updates, including translation, rotation, scaling. * @return {!Array.} Array of glPoints which are Array * @private */ _getTransformedHullPoints() { if (!this._transformedHullDirty) { return this._transformedHullPoints; } const projection = twgl.m4.ortho(-1, 1, -1, 1, -1, 1); const skinSize = this.skin.size; const halfXPixel = 1 / skinSize[0] / 2; const halfYPixel = 1 / skinSize[1] / 2; const tm = twgl.m4.multiply(this._uniforms.u_modelMatrix, projection); for (let i = 0; i < this._convexHullPoints.length; i++) { const point = this._convexHullPoints[i]; const dstPoint = this._transformedHullPoints[i]; dstPoint[0] = 0.5 + -point[0] / skinSize[0] - halfXPixel; dstPoint[1] = point[1] / skinSize[1] - 0.5 + halfYPixel; twgl.m4.transformPoint(tm, dstPoint, dstPoint); } this._transformedHullDirty = false; return this._transformedHullPoints; } /** * Update the transform matrix and calculate it's inverse for collision * and local texture position purposes. */ updateMatrix() { if (this._transformDirty) { this._calculateTransform(); } // Get the inverse of the model matrix or update it. if (this._inverseTransformDirty) { const inverse = this._inverseMatrix; twgl.m4.copy(this._uniforms.u_modelMatrix, inverse); // The normal matrix uses a z scaling of 0 causing model[10] to be // 0. Getting a 4x4 inverse is impossible without a scaling in x, y, // and z. inverse[10] = 1; twgl.m4.inverse(inverse, inverse); this._inverseTransformDirty = false; } } /** * Update everything necessary to render this drawable on the CPU. */ updateCPURenderAttributes() { this.updateMatrix(); // CPU rendering always occurs at the "native" size, so no need to scale up this._scale if (this.skin) { this.skin.updateSilhouette(this._scale); if (this.skin.useNearest(this._scale, this)) { this.isTouching = this._isTouchingNearest; } else { this.isTouching = this._isTouchingLinear; } } else { log.warn("Could not find skin for drawable with id: ".concat(this._id)); this.isTouching = this._isTouchingNever; } } /** * Respond to an internal change in the current Skin. */ _skinWasAltered() { this._renderer.dirty = true; this._rotationCenterDirty = true; this._skinScaleDirty = true; this.setConvexHullDirty(); this.setTransformDirty(); } /** * Calculate a color to represent the given ID number. At least one component of * the resulting color will be non-zero if the ID is not RenderConstants.ID_NONE. * @param {int} id The ID to convert. * @returns {Array} An array of [r,g,b,a], each component in the range [0,1]. */ static color4fFromID(id) { id -= RenderConstants.ID_NONE; const r = (id >> 0 & 255) / 255.0; const g = (id >> 8 & 255) / 255.0; const b = (id >> 16 & 255) / 255.0; return [r, g, b, 1.0]; } /** * Calculate the ID number represented by the given color. If all components of * the color are zero, the result will be RenderConstants.ID_NONE; otherwise the result * will be a valid ID. * @param {int} r The red value of the color, in the range [0,255]. * @param {int} g The green value of the color, in the range [0,255]. * @param {int} b The blue value of the color, in the range [0,255]. * @returns {int} The ID represented by that color. */ static color3bToID(r, g, b) { let id; id = (r & 255) << 0; id |= (g & 255) << 8; id |= (b & 255) << 16; return id + RenderConstants.ID_NONE; } /** * Sample a color from a drawable's texture. * The caller is responsible for ensuring this drawable's inverse matrix & its skin's silhouette are up-to-date. * @see updateCPURenderAttributes * @param {twgl.v3} vec The scratch space [x,y] vector * @param {Drawable} drawable The drawable to sample the texture from * @param {Uint8ClampedArray} dst The "color4b" representation of the texture at point. * @param {number} [effectMask] A bitmask for which effects to use. Optional. * @returns {Uint8ClampedArray} The dst object filled with the color4b */ static sampleColor4b(vec, drawable, dst, effectMask) { const localPosition = getLocalPosition(drawable, vec); if (localPosition[0] < 0 || localPosition[1] < 0 || localPosition[0] > 1 || localPosition[1] > 1) { dst[0] = 0; dst[1] = 0; dst[2] = 0; dst[3] = 0; return dst; } const textColor = // commenting out to only use nearest for now // drawable.skin.useNearest(drawable._scale, drawable) ? drawable.skin._silhouette.colorAtNearest(localPosition, dst); // : drawable.skin._silhouette.colorAtLinear(localPosition, dst); if (drawable.enabledEffects === 0) return textColor; return EffectTransform.transformColor(drawable, textColor, effectMask); } } module.exports = Drawable; /***/ }), /***/ "./node_modules/scratch-render/src/EffectTransform.js": /*!************************************************************!*\ !*** ./node_modules/scratch-render/src/EffectTransform.js ***! \************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /** * @fileoverview * A utility to transform a texture coordinate to another texture coordinate * representing how the shaders apply effects. */ const twgl = __webpack_require__(/*! twgl.js */ "./node_modules/twgl.js/dist/4.x/twgl-full.js"); const { rgbToHsv, hsvToRgb } = __webpack_require__(/*! ./util/color-conversions */ "./node_modules/scratch-render/src/util/color-conversions.js"); const ShaderManager = __webpack_require__(/*! ./ShaderManager */ "./node_modules/scratch-render/src/ShaderManager.js"); /** * A texture coordinate is between 0 and 1. 0.5 is the center position. * @const {number} */ const CENTER_X = 0.5; /** * A texture coordinate is between 0 and 1. 0.5 is the center position. * @const {number} */ const CENTER_Y = 0.5; /** * Reused memory location for storing an HSV color value. * @type {Array} */ const __hsv = [0, 0, 0]; class EffectTransform { /** * Transform a color in-place given the drawable's effect uniforms. Will apply * Ghost and Color and Brightness effects. * @param {Drawable} drawable The drawable to get uniforms from. * @param {Uint8ClampedArray} inOutColor The color to transform. * @param {number} [effectMask] A bitmask for which effects to use. Optional. * @returns {Uint8ClampedArray} dst filled with the transformed color */ static transformColor(drawable, inOutColor, effectMask) { // If the color is fully transparent, don't bother attempting any transformations. if (inOutColor[3] === 0) { return inOutColor; } let effects = drawable.enabledEffects; if (typeof effectMask === 'number') effects &= effectMask; const uniforms = drawable.getUniforms(); const enableColor = (effects & ShaderManager.EFFECT_INFO.color.mask) !== 0; const enableBrightness = (effects & ShaderManager.EFFECT_INFO.brightness.mask) !== 0; if (enableColor || enableBrightness) { // gl_FragColor.rgb /= gl_FragColor.a + epsilon; // Here, we're dividing by the (previously pre-multiplied) alpha to ensure HSV is properly calculated // for partially transparent pixels. // epsilon is present in the shader because dividing by 0 (fully transparent pixels) messes up calculations. // We're doing this with a Uint8ClampedArray here, so dividing by 0 just gives 255. We're later multiplying // by 0 again, so it won't affect results. const alpha = inOutColor[3] / 255; inOutColor[0] /= alpha; inOutColor[1] /= alpha; inOutColor[2] /= alpha; if (enableColor) { // vec3 hsv = convertRGB2HSV(gl_FragColor.xyz); const hsv = rgbToHsv(inOutColor, __hsv); // this code forces grayscale values to be slightly saturated // so that some slight change of hue will be visible // const float minLightness = 0.11 / 2.0; const minV = 0.11 / 2.0; // const float minSaturation = 0.09; const minS = 0.09; // if (hsv.z < minLightness) hsv = vec3(0.0, 1.0, minLightness); if (hsv[2] < minV) { hsv[0] = 0; hsv[1] = 1; hsv[2] = minV; // else if (hsv.y < minSaturation) hsv = vec3(0.0, minSaturation, hsv.z); } else if (hsv[1] < minS) { hsv[0] = 0; hsv[1] = minS; } // hsv.x = mod(hsv.x + u_color, 1.0); // if (hsv.x < 0.0) hsv.x += 1.0; hsv[0] = uniforms.u_color + hsv[0] + 1; // gl_FragColor.rgb = convertHSV2RGB(hsl); hsvToRgb(hsv, inOutColor); } if (enableBrightness) { const brightness = uniforms.u_brightness * 255; // gl_FragColor.rgb = clamp(gl_FragColor.rgb + vec3(u_brightness), vec3(0), vec3(1)); // We don't need to clamp because the Uint8ClampedArray does that for us inOutColor[0] += brightness; inOutColor[1] += brightness; inOutColor[2] += brightness; } // gl_FragColor.rgb *= gl_FragColor.a + epsilon; // Now we're doing the reverse, premultiplying by the alpha once again. inOutColor[0] *= alpha; inOutColor[1] *= alpha; inOutColor[2] *= alpha; } if ((effects & ShaderManager.EFFECT_INFO.ghost.mask) !== 0) { // gl_FragColor *= u_ghost inOutColor[0] *= uniforms.u_ghost; inOutColor[1] *= uniforms.u_ghost; inOutColor[2] *= uniforms.u_ghost; inOutColor[3] *= uniforms.u_ghost; } return inOutColor; } /** * Transform a texture coordinate to one that would be select after applying shader effects. * @param {Drawable} drawable The drawable whose effects to emulate. * @param {twgl.v3} vec The texture coordinate to transform. * @param {twgl.v3} dst A place to store the output coordinate. * @return {twgl.v3} dst - The coordinate after being transform by effects. */ static transformPoint(drawable, vec, dst) { twgl.v3.copy(vec, dst); const effects = drawable.enabledEffects; const uniforms = drawable.getUniforms(); if ((effects & ShaderManager.EFFECT_INFO.mosaic.mask) !== 0) { // texcoord0 = fract(u_mosaic * texcoord0); dst[0] = uniforms.u_mosaic * dst[0] % 1; dst[1] = uniforms.u_mosaic * dst[1] % 1; } if ((effects & ShaderManager.EFFECT_INFO.pixelate.mask) !== 0) { const skinUniforms = drawable.skin.getUniforms(); // vec2 pixelTexelSize = u_skinSize / u_pixelate; const texelX = skinUniforms.u_skinSize[0] / uniforms.u_pixelate; const texelY = skinUniforms.u_skinSize[1] / uniforms.u_pixelate; // texcoord0 = (floor(texcoord0 * pixelTexelSize) + kCenter) / // pixelTexelSize; dst[0] = (Math.floor(dst[0] * texelX) + CENTER_X) / texelX; dst[1] = (Math.floor(dst[1] * texelY) + CENTER_Y) / texelY; } if ((effects & ShaderManager.EFFECT_INFO.whirl.mask) !== 0) { // const float kRadius = 0.5; const RADIUS = 0.5; // vec2 offset = texcoord0 - kCenter; const offsetX = dst[0] - CENTER_X; const offsetY = dst[1] - CENTER_Y; // float offsetMagnitude = length(offset); const offsetMagnitude = Math.sqrt(Math.pow(offsetX, 2) + Math.pow(offsetY, 2)); // float whirlFactor = max(1.0 - (offsetMagnitude / kRadius), 0.0); const whirlFactor = Math.max(1.0 - offsetMagnitude / RADIUS, 0.0); // float whirlActual = u_whirl * whirlFactor * whirlFactor; const whirlActual = uniforms.u_whirl * whirlFactor * whirlFactor; // float sinWhirl = sin(whirlActual); const sinWhirl = Math.sin(whirlActual); // float cosWhirl = cos(whirlActual); const cosWhirl = Math.cos(whirlActual); // mat2 rotationMatrix = mat2( // cosWhirl, -sinWhirl, // sinWhirl, cosWhirl // ); const rot1 = cosWhirl; const rot2 = -sinWhirl; const rot3 = sinWhirl; const rot4 = cosWhirl; // texcoord0 = rotationMatrix * offset + kCenter; dst[0] = rot1 * offsetX + rot3 * offsetY + CENTER_X; dst[1] = rot2 * offsetX + rot4 * offsetY + CENTER_Y; } if ((effects & ShaderManager.EFFECT_INFO.fisheye.mask) !== 0) { // vec2 vec = (texcoord0 - kCenter) / kCenter; const vX = (dst[0] - CENTER_X) / CENTER_X; const vY = (dst[1] - CENTER_Y) / CENTER_Y; // float vecLength = length(vec); const vLength = Math.sqrt(vX * vX + vY * vY); // float r = pow(min(vecLength, 1.0), u_fisheye) * max(1.0, vecLength); const r = Math.pow(Math.min(vLength, 1), uniforms.u_fisheye) * Math.max(1, vLength); // vec2 unit = vec / vecLength; const unitX = vX / vLength; const unitY = vY / vLength; // texcoord0 = kCenter + r * unit * kCenter; dst[0] = CENTER_X + r * unitX * CENTER_X; dst[1] = CENTER_Y + r * unitY * CENTER_Y; } return dst; } } module.exports = EffectTransform; /***/ }), /***/ "./node_modules/scratch-render/src/PenSkin.js": /*!****************************************************!*\ !*** ./node_modules/scratch-render/src/PenSkin.js ***! \****************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const twgl = __webpack_require__(/*! twgl.js */ "./node_modules/twgl.js/dist/4.x/twgl-full.js"); const RenderConstants = __webpack_require__(/*! ./RenderConstants */ "./node_modules/scratch-render/src/RenderConstants.js"); const Skin = __webpack_require__(/*! ./Skin */ "./node_modules/scratch-render/src/Skin.js"); const ShaderManager = __webpack_require__(/*! ./ShaderManager */ "./node_modules/scratch-render/src/ShaderManager.js"); /** * Attributes to use when drawing with the pen * @typedef {object} PenSkin#PenAttributes * @property {number} [diameter] - The size (diameter) of the pen. * @property {Array} [color4f] - The pen color as an array of [r,g,b,a], each component in the range [0,1]. */ /** * The pen attributes to use when unspecified. * @type {PenSkin#PenAttributes} * @memberof PenSkin * @private * @const */ const DefaultPenAttributes = { color4f: [0, 0, 1, 1], diameter: 1 }; /** * Reused memory location for storing a premultiplied pen color. * @type {FloatArray} */ const __premultipliedColor = [0, 0, 0, 0]; const PEN_BUFFER_SIZE_LARGER = 65520; const PEN_BUFFER_SIZE_SMALLER = 32760; class PenSkin extends Skin { /** * Create a Skin which implements a Scratch pen layer. * @param {int} id - The unique ID for this Skin. * @param {RenderWebGL} renderer - The renderer which will use this Skin. * @extends Skin * @listens RenderWebGL#event:NativeSizeChanged */ constructor(id, renderer) { super(id, renderer); /** @type {Array} */ this._size = null; /** @type {WebGLFramebuffer} */ this._framebuffer = null; /** @type {boolean} */ this._silhouetteDirty = false; /** @type {Uint8Array} */ this._silhouettePixels = null; /** @type {ImageData} */ this._silhouetteImageData = null; /** @type {object} */ this._lineOnBufferDrawRegionId = { enter: () => this._enterDrawLineOnBuffer(), exit: () => this._exitDrawLineOnBuffer() }; /** @type {object} */ this._usePenBufferDrawRegionId = { enter: () => this._enterUsePenBuffer(), exit: () => this._exitUsePenBuffer() }; // tw: renderQuality attribute this.renderQuality = 1; // tw: keep track of native size this._nativeSize = renderer.getNativeSize(); // tw: create the extra data structures needed to buffer pen this._resetAttributeIndexes(); this.a_lineColor = new Float32Array(PEN_BUFFER_SIZE_LARGER); this.a_lineThicknessAndLength = new Float32Array(PEN_BUFFER_SIZE_SMALLER); this.a_penPoints = new Float32Array(PEN_BUFFER_SIZE_LARGER); this.a_position = new Float32Array(PEN_BUFFER_SIZE_SMALLER); for (let i = 0; i < this.a_position.length; i += 12) { this.a_position[i + 0] = 1; this.a_position[i + 1] = 0; this.a_position[i + 2] = 0; this.a_position[i + 3] = 0; this.a_position[i + 4] = 1; this.a_position[i + 5] = 1; this.a_position[i + 6] = 1; this.a_position[i + 7] = 1; this.a_position[i + 8] = 0; this.a_position[i + 9] = 0; this.a_position[i + 10] = 0; this.a_position[i + 11] = 1; } /** @type {twgl.BufferInfo} */ this._lineBufferInfo = twgl.createBufferInfoFromArrays(this._renderer.gl, { a_position: { numComponents: 2, data: this.a_position }, a_lineColor: { numComponents: 4, drawType: this._renderer.gl.STREAM_DRAW, data: this.a_lineColor }, a_lineThicknessAndLength: { numComponents: 2, drawType: this._renderer.gl.STREAM_DRAW, data: this.a_lineThicknessAndLength }, a_penPoints: { numComponents: 4, drawType: this._renderer.gl.STREAM_DRAW, data: this.a_penPoints } }); const NO_EFFECTS = 0; /** @type {twgl.ProgramInfo} */ this._lineShader = this._renderer._shaderManager.getShader(ShaderManager.DRAW_MODE.line, NO_EFFECTS); // tw: draw region used to preserve texture when resizing this._drawTextureShader = this._renderer._shaderManager.getShader(ShaderManager.DRAW_MODE.default, NO_EFFECTS); /** @type {object} */ this._drawTextureRegionId = { enter: () => this._enterDrawTexture(), exit: () => this._exitDrawTexture() }; this.onNativeSizeChanged = this.onNativeSizeChanged.bind(this); this._renderer.on(RenderConstants.Events.NativeSizeChanged, this.onNativeSizeChanged); this._setCanvasSize(renderer.getNativeSize()); } /** * Dispose of this object. Do not use it after calling this method. */ dispose() { this._renderer.removeListener(RenderConstants.Events.NativeSizeChanged, this.onNativeSizeChanged); this._renderer.gl.deleteTexture(this._texture); this._texture = null; super.dispose(); } /** * @return {Array} the "native" size, in texels, of this skin. [width, height] */ get size() { // tw: use native size for Drawable positioning logic return this._nativeSize; } useNearest(scale) { // Use nearest-neighbor interpolation when scaling up the pen skin-- this matches Scratch 2.0. // When scaling it down, use linear interpolation to avoid giving pen lines a "dashed" appearance. return Math.max(scale[0], scale[1]) >= 100; } /** * @param {Array} scale The X and Y scaling factors to be used, as percentages of this skin's "native" size. * @return {WebGLTexture} The GL texture representation of this skin when drawing at the given size. */ // eslint-disable-next-line no-unused-vars getTexture(scale) { return this._texture; } /** * Clear the pen layer. */ clear() { this._renderer.enterDrawRegion(this._usePenBufferDrawRegionId); /* Reset framebuffer to transparent black */ const gl = this._renderer.gl; gl.clearColor(0, 0, 0, 0); gl.clear(gl.COLOR_BUFFER_BIT); this._silhouetteDirty = true; } /** * Draw a point on the pen layer. * @param {PenAttributes} penAttributes - how the point should be drawn. * @param {number} x - the X coordinate of the point to draw. * @param {number} y - the Y coordinate of the point to draw. */ drawPoint(penAttributes, x, y) { this.drawLine(penAttributes, x, y, x, y); } /** * Draw a line on the pen layer. * @param {PenAttributes} penAttributes - how the line should be drawn. * @param {number} x0 - the X coordinate of the beginning of the line. * @param {number} y0 - the Y coordinate of the beginning of the line. * @param {number} x1 - the X coordinate of the end of the line. * @param {number} y1 - the Y coordinate of the end of the line. */ drawLine(penAttributes, x0, y0, x1, y1) { // For compatibility with Scratch 2.0, offset pen lines of width 1 and 3 so they're pixel-aligned. // See https://github.com/LLK/scratch-render/pull/314 const diameter = penAttributes.diameter || DefaultPenAttributes.diameter; const offset = diameter === 1 || diameter === 3 ? 0.5 : 0; this._drawLineOnBuffer(penAttributes, x0 + offset, y0 + offset, x1 + offset, y1 + offset); this._silhouetteDirty = true; } /** * Prepare to draw lines in the _lineOnBufferDrawRegionId region. */ _enterDrawLineOnBuffer() { // tw: reset attributes when starting pen drawing this._resetAttributeIndexes(); const gl = this._renderer.gl; twgl.bindFramebufferInfo(gl, this._framebuffer); gl.viewport(0, 0, this._size[0], this._size[1]); const currentShader = this._lineShader; gl.useProgram(currentShader.program); twgl.setBuffersAndAttributes(gl, currentShader, this._lineBufferInfo); const uniforms = { u_skin: this._texture, u_stageSize: this._size }; twgl.setUniforms(currentShader, uniforms); } /** * Return to a base state from _lineOnBufferDrawRegionId. */ _exitDrawLineOnBuffer() { // tw: flush when exiting pen rendering if (this.a_lineColorIndex) { this._flushLines(); } const gl = this._renderer.gl; twgl.bindFramebufferInfo(gl, null); } /** * Prepare to do things with this PenSkin's framebuffer */ _enterUsePenBuffer() { twgl.bindFramebufferInfo(this._renderer.gl, this._framebuffer); } /** * Return to a base state */ _exitUsePenBuffer() { twgl.bindFramebufferInfo(this._renderer.gl, null); } // tw: draw region used to preserve texture when resizing _enterDrawTexture() { this._enterUsePenBuffer(); const gl = this._renderer.gl; gl.viewport(0, 0, this._size[0], this._size[1]); gl.useProgram(this._drawTextureShader.program); twgl.setBuffersAndAttributes(gl, this._drawTextureShader, this._renderer._bufferInfo); } _exitDrawTexture() { this._exitUsePenBuffer(); } _drawPenTexture(texture) { this._renderer.enterDrawRegion(this._drawTextureRegionId); const gl = this._renderer.gl; const width = this._size[0]; const height = this._size[1]; const uniforms = { u_skin: texture, u_projectionMatrix: twgl.m4.ortho(width / 2, width / -2, height / -2, height / 2, -1, 1, twgl.m4.identity()), u_modelMatrix: twgl.m4.scaling(twgl.v3.create(width, height, 0), twgl.m4.identity()) }; twgl.setTextureParameters(gl, texture, { // Always use NEAREST because this most closely matches Scratch behavior minMag: gl.NEAREST }); twgl.setUniforms(this._drawTextureShader, uniforms); twgl.drawBufferInfo(gl, this._renderer._bufferInfo, gl.TRIANGLES); } /** * Draw a line on the framebuffer. * Note that the point coordinates are in the following coordinate space: * +y is down, (0, 0) is the center, and the coords range from (-width / 2, -height / 2) to (height / 2, width / 2). * @param {PenAttributes} penAttributes - how the line should be drawn. * @param {number} x0 - the X coordinate of the beginning of the line. * @param {number} y0 - the Y coordinate of the beginning of the line. * @param {number} x1 - the X coordinate of the end of the line. * @param {number} y1 - the Y coordinate of the end of the line. */ _drawLineOnBuffer(penAttributes, x0, y0, x1, y1) { this._renderer.enterDrawRegion(this._lineOnBufferDrawRegionId); // tw: flush if this line would overflow buffers // For some reason, looking up the size of a_lineColor with .length is very slow in some browsers. // We see measurable performance improvements by comparing to a constant instead. if (this.a_lineColorIndex + 24 > PEN_BUFFER_SIZE_LARGER) { this._flushLines(); } // Premultiply pen color by pen transparency const penColor = penAttributes.color4f || DefaultPenAttributes.color4f; __premultipliedColor[0] = penColor[0] * penColor[3]; __premultipliedColor[1] = penColor[1] * penColor[3]; __premultipliedColor[2] = penColor[2] * penColor[3]; __premultipliedColor[3] = penColor[3]; // tw: apply renderQuality x0 *= this.renderQuality; y0 *= this.renderQuality; x1 *= this.renderQuality; y1 *= this.renderQuality; // Fun fact: Doing this calculation in the shader has the potential to overflow the floating-point range. // 'mediump' precision is only required to have a range up to 2^14 (16384), so any lines longer than 2^7 (128) // can overflow that, because you're squaring the operands, and they could end up as "infinity". // Even GLSL's `length` function won't save us here: // https://asawicki.info/news_1596_watch_out_for_reduced_precision_normalizelength_in_opengl_es const lineDiffX = x1 - x0; const lineDiffY = y1 - y0; const lineLength = Math.sqrt(lineDiffX * lineDiffX + lineDiffY * lineDiffY); // tw: apply renderQuality const lineThickness = (penAttributes.diameter || DefaultPenAttributes.diameter) * this.renderQuality; // tw: write pen draws to buffers where they will be flushed later for (let i = 0; i < 6; i++) { this.a_lineColor[this.a_lineColorIndex] = __premultipliedColor[0]; this.a_lineColorIndex++; this.a_lineColor[this.a_lineColorIndex] = __premultipliedColor[1]; this.a_lineColorIndex++; this.a_lineColor[this.a_lineColorIndex] = __premultipliedColor[2]; this.a_lineColorIndex++; this.a_lineColor[this.a_lineColorIndex] = __premultipliedColor[3]; this.a_lineColorIndex++; this.a_lineThicknessAndLength[this.a_lineThicknessAndLengthIndex] = lineThickness; this.a_lineThicknessAndLengthIndex++; this.a_lineThicknessAndLength[this.a_lineThicknessAndLengthIndex] = lineLength; this.a_lineThicknessAndLengthIndex++; this.a_penPoints[this.a_penPointsIndex] = x0; this.a_penPointsIndex++; this.a_penPoints[this.a_penPointsIndex] = -y0; this.a_penPointsIndex++; this.a_penPoints[this.a_penPointsIndex] = lineDiffX; this.a_penPointsIndex++; this.a_penPoints[this.a_penPointsIndex] = -lineDiffY; this.a_penPointsIndex++; } } // tw: resets indexes in the pen drawing buffers _resetAttributeIndexes() { this.a_lineColorIndex = 0; this.a_lineThicknessAndLengthIndex = 0; this.a_penPointsIndex = 0; } // tw: flushes buffered pen lines to the GPU _flushLines() { const gl = this._renderer.gl; const currentShader = this._lineShader; // If only a small amount of data needs to be uploaded, only upload part of the data. // todo: need to see if this helps and fine tune this number if (this.a_lineColorIndex < 1000) { twgl.setAttribInfoBufferFromArray(gl, this._lineBufferInfo.attribs.a_lineColor, new Float32Array(this.a_lineColor.buffer, 0, this.a_lineColorIndex), 0); twgl.setAttribInfoBufferFromArray(gl, this._lineBufferInfo.attribs.a_penPoints, new Float32Array(this.a_penPoints.buffer, 0, this.a_penPointsIndex), 0); twgl.setAttribInfoBufferFromArray(gl, this._lineBufferInfo.attribs.a_lineThicknessAndLength, new Float32Array(this.a_lineThicknessAndLength.buffer, 0, this.a_lineThicknessAndLengthIndex), 0); } else { twgl.setAttribInfoBufferFromArray(gl, this._lineBufferInfo.attribs.a_lineColor, this.a_lineColor); twgl.setAttribInfoBufferFromArray(gl, this._lineBufferInfo.attribs.a_penPoints, this.a_penPoints); twgl.setAttribInfoBufferFromArray(gl, this._lineBufferInfo.attribs.a_lineThicknessAndLength, this.a_lineThicknessAndLength); } // todo: if we skip twgl and do all this buffer stuff ourselves, we can skip some unneeded gl calls twgl.setBuffersAndAttributes(gl, currentShader, this._lineBufferInfo); twgl.drawBufferInfo(gl, this._lineBufferInfo, gl.TRIANGLES, this.a_lineThicknessAndLengthIndex / 2); this._resetAttributeIndexes(); this._silhouetteDirty = true; } /** * React to a change in the renderer's native size. * @param {object} event - The change event. */ onNativeSizeChanged(event) { // tw: keep track of native size this._nativeSize = event.newSize; this._setCanvasSize([event.newSize[0] * this.renderQuality, event.newSize[1] * this.renderQuality]); this.emitWasAltered(); } /** * Set the size of the pen canvas. * @param {Array} canvasSize - the new width and height for the canvas. * @private */ _setCanvasSize(canvasSize) { const [width, height] = canvasSize; // tw: do not resize if new size === old size if (this._size && this._size[0] === width && this._size[1] === height) { return; } this._size = canvasSize; // tw: use native size for Drawable positioning logic this._rotationCenter[0] = this._nativeSize[0] / 2; this._rotationCenter[1] = this._nativeSize[1] / 2; const gl = this._renderer.gl; // tw: store current texture to redraw it later const oldTexture = this._texture; this._texture = twgl.createTexture(gl, { mag: gl.NEAREST, min: gl.NEAREST, wrap: gl.CLAMP_TO_EDGE, width, height }); const attachments = [{ format: gl.RGBA, attachment: this._texture }]; if (this._framebuffer) { // tw: resize framebuffer info doesn't work here, so always make a new framebuffer // twgl.resizeFramebufferInfo(gl, this._framebuffer, attachments, width, height); this._framebuffer = twgl.createFramebufferInfo(gl, attachments, width, height); } else { this._framebuffer = twgl.createFramebufferInfo(gl, attachments, width, height); } gl.clearColor(0, 0, 0, 0); gl.clear(gl.COLOR_BUFFER_BIT); // tw: preserve old texture when resizing if (oldTexture) { this._drawPenTexture(oldTexture); } this._silhouettePixels = new Uint8Array(Math.floor(width * height * 4)); this._silhouetteImageData = new ImageData(width, height); this._silhouetteDirty = true; } // tw: sets the "quality" of the pen skin setRenderQuality(quality) { if (this.renderQuality === quality) { return; } this.renderQuality = quality; this._setCanvasSize([Math.round(this._nativeSize[0] * quality), Math.round(this._nativeSize[1] * quality)]); } /** * If there have been pen operations that have dirtied the canvas, update * now before someone wants to use our silhouette. */ updateSilhouette() { if (this._silhouetteDirty) { this._renderer.enterDrawRegion(this._usePenBufferDrawRegionId); // Sample the framebuffer's pixels into the silhouette instance const gl = this._renderer.gl; gl.readPixels(0, 0, this._size[0], this._size[1], gl.RGBA, gl.UNSIGNED_BYTE, this._silhouettePixels); this._silhouetteImageData.data.set(this._silhouettePixels); this._silhouette.update(this._silhouetteImageData, true /* isPremultiplied */ ); this._silhouetteDirty = false; } } } module.exports = PenSkin; /***/ }), /***/ "./node_modules/scratch-render/src/Rectangle.js": /*!******************************************************!*\ !*** ./node_modules/scratch-render/src/Rectangle.js ***! \******************************************************/ /*! no static exports found */ /***/ (function(module, exports) { class Rectangle { /** * A utility for creating and comparing axis-aligned rectangles. * Rectangles are always initialized to the "largest possible rectangle"; * use one of the init* methods below to set up a particular rectangle. * @constructor */ constructor() { this.left = -Infinity; this.right = Infinity; this.bottom = -Infinity; this.top = Infinity; } /** * Initialize a Rectangle from given Scratch-coordinate bounds. * @param {number} left Left bound of the rectangle. * @param {number} right Right bound of the rectangle. * @param {number} bottom Bottom bound of the rectangle. * @param {number} top Top bound of the rectangle. */ initFromBounds(left, right, bottom, top) { this.left = left; this.right = right; this.bottom = bottom; this.top = top; } /** * Initialize a Rectangle to the minimum AABB around a set of points. * @param {Array>} points Array of [x, y] points. */ initFromPointsAABB(points) { this.left = Infinity; this.right = -Infinity; this.top = -Infinity; this.bottom = Infinity; for (let i = 0; i < points.length; i++) { const x = points[i][0]; const y = points[i][1]; if (x < this.left) { this.left = x; } if (x > this.right) { this.right = x; } if (y > this.top) { this.top = y; } if (y < this.bottom) { this.bottom = y; } } } /** * Initialize a Rectangle to a 1 unit square centered at 0 x 0 transformed * by a model matrix. * @param {Array.} m A 4x4 matrix to transform the rectangle by. * @tutorial Rectangle-AABB-Matrix */ initFromModelMatrix(m) { // In 2D space, we will soon use the 2x2 "top left" scale and rotation // submatrix, while we store and the 1x2 "top right" that position // vector. const m30 = m[3 * 4 + 0]; const m31 = m[3 * 4 + 1]; // "Transform" a (0.5, 0.5) vector by the scale and rotation matrix but // sum the absolute of each component instead of use the signed values. const x = Math.abs(0.5 * m[0 * 4 + 0]) + Math.abs(0.5 * m[1 * 4 + 0]); const y = Math.abs(0.5 * m[0 * 4 + 1]) + Math.abs(0.5 * m[1 * 4 + 1]); // And adding them to the position components initializes our Rectangle. this.left = -x + m30; this.right = x + m30; this.top = y + m31; this.bottom = -y + m31; } /** * Determine if this Rectangle intersects some other. * Note that this is a comparison assuming the Rectangle was * initialized with Scratch-space bounds or points. * @param {!Rectangle} other Rectangle to check if intersecting. * @return {boolean} True if this Rectangle intersects other. */ intersects(other) { return this.left <= other.right && other.left <= this.right && this.top >= other.bottom && other.top >= this.bottom; } /** * Determine if this Rectangle fully contains some other. * Note that this is a comparison assuming the Rectangle was * initialized with Scratch-space bounds or points. * @param {!Rectangle} other Rectangle to check if fully contained. * @return {boolean} True if this Rectangle fully contains other. */ contains(other) { return other.left > this.left && other.right < this.right && other.top < this.top && other.bottom > this.bottom; } /** * Clamp a Rectangle to bounds. * @param {number} left Left clamp. * @param {number} right Right clamp. * @param {number} bottom Bottom clamp. * @param {number} top Top clamp. */ clamp(left, right, bottom, top) { this.left = Math.max(this.left, left); this.right = Math.min(this.right, right); this.bottom = Math.max(this.bottom, bottom); this.top = Math.min(this.top, top); this.left = Math.min(this.left, right); this.right = Math.max(this.right, left); this.bottom = Math.min(this.bottom, top); this.top = Math.max(this.top, bottom); } /** * Push out the Rectangle to integer bounds. */ snapToInt() { this.left = Math.floor(this.left); this.right = Math.ceil(this.right); this.bottom = Math.floor(this.bottom); this.top = Math.ceil(this.top); } /** * Compute the intersection of two bounding Rectangles. * Could be an impossible box if they don't intersect. * @param {Rectangle} a One rectangle * @param {Rectangle} b Other rectangle * @param {?Rectangle} result A resulting storage rectangle (safe to pass * a or b if you want to overwrite one) * @returns {Rectangle} resulting rectangle */ static intersect(a, b, result = new Rectangle()) { result.left = Math.max(a.left, b.left); result.right = Math.min(a.right, b.right); result.top = Math.min(a.top, b.top); result.bottom = Math.max(a.bottom, b.bottom); return result; } /** * Compute the union of two bounding Rectangles. * @param {Rectangle} a One rectangle * @param {Rectangle} b Other rectangle * @param {?Rectangle} result A resulting storage rectangle (safe to pass * a or b if you want to overwrite one) * @returns {Rectangle} resulting rectangle */ static union(a, b, result = new Rectangle()) { result.left = Math.min(a.left, b.left); result.right = Math.max(a.right, b.right); // Scratch Space - +y is up result.top = Math.max(a.top, b.top); result.bottom = Math.min(a.bottom, b.bottom); return result; } /** * Width of the Rectangle. * @return {number} Width of rectangle. */ get width() { return Math.abs(this.left - this.right); } /** * Height of the Rectangle. * @return {number} Height of rectangle. */ get height() { return Math.abs(this.top - this.bottom); } } module.exports = Rectangle; /***/ }), /***/ "./node_modules/scratch-render/src/RenderConstants.js": /*!************************************************************!*\ !*** ./node_modules/scratch-render/src/RenderConstants.js ***! \************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /** @module RenderConstants */ /** * Various constants meant for use throughout the renderer. * @enum */ module.exports = { /** * The ID value to use for "no item" or when an object has been disposed. * @const {int} */ ID_NONE: -1, /** * @enum {string} */ Events: { /** * Event emitted when the high quality render option changes. */ UseHighQualityRenderChanged: 'UseHighQualityRenderChanged', /** * Event emitted when the private skin access option changes. */ AllowPrivateSkinAccessChanged: 'AllowPrivateSkinAccessChanged', /** * NativeSizeChanged event * * @event RenderWebGL#event:NativeSizeChanged * @type {object} * @property {Array} newSize - the new size of the renderer */ NativeSizeChanged: 'NativeSizeChanged' } }; /***/ }), /***/ "./node_modules/scratch-render/src/RenderWebGL.js": /*!********************************************************!*\ !*** ./node_modules/scratch-render/src/RenderWebGL.js ***! \********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const EventEmitter = __webpack_require__(/*! events */ "./node_modules/events/events.js"); const hull = __webpack_require__(/*! hull.js */ "./node_modules/hull.js/src/hull.js"); const twgl = __webpack_require__(/*! twgl.js */ "./node_modules/twgl.js/dist/4.x/twgl-full.js"); const BitmapSkin = __webpack_require__(/*! ./BitmapSkin */ "./node_modules/scratch-render/src/BitmapSkin.js"); const Drawable = __webpack_require__(/*! ./Drawable */ "./node_modules/scratch-render/src/Drawable.js"); const Rectangle = __webpack_require__(/*! ./Rectangle */ "./node_modules/scratch-render/src/Rectangle.js"); const PenSkin = __webpack_require__(/*! ./PenSkin */ "./node_modules/scratch-render/src/PenSkin.js"); const RenderConstants = __webpack_require__(/*! ./RenderConstants */ "./node_modules/scratch-render/src/RenderConstants.js"); const ShaderManager = __webpack_require__(/*! ./ShaderManager */ "./node_modules/scratch-render/src/ShaderManager.js"); const SVGSkin = __webpack_require__(/*! ./SVGSkin */ "./node_modules/scratch-render/src/SVGSkin.js"); const TextBubbleSkin = __webpack_require__(/*! ./TextBubbleSkin */ "./node_modules/scratch-render/src/TextBubbleSkin.js"); const EffectTransform = __webpack_require__(/*! ./EffectTransform */ "./node_modules/scratch-render/src/EffectTransform.js"); const log = __webpack_require__(/*! ./util/log */ "./node_modules/scratch-render/src/util/log.js"); const __isTouchingDrawablesPoint = twgl.v3.create(); const __candidatesBounds = new Rectangle(); const __fenceBounds = new Rectangle(); const __touchingColor = new Uint8ClampedArray(4); const __blendColor = new Uint8ClampedArray(4); // More pixels than this and we give up to the GPU and take the cost of readPixels // Width * Height * Number of drawables at location const __cpuTouchingColorPixelCount = 4e4; /** * @callback RenderWebGL#idFilterFunc * @param {int} drawableID The ID to filter. * @return {bool} True if the ID passes the filter, otherwise false. */ /** * Maximum touch size for a picking check. * @todo Figure out a reasonable max size. Maybe this should be configurable? * @type {Array} * @memberof RenderWebGL */ const MAX_TOUCH_SIZE = [3, 3]; /** * Passed to the uniforms for mask in touching color */ const MASK_TOUCHING_COLOR_TOLERANCE = 2; /** * Maximum number of pixels in either dimension of "extracted drawable" data * @type {int} */ const MAX_EXTRACTED_DRAWABLE_DIMENSION = 2048; /** * Determines if the mask color is "close enough" (only test the 6 top bits for * each color). These bit masks are what scratch 2 used to use, so we do the same. * @param {Uint8Array} a A color3b or color4b value. * @param {Uint8Array} b A color3b or color4b value. * @returns {boolean} If the colors match within the parameters. */ const maskMatches = (a, b) => // has some non-alpha component to test against a[3] > 0 && (a[0] & 0b11111100) === (b[0] & 0b11111100) && (a[1] & 0b11111100) === (b[1] & 0b11111100) && (a[2] & 0b11111100) === (b[2] & 0b11111100); /** * Determines if the given color is "close enough" (only test the 5 top bits for * red and green, 4 bits for blue). These bit masks are what scratch 2 used to use, * so we do the same. * @param {Uint8Array} a A color3b or color4b value. * @param {Uint8Array} b A color3b or color4b value / or a larger array when used with offsets * @param {number} offset An offset into the `b` array, which lets you use a larger array to test * multiple values at the same time. * @returns {boolean} If the colors match within the parameters. */ const colorMatches = (a, b, offset) => (a[0] & 0b11111000) === (b[offset + 0] & 0b11111000) && (a[1] & 0b11111000) === (b[offset + 1] & 0b11111000) && (a[2] & 0b11110000) === (b[offset + 2] & 0b11110000); /** * Sprite Fencing - The number of pixels a sprite is required to leave remaining * onscreen around the edge of the staging area. * @type {number} */ const FENCE_WIDTH = 15; class RenderWebGL extends EventEmitter { /** * Check if this environment appears to support this renderer before attempting to create an instance. * Catching an exception from the constructor is also a valid way to test for (lack of) support. * @param {canvas} [optCanvas] - An optional canvas to use for the test. Otherwise a temporary canvas will be used. * @returns {boolean} - True if this environment appears to support this renderer, false otherwise. */ static isSupported(optCanvas) { try { optCanvas = optCanvas || document.createElement('canvas'); const options = { alpha: false, stencil: true, antialias: false }; return !!(optCanvas.getContext('webgl', options) || optCanvas.getContext('experimental-webgl', options) || optCanvas.getContext('webgl2', options)); } catch (e) { return false; } } /** * Ask TWGL to create a rendering context with the attributes used by this renderer. * @param {canvas} canvas - attach the context to this canvas. * @returns {WebGLRenderingContext} - a TWGL rendering context (backed by either WebGL 1.0 or 2.0). * @private */ static _getContext(canvas) { const contextAttribs = { alpha: false, stencil: true, antialias: false, powerPreference: RenderWebGL.powerPreference }; // getWebGLContext = try WebGL 1.0 only // getContext = try WebGL 2.0 and if that doesn't work, try WebGL 1.0 // getWebGLContext || getContext = try WebGL 1.0 and if that doesn't work, try WebGL 2.0 return twgl.getWebGLContext(canvas, contextAttribs) || twgl.getContext(canvas, contextAttribs); } /** * Create a renderer for drawing Scratch sprites to a canvas using WebGL. * Coordinates will default to Scratch 2.0 values if unspecified. * The stage's "native" size will be calculated from the these coordinates. * For example, the defaults result in a native size of 480x360. * Queries such as "touching color?" will always execute at the native size. * @see RenderWebGL#setStageSize * @see RenderWebGL#resize * @param {canvas} canvas The canvas to draw onto. * @param {int} [xLeft=-240] The x-coordinate of the left edge. * @param {int} [xRight=240] The x-coordinate of the right edge. * @param {int} [yBottom=-180] The y-coordinate of the bottom edge. * @param {int} [yTop=180] The y-coordinate of the top edge. * @constructor * @listens RenderWebGL#event:NativeSizeChanged */ constructor(canvas, xLeft, xRight, yBottom, yTop) { super(); /** @type {WebGLRenderingContext} */ const gl = this._gl = RenderWebGL._getContext(canvas); if (!gl) { throw new Error('Could not get WebGL context: this browser or environment may not support WebGL.'); } /** @type {RenderWebGL.UseGpuModes} */ this._useGpuMode = RenderWebGL.UseGpuModes.Automatic; /** @type {Drawable[]} */ this._allDrawables = []; /** @type {Skin[]} */ this._allSkins = []; /** @type {Array} */ this._drawList = []; // A list of layer group names in the order they should appear // from furthest back to furthest in front. /** @type {Array} */ this._groupOrdering = []; /** * @typedef LayerGroup * @property {int} groupIndex The relative position of this layer group in the group ordering * @property {int} drawListOffset The absolute position of this layer group in the draw list * This number gets updated as drawables get added to or deleted from the draw list. */ // Map of group name to layer group /** @type {Object.} */ this._layerGroups = {}; /** @type {int} */ this._nextDrawableId = RenderConstants.ID_NONE + 1; /** @type {int} */ this._nextSkinId = RenderConstants.ID_NONE + 1; /** @type {module:twgl/m4.Mat4} */ this._projection = twgl.m4.identity(); /** @type {ShaderManager} */ this._shaderManager = new ShaderManager(gl); /** @type {any} */ this._regionId = null; /** @type {function} */ this._exitRegion = null; /** @type {object} */ this._backgroundDrawRegionId = { enter: () => this._enterDrawBackground(), exit: () => this._exitDrawBackground() }; /** @type {Array.} */ this._snapshotCallbacks = []; /** @type {Array} */ // Don't set this directly-- use setBackgroundColor so it stays in sync with _backgroundColor3b this._backgroundColor4f = [0, 0, 0, 1]; /** @type {Uint8ClampedArray} */ // Don't set this directly-- use setBackgroundColor so it stays in sync with _backgroundColor4f this._backgroundColor3b = new Uint8ClampedArray(3); // tw: track id of pen skin this._penSkinId = null; this.useHighQualityRender = false; this.offscreenTouching = false; this.dirty = true; this.skinsWereAltered = false; this._createGeometry(); this.on(RenderConstants.Events.NativeSizeChanged, this.onNativeSizeChanged); this.setBackgroundColor(1, 1, 1); this.setStageSize(xLeft || -240, xRight || 240, yBottom || -180, yTop || 180); this.resize(this._nativeSize[0], this._nativeSize[1]); gl.disable(gl.DEPTH_TEST); /** @todo disable when no partial transparency? */ gl.enable(gl.BLEND); gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); /** * Whether projects should be able to access the contents of private skins such as webcams. * If set to false, routines such as isTouchingColor will ignore private skins. * Private skins will still be rendered on the canvas regardless of this setting. * This is set to true by default for compatibility with vanilla Scratch. * @type {boolean} */ this.allowPrivateSkinAccess = true; } // tw: implement high quality pen option setUseHighQualityRender(enabled) { this.dirty = true; this.useHighQualityRender = enabled; this.emit(RenderConstants.Events.UseHighQualityRenderChanged, enabled); this._updateRenderQuality(); } _updateRenderQuality() { if (this._penSkinId !== null) { const skin = this._allSkins[this._penSkinId]; if (skin) { if (this.useHighQualityRender) { skin.setRenderQuality(this.canvas.width / this._nativeSize[0]); } else { skin.setRenderQuality(1); } } } for (const drawable of this._allDrawables) { if (drawable) { drawable.setHighQuality(this.useHighQualityRender); } } } /** * Configure whether the renderer should let projects access private skins. * @param {boolean} allowPrivateSkinAccess Whether projects can access private skins or not. */ setPrivateSkinAccess(allowPrivateSkinAccess) { this.allowPrivateSkinAccess = allowPrivateSkinAccess; this.emit(RenderConstants.Events.AllowPrivateSkinAccessChanged, allowPrivateSkinAccess); } /** * @returns {WebGLRenderingContext} the WebGL rendering context associated with this renderer. */ get gl() { return this._gl; } /** * @returns {HTMLCanvasElement} the canvas of the WebGL rendering context associated with this renderer. */ get canvas() { return this._gl && this._gl.canvas; } /** * Set the physical size of the stage in device-independent pixels. * This will be multiplied by the device's pixel ratio on high-DPI displays. * @param {int} pixelsWide The desired width in device-independent pixels. * @param {int} pixelsTall The desired height in device-independent pixels. */ resize(pixelsWide, pixelsTall) { const { canvas } = this._gl; const pixelRatio = window.devicePixelRatio || 1; const newWidth = pixelsWide * pixelRatio; const newHeight = pixelsTall * pixelRatio; // Certain operations, such as moving the color picker, call `resize` once per frame, even though the canvas // size doesn't change. To avoid unnecessary canvas updates, check that we *really* need to resize the canvas. if (canvas.width !== newWidth || canvas.height !== newHeight) { canvas.width = newWidth; canvas.height = newHeight; // Resizing the canvas causes it to be cleared, so redraw it. this.dirty = true; this.draw(); this._updateRenderQuality(); } } /** * Set the background color for the stage. The stage will be cleared with this * color each frame. * @param {number} red The red component for the background. * @param {number} green The green component for the background. * @param {number} blue The blue component for the background. */ setBackgroundColor(red, green, blue) { this._backgroundColor4f[0] = red; this._backgroundColor4f[1] = green; this._backgroundColor4f[2] = blue; this._backgroundColor3b[0] = red * 255; this._backgroundColor3b[1] = green * 255; this._backgroundColor3b[2] = blue * 255; } /** * Tell the renderer to draw various debug information to the provided canvas * during certain operations. * @param {canvas} canvas The canvas to use for debug output. */ setDebugCanvas(canvas) { this._debugCanvas = canvas; } /** * Control the use of the GPU or CPU paths in `isTouchingColor`. * @param {RenderWebGL.UseGpuModes} useGpuMode - automatically decide, force CPU, or force GPU. */ setUseGpuMode(useGpuMode) { this._useGpuMode = useGpuMode; } /** * Set logical size of the stage in Scratch units. * @param {int} xLeft The left edge's x-coordinate. Scratch 2 uses -240. * @param {int} xRight The right edge's x-coordinate. Scratch 2 uses 240. * @param {int} yBottom The bottom edge's y-coordinate. Scratch 2 uses -180. * @param {int} yTop The top edge's y-coordinate. Scratch 2 uses 180. */ setStageSize(xLeft, xRight, yBottom, yTop) { this._xLeft = xLeft; this._xRight = xRight; this._yBottom = yBottom; this._yTop = yTop; // swap yBottom & yTop to fit Scratch convention of +y=up this._projection = twgl.m4.ortho(xLeft, xRight, yBottom, yTop, -1, 1); this._setNativeSize(Math.abs(xRight - xLeft), Math.abs(yBottom - yTop)); } /** * @return {Array} the "native" size of the stage, which is used for pen, query renders, etc. */ getNativeSize() { return [this._nativeSize[0], this._nativeSize[1]]; } /** * Set the "native" size of the stage, which is used for pen, query renders, etc. * @param {int} width - the new width to set. * @param {int} height - the new height to set. * @private * @fires RenderWebGL#event:NativeSizeChanged */ _setNativeSize(width, height) { this._nativeSize = [width, height]; this.emit(RenderConstants.Events.NativeSizeChanged, { newSize: this._nativeSize }); } /** * Create a new bitmap skin from a snapshot of the provided bitmap data. * @param {ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} bitmapData - new contents for this skin. * @param {!int} [costumeResolution=1] - The resolution to use for this bitmap. * @param {?Array} [rotationCenter] Optional: rotation center of the skin. If not supplied, the center of * the skin will be used. * @returns {!int} the ID for the new skin. */ createBitmapSkin(bitmapData, costumeResolution, rotationCenter) { const skinId = this._nextSkinId++; const newSkin = new BitmapSkin(skinId, this); newSkin.setBitmap(bitmapData, costumeResolution, rotationCenter); this._allSkins[skinId] = newSkin; return skinId; } /** * Create a new SVG skin. * @param {!string} svgData - new SVG to use. * @param {?Array} rotationCenter Optional: rotation center of the skin. If not supplied, the center of the * skin will be used * @returns {!int} the ID for the new skin. */ createSVGSkin(svgData, rotationCenter) { const skinId = this._nextSkinId++; const newSkin = new SVGSkin(skinId, this); newSkin.setSVG(svgData, rotationCenter); this._allSkins[skinId] = newSkin; return skinId; } /** * Create a new PenSkin - a skin which implements a Scratch pen layer. * @returns {!int} the ID for the new skin. */ createPenSkin() { const skinId = this._nextSkinId++; const newSkin = new PenSkin(skinId, this); this._allSkins[skinId] = newSkin; // tw: track id of pen skin this._penSkinId = skinId; // tw: high quality pen may have been enabled before the pen skin was created this._updateRenderQuality(); return skinId; } /** * Create a new SVG skin using the text bubble svg creator. The rotation center * is always placed at the top left. * @param {!string} type - either "say" or "think". * @param {!string} text - the text for the bubble. * @param {!boolean} pointsLeft - which side the bubble is pointing. * @returns {!int} the ID for the new skin. */ createTextSkin(type, text, pointsLeft) { const skinId = this._nextSkinId++; const newSkin = new TextBubbleSkin(skinId, this); newSkin.setTextBubble(type, text, pointsLeft); this._allSkins[skinId] = newSkin; return skinId; } /** * Update an existing SVG skin, or create an SVG skin if the previous skin was not SVG. * @param {!int} skinId the ID for the skin to change. * @param {!string} svgData - new SVG to use. * @param {?Array} rotationCenter Optional: rotation center of the skin. If not supplied, the center of the * skin will be used */ updateSVGSkin(skinId, svgData, rotationCenter) { if (this._allSkins[skinId] instanceof SVGSkin) { this._allSkins[skinId].setSVG(svgData, rotationCenter); return; } const newSkin = new SVGSkin(skinId, this); newSkin.setSVG(svgData, rotationCenter); this._reskin(skinId, newSkin); } /** * Update an existing bitmap skin, or create a bitmap skin if the previous skin was not bitmap. * @param {!int} skinId the ID for the skin to change. * @param {!ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} imgData - new contents for this skin. * @param {!number} bitmapResolution - the resolution scale for a bitmap costume. * @param {?Array} rotationCenter Optional: rotation center of the skin. If not supplied, the center of the * skin will be used */ updateBitmapSkin(skinId, imgData, bitmapResolution, rotationCenter) { if (this._allSkins[skinId] instanceof BitmapSkin) { this._allSkins[skinId].setBitmap(imgData, bitmapResolution, rotationCenter); return; } const newSkin = new BitmapSkin(skinId, this); newSkin.setBitmap(imgData, bitmapResolution, rotationCenter); this._reskin(skinId, newSkin); } _reskin(skinId, newSkin) { const oldSkin = this._allSkins[skinId]; this._allSkins[skinId] = newSkin; // Tell drawables to update for (const drawable of this._allDrawables) { if (drawable && drawable.skin === oldSkin) { drawable.skin = newSkin; } } oldSkin.dispose(); } /** * Update a skin using the text bubble svg creator. * @param {!int} skinId the ID for the skin to change. * @param {!string} type - either "say" or "think". * @param {!string} text - the text for the bubble. * @param {!boolean} pointsLeft - which side the bubble is pointing. */ updateTextSkin(skinId, type, text, pointsLeft) { if (this._allSkins[skinId] instanceof TextBubbleSkin) { this._allSkins[skinId].setTextBubble(type, text, pointsLeft); return; } const newSkin = new TextBubbleSkin(skinId, this); newSkin.setTextBubble(type, text, pointsLeft); this._reskin(skinId, newSkin); } /** * Destroy an existing skin. Do not use the skin or its ID after calling this. * @param {!int} skinId - The ID of the skin to destroy. */ destroySkin(skinId) { const oldSkin = this._allSkins[skinId]; oldSkin.dispose(); delete this._allSkins[skinId]; } /** * Create a new Drawable and add it to the scene. * @param {string} group Layer group to add the drawable to * @returns {int} The ID of the new Drawable. */ createDrawable(group) { if (!group || !Object.prototype.hasOwnProperty.call(this._layerGroups, group)) { log.warn('Cannot create a drawable without a known layer group'); return; } const drawableID = this._nextDrawableId++; const drawable = new Drawable(drawableID, this); this._allDrawables[drawableID] = drawable; this._addToDrawList(drawableID, group); // tw: implement high quality render drawable.setHighQuality(this.useHighQualityRender); drawable.skin = null; return drawableID; } /** * Mark a skin as containing private information. * @param {number} skinID The skin's ID */ markSkinAsPrivate(skinID) { const skin = this._allSkins[skinID]; if (!skin) { return; } skin.private = true; } /** * Set the layer group ordering for the renderer. * @param {Array} groupOrdering The ordered array of layer group * names */ setLayerGroupOrdering(groupOrdering) { this._groupOrdering = groupOrdering; for (let i = 0; i < this._groupOrdering.length; i++) { this._layerGroups[this._groupOrdering[i]] = { groupIndex: i, drawListOffset: 0 }; } } _addToDrawList(drawableID, group) { const currentLayerGroup = this._layerGroups[group]; const currentGroupOrderingIndex = currentLayerGroup.groupIndex; const drawListOffset = this._endIndexForKnownLayerGroup(currentLayerGroup); this._drawList.splice(drawListOffset, 0, drawableID); this._updateOffsets('add', currentGroupOrderingIndex); } _updateOffsets(updateType, currentGroupOrderingIndex) { for (let i = currentGroupOrderingIndex + 1; i < this._groupOrdering.length; i++) { const laterGroupName = this._groupOrdering[i]; if (updateType === 'add') { this._layerGroups[laterGroupName].drawListOffset++; } else if (updateType === 'delete') { this._layerGroups[laterGroupName].drawListOffset--; } } } get _visibleDrawList() { return this._drawList.filter(id => this._allDrawables[id]._visible); } // Given a layer group, return the index where it ends (non-inclusive), // e.g. the returned index does not have a drawable from this layer group in it) _endIndexForKnownLayerGroup(layerGroup) { const groupIndex = layerGroup.groupIndex; if (groupIndex === this._groupOrdering.length - 1) { return this._drawList.length; } return this._layerGroups[this._groupOrdering[groupIndex + 1]].drawListOffset; } /** * Destroy a Drawable, removing it from the scene. * @param {int} drawableID The ID of the Drawable to remove. * @param {string} group Group name that the drawable belongs to */ destroyDrawable(drawableID, group) { if (!group || !Object.prototype.hasOwnProperty.call(this._layerGroups, group)) { log.warn('Cannot destroy drawable without known layer group.'); return; } this.dirty = true; const drawable = this._allDrawables[drawableID]; drawable.dispose(); delete this._allDrawables[drawableID]; const currentLayerGroup = this._layerGroups[group]; const endIndex = this._endIndexForKnownLayerGroup(currentLayerGroup); let index = currentLayerGroup.drawListOffset; while (index < endIndex) { if (this._drawList[index] === drawableID) { break; } index++; } if (index < endIndex) { this._drawList.splice(index, 1); this._updateOffsets('delete', currentLayerGroup.groupIndex); } else { log.warn('Could not destroy drawable that could not be found in layer group.'); return; } } /** * Returns the position of the given drawableID in the draw list. This is * the absolute position irrespective of layer group. * @param {number} drawableID The drawable ID to find. * @return {number} The postion of the given drawable ID. */ getDrawableOrder(drawableID) { return this._drawList.indexOf(drawableID); } /** * Set a drawable's order in the drawable list (effectively, z/layer). * Can be used to move drawables to absolute positions in the list, * or relative to their current positions. * "go back N layers": setDrawableOrder(id, -N, true, 1); (assuming stage at 0). * "go to back": setDrawableOrder(id, 1); (assuming stage at 0). * "go to front": setDrawableOrder(id, Infinity); * @param {int} drawableID ID of Drawable to reorder. * @param {number} order New absolute order or relative order adjusment. * @param {string=} group Name of layer group drawable belongs to. * Reordering will not take place if drawable cannot be found within the bounds * of the layer group. * @param {boolean=} optIsRelative If set, `order` refers to a relative change. * @param {number=} optMin If set, order constrained to be at least `optMin`. * @return {?number} New order if changed, or null. */ setDrawableOrder(drawableID, order, group, optIsRelative, optMin) { if (!group || !Object.prototype.hasOwnProperty.call(this._layerGroups, group)) { log.warn('Cannot set the order of a drawable without a known layer group.'); return; } this.dirty = true; const currentLayerGroup = this._layerGroups[group]; const startIndex = currentLayerGroup.drawListOffset; const endIndex = this._endIndexForKnownLayerGroup(currentLayerGroup); let oldIndex = startIndex; while (oldIndex < endIndex) { if (this._drawList[oldIndex] === drawableID) { break; } oldIndex++; } if (oldIndex < endIndex) { // Remove drawable from the list. if (order === 0) { return oldIndex; } const _ = this._drawList.splice(oldIndex, 1)[0]; // Determine new index. let newIndex = order; if (optIsRelative) { newIndex += oldIndex; } const possibleMin = (optMin || 0) + startIndex; const min = possibleMin >= startIndex && possibleMin < endIndex ? possibleMin : startIndex; newIndex = Math.max(newIndex, min); newIndex = Math.min(newIndex, endIndex); // Insert at new index. this._drawList.splice(newIndex, 0, drawableID); return newIndex; } return null; } skinWasAltered(skin) { // This is very hot function. for (let i = 0; i < this._allDrawables.length; i++) { const drawable = this._allDrawables[i]; if (drawable && drawable._skin === skin) { drawable._skinWasAltered(); } } } /** * Draw all current drawables and present the frame on the canvas. */ draw() { if (!this.dirty) { return; } this.dirty = false; this._doExitDrawRegion(); const gl = this._gl; twgl.bindFramebufferInfo(gl, null); gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); gl.clearColor(...this._backgroundColor4f); gl.clear(gl.COLOR_BUFFER_BIT); this._drawThese(this._drawList, ShaderManager.DRAW_MODE.default, this._projection, { framebufferWidth: gl.canvas.width, framebufferHeight: gl.canvas.height }); if (this._snapshotCallbacks.length > 0) { const snapshot = gl.canvas.toDataURL(); this._snapshotCallbacks.forEach(cb => cb(snapshot)); this._snapshotCallbacks = []; } } /** * Get the precise bounds for a Drawable. * @param {int} drawableID ID of Drawable to get bounds for. * @return {object} Bounds for a tight box around the Drawable. */ getBounds(drawableID) { const drawable = this._allDrawables[drawableID]; // Tell the Drawable about its updated convex hull, if necessary. if (drawable.needsConvexHullPoints()) { const points = this._getConvexHullPointsForDrawable(drawableID); drawable.setConvexHullPoints(points); } const bounds = drawable.getFastBounds(); // In debug mode, draw the bounds. if (this._debugCanvas) { const gl = this._gl; this._debugCanvas.width = gl.canvas.width; this._debugCanvas.height = gl.canvas.height; const context = this._debugCanvas.getContext('2d'); context.drawImage(gl.canvas, 0, 0); context.strokeStyle = '#FF0000'; const pr = window.devicePixelRatio; context.strokeRect(pr * (bounds.left + this._nativeSize[0] / 2), pr * (-bounds.top + this._nativeSize[1] / 2), pr * (bounds.right - bounds.left), pr * (-bounds.bottom + bounds.top)); } return bounds; } /** * Get the precise bounds for a Drawable around the top slice. * Used for positioning speech bubbles more closely to the sprite. * @param {int} drawableID ID of Drawable to get bubble bounds for. * @return {object} Bounds for a tight box around the Drawable top slice. */ getBoundsForBubble(drawableID) { const drawable = this._allDrawables[drawableID]; // Tell the Drawable about its updated convex hull, if necessary. if (drawable.needsConvexHullPoints()) { const points = this._getConvexHullPointsForDrawable(drawableID); drawable.setConvexHullPoints(points); } const bounds = drawable.getBoundsForBubble(); // In debug mode, draw the bounds. if (this._debugCanvas) { const gl = this._gl; this._debugCanvas.width = gl.canvas.width; this._debugCanvas.height = gl.canvas.height; const context = this._debugCanvas.getContext('2d'); context.drawImage(gl.canvas, 0, 0); context.strokeStyle = '#FF0000'; const pr = window.devicePixelRatio; context.strokeRect(pr * (bounds.left + this._nativeSize[0] / 2), pr * (-bounds.top + this._nativeSize[1] / 2), pr * (bounds.right - bounds.left), pr * (-bounds.bottom + bounds.top)); } return bounds; } /** * Get the current skin (costume) size of a Drawable. * @param {int} drawableID The ID of the Drawable to measure. * @return {Array} Skin size, width and height. */ getCurrentSkinSize(drawableID) { const drawable = this._allDrawables[drawableID]; return this.getSkinSize(drawable.skin.id); } /** * Get the size of a skin by ID. * @param {int} skinID The ID of the Skin to measure. * @return {Array} Skin size, width and height. */ getSkinSize(skinID) { const skin = this._allSkins[skinID]; return skin.size; } /** * Get the rotation center of a skin by ID. * @param {int} skinID The ID of the Skin * @return {Array} The rotationCenterX and rotationCenterY */ getSkinRotationCenter(skinID) { const skin = this._allSkins[skinID]; return skin.calculateRotationCenter(); } /** * Check if a particular Drawable is touching a particular color. * Unlike touching drawable, if the "tester" is invisble, we will still test. * @param {int} drawableID The ID of the Drawable to check. * @param {Array} color3b Test if the Drawable is touching this color. * @param {Array} [mask3b] Optionally mask the check to this part of Drawable. * @returns {boolean} True iff the Drawable is touching the color. */ isTouchingColor(drawableID, color3b, mask3b) { const candidates = this._candidatesTouching(drawableID, this._visibleDrawList); let bounds; if (colorMatches(color3b, this._backgroundColor3b, 0)) { // If the color we're checking for is the background color, don't confine the check to // candidate drawables' bounds--since the background spans the entire stage, we must check // everything that lies inside the drawable. bounds = this._touchingBounds(drawableID); // e.g. empty costume, or off the stage if (bounds === null) return false; } else if (candidates.length === 0) { // If not checking for the background color, we can return early if there are no candidate drawables. return false; } else { bounds = this._candidatesBounds(candidates); } const maxPixelsForCPU = this._getMaxPixelsForCPU(); const debugCanvasContext = this._debugCanvas && this._debugCanvas.getContext('2d'); if (debugCanvasContext) { this._debugCanvas.width = bounds.width; this._debugCanvas.height = bounds.height; } // if there are just too many pixels to CPU render efficiently, we need to let readPixels happen if (bounds.width * bounds.height * (candidates.length + 1) >= maxPixelsForCPU) { this._isTouchingColorGpuStart(drawableID, candidates.map(({ id }) => id).reverse(), bounds, color3b, mask3b); } const drawable = this._allDrawables[drawableID]; const point = __isTouchingDrawablesPoint; const color = __touchingColor; const hasMask = Boolean(mask3b); drawable.updateCPURenderAttributes(); // Masked drawable ignores ghost effect const effectMask = ~ShaderManager.EFFECT_INFO.ghost.mask; // Scratch Space - +y is top for (let y = bounds.bottom; y <= bounds.top; y++) { if (bounds.width * (y - bounds.bottom) * (candidates.length + 1) >= maxPixelsForCPU) { return this._isTouchingColorGpuFin(bounds, color3b, y - bounds.bottom); } for (let x = bounds.left; x <= bounds.right; x++) { point[1] = y; point[0] = x; // if we use a mask, check our sample color... if (hasMask ? maskMatches(Drawable.sampleColor4b(point, drawable, color, effectMask), mask3b) : drawable.isTouching(point)) { RenderWebGL.sampleColor3b(point, candidates, color); if (debugCanvasContext) { debugCanvasContext.fillStyle = "rgb(".concat(color[0], ",").concat(color[1], ",").concat(color[2], ")"); debugCanvasContext.fillRect(x - bounds.left, bounds.bottom - y, 1, 1); } // ...and the target color is drawn at this pixel if (colorMatches(color, color3b, 0)) { return true; } } } } return false; } _getMaxPixelsForCPU() { switch (this._useGpuMode) { case RenderWebGL.UseGpuModes.ForceCPU: return Infinity; case RenderWebGL.UseGpuModes.ForceGPU: return 0; case RenderWebGL.UseGpuModes.Automatic: default: return __cpuTouchingColorPixelCount; } } _enterDrawBackground() { const gl = this.gl; const currentShader = this._shaderManager.getShader(ShaderManager.DRAW_MODE.background, 0); gl.disable(gl.BLEND); gl.useProgram(currentShader.program); twgl.setBuffersAndAttributes(gl, currentShader, this._bufferInfo); } _exitDrawBackground() { const gl = this.gl; gl.enable(gl.BLEND); } _isTouchingColorGpuStart(drawableID, candidateIDs, bounds, color3b, mask3b) { this._doExitDrawRegion(); const gl = this._gl; twgl.bindFramebufferInfo(gl, this._queryBufferInfo); // Limit size of viewport to the bounds around the target Drawable, // and create the projection matrix for the draw. gl.viewport(0, 0, bounds.width, bounds.height); const projection = twgl.m4.ortho(bounds.left, bounds.right, bounds.top, bounds.bottom, -1, 1); // Clear the query buffer to fully transparent. This will be the color of pixels that fail the stencil test. gl.clearColor(0, 0, 0, 0); gl.clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); let extraUniforms; if (mask3b) { extraUniforms = { u_colorMask: [mask3b[0] / 255, mask3b[1] / 255, mask3b[2] / 255], u_colorMaskTolerance: MASK_TOUCHING_COLOR_TOLERANCE / 255 }; } try { // Using the stencil buffer, mask out the drawing to either the drawable's alpha channel // or pixels of the drawable which match the mask color, depending on whether a mask color is given. // Masked-out pixels will not be checked. gl.enable(gl.STENCIL_TEST); gl.stencilFunc(gl.ALWAYS, 1, 1); gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE); gl.colorMask(false, false, false, false); this._drawThese([drawableID], mask3b ? ShaderManager.DRAW_MODE.colorMask : ShaderManager.DRAW_MODE.silhouette, projection, { extraUniforms, ignoreVisibility: true, // Touching color ignores sprite visibility, effectMask: ~ShaderManager.EFFECT_INFO.ghost.mask }); gl.stencilFunc(gl.EQUAL, 1, 1); gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); gl.colorMask(true, true, true, true); // Draw the background as a quad. Drawing a background with gl.clear will not mask to the stenciled area. this.enterDrawRegion(this._backgroundDrawRegionId); const uniforms = { u_backgroundColor: this._backgroundColor4f }; const currentShader = this._shaderManager.getShader(ShaderManager.DRAW_MODE.background, 0); twgl.setUniforms(currentShader, uniforms); twgl.drawBufferInfo(gl, this._bufferInfo, gl.TRIANGLES); // Draw the candidate drawables on top of the background. this._drawThese(candidateIDs, ShaderManager.DRAW_MODE.default, projection, { idFilterFunc: testID => testID !== drawableID }); } finally { gl.colorMask(true, true, true, true); gl.disable(gl.STENCIL_TEST); this._doExitDrawRegion(); } } _isTouchingColorGpuFin(bounds, color3b, stop) { const gl = this._gl; const pixels = new Uint8Array(Math.floor(bounds.width * (bounds.height - stop) * 4)); gl.readPixels(0, 0, bounds.width, bounds.height - stop, gl.RGBA, gl.UNSIGNED_BYTE, pixels); if (this._debugCanvas) { this._debugCanvas.width = bounds.width; this._debugCanvas.height = bounds.height; const context = this._debugCanvas.getContext('2d'); const imageData = context.getImageData(0, 0, bounds.width, bounds.height - stop); imageData.data.set(pixels); context.putImageData(imageData, 0, 0); } for (let pixelBase = 0; pixelBase < pixels.length; pixelBase += 4) { // Transparent pixels are masked (either by the drawable's alpha channel or color mask). if (pixels[pixelBase + 3] !== 0 && colorMatches(color3b, pixels, pixelBase)) { return true; } } return false; } /** * Check if a particular Drawable is touching any in a set of Drawables. * @param {int} drawableID The ID of the Drawable to check. * @param {?Array} candidateIDs The Drawable IDs to check, otherwise all visible drawables in the renderer * @returns {boolean} True if the Drawable is touching one of candidateIDs. */ isTouchingDrawables(drawableID, candidateIDs = this._drawList) { const candidates = this._candidatesTouching(drawableID, // even if passed an invisible drawable, we will NEVER touch it! candidateIDs.filter(id => this._allDrawables[id]._visible)); // if we are invisble we don't touch anything. if (candidates.length === 0 || !this._allDrawables[drawableID]._visible) { return false; } // Get the union of all the candidates intersections. const bounds = this._candidatesBounds(candidates); const drawable = this._allDrawables[drawableID]; const point = __isTouchingDrawablesPoint; drawable.updateCPURenderAttributes(); // This is an EXTREMELY brute force collision detector, but it is // still faster than asking the GPU to give us the pixels. for (let x = bounds.left; x <= bounds.right; x++) { // Scratch Space - +y is top point[0] = x; for (let y = bounds.bottom; y <= bounds.top; y++) { point[1] = y; if (drawable.isTouching(point)) { for (let index = 0; index < candidates.length; index++) { if (candidates[index].drawable.isTouching(point)) { return true; } } } } } return false; } /** * Convert a client based x/y position on the canvas to a Scratch 3 world space * Rectangle. This creates recangles with a radius to cover selecting multiple * scratch pixels with touch / small render areas. * * @param {int} centerX The client x coordinate of the picking location. * @param {int} centerY The client y coordinate of the picking location. * @param {int} [width] The client width of the touch event (optional). * @param {int} [height] The client width of the touch event (optional). * @returns {Rectangle} Scratch world space rectangle, iterate bottom <= top, * left <= right. */ clientSpaceToScratchBounds(centerX, centerY, width = 1, height = 1) { const gl = this._gl; const clientToScratchX = this._nativeSize[0] / gl.canvas.clientWidth; const clientToScratchY = this._nativeSize[1] / gl.canvas.clientHeight; width *= clientToScratchX; height *= clientToScratchY; width = Math.max(1, Math.min(Math.round(width), MAX_TOUCH_SIZE[0])); height = Math.max(1, Math.min(Math.round(height), MAX_TOUCH_SIZE[1])); const x = centerX * clientToScratchX - (width - 1) / 2; // + because scratch y is inverted const y = centerY * clientToScratchY + (height - 1) / 2; const xOfs = width % 2 ? 0 : -0.5; // y is offset +0.5 const yOfs = height % 2 ? 0 : -0.5; const bounds = new Rectangle(); bounds.initFromBounds(Math.floor(this._xLeft + x + xOfs), Math.floor(this._xLeft + x + xOfs + width - 1), Math.ceil(this._yTop - y + yOfs), Math.ceil(this._yTop - y + yOfs + height - 1)); return bounds; } /** * Determine if the drawable is touching a client based x/y. Helper method for sensing * touching mouse-pointer. Ignores visibility. * * @param {int} drawableID The ID of the drawable to check. * @param {int} centerX The client x coordinate of the picking location. * @param {int} centerY The client y coordinate of the picking location. * @param {int} [touchWidth] The client width of the touch event (optional). * @param {int} [touchHeight] The client height of the touch event (optional). * @returns {boolean} If the drawable has any pixels that would draw in the touch area */ drawableTouching(drawableID, centerX, centerY, touchWidth, touchHeight) { const drawable = this._allDrawables[drawableID]; if (!drawable) { return false; } const bounds = this.clientSpaceToScratchBounds(centerX, centerY, touchWidth, touchHeight); const drawableBounds = drawable.getFastBounds(); drawableBounds.snapToInt(); if (!drawableBounds.intersects(bounds)) { return false; } drawable.updateCPURenderAttributes(); const worldPos = twgl.v3.create(); for (worldPos[1] = bounds.bottom; worldPos[1] <= bounds.top; worldPos[1]++) { for (worldPos[0] = bounds.left; worldPos[0] <= bounds.right; worldPos[0]++) { if (drawable.isTouching(worldPos)) { return true; } } } return false; } /** * Detect which sprite, if any, is at the given location. * This function will pick all drawables that are visible, unless specific * candidate drawable IDs are provided. Used for determining what is clicked * or dragged. Will not select hidden / ghosted sprites. * * @param {int} centerX The client x coordinate of the picking location. * @param {int} centerY The client y coordinate of the picking location. * @param {int} [touchWidth] The client width of the touch event (optional). * @param {int} [touchHeight] The client height of the touch event (optional). * @param {Array} [candidateIDs] The Drawable IDs to pick from, otherwise all visible drawables. * @returns {int} The ID of the topmost Drawable under the picking location, or * RenderConstants.ID_NONE if there is no Drawable at that location. */ pick(centerX, centerY, touchWidth, touchHeight, candidateIDs) { const bounds = this.clientSpaceToScratchBounds(centerX, centerY, touchWidth, touchHeight); if (bounds.left === -Infinity || bounds.bottom === -Infinity) { return false; } candidateIDs = (candidateIDs || this._drawList).filter(id => { const drawable = this._allDrawables[id]; // default pick list ignores visible and ghosted sprites. if (drawable.getVisible() && drawable.getUniforms().u_ghost !== 0) { const drawableBounds = drawable.getFastBounds(); const inRange = bounds.intersects(drawableBounds); if (!inRange) return false; if (drawable.skin instanceof PenSkin) return false; drawable.updateCPURenderAttributes(); return true; } return false; }); if (candidateIDs.length === 0) { return false; } const hits = []; const worldPos = twgl.v3.create(0, 0, 0); // Iterate over the scratch pixels and check if any candidate can be // touched at that point. for (worldPos[1] = bounds.bottom; worldPos[1] <= bounds.top; worldPos[1]++) { for (worldPos[0] = bounds.left; worldPos[0] <= bounds.right; worldPos[0]++) { // Check candidates in the reverse order they would have been // drawn. This will determine what candiate's silhouette pixel // would have been drawn at the point. for (let d = candidateIDs.length - 1; d >= 0; d--) { const id = candidateIDs[d]; const drawable = this._allDrawables[id]; if (drawable.isTouching(worldPos)) { hits[id] = (hits[id] || 0) + 1; break; } } } } // Bias toward selecting anything over nothing hits[RenderConstants.ID_NONE] = 0; let hit = RenderConstants.ID_NONE; for (const hitID in hits) { if (Object.prototype.hasOwnProperty.call(hits, hitID) && hits[hitID] > hits[hit]) { hit = hitID; } } return Number(hit); } /** * @typedef DrawableExtraction * @property {ImageData} data Raw pixel data for the drawable * @property {number} x The x coordinate of the drawable's bounding box's top-left corner, in 'CSS pixels' * @property {number} y The y coordinate of the drawable's bounding box's top-left corner, in 'CSS pixels' * @property {number} width The drawable's bounding box width, in 'CSS pixels' * @property {number} height The drawable's bounding box height, in 'CSS pixels' */ /** * Return a drawable's pixel data and bounds in screen space. * @param {int} drawableID The ID of the drawable to get pixel data for * @return {DrawableExtraction} Data about the picked drawable */ extractDrawableScreenSpace(drawableID) { const drawable = this._allDrawables[drawableID]; if (!drawable) throw new Error("Could not extract drawable with ID ".concat(drawableID, "; it does not exist")); this._doExitDrawRegion(); const nativeCenterX = this._nativeSize[0] * 0.5; const nativeCenterY = this._nativeSize[1] * 0.5; const scratchBounds = drawable.getFastBounds(); const canvas = this.canvas; // Ratio of the screen-space scale of the stage's canvas to the "native size" of the stage const scaleFactor = canvas.width / this._nativeSize[0]; // Bounds of the extracted drawable, in "canvas pixel space" // (origin is 0, 0, destination is the canvas width, height). const canvasSpaceBounds = new Rectangle(); canvasSpaceBounds.initFromBounds((scratchBounds.left + nativeCenterX) * scaleFactor, (scratchBounds.right + nativeCenterX) * scaleFactor, // in "canvas space", +y is down, but Rectangle methods assume bottom < top, so swap them (nativeCenterY - scratchBounds.top) * scaleFactor, (nativeCenterY - scratchBounds.bottom) * scaleFactor); canvasSpaceBounds.snapToInt(); // undo the transformation to transform the bounds, snapped to "canvas-pixel space", back to "Scratch space" // We have to transform -> snap -> invert transform so that the "Scratch-space" bounds are snapped in // "canvas-pixel space". scratchBounds.initFromBounds(canvasSpaceBounds.left / scaleFactor - nativeCenterX, canvasSpaceBounds.right / scaleFactor - nativeCenterX, nativeCenterY - canvasSpaceBounds.top / scaleFactor, nativeCenterY - canvasSpaceBounds.bottom / scaleFactor); const gl = this._gl; // Set a reasonable max limit width and height for the bufferInfo bounds const maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE); const clampedWidth = Math.min(MAX_EXTRACTED_DRAWABLE_DIMENSION, canvasSpaceBounds.width, maxTextureSize); const clampedHeight = Math.min(MAX_EXTRACTED_DRAWABLE_DIMENSION, canvasSpaceBounds.height, maxTextureSize); // Make a new bufferInfo since this._queryBufferInfo is limited to 480x360 const bufferInfo = twgl.createFramebufferInfo(gl, [{ format: gl.RGBA }], clampedWidth, clampedHeight); try { twgl.bindFramebufferInfo(gl, bufferInfo); // Limit size of viewport to the bounds around the target Drawable, // and create the projection matrix for the draw. gl.viewport(0, 0, clampedWidth, clampedHeight); const projection = twgl.m4.ortho(scratchBounds.left, scratchBounds.right, scratchBounds.top, scratchBounds.bottom, -1, 1); gl.clearColor(0, 0, 0, 0); gl.clear(gl.COLOR_BUFFER_BIT); this._drawThese([drawableID], ShaderManager.DRAW_MODE.straightAlpha, projection, { // Don't apply the ghost effect. TODO: is this an intentional design decision? effectMask: ~ShaderManager.EFFECT_INFO.ghost.mask, // We're doing this in screen-space, so the framebuffer dimensions should be those of the canvas in // screen-space. This is used to ensure SVG skins are rendered at the proper resolution. framebufferWidth: canvas.width, framebufferHeight: canvas.height }); const data = new Uint8Array(Math.floor(clampedWidth * clampedHeight * 4)); gl.readPixels(0, 0, clampedWidth, clampedHeight, gl.RGBA, gl.UNSIGNED_BYTE, data); // readPixels can only read into a Uint8Array, but ImageData has to take a Uint8ClampedArray. // We can share the same underlying buffer between them to avoid having to copy any data. const imageData = new ImageData(new Uint8ClampedArray(data.buffer), clampedWidth, clampedHeight); // On high-DPI devices, the canvas' width (in canvas pixels) will be larger than its width in CSS pixels. // We want to return the CSS-space bounds, // so take into account the ratio between the canvas' pixel dimensions and its layout dimensions. // This is usually the same as 1 / window.devicePixelRatio, but if e.g. you zoom your browser window without // the canvas resizing, then it'll differ. const ratio = canvas.getBoundingClientRect().width / canvas.width; return { imageData, x: canvasSpaceBounds.left * ratio, y: canvasSpaceBounds.bottom * ratio, width: canvasSpaceBounds.width * ratio, height: canvasSpaceBounds.height * ratio }; } finally { gl.deleteFramebuffer(bufferInfo.framebuffer); } } /** * @typedef ColorExtraction * @property {Uint8Array} data Raw pixel data for the drawable * @property {int} width Drawable bounding box width * @property {int} height Drawable bounding box height * @property {object} color Color object with RGBA properties at picked location */ /** * Return drawable pixel data and color at a given position * @param {int} x The client x coordinate of the picking location. * @param {int} y The client y coordinate of the picking location. * @param {int} radius The client radius to extract pixels with. * @return {?ColorExtraction} Data about the picked color */ extractColor(x, y, radius) { this._doExitDrawRegion(); const scratchX = Math.round(this._nativeSize[0] * (x / this._gl.canvas.clientWidth - 0.5)); const scratchY = Math.round(-this._nativeSize[1] * (y / this._gl.canvas.clientHeight - 0.5)); const gl = this._gl; twgl.bindFramebufferInfo(gl, this._queryBufferInfo); const bounds = new Rectangle(); bounds.initFromBounds(scratchX - radius, scratchX + radius, scratchY - radius, scratchY + radius); const pickX = scratchX - bounds.left; const pickY = bounds.top - scratchY; gl.viewport(0, 0, bounds.width, bounds.height); const projection = twgl.m4.ortho(bounds.left, bounds.right, bounds.top, bounds.bottom, -1, 1); gl.clearColor(...this._backgroundColor4f); gl.clear(gl.COLOR_BUFFER_BIT); this._drawThese(this._drawList, ShaderManager.DRAW_MODE.default, projection); const data = new Uint8Array(Math.floor(bounds.width * bounds.height * 4)); gl.readPixels(0, 0, bounds.width, bounds.height, gl.RGBA, gl.UNSIGNED_BYTE, data); const pixelBase = Math.floor(4 * (pickY * bounds.width + pickX)); const color = { r: data[pixelBase], g: data[pixelBase + 1], b: data[pixelBase + 2], a: data[pixelBase + 3] }; if (this._debugCanvas) { this._debugCanvas.width = bounds.width; this._debugCanvas.height = bounds.height; const ctx = this._debugCanvas.getContext('2d'); const imageData = ctx.createImageData(bounds.width, bounds.height); imageData.data.set(data); ctx.putImageData(imageData, 0, 0); ctx.strokeStyle = 'black'; ctx.fillStyle = "rgba(".concat(color.r, ", ").concat(color.g, ", ").concat(color.b, ", ").concat(color.a, ")"); ctx.rect(pickX - 4, pickY - 4, 8, 8); ctx.fill(); ctx.stroke(); } return { data: data, width: bounds.width, height: bounds.height, color: color }; } /** * Get the candidate bounding box for a touching query. * @param {int} drawableID ID for drawable of query. * @return {?Rectangle} Rectangle bounds for touching query, or null. */ _touchingBounds(drawableID) { const drawable = this._allDrawables[drawableID]; /** @todo remove this once URL-based skin setting is removed. */ if (!drawable.skin || !drawable.skin.getTexture([100, 100])) return null; const bounds = drawable.getFastBounds(); // Limit queries to the stage size. if (!this.offscreenTouching) { bounds.clamp(this._xLeft, this._xRight, this._yBottom, this._yTop); } // Use integer coordinates for queries - weird things happen // when you provide float width/heights to gl.viewport and projection. bounds.snapToInt(); if (bounds.width === 0 || bounds.height === 0) { // No space to query. return null; } return bounds; } _unsnappedTouchingBounds(drawableID) { // _touchingBounds with the snapToint call removed. const drawable = this._allDrawables[drawableID]; if (!drawable.skin || !drawable.skin.getTexture([100, 100])) return null; const bounds = drawable.getFastBounds(); if (!this.offscreenTouching) { bounds.clamp(this._xLeft, this._xRight, this._yBottom, this._yTop); } if (bounds.width === 0 || bounds.height === 0) { return null; } return bounds; } /** * Filter a list of candidates for a touching query into only those that * could possibly intersect the given bounds. * @param {int} drawableID - ID for drawable of query. * @param {Array} candidateIDs - Candidates for touching query. * @return {?Array< {id, drawable, intersection} >} Filtered candidates with useful data. */ _candidatesTouching(drawableID, candidateIDs) { const bounds = this._touchingBounds(drawableID); const result = []; if (bounds === null) { return result; } // iterate through the drawables list BACKWARDS - we want the top most item to be the first we check for (let index = candidateIDs.length - 1; index >= 0; index--) { const id = candidateIDs[index]; if (id !== drawableID) { const drawable = this._allDrawables[id]; // Text bubbles aren't considered in "touching" queries if (drawable.skin instanceof TextBubbleSkin) continue; if (drawable.skin && drawable._visible) { // If private skin access is disabled, do not allow projects to use touching blocks to guess the // contents of a private skin. if (!this.allowPrivateSkinAccess && drawable.skin.private) continue; // Update the CPU position data drawable.updateCPURenderAttributes(); const candidateBounds = drawable.getFastBounds(); // Push bounds out to integers. If a drawable extends out into half a pixel, that half-pixel still // needs to be tested. Plus, in some areas we construct another rectangle from the union of these, // and iterate over its pixels (width * height). Turns out that doesn't work so well when the // width/height aren't integers. candidateBounds.snapToInt(); if (bounds.intersects(candidateBounds)) { result.push({ id, drawable, intersection: Rectangle.intersect(bounds, candidateBounds) }); } } } } return result; } /** * Helper to get the union bounds from a set of candidates returned from the above method * @private * @param {Array} candidates info from _candidatesTouching * @return {Rectangle} the outer bounding box union */ _candidatesBounds(candidates) { return candidates.reduce((memo, { intersection }) => { if (!memo) { return intersection; } // store the union of the two rectangles in our static rectangle instance return Rectangle.union(memo, intersection, __candidatesBounds); }, null); } /** * Update a drawable's skin. * @param {number} drawableID The drawable's id. * @param {number} skinId The skin to update to. */ updateDrawableSkinId(drawableID, skinId) { const drawable = this._allDrawables[drawableID]; // TODO: https://github.com/LLK/scratch-vm/issues/2288 if (!drawable) return; drawable.skin = this._allSkins[skinId]; } /** * Update a drawable's position. * @param {number} drawableID The drawable's id. * @param {Array.} position The new position. */ updateDrawablePosition(drawableID, position) { const drawable = this._allDrawables[drawableID]; // TODO: https://github.com/LLK/scratch-vm/issues/2288 if (!drawable) return; drawable.updatePosition(position); } /** * Update a drawable's direction. * @param {number} drawableID The drawable's id. * @param {number} direction A new direction. */ updateDrawableDirection(drawableID, direction) { const drawable = this._allDrawables[drawableID]; // TODO: https://github.com/LLK/scratch-vm/issues/2288 if (!drawable) return; drawable.updateDirection(direction); } /** * Update a drawable's scale. * @param {number} drawableID The drawable's id. * @param {Array.} scale A new scale. */ updateDrawableScale(drawableID, scale) { const drawable = this._allDrawables[drawableID]; // TODO: https://github.com/LLK/scratch-vm/issues/2288 if (!drawable) return; drawable.updateScale(scale); } /** * Update a drawable's direction and scale together. * @param {number} drawableID The drawable's id. * @param {number} direction A new direction. * @param {Array.} scale A new scale. */ updateDrawableDirectionScale(drawableID, direction, scale) { const drawable = this._allDrawables[drawableID]; // TODO: https://github.com/LLK/scratch-vm/issues/2288 if (!drawable) return; drawable.updateDirection(direction); drawable.updateScale(scale); } /** * Update a drawable's visibility. * @param {number} drawableID The drawable's id. * @param {boolean} visible Will the drawable be visible? */ updateDrawableVisible(drawableID, visible) { const drawable = this._allDrawables[drawableID]; // TODO: https://github.com/LLK/scratch-vm/issues/2288 if (!drawable) return; drawable.updateVisible(visible); } /** * Update a drawable's visual effect. * @param {number} drawableID The drawable's id. * @param {string} effectName The effect to change. * @param {number} value A new effect value. */ updateDrawableEffect(drawableID, effectName, value) { const drawable = this._allDrawables[drawableID]; // TODO: https://github.com/LLK/scratch-vm/issues/2288 if (!drawable) return; drawable.updateEffect(effectName, value); } /** * Update the position, direction, scale, or effect properties of this Drawable. * @deprecated Use specific updateDrawable* methods instead. * @param {int} drawableID The ID of the Drawable to update. * @param {object.} properties The new property values to set. */ updateDrawableProperties(drawableID, properties) { const drawable = this._allDrawables[drawableID]; if (!drawable) { /** * @todo(https://github.com/LLK/scratch-vm/issues/2288) fix whatever's wrong in the VM which causes this, then add a warning or throw here. * Right now this happens so much on some projects that a warning or exception here can hang the browser. */ return; } if ('skinId' in properties) { this.updateDrawableSkinId(drawableID, properties.skinId); } drawable.updateProperties(properties); } /** * Update the position object's x & y members to keep the drawable fenced in view. * @param {int} drawableID - The ID of the Drawable to update. * @param {Array.} position to be fenced - An array of type [x, y] * @return {Array.} The fenced position as an array [x, y] */ getFencedPositionOfDrawable(drawableID, position) { let x = position[0]; let y = position[1]; const drawable = this._allDrawables[drawableID]; if (!drawable) { // @todo(https://github.com/LLK/scratch-vm/issues/2288) fix whatever's wrong in the VM which causes this, then add a warning or throw here. // Right now this happens so much on some projects that a warning or exception here can hang the browser. return [x, y]; } const dx = x - drawable._position[0]; const dy = y - drawable._position[1]; const aabb = drawable._skin.getFenceBounds(drawable, __fenceBounds); const inset = Math.floor(Math.min(aabb.width, aabb.height) / 2); const sx = this._xRight - Math.min(FENCE_WIDTH, inset); if (aabb.right + dx < -sx) { x = Math.ceil(drawable._position[0] - (sx + aabb.right)); } else if (aabb.left + dx > sx) { x = Math.floor(drawable._position[0] + (sx - aabb.left)); } const sy = this._yTop - Math.min(FENCE_WIDTH, inset); if (aabb.top + dy < -sy) { y = Math.ceil(drawable._position[1] - (sy + aabb.top)); } else if (aabb.bottom + dy > sy) { y = Math.floor(drawable._position[1] + (sy - aabb.bottom)); } return [x, y]; } /** * Clear a pen layer. * @param {int} penSkinID - the unique ID of a Pen Skin. */ penClear(penSkinID) { this.dirty = true; const skin = /** @type {PenSkin} */ this._allSkins[penSkinID]; skin.clear(); } /** * Draw a point on a pen layer. * @param {int} penSkinID - the unique ID of a Pen Skin. * @param {PenAttributes} penAttributes - how the point should be drawn. * @param {number} x - the X coordinate of the point to draw. * @param {number} y - the Y coordinate of the point to draw. */ penPoint(penSkinID, penAttributes, x, y) { this.dirty = true; const skin = /** @type {PenSkin} */ this._allSkins[penSkinID]; skin.drawPoint(penAttributes, x, y); } /** * Draw a line on a pen layer. * @param {int} penSkinID - the unique ID of a Pen Skin. * @param {PenAttributes} penAttributes - how the line should be drawn. * @param {number} x0 - the X coordinate of the beginning of the line. * @param {number} y0 - the Y coordinate of the beginning of the line. * @param {number} x1 - the X coordinate of the end of the line. * @param {number} y1 - the Y coordinate of the end of the line. */ penLine(penSkinID, penAttributes, x0, y0, x1, y1) { this.dirty = true; const skin = /** @type {PenSkin} */ this._allSkins[penSkinID]; skin.drawLine(penAttributes, x0, y0, x1, y1); } /** * Stamp a Drawable onto a pen layer. * @param {int} penSkinID - the unique ID of a Pen Skin. * @param {int} stampID - the unique ID of the Drawable to use as the stamp. */ penStamp(penSkinID, stampID) { this.dirty = true; const stampDrawable = this._allDrawables[stampID]; if (!stampDrawable) { return; } // TW: The bounds will be snapped later const bounds = this._unsnappedTouchingBounds(stampID); if (!bounds) { return; } this._doExitDrawRegion(); const skin = /** @type {PenSkin} */ this._allSkins[penSkinID]; const gl = this._gl; twgl.bindFramebufferInfo(gl, skin._framebuffer); // Limit size of viewport to the bounds around the stamp Drawable and create the projection matrix for the draw. // TW: We upscale the "stage space" to "screen space" and then snap the coordinates so that tiled projects // don't have seems between sprites. const quality = skin.renderQuality; bounds.left *= quality; bounds.right *= quality; bounds.top *= quality; bounds.bottom *= quality; bounds.snapToInt(); gl.viewport(this._nativeSize[0] * 0.5 * quality + bounds.left, this._nativeSize[1] * 0.5 * quality - bounds.top, bounds.width, bounds.height); const projection = twgl.m4.ortho( // TW: We have to convert the snapped "screen-space" back to "stage-space" for rendering. bounds.left / quality, bounds.right / quality, bounds.top / quality, bounds.bottom / quality, -1, 1); // Draw the stamped sprite onto the PenSkin's framebuffer. this._drawThese([stampID], ShaderManager.DRAW_MODE.default, projection, { ignoreVisibility: true, framebufferWidth: this._nativeSize[0] * quality, framebufferHeight: this._nativeSize[1] * quality }); skin._silhouetteDirty = true; } /* ****** * Truly internal functions: these support the functions above. ********/ /** * Build geometry (vertex and index) buffers. * @private */ _createGeometry() { const quad = { a_position: { numComponents: 2, data: [-0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5] }, a_texCoord: { numComponents: 2, data: [1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1] } }; this._bufferInfo = twgl.createBufferInfoFromArrays(this._gl, quad); } /** * Respond to a change in the "native" rendering size. The native size is used by buffers which are fixed in size * regardless of the size of the main render target. This includes the buffers used for queries such as picking and * color-touching. The fixed size allows (more) consistent behavior across devices and presentation modes. * @param {object} event - The change event. * @private */ onNativeSizeChanged(event) { this.dirty = true; const [width, height] = event.newSize; const gl = this._gl; const attachments = [{ format: gl.RGBA }, { format: gl.DEPTH_STENCIL }]; if (!this._pickBufferInfo) { this._pickBufferInfo = twgl.createFramebufferInfo(gl, attachments, MAX_TOUCH_SIZE[0], MAX_TOUCH_SIZE[1]); } /** @todo should we create this on demand to save memory? */ // A 480x360 32-bpp buffer is 675 KiB. if (this._queryBufferInfo) { twgl.resizeFramebufferInfo(gl, this._queryBufferInfo, attachments, width, height); } else { this._queryBufferInfo = twgl.createFramebufferInfo(gl, attachments, width, height); } } /** * Enter a draw region. * * A draw region is where multiple draw operations are performed with the * same GL state. WebGL performs poorly when it changes state like blend * mode. Marking a collection of state values as a "region" the renderer * can skip superfluous extra state calls when it is already in that * region. Since one region may be entered from within another a exit * handle can also be registered that is called when a new region is about * to be entered to restore a common inbetween state. * * @param {any} regionId - id of the region to enter * @param {function} enter - handle to call when first entering a region * @param {function} exit - handle to call when leaving a region */ enterDrawRegion(regionId, enter = regionId.enter, exit = regionId.exit) { if (this._regionId !== regionId) { this._doExitDrawRegion(); this._regionId = regionId; enter(); this._exitRegion = exit; } } /** * Forcefully exit the current region returning to a common inbetween GL * state. */ _doExitDrawRegion() { if (this._exitRegion !== null) { this._exitRegion(); } this._exitRegion = null; this._regionId = null; } /** * Draw a set of Drawables, by drawable ID * @param {Array} drawables The Drawable IDs to draw, possibly this._drawList. * @param {ShaderManager.DRAW_MODE} drawMode Draw normally, silhouette, etc. * @param {module:twgl/m4.Mat4} projection The projection matrix to use. * @param {object} [opts] Options for drawing * @param {idFilterFunc} opts.filter An optional filter function. * @param {object.} opts.extraUniforms Extra uniforms for the shaders. * @param {int} opts.effectMask Bitmask for effects to allow * @param {boolean} opts.ignoreVisibility Draw all, despite visibility (e.g. stamping, touching color) * @param {int} opts.framebufferWidth The width of the framebuffer being drawn onto. Defaults to "native" width * @param {int} opts.framebufferHeight The height of the framebuffer being drawn onto. Defaults to "native" height * @private */ _drawThese(drawables, drawMode, projection, opts = {}) { const gl = this._gl; let currentShader = null; const framebufferSpaceScaleDiffers = 'framebufferWidth' in opts && 'framebufferHeight' in opts && opts.framebufferWidth !== this._nativeSize[0] && opts.framebufferHeight !== this._nativeSize[1]; const numDrawables = drawables.length; for (let drawableIndex = 0; drawableIndex < numDrawables; ++drawableIndex) { const drawableID = drawables[drawableIndex]; // If we have a filter, check whether the ID fails if (opts.filter && !opts.filter(drawableID)) continue; const drawable = this._allDrawables[drawableID]; /** @todo check if drawable is inside the viewport before anything else */ // Hidden drawables (e.g., by a "hide" block) are not drawn unless // the ignoreVisibility flag is used (e.g. for stamping or touchingColor). if (!drawable.getVisible() && !opts.ignoreVisibility) continue; // drawableScale is the "framebuffer-pixel-space" scale of the drawable, as percentages of the drawable's // "native size" (so 100 = same as skin's "native size", 200 = twice "native size"). // If the framebuffer dimensions are the same as the stage's "native" size, there's no need to calculate it. const drawableScale = framebufferSpaceScaleDiffers ? [drawable.scale[0] * opts.framebufferWidth / this._nativeSize[0], drawable.scale[1] * opts.framebufferHeight / this._nativeSize[1]] : drawable.scale; // If the skin or texture isn't ready yet, skip it. if (!drawable.skin || !drawable.skin.getTexture(drawableScale)) continue; const uniforms = {}; let effectBits = drawable.enabledEffects; effectBits &= Object.prototype.hasOwnProperty.call(opts, 'effectMask') ? opts.effectMask : effectBits; const newShader = this._shaderManager.getShader(drawMode, effectBits); // Manually perform region check. Do not create functions inside a // loop. if (this._regionId !== newShader) { this._doExitDrawRegion(); this._regionId = newShader; currentShader = newShader; gl.useProgram(currentShader.program); twgl.setBuffersAndAttributes(gl, currentShader, this._bufferInfo); Object.assign(uniforms, { u_projectionMatrix: projection }); } Object.assign(uniforms, drawable.skin.getUniforms(drawableScale), drawable.getUniforms()); // Apply extra uniforms after the Drawable's, to allow overwriting. if (opts.extraUniforms) { Object.assign(uniforms, opts.extraUniforms); } if (uniforms.u_skin) { twgl.setTextureParameters(gl, uniforms.u_skin, { minMag: drawable.skin.useNearest(drawableScale, drawable) ? gl.NEAREST : gl.LINEAR }); } twgl.setUniforms(currentShader, uniforms); twgl.drawBufferInfo(gl, this._bufferInfo, gl.TRIANGLES); } this._regionId = null; } /** * Get the convex hull points for a particular Drawable. * To do this, calculate it based on the drawable's Silhouette. * @param {int} drawableID The Drawable IDs calculate convex hull for. * @return {Array>} points Convex hull points, as [[x, y], ...] */ _getConvexHullPointsForDrawable(drawableID) { const drawable = this._allDrawables[drawableID]; const [width, height] = drawable.skin.size; // No points in the hull if invisible or size is 0. if (!drawable.getVisible() || width === 0 || height === 0) { return []; } drawable.updateCPURenderAttributes(); /** * Return the determinant of two vectors, the vector from A to B and the vector from A to C. * * The determinant is useful in this case to know if AC is counter-clockwise from AB. * A positive value means that AC is counter-clockwise from AB. A negative value means AC is clockwise from AB. * * @param {Float32Array} A A 2d vector in space. * @param {Float32Array} B A 2d vector in space. * @param {Float32Array} C A 2d vector in space. * @return {number} Greater than 0 if counter clockwise, less than if clockwise, 0 if all points are on a line. */ const determinant = function determinant(A, B, C) { // AB = B - A // AC = C - A // det (AB BC) = AB0 * AC1 - AB1 * AC0 return (B[0] - A[0]) * (C[1] - A[1]) - (B[1] - A[1]) * (C[0] - A[0]); }; // This algorithm for calculating the convex hull somewhat resembles the monotone chain algorithm. // The main difference is that instead of sorting the points by x-coordinate, and y-coordinate in case of ties, // it goes through them by y-coordinate in the outer loop and x-coordinate in the inner loop. // This gives us "left" and "right" hulls, whereas the monotone chain algorithm gives "top" and "bottom" hulls. // Adapted from https://github.com/LLK/scratch-flash/blob/dcbeeb59d44c3be911545dfe54d46a32404f8e69/src/scratch/ScratchCostume.as#L369-L413 const leftHull = []; const rightHull = []; // While convex hull algorithms usually push and pop values from the list of hull points, // here, we keep indices for the "last" point in each array. Any points past these indices are ignored. // This is functionally equivalent to pushing and popping from a "stack" of hull points. let leftEndPointIndex = -1; let rightEndPointIndex = -1; const _pixelPos = twgl.v3.create(); const _effectPos = twgl.v3.create(); let currentPoint; // *Not* Scratch Space-- +y is bottom // Loop over all rows of pixels, starting at the top for (let y = 0; y < height; y++) { _pixelPos[1] = y / height; // We start at the leftmost point, then go rightwards until we hit an opaque pixel let x = 0; for (; x < width; x++) { _pixelPos[0] = x / width; EffectTransform.transformPoint(drawable, _pixelPos, _effectPos); if (drawable.skin.isTouchingLinear(_effectPos)) { currentPoint = [x, y]; break; } } // If we managed to loop all the way through, there are no opaque pixels on this row. Go to the next one if (x >= width) { continue; } // Because leftEndPointIndex is initialized to -1, this is skipped for the first two rows. // It runs only when there are enough points in the left hull to make at least one line. // If appending the current point to the left hull makes a counter-clockwise turn, // we want to append the current point. Otherwise, we decrement the index of the "last" hull point until the // current point makes a counter-clockwise turn. // This decrementing has the same effect as popping from the point list, but is hopefully faster. while (leftEndPointIndex > 0) { if (determinant(leftHull[leftEndPointIndex], leftHull[leftEndPointIndex - 1], currentPoint) > 0) { break; } else { // leftHull.pop(); --leftEndPointIndex; } } // This has the same effect as pushing to the point list. // This "list head pointer" coding style leaves excess points dangling at the end of the list, // but that doesn't matter; we simply won't copy them over to the final hull. // leftHull.push(currentPoint); leftHull[++leftEndPointIndex] = currentPoint; // Now we repeat the process for the right side, looking leftwards for a pixel. for (x = width - 1; x >= 0; x--) { _pixelPos[0] = x / width; EffectTransform.transformPoint(drawable, _pixelPos, _effectPos); if (drawable.skin.isTouchingLinear(_effectPos)) { currentPoint = [x, y]; break; } } // Because we're coming at this from the right, it goes clockwise this time. while (rightEndPointIndex > 0) { if (determinant(rightHull[rightEndPointIndex], rightHull[rightEndPointIndex - 1], currentPoint) < 0) { break; } else { --rightEndPointIndex; } } rightHull[++rightEndPointIndex] = currentPoint; } // Start off "hullPoints" with the left hull points. const hullPoints = leftHull; // This is where we get rid of those dangling extra points. hullPoints.length = leftEndPointIndex + 1; // Add points from the right side in reverse order so all points are ordered clockwise. for (let j = rightEndPointIndex; j >= 0; --j) { hullPoints.push(rightHull[j]); } // Simplify boundary points using hull.js. // TODO: Remove this; this algorithm already generates convex hulls. return hull(hullPoints, Infinity); } /** * Sample a "final" color from an array of drawables at a given scratch space. * Will blend any alpha values with the drawables "below" it. * @param {twgl.v3} vec Scratch Vector Space to sample * @param {Array} drawables A list of drawables with the "top most" * drawable at index 0 * @param {Uint8ClampedArray} dst The color3b space to store the answer in. * @return {Uint8ClampedArray} The dst vector with everything blended down. */ static sampleColor3b(vec, drawables, dst) { dst = dst || new Uint8ClampedArray(3); dst.fill(0); let blendAlpha = 1; for (let index = 0; blendAlpha !== 0 && index < drawables.length; index++) { /* if (left > vec[0] || right < vec[0] || bottom > vec[1] || top < vec[0]) { continue; } */ Drawable.sampleColor4b(vec, drawables[index].drawable, __blendColor); // Equivalent to gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) dst[0] += __blendColor[0] * blendAlpha; dst[1] += __blendColor[1] * blendAlpha; dst[2] += __blendColor[2] * blendAlpha; blendAlpha *= 1 - __blendColor[3] / 255; } // Backdrop could be transparent, so we need to go to the "clear color" of the // draw scene (white) as a fallback if everything was alpha dst[0] += blendAlpha * 255; dst[1] += blendAlpha * 255; dst[2] += blendAlpha * 255; return dst; } /** * @callback RenderWebGL#snapshotCallback * @param {string} dataURI Data URI of the snapshot of the renderer */ /** * @param {snapshotCallback} callback Function called in the next frame with the snapshot data */ requestSnapshot(callback) { this.dirty = true; this._snapshotCallbacks.push(callback); } } // :3 RenderWebGL.prototype.canHazPixels = RenderWebGL.prototype.extractDrawableScreenSpace; /** * Values for setUseGPU() * @enum {string} */ RenderWebGL.UseGpuModes = { /** * Heuristically decide whether to use the GPU path, the CPU path, or a dynamic mixture of the two. */ Automatic: 'Automatic', /** * Always use the GPU path. */ ForceGPU: 'ForceGPU', /** * Always use the CPU path. */ ForceCPU: 'ForceCPU' }; /** * WebGL powerPreference used for future RenderWebGL instances. * The power preference of a renderer cannot be changed after instantiation. * @type {'default'|'high-performance'|'low-power'} */ RenderWebGL.powerPreference = 'default'; module.exports = RenderWebGL; /***/ }), /***/ "./node_modules/scratch-render/src/SVGSkin.js": /*!****************************************************!*\ !*** ./node_modules/scratch-render/src/SVGSkin.js ***! \****************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const twgl = __webpack_require__(/*! twgl.js */ "./node_modules/twgl.js/dist/4.x/twgl-full.js"); const Skin = __webpack_require__(/*! ./Skin */ "./node_modules/scratch-render/src/Skin.js"); const { loadSvgString, serializeSvgToString } = __webpack_require__(/*! scratch-svg-renderer */ "./node_modules/scratch-render/node_modules/scratch-svg-renderer/src/index.js"); const ShaderManager = __webpack_require__(/*! ./ShaderManager */ "./node_modules/scratch-render/src/ShaderManager.js"); const MAX_TEXTURE_DIMENSION = 2048; /** * All scaled renderings of the SVG are stored in an array. The 1.0 scale of * the SVG is stored at the 8th index. The smallest possible 1 / 256 scale * rendering is stored at the 0th index. * @const {number} */ const INDEX_OFFSET = 8; class SVGSkin extends Skin { /** * Create a new SVG skin. * @param {!int} id - The ID for this Skin. * @param {!RenderWebGL} renderer - The renderer which will use this skin. * @constructor * @extends Skin */ constructor(id, renderer) { super(id, renderer); /** @type {HTMLImageElement} */ this._svgImage = document.createElement('img'); /** @type {boolean} */ this._svgImageLoaded = false; /** @type {Array} */ this._size = [0, 0]; /** @type {HTMLCanvasElement} */ this._canvas = document.createElement('canvas'); /** @type {CanvasRenderingContext2D} */ this._context = this._canvas.getContext('2d'); /** @type {Array} */ this._scaledMIPs = []; /** @type {number} */ this._largestMIPScale = 0; /** * Ratio of the size of the SVG and the max size of the WebGL texture * @type {Number} */ this._maxTextureScale = 1; } /** * Dispose of this object. Do not use it after calling this method. */ dispose() { this.resetMIPs(); super.dispose(); } /** * @return {Array} the natural size, in Scratch units, of this skin. */ get size() { return [this._size[0], this._size[1]]; } useNearest(scale, drawable) { // If the effect bits for mosaic, pixelate, whirl, or fisheye are set, use linear if ((drawable.enabledEffects & (ShaderManager.EFFECT_INFO.fisheye.mask | ShaderManager.EFFECT_INFO.whirl.mask | ShaderManager.EFFECT_INFO.pixelate.mask | ShaderManager.EFFECT_INFO.mosaic.mask)) !== 0) { return false; } // We can't use nearest neighbor unless we are a multiple of 90 rotation if (drawable._direction % 90 !== 0) { return false; } // Because SVG skins' bounding boxes are currently not pixel-aligned, the idea here is to hide blurriness // by using nearest-neighbor scaling if one screen-space pixel is "close enough" to one texture pixel. // If the scale of the skin is very close to 100 (0.99999 variance is okay I guess) // TODO: Make this check more precise. We should use nearest if there's less than one pixel's difference // between the screen-space and texture-space sizes of the skin. Mipmaps make this harder because there are // multiple textures (and hence multiple texture spaces) and we need to know which one to choose. if (Math.abs(scale[0]) > 99 && Math.abs(scale[0]) < 101 && Math.abs(scale[1]) > 99 && Math.abs(scale[1]) < 101) { return true; } return false; } /** * Create a MIP for a given scale. * @param {number} scale - The relative size of the MIP * @return {SVGMIP} An object that handles creating and updating SVG textures. */ createMIP(scale) { const isLargestMIP = this._largestMIPScale < scale; // TW: Silhouette will lazily read image data from our . However, this canvas is shared // between the Skin and Silhouette so changing it here can mess up Silhouette. To prevent that, // we will force the silhouette to synchronously read the image data before we mutate the // canvas, unless the new MIP is the largest MIP, in which case doing so is unnecessary as we // will update the silhouette later anyways. if (!isLargestMIP) { this._silhouette.unlazy(); } const [width, height] = this._size; this._canvas.width = width * scale; this._canvas.height = height * scale; if (this._canvas.width <= 0 || this._canvas.height <= 0 || // Even if the canvas at the current scale has a nonzero size, the image's dimensions are floored // pre-scaling; e.g. if an image has a width of 0.4 and is being rendered at 3x scale, the canvas will have // a width of 1, but the image's width will be rounded down to 0 on some browsers (Firefox) prior to being // drawn at that scale, resulting in an IndexSizeError if we attempt to draw it. this._svgImage.naturalWidth <= 0 || this._svgImage.naturalHeight <= 0) return super.getTexture(); this._context.clearRect(0, 0, this._canvas.width, this._canvas.height); this._context.setTransform(scale, 0, 0, scale, 0, 0); this._context.drawImage(this._svgImage, 0, 0); // TW: Reading image data from is very slow and causes animations to stutter, // so we just use the canvas directly instead. const textureData = this._canvas; const textureOptions = { auto: false, wrap: this._renderer.gl.CLAMP_TO_EDGE, src: textureData, premultiplyAlpha: true }; const mip = twgl.createTexture(this._renderer.gl, textureOptions); // Check if this is the largest MIP created so far. Currently, silhouettes only get scaled up. if (isLargestMIP) { this._silhouette.update(textureData); this._largestMIPScale = scale; } return mip; } updateSilhouette(scale = [100, 100]) { // Ensure a silhouette exists. this.getTexture(scale); this._silhouette.unlazy(); } /** * @param {Array} scale - The scaling factors to be used, each in the [0,100] range. * @return {WebGLTexture} The GL texture representation of this skin when drawing at the given scale. */ getTexture(scale) { // The texture only ever gets uniform scale. Take the larger of the two axes. const scaleMax = scale ? Math.max(Math.abs(scale[0]), Math.abs(scale[1])) : 100; const requestedScale = Math.min(scaleMax / 100, this._maxTextureScale); // Math.ceil(Math.log2(scale)) means we use the "1x" texture at (0.5, 1] scale, // the "2x" texture at (1, 2] scale, the "4x" texture at (2, 4] scale, etc. // This means that one texture pixel will always be between 0.5x and 1x the size of one rendered pixel, // but never bigger than one rendered pixel--this prevents blurriness from blowing up the texture too much. const mipLevel = Math.max(Math.ceil(Math.log2(requestedScale)) + INDEX_OFFSET, 0); // Can't use bitwise stuff here because we need to handle negative exponents const mipScale = Math.pow(2, mipLevel - INDEX_OFFSET); if (this._svgImageLoaded && !this._scaledMIPs[mipLevel]) { this._scaledMIPs[mipLevel] = this.createMIP(mipScale); } return this._scaledMIPs[mipLevel] || super.getTexture(); } /** * Do a hard reset of the existing MIPs by deleting them. */ resetMIPs() { this._scaledMIPs.forEach(oldMIP => this._renderer.gl.deleteTexture(oldMIP)); this._scaledMIPs.length = 0; this._largestMIPScale = 0; } /** * Set the contents of this skin to a snapshot of the provided SVG data. * @param {string} svgData - new SVG to use. * @param {Array} [rotationCenter] - Optional rotation center for the SVG. If not supplied, it will be * calculated from the bounding box * @fires Skin.event:WasAltered */ setSVG(svgData, rotationCenter) { const svgTag = loadSvgString(svgData); const svgText = serializeSvgToString(svgTag, true /* shouldInjectFonts */ ); this._svgImageLoaded = false; const { x, y, width, height } = svgTag.viewBox.baseVal; // While we're setting the size before the image is loaded, this doesn't cause the skin to appear with the wrong // size for a few frames while the new image is loading, because we don't emit the `WasAltered` event, telling // drawables using this skin to update, until the image is loaded. // We need to do this because the VM reads the skin's `size` directly after calling `setSVG`. // TODO: return a Promise so that the VM can read the skin's `size` after the image is loaded. this._size[0] = width; this._size[1] = height; // If there is another load already in progress, replace the old onload to effectively cancel the old load this._svgImage.onload = () => { if (width === 0 || height === 0) { super.setEmptyImageData(); return; } const maxDimension = Math.ceil(Math.max(width, height)); let testScale = 2; for (testScale; maxDimension * testScale <= MAX_TEXTURE_DIMENSION; testScale *= 2) { this._maxTextureScale = testScale; } this.resetMIPs(); if (typeof rotationCenter === 'undefined') rotationCenter = this.calculateRotationCenter(); // Compensate for viewbox offset. // See https://github.com/LLK/scratch-render/pull/90. this._rotationCenter[0] = rotationCenter[0] - x; this._rotationCenter[1] = rotationCenter[1] - y; this._svgImageLoaded = true; this.emitWasAltered(); }; this._svgImage.src = "data:image/svg+xml;utf8,".concat(encodeURIComponent(svgText)); } } module.exports = SVGSkin; /***/ }), /***/ "./node_modules/scratch-render/src/ShaderManager.js": /*!**********************************************************!*\ !*** ./node_modules/scratch-render/src/ShaderManager.js ***! \**********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const twgl = __webpack_require__(/*! twgl.js */ "./node_modules/twgl.js/dist/4.x/twgl-full.js"); class ShaderManager { /** * @param {WebGLRenderingContext} gl WebGL rendering context to create shaders for * @constructor */ constructor(gl) { this._gl = gl; /** * The cache of all shaders compiled so far, filled on demand. * @type {Object>} * @private */ this._shaderCache = {}; for (const modeName in ShaderManager.DRAW_MODE) { if (Object.prototype.hasOwnProperty.call(ShaderManager.DRAW_MODE, modeName)) { this._shaderCache[modeName] = []; } } } /** * Fetch the shader for a particular set of active effects. * Build the shader if necessary. * @param {ShaderManager.DRAW_MODE} drawMode Draw normally, silhouette, etc. * @param {int} effectBits Bitmask representing the enabled effects. * @returns {ProgramInfo} The shader's program info. */ getShader(drawMode, effectBits) { const cache = this._shaderCache[drawMode]; if (drawMode === ShaderManager.DRAW_MODE.silhouette) { // Silhouette mode isn't affected by these effects. effectBits &= ~(ShaderManager.EFFECT_INFO.color.mask | ShaderManager.EFFECT_INFO.brightness.mask); } let shader = cache[effectBits]; if (!shader) { shader = cache[effectBits] = this._buildShader(drawMode, effectBits); } return shader; } /** * Build the shader for a particular set of active effects. * @param {ShaderManager.DRAW_MODE} drawMode Draw normally, silhouette, etc. * @param {int} effectBits Bitmask representing the enabled effects. * @returns {ProgramInfo} The new shader's program info. * @private */ _buildShader(drawMode, effectBits) { const numEffects = ShaderManager.EFFECTS.length; const defines = ["#define DRAW_MODE_".concat(drawMode)]; for (let index = 0; index < numEffects; ++index) { if ((effectBits & 1 << index) !== 0) { defines.push("#define ENABLE_".concat(ShaderManager.EFFECTS[index])); } } const definesText = "".concat(defines.join('\n'), "\n"); /* eslint-disable global-require */ const vsFullText = definesText + __webpack_require__(/*! raw-loader!./shaders/sprite.vert */ "./node_modules/raw-loader/index.js!./node_modules/scratch-render/src/shaders/sprite.vert"); const fsFullText = definesText + __webpack_require__(/*! raw-loader!./shaders/sprite.frag */ "./node_modules/raw-loader/index.js!./node_modules/scratch-render/src/shaders/sprite.frag"); /* eslint-enable global-require */ return twgl.createProgramInfo(this._gl, [vsFullText, fsFullText]); } } /** * @typedef {object} ShaderManager.Effect * @prop {int} mask - The bit in 'effectBits' representing the effect. * @prop {function} converter - A conversion function which takes a Scratch value (generally in the range * 0..100 or -100..100) and maps it to a value useful to the shader. This * mapping may not be reversible. * @prop {boolean} shapeChanges - Whether the effect could change the drawn shape. */ /** * Mapping of each effect name to info about that effect. * @enum {ShaderManager.Effect} */ ShaderManager.EFFECT_INFO = { /** Color effect */ color: { uniformName: 'u_color', mask: 1 << 0, converter: x => x / 200 % 1, shapeChanges: false }, /** Fisheye effect */ fisheye: { uniformName: 'u_fisheye', mask: 1 << 1, converter: x => Math.max(0, (x + 100) / 100), shapeChanges: true }, /** Whirl effect */ whirl: { uniformName: 'u_whirl', mask: 1 << 2, converter: x => -x * Math.PI / 180, shapeChanges: true }, /** Pixelate effect */ pixelate: { uniformName: 'u_pixelate', mask: 1 << 3, converter: x => Math.abs(x) / 10, shapeChanges: true }, /** Mosaic effect */ mosaic: { uniformName: 'u_mosaic', mask: 1 << 4, converter: x => { x = Math.round((Math.abs(x) + 10) / 10); /** @todo cap by Math.min(srcWidth, srcHeight) */ return Math.max(1, Math.min(x, 512)); }, shapeChanges: true }, /** Brightness effect */ brightness: { uniformName: 'u_brightness', mask: 1 << 5, converter: x => Math.max(-100, Math.min(x, 100)) / 100, shapeChanges: false }, /** Ghost effect */ ghost: { uniformName: 'u_ghost', mask: 1 << 6, converter: x => 1 - Math.max(0, Math.min(x, 100)) / 100, shapeChanges: false } }; /** * The name of each supported effect. * @type {Array} */ ShaderManager.EFFECTS = Object.keys(ShaderManager.EFFECT_INFO); /** * The available draw modes. * @readonly * @enum {string} */ ShaderManager.DRAW_MODE = { /** * Draw normally. Its output will use premultiplied alpha. */ default: 'default', /** * Draw with non-premultiplied alpha. Useful for reading pixels from GL into an ImageData object. */ straightAlpha: 'straightAlpha', /** * Draw a silhouette using a solid color. */ silhouette: 'silhouette', /** * Draw only the parts of the drawable which match a particular color. */ colorMask: 'colorMask', /** * Draw a line with caps. */ line: 'line', /** * Draw the background in a certain color. Must sometimes be used instead of gl.clear. */ background: 'background' }; module.exports = ShaderManager; /***/ }), /***/ "./node_modules/scratch-render/src/Silhouette.js": /*!*******************************************************!*\ !*** ./node_modules/scratch-render/src/Silhouette.js ***! \*******************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /** * @fileoverview * A representation of a Skin's silhouette that can test if a point on the skin * renders a pixel where it is drawn. */ /** * element used to update Silhouette data from skin bitmap data. * @type {CanvasElement} */ let __SilhouetteUpdateCanvas; // Optimized Math.min and Math.max for integers; // taken from https://web.archive.org/web/20190716181049/http://guihaire.com/code/?p=549 const intMin = (i, j) => j ^ (i ^ j) & i - j >> 31; const intMax = (i, j) => i ^ (i ^ j) & i - j >> 31; /** * Internal helper function (in hopes that compiler can inline). Get a pixel * from silhouette data, or 0 if outside it's bounds. * @private * @param {Silhouette} silhouette - has data width and height * @param {number} x - x * @param {number} y - y * @return {number} Alpha value for x/y position */ const getPoint = ({ _width: width, _height: height, _colorData: data }, x, y) => { // 0 if outside bounds, otherwise read from data. if (x >= width || y >= height || x < 0 || y < 0) { return 0; } return data[(y * width + x) * 4 + 3]; }; /** * Memory buffers for doing 4 corner sampling for linear interpolation */ const __cornerWork = [new Uint8ClampedArray(4), new Uint8ClampedArray(4), new Uint8ClampedArray(4), new Uint8ClampedArray(4)]; /** * Get the color from a given silhouette at an x/y local texture position. * Multiply color values by alpha for proper blending. * @param {Silhouette} $0 The silhouette to sample. * @param {number} x X position of texture [0, width). * @param {number} y Y position of texture [0, height). * @param {Uint8ClampedArray} dst A color 4b space. * @return {Uint8ClampedArray} The dst vector. */ const getColor4b = ({ _width: width, _height: height, _colorData: data }, x, y, dst) => { // Clamp coords to edge, matching GL_CLAMP_TO_EDGE. // (See github.com/LLK/scratch-render/blob/954cfff02b08069a082cbedd415c1fecd9b1e4fb/src/BitmapSkin.js#L88) x = intMax(0, intMin(x, width - 1)); y = intMax(0, intMin(y, height - 1)); // 0 if outside bounds, otherwise read from data. if (x >= width || y >= height || x < 0 || y < 0) { return dst.fill(0); } const offset = (y * width + x) * 4; // premultiply alpha const alpha = data[offset + 3] / 255; dst[0] = data[offset] * alpha; dst[1] = data[offset + 1] * alpha; dst[2] = data[offset + 2] * alpha; dst[3] = data[offset + 3]; return dst; }; /** * Get the color from a given silhouette at an x/y local texture position. * Do not multiply color values by alpha, as it has already been done. * @param {Silhouette} $0 The silhouette to sample. * @param {number} x X position of texture [0, width). * @param {number} y Y position of texture [0, height). * @param {Uint8ClampedArray} dst A color 4b space. * @return {Uint8ClampedArray} The dst vector. */ const getPremultipliedColor4b = ({ _width: width, _height: height, _colorData: data }, x, y, dst) => { // Clamp coords to edge, matching GL_CLAMP_TO_EDGE. x = intMax(0, intMin(x, width - 1)); y = intMax(0, intMin(y, height - 1)); const offset = (y * width + x) * 4; dst[0] = data[offset]; dst[1] = data[offset + 1]; dst[2] = data[offset + 2]; dst[3] = data[offset + 3]; return dst; }; class Silhouette { constructor() { /** * The width of the data representing the current skin data. * @type {number} */ this._width = 0; /** * The height of the data representing the current skin date. * @type {number} */ this._height = 0; this._lazyData = null; /** * The data representing a skin's silhouette shape. * @type {Uint8ClampedArray} */ this._colorData = null; // By default, silhouettes are assumed not to contain premultiplied image data, // so when we get a color, we want to multiply it by its alpha channel. // Point `_getColor` to the version of the function that multiplies. this._getColor = getColor4b; this.colorAtNearest = this.colorAtLinear = (_, dst) => dst.fill(0); } /** * Update this silhouette with the bitmapData for a skin. * @param {ImageData|HTMLCanvasElement|HTMLImageElement} bitmapData An image, canvas or other element that the skin * @param {boolean} isPremultiplied True if the source bitmap data comes premultiplied (e.g. from readPixels). * rendering can be queried from. */ update(bitmapData, isPremultiplied = false) { let imageData; if (bitmapData instanceof ImageData) { // If handed ImageData directly, use it directly. imageData = bitmapData; this._width = bitmapData.width; this._height = bitmapData.height; this._lazyData = null; this._colorData = imageData.data; } else { // TW: No reason to read the image data now, there's a high chance it won't be needed and will // just waste memory and CPU time. We'll read it lazily, only when necessary. this._width = bitmapData.width; this._height = bitmapData.height; if (!(this._width && this._height)) { // TW: It might seem really weird to return here before updating anything else, but this is what // LLK/scratch-render does. return; } this._lazyData = bitmapData; this._colorData = null; } if (isPremultiplied) { this._getColor = getPremultipliedColor4b; } else { this._getColor = getColor4b; } // delete our custom overriden "uninitalized" color functions // let the prototype work for itself delete this.colorAtNearest; delete this.colorAtLinear; } unlazy() { if (!this._lazyData) { return; } const width = this._lazyData.width; const height = this._lazyData.height; if (width && height) { const canvas = Silhouette._updateCanvas(); canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, width, height); ctx.drawImage(this._lazyData, 0, 0, width, height); const textureData = ctx.getImageData(0, 0, width, height); this._colorData = textureData.data; } this._lazyData = null; } /** * Sample a color from the silhouette at a given local position using * "nearest neighbor" * @param {twgl.v3} vec [x,y] texture space (0-1) * @param {Uint8ClampedArray} dst The memory buffer to store the value in. (4 bytes) * @returns {Uint8ClampedArray} dst */ colorAtNearest(vec, dst) { return this._getColor(this, Math.floor(vec[0] * (this._width - 1)), Math.floor(vec[1] * (this._height - 1)), dst); } /** * Sample a color from the silhouette at a given local position using * "linear interpolation" * @param {twgl.v3} vec [x,y] texture space (0-1) * @param {Uint8ClampedArray} dst The memory buffer to store the value in. (4 bytes) * @returns {Uint8ClampedArray} dst */ colorAtLinear(vec, dst) { const x = vec[0] * (this._width - 1); const y = vec[1] * (this._height - 1); const x1D = x % 1; const y1D = y % 1; const x0D = 1 - x1D; const y0D = 1 - y1D; const xFloor = Math.floor(x); const yFloor = Math.floor(y); const x0y0 = this._getColor(this, xFloor, yFloor, __cornerWork[0]); const x1y0 = this._getColor(this, xFloor + 1, yFloor, __cornerWork[1]); const x0y1 = this._getColor(this, xFloor, yFloor + 1, __cornerWork[2]); const x1y1 = this._getColor(this, xFloor + 1, yFloor + 1, __cornerWork[3]); dst[0] = x0y0[0] * x0D * y0D + x0y1[0] * x0D * y1D + x1y0[0] * x1D * y0D + x1y1[0] * x1D * y1D; dst[1] = x0y0[1] * x0D * y0D + x0y1[1] * x0D * y1D + x1y0[1] * x1D * y0D + x1y1[1] * x1D * y1D; dst[2] = x0y0[2] * x0D * y0D + x0y1[2] * x0D * y1D + x1y0[2] * x1D * y0D + x1y1[2] * x1D * y1D; dst[3] = x0y0[3] * x0D * y0D + x0y1[3] * x0D * y1D + x1y0[3] * x1D * y0D + x1y1[3] * x1D * y1D; return dst; } /** * Test if texture coordinate touches the silhouette using nearest neighbor. * @param {twgl.v3} vec A texture coordinate. * @return {boolean} If the nearest pixel has an alpha value. */ isTouchingNearest(vec) { if (!this._colorData) return; return getPoint(this, Math.floor(vec[0] * (this._width - 1)), Math.floor(vec[1] * (this._height - 1))) > 0; } /** * Test to see if any of the 4 pixels used in the linear interpolate touch * the silhouette. * @param {twgl.v3} vec A texture coordinate. * @return {boolean} Any of the pixels have some alpha. */ isTouchingLinear(vec) { if (!this._colorData) return; const x = Math.floor(vec[0] * (this._width - 1)); const y = Math.floor(vec[1] * (this._height - 1)); return getPoint(this, x, y) > 0 || getPoint(this, x + 1, y) > 0 || getPoint(this, x, y + 1) > 0 || getPoint(this, x + 1, y + 1) > 0; } /** * Get the canvas element reused by Silhouettes to update their data with. * @private * @return {CanvasElement} A canvas to draw bitmap data to. */ static _updateCanvas() { if (typeof __SilhouetteUpdateCanvas === 'undefined') { __SilhouetteUpdateCanvas = document.createElement('canvas'); } return __SilhouetteUpdateCanvas; } } module.exports = Silhouette; /***/ }), /***/ "./node_modules/scratch-render/src/Skin.js": /*!*************************************************!*\ !*** ./node_modules/scratch-render/src/Skin.js ***! \*************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const twgl = __webpack_require__(/*! twgl.js */ "./node_modules/twgl.js/dist/4.x/twgl-full.js"); const RenderConstants = __webpack_require__(/*! ./RenderConstants */ "./node_modules/scratch-render/src/RenderConstants.js"); const Silhouette = __webpack_require__(/*! ./Silhouette */ "./node_modules/scratch-render/src/Silhouette.js"); class Skin { /** * Create a Skin, which stores and/or generates textures for use in rendering. * @param {int} id - The unique ID for this Skin. * @param {RenderWebGL} renderer - The renderer which will use this skin. * @constructor */ constructor(id, renderer) { /** @type {RenderWebGL} */ this._renderer = renderer; /** @type {int} */ this._id = id; /** @type {Vec3} */ this._rotationCenter = twgl.v3.create(0, 0); /** @type {WebGLTexture} */ this._texture = null; /** * The uniforms to be used by the vertex and pixel shaders. * Some of these are used by other parts of the renderer as well. * @type {Object.} * @private */ this._uniforms = { /** * The nominal (not necessarily current) size of the current skin. * @type {Array} */ u_skinSize: [0, 0], /** * The actual WebGL texture object for the skin. * @type {WebGLTexture} */ u_skin: null }; /** * A silhouette to store touching data, skins are responsible for keeping it up to date. * @protected */ this._silhouette = new Silhouette(); /** * Whether this skin might include private information about the user. */ this.private = false; } /** * Dispose of this object. Do not use it after calling this method. */ dispose() { this._id = RenderConstants.ID_NONE; } /** * @return {int} the unique ID for this Skin. */ get id() { return this._id; } /** * @returns {Vec3} the origin, in object space, about which this Skin should rotate. */ get rotationCenter() { return this._rotationCenter; } /** * @abstract * @return {Array} the "native" size, in texels, of this skin. */ get size() { return [0, 0]; } /** * Should this skin's texture be filtered with nearest-neighbor or linear interpolation at the given scale? * @param {?Array} scale The screen-space X and Y scaling factors at which this skin's texture will be * displayed, as percentages (100 means 1 "native size" unit is 1 screen pixel; 200 means 2 screen pixels, etc). * @param {Drawable} drawable The drawable that this skin's texture will be applied to. * @return {boolean} True if this skin's texture, as returned by {@link getTexture}, should be filtered with * nearest-neighbor interpolation. */ // eslint-disable-next-line no-unused-vars useNearest(scale, drawable) { return true; } /** * Get the center of the current bounding box * @return {Array} the center of the current bounding box */ calculateRotationCenter() { return [this.size[0] / 2, this.size[1] / 2]; } /** * @abstract * @param {Array} scale - The scaling factors to be used. * @return {WebGLTexture} The GL texture representation of this skin when drawing at the given size. */ // eslint-disable-next-line no-unused-vars getTexture(scale) { return this._emptyImageTexture; } /** * Get the bounds of the drawable for determining its fenced position. * @param {Array} drawable - The Drawable instance this skin is using. * @param {?Rectangle} result - Optional destination for bounds calculation. * @return {!Rectangle} The drawable's bounds. For compatibility with Scratch 2, we always use getAABB. */ getFenceBounds(drawable, result) { return drawable.getAABB(result); } /** * Update and returns the uniforms for this skin. * @param {Array} scale - The scaling factors to be used. * @returns {object.} the shader uniforms to be used when rendering with this Skin. */ getUniforms(scale) { this._uniforms.u_skin = this.getTexture(scale); this._uniforms.u_skinSize = this.size; return this._uniforms; } emitWasAltered() { this._renderer.skinWasAltered(this); } /** * If the skin defers silhouette operations until the last possible minute, * this will be called before isTouching uses the silhouette. */ updateSilhouette() { this._silhouette.unlazy(); } /** * Set this skin's texture to the given image. * @param {ImageData|HTMLCanvasElement} textureData - The canvas or image data to set the texture to. */ _setTexture(textureData) { const gl = this._renderer.gl; gl.bindTexture(gl.TEXTURE_2D, this._texture); // Premultiplied alpha is necessary for proper blending. // See http://www.realtimerendering.com/blog/gpus-prefer-premultiplication/ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureData); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); this._silhouette.update(textureData); } /** * Set the contents of this skin to an empty skin. * @fires Skin.event:WasAltered */ setEmptyImageData() { // Free up the current reference to the _texture this._texture = null; if (!this._emptyImageData) { // Create a transparent pixel this._emptyImageData = new ImageData(1, 1); // Create a new texture and update the silhouette const gl = this._renderer.gl; const textureOptions = { auto: true, wrap: gl.CLAMP_TO_EDGE, src: this._emptyImageData }; // Note: we're using _emptyImageTexture here instead of _texture // so that we can cache this empty texture for later use as needed. // this._texture can get modified by other skins (e.g. BitmapSkin // and SVGSkin, so we can't use that same field for caching) this._emptyImageTexture = twgl.createTexture(gl, textureOptions); } this._rotationCenter[0] = 0; this._rotationCenter[1] = 0; this._silhouette.update(this._emptyImageData); this.emitWasAltered(); } /** * Does this point touch an opaque or translucent point on this skin? * Nearest Neighbor version * The caller is responsible for ensuring this skin's silhouette is up-to-date. * @see updateSilhouette * @see Drawable.updateCPURenderAttributes * @param {twgl.v3} vec A texture coordinate. * @return {boolean} Did it touch? */ isTouchingNearest(vec) { return this._silhouette.isTouchingNearest(vec); } /** * Does this point touch an opaque or translucent point on this skin? * Linear Interpolation version * The caller is responsible for ensuring this skin's silhouette is up-to-date. * @see updateSilhouette * @see Drawable.updateCPURenderAttributes * @param {twgl.v3} vec A texture coordinate. * @return {boolean} Did it touch? */ isTouchingLinear(vec) { return this._silhouette.isTouchingLinear(vec); } } module.exports = Skin; /***/ }), /***/ "./node_modules/scratch-render/src/TextBubbleSkin.js": /*!***********************************************************!*\ !*** ./node_modules/scratch-render/src/TextBubbleSkin.js ***! \***********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const twgl = __webpack_require__(/*! twgl.js */ "./node_modules/twgl.js/dist/4.x/twgl-full.js"); const CanvasMeasurementProvider = __webpack_require__(/*! ./util/canvas-measurement-provider */ "./node_modules/scratch-render/src/util/canvas-measurement-provider.js"); const Skin = __webpack_require__(/*! ./Skin */ "./node_modules/scratch-render/src/Skin.js"); let _TextWrapper; const getTextWrapper = () => { if (!_TextWrapper) { // eslint-disable-next-line global-require _TextWrapper = __webpack_require__(/*! ./util/text-wrapper */ "./node_modules/scratch-render/src/util/text-wrapper.js"); } return _TextWrapper; }; const BubbleStyle = { MAX_LINE_WIDTH: 170, // Maximum width, in Scratch pixels, of a single line of text MIN_WIDTH: 50, // Minimum width, in Scratch pixels, of a text bubble STROKE_WIDTH: 4, // Thickness of the stroke around the bubble. Only half's visible because it's drawn under the fill PADDING: 10, // Padding around the text area CORNER_RADIUS: 16, // Radius of the rounded corners TAIL_HEIGHT: 12, // Height of the speech bubble's "tail". Probably should be a constant. FONT: 'Helvetica', // Font to render the text with FONT_SIZE: 14, // Font size, in Scratch pixels FONT_HEIGHT_RATIO: 0.9, // Height, in Scratch pixels, of the text, as a proportion of the font's size LINE_HEIGHT: 16, // Spacing between each line of text COLORS: { BUBBLE_FILL: 'white', BUBBLE_STROKE: 'rgba(0, 0, 0, 0.15)', TEXT_FILL: '#575E75' } }; const MAX_SCALE = 10; class TextBubbleSkin extends Skin { /** * Create a new text bubble skin. * @param {!int} id - The ID for this Skin. * @param {!RenderWebGL} renderer - The renderer which will use this skin. * @constructor * @extends Skin */ constructor(id, renderer) { super(id, renderer); /** @type {HTMLCanvasElement} */ this._canvas = document.createElement('canvas'); /** @type {Array} */ this._size = [0, 0]; /** @type {number} */ this._renderedScale = 0; /** @type {Array} */ this._lines = []; /** @type {object} */ this._textAreaSize = { width: 0, height: 0 }; /** @type {string} */ this._bubbleType = ''; /** @type {boolean} */ this._pointsLeft = false; /** @type {boolean} */ this._textDirty = true; /** @type {boolean} */ this._textureDirty = true; this.measurementProvider = new CanvasMeasurementProvider(this._canvas.getContext('2d')); this.textWrapper = new (getTextWrapper())(this.measurementProvider); this._restyleCanvas(); } /** * Dispose of this object. Do not use it after calling this method. */ dispose() { if (this._texture) { this._renderer.gl.deleteTexture(this._texture); this._texture = null; } this._canvas = null; super.dispose(); } /** * @return {Array} the dimensions, in Scratch units, of this skin. */ get size() { if (this._textDirty) { this._reflowLines(); } return this._size; } /** * Set parameters for this text bubble. * @param {!string} type - either "say" or "think". * @param {!string} text - the text for the bubble. * @param {!boolean} pointsLeft - which side the bubble is pointing. */ setTextBubble(type, text, pointsLeft) { this._text = text; this._bubbleType = type; this._pointsLeft = pointsLeft; this._textDirty = true; this._textureDirty = true; this.emitWasAltered(); } /** * Re-style the canvas after resizing it. This is necessary to ensure proper text measurement. */ _restyleCanvas() { this._canvas.getContext('2d').font = "".concat(BubbleStyle.FONT_SIZE, "px ").concat(BubbleStyle.FONT, ", sans-serif"); } /** * Update the array of wrapped lines and the text dimensions. */ _reflowLines() { this._lines = this.textWrapper.wrapText(BubbleStyle.MAX_LINE_WIDTH, this._text); // Measure width of longest line to avoid extra-wide bubbles let longestLineWidth = 0; for (const line of this._lines) { longestLineWidth = Math.max(longestLineWidth, this.measurementProvider.measureText(line)); } // Calculate the canvas-space sizes of the padded text area and full text bubble const paddedWidth = Math.max(longestLineWidth, BubbleStyle.MIN_WIDTH) + BubbleStyle.PADDING * 2; const paddedHeight = BubbleStyle.LINE_HEIGHT * this._lines.length + BubbleStyle.PADDING * 2; this._textAreaSize.width = paddedWidth; this._textAreaSize.height = paddedHeight; this._size[0] = paddedWidth + BubbleStyle.STROKE_WIDTH; this._size[1] = paddedHeight + BubbleStyle.STROKE_WIDTH + BubbleStyle.TAIL_HEIGHT; this._textDirty = false; } /** * Render this text bubble at a certain scale, using the current parameters, to the canvas. * @param {number} scale The scale to render the bubble at */ _renderTextBubble(scale) { const ctx = this._canvas.getContext('2d'); if (this._textDirty) { this._reflowLines(); } // Calculate the canvas-space sizes of the padded text area and full text bubble const paddedWidth = this._textAreaSize.width; const paddedHeight = this._textAreaSize.height; // Resize the canvas to the correct screen-space size this._canvas.width = Math.ceil(this._size[0] * scale); this._canvas.height = Math.ceil(this._size[1] * scale); this._restyleCanvas(); // Reset the transform before clearing to ensure 100% clearage ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.clearRect(0, 0, this._canvas.width, this._canvas.height); ctx.scale(scale, scale); ctx.translate(BubbleStyle.STROKE_WIDTH * 0.5, BubbleStyle.STROKE_WIDTH * 0.5); // If the text bubble points leftward, flip the canvas ctx.save(); if (this._pointsLeft) { ctx.scale(-1, 1); ctx.translate(-paddedWidth, 0); } // Draw the bubble's rounded borders ctx.beginPath(); ctx.moveTo(BubbleStyle.CORNER_RADIUS, paddedHeight); ctx.arcTo(0, paddedHeight, 0, paddedHeight - BubbleStyle.CORNER_RADIUS, BubbleStyle.CORNER_RADIUS); ctx.arcTo(0, 0, paddedWidth, 0, BubbleStyle.CORNER_RADIUS); ctx.arcTo(paddedWidth, 0, paddedWidth, paddedHeight, BubbleStyle.CORNER_RADIUS); ctx.arcTo(paddedWidth, paddedHeight, paddedWidth - BubbleStyle.CORNER_RADIUS, paddedHeight, BubbleStyle.CORNER_RADIUS); // Translate the canvas so we don't have to do a bunch of width/height arithmetic ctx.save(); ctx.translate(paddedWidth - BubbleStyle.CORNER_RADIUS, paddedHeight); // Draw the bubble's "tail" if (this._bubbleType === 'say') { // For a speech bubble, draw one swoopy thing ctx.bezierCurveTo(0, 4, 4, 8, 4, 10); ctx.arcTo(4, 12, 2, 12, 2); ctx.bezierCurveTo(-1, 12, -11, 8, -16, 0); ctx.closePath(); } else { // For a thinking bubble, draw a partial circle attached to the bubble... ctx.arc(-16, 0, 4, 0, Math.PI); ctx.closePath(); // and two circles detached from it ctx.moveTo(-7, 7.25); ctx.arc(-9.25, 7.25, 2.25, 0, Math.PI * 2); ctx.moveTo(0, 9.5); ctx.arc(-1.5, 9.5, 1.5, 0, Math.PI * 2); } // Un-translate the canvas and fill + stroke the text bubble ctx.restore(); ctx.fillStyle = BubbleStyle.COLORS.BUBBLE_FILL; ctx.strokeStyle = BubbleStyle.COLORS.BUBBLE_STROKE; ctx.lineWidth = BubbleStyle.STROKE_WIDTH; ctx.stroke(); ctx.fill(); // Un-flip the canvas if it was flipped ctx.restore(); // Draw each line of text ctx.fillStyle = BubbleStyle.COLORS.TEXT_FILL; ctx.font = "".concat(BubbleStyle.FONT_SIZE, "px ").concat(BubbleStyle.FONT, ", sans-serif"); const lines = this._lines; for (let lineNumber = 0; lineNumber < lines.length; lineNumber++) { const line = lines[lineNumber]; ctx.fillText(line, BubbleStyle.PADDING, BubbleStyle.PADDING + BubbleStyle.LINE_HEIGHT * lineNumber + BubbleStyle.FONT_HEIGHT_RATIO * BubbleStyle.FONT_SIZE); } this._renderedScale = scale; } updateSilhouette(scale = [100, 100]) { // Ensure a silhouette exists. this.getTexture(scale); } /** * @param {Array} scale - The scaling factors to be used, each in the [0,100] range. * @return {WebGLTexture} The GL texture representation of this skin when drawing at the given scale. */ getTexture(scale) { // The texture only ever gets uniform scale. Take the larger of the two axes. const scaleMax = scale ? Math.max(Math.abs(scale[0]), Math.abs(scale[1])) : 100; const requestedScale = Math.min(MAX_SCALE, scaleMax / 100); // If we already rendered the text bubble at this scale, we can skip re-rendering it. if (this._textureDirty || this._renderedScale !== requestedScale) { this._renderTextBubble(requestedScale); this._textureDirty = false; const context = this._canvas.getContext('2d'); const textureData = context.getImageData(0, 0, this._canvas.width, this._canvas.height); const gl = this._renderer.gl; if (this._texture === null) { const textureOptions = { auto: false, wrap: gl.CLAMP_TO_EDGE }; this._texture = twgl.createTexture(gl, textureOptions); } this._setTexture(textureData); } return this._texture; } } module.exports = TextBubbleSkin; /***/ }), /***/ "./node_modules/scratch-render/src/index.js": /*!**************************************************!*\ !*** ./node_modules/scratch-render/src/index.js ***! \**************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const RenderWebGL = __webpack_require__(/*! ./RenderWebGL */ "./node_modules/scratch-render/src/RenderWebGL.js"); /** * Export for NPM & Node.js * @type {RenderWebGL} */ module.exports = RenderWebGL; /***/ }), /***/ "./node_modules/scratch-render/src/util/canvas-measurement-provider.js": /*!*****************************************************************************!*\ !*** ./node_modules/scratch-render/src/util/canvas-measurement-provider.js ***! \*****************************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { class CanvasMeasurementProvider { /** * @param {CanvasRenderingContext2D} ctx - provides a canvas rendering context * with 'font' set to the text style of the text to be wrapped. */ constructor(ctx) { this._ctx = ctx; this._cache = {}; } // We don't need to set up or tear down anything here. Should these be removed altogether? /** * Called by the TextWrapper before a batch of zero or more calls to measureText(). */ beginMeasurementSession() {} /** * Called by the TextWrapper after a batch of zero or more calls to measureText(). */ endMeasurementSession() {} /** * Measure a whole string as one unit. * @param {string} text - the text to measure. * @returns {number} - the length of the string. */ measureText(text) { if (!this._cache[text]) { this._cache[text] = this._ctx.measureText(text).width; } return this._cache[text]; } } module.exports = CanvasMeasurementProvider; /***/ }), /***/ "./node_modules/scratch-render/src/util/color-conversions.js": /*!*******************************************************************!*\ !*** ./node_modules/scratch-render/src/util/color-conversions.js ***! \*******************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /** * Converts an RGB color value to HSV. Conversion formula * adapted from http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv. * Assumes r, g, and b are in the range [0, 255] and * returns h, s, and v in the range [0, 1]. * * @param {Array} rgb The RGB color value * @param {number} rgb.r The red color value * @param {number} rgb.g The green color value * @param {number} rgb.b The blue color value * @param {Array} dst The array to store the HSV values in * @return {Array} The `dst` array passed in */ const rgbToHsv = ([r, g, b], dst) => { let K = 0.0; r /= 255; g /= 255; b /= 255; let tmp = 0; if (g < b) { tmp = g; g = b; b = tmp; K = -1; } if (r < g) { tmp = r; r = g; g = tmp; K = -2 / 6 - K; } const chroma = r - Math.min(g, b); const h = Math.abs(K + (g - b) / (6 * chroma + Number.EPSILON)); const s = chroma / (r + Number.EPSILON); const v = r; dst[0] = h; dst[1] = s; dst[2] = v; return dst; }; /** * Converts an HSV color value to RGB. Conversion formula * adapted from https://gist.github.com/mjackson/5311256. * Assumes h, s, and v are contained in the set [0, 1] and * returns r, g, and b in the set [0, 255]. * * @param {Array} hsv The HSV color value * @param {number} hsv.h The hue * @param {number} hsv.s The saturation * @param {number} hsv.v The value * @param {Uint8Array|Uint8ClampedArray} dst The array to store the RGB values in * @return {Uint8Array|Uint8ClampedArray} The `dst` array passed in */ const hsvToRgb = ([h, s, v], dst) => { if (s === 0) { dst[0] = dst[1] = dst[2] = v * 255 + 0.5; return dst; } // keep hue in [0,1) so the `switch(i)` below only needs 6 cases (0-5) h %= 1; const i = h * 6 | 0; const f = h * 6 - i; const p = v * (1 - s); const q = v * (1 - s * f); const t = v * (1 - s * (1 - f)); let r = 0; let g = 0; let b = 0; switch (i) { case 0: r = v; g = t; b = p; break; case 1: r = q; g = v; b = p; break; case 2: r = p; g = v; b = t; break; case 3: r = p; g = q; b = v; break; case 4: r = t; g = p; b = v; break; case 5: r = v; g = p; b = q; break; } // Add 0.5 in order to round. Setting integer TypedArray elements implicitly floors. dst[0] = r * 255 + 0.5; dst[1] = g * 255 + 0.5; dst[2] = b * 255 + 0.5; return dst; }; module.exports = { rgbToHsv, hsvToRgb }; /***/ }), /***/ "./node_modules/scratch-render/src/util/log.js": /*!*****************************************************!*\ !*** ./node_modules/scratch-render/src/util/log.js ***! \*****************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const minilog = __webpack_require__(/*! minilog */ "./node_modules/minilog/lib/web/index.js"); minilog.enable(); module.exports = minilog('scratch-render'); /***/ }), /***/ "./node_modules/scratch-render/src/util/text-wrapper.js": /*!**************************************************************!*\ !*** ./node_modules/scratch-render/src/util/text-wrapper.js ***! \**************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const LineBreaker = __webpack_require__(/*! ify-loader!linebreak */ "./node_modules/ify-loader/index.js!./node_modules/linebreak/src/linebreaker.js"); const GraphemeBreaker = __webpack_require__(/*! ify-loader!grapheme-breaker */ "./node_modules/ify-loader/index.js!./node_modules/grapheme-breaker/src/GraphemeBreaker.js"); /** * Tell this text wrapper to use a specific measurement provider. * @typedef {object} MeasurementProvider - the new measurement provider. * @property {Function} beginMeasurementSession - this will be called before a batch of measurements are made. * Optionally, this function may return an object to be provided to the endMeasurementSession function. * @property {Function} measureText - this will be called each time a piece of text must be measured. * @property {Function} endMeasurementSession - this will be called after a batch of measurements is finished. * It will be passed whatever value beginMeasurementSession returned, if any. */ /** * Utility to wrap text across several lines, respecting Unicode grapheme clusters and, when possible, Unicode line * break opportunities. * Reference material: * - Unicode Standard Annex #14: http://unicode.org/reports/tr14/ * - Unicode Standard Annex #29: http://unicode.org/reports/tr29/ * - "JavaScript has a Unicode problem" by Mathias Bynens: https://mathiasbynens.be/notes/javascript-unicode */ class TextWrapper { /** * Construct a text wrapper which will measure text using the specified measurement provider. * @param {MeasurementProvider} measurementProvider - a helper object to provide text measurement services. */ constructor(measurementProvider) { this._measurementProvider = measurementProvider; this._cache = {}; } /** * Wrap the provided text into lines restricted to a maximum width. See Unicode Standard Annex (UAX) #14. * @param {number} maxWidth - the maximum allowed width of a line. * @param {string} text - the text to be wrapped. Will be split on whitespace. * @returns {Array.} an array containing the wrapped lines of text. */ wrapText(maxWidth, text) { // Normalize to canonical composition (see Unicode Standard Annex (UAX) #15) text = text.normalize(); const cacheKey = "".concat(maxWidth, "-").concat(text); if (this._cache[cacheKey]) { return this._cache[cacheKey]; } const measurementSession = this._measurementProvider.beginMeasurementSession(); const breaker = new LineBreaker(text); let lastPosition = 0; let nextBreak; let currentLine = null; const lines = []; while (nextBreak = breaker.nextBreak()) { const word = text.slice(lastPosition, nextBreak.position).replace(/\n+$/, ''); let proposedLine = (currentLine || '').concat(word); let proposedLineWidth = this._measurementProvider.measureText(proposedLine); if (proposedLineWidth > maxWidth) { // The next word won't fit on this line. Will it fit on a line by itself? const wordWidth = this._measurementProvider.measureText(word); if (wordWidth > maxWidth) { // The next word can't even fit on a line by itself. Consume it one grapheme cluster at a time. let lastCluster = 0; let nextCluster; while (lastCluster !== (nextCluster = GraphemeBreaker.nextBreak(word, lastCluster))) { const cluster = word.substring(lastCluster, nextCluster); proposedLine = (currentLine || '').concat(cluster); proposedLineWidth = this._measurementProvider.measureText(proposedLine); if (currentLine === null || proposedLineWidth <= maxWidth) { // first cluster of a new line or the cluster fits currentLine = proposedLine; } else { // no more can fit lines.push(currentLine); currentLine = cluster; } lastCluster = nextCluster; } } else { // The next word can fit on the next line. Finish the current line and move on. if (currentLine !== null) lines.push(currentLine); currentLine = word; } } else { // The next word fits on this line. Just keep going. currentLine = proposedLine; } // Did we find a \n or similar? if (nextBreak.required) { if (currentLine !== null) lines.push(currentLine); currentLine = null; } lastPosition = nextBreak.position; } currentLine = currentLine || ''; if (currentLine.length > 0 || lines.length === 0) { lines.push(currentLine); } this._cache[cacheKey] = lines; this._measurementProvider.endMeasurementSession(measurementSession); return lines; } } module.exports = TextWrapper; /***/ }), /***/ "./node_modules/scratch-sb1-converter/index.js": /*!*****************************************************!*\ !*** ./node_modules/scratch-sb1-converter/index.js ***! \*****************************************************/ /*! exports provided: SB1File, AssertionError, ValidationError */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony import */ var _src_sb1_file__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./src/sb1-file */ "./node_modules/scratch-sb1-converter/src/sb1-file.js"); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "SB1File", function() { return _src_sb1_file__WEBPACK_IMPORTED_MODULE_0__["SB1File"]; }); /* harmony import */ var _src_util_assert__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./src/util/assert */ "./node_modules/scratch-sb1-converter/src/util/assert.js"); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "AssertionError", function() { return _src_util_assert__WEBPACK_IMPORTED_MODULE_1__["AssertionError"]; }); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ValidationError", function() { return _src_util_assert__WEBPACK_IMPORTED_MODULE_1__["ValidationError"]; }); /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/coders/adler32.js": /*!******************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/coders/adler32.js ***! \******************************************************************/ /*! exports provided: Adler32 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Adler32", function() { return Adler32; }); class Adler32 { constructor() { this.adler = 1; } update(uint8a, position, length) { let a = this.adler & 0xffff; let b = this.adler >>> 16; for (let i = 0; i < length; i++) { a = (a + uint8a[position + i]) % 65521; b = (b + a) % 65521; } this.adler = b << 16 | a; return this; } get digest() { return this.adler; } } /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/coders/byte-packets.js": /*!***********************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/coders/byte-packets.js ***! \***********************************************************************/ /*! exports provided: Packet */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Packet", function() { return Packet; }); /** * @typedef {function} PacketConstructor */ /** * A packet of bytes represented with getter/setter properties for decoding and * encoding values mapped to names, located at known offsets. * * ```js * // Defining a subclass: * import {Packet} from '../coders/byte-packets'; * import {Uint8, Uint16LE} from '../coders/byte-primitives'; * * class MyIdentifiedUint16 extends Packet.extend({ * binaryType: Uint8, * value: Uint16LE * }) {} * * Packet.initConstructor(MyIdentifiedUint16); * * // One way to use it: * const indentifiedUint16 = new MyIdentifiedUint16(uint8a, position); * indentifiedUint16.binaryType = IDENTIFIED_UINT_16; * indentifiedUint16.value = value; * ``` */ class Packet { /** * @param {Uint8Array=} [uint8a=new Uint8Array(this.size)] - byte array to * encode to and decode from * @param {number=} offset - offset in addition to the member offsets to * encode to and decode from */ constructor(uint8a = new Uint8Array(this.size), offset = 0) { /** * Byte array to encode to and decode from. * @type {Uint8Array} */ this.uint8a = uint8a; /** * Offset in addition to the member offsets to encode to and decode * from. * @type {number} */ this.offset = offset; } /** * Check that the decoded values of this Packet match the values in other. * @param {object} other - object to match against * @returns {boolean} true if all keys in other match values in this packet */ equals(other) { for (const key in other) { if (this[key] !== other[key]) { return false; } } return true; } view() { const className = this.constructor.name; const obj = { toString() { return className; } }; for (const key in this.shape) { obj[key] = this[key]; } return obj; } /** * Initialize the Packet subclass constructor for easy access to static * members like size. * @param {function} PacketConstructor - constuctor function for the Packet * subclass * @returns {function} initialized constructor */ static initConstructor(PacketConstructor) { PacketConstructor.size = PacketConstructor.prototype.size; return PacketConstructor; } /** * Extend a subclass of Packet with given BytePrimitive members. * @param {object} shape - shape of the packet defined with BytePrimitives * @returns {function} Packet subclass constructor */ static extend(shape) { const DefinedPacket = class extends Packet { get shape() { return shape; } }; let position = 0; Object.keys(shape).forEach(key => { Object.defineProperty(DefinedPacket.prototype, key, shape[key].asPropertyObject(position)); if (shape[key].size === 0) { throw new Error('Packet cannot be defined with variable sized members.'); } position += shape[key].size; }); DefinedPacket.prototype.size = position; DefinedPacket.size = position; return DefinedPacket; } } /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/coders/byte-primitives.js": /*!**************************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/coders/byte-primitives.js ***! \**************************************************************************/ /*! exports provided: IS_HOST_LITTLE_ENDIAN, BytePrimitive, Uint8, Uint16BE, Int16BE, Int32BE, Uint32BE, Uint16LE, Uint32LE, DoubleBE, FixedAsciiString */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "IS_HOST_LITTLE_ENDIAN", function() { return IS_HOST_LITTLE_ENDIAN; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BytePrimitive", function() { return BytePrimitive; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint8", function() { return Uint8; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint16BE", function() { return Uint16BE; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int16BE", function() { return Int16BE; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int32BE", function() { return Int32BE; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint32BE", function() { return Uint32BE; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint16LE", function() { return Uint16LE; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint32LE", function() { return Uint32LE; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DoubleBE", function() { return DoubleBE; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FixedAsciiString", function() { return FixedAsciiString; }); /* harmony import */ var _util_assert__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../util/assert */ "./node_modules/scratch-sb1-converter/src/util/assert.js"); const notImplemented = () => { throw new Error('Not implemented'); }; /** * Is the host computer little or big endian. * @const IS_HOST_LITTLE_ENDIAN * @type {boolean} */ const IS_HOST_LITTLE_ENDIAN = (() => { const ab16 = new Uint16Array(1); const ab8 = new Uint8Array(ab16.buffer); ab16[0] = 0xaabb; return ab8[0] === 0xbb; })(); /** * @callback BytePrimitive~sizeOfCallback * @param {Uint8Array} uint8a * @param {number} position * @returns {number} */ /** * @callback BytePrimitive~writeSizeOfCallback * @param {Uint8Array} uint8a * @param {number} position * @param {*} value * @returns {number} */ /** * @callback BytePrimitive~writeCallback * @param {Uint8Array} uint8a * @param {number} position * @param {*} value */ /** * An interface for reading and writing binary values to typed arrays. * * Combined with {@link Packet Packet} this makes reading and writing packets * of binary values easy. */ class BytePrimitive { /** * @constructor * @param {object} options - Options to initialize BytePrimitive instance * with. * @param {number} [options.size=0] - Fixed size of the BytePrimitive. * Should be 0 if the primitive has a variable size. * @param {BytePrimitive~sizeOfCallback} [options.sizeOf=() => size] - * Variable size of the primitive depending on its value stored in the * array. * @param {BytePrimitive~writeSizeOfCallback} [options.writeSizeOf] - * Variable size of the primitive depending on the value being written. * @param {TypedArray} [options.toBytes=new Uint8Array(1)] - Temporary * space to copy bytes to/from to translate between a value and its * representative byte set. * @param {BytePrimitive#read} options.read - How is a value read * at the given position of the array. * @param {BytePrimitive~writeCallback} [options.write] - How to write a * value to the array at the given position. */ constructor({ size = 0, sizeOf = () => size, writeSizeOf = notImplemented, toBytes = new Uint8Array(1), read, write = notImplemented }) { this.size = size; this.sizeOf = sizeOf; this.writeSizeOf = writeSizeOf; this.toBytes = toBytes; this.bytes = new Uint8Array(toBytes.buffer); this.read = read; this.write = write; } /** * Create an object that can be used with `Object.defineProperty` to read * and write values offset by `position` and the object's `this.offset` * from `this.uint8a` by getting or setting the property. * @param {number} position - Additional offset with `this.offset` to read * from or write to. * @returns {object} - A object that can be passed as the third argument to * `Object.defineProperty`. */ asPropertyObject(position) { const _this = this; return { get() { return _this.read(this.uint8a, position + this.offset); }, set(value) { return _this.write(this.uint8a, position + this.offset, value); }, enumerable: true }; } /** * Read a value from `position` in `uint8a`. * @param {Uint8Array} uint8a - Array to read from. * @param {number} position - Position in `uint8a` to read from. * @returns {*} - Value read from `uint8a` at `position`. */ read() { return null; } } /** * @const Uint8 * @type {BytePrimitive} */ const Uint8 = new BytePrimitive({ size: 1, read(uint8a, position) { return uint8a[position]; }, write(uint8a, position, value) { uint8a[position] = value; return value; } }); const HOSTLE_BE16 = { size: 2, // toBytes: Defined by instance. read(uint8a, position) { this.bytes[1] = uint8a[position + 0]; this.bytes[0] = uint8a[position + 1]; return this.toBytes[0]; }, write(uint8a, position, value) { this.toBytes[0] = value; uint8a[position + 0] = this.bytes[1]; uint8a[position + 1] = this.bytes[0]; return value; } }; const HOSTBE_BE16 = { size: 2, // toBytes: Defined by instance. read(uint8a, position) { this.bytes[0] = uint8a[position + 0]; this.bytes[1] = uint8a[position + 1]; return this.toBytes[0]; }, write(uint8a, position, value) { this.toBytes[0] = value; uint8a[position + 0] = this.bytes[0]; uint8a[position + 1] = this.bytes[1]; return value; } }; let BE16; if (IS_HOST_LITTLE_ENDIAN) { BE16 = HOSTLE_BE16; } else { BE16 = HOSTBE_BE16; } /** * @const Uint16BE * @type {BytePrimitive} */ const Uint16BE = new BytePrimitive(Object.assign({}, BE16, { toBytes: new Uint16Array(1) })); /** * @const Int16BE * @type {BytePrimitive} */ const Int16BE = new BytePrimitive(Object.assign({}, BE16, { toBytes: new Int16Array(1) })); const HOSTLE_BE32 = { size: 4, // toBytes: Defined by instance. read(uint8a, position) { this.bytes[3] = uint8a[position + 0]; this.bytes[2] = uint8a[position + 1]; this.bytes[1] = uint8a[position + 2]; this.bytes[0] = uint8a[position + 3]; return this.toBytes[0]; }, write(uint8a, position, value) { this.toBytes[0] = value; uint8a[position + 0] = this.bytes[3]; uint8a[position + 1] = this.bytes[2]; uint8a[position + 2] = this.bytes[1]; uint8a[position + 3] = this.bytes[0]; return value; } }; const HOSTBE_BE32 = { size: 4, // toBytes: Defined by instance. read(uint8a, position) { this.bytes[0] = uint8a[position + 0]; this.bytes[1] = uint8a[position + 1]; this.bytes[2] = uint8a[position + 2]; this.bytes[3] = uint8a[position + 3]; return this.toBytes[0]; }, write(uint8a, position, value) { this.toBytes[0] = value; uint8a[position + 0] = this.bytes[0]; uint8a[position + 1] = this.bytes[1]; uint8a[position + 2] = this.bytes[2]; uint8a[position + 3] = this.bytes[3]; return value; } }; let BE32; if (IS_HOST_LITTLE_ENDIAN) { BE32 = HOSTLE_BE32; } else { BE32 = HOSTBE_BE32; } /** * @const Int32BE * @type {BytePrimitive} */ const Int32BE = new BytePrimitive(Object.assign({}, BE32, { toBytes: new Int32Array(1) })); /** * @const Uint32BE * @type {BytePrimitive} */ const Uint32BE = new BytePrimitive(Object.assign({}, BE32, { toBytes: new Uint32Array(1) })); let LE16; if (IS_HOST_LITTLE_ENDIAN) { LE16 = HOSTBE_BE16; } else { LE16 = HOSTLE_BE16; } /** * @const Uint16LE * @type {BytePrimitive} */ const Uint16LE = new BytePrimitive(Object.assign({}, LE16, { toBytes: new Uint16Array(1) })); let LE32; if (IS_HOST_LITTLE_ENDIAN) { LE32 = HOSTBE_BE32; } else { LE32 = HOSTLE_BE32; } /** * @const Uint32LE * @type {BytePrimitive} */ const Uint32LE = new BytePrimitive(Object.assign({}, LE32, { toBytes: new Uint32Array(1) })); const HOSTLE_BEDOUBLE = { size: 8, read(uint8a, position) { this.bytes[7] = uint8a[position + 0]; this.bytes[6] = uint8a[position + 1]; this.bytes[5] = uint8a[position + 2]; this.bytes[4] = uint8a[position + 3]; this.bytes[3] = uint8a[position + 4]; this.bytes[2] = uint8a[position + 5]; this.bytes[1] = uint8a[position + 6]; this.bytes[0] = uint8a[position + 7]; return this.toBytes[0]; } }; const HOSTBE_BEDOUBLE = { size: 8, read(uint8a, position) { this.bytes[7] = uint8a[position + 0]; this.bytes[6] = uint8a[position + 1]; this.bytes[5] = uint8a[position + 2]; this.bytes[4] = uint8a[position + 3]; this.bytes[3] = uint8a[position + 4]; this.bytes[2] = uint8a[position + 5]; this.bytes[1] = uint8a[position + 6]; this.bytes[0] = uint8a[position + 7]; return this.toBytes[0]; } }; let BEDOUBLE; if (IS_HOST_LITTLE_ENDIAN) { BEDOUBLE = HOSTLE_BEDOUBLE; } else { BEDOUBLE = HOSTBE_BEDOUBLE; } /** * @const DoubleBE * @type {BytePrimitive} */ const DoubleBE = new BytePrimitive(Object.assign({}, BEDOUBLE, { toBytes: new Float64Array(1) })); /** * @extends BytePrimitive */ class FixedAsciiString extends BytePrimitive { /** * @param {number} size - Number of bytes the FixedAsciiString uses. */ constructor(size) { super({ size, read(uint8a, position) { let str = ''; for (let i = 0; i < size; i++) { const code = uint8a[position + i]; Object(_util_assert__WEBPACK_IMPORTED_MODULE_0__["assert"])(code <= 127, 'Non-ascii character in FixedAsciiString'); str += String.fromCharCode(code); } return str; }, write(uint8a, position, value) { for (let i = 0; i < size; i++) { const code = value.charCodeAt(i); Object(_util_assert__WEBPACK_IMPORTED_MODULE_0__["assert"])(code <= 127, 'Non-ascii character in FixedAsciiString'); uint8a[position + i] = code; } return value; } }); } } /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/coders/byte-stream.js": /*!**********************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/coders/byte-stream.js ***! \**********************************************************************/ /*! exports provided: ByteStream */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ByteStream", function() { return ByteStream; }); /* harmony import */ var _util_assert__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../util/assert */ "./node_modules/scratch-sb1-converter/src/util/assert.js"); /** * Read and write a stream of {@link BytePrimitive}s, {@link Packet}s, or byte * arrays to an ArrayBuffer. */ class ByteStream { /** * @param {ArrayBuffer} buffer - The ArrayBuffer to read from or write to. * @param {number=} [position=0] - The position to start reading or writing * from in the ArrayBuffer. */ constructor(buffer, position = 0) { /** * The ArrayBuffer to read from or write to. * @type {ArrayBuffer} */ this.buffer = buffer; /** * The position to start reading or writing from in the ArrayBuffer. * @type {number} */ this.position = position; /** * The typed array view of the buffer to read and write with. * @type {Uint8Array} */ this.uint8a = new Uint8Array(this.buffer); } /** * Read one instance of a given BytePrimitive and increment position based * on the size of that value. * @param {BytePrimitive} member - BytePrimitive to read and increment size * with. * @returns {*} Return the value produced by the BytePrimitive. */ read(member) { const value = member.read(this.uint8a, this.position); if (member.size === 0) { this.position += member.sizeOf(this.uint8a, this.position); } else { this.position += member.size; } return value; } /** * Read one instance of a given Packet subclass and increment position * based on the size of that value. * @param {PacketConstructor} StructType - Packet subclass constructor that * can read from the current stream position. * @returns {Packet} Instance of a Packet pointed at the position of the * stream before calling readStruct. */ readStruct(StructType) { const obj = new StructType(this.uint8a, this.position); this.position += StructType.size; return obj; } /** * Resize the internal buffer to allow for the needed amount of space. * @param {number} needed - How many bytes need to fit in the buffer. * @private */ resize(needed) { if (this.buffer.byteLength < needed) { const uint8a = this.uint8a; const nextPowerOf2 = Math.pow(2, Math.ceil(Math.log(needed) / Math.log(2))); this.buffer = new ArrayBuffer(nextPowerOf2); this.uint8a = new Uint8Array(this.buffer); this.uint8a.set(uint8a); } } /** * Write a value to the stream (with a BytePrimitive defining how to do so) * and increment the position. * @param {BytePrimitive} member - BytePrimitive to define how to write the * value. * @param {*} value - Value to write. * @returns {*} Value passed to the method. */ write(member, value) { if (member.size === 0) { this.resize(this.position + member.writeSizeOf(value)); } else { this.resize(this.position + member.size); } member.write(this.uint8a, this.position, value); if (member.size === 0) { this.position += member.writeSizeOf(this.uint8a, this.position); } else { this.position += member.size; } return value; } /** * Write data to the stream structured by a given Packet subclass * constructor and increment the position. * @param {PacketConstructor} StructType - The Packet subclass constructor * defining how to write the data. * @param {object} data - Data to write. * @returns {Packet} - Constructed packet after writing data. */ writeStruct(StructType, data) { this.resize(this.position + StructType.size); const st = Object.assign(new StructType(this.uint8a, this.position), data); this.position += StructType.size; return st; } /** * Write bytes from the given Uint8Array array to the stream and increment * the position. * @param {Uint8Array} bytes - Bytes to write to the stream. * @param {number=} [start=0] - Where in bytes to start writing from. * @param {number=} [end=bytes.length] - Where in bytes to stop writing, excluding position at bytes[end]. * @returns {Uint8Array} Passed bytes Uint8Array. */ writeBytes(bytes, start = 0, end = bytes.length) { Object(_util_assert__WEBPACK_IMPORTED_MODULE_0__["assert"])(bytes instanceof Uint8Array, 'writeBytes must be passed an Uint8Array'); this.resize(this.position + (end - start)); for (let i = start; i < end; i++) { this.uint8a[this.position + i - start] = bytes[i]; } this.position += end - start; return bytes; } } /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/coders/crc32.js": /*!****************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/coders/crc32.js ***! \****************************************************************/ /*! exports provided: CRC32 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CRC32", function() { return CRC32; }); class CRC32 { constructor() { this.bit = new Uint32Array(1); this.crc = 0; this.c = 0; this.table = []; let c; for (let i = 0; i < 256; i++) { c = i; for (let j = 0; j < 8; j++) { c = c & 1 ? 0xedb88320 ^ c >>> 1 : c >>> 1; } this.table[i] = c >>> 0; } } update(uint8a, position = 0, length = uint8a.length) { let crc = ~this.crc >>> 0; for (let i = 0; i < length; i++) { crc = crc >>> 8 ^ this.table[(crc ^ uint8a[position + i]) & 0xff]; } this.crc = ~crc >>> 0; return this; } get digest() { return this.crc; } } /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/coders/deflate-packets.js": /*!**************************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/coders/deflate-packets.js ***! \**************************************************************************/ /*! exports provided: DEFLATE_BLOCK_SIZE_MAX, DeflateHeader, DeflateChunkStart, DeflateEnd */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DEFLATE_BLOCK_SIZE_MAX", function() { return DEFLATE_BLOCK_SIZE_MAX; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DeflateHeader", function() { return DeflateHeader; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DeflateChunkStart", function() { return DeflateChunkStart; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DeflateEnd", function() { return DeflateEnd; }); /* harmony import */ var _byte_packets__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./byte-packets */ "./node_modules/scratch-sb1-converter/src/coders/byte-packets.js"); /* harmony import */ var _byte_primitives__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./byte-primitives */ "./node_modules/scratch-sb1-converter/src/coders/byte-primitives.js"); const DEFLATE_BLOCK_SIZE_MAX = 0xffff; class DeflateHeader extends _byte_packets__WEBPACK_IMPORTED_MODULE_0__["Packet"].extend({ cmf: _byte_primitives__WEBPACK_IMPORTED_MODULE_1__["Uint8"], flag: _byte_primitives__WEBPACK_IMPORTED_MODULE_1__["Uint8"] }) {} _byte_packets__WEBPACK_IMPORTED_MODULE_0__["Packet"].initConstructor(DeflateHeader); class DeflateChunkStart extends _byte_packets__WEBPACK_IMPORTED_MODULE_0__["Packet"].extend({ lastPacket: _byte_primitives__WEBPACK_IMPORTED_MODULE_1__["Uint8"], length: _byte_primitives__WEBPACK_IMPORTED_MODULE_1__["Uint16LE"], lengthCheck: _byte_primitives__WEBPACK_IMPORTED_MODULE_1__["Uint16LE"] }) {} _byte_packets__WEBPACK_IMPORTED_MODULE_0__["Packet"].initConstructor(DeflateChunkStart); class DeflateEnd extends _byte_packets__WEBPACK_IMPORTED_MODULE_0__["Packet"].extend({ checksum: _byte_primitives__WEBPACK_IMPORTED_MODULE_1__["Uint32LE"] }) {} _byte_packets__WEBPACK_IMPORTED_MODULE_0__["Packet"].initConstructor(DeflateEnd); /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/coders/deflate-stream.js": /*!*************************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/coders/deflate-stream.js ***! \*************************************************************************/ /*! exports provided: DeflateStream */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DeflateStream", function() { return DeflateStream; }); /* harmony import */ var _adler32__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./adler32 */ "./node_modules/scratch-sb1-converter/src/coders/adler32.js"); /* harmony import */ var _deflate_packets__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./deflate-packets */ "./node_modules/scratch-sb1-converter/src/coders/deflate-packets.js"); /* harmony import */ var _proxy_stream__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./proxy-stream */ "./node_modules/scratch-sb1-converter/src/coders/proxy-stream.js"); class DeflateStream extends _proxy_stream__WEBPACK_IMPORTED_MODULE_2__["ProxyStream"] { constructor(stream) { super(stream); this.stream.writeStruct(_deflate_packets__WEBPACK_IMPORTED_MODULE_1__["DeflateHeader"], { cmf: 0b00001000, flag: 0b00011101 }); this.adler = new _adler32__WEBPACK_IMPORTED_MODULE_0__["Adler32"](); this.chunk = this.stream.writeStruct(_deflate_packets__WEBPACK_IMPORTED_MODULE_1__["DeflateChunkStart"], { lastPacket: 0, length: 0, lengthCheck: 0 ^ 0xffff }); } get _deflateIndex() { return this.chunk.length; } set _deflateIndex(value) { this.chunk.length = value; this.chunk.lengthCheck = value ^ 0xffff; return this.chunk.length; } writeStruct(StructType, data) { this.writeBytes(Object.assign(new StructType(), data).uint8a); } writeBytes(bytes, start = 0, end = bytes.length) { let chunkStart = start; while (end - chunkStart > 0) { if (this._deflateIndex === _deflate_packets__WEBPACK_IMPORTED_MODULE_1__["DEFLATE_BLOCK_SIZE_MAX"]) { this.chunk = this.stream.writeStruct(_deflate_packets__WEBPACK_IMPORTED_MODULE_1__["DeflateChunkStart"], { lastPacket: 0, length: 0, lengthCheck: 0 ^ 0xffff }); } const chunkLength = Math.min(end - chunkStart, _deflate_packets__WEBPACK_IMPORTED_MODULE_1__["DEFLATE_BLOCK_SIZE_MAX"] - this._deflateIndex); this.stream.writeBytes(bytes, chunkStart, chunkStart + chunkLength); this._deflateIndex += chunkLength; chunkStart += chunkLength; } this.adler.update(bytes, start, end - start); } finish() { this.chunk.lastPacket = 1; this.stream.writeStruct(_deflate_packets__WEBPACK_IMPORTED_MODULE_1__["DeflateEnd"], { checksum: this.adler.digest }); } static estimateSize(bodySize) { const packets = Math.ceil(bodySize / _deflate_packets__WEBPACK_IMPORTED_MODULE_1__["DEFLATE_BLOCK_SIZE_MAX"]); return _deflate_packets__WEBPACK_IMPORTED_MODULE_1__["DeflateHeader"].size + packets * _deflate_packets__WEBPACK_IMPORTED_MODULE_1__["DeflateChunkStart"].size + _deflate_packets__WEBPACK_IMPORTED_MODULE_1__["DeflateEnd"].size + bodySize; } } /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/coders/png-chunk-stream.js": /*!***************************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/coders/png-chunk-stream.js ***! \***************************************************************************/ /*! exports provided: PNGChunkStream */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PNGChunkStream", function() { return PNGChunkStream; }); /* harmony import */ var _byte_primitives__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./byte-primitives */ "./node_modules/scratch-sb1-converter/src/coders/byte-primitives.js"); /* harmony import */ var _crc32__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./crc32 */ "./node_modules/scratch-sb1-converter/src/coders/crc32.js"); /* harmony import */ var _png_packets__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./png-packets */ "./node_modules/scratch-sb1-converter/src/coders/png-packets.js"); /* harmony import */ var _proxy_stream__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./proxy-stream */ "./node_modules/scratch-sb1-converter/src/coders/proxy-stream.js"); class PNGChunkStream extends _proxy_stream__WEBPACK_IMPORTED_MODULE_3__["ProxyStream"] { constructor(stream, chunkType = 'IHDR') { super(stream); this.start = this.stream.writeStruct(_png_packets__WEBPACK_IMPORTED_MODULE_2__["PNGChunkStart"], { length: 0, chunkType }); this.crc = new _crc32__WEBPACK_IMPORTED_MODULE_1__["CRC32"](); } finish() { const crcStart = this.start.offset + this.start.size; const length = this.position - crcStart; this.start.length = length; this.crc.update(this.stream.uint8a, crcStart - _byte_primitives__WEBPACK_IMPORTED_MODULE_0__["Uint32BE"].size, length + _byte_primitives__WEBPACK_IMPORTED_MODULE_0__["Uint32BE"].size); this.stream.writeStruct(_png_packets__WEBPACK_IMPORTED_MODULE_2__["PNGChunkEnd"], { checksum: this.crc.digest }); } static size(bodySize) { return _png_packets__WEBPACK_IMPORTED_MODULE_2__["PNGChunkStart"].size + bodySize + _png_packets__WEBPACK_IMPORTED_MODULE_2__["PNGChunkEnd"].size; } } /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/coders/png-file.js": /*!*******************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/coders/png-file.js ***! \*******************************************************************/ /*! exports provided: PNGFile */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PNGFile", function() { return PNGFile; }); /* harmony import */ var _byte_stream__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./byte-stream */ "./node_modules/scratch-sb1-converter/src/coders/byte-stream.js"); /* harmony import */ var _png_packets__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./png-packets */ "./node_modules/scratch-sb1-converter/src/coders/png-packets.js"); /* harmony import */ var _deflate_stream__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./deflate-stream */ "./node_modules/scratch-sb1-converter/src/coders/deflate-stream.js"); /* harmony import */ var _png_chunk_stream__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./png-chunk-stream */ "./node_modules/scratch-sb1-converter/src/coders/png-chunk-stream.js"); class PNGFile { encode(width, height, pixelsUint8) { const rowSize = width * 4 + _png_packets__WEBPACK_IMPORTED_MODULE_1__["PNGFilterMethodByte"].size; const bodySize = rowSize * height; const size = _png_packets__WEBPACK_IMPORTED_MODULE_1__["PNGSignature"].size + // IHDR _png_chunk_stream__WEBPACK_IMPORTED_MODULE_3__["PNGChunkStream"].size(_png_packets__WEBPACK_IMPORTED_MODULE_1__["PNGIHDRChunkBody"].size) + // IDAT _png_chunk_stream__WEBPACK_IMPORTED_MODULE_3__["PNGChunkStream"].size(_deflate_stream__WEBPACK_IMPORTED_MODULE_2__["DeflateStream"].estimateSize(bodySize)) + // IEND _png_chunk_stream__WEBPACK_IMPORTED_MODULE_3__["PNGChunkStream"].size(0); const stream = new _byte_stream__WEBPACK_IMPORTED_MODULE_0__["ByteStream"](new ArrayBuffer(size)); stream.writeStruct(_png_packets__WEBPACK_IMPORTED_MODULE_1__["PNGSignature"], { support8Bit: 0x89, png: 'PNG', dosLineEnding: '\r\n', dosEndOfFile: '\x1a', unixLineEnding: '\n' }); const pngIhdr = new _png_chunk_stream__WEBPACK_IMPORTED_MODULE_3__["PNGChunkStream"](stream, 'IHDR'); pngIhdr.writeStruct(_png_packets__WEBPACK_IMPORTED_MODULE_1__["PNGIHDRChunkBody"], { width, height, bitDepth: 8, colorType: 6, compressionMethod: 0, filterMethod: 0, interlaceMethod: 0 }); pngIhdr.finish(); const pngIdat = new _png_chunk_stream__WEBPACK_IMPORTED_MODULE_3__["PNGChunkStream"](stream, 'IDAT'); const deflate = new _deflate_stream__WEBPACK_IMPORTED_MODULE_2__["DeflateStream"](pngIdat); let pixelsIndex = 0; while (pixelsIndex < pixelsUint8.length) { deflate.writeStruct(_png_packets__WEBPACK_IMPORTED_MODULE_1__["PNGFilterMethodByte"], { method: 0 }); const partialLength = Math.min(pixelsUint8.length - pixelsIndex, rowSize - _png_packets__WEBPACK_IMPORTED_MODULE_1__["PNGFilterMethodByte"].size); deflate.writeBytes(pixelsUint8, pixelsIndex, pixelsIndex + partialLength); pixelsIndex += partialLength; } deflate.finish(); pngIdat.finish(); const pngIend = new _png_chunk_stream__WEBPACK_IMPORTED_MODULE_3__["PNGChunkStream"](stream, 'IEND'); pngIend.finish(); return stream.buffer; } static encode(width, height, pixels) { return new PNGFile().encode(width, height, pixels); } } /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/coders/png-packets.js": /*!**********************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/coders/png-packets.js ***! \**********************************************************************/ /*! exports provided: PNGSignature, PNGChunkStart, PNGChunkEnd, PNGIHDRChunkBody, PNGFilterMethodByte */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PNGSignature", function() { return PNGSignature; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PNGChunkStart", function() { return PNGChunkStart; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PNGChunkEnd", function() { return PNGChunkEnd; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PNGIHDRChunkBody", function() { return PNGIHDRChunkBody; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PNGFilterMethodByte", function() { return PNGFilterMethodByte; }); /* harmony import */ var _util_assert__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../util/assert */ "./node_modules/scratch-sb1-converter/src/util/assert.js"); /* harmony import */ var _byte_packets__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./byte-packets */ "./node_modules/scratch-sb1-converter/src/coders/byte-packets.js"); /* harmony import */ var _byte_primitives__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./byte-primitives */ "./node_modules/scratch-sb1-converter/src/coders/byte-primitives.js"); class PNGSignature extends _byte_packets__WEBPACK_IMPORTED_MODULE_1__["Packet"].extend({ support8Bit: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint8"], png: new _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["FixedAsciiString"](3), dosLineEnding: new _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["FixedAsciiString"](2), dosEndOfFile: new _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["FixedAsciiString"](1), unixLineEnding: new _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["FixedAsciiString"](1) }) { static validate() { Object(_util_assert__WEBPACK_IMPORTED_MODULE_0__["assert"])(this.equals({ support8Bit: 0x89, png: 'PNG', dosLineEnding: '\r\n', dosEndOfFile: '\x1a', unixLineEnding: '\n' }), 'PNGSignature does not match the expected values'); } } _byte_packets__WEBPACK_IMPORTED_MODULE_1__["Packet"].initConstructor(PNGSignature); class PNGChunkStart extends _byte_packets__WEBPACK_IMPORTED_MODULE_1__["Packet"].extend({ length: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"], chunkType: new _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["FixedAsciiString"](4) }) {} _byte_packets__WEBPACK_IMPORTED_MODULE_1__["Packet"].initConstructor(PNGChunkStart); class PNGChunkEnd extends _byte_packets__WEBPACK_IMPORTED_MODULE_1__["Packet"].extend({ checksum: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"] }) {} _byte_packets__WEBPACK_IMPORTED_MODULE_1__["Packet"].initConstructor(PNGChunkEnd); class PNGIHDRChunkBody extends _byte_packets__WEBPACK_IMPORTED_MODULE_1__["Packet"].extend({ width: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"], height: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"], bitDepth: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint8"], colorType: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint8"], compressionMethod: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint8"], filterMethod: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint8"], interlaceMethod: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint8"] }) {} _byte_packets__WEBPACK_IMPORTED_MODULE_1__["Packet"].initConstructor(PNGIHDRChunkBody); class PNGFilterMethodByte extends _byte_packets__WEBPACK_IMPORTED_MODULE_1__["Packet"].extend({ method: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint8"] }) {} _byte_packets__WEBPACK_IMPORTED_MODULE_1__["Packet"].initConstructor(PNGFilterMethodByte); /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/coders/proxy-stream.js": /*!***********************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/coders/proxy-stream.js ***! \***********************************************************************/ /*! exports provided: ProxyStream */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ProxyStream", function() { return ProxyStream; }); class ProxyStream { constructor(stream) { this.stream = stream; } get uint8a() { return this.stream.uint8a; } set uint8a(value) { this.stream.uint8a = value; return this.stream.uint8a; } get position() { return this.stream.position; } set position(value) { this.stream.position = value; return this.stream.position; } writeStruct(StructType, data) { return this.stream.writeStruct(StructType, data); } writeBytes(bytes, start = 0, end = bytes.length) { return this.stream.writeBytes(bytes, start, end); } } /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/coders/squeak-image.js": /*!***********************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/coders/squeak-image.js ***! \***********************************************************************/ /*! exports provided: SqueakImage */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SqueakImage", function() { return SqueakImage; }); /* harmony import */ var _byte_primitives__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./byte-primitives */ "./node_modules/scratch-sb1-converter/src/coders/byte-primitives.js"); /* harmony import */ var _byte_stream__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./byte-stream */ "./node_modules/scratch-sb1-converter/src/coders/byte-stream.js"); const defaultColorMap = [0x00000000, 0xFF000000, 0xFFFFFFFF, 0xFF808080, 0xFFFF0000, 0xFF00FF00, 0xFF0000FF, 0xFF00FFFF, 0xFFFFFF00, 0xFFFF00FF, 0xFF202020, 0xFF404040, 0xFF606060, 0xFF9F9F9F, 0xFFBFBFBF, 0xFFDFDFDF, 0xFF080808, 0xFF101010, 0xFF181818, 0xFF282828, 0xFF303030, 0xFF383838, 0xFF484848, 0xFF505050, 0xFF585858, 0xFF686868, 0xFF707070, 0xFF787878, 0xFF878787, 0xFF8F8F8F, 0xFF979797, 0xFFA7A7A7, 0xFFAFAFAF, 0xFFB7B7B7, 0xFFC7C7C7, 0xFFCFCFCF, 0xFFD7D7D7, 0xFFE7E7E7, 0xFFEFEFEF, 0xFFF7F7F7, 0xFF000000, 0xFF003300, 0xFF006600, 0xFF009900, 0xFF00CC00, 0xFF00FF00, 0xFF000033, 0xFF003333, 0xFF006633, 0xFF009933, 0xFF00CC33, 0xFF00FF33, 0xFF000066, 0xFF003366, 0xFF006666, 0xFF009966, 0xFF00CC66, 0xFF00FF66, 0xFF000099, 0xFF003399, 0xFF006699, 0xFF009999, 0xFF00CC99, 0xFF00FF99, 0xFF0000CC, 0xFF0033CC, 0xFF0066CC, 0xFF0099CC, 0xFF00CCCC, 0xFF00FFCC, 0xFF0000FF, 0xFF0033FF, 0xFF0066FF, 0xFF0099FF, 0xFF00CCFF, 0xFF00FFFF, 0xFF330000, 0xFF333300, 0xFF336600, 0xFF339900, 0xFF33CC00, 0xFF33FF00, 0xFF330033, 0xFF333333, 0xFF336633, 0xFF339933, 0xFF33CC33, 0xFF33FF33, 0xFF330066, 0xFF333366, 0xFF336666, 0xFF339966, 0xFF33CC66, 0xFF33FF66, 0xFF330099, 0xFF333399, 0xFF336699, 0xFF339999, 0xFF33CC99, 0xFF33FF99, 0xFF3300CC, 0xFF3333CC, 0xFF3366CC, 0xFF3399CC, 0xFF33CCCC, 0xFF33FFCC, 0xFF3300FF, 0xFF3333FF, 0xFF3366FF, 0xFF3399FF, 0xFF33CCFF, 0xFF33FFFF, 0xFF660000, 0xFF663300, 0xFF666600, 0xFF669900, 0xFF66CC00, 0xFF66FF00, 0xFF660033, 0xFF663333, 0xFF666633, 0xFF669933, 0xFF66CC33, 0xFF66FF33, 0xFF660066, 0xFF663366, 0xFF666666, 0xFF669966, 0xFF66CC66, 0xFF66FF66, 0xFF660099, 0xFF663399, 0xFF666699, 0xFF669999, 0xFF66CC99, 0xFF66FF99, 0xFF6600CC, 0xFF6633CC, 0xFF6666CC, 0xFF6699CC, 0xFF66CCCC, 0xFF66FFCC, 0xFF6600FF, 0xFF6633FF, 0xFF6666FF, 0xFF6699FF, 0xFF66CCFF, 0xFF66FFFF, 0xFF990000, 0xFF993300, 0xFF996600, 0xFF999900, 0xFF99CC00, 0xFF99FF00, 0xFF990033, 0xFF993333, 0xFF996633, 0xFF999933, 0xFF99CC33, 0xFF99FF33, 0xFF990066, 0xFF993366, 0xFF996666, 0xFF999966, 0xFF99CC66, 0xFF99FF66, 0xFF990099, 0xFF993399, 0xFF996699, 0xFF999999, 0xFF99CC99, 0xFF99FF99, 0xFF9900CC, 0xFF9933CC, 0xFF9966CC, 0xFF9999CC, 0xFF99CCCC, 0xFF99FFCC, 0xFF9900FF, 0xFF9933FF, 0xFF9966FF, 0xFF9999FF, 0xFF99CCFF, 0xFF99FFFF, 0xFFCC0000, 0xFFCC3300, 0xFFCC6600, 0xFFCC9900, 0xFFCCCC00, 0xFFCCFF00, 0xFFCC0033, 0xFFCC3333, 0xFFCC6633, 0xFFCC9933, 0xFFCCCC33, 0xFFCCFF33, 0xFFCC0066, 0xFFCC3366, 0xFFCC6666, 0xFFCC9966, 0xFFCCCC66, 0xFFCCFF66, 0xFFCC0099, 0xFFCC3399, 0xFFCC6699, 0xFFCC9999, 0xFFCCCC99, 0xFFCCFF99, 0xFFCC00CC, 0xFFCC33CC, 0xFFCC66CC, 0xFFCC99CC, 0xFFCCCCCC, 0xFFCCFFCC, 0xFFCC00FF, 0xFFCC33FF, 0xFFCC66FF, 0xFFCC99FF, 0xFFCCCCFF, 0xFFCCFFFF, 0xFFFF0000, 0xFFFF3300, 0xFFFF6600, 0xFFFF9900, 0xFFFFCC00, 0xFFFFFF00, 0xFFFF0033, 0xFFFF3333, 0xFFFF6633, 0xFFFF9933, 0xFFFFCC33, 0xFFFFFF33, 0xFFFF0066, 0xFFFF3366, 0xFFFF6666, 0xFFFF9966, 0xFFFFCC66, 0xFFFFFF66, 0xFFFF0099, 0xFFFF3399, 0xFFFF6699, 0xFFFF9999, 0xFFFFCC99, 0xFFFFFF99, 0xFFFF00CC, 0xFFFF33CC, 0xFFFF66CC, 0xFFFF99CC, 0xFFFFCCCC, 0xFFFFFFCC, 0xFFFF00FF, 0xFFFF33FF, 0xFFFF66FF, 0xFFFF99FF, 0xFFFFCCFF, 0xFFFFFFFF]; const defaultOneBitColorMap = [0xFFFFFFFF, 0xFF000000]; const VariableIntBE = new _byte_primitives__WEBPACK_IMPORTED_MODULE_0__["BytePrimitive"]({ sizeOf(uint8a, position) { const count = uint8a[position]; if (count <= 223) return 1; if (count <= 254) return 2; return 5; }, read(uint8a, position) { const count = uint8a[position]; if (count <= 223) return count; if (count <= 254) return (count - 224) * 256 + uint8a[position + 1]; return _byte_primitives__WEBPACK_IMPORTED_MODULE_0__["Uint32BE"].read(uint8a, position + 1); } }); class SqueakImage { decode(width, height, depth, bytes, colormap) { const pixels = this.decodePixels(bytes, depth === 32); if (depth <= 8) { if (!colormap) { colormap = depth === 1 ? defaultOneBitColorMap : defaultColorMap; } return this.unpackPixels(pixels, width, height, depth, colormap); } else if (depth === 16) { return this.raster16To32(pixels, width, height); } else if (depth === 32) { return pixels; } throw new Error('Unhandled Squeak Image depth.'); } decodePixels(bytes, withAlpha) { let result; // Already decompressed if (Array.isArray(bytes) || bytes instanceof Uint32Array) { result = new Uint32Array(bytes); if (withAlpha) { for (let i = 0; i < result.length; i++) { if (result[i] !== 0) { result[i] = 0xff000000 | result[i]; } } } return result; } const stream = new _byte_stream__WEBPACK_IMPORTED_MODULE_1__["ByteStream"](bytes.buffer, bytes.byteOffset); const pixelsOut = stream.read(VariableIntBE); result = new Uint32Array(pixelsOut); let i = 0; while (i < pixelsOut) { const runLengthAndCode = stream.read(VariableIntBE); const runLength = runLengthAndCode >> 2; const code = runLengthAndCode & 0b11; let w; switch (code) { case 0: i += runLength; break; case 1: w = stream.read(_byte_primitives__WEBPACK_IMPORTED_MODULE_0__["Uint8"]); w = w << 24 | w << 16 | w << 8 | w; if (withAlpha && w !== 0) { w |= 0xff000000; } for (let j = 0; j < runLength; j++) { result[i++] = w; } break; case 2: w = stream.read(_byte_primitives__WEBPACK_IMPORTED_MODULE_0__["Uint32BE"]); if (withAlpha && w !== 0) { w |= 0xff000000; } for (let j = 0; j < runLength; j++) { result[i++] = w; } break; case 3: for (let j = 0; j < runLength; j++) { w = stream.read(_byte_primitives__WEBPACK_IMPORTED_MODULE_0__["Uint32BE"]); if (withAlpha && w !== 0) { w |= 0xff000000; } result[i++] = w; } } } return result; } unpackPixels(words, width, height, depth, colormap) { const result = new Uint32Array(width * height); const mask = (1 << depth) - 1; const pixelsPerWord = 32 / depth; let dst = 0; let src = 0; for (let y = 0; y < height; y++) { let word; let shift = -1; for (let x = 0; x < width; x++) { if (shift < 0) { shift = depth * (pixelsPerWord - 1); word = words[src++]; } result[dst++] = colormap[word >> shift & mask]; shift -= depth; } } return result; } raster16To32(words, width, height) { const result = new Uint32Array(2 * words.length); let shift; let word; let pix; let src = 0; let dst = 0; for (let y = 0; y < height; y++) { shift = -1; for (let x = 0; x < width; x++) { if (shift < 0) { shift = 16; word = words[src++]; } pix = word >> shift & 0xffff; if (pix !== 0) { const red = pix >> 7 & 0b11111000; const green = pix >> 2 & 0b11111000; const blue = pix << 3 & 0b11111000; pix = 0xff000000 | red << 16 | green << 8 | blue; } result[dst++] = pix; shift -= 16; } } return result; } buildCustomColormap(depth, colors, table) { const result = new Uint32Array(1 << depth); for (let i = 0; i < colors.length; i++) { result[i] = table[colors[i].index - 1]; } return result; } } /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/coders/squeak-sound.js": /*!***********************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/coders/squeak-sound.js ***! \***********************************************************************/ /*! exports provided: SqueakSound */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SqueakSound", function() { return SqueakSound; }); /* harmony import */ var _util_assert__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../util/assert */ "./node_modules/scratch-sb1-converter/src/util/assert.js"); /* harmony import */ var _byte_primitives__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./byte-primitives */ "./node_modules/scratch-sb1-converter/src/coders/byte-primitives.js"); /* harmony import */ var _byte_stream__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./byte-stream */ "./node_modules/scratch-sb1-converter/src/coders/byte-stream.js"); const SQUEAK_SOUND_STEP_SIZE_TABLE = [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]; const SQUEAK_SOUND_INDEX_TABLES = { 2: [-1, 2, -1, 2], 3: [-1, -1, 2, 4, -1, -1, 2, 4], 4: [-1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8], 5: [-1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16, -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16] }; class SqueakSound { constructor(bitsPerSample) { this.bitsPerSample = bitsPerSample; this.indexTable = SQUEAK_SOUND_INDEX_TABLES[bitsPerSample]; this.signMask = 1 << bitsPerSample - 1; this.valueMask = this.signMask - 1; this.valueHighBit = this.signMask >> 1; this.bitPosition = 0; this.currentByte = 0; this.stream = null; this.end = 0; } decode(data) { // Reset position information. this.bitPosition = 0; this.currentByte = 0; this.stream = new _byte_stream__WEBPACK_IMPORTED_MODULE_2__["ByteStream"](data.buffer, data.byteOffset); this.end = data.byteOffset + data.length; const size = Math.floor(data.length * 8 / this.bitsPerSample); const result = new Int16Array(size); let sample = 0; let index = 0; for (let i = 0; i < size; i++) { const code = this.nextCode(); Object(_util_assert__WEBPACK_IMPORTED_MODULE_0__["assert"])(code >= 0, 'Ran out of bits in Squeak Sound'); let step = SQUEAK_SOUND_STEP_SIZE_TABLE[index]; let delta = 0; for (let bit = this.valueHighBit; bit > 0; bit = bit >> 1) { if ((code & bit) !== 0) { delta += step; } step = step >> 1; } delta += step; sample += (code & this.signMask) === 0 ? delta : -delta; index += this.indexTable[code]; if (index < 0) index = 0; if (index > 88) index = 88; if (sample > 32767) sample = 32767; if (sample < -32768) sample = -32768; result[i] = sample; } return result; } nextCode() { let remaining = this.bitsPerSample; let shift = remaining - this.bitPosition; let result = shift < 0 ? this.currentByte >> -shift : this.currentByte << shift; while (shift > 0) { remaining -= this.bitPosition; if (this.end - this.stream.position > 0) { this.currentByte = this.stream.read(_byte_primitives__WEBPACK_IMPORTED_MODULE_1__["Uint8"]); this.bitPosition = 8; } else { this.currentByte = 0; this.bitPosition = 0; return -1; } shift = remaining - this.bitPosition; result += shift < 0 ? this.currentByte >> -shift : this.currentByte << shift; } this.bitPosition -= remaining; this.currentByte = this.currentByte & 0xff >> 8 - this.bitPosition; return result; } static samples(bitsPerSample, data) { return data.length * 8 / bitsPerSample; } } /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/coders/wav-file.js": /*!*******************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/coders/wav-file.js ***! \*******************************************************************/ /*! exports provided: WAVFile */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WAVFile", function() { return WAVFile; }); /* harmony import */ var _byte_stream__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./byte-stream */ "./node_modules/scratch-sb1-converter/src/coders/byte-stream.js"); /* harmony import */ var _wav_packets__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./wav-packets */ "./node_modules/scratch-sb1-converter/src/coders/wav-packets.js"); class WAVFile { encode(intSamples, { channels = 1, sampleRate = 22050 } = {}) { const samplesUint8 = new Uint8Array(intSamples.buffer, intSamples.byteOffset, intSamples.byteLength); const size = _wav_packets__WEBPACK_IMPORTED_MODULE_1__["WAVESignature"].size + _wav_packets__WEBPACK_IMPORTED_MODULE_1__["WAVEChunkStart"].size + _wav_packets__WEBPACK_IMPORTED_MODULE_1__["WAVEFMTChunkBody"].size + _wav_packets__WEBPACK_IMPORTED_MODULE_1__["WAVEChunkStart"].size + samplesUint8.length; const stream = new _byte_stream__WEBPACK_IMPORTED_MODULE_0__["ByteStream"](new ArrayBuffer(size)); stream.writeStruct(_wav_packets__WEBPACK_IMPORTED_MODULE_1__["WAVESignature"], { riff: 'RIFF', length: size - 8, wave: 'WAVE' }); stream.writeStruct(_wav_packets__WEBPACK_IMPORTED_MODULE_1__["WAVEChunkStart"], { chunkType: 'fmt ', length: _wav_packets__WEBPACK_IMPORTED_MODULE_1__["WAVEFMTChunkBody"].size }); stream.writeStruct(_wav_packets__WEBPACK_IMPORTED_MODULE_1__["WAVEFMTChunkBody"], { format: 1, channels: channels, sampleRate: sampleRate, bytesPerSec: sampleRate * 2 * channels, blockAlignment: channels * 2, bitsPerSample: 16 }); stream.writeStruct(_wav_packets__WEBPACK_IMPORTED_MODULE_1__["WAVEChunkStart"], { chunkType: 'data', length: size - stream.position - _wav_packets__WEBPACK_IMPORTED_MODULE_1__["WAVEChunkStart"].size }); stream.writeBytes(samplesUint8); return stream.uint8a; } static encode(intSamples, options) { return new WAVFile().encode(intSamples, options); } static samples(bytes) { const headerLength = new _wav_packets__WEBPACK_IMPORTED_MODULE_1__["WAVEChunkStart"](bytes, _wav_packets__WEBPACK_IMPORTED_MODULE_1__["WAVESignature"].size).length; const bodyLength = new _wav_packets__WEBPACK_IMPORTED_MODULE_1__["WAVEChunkStart"](bytes, _wav_packets__WEBPACK_IMPORTED_MODULE_1__["WAVESignature"].size + _wav_packets__WEBPACK_IMPORTED_MODULE_1__["WAVEChunkStart"].size + headerLength).length; return bodyLength / 2; } } /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/coders/wav-packets.js": /*!**********************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/coders/wav-packets.js ***! \**********************************************************************/ /*! exports provided: WAVESignature, WAVEChunkStart, WAVEFMTChunkBody */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WAVESignature", function() { return WAVESignature; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WAVEChunkStart", function() { return WAVEChunkStart; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WAVEFMTChunkBody", function() { return WAVEFMTChunkBody; }); /* harmony import */ var _byte_packets__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./byte-packets */ "./node_modules/scratch-sb1-converter/src/coders/byte-packets.js"); /* harmony import */ var _byte_primitives__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./byte-primitives */ "./node_modules/scratch-sb1-converter/src/coders/byte-primitives.js"); class WAVESignature extends _byte_packets__WEBPACK_IMPORTED_MODULE_0__["Packet"].extend({ riff: new _byte_primitives__WEBPACK_IMPORTED_MODULE_1__["FixedAsciiString"](4), length: _byte_primitives__WEBPACK_IMPORTED_MODULE_1__["Uint32LE"], wave: new _byte_primitives__WEBPACK_IMPORTED_MODULE_1__["FixedAsciiString"](4) }) {} _byte_packets__WEBPACK_IMPORTED_MODULE_0__["Packet"].initConstructor(WAVESignature); class WAVEChunkStart extends _byte_packets__WEBPACK_IMPORTED_MODULE_0__["Packet"].extend({ chunkType: new _byte_primitives__WEBPACK_IMPORTED_MODULE_1__["FixedAsciiString"](4), length: _byte_primitives__WEBPACK_IMPORTED_MODULE_1__["Uint32LE"] }) {} _byte_packets__WEBPACK_IMPORTED_MODULE_0__["Packet"].initConstructor(WAVEChunkStart); class WAVEFMTChunkBody extends _byte_packets__WEBPACK_IMPORTED_MODULE_0__["Packet"].extend({ format: _byte_primitives__WEBPACK_IMPORTED_MODULE_1__["Uint16LE"], channels: _byte_primitives__WEBPACK_IMPORTED_MODULE_1__["Uint16LE"], sampleRate: _byte_primitives__WEBPACK_IMPORTED_MODULE_1__["Uint32LE"], bytesPerSec: _byte_primitives__WEBPACK_IMPORTED_MODULE_1__["Uint32LE"], blockAlignment: _byte_primitives__WEBPACK_IMPORTED_MODULE_1__["Uint16LE"], bitsPerSample: _byte_primitives__WEBPACK_IMPORTED_MODULE_1__["Uint16LE"] }) {} _byte_packets__WEBPACK_IMPORTED_MODULE_0__["Packet"].initConstructor(WAVEFMTChunkBody); /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/sb1-file-packets.js": /*!********************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/sb1-file-packets.js ***! \********************************************************************/ /*! exports provided: SB1Signature, SB1Header */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SB1Signature", function() { return SB1Signature; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SB1Header", function() { return SB1Header; }); /* harmony import */ var _util_assert__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./util/assert */ "./node_modules/scratch-sb1-converter/src/util/assert.js"); /* harmony import */ var _coders_byte_packets__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./coders/byte-packets */ "./node_modules/scratch-sb1-converter/src/coders/byte-packets.js"); /* harmony import */ var _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./coders/byte-primitives */ "./node_modules/scratch-sb1-converter/src/coders/byte-primitives.js"); /** * @augments Packet */ class SB1Signature extends _coders_byte_packets__WEBPACK_IMPORTED_MODULE_1__["Packet"].extend({ /** * 10 byte ascii string equaling `'ScratchV01'` or `'ScratchV02'`. * @type {string} * @memberof SB1Signature# */ version: new _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["FixedAsciiString"](10), /** * Number of bytes in the info block. * @type {number} * @memberof SB1Signature# */ infoByteLength: _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"] }) { /** * Is this a valid SB1Signature? * @method * @throws {AssertionError} Throws if it is not valid. */ validate() { _util_assert__WEBPACK_IMPORTED_MODULE_0__["assert"].validate(this.equals({ version: 'ScratchV01' }) || this.equals({ version: 'ScratchV02' }), 'Invalid Scratch file signature.'); } } _coders_byte_packets__WEBPACK_IMPORTED_MODULE_1__["Packet"].initConstructor(SB1Signature); class SB1Header extends _coders_byte_packets__WEBPACK_IMPORTED_MODULE_1__["Packet"].extend({ ObjS: new _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["FixedAsciiString"](4), ObjSValue: _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint8"], Stch: new _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["FixedAsciiString"](4), StchValue: _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint8"], numObjects: _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"] }) { validate() { _util_assert__WEBPACK_IMPORTED_MODULE_0__["assert"].validate(this.equals({ ObjS: 'ObjS', ObjSValue: 1, Stch: 'Stch', StchValue: 1 }), 'Invalid Scratch file info packet header.'); } } _coders_byte_packets__WEBPACK_IMPORTED_MODULE_1__["Packet"].initConstructor(SB1Header); /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/sb1-file.js": /*!************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/sb1-file.js ***! \************************************************************/ /*! exports provided: SB1File */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SB1File", function() { return SB1File; }); /* harmony import */ var _coders_byte_stream__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./coders/byte-stream */ "./node_modules/scratch-sb1-converter/src/coders/byte-stream.js"); /* harmony import */ var _squeak_byte_take_iterator__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./squeak/byte-take-iterator */ "./node_modules/scratch-sb1-converter/src/squeak/byte-take-iterator.js"); /* harmony import */ var _squeak_field_iterator__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./squeak/field-iterator */ "./node_modules/scratch-sb1-converter/src/squeak/field-iterator.js"); /* harmony import */ var _squeak_type_iterator__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./squeak/type-iterator */ "./node_modules/scratch-sb1-converter/src/squeak/type-iterator.js"); /* harmony import */ var _squeak_reference_fixer__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./squeak/reference-fixer */ "./node_modules/scratch-sb1-converter/src/squeak/reference-fixer.js"); /* harmony import */ var _squeak_types__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./squeak/types */ "./node_modules/scratch-sb1-converter/src/squeak/types.js"); /* harmony import */ var _to_sb2_fake_zip__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./to-sb2/fake-zip */ "./node_modules/scratch-sb1-converter/src/to-sb2/fake-zip.js"); /* harmony import */ var _to_sb2_json_generator__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./to-sb2/json-generator */ "./node_modules/scratch-sb1-converter/src/to-sb2/json-generator.js"); /* harmony import */ var _sb1_file_packets__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./sb1-file-packets */ "./node_modules/scratch-sb1-converter/src/sb1-file-packets.js"); class SB1File { constructor(buffer) { this.buffer = buffer; this.stream = new _coders_byte_stream__WEBPACK_IMPORTED_MODULE_0__["ByteStream"](buffer); this.signature = this.stream.readStruct(_sb1_file_packets__WEBPACK_IMPORTED_MODULE_8__["SB1Signature"]); this.signature.validate(); this.infoHeader = this.stream.readStruct(_sb1_file_packets__WEBPACK_IMPORTED_MODULE_8__["SB1Header"]); this.infoHeader.validate(); this.stream.position += this.signature.infoByteLength - _sb1_file_packets__WEBPACK_IMPORTED_MODULE_8__["SB1Header"].size; this.dataHeader = this.stream.readStruct(_sb1_file_packets__WEBPACK_IMPORTED_MODULE_8__["SB1Header"]); this.dataHeader.validate(); } get json() { return Object(_to_sb2_json_generator__WEBPACK_IMPORTED_MODULE_7__["toSb2Json"])({ info: this.info(), stageData: this.data(), images: this.images(), sounds: this.sounds() }); } get zip() { return Object(_to_sb2_fake_zip__WEBPACK_IMPORTED_MODULE_6__["toSb2FakeZipApi"])({ // Use of this `zip` getter assumes that `json` will be used to // fetch the json and not have it read from the produced "fake" zip. images: this.images(), sounds: this.sounds() }); } view() { return { signature: this.signature, infoHeader: this.infoHeader, dataHeader: this.dataHeader, toString() { return 'SB1File'; } }; } infoRaw() { return new _squeak_byte_take_iterator__WEBPACK_IMPORTED_MODULE_1__["ByteTakeIterator"](new _squeak_field_iterator__WEBPACK_IMPORTED_MODULE_2__["FieldIterator"](this.buffer, this.infoHeader.offset + _sb1_file_packets__WEBPACK_IMPORTED_MODULE_8__["SB1Header"].size), this.signature.infoByteLength + _sb1_file_packets__WEBPACK_IMPORTED_MODULE_8__["SB1Signature"].size); } infoTable() { return new _squeak_type_iterator__WEBPACK_IMPORTED_MODULE_3__["TypeIterator"](this.infoRaw()); } info() { if (!this._info) { this._info = new _squeak_reference_fixer__WEBPACK_IMPORTED_MODULE_4__["ReferenceFixer"](this.infoTable()).table[0]; } return this._info; } dataRaw() { return new _squeak_byte_take_iterator__WEBPACK_IMPORTED_MODULE_1__["ByteTakeIterator"](new _squeak_field_iterator__WEBPACK_IMPORTED_MODULE_2__["FieldIterator"](this.buffer, this.dataHeader.offset + _sb1_file_packets__WEBPACK_IMPORTED_MODULE_8__["SB1Header"].size), this.stream.uint8a.length); } dataTable() { return new _squeak_type_iterator__WEBPACK_IMPORTED_MODULE_3__["TypeIterator"](this.dataRaw()); } dataFixed() { if (!this._data) { this._data = new _squeak_reference_fixer__WEBPACK_IMPORTED_MODULE_4__["ReferenceFixer"](this.dataTable()).table; } return this._data; } data() { return this.dataFixed()[0]; } images() { const unique = new Set(); return this.dataFixed().filter(obj => { if (obj instanceof _squeak_types__WEBPACK_IMPORTED_MODULE_5__["ImageMediaData"]) { if (unique.has(obj.crc)) return false; unique.add(obj.crc); return true; } return false; }); } sounds() { const unique = new Set(); return this.dataFixed().filter(obj => { if (obj instanceof _squeak_types__WEBPACK_IMPORTED_MODULE_5__["SoundMediaData"]) { if (unique.has(obj.crc)) return false; unique.add(obj.crc); return true; } return false; }); } } /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/squeak/byte-primitives.js": /*!**************************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/squeak/byte-primitives.js ***! \**************************************************************************/ /*! exports provided: BUFFER_TOO_BIG, ReferenceBE, LargeInt, AsciiString, Bytes, SoundBytes, Bitmap32BE, UTF8, OpaqueColor, TranslucentColor */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BUFFER_TOO_BIG", function() { return BUFFER_TOO_BIG; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ReferenceBE", function() { return ReferenceBE; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LargeInt", function() { return LargeInt; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AsciiString", function() { return AsciiString; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Bytes", function() { return Bytes; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SoundBytes", function() { return SoundBytes; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Bitmap32BE", function() { return Bitmap32BE; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UTF8", function() { return UTF8; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OpaqueColor", function() { return OpaqueColor; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TranslucentColor", function() { return TranslucentColor; }); /* harmony import */ var text_encoding__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! text-encoding */ "./src/lib/tw-text-encoder.js"); /* harmony import */ var _util_assert__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../util/assert */ "./node_modules/scratch-sb1-converter/src/util/assert.js"); /* harmony import */ var _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../coders/byte-primitives */ "./node_modules/scratch-sb1-converter/src/coders/byte-primitives.js"); const BUFFER_TOO_BIG = 10 * 1024 * 1024; /** * @const ReferenceBE * @type BytePrimitive */ let ReferenceBE; if (_coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["IS_HOST_LITTLE_ENDIAN"]) { ReferenceBE = new _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["BytePrimitive"]({ size: 3, read(uint8a, position) { return uint8a[position + 0] << 16 | uint8a[position + 1] << 8 | uint8a[position + 2]; } }); } else { ReferenceBE = new _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["BytePrimitive"]({ size: 3, read(uint8a, position) { return uint8a[position + 2] << 16 | uint8a[position + 1] << 8 | uint8a[position + 0]; } }); } /** * @const LargeInt * @type BytePrimitive */ const LargeInt = new _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["BytePrimitive"]({ sizeOf(uint8a, position) { const count = _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Int16BE"].read(uint8a, position); return _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Int16BE"].size + count; }, read(uint8a, position) { let num = 0; let multiplier = 0; const count = _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Int16BE"].read(uint8a, position); for (let i = 0; i < count; i++) { num = num + multiplier * _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint8"].read(uint8a, position++); multiplier *= 256; } return num; } }); /** * @const AsciiString * @type BytePrimitive */ const AsciiString = new _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["BytePrimitive"]({ sizeOf(uint8a, position) { const count = _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].read(uint8a, position); return _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].size + count; }, read(uint8a, position) { const count = _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].read(uint8a, position); Object(_util_assert__WEBPACK_IMPORTED_MODULE_1__["assert"])(count < BUFFER_TOO_BIG, 'asciiString too big'); position += 4; let str = ''; for (let i = 0; i < count; i++) { str += String.fromCharCode(uint8a[position++]); } return str; } }); /** * @const Bytes * @type BytePrimitive */ const Bytes = new _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["BytePrimitive"]({ sizeOf(uint8a, position) { return _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].size + _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].read(uint8a, position); }, read(uint8a, position) { const count = _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].read(uint8a, position); Object(_util_assert__WEBPACK_IMPORTED_MODULE_1__["assert"])(count < BUFFER_TOO_BIG, 'bytes too big'); position += _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].size; Object(_util_assert__WEBPACK_IMPORTED_MODULE_1__["assert"])(count < BUFFER_TOO_BIG, 'uint8a array too big'); return new Uint8Array(uint8a.buffer, position, count); } }); /** * @const SoundBytes * @type BytePrimitive */ const SoundBytes = new _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["BytePrimitive"]({ sizeOf(uint8a, position) { return _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].size + _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].read(uint8a, position) * 2; }, read(uint8a, position) { const samples = _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].read(uint8a, position); Object(_util_assert__WEBPACK_IMPORTED_MODULE_1__["assert"])(samples < BUFFER_TOO_BIG, 'sound too big'); position += _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].size; const count = samples * 2; Object(_util_assert__WEBPACK_IMPORTED_MODULE_1__["assert"])(count < BUFFER_TOO_BIG, 'uint8a array too big'); return new Uint8Array(uint8a.buffer, position, count); } }); /** * @const Bitmap32BE * @type BytePrimitive */ const Bitmap32BE = new _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["BytePrimitive"]({ sizeOf(uint8a, position) { return _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].size + _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].read(uint8a, position) * _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].size; }, read(uint8a, position) { const count = _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].read(uint8a, position); Object(_util_assert__WEBPACK_IMPORTED_MODULE_1__["assert"])(count < BUFFER_TOO_BIG, 'bitmap too big'); position += _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].size; Object(_util_assert__WEBPACK_IMPORTED_MODULE_1__["assert"])(count < BUFFER_TOO_BIG, 'uint8a array too big'); const value = new Uint32Array(count); for (let i = 0; i < count; i++) { value[i] = _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].read(uint8a, position); position += _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].size; } return value; } }); let decoder; /* global TextDecoder:true */ if (typeof TextDecoder === 'undefined') { decoder = new text_encoding__WEBPACK_IMPORTED_MODULE_0__["TextDecoder"](); } else { decoder = new TextDecoder(); } /** * @const UTF8 * @type BytePrimitive */ const UTF8 = new _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["BytePrimitive"]({ sizeOf(uint8a, position) { return _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].size + _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].read(uint8a, position); }, read(uint8a, position) { const count = _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].read(uint8a, position); Object(_util_assert__WEBPACK_IMPORTED_MODULE_1__["assert"])(count < BUFFER_TOO_BIG, 'utf8 too big'); position += _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].size; Object(_util_assert__WEBPACK_IMPORTED_MODULE_1__["assert"])(count < BUFFER_TOO_BIG, 'uint8a array too big'); return decoder.decode(new Uint8Array(uint8a.buffer, position, count)); } }); /** * @const OpaqueColor * @type BytePrimitive */ const OpaqueColor = new _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["BytePrimitive"]({ size: 4, read(uint8a, position) { const rgb = _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].read(uint8a, position); const a = 0xff; const r = rgb >> 22 & 0xff; const g = rgb >> 12 & 0xff; const b = rgb >> 2 & 0xff; return (a << 24 | r << 16 | g << 8 | b) >>> 0; } }); /** * @const TranslucentColor * @type BytePrimitive */ const TranslucentColor = new _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["BytePrimitive"]({ size: 5, read(uint8a, position) { const rgb = _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint32BE"].read(uint8a, position); const a = _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Uint8"].read(uint8a, position); const r = rgb >> 22 & 0xff; const g = rgb >> 12 & 0xff; const b = rgb >> 2 & 0xff; return (a << 24 | r << 16 | g << 8 | b) >>> 0; } }); /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/squeak/byte-take-iterator.js": /*!*****************************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/squeak/byte-take-iterator.js ***! \*****************************************************************************/ /*! exports provided: ByteTakeIterator */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ByteTakeIterator", function() { return ByteTakeIterator; }); /** * An iterator that only takes bytes up to a certain position. * * Take iterators constrain the number of times an inner iterator can return * values. Normally it constrains the number of returned values. * ByteTakeIterator instead constrains the number of bytes the inner iterator * may take from its stream before ByteTakeIterator returns done objects. * * Primarily used to wrap {@link FieldIterator}. */ class ByteTakeIterator { /** * @param {{stream: ByteStream}} iter - Iterator with `stream` member. * @param {number} [maxPosition=Infinity] - Position `stream` may not go * beyond when yielding the next value. */ constructor(iter, maxPosition = Infinity) { this.iter = iter; this.maxPosition = maxPosition; } /** * @returns {ByteTakeIterator} - Returns itself. */ [Symbol.iterator]() { return this; } /** * @returns {{value: *, done: boolean}} - Return the next value or indicate * the Iterator has reached its end. */ next() { if (this.iter.stream.position >= this.maxPosition) { return { value: null, done: true }; } return this.iter.next(); } } /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/squeak/field-iterator.js": /*!*************************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/squeak/field-iterator.js ***! \*************************************************************************/ /*! exports provided: FieldIterator */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FieldIterator", function() { return FieldIterator; }); /* harmony import */ var _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../coders/byte-primitives */ "./node_modules/scratch-sb1-converter/src/coders/byte-primitives.js"); /* harmony import */ var _coders_byte_stream__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../coders/byte-stream */ "./node_modules/scratch-sb1-converter/src/coders/byte-stream.js"); /* harmony import */ var _byte_primitives__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./byte-primitives */ "./node_modules/scratch-sb1-converter/src/squeak/byte-primitives.js"); /* harmony import */ var _fields__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./fields */ "./node_modules/scratch-sb1-converter/src/squeak/fields.js"); /* harmony import */ var _ids__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./ids */ "./node_modules/scratch-sb1-converter/src/squeak/ids.js"); /** * Consume values for the byte stream with a iterator-like interface. */ class Consumer { /** * @param {object} options - Define the consumer. * @param {function} [options.type=Value] - The {@link Field} type to * create. * @param {BytePrimitive} options.read - How to read the third Field * argument. The third field argument is the value the field represented in * the `.sb` file. It is either the Value's value, the Reference's index, * or the Header's field size. * @param {function} [options.value] - How to produce the third Field * argument from a stream. Defaults to `stream => * stream.read(options.read)`. */ constructor({ type = _fields__WEBPACK_IMPORTED_MODULE_3__["Value"], read, value = read ? stream => stream.read(read) : null }) { this.type = type; this.value = value; } /** * @param {ByteStream} stream - Stream to read from. * @param {TYPES} classId - FieldObject TYPES identifying the value to read. * @param {number} position - Position in the stream the classId was read * from. * @returns {{value: *, done: boolean}} - An iterator.next() return value. */ next(stream, classId, position) { return { value: new this.type(classId, position, this.value(stream)), done: false }; } } /** * @const CONSUMER_PROTOS * @type {Object.} */ const CONSUMER_PROTOS = { [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].NULL]: { value: () => null }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].TRUE]: { value: () => true }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].FALSE]: { value: () => false }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].SMALL_INT]: { read: _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_0__["Int32BE"] }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].SMALL_INT_16]: { read: _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_0__["Int16BE"] }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].LARGE_INT_POSITIVE]: { read: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["LargeInt"] }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].LARGE_INT_NEGATIVE]: { read: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["LargeInt"] }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].FLOATING]: { read: _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_0__["DoubleBE"] }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].STRING]: { read: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["AsciiString"] }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].SYMBOL]: { read: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["AsciiString"] }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].BYTES]: { read: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Bytes"] }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].SOUND]: { read: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["SoundBytes"] }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].BITMAP]: { read: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["Bitmap32BE"] }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].UTF8]: { read: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["UTF8"] }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].ARRAY]: { type: _fields__WEBPACK_IMPORTED_MODULE_3__["Header"], read: _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_0__["Int32BE"] }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].ORDERED_COLLECTION]: { type: _fields__WEBPACK_IMPORTED_MODULE_3__["Header"], read: _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_0__["Int32BE"] }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].SET]: { type: _fields__WEBPACK_IMPORTED_MODULE_3__["Header"], read: _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_0__["Int32BE"] }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].IDENTITY_SET]: { type: _fields__WEBPACK_IMPORTED_MODULE_3__["Header"], read: _coders_byte_primitives__WEBPACK_IMPORTED_MODULE_0__["Int32BE"] }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].DICTIONARY]: { type: _fields__WEBPACK_IMPORTED_MODULE_3__["Header"], value: stream => stream.read(_coders_byte_primitives__WEBPACK_IMPORTED_MODULE_0__["Int32BE"]) * 2 }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].IDENTITY_DICTIONARY]: { type: _fields__WEBPACK_IMPORTED_MODULE_3__["Header"], value: stream => stream.read(_coders_byte_primitives__WEBPACK_IMPORTED_MODULE_0__["Int32BE"]) * 2 }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].COLOR]: { read: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["OpaqueColor"] }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].TRANSLUCENT_COLOR]: { read: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["TranslucentColor"] }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].POINT]: { type: _fields__WEBPACK_IMPORTED_MODULE_3__["Header"], value: () => 2 }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].RECTANGLE]: { type: _fields__WEBPACK_IMPORTED_MODULE_3__["Header"], value: () => 4 }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].FORM]: { type: _fields__WEBPACK_IMPORTED_MODULE_3__["Header"], value: () => 5 }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].SQUEAK]: { type: _fields__WEBPACK_IMPORTED_MODULE_3__["Header"], value: () => 6 }, [_ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].OBJECT_REF]: { type: _fields__WEBPACK_IMPORTED_MODULE_3__["Reference"], read: _byte_primitives__WEBPACK_IMPORTED_MODULE_2__["ReferenceBE"] } }; /** * @const CONSUMERS * @type {Array.} */ const CONSUMERS = Array.from({ length: 256 }, (_, i) => { if (CONSUMER_PROTOS[i]) return new Consumer(CONSUMER_PROTOS[i]); return null; }); const builtinConsumer = new Consumer({ type: _fields__WEBPACK_IMPORTED_MODULE_3__["BuiltinObjectHeader"], value: () => null }); /** * Field iterator. */ class FieldIterator { /** * @param {ArrayBuffer} buffer - Buffer to read from. * @param {number} position - Position in buffer to start at. */ constructor(buffer, position) { this.buffer = buffer; this.stream = new _coders_byte_stream__WEBPACK_IMPORTED_MODULE_1__["ByteStream"](buffer, position); } /** * @returns {FieldIterator} - Returns this. */ [Symbol.iterator]() { return this; } /** * @returns {{value: *, done: boolean}} - An iterator.next() value. */ next() { if (this.stream.position >= this.stream.uint8a.length) { return { value: null, done: true }; } const position = this.stream.position; const classId = this.stream.read(_coders_byte_primitives__WEBPACK_IMPORTED_MODULE_0__["Uint8"]); const consumer = CONSUMERS[classId]; if (consumer !== null) { return consumer.next(this.stream, classId, position); } else if (classId < _ids__WEBPACK_IMPORTED_MODULE_4__["TYPES"].OBJECT_REF) { // TODO: Does this ever happen? return builtinConsumer.next(this.stream, classId, position); } const classVersion = this.stream.read(_coders_byte_primitives__WEBPACK_IMPORTED_MODULE_0__["Uint8"]); const size = this.stream.read(_coders_byte_primitives__WEBPACK_IMPORTED_MODULE_0__["Uint8"]); return { value: new _fields__WEBPACK_IMPORTED_MODULE_3__["FieldObjectHeader"](classId, position, classVersion, size), done: false }; } } /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/squeak/field-object.js": /*!***********************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/squeak/field-object.js ***! \***********************************************************************/ /*! exports provided: FieldObject */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FieldObject", function() { return FieldObject; }); /* harmony import */ var _ids__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./ids */ "./node_modules/scratch-sb1-converter/src/squeak/ids.js"); const toTitleCase = str => str.toLowerCase().replace(/_(\w)/g, ([, letter]) => letter.toUpperCase()); /** * A object representation of a {@link Header} collecting the given {@link * Header#size} in fields. */ class FieldObject { /** * @param {TYPES} classId - {@link TYPES} id that informs what the shape of * this object is. * @param {number} version - Version number of this object. Some items in * the same class may have different content and so will be different * versions. * @param {Array.} fields - An array of fields in this FieldObject. */ constructor({ classId, version, fields }) { /** @type {number} */ this.classId = classId; /** @type {number} */ this.version = version; /** @type {Array.} */ this.fields = fields; } /** * @type {object} */ get FIELDS() { return []; } /** * @type {Array.} */ get RAW_FIELDS() { return this.fields; } string(field) { return String(this.fields[field]); } number(field) { return +this.fields[field]; } boolean(field) { return !!this.fields[field]; } toString() { if (this.constructor === FieldObject) { return "".concat(this.constructor.name, " ").concat(this.classId, " ").concat(_ids__WEBPACK_IMPORTED_MODULE_0__["TYPE_NAMES"][this.classId]); } return this.constructor.name; } /** * Define a FieldObject subclass by mapping field names to indices in * {@link FieldObject#fields}. * @param {object} FIELDS - Mapping of ALL_CAPS keys to index in {@link * FieldObject#fields}. * @param {function} [Super] - Parent class of the returned subclass. * @returns {function} - FieldObject subclass constructor. */ static define(FIELDS, Super = FieldObject) { class DefinedObject extends Super { get FIELDS() { return FIELDS; } static get FIELDS() { return FIELDS; } } Object.keys(FIELDS).forEach(key => { const index = FIELDS[key]; Object.defineProperty(DefinedObject.prototype, toTitleCase(key), { get() { return this.fields[index]; } }); }); return DefinedObject; } } /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/squeak/fields.js": /*!*****************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/squeak/fields.js ***! \*****************************************************************/ /*! exports provided: Field, value, Value, Header, Reference, BuiltinObjectHeader, FieldObjectHeader */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Field", function() { return Field; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "value", function() { return valueOf; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Value", function() { return Value; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Header", function() { return Header; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Reference", function() { return Reference; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BuiltinObjectHeader", function() { return BuiltinObjectHeader; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FieldObjectHeader", function() { return FieldObjectHeader; }); /* harmony import */ var _ids__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./ids */ "./node_modules/scratch-sb1-converter/src/squeak/ids.js"); /** * An abstract value contained in a `.sb` file. * * `.sb` files are made up of two blocks of Fields. Each field in the binary * file defines its "class" and is possibly followed by some binary data * depending on the class. Each class explicitly defines what follows. Knowing * all the possible classes each block can be broken up into a series of Field * objects. */ class Field { /** * @param {TYPES} classId - The class identifier of this Field. * @param {number} position - Byte position in the `.sb` file. */ constructor(classId, position) { /** * The class identifier of this Field. * @type {TYPES} */ this.classId = classId; /** * Byte position in the `.sb` file. * @type {number} */ this.position = position; } } const valueOf = obj => { if (typeof obj === 'object' && obj) return obj.valueOf(); return obj; }; /** * A concrete value contained in a `.sb` file. * @extends Field */ class Value extends Field { /** * @param {TYPES} classId - The class identifier of this Field. * @param {number} position - Byte position in the `.sb` file. * @param {*} value - A value decoded according to `classId` from an `.sb` * file. */ constructor(classId, position, value) { super(classId, position); /** * A value decoded according to `classId` from an `.sb` file. * @type {*} */ this.value = value; } valueOf() { return this.value; } toJSON() { if (this.classId === _ids__WEBPACK_IMPORTED_MODULE_0__["TYPES"].TRANSLUCENT_COLOR || this.classId === _ids__WEBPACK_IMPORTED_MODULE_0__["TYPES"].COLOR) { // TODO: Can colors be 32 bit in scratch-packets? return this.value & 0xffffff; } return this.value; } toString() { return this.value; } } /** * A header for a FieldObject representing its class and how many fields are in * the object. * * The `size` of a header is the number of Fields that appear in the byte * stream after the header that are related to the header. That set of `size` * length Fields make up a FieldObject of `classId` passed to this header. * @extends Field */ class Header extends Field { /** * @param {TYPES} classId - The class identifier of this Field. * @param {number} position - Byte position in the `.sb` file. * @param {number} size - The number of fields to collect. */ constructor(classId, position, size) { super(classId, position); /** * The number of fields to collect. * @type {number} */ this.size = size; } } /** * A integer reference of an object in an array produced by TypeIterator of * Values and FieldObjects. * @extends Field */ class Reference extends Field { /** * @param {TYPES} classId - The class identifier of this Field. * @param {number} position - Byte position in the `.sb` file. * @param {number} index - The index this Reference refers to. */ constructor(classId, position, index) { super(classId, position); /** * The index this Reference refers to. * @type {number} */ this.index = index; } valueOf() { return "Ref(".concat(this.index, ")"); } } /** * An object header of 0 size. * @extends Header */ class BuiltinObjectHeader extends Header { constructor(classId, position) { super(classId, position, 0); } } /** * An object header with an id more than 99, a version, and a size. The version * and size appear in the `sb` file as one byte for version followed by another * byte for the size. * @extends Header */ class FieldObjectHeader extends Header { /** * @param {TYPES} classId - The class identifier of this Field. * @param {number} position - Byte position in the `.sb` file. * @param {number} version - The version of this instance of a certain * value. * @param {number} size - The number of fields in this object. */ constructor(classId, position, version, size) { super(classId, position, size); /** * The version of this instance of a certain value. * @type {number} */ this.version = version; } } /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/squeak/ids.js": /*!**************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/squeak/ids.js ***! \**************************************************************/ /*! exports provided: TYPES, TYPE_NAMES */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TYPES", function() { return TYPES; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TYPE_NAMES", function() { return TYPE_NAMES; }); /** * A numeric identifier for each possible class of {@link Field} that can be in * a `.sb` file. * @enum {number} */ const TYPES = { /** A `null` {@link Value}. No data is stored after the class id. */ NULL: 1, /** A `true` {@link Value}. No data is stored after the class id. */ TRUE: 2, /** A `false` {@link Value}. No data is stored after the class id. */ FALSE: 3, /** A small integer {@link Value}. The next 4 bytes represent an integer. */ SMALL_INT: 4, /** A small integer {@link Value}. The next 2 bytes represent an integer. */ SMALL_INT_16: 5, /** A large integer {@link Value}. The value is a variable number of bytes. * The next byte defines the number of bytes after that represent the * integer. The integer's bytes are stored least value first (little * endian). */ LARGE_INT_POSITIVE: 6, /** A large integer {@link Value}. The value is a variable number of bytes. * The next byte defines the number of bytes after that represent the * integer. The integer's bytes are stored least value first (little * endian). */ LARGE_INT_NEGATIVE: 7, /** A floating point {@link Value}. The next 8 bytes are stored as a double * precision floating point value. */ FLOATING: 8, /** A ascii string {@link Value}. The next 4 bytes defines the number of * following bytes that make up the string. */ STRING: 9, /** A ascii string {@link Value}. The next 4 bytes defines the number of * following bytes that make up the string. */ SYMBOL: 10, /** A sequence of bytes ({@link Value}). The next 4 bytes defines the * number of bytes in the sequence. */ BYTES: 11, /** A sequence of 16 bit samples ({@link Value}). The next 4 bytes defines * the number of samples in the sequence. */ SOUND: 12, /** A sequence of 32 bit color integers ({@link Value}). The next 4 bytes * defines the number of colors in the bitmap. */ BITMAP: 13, /** A utf8 string {@link Value}. The next 4 bytes defines the number of * bytes used by the string. */ UTF8: 14, /** An array {@link Header}. The next 4 bytes defines the following number * of fields in the array. */ ARRAY: 20, /** An array {@link Header}. The next 4 bytes defines the following number * of fields in the array. */ ORDERED_COLLECTION: 21, /** An array {@link Header}. The next 4 bytes defines the following number * of fields in the array. */ SET: 22, /** An array {@link Header}. The next 4 bytes defines the following number * of fields in the array. */ IDENTITY_SET: 23, /** A dictionary {@link Header}. The next 4 bytes defines the following * number of key/value field pairs in the dictionary. */ DICTIONARY: 24, /** A dictionary {@link Header}. The next 4 bytes defines the following * number of key/value field pairs in the dictionary. */ IDENTITY_DICTIONARY: 25, /** A color {@link Value}. The next 4 bytes represents the color. */ COLOR: 30, /** A color {@link Value}. The next 4 bytes represents the red, green, and * blue subpixels. The following byte represents the alpha. */ TRANSLUCENT_COLOR: 31, /** A 2 field point {@link Header}. The next 2 fields are the x and y * values of this point. */ POINT: 32, /** A 4 field rectangle {@link Header}. The next 4 fields are the x, y, x2, * y2 values of this rectangle. */ RECTANGLE: 33, /** A 5 field image {@link Header}. The next 5 fields are the width, * height, bit depth, unused, and bytes. */ FORM: 34, /** A 6 field image {@link Header}. The next 6 fields are the width, * height, bit depth, unsued, bytes and colormap. */ SQUEAK: 35, /** An object {@link Reference} to a position in the top level array of fields in a * block. */ OBJECT_REF: 99, /** A variable {@link FieldObjectHeader}. */ MORPH: 100, /** A variable {@link FieldObjectHeader}. */ ALIGNMENT: 104, /** A variable {@link FieldObjectHeader}. * * In Scratch 2 this is called String. To reduce confusion in the set of * types, this is called STATIC_STRING in this converter. */ STATIC_STRING: 105, /** A variable {@link FieldObjectHeader}. */ UPDATING_STRING: 106, /** A variable {@link FieldObjectHeader}. */ SAMPLED_SOUND: 109, /** A variable {@link FieldObjectHeader}. */ IMAGE_MORPH: 110, /** A variable {@link FieldObjectHeader}. */ SPRITE: 124, /** A variable {@link FieldObjectHeader}. */ STAGE: 125, /** A variable {@link FieldObjectHeader}. */ WATCHER: 155, /** A variable {@link FieldObjectHeader}. */ IMAGE_MEDIA: 162, /** A variable {@link FieldObjectHeader}. */ SOUND_MEDIA: 164, /** A variable {@link FieldObjectHeader}. */ MULTILINE_STRING: 171, /** A variable {@link FieldObjectHeader}. */ WATCHER_READOUT_FRAME: 173, /** A variable {@link FieldObjectHeader}. */ WATCHER_SLIDER: 174, /** A variable {@link FieldObjectHeader}. */ LIST_WATCHER: 175 }; /** * A inverted map of TYPES. Map id numbers to their string names. * @type {object.} */ const TYPE_NAMES = Object.entries(TYPES).reduce((carry, [key, value]) => { carry[value] = key; return carry; }, {}); /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/squeak/reference-fixer.js": /*!**************************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/squeak/reference-fixer.js ***! \**************************************************************************/ /*! exports provided: ReferenceFixer */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ReferenceFixer", function() { return ReferenceFixer; }); /* harmony import */ var _fields__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./fields */ "./node_modules/scratch-sb1-converter/src/squeak/fields.js"); class ReferenceFixer { constructor(table) { this.table = Array.from(table); this.fixed = this.fix(this.table); } fix() { const fixed = []; for (let i = 0; i < this.table.length; i++) { this.fixItem(this.table[i]); fixed.push(this.table[i]); } return fixed; } fixItem(item) { if (typeof item.fields !== 'undefined') { item = item.fields; } if (Array.isArray(item)) { for (let i = 0; i < item.length; i++) { item[i] = this.deref(item[i]); } } } deref(ref) { if (ref instanceof _fields__WEBPACK_IMPORTED_MODULE_0__["Reference"]) { return this.table[ref.index - 1]; } return ref; } } /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/squeak/type-iterator.js": /*!************************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/squeak/type-iterator.js ***! \************************************************************************/ /*! exports provided: TypeIterator */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TypeIterator", function() { return TypeIterator; }); /* harmony import */ var _fields__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./fields */ "./node_modules/scratch-sb1-converter/src/squeak/fields.js"); /* harmony import */ var _field_object__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./field-object */ "./node_modules/scratch-sb1-converter/src/squeak/field-object.js"); /* harmony import */ var _types__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./types */ "./node_modules/scratch-sb1-converter/src/squeak/types.js"); class TypeIterator { constructor(valueIterator) { this.valueIterator = valueIterator; } [Symbol.iterator]() { return this; } next() { const nextHeader = this.valueIterator.next(); if (nextHeader.done) { return nextHeader; } const header = nextHeader.value; const { classId } = header; let value = header; if (header instanceof _fields__WEBPACK_IMPORTED_MODULE_0__["Header"]) { value = []; for (let i = 0; i < header.size; i++) { value.push(this.next().value); } } if (_types__WEBPACK_IMPORTED_MODULE_2__["FIELD_OBJECT_CONTRUCTORS"][classId] !== null || header instanceof _fields__WEBPACK_IMPORTED_MODULE_0__["FieldObjectHeader"]) { const constructor = _types__WEBPACK_IMPORTED_MODULE_2__["FIELD_OBJECT_CONTRUCTORS"][header.classId] || _field_object__WEBPACK_IMPORTED_MODULE_1__["FieldObject"]; value = new constructor({ classId: header.classId, version: header.version, fields: value }); } return { value, done: false }; } } /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/squeak/types.js": /*!****************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/squeak/types.js ***! \****************************************************************/ /*! exports provided: PointData, RectangleData, ImageData, StageData, SpriteData, TextDetailsData, ImageMediaData, UncompressedData, SoundMediaData, ListWatcherData, AlignmentData, MorphData, StaticStringData, UpdatingStringData, WatcherReadoutFrameData, WATCHER_MODES, WatcherData, FIELD_OBJECT_CONTRUCTORS */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointData", function() { return PointData; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RectangleData", function() { return RectangleData; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImageData", function() { return ImageData; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StageData", function() { return StageData; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpriteData", function() { return SpriteData; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextDetailsData", function() { return TextDetailsData; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImageMediaData", function() { return ImageMediaData; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UncompressedData", function() { return UncompressedData; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SoundMediaData", function() { return SoundMediaData; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ListWatcherData", function() { return ListWatcherData; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AlignmentData", function() { return AlignmentData; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MorphData", function() { return MorphData; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StaticStringData", function() { return StaticStringData; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UpdatingStringData", function() { return UpdatingStringData; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WatcherReadoutFrameData", function() { return WatcherReadoutFrameData; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WATCHER_MODES", function() { return WATCHER_MODES; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WatcherData", function() { return WatcherData; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FIELD_OBJECT_CONTRUCTORS", function() { return FIELD_OBJECT_CONTRUCTORS; }); /* harmony import */ var _coders_crc32__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../coders/crc32 */ "./node_modules/scratch-sb1-converter/src/coders/crc32.js"); /* harmony import */ var _coders_squeak_image__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../coders/squeak-image */ "./node_modules/scratch-sb1-converter/src/coders/squeak-image.js"); /* harmony import */ var _coders_squeak_sound__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../coders/squeak-sound */ "./node_modules/scratch-sb1-converter/src/coders/squeak-sound.js"); /* harmony import */ var _coders_wav_file__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../coders/wav-file */ "./node_modules/scratch-sb1-converter/src/coders/wav-file.js"); /* harmony import */ var _field_object__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./field-object */ "./node_modules/scratch-sb1-converter/src/squeak/field-object.js"); /* harmony import */ var _fields__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./fields */ "./node_modules/scratch-sb1-converter/src/squeak/fields.js"); /* harmony import */ var _ids__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./ids */ "./node_modules/scratch-sb1-converter/src/squeak/ids.js"); /* harmony import */ var js_md5__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! js-md5 */ "./node_modules/js-md5/src/md5.js"); /* harmony import */ var js_md5__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(js_md5__WEBPACK_IMPORTED_MODULE_7__); /** * @extends FieldObject */ class PointData extends _field_object__WEBPACK_IMPORTED_MODULE_4__["FieldObject"].define({ /** * @memberof PointData# * @type {Value} */ X: 0, /** * @memberof PointData# * @type {Value} */ Y: 1 }) {} class RectangleData extends _field_object__WEBPACK_IMPORTED_MODULE_4__["FieldObject"].define({ X: 0, Y: 1, X2: 2, Y2: 3 }) { get width() { return this.x2 - this.x; } get height() { return this.y2 - this.y; } } const _bgra2rgbaInPlace = uint8a => { for (let i = 0; i < uint8a.length; i += 4) { const r = uint8a[i + 2]; const b = uint8a[i + 0]; uint8a[i + 2] = b; uint8a[i + 0] = r; } return uint8a; }; /** * @extends FieldObject */ class ImageData extends _field_object__WEBPACK_IMPORTED_MODULE_4__["FieldObject"].define({ /** * @memberof ImageData# * @type {Value} */ WIDTH: 0, /** * @memberof ImageData# * @type {Value} */ HEIGHT: 1, /** * @memberof ImageData# * @type {Value} */ DEPTH: 2, /** * @memberof ImageData# * @type {Value} */ BYTES: 4, /** * @memberof ImageData# * @type {Value} */ COLORMAP: 5 }) { /** * @type {Uint8Array} */ get decoded() { if (!this._decoded) { this._decoded = _bgra2rgbaInPlace(new Uint8Array(new _coders_squeak_image__WEBPACK_IMPORTED_MODULE_1__["SqueakImage"]().decode(this.width.value, this.height.value, this.depth.value, this.bytes.value, this.colormap && this.colormap.map(color => color.valueOf())).buffer)); } return this._decoded; } /** * @type {string} */ get extension() { return 'uncompressed'; } } class StageData extends _field_object__WEBPACK_IMPORTED_MODULE_4__["FieldObject"].define({ STAGE_CONTENTS: 2, OBJ_NAME: 6, VARS: 7, BLOCKS_BIN: 8, IS_CLONE: 9, MEDIA: 10, CURRENT_COSTUME: 11, ZOOM: 12, H_PAN: 13, V_PAN: 14, OBSOLETE_SAVED_STATE: 15, SPRITE_ORDER_IN_LIBRARY: 16, VOLUME: 17, TEMPO_BPM: 18, SCENE_STATES: 19, LISTS: 20 }) { get spriteOrderInLibrary() { return this.fields[this.FIELDS.SPRITE_ORDER_IN_LIBRARY] || null; } get tempoBPM() { return this.fields[this.FIELDS.TEMPO_BPM] || 0; } get lists() { return this.fields[this.FIELDS.LISTS] || []; } } class SpriteData extends _field_object__WEBPACK_IMPORTED_MODULE_4__["FieldObject"].define({ BOX: 0, PARENT: 1, COLOR: 3, VISIBLE: 4, OBJ_NAME: 6, VARS: 7, BLOCKS_BIN: 8, IS_CLONE: 9, MEDIA: 10, CURRENT_COSTUME: 11, VISIBILITY: 12, SCALE_POINT: 13, ROTATION_DEGREES: 14, ROTATION_STYLE: 15, VOLUME: 16, TEMPO_BPM: 17, DRAGGABLE: 18, SCENE_STATES: 19, LISTS: 20 }) { get scratchX() { return this.box.x + this.currentCostume.rotationCenter.x - 240; } get scratchY() { return 180 - (this.box.y + this.currentCostume.rotationCenter.y); } get visible() { return (this.fields[this.FIELDS.VISIBLE] & 1) === 0; } get tempoBPM() { return this.fields[this.FIELDS.TEMPO_BPM] || 0; } get lists() { return this.fields[this.FIELDS.LISTS] || []; } } class TextDetailsData extends _field_object__WEBPACK_IMPORTED_MODULE_4__["FieldObject"].define({ RECTANGLE: 0, FONT: 8, COLOR: 9, LINES: 11 }) {} class ImageMediaData extends _field_object__WEBPACK_IMPORTED_MODULE_4__["FieldObject"].define({ COSTUME_NAME: 0, BITMAP: 1, ROTATION_CENTER: 2, TEXT_DETAILS: 3, BASE_LAYER_DATA: 4, OLD_COMPOSITE: 5 }) { get image() { if (this.oldComposite instanceof ImageData) { return this.oldComposite; } if (this.baseLayerData.value) { return null; } return this.bitmap; } get width() { if (this.image === null) { return -1; } return this.image.width; } get height() { if (this.image === null) { return -1; } return this.image.height; } get rawBytes() { if (this.image === null) { return this.baseLayerData.value.slice(); } return this.image.bytes.value; } get decoded() { if (this.image === null) { return this.baseLayerData.value.slice(); } return this.image.decoded; } get crc() { if (!this._crc) { const crc = new _coders_crc32__WEBPACK_IMPORTED_MODULE_0__["CRC32"]().update(new Uint8Array(new Uint32Array([this.bitmap.width]).buffer)).update(new Uint8Array(new Uint32Array([this.bitmap.height]).buffer)).update(new Uint8Array(new Uint32Array([this.bitmap.depth]).buffer)).update(this.rawBytes); this._crc = crc.digest; } return this._crc; } get extension() { if (this.oldComposite instanceof ImageData) return 'uncompressed'; if (this.baseLayerData.value) return 'jpg'; return 'uncompressed'; } toString() { return "ImageMediaData \"".concat(this.costumeName, "\""); } } class UncompressedData extends _field_object__WEBPACK_IMPORTED_MODULE_4__["FieldObject"].define({ DATA: 3, RATE: 4 }) {} const reverseBytes16 = input => { const uint8a = new Uint8Array(input); for (let i = 0; i < uint8a.length; i += 2) { uint8a[i] = input[i + 1]; uint8a[i + 1] = input[i]; } return uint8a; }; class SoundMediaData extends _field_object__WEBPACK_IMPORTED_MODULE_4__["FieldObject"].define({ NAME: 0, UNCOMPRESSED: 1, RATE: 4, BITS_PER_SAMPLE: 5, DATA: 6 }) { get rate() { if (this.uncompressed.data.value.length !== 0) { return this.uncompressed.rate; } return this.fields[this.FIELDS.RATE]; } get rawBytes() { if (this.data && this.data.value) { return this.data.value; } return this.uncompressed.data.value; } get decoded() { if (!this._decoded) { if (this.data && this.data.value) { this._decoded = new _coders_squeak_sound__WEBPACK_IMPORTED_MODULE_2__["SqueakSound"](this.bitsPerSample.value).decode(this.data.value); } else { this._decoded = new Int16Array(reverseBytes16(this.uncompressed.data.value.slice()).buffer); } } return this._decoded; } get crc() { if (!this._crc) { this._crc = new _coders_crc32__WEBPACK_IMPORTED_MODULE_0__["CRC32"]().update(new Uint32Array([this.rate])).update(this.rawBytes).digest; } return this._crc; } get sampleCount() { if (this.data && this.data.value) { return _coders_squeak_sound__WEBPACK_IMPORTED_MODULE_2__["SqueakSound"].samples(this.bitsPerSample.value, this.data.value); } return this.uncompressed.data.value.length / 2; } get extension() { return 'pcm'; } get wavEncodedData() { if (!this._wavEncodedData) { this._wavEncodedData = new Uint8Array(_coders_wav_file__WEBPACK_IMPORTED_MODULE_3__["WAVFile"].encode(this.decoded, { sampleRate: this.rate && this.rate.value })); } return this._wavEncodedData; } get md5() { if (!this._md5) { this._md5 = js_md5__WEBPACK_IMPORTED_MODULE_7___default()(this.wavEncodedData); } return this._md5; } toString() { return "SoundMediaData \"".concat(this.name, "\""); } } class ListWatcherData extends _field_object__WEBPACK_IMPORTED_MODULE_4__["FieldObject"].define({ BOX: 0, HIDDEN_WHEN_NULL: 1, LIST_NAME: 8, CONTENTS: 9, TARGET: 10 }) { get x() { if (Object(_fields__WEBPACK_IMPORTED_MODULE_5__["value"])(this.hiddenWhenNull) === null) return 5; return this.box.x + 1; } get y() { if (Object(_fields__WEBPACK_IMPORTED_MODULE_5__["value"])(this.hiddenWhenNull) === null) return 5; return this.box.y + 1; } get width() { return this.box.width - 2; } get height() { return this.box.height - 2; } } class AlignmentData extends _field_object__WEBPACK_IMPORTED_MODULE_4__["FieldObject"].define({ BOX: 0, PARENT: 1, FRAMES: 2, COLOR: 3, DIRECTION: 8, ALIGNMENT: 9 }) {} class MorphData extends _field_object__WEBPACK_IMPORTED_MODULE_4__["FieldObject"].define({ BOX: 0, PARENT: 1, COLOR: 3 }) {} class StaticStringData extends _field_object__WEBPACK_IMPORTED_MODULE_4__["FieldObject"].define({ BOX: 0, COLOR: 3, VALUE: 8 }) {} class UpdatingStringData extends _field_object__WEBPACK_IMPORTED_MODULE_4__["FieldObject"].define({ BOX: 0, READOUT_FRAME: 1, COLOR: 3, FONT: 6, VALUE: 8, TARGET: 10, CMD: 11, PARAM: 13 }) {} class WatcherReadoutFrameData extends _field_object__WEBPACK_IMPORTED_MODULE_4__["FieldObject"].define({ BOX: 0 }) {} const WATCHER_MODES = { NORMAL: 1, LARGE: 2, SLIDER: 3, TEXT: 4 }; class WatcherData extends _field_object__WEBPACK_IMPORTED_MODULE_4__["FieldObject"].define({ BOX: 0, TARGET: 1, SHAPE: 2, READOUT: 14, READOUT_FRAME: 15, SLIDER: 16, ALIGNMENT: 17, SLIDER_MIN: 20, SLIDER_MAX: 21 }) { get x() { return this.box.x; } get y() { return this.box.y; } get mode() { if (Object(_fields__WEBPACK_IMPORTED_MODULE_5__["value"])(this.slider) === null) { if (this.readoutFrame.box.height <= 14) { return WATCHER_MODES.NORMAL; } return WATCHER_MODES.LARGE; } return WATCHER_MODES.SLIDER; } get isDiscrete() { return Math.floor(this.sliderMin) === this.sliderMin && Math.floor(this.sliderMax) === this.sliderMax && Math.floor(this.readout.value) === this.readout.value; } } const FIELD_OBJECT_CONTRUCTOR_PROTOS = { [_ids__WEBPACK_IMPORTED_MODULE_6__["TYPES"].POINT]: PointData, [_ids__WEBPACK_IMPORTED_MODULE_6__["TYPES"].RECTANGLE]: RectangleData, [_ids__WEBPACK_IMPORTED_MODULE_6__["TYPES"].FORM]: ImageData, [_ids__WEBPACK_IMPORTED_MODULE_6__["TYPES"].SQUEAK]: ImageData, [_ids__WEBPACK_IMPORTED_MODULE_6__["TYPES"].SAMPLED_SOUND]: UncompressedData, [_ids__WEBPACK_IMPORTED_MODULE_6__["TYPES"].SPRITE]: SpriteData, [_ids__WEBPACK_IMPORTED_MODULE_6__["TYPES"].STAGE]: StageData, [_ids__WEBPACK_IMPORTED_MODULE_6__["TYPES"].IMAGE_MEDIA]: ImageMediaData, [_ids__WEBPACK_IMPORTED_MODULE_6__["TYPES"].SOUND_MEDIA]: SoundMediaData, [_ids__WEBPACK_IMPORTED_MODULE_6__["TYPES"].ALIGNMENT]: AlignmentData, [_ids__WEBPACK_IMPORTED_MODULE_6__["TYPES"].MORPH]: MorphData, [_ids__WEBPACK_IMPORTED_MODULE_6__["TYPES"].WATCHER_READOUT_FRAME]: WatcherReadoutFrameData, [_ids__WEBPACK_IMPORTED_MODULE_6__["TYPES"].STATIC_STRING]: StaticStringData, [_ids__WEBPACK_IMPORTED_MODULE_6__["TYPES"].UPDATING_STRING]: UpdatingStringData, [_ids__WEBPACK_IMPORTED_MODULE_6__["TYPES"].WATCHER]: WatcherData, [_ids__WEBPACK_IMPORTED_MODULE_6__["TYPES"].LIST_WATCHER]: ListWatcherData }; const FIELD_OBJECT_CONTRUCTORS = Array.from({ length: 256 }, (_, i) => FIELD_OBJECT_CONTRUCTOR_PROTOS[i] || null); /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/to-sb2/fake-zip.js": /*!*******************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/to-sb2/fake-zip.js ***! \*******************************************************************/ /*! exports provided: FakeZipFile, FakeZip, toSb2FakeZipApi */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FakeZipFile", function() { return FakeZipFile; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FakeZip", function() { return FakeZip; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "toSb2FakeZipApi", function() { return toSb2FakeZipApi; }); /* harmony import */ var _util_assert__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../util/assert */ "./node_modules/scratch-sb1-converter/src/util/assert.js"); /* harmony import */ var _coders_png_file__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../coders/png-file */ "./node_modules/scratch-sb1-converter/src/coders/png-file.js"); class FakeZipFile { constructor(file) { this.file = file; } async(outputType) { Object(_util_assert__WEBPACK_IMPORTED_MODULE_0__["assert"])(outputType === 'uint8array', 'SB1FakeZipFile only supports uint8array'); return Promise.resolve(this.file.bytes); } } class FakeZip { constructor(files) { this.files = files; } file(file) { if (file in this.files) { return new FakeZipFile(this.files[file]); } } } const toSb2ImageExtension = imageMedia => { if (imageMedia.extension === 'uncompressed') { return 'png'; } return 'jpg'; }; const toSb2ImageMedia = imageMedia => { if (imageMedia.extension === 'uncompressed') { return new Uint8Array(_coders_png_file__WEBPACK_IMPORTED_MODULE_1__["PNGFile"].encode(imageMedia.width, imageMedia.height, imageMedia.decoded)); } return imageMedia.decoded; }; const toSb2SoundMedia = soundMedia => soundMedia.wavEncodedData; const toSb2FakeZipApi = ({ images, sounds }) => { const files = {}; let index = 0; for (const image of images) { files["".concat(index++, ".").concat(toSb2ImageExtension(image))] = { bytes: toSb2ImageMedia(image) }; } index = 0; for (const sound of sounds) { files["".concat(index++, ".wav")] = { bytes: toSb2SoundMedia(sound) }; } return new FakeZip(files); }; /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/to-sb2/json-generator.js": /*!*************************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/to-sb2/json-generator.js ***! \*************************************************************************/ /*! exports provided: toSb2Json */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "toSb2Json", function() { return toSb2Json; }); /* harmony import */ var _squeak_types__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../squeak/types */ "./node_modules/scratch-sb1-converter/src/squeak/types.js"); /* harmony import */ var js_md5__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! js-md5 */ "./node_modules/js-md5/src/md5.js"); /* harmony import */ var js_md5__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(js_md5__WEBPACK_IMPORTED_MODULE_1__); /* eslint no-use-before-define:1 */ // https://github.com/LLK/scratch-flash/blob/cb5f42f039ef633710faf9c63b69e8368b280372/src/blocks/BlockIO.as#L292-L308 const fixMouseEdgeRef = block => { const oldVal = String(block[block.length - 1]); const last = block.length - 1; if (oldVal === 'mouse') { block[last] = '_mouse_'; } else if (oldVal === 'edge') { block[last] = '_edge_'; } else if (block[block.length - 1] instanceof _squeak_types__WEBPACK_IMPORTED_MODULE_0__["StageData"]) { block[last] = '_stage_'; } return block; }; const sb1SpecMap = { // https://github.com/LLK/scratch-flash/blob/cb5f42f039ef633710faf9c63b69e8368b280372/src/blocks/BlockIO.as#L197-L199 'getParam': ([a, b, c, d]) => [a, b, c, d || 'r'], // https://github.com/LLK/scratch-flash/blob/cb5f42f039ef633710faf9c63b69e8368b280372/src/blocks/BlockIO.as#L200-L212 'changeVariable': block => [block[2], block[1], block[3]], // https://github.com/LLK/scratch-flash/blob/cb5f42f039ef633710faf9c63b69e8368b280372/src/blocks/BlockIO.as#L213-L219 'EventHatMorph': block => { if (String(block[1]) === 'Scratch-StartClicked') { return ['whenGreenFlag']; } return ['whenIReceive', block[1]]; }, // https://github.com/LLK/scratch-flash/blob/cb5f42f039ef633710faf9c63b69e8368b280372/src/blocks/BlockIO.as#L220-L222 'MouseClickEventHatMorph': () => ['whenClicked'], // https://github.com/LLK/scratch-flash/blob/cb5f42f039ef633710faf9c63b69e8368b280372/src/blocks/BlockIO.as#L223-L226 'KeyEventHatMorph': block => ['whenKeyPressed', block[1]], // https://github.com/LLK/scratch-flash/blob/cb5f42f039ef633710faf9c63b69e8368b280372/src/blocks/BlockIO.as#L227-L235 'stopScripts': block => { if (String(block[1]) === 'other scripts') { return [block[0], 'other scripts in sprite']; } return block; }, // https://github.com/LLK/scratch-flash/blob/cb5f42f039ef633710faf9c63b69e8368b280372/src/blocks/BlockIO.as#L249-L253 'abs': block => ['computeFunction:of:', 'abs', block[1]], // https://github.com/LLK/scratch-flash/blob/cb5f42f039ef633710faf9c63b69e8368b280372/src/blocks/BlockIO.as#L254-L258 'sqrt': block => ['computeFunction:of:', 'sqrt', block[1]], // https://github.com/LLK/scratch-flash/blob/cb5f42f039ef633710faf9c63b69e8368b280372/src/blocks/BlockIO.as#L137 '\\\\': block => ['%', ...block.slice(1)], // https://github.com/LLK/scratch-flash/blob/cb5f42f039ef633710faf9c63b69e8368b280372/src/blocks/BlockIO.as#L259-L262 'doReturn': () => ['stopScripts', 'this script'], // https://github.com/LLK/scratch-flash/blob/cb5f42f039ef633710faf9c63b69e8368b280372/src/blocks/BlockIO.as#L263-L266 'stopAll': () => ['stopScripts', 'all'], // https://github.com/LLK/scratch-flash/blob/cb5f42f039ef633710faf9c63b69e8368b280372/src/blocks/BlockIO.as#L267-L270 'showBackground:': block => ['startScene', block[1]], // https://github.com/LLK/scratch-flash/blob/cb5f42f039ef633710faf9c63b69e8368b280372/src/blocks/BlockIO.as#L271-L273 'nextBackground': () => ['nextScene'], // https://github.com/LLK/scratch-flash/blob/cb5f42f039ef633710faf9c63b69e8368b280372/src/blocks/BlockIO.as#L274-L282 'doForeverIf': block => ['doForever', [['doIf', block[1], block[2]]]], 'getAttribute:of:': fixMouseEdgeRef, 'gotoSpriteOrMouse:': fixMouseEdgeRef, 'distanceTo:': fixMouseEdgeRef, 'pointTowards:': fixMouseEdgeRef, 'touching:': fixMouseEdgeRef }; const valueOf = obj => { if (typeof obj === 'object' && obj) return obj.valueOf(); return obj; }; const toSb2Json = root => { const { info, stageData, images, sounds } = root; const pairs = array => { const _pairs = []; for (let i = 0; i < array.length; i += 2) { _pairs.push([array[i], array[i + 1]]); } return _pairs; }; const toSb2JsonVariable = ([name, value]) => ({ name, value, isPersistent: false }); const toSb2JsonList = ([, { listName, contents, x, y, width, height, hiddenWhenNull }]) => ({ listName: listName, contents: contents, isPersistent: false, x: x, y: y, width: width, height: height, visible: valueOf(hiddenWhenNull) !== null }); // TODO: Implement toSb2JsonWatcher // const toSb2JsonWatcher = watcher => { // // }; // TODO: Implement toSb2JsonListWatcher // const toSb2JsonListWatcher = listWatcher => { // // }; const toSb2JsonSound = soundMediaData => { const soundID = sounds.findIndex(sound => sound.crc === soundMediaData.crc); return { soundName: soundMediaData.name, soundID, md5: "".concat(soundMediaData.md5, ".wav"), sampleCount: soundMediaData.sampleCount, rate: soundMediaData.rate, format: '' }; }; const toSb2ImageExtension = imageMedia => { if (imageMedia.extension === 'uncompressed') { return 'png'; } return 'jpg'; }; const toSb2JsonCostume = imageMediaData => { const baseLayerID = images.findIndex(image => image.crc === imageMediaData.crc); return { costumeName: imageMediaData.costumeName, baseLayerID, baseLayerMD5: "".concat(js_md5__WEBPACK_IMPORTED_MODULE_1___default()(imageMediaData.rawBytes), ".").concat(toSb2ImageExtension(imageMediaData)), bitmapResolution: 1, rotationCenterX: imageMediaData.rotationCenter.x, rotationCenterY: imageMediaData.rotationCenter.y }; }; const toSb2JsonBlock = blockData => { let output = blockData.map(toSb2JsonBlockArg); const spec = sb1SpecMap[output[0]]; if (spec) { output = spec(output); } return output; }; const toSb2JsonStack = stackData => stackData.map(toSb2JsonBlock); const toSb2JsonBlockArg = argData => { if (argData instanceof _squeak_types__WEBPACK_IMPORTED_MODULE_0__["SpriteData"]) { return argData.objName; } else if (Array.isArray(argData)) { if (argData.length === 0 || Array.isArray(argData[0])) { return toSb2JsonStack(argData); } return toSb2JsonBlock(argData); } return argData; }; const toSb2JsonScript = scriptData => [scriptData[0].x, scriptData[0].y, toSb2JsonStack(scriptData[1])]; const toSb2JsonSprite = spriteData => { const rawCostumes = spriteData.media.filter(data => data instanceof _squeak_types__WEBPACK_IMPORTED_MODULE_0__["ImageMediaData"]); const rawSounds = spriteData.media.filter(data => data instanceof _squeak_types__WEBPACK_IMPORTED_MODULE_0__["SoundMediaData"]); return { objName: spriteData.objName, variables: pairs(spriteData.vars).map(toSb2JsonVariable), lists: pairs(spriteData.lists).map(toSb2JsonList), scripts: spriteData.blocksBin.map(toSb2JsonScript), costumes: rawCostumes.map(toSb2JsonCostume), currentCostumeIndex: rawCostumes.findIndex(image => image.crc === spriteData.currentCostume.crc), sounds: rawSounds.map(toSb2JsonSound), scratchX: spriteData.scratchX, scratchY: spriteData.scratchY, scale: spriteData.scalePoint.x, direction: Math.round(spriteData.rotationDegrees * 1e6) / 1e6 - 270, rotationStyle: spriteData.rotationStyle, isDraggable: spriteData.draggable, indexInLibrary: stageData.spriteOrderInLibrary.indexOf(spriteData), visible: spriteData.visible, spriteInfo: {} }; }; const toSb2JsonChild = child => { if (child instanceof _squeak_types__WEBPACK_IMPORTED_MODULE_0__["SpriteData"]) { return toSb2JsonSprite(child); } return null; }; const toSb2JsonStage = _stageData => { const rawCostumes = _stageData.media.filter(data => data instanceof _squeak_types__WEBPACK_IMPORTED_MODULE_0__["ImageMediaData"]); const rawSounds = _stageData.media.filter(data => data instanceof _squeak_types__WEBPACK_IMPORTED_MODULE_0__["SoundMediaData"]); return { objName: _stageData.objName, variables: pairs(_stageData.vars).map(toSb2JsonVariable), lists: pairs(_stageData.lists).map(toSb2JsonList), scripts: _stageData.blocksBin.map(toSb2JsonScript), costumes: rawCostumes.map(toSb2JsonCostume), currentCostumeIndex: rawCostumes.findIndex(image => image.crc === _stageData.currentCostume.crc), sounds: rawSounds.map(toSb2JsonSound), // TODO: Where does this come from? Is it always the same for SB1? penLayerMD5: '5c81a336fab8be57adc039a8a2b33ca9.png', penLayerID: 0, tempoBPM: _stageData.tempoBPM, videoAlpha: 0.5, children: _stageData.stageContents.map(toSb2JsonChild).filter(Boolean).reverse() }; }; const toSb2JsonInfo = _info => { const obj = {}; for (let i = 0; i < _info.length; i += 2) { if (String(_info[i]) === 'thumbnail') continue; obj[String(_info[i])] = String(_info[i + 1]); } return obj; }; return JSON.parse(JSON.stringify(Object.assign(toSb2JsonStage(stageData), { info: toSb2JsonInfo(info) }))); }; /***/ }), /***/ "./node_modules/scratch-sb1-converter/src/util/assert.js": /*!***************************************************************!*\ !*** ./node_modules/scratch-sb1-converter/src/util/assert.js ***! \***************************************************************/ /*! exports provided: assert, AssertionError, ValidationError */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "assert", function() { return assert; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AssertionError", function() { return AssertionError; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ValidationError", function() { return ValidationError; }); /** * A `scratch-sb1-converter` assertion. */ class AssertionError extends Error {} /** * A `scratch-sb1-converter` validation error. */ class ValidationError extends AssertionError {} const assert = function assert(test, message) { if (!test) throw new AssertionError(message); }; assert.validate = function (test, message) { if (!test) throw new ValidationError(message); }; /***/ }), /***/ "./node_modules/scratch-storage/node_modules/base64-js/index.js": /*!**********************************************************************!*\ !*** ./node_modules/scratch-storage/node_modules/base64-js/index.js ***! \**********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; exports.byteLength = byteLength exports.toByteArray = toByteArray exports.fromByteArray = fromByteArray var lookup = [] var revLookup = [] var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' for (var i = 0, len = code.length; i < len; ++i) { lookup[i] = code[i] revLookup[code.charCodeAt(i)] = i } // Support decoding URL-safe base64 strings, as Node.js does. // See: https://en.wikipedia.org/wiki/Base64#URL_applications revLookup['-'.charCodeAt(0)] = 62 revLookup['_'.charCodeAt(0)] = 63 function getLens (b64) { var len = b64.length if (len % 4 > 0) { throw new Error('Invalid string. Length must be a multiple of 4') } // Trim off extra bytes after placeholder bytes are found // See: https://github.com/beatgammit/base64-js/issues/42 var validLen = b64.indexOf('=') if (validLen === -1) validLen = len var placeHoldersLen = validLen === len ? 0 : 4 - (validLen % 4) return [validLen, placeHoldersLen] } // base64 is 4/3 + up to two characters of the original data function byteLength (b64) { var lens = getLens(b64) var validLen = lens[0] var placeHoldersLen = lens[1] return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen } function _byteLength (b64, validLen, placeHoldersLen) { return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen } function toByteArray (b64) { var tmp var lens = getLens(b64) var validLen = lens[0] var placeHoldersLen = lens[1] var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)) var curByte = 0 // if there are placeholders, only get up to the last complete 4 chars var len = placeHoldersLen > 0 ? validLen - 4 : validLen for (var i = 0; i < len; i += 4) { tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)] arr[curByte++] = (tmp >> 16) & 0xFF arr[curByte++] = (tmp >> 8) & 0xFF arr[curByte++] = tmp & 0xFF } if (placeHoldersLen === 2) { tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4) arr[curByte++] = tmp & 0xFF } if (placeHoldersLen === 1) { tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2) arr[curByte++] = (tmp >> 8) & 0xFF arr[curByte++] = tmp & 0xFF } return arr } function tripletToBase64 (num) { return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F] } function encodeChunk (uint8, start, end) { var tmp var output = [] for (var i = start; i < end; i += 3) { tmp = ((uint8[i] << 16) & 0xFF0000) + ((uint8[i + 1] << 8) & 0xFF00) + (uint8[i + 2] & 0xFF) output.push(tripletToBase64(tmp)) } return output.join('') } function fromByteArray (uint8) { var tmp var len = uint8.length var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes var parts = [] var maxChunkLength = 16383 // must be multiple of 3 // go through the array every three bytes, we'll deal with trailing stuff later for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { parts.push(encodeChunk( uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength) )) } // pad the end with zeros, but make sure to not forget the extra bytes if (extraBytes === 1) { tmp = uint8[len - 1] parts.push( lookup[tmp >> 2] + lookup[(tmp << 4) & 0x3F] + '==' ) } else if (extraBytes === 2) { tmp = (uint8[len - 2] << 8) + uint8[len - 1] parts.push( lookup[tmp >> 10] + lookup[(tmp >> 4) & 0x3F] + lookup[(tmp << 2) & 0x3F] + '=' ) } return parts.join('') } /***/ }), /***/ "./node_modules/scratch-storage/src/Asset.js": /*!***************************************************!*\ !*** ./node_modules/scratch-storage/src/Asset.js ***! \***************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { // Use JS implemented TextDecoder and TextEncoder if it is not provided by the // browser. if (typeof TextDecoder === 'undefined' || typeof TextEncoder === 'undefined') { // Wait to require the text encoding polyfill until we know it's needed. // eslint-disable-next-line global-require __webpack_require__(/*! fastestsmallesttextencoderdecoder */ "./node_modules/fastestsmallesttextencoderdecoder/EncoderDecoderTogether.min.js"); } const md5 = __webpack_require__(/*! js-md5 */ "./node_modules/js-md5/src/md5.js"); /** * The maximum length of a chunk before encoding it into base64. * * 32766 is a multiple of 3 so btoa does not need to use padding characters * except for the final chunk where that is fine. 32766 is also close to * 32768 so it is close to a size an memory allocator would prefer. * @const {number} */ const BTOA_CHUNK_MAX_LENGTH = 32766; /** * An array cache of bytes to characters. * @const {?Array.} */ let fromCharCode = null; const memoizedStrings = {}; const memoizedToString = (assetId, data) => { if (!Object.prototype.hasOwnProperty.call(memoizedStrings, assetId)) { if (typeof btoa === 'undefined') { // Use a library that does not need btoa to run. /* eslint-disable-next-line global-require */ const base64js = __webpack_require__(/*! base64-js */ "./node_modules/scratch-storage/node_modules/base64-js/index.js"); memoizedStrings[assetId] = base64js.fromByteArray(data); } else { // Native btoa is faster than javascript translation. Use js to // create a "binary" string and btoa to encode it. if (fromCharCode === null) { // Cache the first 256 characters for input byte values. fromCharCode = new Array(256); for (let i = 0; i < 256; i++) { fromCharCode[i] = String.fromCharCode(i); } } const { length } = data; let s = ''; // Iterate over chunks of the binary data. for (let i = 0, e = 0; i < length; i = e) { // Create small chunks to cause more small allocations and // less large allocations. e = Math.min(e + BTOA_CHUNK_MAX_LENGTH, length); let s_ = ''; for (let j = i; j < e; j += 1) { s_ += fromCharCode[data[j]]; } // Encode the latest chunk so the we create one big output // string instead of creating a big input string and then // one big output string. /* global btoa */ s += btoa(s_); } memoizedStrings[assetId] = s; } } return memoizedStrings[assetId]; }; const assetIdCounts = {}; /* globals FinalizationRegistry */ const finalizationRegistry = typeof FinalizationRegistry === 'function' ? new FinalizationRegistry(assetId => { const count = assetIdCounts[assetId]; if (count === 1) { // This was the last reference delete assetIdCounts[assetId]; delete memoizedStrings[assetId]; } else { assetIdCounts[assetId] = count - 1; } }) : null; const addFinalizationReference = finalizationRegistry ? asset => { const assetId = asset.assetId; const count = assetIdCounts[assetId] || 0; assetIdCounts[assetId] = count + 1; finalizationRegistry.register(asset, assetId); } : () => {}; class Asset { /** * Construct an Asset. * @param {AssetType} assetType - The type of this asset (sound, image, etc.) * @param {string} assetId - The ID of this asset. * @param {DataFormat} [dataFormat] - The format of the data (WAV, PNG, etc.); required iff `data` is present. * @param {Buffer} [data] - The in-memory data for this asset; optional. * @param {bool} [generateId] - Whether to create id from an md5 hash of data */ constructor(assetType, assetId, dataFormat, data, generateId) { /** @type {AssetType} */ this.assetType = assetType; /** @type {string} */ this.assetId = assetId; this.setData(data, dataFormat || assetType.runtimeFormat, generateId); /** @type {Asset[]} */ this.dependencies = []; addFinalizationReference(this); } setData(data, dataFormat, generateId) { if (data && !dataFormat) { throw new Error('Data provided without specifying its format'); } /** @type {DataFormat} */ this.dataFormat = dataFormat; /** @type {Buffer} */ this.data = data; if (generateId) this.assetId = md5(data); // Mark as clean only if set is being called without generateId // If a new id is being generated, mark this asset as not clean this.clean = !generateId; } /** * @returns {string} - This asset's data, decoded as text. */ decodeText() { const decoder = new TextDecoder(); return decoder.decode(this.data); } /** * Same as `setData` but encodes text first. * @param {string} data - the text data to encode and store. * @param {DataFormat} dataFormat - the format of the data (DataFormat.SVG for example). * @param {bool} generateId - after setting data, set the id to an md5 of the data? */ encodeTextData(data, dataFormat, generateId) { const encoder = new TextEncoder(); this.setData(encoder.encode(data), dataFormat, generateId); } /** * @param {string} [contentType] - Optionally override the content type to be included in the data URI. * @returns {string} - A data URI representing the asset's data. */ encodeDataURI(contentType) { contentType = contentType || this.assetType.contentType; return "data:".concat(contentType, ";base64,").concat(memoizedToString(this.assetId, this.data)); } } module.exports = Asset; /***/ }), /***/ "./node_modules/scratch-storage/src/AssetType.js": /*!*******************************************************!*\ !*** ./node_modules/scratch-storage/src/AssetType.js ***! \*******************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const DataFormat = __webpack_require__(/*! ./DataFormat */ "./node_modules/scratch-storage/src/DataFormat.js"); /** * Enumeration of the supported asset types. * @type {Object.} * @typedef {Object} AssetType - Information about a supported asset type. * @property {string} contentType - the MIME type associated with this kind of data. Useful for data URIs, etc. * @property {string} name - The human-readable name of this asset type. * @property {DataFormat} runtimeFormat - The default format used for runtime, in-memory storage of this asset. For * example, a project stored in SB2 format on disk will be returned as JSON when loaded into memory. * @property {boolean} immutable - Indicates if the asset id is determined by the asset content. */ const AssetType = { ImageBitmap: { contentType: 'image/png', name: 'ImageBitmap', runtimeFormat: DataFormat.PNG, immutable: true }, ImageVector: { contentType: 'image/svg+xml', name: 'ImageVector', runtimeFormat: DataFormat.SVG, immutable: true }, Project: { contentType: 'application/json', name: 'Project', runtimeFormat: DataFormat.JSON, immutable: false }, Sound: { contentType: 'audio/x-wav', name: 'Sound', runtimeFormat: DataFormat.WAV, immutable: true }, Sprite: { contentType: 'application/json', name: 'Sprite', runtimeFormat: DataFormat.JSON, immutable: true } }; module.exports = AssetType; /***/ }), /***/ "./node_modules/scratch-storage/src/BuiltinHelper.js": /*!***********************************************************!*\ !*** ./node_modules/scratch-storage/src/BuiltinHelper.js ***! \***********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(Buffer) {const md5 = __webpack_require__(/*! js-md5 */ "./node_modules/js-md5/src/md5.js"); const Asset = __webpack_require__(/*! ./Asset */ "./node_modules/scratch-storage/src/Asset.js"); const AssetType = __webpack_require__(/*! ./AssetType */ "./node_modules/scratch-storage/src/AssetType.js"); const DataFormat = __webpack_require__(/*! ./DataFormat */ "./node_modules/scratch-storage/src/DataFormat.js"); const Helper = __webpack_require__(/*! ./Helper */ "./node_modules/scratch-storage/src/Helper.js"); /** * @typedef {object} BuiltinAssetRecord * @property {AssetType} type - The type of the asset. * @property {DataFormat} format - The format of the asset's data. * @property {?string} id - The asset's unique ID. * @property {Buffer} data - The asset's data. */ /** * @type {BuiltinAssetRecord[]} */ const DefaultAssets = [{ type: AssetType.ImageBitmap, format: DataFormat.PNG, id: null, data: Buffer.from(__webpack_require__(/*! arraybuffer-loader!./builtins/defaultBitmap.png */ "./node_modules/arraybuffer-loader/index.js!./node_modules/scratch-storage/src/builtins/defaultBitmap.png") // eslint-disable-line global-require ) }, { type: AssetType.Sound, format: DataFormat.WAV, id: null, data: Buffer.from(__webpack_require__(/*! arraybuffer-loader!./builtins/defaultSound.wav */ "./node_modules/arraybuffer-loader/index.js!./node_modules/scratch-storage/src/builtins/defaultSound.wav") // eslint-disable-line global-require ) }, { type: AssetType.ImageVector, format: DataFormat.SVG, id: null, data: Buffer.from(__webpack_require__(/*! arraybuffer-loader!./builtins/defaultVector.svg */ "./node_modules/arraybuffer-loader/index.js!./node_modules/scratch-storage/src/builtins/defaultVector.svg") // eslint-disable-line global-require ) }]; /** * @type {BuiltinAssetRecord[]} */ const BuiltinAssets = DefaultAssets.concat([]); class BuiltinHelper extends Helper { constructor(parent) { super(parent); /** * In-memory storage for all built-in assets. * @type {Object.} Maps asset type to a map of asset ID to actual assets. * @typedef {Object.} AssetIdMap - Maps asset ID to asset. */ this.assets = {}; BuiltinAssets.forEach(assetRecord => { assetRecord.id = this._store(assetRecord.type, assetRecord.format, assetRecord.data, assetRecord.id); }); } /** * Call `setDefaultAssetId` on the parent `ScratchStorage` instance to register all built-in default assets. */ registerDefaultAssets() { const numAssets = DefaultAssets.length; for (let assetIndex = 0; assetIndex < numAssets; ++assetIndex) { const assetRecord = DefaultAssets[assetIndex]; this.parent.setDefaultAssetId(assetRecord.type, assetRecord.id); } } /** * Synchronously fetch a cached asset for a given asset id. Returns null if not found. * @param {string} assetId - The id for the asset to fetch. * @returns {?Asset} The asset for assetId, if it exists. */ get(assetId) { let asset = null; if (Object.prototype.hasOwnProperty.call(this.assets, assetId)) { /** @type{BuiltinAssetRecord} */ const assetRecord = this.assets[assetId]; asset = new Asset(assetRecord.type, assetRecord.id, assetRecord.format, assetRecord.data); } return asset; } /** * Alias for store (old name of store) * @deprecated Use BuiltinHelper.store * @param {AssetType} assetType - The type of the asset to cache. * @param {DataFormat} dataFormat - The dataFormat of the data for the cached asset. * @param {Buffer} data - The data for the cached asset. * @param {string} id - The id for the cached asset. * @returns {string} The calculated id of the cached asset, or the supplied id if the asset is mutable. */ cache(assetType, dataFormat, data, id) { return this.store(assetType, dataFormat, data, id); } /** * Deprecated external API for _store * @deprecated Not for external use. Create assets and keep track of them outside of the storage instance. * @param {AssetType} assetType - The type of the asset to cache. * @param {DataFormat} dataFormat - The dataFormat of the data for the cached asset. * @param {Buffer} data - The data for the cached asset. * @param {(string|number)} id - The id for the cached asset. * @returns {string} The calculated id of the cached asset, or the supplied id if the asset is mutable. */ store(assetType, dataFormat, data, id) { return this._store(assetType, dataFormat, data, id); } /** * Cache an asset for future lookups by ID. * @param {AssetType} assetType - The type of the asset to cache. * @param {DataFormat} dataFormat - The dataFormat of the data for the cached asset. * @param {Buffer} data - The data for the cached asset. * @param {(string|number)} id - The id for the cached asset. * @returns {string} The calculated id of the cached asset, or the supplied id if the asset is mutable. */ _store(assetType, dataFormat, data, id) { if (!dataFormat) throw new Error('Data cached without specifying its format'); if (id !== '' && id !== null && typeof id !== 'undefined') { if (Object.prototype.hasOwnProperty.call(this.assets, id) && assetType.immutable) return id; } else if (assetType.immutable) { id = md5(data); } else { throw new Error('Tried to cache data without an id'); } this.assets[id] = { type: assetType, format: dataFormat, id: id, data: data }; return id; } /** * Fetch an asset but don't process dependencies. * @param {AssetType} assetType - The type of asset to fetch. * @param {string} assetId - The ID of the asset to fetch: a project ID, MD5, etc. * @return {?Promise.} A promise for the contents of the asset. */ load(assetType, assetId) { if (!this.get(assetId)) { // Return null immediately so Storage can quickly move to trying the // next helper. return null; } return Promise.resolve(this.get(assetId)); } } module.exports = BuiltinHelper; /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../../buffer/index.js */ "./node_modules/buffer/index.js").Buffer)) /***/ }), /***/ "./node_modules/scratch-storage/src/DataFormat.js": /*!********************************************************!*\ !*** ./node_modules/scratch-storage/src/DataFormat.js ***! \********************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /** * Enumeration of the supported data formats. * @enum {string} */ const DataFormat = { JPG: 'jpg', JSON: 'json', MP3: 'mp3', PNG: 'png', SB2: 'sb2', SB3: 'sb3', SVG: 'svg', WAV: 'wav' }; module.exports = DataFormat; /***/ }), /***/ "./node_modules/scratch-storage/src/FetchTool.js": /*!*******************************************************!*\ !*** ./node_modules/scratch-storage/src/FetchTool.js ***! \*******************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const _excluded = ["url"], _excluded2 = ["url", "withCredentials"]; function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } /* eslint-env browser */ const saferFetchAsArrayBuffer = __webpack_require__(/*! ./safer-fetch */ "./node_modules/scratch-storage/src/safer-fetch.js"); /** * Get and send assets with the fetch standard web api. */ class FetchTool { /** * Is get supported? false if the environment does not support fetch. * @returns {boolean} Is get supported? */ get isGetSupported() { return typeof fetch !== 'undefined'; } /** * Request data from a server with fetch. * @param {{url:string}} reqConfig - Request configuration for data to get. * @param {{method:string}} options - Additional options to configure fetch. * @returns {Promise.} Resolve to Buffer of data from server. */ get(_ref) { let { url } = _ref, options = _objectWithoutProperties(_ref, _excluded); return saferFetchAsArrayBuffer(url, Object.assign({ method: 'GET' }, options)).then(arrayBufferOrNull => { if (arrayBufferOrNull) { return new Uint8Array(arrayBufferOrNull); } return arrayBufferOrNull; }); } /** * Is sending supported? false if the environment does not support sending * with fetch. * @returns {boolean} Is sending supported? */ get isSendSupported() { return typeof fetch !== 'undefined'; } /** * Send data to a server with fetch. * @param {Request} reqConfig - Request configuration for data to send. * @returns {Promise.} Server returned metadata. */ send(_ref2) { let { url, withCredentials = false } = _ref2, options = _objectWithoutProperties(_ref2, _excluded2); return fetch(url, Object.assign({ credentials: withCredentials ? 'include' : 'omit' }, options)).then(response => { if (response.ok) return response.text(); return Promise.reject(response.status); }); } } module.exports = FetchTool; /***/ }), /***/ "./node_modules/scratch-storage/src/FetchWorkerTool.js": /*!*************************************************************!*\ !*** ./node_modules/scratch-storage/src/FetchWorkerTool.js ***! \*************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const _excluded = ["url"]; function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } /** * Get and send assets with a worker that uses fetch. */ class PrivateFetchWorkerTool { constructor() { /** * What does the worker support of the APIs we need? * @type {{fetch:boolean}} */ this._workerSupport = { fetch: typeof fetch !== 'undefined' }; /** * A possible error occurred standing up the worker. * @type {!Error} */ this._supportError = null; /** * The worker that runs fetch and returns data for us. * @type {!Worker} */ this.worker = null; /** * A map of ids to fetch job objects. * @type {object} */ this.jobs = {}; try { if (this.isGetSupported) { // eslint-disable-next-line global-require const FetchWorker = __webpack_require__(/*! worker-loader?{"inline":true,"fallback":true}!./FetchWorkerTool.worker */ "./node_modules/worker-loader/dist/cjs.js?{\"inline\":true,\"fallback\":true}!./node_modules/scratch-storage/src/FetchWorkerTool.worker.js"); this.worker = new FetchWorker(); this.worker.addEventListener('message', ({ data }) => { if (data.support) { this._workerSupport = data.support; return; } for (const message of data) { if (this.jobs[message.id]) { if (message.error) { this.jobs[message.id].reject(message.error); } else { this.jobs[message.id].resolve(message.buffer); } delete this.jobs[message.id]; } } }); } } catch (error) { this._supportError = error; } } /** * Is get supported? * * false if the environment does not workers, fetch, or fetch from inside a * worker. Finding out the worker supports fetch is asynchronous and will * guess that it does if the window does until the worker can inform us. * @returns {boolean} Is get supported? */ get isGetSupported() { return typeof Worker !== 'undefined' && this._workerSupport.fetch && !this._supportError; } /** * Request data from a server with a worker using fetch. * @param {{url:string}} reqConfig - Request configuration for data to get. * @param {{method:string}} options - Additional options to configure fetch. * @returns {Promise.} Resolve to Buffer of data from server. */ get(_ref) { let { url } = _ref, options = _objectWithoutProperties(_ref, _excluded); return new Promise((resolve, reject) => { // TODO: Use a Scratch standard ID generator ... const id = Math.random().toString(16).substring(2); this.worker.postMessage({ id, url, options: Object.assign({ method: 'GET' }, options) }); this.jobs[id] = { id, resolve, reject }; }) /* eslint no-confusing-arrow: ["error", {"allowParens": true}] */ .then(body => body ? new Uint8Array(body) : null); } /** * Is sending supported? always false for FetchWorkerTool. * @returns {boolean} Is sending supported? */ get isSendSupported() { return false; } /** * Send data to a server. * @throws {Error} A not implemented error. */ send() { throw new Error('Not implemented.'); } /** * Return a static PrivateFetchWorkerTool instance on demand. * @returns {PrivateFetchWorkerTool} A static PrivateFetchWorkerTool * instance */ static get instance() { if (!this._instance) { this._instance = new PrivateFetchWorkerTool(); } return this._instance; } } /** * Get and send assets with a worker that uses fetch. */ class PublicFetchWorkerTool { constructor() { /** * Shared instance of an internal worker. PublicFetchWorkerTool proxies * it. * @type {PrivateFetchWorkerTool} */ this.inner = PrivateFetchWorkerTool.instance; } /** * Is get supported? * @returns {boolean} Is get supported? */ get isGetSupported() { return this.inner.isGetSupported; } /** * Request data from a server with a worker that uses fetch. * @param {{url:string}} reqConfig - Request configuration for data to get. * @returns {Promise.} Resolve to Buffer of data from server. */ get(reqConfig) { return this.inner.get(reqConfig); } /** * Is sending supported? * @returns {boolean} Is sending supported? */ get isSendSupported() { return false; } /** * Send data to a server with a worker that uses fetch. * @throws {Error} A not implemented error. */ send() { throw new Error('Not implemented.'); } } module.exports = PublicFetchWorkerTool; /***/ }), /***/ "./node_modules/scratch-storage/src/Helper.js": /*!****************************************************!*\ !*** ./node_modules/scratch-storage/src/Helper.js ***! \****************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /** * Base class for asset load/save helpers. * @abstract */ class Helper { constructor(parent) { this.parent = parent; } /** * Fetch an asset but don't process dependencies. * @param {AssetType} assetType - The type of asset to fetch. * @param {string} assetId - The ID of the asset to fetch: a project ID, MD5, etc. * @param {DataFormat} dataFormat - The file format / file extension of the asset to fetch: PNG, JPG, etc. * @return {Promise.} A promise for the contents of the asset. */ load(assetType, assetId, dataFormat) { return Promise.reject(new Error("No asset of type ".concat(assetType, " for ID ").concat(assetId, " with format ").concat(dataFormat))); } } module.exports = Helper; /***/ }), /***/ "./node_modules/scratch-storage/src/ProxyTool.js": /*!*******************************************************!*\ !*** ./node_modules/scratch-storage/src/ProxyTool.js ***! \*******************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const FetchWorkerTool = __webpack_require__(/*! ./FetchWorkerTool */ "./node_modules/scratch-storage/src/FetchWorkerTool.js"); const FetchTool = __webpack_require__(/*! ./FetchTool */ "./node_modules/scratch-storage/src/FetchTool.js"); /** * @typedef {object} Request * @property {string} url * @property {*} body * @property {string} method * @property {boolean} withCredentials */ /** * Get and send assets with other tools in sequence. */ class ProxyTool { constructor(filter = ProxyTool.TOOL_FILTER.ALL) { let tools; if (filter === ProxyTool.TOOL_FILTER.READY) { tools = [new FetchTool()]; } else { tools = [new FetchWorkerTool(), new FetchTool()]; } /** * Sequence of tools to proxy. * @type {Array.} */ this.tools = tools; } /** * Is get supported? false if all proxied tool return false. * @returns {boolean} Is get supported? */ get isGetSupported() { return this.tools.some(tool => tool.isGetSupported); } /** * Request data from with one of the proxied tools. * @param {Request} reqConfig - Request configuration for data to get. * @returns {Promise.} Resolve to Buffer of data from server. */ get(reqConfig) { let toolIndex = 0; const nextTool = err => { const tool = this.tools[toolIndex++]; if (!tool) { throw err; } if (!tool.isGetSupported) { return nextTool(err); } return tool.get(reqConfig).catch(nextTool); }; return nextTool(); } /** * Is sending supported? false if all proxied tool return false. * @returns {boolean} Is sending supported? */ get isSendSupported() { return this.tools.some(tool => tool.isSendSupported); } /** * Send data to a server with one of the proxied tools. * @param {Request} reqConfig - Request configuration for data to send. * @returns {Promise.} Server returned metadata. */ send(reqConfig) { let toolIndex = 0; const nextTool = err => { const tool = this.tools[toolIndex++]; if (!tool) { throw err; } if (!tool.isSendSupported) { return nextTool(err); } return tool.send(reqConfig).catch(nextTool); }; return nextTool(); } } /** * Constant values that filter the set of tools in a ProxyTool instance. * @enum {string} */ ProxyTool.TOOL_FILTER = { /** * Use all tools. */ ALL: 'all', /** * Use tools that are ready right now. */ READY: 'ready' }; module.exports = ProxyTool; /***/ }), /***/ "./node_modules/scratch-storage/src/ScratchStorage.js": /*!************************************************************!*\ !*** ./node_modules/scratch-storage/src/ScratchStorage.js ***! \************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const BuiltinHelper = __webpack_require__(/*! ./BuiltinHelper */ "./node_modules/scratch-storage/src/BuiltinHelper.js"); const WebHelper = __webpack_require__(/*! ./WebHelper */ "./node_modules/scratch-storage/src/WebHelper.js"); const _Asset = __webpack_require__(/*! ./Asset */ "./node_modules/scratch-storage/src/Asset.js"); const _AssetType = __webpack_require__(/*! ./AssetType */ "./node_modules/scratch-storage/src/AssetType.js"); const _DataFormat = __webpack_require__(/*! ./DataFormat */ "./node_modules/scratch-storage/src/DataFormat.js"); class ScratchStorage { constructor() { this.defaultAssetId = {}; this.builtinHelper = new BuiltinHelper(this); this.webHelper = new WebHelper(this); this.builtinHelper.registerDefaultAssets(this); this._helpers = [{ helper: this.builtinHelper, priority: 100 }, { helper: this.webHelper, priority: -100 }]; } /** * @return {Asset} - the `Asset` class constructor. * @constructor */ get Asset() { return _Asset; } /** * @return {AssetType} - the list of supported asset types. * @constructor */ get AssetType() { return _AssetType; } /** * @return {DataFormat} - the list of supported data formats. * @constructor */ get DataFormat() { return _DataFormat; } /** * @deprecated Please use the `Asset` member of a storage instance instead. * @return {Asset} - the `Asset` class constructor. * @constructor */ static get Asset() { return _Asset; } /** * @deprecated Please use the `AssetType` member of a storage instance instead. * @return {AssetType} - the list of supported asset types. * @constructor */ static get AssetType() { return _AssetType; } /** * Add a storage helper to this manager. Helpers with a higher priority number will be checked first when loading * or storing assets. For comparison, the helper for built-in assets has `priority=100` and the default web helper * has `priority=-100`. The relative order of helpers with equal priorities is undefined. * @param {Helper} helper - the helper to be added. * @param {number} [priority] - the priority for this new helper (default: 0). */ addHelper(helper, priority = 0) { this._helpers.push({ helper, priority }); this._helpers.sort((a, b) => b.priority - a.priority); } /** * Synchronously fetch a cached asset from built-in storage. Assets are cached when they are loaded. * @param {string} assetId - The id of the asset to fetch. * @returns {?Asset} The asset, if it exists. */ get(assetId) { return this.builtinHelper.get(assetId); } /** * Deprecated API for caching built-in assets. Use createAsset. * @param {AssetType} assetType - The type of the asset to cache. * @param {DataFormat} dataFormat - The dataFormat of the data for the cached asset. * @param {Buffer} data - The data for the cached asset. * @param {string} id - The id for the cached asset. * @returns {string} The calculated id of the cached asset, or the supplied id if the asset is mutable. */ cache(assetType, dataFormat, data, id) { return this.builtinHelper._store(assetType, dataFormat, data, id); } /** * Construct an Asset, and optionally generate an md5 hash of its data to create an id * @param {AssetType} assetType - The type of the asset to cache. * @param {DataFormat} dataFormat - The dataFormat of the data for the cached asset. * @param {Buffer} data - The data for the cached asset. * @param {string} [id] - The id for the cached asset. * @param {bool} [generateId] - flag to set id to an md5 hash of data if `id` isn't supplied * @returns {Asset} generated Asset with `id` attribute set if not supplied */ createAsset(assetType, dataFormat, data, id, generateId) { if (!dataFormat) throw new Error('Tried to create asset without a dataFormat'); return new _Asset(assetType, id, dataFormat, data, generateId); } /** * Register a web-based source for assets. Sources will be checked in order of registration. * @param {Array.} types - The types of asset provided by this source. * @param {UrlFunction} getFunction - A function which computes a GET URL from an Asset. * @param {UrlFunction} createFunction - A function which computes a POST URL for asset data. * @param {UrlFunction} updateFunction - A function which computes a PUT URL for asset data. */ addWebStore(types, getFunction, createFunction, updateFunction) { this.webHelper.addStore(types, getFunction, createFunction, updateFunction); } /** * Register a web-based source for assets. Sources will be checked in order of registration. * @deprecated Please use addWebStore * @param {Array.} types - The types of asset provided by this source. * @param {UrlFunction} urlFunction - A function which computes a GET URL from an Asset. */ addWebSource(types, urlFunction) { this.addWebStore(types, urlFunction); } /** * TODO: Should this be removed in favor of requesting an asset with `null` as the ID? * @param {AssetType} type - Get the default ID for assets of this type. * @return {?string} The ID of the default asset of the given type, if any. */ getDefaultAssetId(type) { if (Object.prototype.hasOwnProperty.call(this.defaultAssetId, type.name)) { return this.defaultAssetId[type.name]; } } /** * Set the default ID for a particular type of asset. This default asset will be used if a requested asset cannot * be found and automatic fallback is enabled. Ideally this should be an asset that is available locally or even * one built into this module. * TODO: Should this be removed in favor of requesting an asset with `null` as the ID? * @param {AssetType} type - The type of asset for which the default will be set. * @param {string} id - The default ID to use for this type of asset. */ setDefaultAssetId(type, id) { this.defaultAssetId[type.name] = id; } /** * Fetch an asset by type & ID. * @param {AssetType} assetType - The type of asset to fetch. This also determines which asset store to use. * @param {string} assetId - The ID of the asset to fetch: a project ID, MD5, etc. * @param {DataFormat} [dataFormat] - Optional: load this format instead of the AssetType's default. * @return {Promise.} A promise for the requested Asset. * If the promise is resolved with non-null, the value is the requested asset. * If the promise is resolved with null, the desired asset could not be found with the current asset sources. * If the promise is rejected, there was an error on at least one asset source. HTTP 404 does not count as an * error here, but (for example) HTTP 403 does. */ load(assetType, assetId, dataFormat) { /** @type {Helper[]} */ const helpers = this._helpers.map(x => x.helper); const errors = []; dataFormat = dataFormat || assetType.runtimeFormat; let helperIndex = 0; let helper; const tryNextHelper = err => { if (err) { // Track the error, but continue looking errors.push(err); } helper = helpers[helperIndex++]; if (helper) { const loading = helper.load(assetType, assetId, dataFormat); if (loading === null) { return tryNextHelper(); } // Note that other attempts may have logged errors; if this succeeds they will be suppressed. return loading // TODO: maybe some types of error should prevent trying the next helper? .catch(tryNextHelper); } else if (errors.length > 0) { // We looked through all the helpers and couldn't find the asset, AND // at least one thing went wrong while we were looking. return Promise.reject(errors); } // Nothing went wrong but we couldn't find the asset. return Promise.resolve(null); }; return tryNextHelper(); } /** * Store an asset by type & ID. * @param {AssetType} assetType - The type of asset to fetch. This also determines which asset store to use. * @param {?DataFormat} [dataFormat] - Optional: load this format instead of the AssetType's default. * @param {Buffer} data - Data to store for the asset * @param {?string} [assetId] - The ID of the asset to fetch: a project ID, MD5, etc. * @return {Promise.} A promise for asset metadata */ store(assetType, dataFormat, data, assetId) { dataFormat = dataFormat || assetType.runtimeFormat; return new Promise((resolve, reject) => this.webHelper.store(assetType, dataFormat, data, assetId).then(body => { this.builtinHelper._store(assetType, dataFormat, data, body.id); return resolve(body); }).catch(error => reject(error))); } } module.exports = ScratchStorage; /***/ }), /***/ "./node_modules/scratch-storage/src/WebHelper.js": /*!*******************************************************!*\ !*** ./node_modules/scratch-storage/src/WebHelper.js ***! \*******************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const Asset = __webpack_require__(/*! ./Asset */ "./node_modules/scratch-storage/src/Asset.js"); const Helper = __webpack_require__(/*! ./Helper */ "./node_modules/scratch-storage/src/Helper.js"); const ProxyTool = __webpack_require__(/*! ./ProxyTool */ "./node_modules/scratch-storage/src/ProxyTool.js"); const ensureRequestConfig = reqConfig => { if (typeof reqConfig === 'string') { return { url: reqConfig }; } return reqConfig; }; /** * @typedef {function} UrlFunction - A function which computes a URL from asset information. * @param {Asset} - The asset for which the URL should be computed. * @returns {(string|object)} - A string representing the URL for the asset request OR an object with configuration for * the underlying fetch call (necessary for configuring e.g. authentication) */ class WebHelper extends Helper { constructor(parent) { super(parent); /** * @type {Array.} * @typedef {object} StoreRecord * @property {Array.} types - The types of asset provided by this store, from AssetType's name field. * @property {UrlFunction} getFunction - A function which computes a URL from an Asset. * @property {UrlFunction} createFunction - A function which computes a URL from an Asset. * @property {UrlFunction} updateFunction - A function which computes a URL from an Asset. */ this.stores = []; /** * Set of tools to best load many assets in parallel. If one tool * cannot be used, it will use the next. * @type {ProxyTool} */ this.assetTool = new ProxyTool(); /** * Set of tools to best load project data in parallel with assets. This * tool set prefers tools that are immediately ready. Some tools have * to initialize before they can load files. * @type {ProxyTool} */ this.projectTool = new ProxyTool(ProxyTool.TOOL_FILTER.READY); } /** * Register a web-based source for assets. Sources will be checked in order of registration. * @deprecated Please use addStore * @param {Array.} types - The types of asset provided by this source. * @param {UrlFunction} urlFunction - A function which computes a URL from an Asset. */ addSource(types, urlFunction) { this.addStore(types, urlFunction); } /** * Register a web-based store for assets. Sources will be checked in order of registration. * @param {Array.} types - The types of asset provided by this store. * @param {UrlFunction} getFunction - A function which computes a GET URL for an Asset * @param {UrlFunction} createFunction - A function which computes a POST URL for an Asset * @param {UrlFunction} updateFunction - A function which computes a PUT URL for an Asset */ addStore(types, getFunction, createFunction, updateFunction) { this.stores.push({ types: types.map(assetType => assetType.name), get: getFunction, create: createFunction, update: updateFunction }); } /** * Fetch an asset but don't process dependencies. * @param {AssetType} assetType - The type of asset to fetch. * @param {string} assetId - The ID of the asset to fetch: a project ID, MD5, etc. * @param {DataFormat} dataFormat - The file format / file extension of the asset to fetch: PNG, JPG, etc. * @return {Promise.} A promise for the contents of the asset. */ load(assetType, assetId, dataFormat) { /** @type {Array.<{url:string, result:*}>} List of URLs attempted & errors encountered. */ const errors = []; const stores = this.stores.slice().filter(store => store.types.indexOf(assetType.name) >= 0); // New empty asset but it doesn't have data yet const asset = new Asset(assetType, assetId, dataFormat); let tool = this.assetTool; if (assetType.name === 'Project') { tool = this.projectTool; } let storeIndex = 0; const tryNextSource = err => { if (err) { errors.push(err); } const store = stores[storeIndex++]; /** @type {UrlFunction} */ const reqConfigFunction = store && store.get; if (reqConfigFunction) { const reqConfig = ensureRequestConfig(reqConfigFunction(asset)); if (reqConfig === false) { return tryNextSource(); } return tool.get(reqConfig).then(body => { if (body) { asset.setData(body, dataFormat); return asset; } return tryNextSource(); }).catch(tryNextSource); } else if (errors.length > 0) { return Promise.reject(errors); } // no stores matching asset return Promise.resolve(null); }; return tryNextSource(); } /** * Create or update an asset with provided data. The create function is called if no asset id is provided * @param {AssetType} assetType - The type of asset to create or update. * @param {?DataFormat} dataFormat - DataFormat of the data for the stored asset. * @param {Buffer} data - The data for the cached asset. * @param {?string} assetId - The ID of the asset to fetch: a project ID, MD5, etc. * @return {Promise.} A promise for the response from the create or update request */ store(assetType, dataFormat, data, assetId) { const asset = new Asset(assetType, assetId, dataFormat); // If we have an asset id, we should update, otherwise create to get an id const create = assetId === '' || assetId === null || typeof assetId === 'undefined'; // Use the first store with the appropriate asset type and url function const store = this.stores.filter(s => // Only use stores for the incoming asset type s.types.indexOf(assetType.name) !== -1 && ( // Only use stores that have a create function if this is a create request // or an update function if this is an update request create && s.create || s.update))[0]; const method = create ? 'post' : 'put'; if (!store) return Promise.reject(new Error('No appropriate stores')); let tool = this.assetTool; if (assetType.name === 'Project') { tool = this.projectTool; } const reqConfig = ensureRequestConfig(create ? store.create(asset) : store.update(asset)); const reqBodyConfig = Object.assign({ body: data, method }, reqConfig); return tool.send(reqBodyConfig).then(body => { // xhr makes it difficult to both send FormData and // automatically parse a JSON response. So try to parse // everything as JSON. if (typeof body === 'string') { try { body = JSON.parse(body); } catch (parseError) { // If it's not parseable, then we can't add the id even // if we want to, so stop here return body; } } return Object.assign({ id: body['content-name'] || assetId }, body); }); } } module.exports = WebHelper; /***/ }), /***/ "./node_modules/scratch-storage/src/index.js": /*!***************************************************!*\ !*** ./node_modules/scratch-storage/src/index.js ***! \***************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const ScratchStorage = __webpack_require__(/*! ./ScratchStorage */ "./node_modules/scratch-storage/src/ScratchStorage.js"); /** * Export for use with NPM & Node.js. * @type {ScratchStorage} */ module.exports = ScratchStorage; /***/ }), /***/ "./node_modules/scratch-storage/src/safer-fetch.js": /*!*********************************************************!*\ !*** ./node_modules/scratch-storage/src/safer-fetch.js ***! \*********************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /* eslint-env browser */ /* eslint-disable no-use-before-define */ // This throttles and retries fetch() to mitigate the effect of random network errors and // random browser errors (especially in Chrome) let currentFetches = 0; const queue = []; const startNextFetch = ([resolve, url, options]) => { let firstError; let failedAttempts = 0; const attemptToFetch = () => fetch(url, options).then(result => { // In a macOS WKWebView, requests from file: URLs to other file: URLs always have status: 0 and ok: false // even though the requests were successful. If the requested file doesn't exist, fetch() rejects instead. // We aren't aware of any other cases where fetch() can resolve with status 0, so this should be safe. if (result.ok || result.status === 0) return result.arrayBuffer(); if (result.status === 404) return null; return Promise.reject(result.status); }).then(buffer => { currentFetches--; checkStartNextFetch(); return buffer; }).catch(error => { console.warn("Attempt to fetch ".concat(url, " failed"), error); if (!firstError) { firstError = error; } if (failedAttempts < 2) { failedAttempts++; return new Promise(cb => setTimeout(cb, (failedAttempts + Math.random() - 1) * 5000)).then(attemptToFetch); } currentFetches--; checkStartNextFetch(); throw firstError; }); return resolve(attemptToFetch()); }; const checkStartNextFetch = () => { if (currentFetches < 100 && queue.length > 0) { currentFetches++; startNextFetch(queue.shift()); } }; const saferFetchAsArrayBuffer = (url, options) => new Promise(resolve => { queue.push([resolve, url, options]); checkStartNextFetch(); }); module.exports = saferFetchAsArrayBuffer; /***/ }), /***/ "./node_modules/scratch-svg-renderer/node_modules/base64-js/index.js": /*!***************************************************************************!*\ !*** ./node_modules/scratch-svg-renderer/node_modules/base64-js/index.js ***! \***************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; exports.byteLength = byteLength exports.toByteArray = toByteArray exports.fromByteArray = fromByteArray var lookup = [] var revLookup = [] var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' for (var i = 0, len = code.length; i < len; ++i) { lookup[i] = code[i] revLookup[code.charCodeAt(i)] = i } revLookup['-'.charCodeAt(0)] = 62 revLookup['_'.charCodeAt(0)] = 63 function placeHoldersCount (b64) { var len = b64.length if (len % 4 > 0) { throw new Error('Invalid string. Length must be a multiple of 4') } // the number of equal signs (place holders) // if there are two placeholders, than the two characters before it // represent one byte // if there is only one, then the three characters before it represent 2 bytes // this is just a cheap hack to not do indexOf twice return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0 } function byteLength (b64) { // base64 is 4/3 + up to two characters of the original data return (b64.length * 3 / 4) - placeHoldersCount(b64) } function toByteArray (b64) { var i, l, tmp, placeHolders, arr var len = b64.length placeHolders = placeHoldersCount(b64) arr = new Arr((len * 3 / 4) - placeHolders) // if there are placeholders, only get up to the last complete 4 chars l = placeHolders > 0 ? len - 4 : len var L = 0 for (i = 0; i < l; i += 4) { tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)] arr[L++] = (tmp >> 16) & 0xFF arr[L++] = (tmp >> 8) & 0xFF arr[L++] = tmp & 0xFF } if (placeHolders === 2) { tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4) arr[L++] = tmp & 0xFF } else if (placeHolders === 1) { tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2) arr[L++] = (tmp >> 8) & 0xFF arr[L++] = tmp & 0xFF } return arr } function tripletToBase64 (num) { return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F] } function encodeChunk (uint8, start, end) { var tmp var output = [] for (var i = start; i < end; i += 3) { tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) output.push(tripletToBase64(tmp)) } return output.join('') } function fromByteArray (uint8) { var tmp var len = uint8.length var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes var output = '' var parts = [] var maxChunkLength = 16383 // must be multiple of 3 // go through the array every three bytes, we'll deal with trailing stuff later for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) } // pad the end with zeros, but make sure to not forget the extra bytes if (extraBytes === 1) { tmp = uint8[len - 1] output += lookup[tmp >> 2] output += lookup[(tmp << 4) & 0x3F] output += '==' } else if (extraBytes === 2) { tmp = (uint8[len - 2] << 8) + (uint8[len - 1]) output += lookup[tmp >> 10] output += lookup[(tmp >> 4) & 0x3F] output += lookup[(tmp << 2) & 0x3F] output += '=' } parts.push(output) return parts.join('') } /***/ }), /***/ "./node_modules/scratch-svg-renderer/src/bitmap-adapter.js": /*!*****************************************************************!*\ !*** ./node_modules/scratch-svg-renderer/src/bitmap-adapter.js ***! \*****************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const base64js = __webpack_require__(/*! base64-js */ "./node_modules/scratch-svg-renderer/node_modules/base64-js/index.js"); /** * Adapts Scratch 2.0 bitmaps for use in scratch 3.0 */ class BitmapAdapter { /** * @param {?function} makeImage HTML image constructor. Tests can provide this. * @param {?function} makeCanvas HTML canvas constructor. Tests can provide this. */ constructor(makeImage, makeCanvas) { this._makeImage = makeImage ? makeImage : () => new Image(); this._makeCanvas = makeCanvas ? makeCanvas : () => document.createElement('canvas'); this.stageWidth = 480; this.stageHeight = 360; } setStageSize(width, height) { this.stageWidth = width; this.stageHeight = height; } /** * Return a canvas with the resized version of the given image, done using nearest-neighbor interpolation * @param {CanvasImageSource} image The image to resize * @param {int} newWidth The desired post-resize width of the image * @param {int} newHeight The desired post-resize height of the image * @returns {HTMLCanvasElement} A canvas with the resized image drawn on it. */ resize(image, newWidth, newHeight) { // We want to always resize using nearest-neighbor interpolation. However, canvas implementations are free to // use linear interpolation (or other "smooth" interpolation methods) when downscaling: // https://bugzilla.mozilla.org/show_bug.cgi?id=1360415 // It seems we can get around this by resizing in two steps: first width, then height. This will always result // in nearest-neighbor interpolation, even when downscaling. const stretchWidthCanvas = this._makeCanvas(); stretchWidthCanvas.width = newWidth; stretchWidthCanvas.height = image.height; let context = stretchWidthCanvas.getContext('2d'); context.imageSmoothingEnabled = false; context.drawImage(image, 0, 0, stretchWidthCanvas.width, stretchWidthCanvas.height); const stretchHeightCanvas = this._makeCanvas(); stretchHeightCanvas.width = newWidth; stretchHeightCanvas.height = newHeight; context = stretchHeightCanvas.getContext('2d'); context.imageSmoothingEnabled = false; context.drawImage(stretchWidthCanvas, 0, 0, stretchHeightCanvas.width, stretchHeightCanvas.height); return stretchHeightCanvas; } /** * Scratch 2.0 had resolution 1 and 2 bitmaps. All bitmaps in Scratch 3.0 are equivalent * to resolution 2 bitmaps. Therefore, converting a resolution 1 bitmap means doubling * it in width and height. * @param {!string} dataURI Base 64 encoded image data of the bitmap * @param {!function} callback Node-style callback that returns updated dataURI if conversion succeeded */ convertResolution1Bitmap(dataURI, callback) { const image = this._makeImage(); image.src = dataURI; image.onload = () => { callback(null, this.resize(image, image.width * 2, image.height * 2).toDataURL()); }; image.onerror = () => { callback('Image load failed'); }; } /** * Given width/height of an uploaded item, return width/height the image will be resized * to in Scratch 3.0 * @param {!number} oldWidth original width * @param {!number} oldHeight original height * @return {object} Array of new width, new height */ getResizedWidthHeight(oldWidth, oldHeight) { const STAGE_WIDTH = this.stageWidth; const STAGE_HEIGHT = this.stageHeight; const STAGE_RATIO = STAGE_WIDTH / STAGE_HEIGHT; // If both dimensions are smaller than or equal to corresponding stage dimension, // double both dimensions if (oldWidth <= STAGE_WIDTH && oldHeight <= STAGE_HEIGHT) { return { width: oldWidth * 2, height: oldHeight * 2 }; } // If neither dimension is larger than 2x corresponding stage dimension, // this is an in-between image, return it as is if (oldWidth <= STAGE_WIDTH * 2 && oldHeight <= STAGE_HEIGHT * 2) { return { width: oldWidth, height: oldHeight }; } const imageRatio = oldWidth / oldHeight; // Otherwise, figure out how to resize if (imageRatio >= STAGE_RATIO) { // Wide Image return { width: STAGE_WIDTH * 2, height: STAGE_WIDTH * 2 / imageRatio }; } // In this case we have either: // - A wide image, but not with as big a ratio between width and height, // making it so that fitting the width to double stage size would leave // the height too big to fit in double the stage height // - A square image that's still larger than the double at least // one of the stage dimensions, so pick the smaller of the two dimensions (to fit) // - A tall image // In any of these cases, resize the image to fit the height to double the stage height return { width: STAGE_HEIGHT * 2 * imageRatio, height: STAGE_HEIGHT * 2 }; } /** * Given bitmap data, resize as necessary. * @param {ArrayBuffer | string} fileData Base 64 encoded image data of the bitmap * @param {string} fileType The MIME type of this file * @returns {Promise} Resolves to resized image data Uint8Array */ importBitmap(fileData, fileType) { let dataURI = fileData; if (fileData instanceof ArrayBuffer) { dataURI = this.convertBinaryToDataURI(fileData, fileType); } return new Promise((resolve, reject) => { const image = this._makeImage(); image.src = dataURI; image.onload = () => { const newSize = this.getResizedWidthHeight(image.width, image.height); if (newSize.width === image.width && newSize.height === image.height) { // No change resolve(this.convertDataURIToBinary(dataURI)); } else { const resizedDataURI = this.resize(image, newSize.width, newSize.height).toDataURL(); resolve(this.convertDataURIToBinary(resizedDataURI)); } }; image.onerror = () => { reject('Image load failed'); }; }); } // TODO consolidate with scratch-vm/src/util/base64-util.js // From https://gist.github.com/borismus/1032746 convertDataURIToBinary(dataURI) { const BASE64_MARKER = ';base64,'; const base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length; const base64 = dataURI.substring(base64Index); const raw = window.atob(base64); const rawLength = raw.length; const array = new Uint8Array(new ArrayBuffer(rawLength)); for (let i = 0; i < rawLength; i++) { array[i] = raw.charCodeAt(i); } return array; } convertBinaryToDataURI(arrayBuffer, contentType) { return "data:".concat(contentType, ";base64,").concat(base64js.fromByteArray(new Uint8Array(arrayBuffer))); } } module.exports = BitmapAdapter; /***/ }), /***/ "./node_modules/scratch-svg-renderer/src/fixup-svg-string.js": /*!*******************************************************************!*\ !*** ./node_modules/scratch-svg-renderer/src/fixup-svg-string.js ***! \*******************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /** * Fixup svg string prior to parsing. * @param {!string} svgString String of the svg to fix. * @returns {!string} fixed svg that should be parseable. */ module.exports = function (svgString) { // Add root svg namespace if it does not exist. const svgAttrs = svgString.match(/]*>/); if (svgAttrs && svgAttrs[0].indexOf('xmlns=') === -1) { svgString = svgString.replace(']+?xlink:href=["'])data:img\/png/g, // use the captured ]+?xmlns:(?!xml=)[^ ]+=)"http:\/\/www.w3.org\/XML\/1998\/namespace"/g; if (svgString.match(xmlnsRegex) !== null) { svgString = svgString.replace( // capture the entire attribute xmlnsRegex, // use the captured attribute name; replace only the URL ($0, $1) => "".concat($1, "\"http://dummy.namespace\"")); } // Strip `svg:` prefix (sometimes added by Inkscape) from all tags. They interfere with DOMPurify (prefixed tag // names are not recognized) and the paint editor. // This matches opening and closing tags--the capture group captures the slash if it exists, and it is reinserted // in the replacement text. svgString = svgString.replace(/<(\/?)\s*svg:/g, '<$1'); // The element is not needed for rendering and sometimes contains // unparseable garbage from Illustrator :( Empty out the contents. // Note: [\s\S] matches everything including newlines, which .* does not svgString = svgString.replace(/[\s\S]*<\/metadata>/, ''); // Empty script tags and javascript executing svgString = svgString.replace(/[\s\S]*<\/script>/, ''); return svgString; }; /***/ }), /***/ "./node_modules/scratch-svg-renderer/src/font-converter.js": /*!*****************************************************************!*\ !*** ./node_modules/scratch-svg-renderer/src/font-converter.js ***! \*****************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /** * @fileOverview Convert 2.0 fonts to 3.0 fonts. */ /** * Given an SVG, replace Scratch 2.0 fonts with new 3.0 fonts. Add defaults where there are none. * @param {SVGElement} svgTag The SVG dom object * @return {void} */ const convertFonts = function convertFonts(svgTag) { // Collect all text elements into a list. const textElements = []; const collectText = domElement => { if (domElement.localName === 'text') { textElements.push(domElement); } for (let i = 0; i < domElement.childNodes.length; i++) { collectText(domElement.childNodes[i]); } }; collectText(svgTag); // If there's an old font-family, switch to the new one. for (const textElement of textElements) { // If there's no font-family provided, provide one. if (!textElement.getAttribute('font-family') || textElement.getAttribute('font-family') === 'Helvetica') { textElement.setAttribute('font-family', 'Sans Serif'); } else if (textElement.getAttribute('font-family') === 'Mystery') { textElement.setAttribute('font-family', 'Curly'); } else if (textElement.getAttribute('font-family') === 'Gloria') { textElement.setAttribute('font-family', 'Handwriting'); } else if (textElement.getAttribute('font-family') === 'Donegal') { textElement.setAttribute('font-family', 'Serif'); } } }; module.exports = convertFonts; /***/ }), /***/ "./node_modules/scratch-svg-renderer/src/font-inliner.js": /*!***************************************************************!*\ !*** ./node_modules/scratch-svg-renderer/src/font-inliner.js ***! \***************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /** * @fileOverview Import bitmap data into Scratch 3.0, resizing image as necessary. */ const getFonts = __webpack_require__(/*! scratch-render-fonts */ "./src/lib/tw-scratch-render-fonts/index.js"); /** * Given SVG data, inline the fonts. This allows them to be rendered correctly when set * as the source of an HTMLImageElement. Here is a note from tmickel: * // Inject fonts that are needed. * // It would be nice if there were another way to get the SVG-in-canvas * // to render the correct font family, but I couldn't find any other way. * // Other things I tried: * // Just injecting the font-family into the document: no effect. * // External stylesheet linked to by SVG: no effect. * // Using a or to link to font-family * // injected into the document: no effect. * @param {string} svgString The string representation of the svg to modify * @return {string} The svg with any needed fonts inlined */ const inlineSvgFonts = function inlineSvgFonts(svgString) { const FONTS = getFonts(); // Make it clear that this function only operates on strings. // If we don't explicitly throw this here, the function silently fails. if (typeof svgString !== 'string') { throw new Error('SVG to be inlined is not a string'); } // Collect fonts that need injection. const fontsNeeded = new Set(); const fontRegex = /font-family="([^"]*)"/g; let matches = fontRegex.exec(svgString); while (matches) { fontsNeeded.add(matches[1]); matches = fontRegex.exec(svgString); } if (fontsNeeded.size > 0) { let str = ''; svgString = svgString.replace(/]*>/, "$&".concat(str)); return svgString; } return svgString; }; module.exports = inlineSvgFonts; /***/ }), /***/ "./node_modules/scratch-svg-renderer/src/index.js": /*!********************************************************!*\ !*** ./node_modules/scratch-svg-renderer/src/index.js ***! \********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const SVGRenderer = __webpack_require__(/*! ./svg-renderer */ "./node_modules/scratch-svg-renderer/src/svg-renderer.js"); const BitmapAdapter = __webpack_require__(/*! ./bitmap-adapter */ "./node_modules/scratch-svg-renderer/src/bitmap-adapter.js"); const inlineSvgFonts = __webpack_require__(/*! ./font-inliner */ "./node_modules/scratch-svg-renderer/src/font-inliner.js"); const loadSvgString = __webpack_require__(/*! ./load-svg-string */ "./node_modules/scratch-svg-renderer/src/load-svg-string.js"); const sanitizeSvg = __webpack_require__(/*! ./sanitize-svg */ "./node_modules/scratch-svg-renderer/src/sanitize-svg.js"); const serializeSvgToString = __webpack_require__(/*! ./serialize-svg-to-string */ "./node_modules/scratch-svg-renderer/src/serialize-svg-to-string.js"); const SvgElement = __webpack_require__(/*! ./svg-element */ "./node_modules/scratch-svg-renderer/src/svg-element.js"); const convertFonts = __webpack_require__(/*! ./font-converter */ "./node_modules/scratch-svg-renderer/src/font-converter.js"); // /** // * Export for NPM & Node.js // * @type {RenderWebGL} // */ module.exports = { BitmapAdapter: BitmapAdapter, convertFonts: convertFonts, inlineSvgFonts: inlineSvgFonts, loadSvgString: loadSvgString, sanitizeSvg: sanitizeSvg, serializeSvgToString: serializeSvgToString, SvgElement: SvgElement, SVGRenderer: SVGRenderer }; /***/ }), /***/ "./node_modules/scratch-svg-renderer/src/load-svg-string.js": /*!******************************************************************!*\ !*** ./node_modules/scratch-svg-renderer/src/load-svg-string.js ***! \******************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const DOMPurify = __webpack_require__(/*! dompurify */ "./node_modules/dompurify/dist/purify.js"); const SvgElement = __webpack_require__(/*! ./svg-element */ "./node_modules/scratch-svg-renderer/src/svg-element.js"); const convertFonts = __webpack_require__(/*! ./font-converter */ "./node_modules/scratch-svg-renderer/src/font-converter.js"); const fixupSvgString = __webpack_require__(/*! ./fixup-svg-string */ "./node_modules/scratch-svg-renderer/src/fixup-svg-string.js"); const transformStrokeWidths = __webpack_require__(/*! ./transform-applier */ "./node_modules/scratch-svg-renderer/src/transform-applier.js"); /** * @param {SVGElement} svgTag the tag to search within * @param {string} [tagName] svg tag to search for (or collect all elements if not given) * @return {Array} a list of elements with the given tagname */ const collectElements = (svgTag, tagName) => { const elts = []; const collectElementsInner = domElement => { if ((domElement.localName === tagName || typeof tagName === 'undefined') && domElement.getAttribute) { elts.push(domElement); } for (let i = 0; i < domElement.childNodes.length; i++) { collectElementsInner(domElement.childNodes[i]); } }; collectElementsInner(svgTag); return elts; }; /** * Fix SVGs to comply with SVG spec. Scratch 2 defaults to x2 = 0 when x2 is missing, but * SVG defaults to x2 = 1 when missing. * @param {SVGSVGElement} svgTag the SVG tag to apply the transformation to */ const transformGradients = svgTag => { const linearGradientElements = collectElements(svgTag, 'linearGradient'); // For each gradient element, supply x2 if necessary. for (const gradientElement of linearGradientElements) { if (!gradientElement.getAttribute('x2')) { gradientElement.setAttribute('x2', '0'); } } }; /** * Fix SVGs to match appearance in Scratch 2, which used nearest neighbor scaling for bitmaps * within SVGs. * @param {SVGSVGElement} svgTag the SVG tag to apply the transformation to */ const transformImages = svgTag => { const imageElements = collectElements(svgTag, 'image'); // For each image element, set image rendering to pixelated const pixelatedImages = 'image-rendering: optimizespeed; image-rendering: pixelated;'; for (const elt of imageElements) { if (elt.getAttribute('style')) { elt.setAttribute('style', "".concat(pixelatedImages, " ").concat(elt.getAttribute('style'))); } else { elt.setAttribute('style', pixelatedImages); } } }; /** * Transforms an SVG's text elements for Scratch 2.0 quirks. * These quirks include: * 1. `x` and `y` properties are removed/ignored. * 2. Alignment is set to `text-before-edge`. * 3. Line-breaks are converted to explicit elements. * 4. Any required fonts are injected. * @param {SVGSVGElement} svgTag the SVG tag to apply the transformation to */ const transformText = svgTag => { // Collect all text elements into a list. const textElements = []; const collectText = domElement => { if (domElement.localName === 'text') { textElements.push(domElement); } for (let i = 0; i < domElement.childNodes.length; i++) { collectText(domElement.childNodes[i]); } }; collectText(svgTag); convertFonts(svgTag); // For each text element, apply quirks. for (const textElement of textElements) { // Remove x and y attributes - they are not used in Scratch. textElement.removeAttribute('x'); textElement.removeAttribute('y'); // Set text-before-edge alignment: // Scratch renders all text like this. textElement.setAttribute('alignment-baseline', 'text-before-edge'); textElement.setAttribute('xml:space', 'preserve'); // If there's no font size provided, provide one. if (!textElement.getAttribute('font-size')) { textElement.setAttribute('font-size', '18'); } let text = textElement.textContent; // Fix line breaks in text, which are not natively supported by SVG. // Only fix if text does not have child tspans. // @todo this will not work for font sizes with units such as em, percent // However, text made in scratch 2 should only ever export size 22 font. const fontSize = parseFloat(textElement.getAttribute('font-size')); const tx = 2; let ty = 0; let spacing = 1.2; // Try to match the position and spacing of Scratch 2.0's fonts. // Different fonts seem to use different line spacing. // Scratch 2 always uses alignment-baseline=text-before-edge // However, most SVG readers don't support this attribute // or don't support it alongside use of tspan, so the translations // here are to make up for that. if (textElement.getAttribute('font-family') === 'Handwriting') { spacing = 2; ty = -11 * fontSize / 22; } else if (textElement.getAttribute('font-family') === 'Scratch') { spacing = 0.89; ty = -3 * fontSize / 22; } else if (textElement.getAttribute('font-family') === 'Curly') { spacing = 1.38; ty = -6 * fontSize / 22; } else if (textElement.getAttribute('font-family') === 'Marker') { spacing = 1.45; ty = -6 * fontSize / 22; } else if (textElement.getAttribute('font-family') === 'Sans Serif') { spacing = 1.13; ty = -3 * fontSize / 22; } else if (textElement.getAttribute('font-family') === 'Serif') { spacing = 1.25; ty = -4 * fontSize / 22; } if (textElement.transform.baseVal.numberOfItems === 0) { const transform = svgTag.createSVGTransform(); textElement.transform.baseVal.appendItem(transform); } // Right multiply matrix by a translation of (tx, ty) const mtx = textElement.transform.baseVal.getItem(0).matrix; mtx.e += mtx.a * tx + mtx.c * ty; mtx.f += mtx.b * tx + mtx.d * ty; if (text && textElement.childElementCount === 0) { textElement.textContent = ''; const lines = text.split('\n'); text = ''; for (const line of lines) { const tspanNode = SvgElement.create('tspan'); tspanNode.setAttribute('x', '0'); tspanNode.setAttribute('style', 'white-space: pre'); tspanNode.setAttribute('dy', "".concat(spacing, "em")); tspanNode.textContent = line ? line : ' '; textElement.appendChild(tspanNode); } } } }; /** * Find the largest stroke width in the svg. If a shape has no * `stroke` property, it has a stroke-width of 0. If it has a `stroke`, * it is by default a stroke-width of 1. * This is used to enlarge the computed bounding box, which doesn't take * stroke width into account. * @param {SVGSVGElement} rootNode The root SVG node to traverse. * @return {number} The largest stroke width in the SVG. */ const findLargestStrokeWidth = rootNode => { let largestStrokeWidth = 0; const collectStrokeWidths = domElement => { if (domElement.getAttribute) { if (domElement.getAttribute('stroke')) { largestStrokeWidth = Math.max(largestStrokeWidth, 1); } if (domElement.getAttribute('stroke-width')) { largestStrokeWidth = Math.max(largestStrokeWidth, Number(domElement.getAttribute('stroke-width')) || 0); } } for (let i = 0; i < domElement.childNodes.length; i++) { collectStrokeWidths(domElement.childNodes[i]); } }; collectStrokeWidths(rootNode); return largestStrokeWidth; }; /** * Transform the measurements of the SVG. * In Scratch 2.0, SVGs are drawn without respect to the width, * height, and viewBox attribute on the tag. The exporter * does output these properties - but they appear to be incorrect often. * To address the incorrect measurements, we append the DOM to the * document, and then use SVG's native `getBBox` to find the real * drawn dimensions. This ensures things drawn in negative dimensions, * outside the given viewBox, etc., are all eventually drawn to the canvas. * I tried to do this several other ways: stripping the width/height/viewBox * attributes and then drawing (Firefox won't draw anything), * or inflating them and then measuring a canvas. But this seems to be * a natural and performant way. * @param {SVGSVGElement} svgTag the SVG tag to apply the transformation to */ const transformMeasurements = svgTag => { // Append the SVG dom to the document. // This allows us to use `getBBox` on the page, // which returns the full bounding-box of all drawn SVG // elements, similar to how Scratch 2.0 did measurement. const svgSpot = document.createElement('span'); // Since we're adding user-provided SVG to document.body, // sanitizing is required. This should not affect bounding box calculation. // outerHTML is attribute of Element (and not HTMLElement), so use it instead of // calling serializer or toString() // NOTE: svgTag remains untouched! const rawValue = svgTag.outerHTML; const sanitizedValue = DOMPurify.sanitize(rawValue, { // Use SVG profile (no HTML elements) USE_PROFILES: { svg: true }, // Remove some tags that Scratch does not use. FORBID_TAGS: ['a', 'audio', 'canvas', 'video'], // Allow data URI in image tags (e.g. SVGs converted from bitmap) ADD_DATA_URI_TAGS: ['image'] }); let bbox; try { // Insert sanitized value. svgSpot.innerHTML = sanitizedValue; document.body.appendChild(svgSpot); // Take the bounding box. We have to get elements via svgSpot // because we added it via innerHTML. bbox = svgSpot.children[0].getBBox(); } finally { // Always destroy the element, even if, for example, getBBox throws. document.body.removeChild(svgSpot); } // Enlarge the bbox from the largest found stroke width // This may have false-positives, but at least the bbox will always // contain the full graphic including strokes. // If the width or height is zero however, don't enlarge since // they won't have a stroke width that needs to be enlarged. let halfStrokeWidth; if (bbox.width === 0 || bbox.height === 0) { halfStrokeWidth = 0; } else { halfStrokeWidth = findLargestStrokeWidth(svgTag) / 2; } const width = bbox.width + halfStrokeWidth * 2; const height = bbox.height + halfStrokeWidth * 2; const x = bbox.x - halfStrokeWidth; const y = bbox.y - halfStrokeWidth; // Set the correct measurements on the SVG tag svgTag.setAttribute('width', width); svgTag.setAttribute('height', height); svgTag.setAttribute('viewBox', "".concat(x, " ").concat(y, " ").concat(width, " ").concat(height)); }; /** * Find all instances of a URL-referenced `stroke` in the svg. In 2.0, all gradient strokes * have a round `stroke-linejoin` and `stroke-linecap`... for some reason. * @param {SVGSVGElement} svgTag the SVG tag to apply the transformation to */ const setGradientStrokeRoundedness = svgTag => { const elements = collectElements(svgTag); for (const elt of elements) { if (!elt.style) continue; const stroke = elt.style.stroke || elt.getAttribute('stroke'); if (stroke && stroke.match(/^url\(#.*\)$/)) { elt.style['stroke-linejoin'] = 'round'; elt.style['stroke-linecap'] = 'round'; } } }; /** * In-place, convert passed SVG to something consistent that will be rendered the way we want them to be. * @param {SVGSvgElement} svgTag root SVG node to operate upon * @param {boolean} [fromVersion2] True if we should perform conversion from version 2 to version 3 svg. */ const normalizeSvg = (svgTag, fromVersion2) => { if (fromVersion2) { // Fix gradients. Scratch 2 exports no x2 when x2 = 0, but // SVG default is that x2 is 1. This must be done before // transformStrokeWidths since transformStrokeWidths affects // gradients. transformGradients(svgTag); } transformStrokeWidths(svgTag, window); transformImages(svgTag); if (fromVersion2) { // Transform all text elements. transformText(svgTag); // Transform measurements. transformMeasurements(svgTag); // Fix stroke roundedness. setGradientStrokeRoundedness(svgTag); } else if (!svgTag.getAttribute('viewBox')) { // Renderer expects a view box. transformMeasurements(svgTag); } else if (!svgTag.getAttribute('width') || !svgTag.getAttribute('height')) { svgTag.setAttribute('width', svgTag.viewBox.baseVal.width); svgTag.setAttribute('height', svgTag.viewBox.baseVal.height); } }; /** * Load an SVG string and normalize it. All the steps before drawing/measuring. * Currently, this will normalize stroke widths (see transform-applier.js) and render all embedded images pixelated. * The returned SVG will be guaranteed to always have a `width`, `height` and `viewBox`. * In addition, if the `fromVersion2` parameter is `true`, several "quirks-mode" transformations will be applied which * mimic Scratch 2.0's SVG rendering. * @param {!string} svgString String of SVG data to draw in quirks-mode. * @param {boolean} [fromVersion2] True if we should perform conversion from version 2 to version 3 svg. * @return {SVGSVGElement} The normalized SVG element. */ const loadSvgString = (svgString, fromVersion2) => { // Parse string into SVG XML. const parser = new DOMParser(); svgString = fixupSvgString(svgString); const svgDom = parser.parseFromString(svgString, 'text/xml'); if (svgDom.childNodes.length < 1 || svgDom.documentElement.localName !== 'svg') { throw new Error('Document does not appear to be SVG.'); } const svgTag = svgDom.documentElement; normalizeSvg(svgTag, fromVersion2); return svgTag; }; module.exports = loadSvgString; /***/ }), /***/ "./node_modules/scratch-svg-renderer/src/sanitize-svg.js": /*!***************************************************************!*\ !*** ./node_modules/scratch-svg-renderer/src/sanitize-svg.js ***! \***************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /** * @fileOverview Sanitize the content of an SVG aggressively, to make it as safe * as possible */ const fixupSvgString = __webpack_require__(/*! ./fixup-svg-string */ "./node_modules/scratch-svg-renderer/src/fixup-svg-string.js"); const DOMPurify = __webpack_require__(/*! dompurify */ "./node_modules/dompurify/dist/purify.js"); const sanitizeSvg = {}; DOMPurify.addHook('beforeSanitizeAttributes', currentNode => { if (currentNode && currentNode.href && currentNode.href.baseVal) { const href = currentNode.href.baseVal.replace(/\s/g, ''); // "data:" and "#" are valid hrefs if (href.slice(0, 5) !== 'data:' && href.slice(0, 1) !== '#') { if (currentNode.attributes.getNamedItem('xlink:href')) { currentNode.attributes.removeNamedItem('xlink:href'); delete currentNode['xlink:href']; } if (currentNode.attributes.getNamedItem('href')) { currentNode.attributes.removeNamedItem('href'); delete currentNode.href; } } } return currentNode; }); // Use JS implemented TextDecoder and TextEncoder if it is not provided by the // browser. let _TextDecoder; let _TextEncoder; if (typeof TextDecoder === 'undefined' || typeof TextEncoder === 'undefined') { // Wait to require the text encoding polyfill until we know it's needed. // eslint-disable-next-line global-require const encoding = __webpack_require__(/*! fastestsmallesttextencoderdecoder */ "./node_modules/fastestsmallesttextencoderdecoder/EncoderDecoderTogether.min.js"); _TextDecoder = encoding.TextDecoder; _TextEncoder = encoding.TextEncoder; } else { _TextDecoder = TextDecoder; _TextEncoder = TextEncoder; } /** * Load an SVG Uint8Array of bytes and "sanitize" it * @param {!Uint8Array} rawData unsanitized SVG daata * @return {Uint8Array} sanitized SVG data */ sanitizeSvg.sanitizeByteStream = function (rawData) { const decoder = new _TextDecoder(); const encoder = new _TextEncoder(); const sanitizedText = sanitizeSvg.sanitizeSvgText(decoder.decode(rawData)); return encoder.encode(sanitizedText); }; // TW: Don't remove extra metadata tag: // Using literal HTML comments tokens will cause this script to be very hard to inline in // a ` element with the contents of the currently loaded SVG. * @type {?HTMLImageElement} * @private */ this._cachedImage = null; /** * True if this renderer's current SVG is loaded and can be rendered to the canvas. * @type {boolean} */ this.loaded = false; } /** * @returns {!HTMLCanvasElement} this renderer's target canvas. */ get canvas() { return this._canvas; } /** * @return {Array} the natural size, in Scratch units, of this SVG. */ get size() { return [this._measurements.width, this._measurements.height]; } /** * @return {Array} the offset (upper left corner) of the SVG's view box. */ get viewOffset() { return [this._measurements.x, this._measurements.y]; } /** * Load an SVG string and normalize it. All the steps before drawing/measuring. * @param {!string} svgString String of SVG data to draw in quirks-mode. * @param {?boolean} fromVersion2 True if we should perform conversion from * version 2 to version 3 svg. */ loadString(svgString, fromVersion2) { // New svg string invalidates the cached image this._cachedImage = null; const svgTag = loadSvgString(svgString, fromVersion2); this._svgTag = svgTag; this._measurements = { width: svgTag.viewBox.baseVal.width, height: svgTag.viewBox.baseVal.height, x: svgTag.viewBox.baseVal.x, y: svgTag.viewBox.baseVal.y }; } /** * Load an SVG string, normalize it, and prepare it for (synchronous) rendering. * @param {!string} svgString String of SVG data to draw in quirks-mode. * @param {?boolean} fromVersion2 True if we should perform conversion from version 2 to version 3 svg. * @param {Function} [onFinish] - An optional callback to call when the SVG is loaded and can be rendered. */ loadSVG(svgString, fromVersion2, onFinish) { this.loadString(svgString, fromVersion2); this._createSVGImage(onFinish); } /** * Creates an element for the currently loaded SVG string, then calls the callback once it's loaded. * @param {Function} [onFinish] - An optional callback to call when the has loaded. */ _createSVGImage(onFinish) { if (this._cachedImage === null) this._cachedImage = new Image(); const img = this._cachedImage; img.onload = () => { this.loaded = true; if (onFinish) onFinish(); }; const svgText = this.toString(true /* shouldInjectFonts */ ); img.src = "data:image/svg+xml;utf8,".concat(encodeURIComponent(svgText)); this.loaded = false; } /** * Serialize the active SVG DOM to a string. * @param {?boolean} shouldInjectFonts True if fonts should be included in the SVG as * base64 data. * @returns {string} String representing current SVG data. * @deprecated Use the standalone `serializeSvgToString` export instead. */ toString(shouldInjectFonts) { return serializeSvgToString(this._svgTag, shouldInjectFonts); } /** * Synchronously draw the loaded SVG to this renderer's `canvas`. * @param {number} [scale] - Optionally, also scale the image by this factor. */ draw(scale) { if (!this.loaded) throw new Error('SVG image has not finished loading'); this._drawFromImage(scale); } /** * Draw to the canvas from a loaded image element. * @param {number} [scale] - Optionally, also scale the image by this factor. **/ _drawFromImage(scale) { if (this._cachedImage === null) return; const ratio = Number.isFinite(scale) ? scale : 1; const bbox = this._measurements; this._canvas.width = bbox.width * ratio; this._canvas.height = bbox.height * ratio; // Even if the canvas at the current scale has a nonzero size, the image's dimensions are floored pre-scaling. // e.g. if an image has a width of 0.4 and is being rendered at 3x scale, the canvas will have a width of 1, but // the image's width will be rounded down to 0 on some browsers (Firefox) prior to being drawn at that scale. if (this._canvas.width <= 0 || this._canvas.height <= 0 || this._cachedImage.naturalWidth <= 0 || this._cachedImage.naturalHeight <= 0) return; this._context.clearRect(0, 0, this._canvas.width, this._canvas.height); this._context.setTransform(ratio, 0, 0, ratio, 0, 0); this._context.drawImage(this._cachedImage, 0, 0); } } module.exports = SvgRenderer; /***/ }), /***/ "./node_modules/scratch-svg-renderer/src/transform-applier.js": /*!********************************************************************!*\ !*** ./node_modules/scratch-svg-renderer/src/transform-applier.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const Matrix = __webpack_require__(/*! transformation-matrix */ "./node_modules/transformation-matrix/build-umd/transformation-matrix.min.js"); const SvgElement = __webpack_require__(/*! ./svg-element */ "./node_modules/scratch-svg-renderer/src/svg-element.js"); const log = __webpack_require__(/*! ./util/log */ "./node_modules/scratch-svg-renderer/src/util/log.js"); /** * @fileOverview Apply transforms to match stroke width appearance in 2.0 and 3.0 */ // Adapted from paper.js's Path.applyTransform const _parseTransform = function _parseTransform(domElement) { let matrix = Matrix.identity(); const string = domElement.attributes && domElement.attributes.transform && domElement.attributes.transform.value; if (!string) return matrix; // https://www.w3.org/TR/SVG/types.html#DataTypeTransformList // Parse SVG transform string. First we split at /)\s*/, to separate // commands const transforms = string.split(/\)\s*/g); for (const transform of transforms) { if (!transform) break; // Command come before the '(', values after const parts = transform.split(/\(\s*/); const command = parts[0].trim(); const v = parts[1].split(/[\s,]+/g); // Convert values to floats for (let j = 0; j < v.length; j++) { v[j] = parseFloat(v[j]); } switch (command) { case 'matrix': matrix = Matrix.compose(matrix, { a: v[0], b: v[1], c: v[2], d: v[3], e: v[4], f: v[5] }); break; case 'rotate': matrix = Matrix.compose(matrix, Matrix.rotateDEG(v[0], v[1] || 0, v[2] || 0)); break; case 'translate': matrix = Matrix.compose(matrix, Matrix.translate(v[0], v[1] || 0)); break; case 'scale': matrix = Matrix.compose(matrix, Matrix.scale(v[0], v[1] || v[0])); break; case 'skewX': matrix = Matrix.compose(matrix, Matrix.skewDEG(v[0], 0)); break; case 'skewY': matrix = Matrix.compose(matrix, Matrix.skewDEG(0, v[0])); break; default: log.error("Couldn't parse: ".concat(command)); } } return matrix; }; // Adapted from paper.js's Matrix.decompose // Given a matrix, return the x and y scale factors of the matrix const _getScaleFactor = function _getScaleFactor(matrix) { const a = matrix.a; const b = matrix.b; const c = matrix.c; const d = matrix.d; const det = a * d - b * c; if (a !== 0 || b !== 0) { const r = Math.sqrt(a * a + b * b); return { x: r, y: det / r }; } if (c !== 0 || d !== 0) { const s = Math.sqrt(c * c + d * d); return { x: det / s, y: s }; } // a = b = c = d = 0 return { x: 0, y: 0 }; }; // Returns null if matrix is not invertible. Otherwise returns given ellipse // transformed by transform, an object {radiusX, radiusY, rotation}. const _calculateTransformedEllipse = function _calculateTransformedEllipse(radiusX, radiusY, theta, transform) { theta = -theta * Math.PI / 180; const a = transform.a; const b = -transform.c; const c = -transform.b; const d = transform.d; // Since other parameters determine the translation of the ellipse in SVG, we do not need to worry // about what e and f are. const det = a * d - b * c; // Non-invertible matrix if (det === 0) return null; // rotA, rotB, and rotC represent Ax^2 + Bxy + Cy^2 = 1 coefficients for a rotated ellipse formula const sinT = Math.sin(theta); const cosT = Math.cos(theta); const sin2T = Math.sin(2 * theta); const rotA = cosT * cosT / radiusX / radiusX + sinT * sinT / radiusY / radiusY; const rotB = sin2T / radiusX / radiusX - sin2T / radiusY / radiusY; const rotC = sinT * sinT / radiusX / radiusX + cosT * cosT / radiusY / radiusY; // Calculate the ellipse formula of the transformed ellipse // A, B, and C represent Ax^2 + Bxy + Cy^2 = 1 / det / det coefficients in a transformed ellipse formula // scaled by inverse det squared (to preserve accuracy) const A = rotA * d * d - rotB * d * c + rotC * c * c; const B = -2 * rotA * b * d + rotB * a * d + rotB * b * c - 2 * rotC * a * c; const C = rotA * b * b - rotB * a * b + rotC * a * a; // Derive new radii and theta from the transformed ellipse formula const newRadiusXOverDet = Math.sqrt(2) * Math.sqrt((A + C - Math.sqrt(A * A + B * B - 2 * A * C + C * C)) / (-B * B + 4 * A * C)); const newRadiusYOverDet = 1 / Math.sqrt(A + C - 1 / newRadiusXOverDet / newRadiusXOverDet); let temp = (A - 1 / newRadiusXOverDet / newRadiusXOverDet) / (1 / newRadiusYOverDet / newRadiusYOverDet - 1 / newRadiusXOverDet / newRadiusXOverDet); if (temp < 0 && Math.abs(temp) < 1e-8) temp = 0; // Fix floating point issue temp = Math.sqrt(temp); if (Math.abs(1 - temp) < 1e-8) temp = 1; // Fix floating point issue // Solve for which of the two possible thetas is correct let newTheta = Math.asin(temp); temp = B / (1 / newRadiusXOverDet / newRadiusXOverDet - 1 / newRadiusYOverDet / newRadiusYOverDet); const newTheta2 = -newTheta; if (Math.abs(Math.sin(2 * newTheta2) - temp) < Math.abs(Math.sin(2 * newTheta) - temp)) { newTheta = newTheta2; } return { radiusX: newRadiusXOverDet * det, radiusY: newRadiusYOverDet * det, rotation: -newTheta * 180 / Math.PI }; }; // Adapted from paper.js's PathItem.setPathData const _transformPath = function _transformPath(pathString, transform) { if (!transform || Matrix.toString(transform) === Matrix.toString(Matrix.identity())) return pathString; // First split the path data into parts of command-coordinates pairs // Commands are any of these characters: mzlhvcsqta const parts = pathString && pathString.match(/[mlhvcsqtaz][^mlhvcsqtaz]*/ig); let coords; let relative = false; let previous; let control; let current = { x: 0, y: 0 }; let start = { x: 0, y: 0 }; let result = ''; const getCoord = function getCoord(index, coord) { let val = +coords[index]; if (relative) { val += current[coord]; } return val; }; const getPoint = function getPoint(index) { return { x: getCoord(index, 'x'), y: getCoord(index + 1, 'y') }; }; const roundTo4Places = function roundTo4Places(num) { return Math.round(num * 1e4) / 1e4; }; // Returns the transformed point as a string const getString = function getString(point) { const transformed = Matrix.applyToPoint(transform, point); return "".concat(roundTo4Places(transformed.x), " ").concat(roundTo4Places(transformed.y), " "); }; for (let i = 0, l = parts && parts.length; i < l; i++) { const part = parts[i]; const command = part[0]; const lower = command.toLowerCase(); // Match all coordinate values coords = part.match(/[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g); const length = coords && coords.length; relative = command === lower; // Fix issues with z in the middle of SVG path data, not followed by // a m command, see paper.js#413: if (previous === 'z' && !/[mz]/.test(lower)) { result += "M ".concat(current.x, " ").concat(current.y, " "); } switch (lower) { case 'm': // Move to case 'l': // Line to { let move = lower === 'm'; for (let j = 0; j < length; j += 2) { result += move ? 'M ' : 'L '; current = getPoint(j); result += getString(current); if (move) { start = current; move = false; } } control = current; break; } case 'h': // Horizontal line case 'v': // Vertical line { const coord = lower === 'h' ? 'x' : 'y'; current = { x: current.x, y: current.y }; // Clone as we're going to modify it. for (let j = 0; j < length; j++) { current[coord] = getCoord(j, coord); result += "L ".concat(getString(current)); } control = current; break; } case 'c': // Cubic Bezier curve for (let j = 0; j < length; j += 6) { const handle1 = getPoint(j); control = getPoint(j + 2); current = getPoint(j + 4); result += "C ".concat(getString(handle1)).concat(getString(control)).concat(getString(current)); } break; case 's': // Smooth cubic Bezier curve for (let j = 0; j < length; j += 4) { const handle1 = /[cs]/.test(previous) ? { x: current.x * 2 - control.x, y: current.y * 2 - control.y } : current; control = getPoint(j); current = getPoint(j + 2); result += "C ".concat(getString(handle1)).concat(getString(control)).concat(getString(current)); previous = lower; } break; case 'q': // Quadratic Bezier curve for (let j = 0; j < length; j += 4) { control = getPoint(j); current = getPoint(j + 2); result += "Q ".concat(getString(control)).concat(getString(current)); } break; case 't': // Smooth quadratic Bezier curve for (let j = 0; j < length; j += 2) { control = /[qt]/.test(previous) ? { x: current.x * 2 - control.x, y: current.y * 2 - control.y } : current; current = getPoint(j); result += "Q ".concat(getString(control)).concat(getString(current)); previous = lower; } break; case 'a': // Elliptical arc curve for (let j = 0; j < length; j += 7) { current = getPoint(j + 5); const rx = +coords[j]; const ry = +coords[j + 1]; const rotation = +coords[j + 2]; const largeArcFlag = +coords[j + 3]; let clockwiseFlag = +coords[j + 4]; const newEllipse = _calculateTransformedEllipse(rx, ry, rotation, transform); const matrixScale = _getScaleFactor(transform); if (newEllipse) { if (matrixScale.x > 0 && matrixScale.y < 0 || matrixScale.x < 0 && matrixScale.y > 0) { clockwiseFlag = clockwiseFlag ^ 1; } result += "A ".concat(roundTo4Places(Math.abs(newEllipse.radiusX)), " ") + "".concat(roundTo4Places(Math.abs(newEllipse.radiusY)), " ") + "".concat(roundTo4Places(newEllipse.rotation), " ").concat(largeArcFlag, " ") + "".concat(clockwiseFlag, " ").concat(getString(current)); } else { result += "L ".concat(getString(current)); } } break; case 'z': // Close path result += "Z "; // Correctly handle relative m commands, see paper.js#1101: current = start; break; } previous = lower; } return result; }; const GRAPHICS_ELEMENTS = ['circle', 'ellipse', 'image', 'line', 'path', 'polygon', 'polyline', 'rect', 'text', 'use']; const CONTAINER_ELEMENTS = ['a', 'defs', 'g', 'marker', 'glyph', 'missing-glyph', 'pattern', 'svg', 'switch', 'symbol']; const _isContainerElement = function _isContainerElement(element) { return element.tagName && CONTAINER_ELEMENTS.includes(element.tagName.toLowerCase()); }; const _isGraphicsElement = function _isGraphicsElement(element) { return element.tagName && GRAPHICS_ELEMENTS.includes(element.tagName.toLowerCase()); }; const _isPathWithTransformAndStroke = function _isPathWithTransformAndStroke(element, strokeWidth) { if (!element.attributes) return false; strokeWidth = element.attributes['stroke-width'] ? Number(element.attributes['stroke-width'].value) : Number(strokeWidth); return strokeWidth && element.tagName && element.tagName.toLowerCase() === 'path' && element.attributes.d && element.attributes.d.value; }; const _quadraticMean = function _quadraticMean(a, b) { return Math.sqrt((a * a + b * b) / 2); }; const _createGradient = function _createGradient(gradientId, svgTag, bbox, matrix) { // Adapted from Paper.js's SvgImport.getValue const getValue = function getValue(node, name, isString, allowNull, allowPercent, defaultValue) { // Interpret value as number. Never return NaN, but 0 instead. // If the value is a sequence of numbers, parseFloat will // return the first occurring number, which is enough for now. let value = SvgElement.get(node, name); let res; if (value === null) { if (defaultValue) { res = defaultValue; if (/%\s*$/.test(res)) { value = defaultValue; res = parseFloat(value); } } else if (allowNull) { res = null; } else if (isString) { res = ''; } else { res = 0; } } else if (isString) { res = value; } else { res = parseFloat(value); } // Support for dimensions in percentage of the root size. If root-size // is not set (e.g. during ), just scale the percentage value to // 0..1, as required by gradients with gradientUnits="objectBoundingBox" if (/%\s*$/.test(value)) { const size = allowPercent ? 1 : bbox[/x|^width/.test(name) ? 'width' : 'height']; return res / 100 * size; } return res; }; const getPoint = function getPoint(node, x, y, allowNull, allowPercent, defaultX, defaultY) { x = getValue(node, x || 'x', false, allowNull, allowPercent, defaultX); y = getValue(node, y || 'y', false, allowNull, allowPercent, defaultY); return allowNull && (x === null || y === null) ? null : { x, y }; }; let defs = svgTag.getElementsByTagName('defs'); if (defs.length === 0) { defs = SvgElement.create('defs'); svgTag.appendChild(defs); } else { defs = defs[0]; } // Clone the old gradient. We'll make a new one, since the gradient might be reused elsewhere // with different transform matrix const oldGradient = svgTag.getElementById(gradientId); if (!oldGradient) return; const radial = oldGradient.tagName.toLowerCase() === 'radialgradient'; const newGradient = svgTag.getElementById(gradientId).cloneNode(true /* deep */ ); // Give the new gradient a new ID let matrixString = Matrix.toString(matrix); matrixString = matrixString.substring(8, matrixString.length - 1); const newGradientId = "".concat(gradientId, "-").concat(matrixString); newGradient.setAttribute('id', newGradientId); // This gradient already exists and was transformed before. Just reuse the already-transformed one. if (svgTag.getElementById(newGradientId)) { // This is the same code as in the end of the function, but I don't feel like wrapping the next 80 lines // in an `if (!svgTag.getElementById(newGradientId))` block return "url(#".concat(newGradientId, ")"); } const scaleToBounds = getValue(newGradient, 'gradientUnits', true) !== 'userSpaceOnUse'; let origin; let destination; let radius; let focal; if (radial) { origin = getPoint(newGradient, 'cx', 'cy', false, scaleToBounds, '50%', '50%'); radius = getValue(newGradient, 'r', false, false, scaleToBounds, '50%'); focal = getPoint(newGradient, 'fx', 'fy', true, scaleToBounds); } else { origin = getPoint(newGradient, 'x1', 'y1', false, scaleToBounds); destination = getPoint(newGradient, 'x2', 'y2', false, scaleToBounds, '1'); if (origin.x === destination.x && origin.y === destination.y) { // If it's degenerate, use the color of the last stop, as described by // https://www.w3.org/TR/SVG/pservers.html#LinearGradientNotes const stops = newGradient.getElementsByTagName('stop'); if (!stops.length || !stops[stops.length - 1].attributes || !stops[stops.length - 1].attributes['stop-color']) { return null; } return stops[stops.length - 1].attributes['stop-color'].value; } } // Transform points // Emulate SVG's gradientUnits="objectBoundingBox" if (scaleToBounds) { const boundsMatrix = Matrix.compose(Matrix.translate(bbox.x, bbox.y), Matrix.scale(bbox.width, bbox.height)); origin = Matrix.applyToPoint(boundsMatrix, origin); if (destination) destination = Matrix.applyToPoint(boundsMatrix, destination); if (radius) { radius = _quadraticMean(bbox.width, bbox.height) * radius; } if (focal) focal = Matrix.applyToPoint(boundsMatrix, focal); } if (radial) { origin = Matrix.applyToPoint(matrix, origin); const matrixScale = _getScaleFactor(matrix); radius = _quadraticMean(matrixScale.x, matrixScale.y) * radius; if (focal) focal = Matrix.applyToPoint(matrix, focal); } else { const dot = (a, b) => a.x * b.x + a.y * b.y; const multiply = (coefficient, v) => ({ x: coefficient * v.x, y: coefficient * v.y }); const add = (a, b) => ({ x: a.x + b.x, y: a.y + b.y }); const subtract = (a, b) => ({ x: a.x - b.x, y: a.y - b.y }); // The line through origin and gradientPerpendicular is the line at which the gradient starts let gradientPerpendicular = Math.abs(origin.x - destination.x) < 1e-8 ? add(origin, { x: 1, y: (origin.x - destination.x) / (destination.y - origin.y) }) : add(origin, { x: (destination.y - origin.y) / (origin.x - destination.x), y: 1 }); // Transform points gradientPerpendicular = Matrix.applyToPoint(matrix, gradientPerpendicular); origin = Matrix.applyToPoint(matrix, origin); destination = Matrix.applyToPoint(matrix, destination); // Calculate the direction that the gradient has changed to const originToPerpendicular = subtract(gradientPerpendicular, origin); const originToDestination = subtract(destination, origin); const gradientDirection = Math.abs(originToPerpendicular.x) < 1e-8 ? { x: 1, y: -originToPerpendicular.x / originToPerpendicular.y } : { x: -originToPerpendicular.y / originToPerpendicular.x, y: 1 }; // Set the destination so that the gradient moves in the correct direction, by projecting the destination vector // onto the gradient direction vector const projectionCoeff = dot(originToDestination, gradientDirection) / dot(gradientDirection, gradientDirection); const projection = multiply(projectionCoeff, gradientDirection); destination = { x: origin.x + projection.x, y: origin.y + projection.y }; } // Put values back into svg if (radial) { newGradient.setAttribute('cx', Number(origin.x.toFixed(4))); newGradient.setAttribute('cy', Number(origin.y.toFixed(4))); newGradient.setAttribute('r', Number(radius.toFixed(4))); if (focal) { newGradient.setAttribute('fx', Number(focal.x.toFixed(4))); newGradient.setAttribute('fy', Number(focal.y.toFixed(4))); } } else { newGradient.setAttribute('x1', Number(origin.x.toFixed(4))); newGradient.setAttribute('y1', Number(origin.y.toFixed(4))); newGradient.setAttribute('x2', Number(destination.x.toFixed(4))); newGradient.setAttribute('y2', Number(destination.y.toFixed(4))); } newGradient.setAttribute('gradientUnits', 'userSpaceOnUse'); defs.appendChild(newGradient); return "url(#".concat(newGradientId, ")"); }; // Adapted from paper.js's SvgImport.getDefinition const _parseUrl = (value, windowRef) => { // When url() comes from a style property, '#'' seems to be missing on // WebKit. We also get variations of quotes or no quotes, single or // double, so handle it all with one regular expression: const match = value && value.match(/\((?:["'#]*)([^"')]+)/); const name = match && match[1]; const res = name && windowRef ? // This is required by Firefox, which can produce absolute // urls for local gradients, see paperjs#1001: name.replace("".concat(windowRef.location.href.split('#')[0], "#"), '') : name; return res; }; /** * Scratch 2.0 displays stroke widths in a "normalized" way, that is, * if a shape with a stroke width has a transform applied, it will be * rendered with a stroke that is the same width all the way around, * instead of stretched looking. * * The vector paint editor also prefers to normalize the stroke width, * rather than keep track of transforms at the group level, as this * simplifies editing (e.g. stroke width 3 always means the same thickness) * * This function performs that normalization process, pushing transforms * on groups down to the leaf level and averaging out the stroke width * around the shapes. Note that this doens't just change stroke widths, it * changes path data and attributes throughout the SVG. * * @param {SVGElement} svgTag The SVG dom object * @param {Window} windowRef The window to use. Need to pass in for * tests to work, as they get angry at even the mention of window. * @param {object} bboxForTesting The bounds to use. Need to pass in for * tests only, because getBBox doesn't work in Node. This should * be the bounds of the svgTag without including stroke width or transforms. * @return {void} */ const transformStrokeWidths = function transformStrokeWidths(svgTag, windowRef, bboxForTesting) { const inherited = Matrix.identity(); const applyTransforms = (element, matrix, strokeWidth, fill, stroke) => { if (_isContainerElement(element)) { // Push fills and stroke width down to leaves if (element.attributes['stroke-width']) { strokeWidth = element.attributes['stroke-width'].value; } if (element.attributes) { if (element.attributes.fill) fill = element.attributes.fill.value; if (element.attributes.stroke) stroke = element.attributes.stroke.value; } // If any child nodes don't take attributes, leave the attributes // at the parent level. for (let i = 0; i < element.childNodes.length; i++) { applyTransforms(element.childNodes[i], Matrix.compose(matrix, _parseTransform(element)), strokeWidth, fill, stroke); } element.removeAttribute('transform'); element.removeAttribute('stroke-width'); element.removeAttribute('fill'); element.removeAttribute('stroke'); } else if (_isPathWithTransformAndStroke(element, strokeWidth)) { if (element.attributes['stroke-width']) { strokeWidth = element.attributes['stroke-width'].value; } if (element.attributes.fill) fill = element.attributes.fill.value; if (element.attributes.stroke) stroke = element.attributes.stroke.value; matrix = Matrix.compose(matrix, _parseTransform(element)); if (Matrix.toString(matrix) === Matrix.toString(Matrix.identity())) { element.removeAttribute('transform'); element.setAttribute('stroke-width', strokeWidth); if (fill) element.setAttribute('fill', fill); if (stroke) element.setAttribute('stroke', stroke); return; } // Transform gradient const fillGradientId = _parseUrl(fill, windowRef); const strokeGradientId = _parseUrl(stroke, windowRef); if (fillGradientId || strokeGradientId) { const doc = windowRef.document; // Need path bounds to transform gradient const svgSpot = doc.createElement('span'); let bbox; if (bboxForTesting) { bbox = bboxForTesting; } else { try { doc.body.appendChild(svgSpot); const svg = SvgElement.set(doc.createElementNS(SvgElement.svg, 'svg')); const path = SvgElement.set(doc.createElementNS(SvgElement.svg, 'path')); path.setAttribute('d', element.attributes.d.value); svg.appendChild(path); svgSpot.appendChild(svg); // Take the bounding box. bbox = svg.getBBox(); } finally { // Always destroy the element, even if, for example, getBBox throws. doc.body.removeChild(svgSpot); } } if (fillGradientId) { const newFillRef = _createGradient(fillGradientId, svgTag, bbox, matrix); if (newFillRef) fill = newFillRef; } if (strokeGradientId) { const newStrokeRef = _createGradient(strokeGradientId, svgTag, bbox, matrix); if (newStrokeRef) stroke = newStrokeRef; } } // Transform path data element.setAttribute('d', _transformPath(element.attributes.d.value, matrix)); element.removeAttribute('transform'); // Transform stroke width const matrixScale = _getScaleFactor(matrix); element.setAttribute('stroke-width', _quadraticMean(matrixScale.x, matrixScale.y) * strokeWidth); if (fill) element.setAttribute('fill', fill); if (stroke) element.setAttribute('stroke', stroke); } else if (_isGraphicsElement(element)) { // Push stroke width, fill, and stroke down to leaves if (strokeWidth && !element.attributes['stroke-width']) { element.setAttribute('stroke-width', strokeWidth); } if (fill && !element.attributes.fill) { element.setAttribute('fill', fill); } if (stroke && !element.attributes.stroke) { element.setAttribute('stroke', stroke); } // Push transform down to leaves matrix = Matrix.compose(matrix, _parseTransform(element)); if (Matrix.toString(matrix) === Matrix.toString(Matrix.identity())) { element.removeAttribute('transform'); } else { element.setAttribute('transform', Matrix.toString(matrix)); } } }; applyTransforms(svgTag, inherited, 1 /* default SVG stroke width */ ); }; module.exports = transformStrokeWidths; /***/ }), /***/ "./node_modules/scratch-svg-renderer/src/util/log.js": /*!***********************************************************!*\ !*** ./node_modules/scratch-svg-renderer/src/util/log.js ***! \***********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const minilog = __webpack_require__(/*! minilog */ "./node_modules/minilog/lib/web/index.js"); minilog.enable(); module.exports = minilog('scratch-svg-render'); /***/ }), /***/ "./node_modules/scratch-translate-extension-languages/languages.json": /*!***************************************************************************!*\ !*** ./node_modules/scratch-translate-extension-languages/languages.json ***! \***************************************************************************/ /*! exports provided: menuMap, nameMap, scratchToGoogleMap, previouslySupported, spokenLanguages, default */ /***/ (function(module) { module.exports = JSON.parse("{\"menuMap\":{\"cs\":[{\"code\":\"am\",\"name\":\"amharština\"},{\"code\":\"en\",\"name\":\"angličtina\"},{\"code\":\"ar\",\"name\":\"arabština\"},{\"code\":\"az\",\"name\":\"ázerbájdžánština\"},{\"code\":\"eu\",\"name\":\"baskičtina\"},{\"code\":\"bg\",\"name\":\"bulharština\"},{\"code\":\"cs\",\"name\":\"čeština\"},{\"code\":\"zh-tw\",\"name\":\"čínština (tradiční)\"},{\"code\":\"zh-cn\",\"name\":\"čínština (zjednodušená)\"},{\"code\":\"da\",\"name\":\"dánština\"},{\"code\":\"et\",\"name\":\"estonština\"},{\"code\":\"fi\",\"name\":\"finština\"},{\"code\":\"fr\",\"name\":\"francouzština\"},{\"code\":\"gl\",\"name\":\"galicijština\"},{\"code\":\"he\",\"name\":\"hebrejština\"},{\"code\":\"nl\",\"name\":\"holandština\"},{\"code\":\"hr\",\"name\":\"chorvatština\"},{\"code\":\"id\",\"name\":\"indonéština\"},{\"code\":\"ga\",\"name\":\"irština\"},{\"code\":\"is\",\"name\":\"islandština\"},{\"code\":\"it\",\"name\":\"italština\"},{\"code\":\"ja\",\"name\":\"japonština\"},{\"code\":\"ca\",\"name\":\"katalánština\"},{\"code\":\"ko\",\"name\":\"korejština\"},{\"code\":\"lt\",\"name\":\"litevština\"},{\"code\":\"lv\",\"name\":\"lotyština\"},{\"code\":\"hu\",\"name\":\"maďarština\"},{\"code\":\"mi\",\"name\":\"maorština\"},{\"code\":\"de\",\"name\":\"němčina\"},{\"code\":\"nb\",\"name\":\"norština\"},{\"code\":\"fa\",\"name\":\"perština\"},{\"code\":\"pl\",\"name\":\"polština\"},{\"code\":\"pt\",\"name\":\"portugalština\"},{\"code\":\"ro\",\"name\":\"rumunština\"},{\"code\":\"ru\",\"name\":\"ruština\"},{\"code\":\"el\",\"name\":\"řečtina\"},{\"code\":\"gd\",\"name\":\"skotská gaelština\"},{\"code\":\"sk\",\"name\":\"slovenština\"},{\"code\":\"sl\",\"name\":\"slovinština\"},{\"code\":\"sr\",\"name\":\"srbština\"},{\"code\":\"es\",\"name\":\"španělština\"},{\"code\":\"sv\",\"name\":\"švédština\"},{\"code\":\"th\",\"name\":\"thajština\"},{\"code\":\"tr\",\"name\":\"turečtina\"},{\"code\":\"uk\",\"name\":\"ukrajinština\"},{\"code\":\"cy\",\"name\":\"velština\"},{\"code\":\"vi\",\"name\":\"vietnamština\"},{\"code\":\"zu\",\"name\":\"zulu\"}],\"da\":[{\"code\":\"am\",\"name\":\"Amharisk\"},{\"code\":\"ar\",\"name\":\"Arabisk\"},{\"code\":\"az\",\"name\":\"Aserbajdsjansk\"},{\"code\":\"eu\",\"name\":\"Baskisk\"},{\"code\":\"bg\",\"name\":\"Bulgarsk\"},{\"code\":\"da\",\"name\":\"Dansk\"},{\"code\":\"en\",\"name\":\"Engelsk\"},{\"code\":\"et\",\"name\":\"Estisk\"},{\"code\":\"fi\",\"name\":\"Finsk\"},{\"code\":\"fr\",\"name\":\"Fransk\"},{\"code\":\"gl\",\"name\":\"Galicisk\"},{\"code\":\"el\",\"name\":\"Græsk\"},{\"code\":\"he\",\"name\":\"Hebraisk\"},{\"code\":\"nl\",\"name\":\"Hollandsk\"},{\"code\":\"id\",\"name\":\"Indonesisk\"},{\"code\":\"ga\",\"name\":\"Irsk\"},{\"code\":\"is\",\"name\":\"Islandsk\"},{\"code\":\"it\",\"name\":\"Italiensk\"},{\"code\":\"ja\",\"name\":\"Japansk\"},{\"code\":\"ca\",\"name\":\"Katalansk\"},{\"code\":\"zh-cn\",\"name\":\"Kinesisk (forenklet)\"},{\"code\":\"zh-tw\",\"name\":\"Kinesisk (traditionelt)\"},{\"code\":\"ko\",\"name\":\"Koreansk\"},{\"code\":\"hr\",\"name\":\"Kroatisk\"},{\"code\":\"lv\",\"name\":\"Lettisk\"},{\"code\":\"lt\",\"name\":\"Litauisk\"},{\"code\":\"mi\",\"name\":\"Maori\"},{\"code\":\"nb\",\"name\":\"Norsk\"},{\"code\":\"fa\",\"name\":\"Persisk\"},{\"code\":\"pl\",\"name\":\"Polsk\"},{\"code\":\"pt\",\"name\":\"Portugisisk\"},{\"code\":\"ro\",\"name\":\"Rumænsk\"},{\"code\":\"ru\",\"name\":\"Russisk\"},{\"code\":\"sr\",\"name\":\"Serbisk\"},{\"code\":\"gd\",\"name\":\"Skotsk gælisk\"},{\"code\":\"sk\",\"name\":\"Slovakisk\"},{\"code\":\"sl\",\"name\":\"Slovensk\"},{\"code\":\"es\",\"name\":\"Spansk\"},{\"code\":\"sv\",\"name\":\"Svensk\"},{\"code\":\"th\",\"name\":\"Thailandsk\"},{\"code\":\"cs\",\"name\":\"Tjekkisk\"},{\"code\":\"tr\",\"name\":\"Tyrkisk\"},{\"code\":\"de\",\"name\":\"Tysk\"},{\"code\":\"uk\",\"name\":\"Ukrainsk\"},{\"code\":\"hu\",\"name\":\"Ungarsk\"},{\"code\":\"vi\",\"name\":\"Vietnamesisk\"},{\"code\":\"cy\",\"name\":\"Walisisk\"},{\"code\":\"zu\",\"name\":\"Zulu\"}],\"gl\":[{\"code\":\"az\",\"name\":\"acerbaixano\"},{\"code\":\"de\",\"name\":\"alemán\"},{\"code\":\"am\",\"name\":\"amárico\"},{\"code\":\"ar\",\"name\":\"árabe\"},{\"code\":\"bg\",\"name\":\"búlgaro\"},{\"code\":\"ca\",\"name\":\"catalán\"},{\"code\":\"cs\",\"name\":\"checo\"},{\"code\":\"zh-cn\",\"name\":\"chinés (simplificado)\"},{\"code\":\"zh-tw\",\"name\":\"chinés (tradicional)\"},{\"code\":\"ko\",\"name\":\"coreano\"},{\"code\":\"hr\",\"name\":\"croata\"},{\"code\":\"da\",\"name\":\"dinamarqués\"},{\"code\":\"sk\",\"name\":\"eslovaco\"},{\"code\":\"sl\",\"name\":\"esloveno\"},{\"code\":\"es\",\"name\":\"español\"},{\"code\":\"et\",\"name\":\"estoniano\"},{\"code\":\"eu\",\"name\":\"éuscaro\"},{\"code\":\"fi\",\"name\":\"finés\"},{\"code\":\"fr\",\"name\":\"francés\"},{\"code\":\"gd\",\"name\":\"gaélico escocés\"},{\"code\":\"gl\",\"name\":\"galego\"},{\"code\":\"cy\",\"name\":\"galés\"},{\"code\":\"el\",\"name\":\"grego\"},{\"code\":\"he\",\"name\":\"hebreo\"},{\"code\":\"hu\",\"name\":\"húngaro\"},{\"code\":\"id\",\"name\":\"indonesio\"},{\"code\":\"en\",\"name\":\"inglés\"},{\"code\":\"ga\",\"name\":\"irlandés\"},{\"code\":\"is\",\"name\":\"islandés\"},{\"code\":\"it\",\"name\":\"italiano\"},{\"code\":\"lv\",\"name\":\"letón\"},{\"code\":\"lt\",\"name\":\"lituano\"},{\"code\":\"mi\",\"name\":\"maorí\"},{\"code\":\"nl\",\"name\":\"neerlandés\"},{\"code\":\"nb\",\"name\":\"noruegués\"},{\"code\":\"fa\",\"name\":\"persa\"},{\"code\":\"pl\",\"name\":\"polaco\"},{\"code\":\"pt\",\"name\":\"portugués\"},{\"code\":\"ro\",\"name\":\"romanés\"},{\"code\":\"ru\",\"name\":\"ruso\"},{\"code\":\"sr\",\"name\":\"serbio\"},{\"code\":\"sv\",\"name\":\"sueco\"},{\"code\":\"th\",\"name\":\"tailandés\"},{\"code\":\"tr\",\"name\":\"turco\"},{\"code\":\"uk\",\"name\":\"ucraíno\"},{\"code\":\"vi\",\"name\":\"vietnamita\"},{\"code\":\"ja\",\"name\":\"xaponés\"},{\"code\":\"zu\",\"name\":\"zulú\"}],\"sl\":[{\"code\":\"am\",\"name\":\"amharščina\"},{\"code\":\"en\",\"name\":\"angleščina\"},{\"code\":\"ar\",\"name\":\"arabščina\"},{\"code\":\"az\",\"name\":\"azerbajdžanščina\"},{\"code\":\"eu\",\"name\":\"baskovščina\"},{\"code\":\"bg\",\"name\":\"bolgarščina\"},{\"code\":\"cs\",\"name\":\"češčina\"},{\"code\":\"da\",\"name\":\"danščina\"},{\"code\":\"et\",\"name\":\"estonščina\"},{\"code\":\"fi\",\"name\":\"finščina\"},{\"code\":\"fr\",\"name\":\"francoščina\"},{\"code\":\"gl\",\"name\":\"galicijščina\"},{\"code\":\"el\",\"name\":\"grščina\"},{\"code\":\"he\",\"name\":\"hebrejščina\"},{\"code\":\"hr\",\"name\":\"hrvaščina\"},{\"code\":\"id\",\"name\":\"indonezijščina\"},{\"code\":\"ga\",\"name\":\"irščina\"},{\"code\":\"is\",\"name\":\"islandščina\"},{\"code\":\"it\",\"name\":\"italijanščina\"},{\"code\":\"ja\",\"name\":\"japonščina\"},{\"code\":\"ca\",\"name\":\"katalonščina\"},{\"code\":\"zh-cn\",\"name\":\"kitajščina (poenostavljena)\"},{\"code\":\"zh-tw\",\"name\":\"kitajščina (tradicionalna)\"},{\"code\":\"ko\",\"name\":\"korejščina\"},{\"code\":\"lv\",\"name\":\"latvijščina\"},{\"code\":\"lt\",\"name\":\"litovščina\"},{\"code\":\"hu\",\"name\":\"madžarščina\"},{\"code\":\"mi\",\"name\":\"maorščina\"},{\"code\":\"de\",\"name\":\"nemščina\"},{\"code\":\"nl\",\"name\":\"nizozemščina\"},{\"code\":\"nb\",\"name\":\"norveščina\"},{\"code\":\"fa\",\"name\":\"perzijščina\"},{\"code\":\"pl\",\"name\":\"poljščina\"},{\"code\":\"pt\",\"name\":\"portugalščina\"},{\"code\":\"ro\",\"name\":\"romunščina\"},{\"code\":\"ru\",\"name\":\"ruščina\"},{\"code\":\"sk\",\"name\":\"slovaščina\"},{\"code\":\"sl\",\"name\":\"slovenščina\"},{\"code\":\"sr\",\"name\":\"srbščina\"},{\"code\":\"gd\",\"name\":\"škotska gelščina\"},{\"code\":\"es\",\"name\":\"španščina\"},{\"code\":\"sv\",\"name\":\"švedščina\"},{\"code\":\"th\",\"name\":\"tajščina\"},{\"code\":\"tr\",\"name\":\"turščina\"},{\"code\":\"uk\",\"name\":\"ukrajinščina\"},{\"code\":\"cy\",\"name\":\"valižanščina\"},{\"code\":\"vi\",\"name\":\"vietnamščina\"},{\"code\":\"zu\",\"name\":\"zulujščina\"}],\"fr\":[{\"code\":\"de\",\"name\":\"Allemand\"},{\"code\":\"am\",\"name\":\"Amharique\"},{\"code\":\"en\",\"name\":\"Anglais\"},{\"code\":\"ar\",\"name\":\"Arabe\"},{\"code\":\"az\",\"name\":\"Azéri\"},{\"code\":\"eu\",\"name\":\"Basque\"},{\"code\":\"bg\",\"name\":\"Bulgare\"},{\"code\":\"ca\",\"name\":\"Catalan\"},{\"code\":\"zh-cn\",\"name\":\"Chinois (simplifié)\"},{\"code\":\"zh-tw\",\"name\":\"Chinois (traditionnel)\"},{\"code\":\"ko\",\"name\":\"Coréen\"},{\"code\":\"hr\",\"name\":\"Croate\"},{\"code\":\"da\",\"name\":\"Danois\"},{\"code\":\"es\",\"name\":\"Espagnol\"},{\"code\":\"et\",\"name\":\"Estonien\"},{\"code\":\"fi\",\"name\":\"Finnois\"},{\"code\":\"fr\",\"name\":\"Français\"},{\"code\":\"gd\",\"name\":\"Gaélique (Écosse)\"},{\"code\":\"gl\",\"name\":\"Galicien\"},{\"code\":\"cy\",\"name\":\"Gallois\"},{\"code\":\"el\",\"name\":\"Grec\"},{\"code\":\"he\",\"name\":\"Hébreu\"},{\"code\":\"hu\",\"name\":\"Hongrois\"},{\"code\":\"id\",\"name\":\"Indonésien\"},{\"code\":\"ga\",\"name\":\"Irlandais\"},{\"code\":\"is\",\"name\":\"Islandais\"},{\"code\":\"it\",\"name\":\"Italien\"},{\"code\":\"ja\",\"name\":\"Japonais\"},{\"code\":\"lv\",\"name\":\"Letton\"},{\"code\":\"lt\",\"name\":\"Lituanien\"},{\"code\":\"mi\",\"name\":\"Maori\"},{\"code\":\"nl\",\"name\":\"Néerlandais\"},{\"code\":\"nb\",\"name\":\"Norvégien\"},{\"code\":\"fa\",\"name\":\"Persan\"},{\"code\":\"pl\",\"name\":\"Polonais\"},{\"code\":\"pt\",\"name\":\"Portugais\"},{\"code\":\"ro\",\"name\":\"Roumain\"},{\"code\":\"ru\",\"name\":\"Russe\"},{\"code\":\"sr\",\"name\":\"Serbe\"},{\"code\":\"sk\",\"name\":\"Slovaque\"},{\"code\":\"sl\",\"name\":\"Slovène\"},{\"code\":\"sv\",\"name\":\"Suédois\"},{\"code\":\"cs\",\"name\":\"Tchèque\"},{\"code\":\"th\",\"name\":\"Thaï\"},{\"code\":\"tr\",\"name\":\"Turc\"},{\"code\":\"uk\",\"name\":\"Ukrainien\"},{\"code\":\"vi\",\"name\":\"Vietnamien\"},{\"code\":\"zu\",\"name\":\"Zoulou\"}],\"hu\":[{\"code\":\"am\",\"name\":\"amhara\"},{\"code\":\"en\",\"name\":\"angol\"},{\"code\":\"ar\",\"name\":\"arab\"},{\"code\":\"az\",\"name\":\"azeri\"},{\"code\":\"eu\",\"name\":\"baszk\"},{\"code\":\"bg\",\"name\":\"bolgár\"},{\"code\":\"cs\",\"name\":\"cseh\"},{\"code\":\"da\",\"name\":\"dán\"},{\"code\":\"et\",\"name\":\"észt\"},{\"code\":\"fi\",\"name\":\"finn\"},{\"code\":\"fr\",\"name\":\"francia\"},{\"code\":\"gl\",\"name\":\"galíciai\"},{\"code\":\"el\",\"name\":\"görög\"},{\"code\":\"he\",\"name\":\"héber\"},{\"code\":\"nl\",\"name\":\"holland\"},{\"code\":\"hr\",\"name\":\"horvát\"},{\"code\":\"id\",\"name\":\"indonéz\"},{\"code\":\"ga\",\"name\":\"ír\"},{\"code\":\"is\",\"name\":\"izlandi\"},{\"code\":\"ja\",\"name\":\"japán\"},{\"code\":\"ca\",\"name\":\"katalán\"},{\"code\":\"zh-cn\",\"name\":\"kínai (egyszerűsített)\"},{\"code\":\"zh-tw\",\"name\":\"kínai (hagyományos)\"},{\"code\":\"ko\",\"name\":\"koreai\"},{\"code\":\"pl\",\"name\":\"lengyel\"},{\"code\":\"lv\",\"name\":\"lett\"},{\"code\":\"lt\",\"name\":\"litván\"},{\"code\":\"hu\",\"name\":\"magyar\"},{\"code\":\"mi\",\"name\":\"maori\"},{\"code\":\"de\",\"name\":\"német\"},{\"code\":\"nb\",\"name\":\"norvég\"},{\"code\":\"it\",\"name\":\"olasz\"},{\"code\":\"ru\",\"name\":\"orosz\"},{\"code\":\"fa\",\"name\":\"perzsa\"},{\"code\":\"pt\",\"name\":\"portugál\"},{\"code\":\"ro\",\"name\":\"román\"},{\"code\":\"gd\",\"name\":\"skót-gael\"},{\"code\":\"es\",\"name\":\"spanyol\"},{\"code\":\"sv\",\"name\":\"svéd\"},{\"code\":\"sr\",\"name\":\"szerb\"},{\"code\":\"sk\",\"name\":\"szlovák\"},{\"code\":\"sl\",\"name\":\"szlovén\"},{\"code\":\"th\",\"name\":\"thai\"},{\"code\":\"tr\",\"name\":\"török\"},{\"code\":\"uk\",\"name\":\"ukrán\"},{\"code\":\"vi\",\"name\":\"vietnami\"},{\"code\":\"cy\",\"name\":\"walesi\"},{\"code\":\"zu\",\"name\":\"zulu\"}],\"uk\":[{\"code\":\"az\",\"name\":\"азербайджанська\"},{\"code\":\"am\",\"name\":\"амхарська\"},{\"code\":\"en\",\"name\":\"англійська\"},{\"code\":\"ar\",\"name\":\"арабська\"},{\"code\":\"eu\",\"name\":\"баскська\"},{\"code\":\"bg\",\"name\":\"болгарська\"},{\"code\":\"vi\",\"name\":\"в’єтнамська\"},{\"code\":\"cy\",\"name\":\"валлійська\"},{\"code\":\"el\",\"name\":\"грецька\"},{\"code\":\"gl\",\"name\":\"ґалісійська\"},{\"code\":\"da\",\"name\":\"данська\"},{\"code\":\"et\",\"name\":\"естонська\"},{\"code\":\"zu\",\"name\":\"зулу\"},{\"code\":\"he\",\"name\":\"іврит\"},{\"code\":\"id\",\"name\":\"індонезійська\"},{\"code\":\"ga\",\"name\":\"ірландська\"},{\"code\":\"is\",\"name\":\"ісландська\"},{\"code\":\"es\",\"name\":\"іспанська\"},{\"code\":\"it\",\"name\":\"італійська\"},{\"code\":\"ca\",\"name\":\"каталанська\"},{\"code\":\"zh-cn\",\"name\":\"китайська (спрощена)\"},{\"code\":\"zh-tw\",\"name\":\"китайська (традиційна)\"},{\"code\":\"ko\",\"name\":\"корейська\"},{\"code\":\"lv\",\"name\":\"латиська\"},{\"code\":\"lt\",\"name\":\"литовська\"},{\"code\":\"mi\",\"name\":\"маорі\"},{\"code\":\"nl\",\"name\":\"нідерландська\"},{\"code\":\"de\",\"name\":\"німецька\"},{\"code\":\"nb\",\"name\":\"норвезька\"},{\"code\":\"fa\",\"name\":\"перська\"},{\"code\":\"pl\",\"name\":\"польська\"},{\"code\":\"pt\",\"name\":\"португальська\"},{\"code\":\"ru\",\"name\":\"російська\"},{\"code\":\"ro\",\"name\":\"румунська\"},{\"code\":\"sr\",\"name\":\"сербська\"},{\"code\":\"sk\",\"name\":\"словацька\"},{\"code\":\"sl\",\"name\":\"словенська\"},{\"code\":\"th\",\"name\":\"тайська\"},{\"code\":\"tr\",\"name\":\"турецька\"},{\"code\":\"hu\",\"name\":\"угорська\"},{\"code\":\"uk\",\"name\":\"українська\"},{\"code\":\"fi\",\"name\":\"фінська\"},{\"code\":\"fr\",\"name\":\"французька\"},{\"code\":\"hr\",\"name\":\"хорватська\"},{\"code\":\"cs\",\"name\":\"чеська\"},{\"code\":\"sv\",\"name\":\"шведська\"},{\"code\":\"gd\",\"name\":\"шотландська (ґельська)\"},{\"code\":\"ja\",\"name\":\"японська\"}],\"zh-tw\":[{\"code\":\"tr\",\"name\":\"土耳其文\"},{\"code\":\"zh-tw\",\"name\":\"中文(繁體)\"},{\"code\":\"zh-cn\",\"name\":\"中文(簡體)\"},{\"code\":\"da\",\"name\":\"丹麥文\"},{\"code\":\"eu\",\"name\":\"巴斯克文\"},{\"code\":\"ja\",\"name\":\"日文\"},{\"code\":\"mi\",\"name\":\"毛利文\"},{\"code\":\"gl\",\"name\":\"加里西亞文\"},{\"code\":\"ca\",\"name\":\"加泰羅尼亞文\"},{\"code\":\"lt\",\"name\":\"立陶宛文\"},{\"code\":\"is\",\"name\":\"冰島文\"},{\"code\":\"hu\",\"name\":\"匈牙利文\"},{\"code\":\"id\",\"name\":\"印尼文\"},{\"code\":\"es\",\"name\":\"西班牙文\"},{\"code\":\"hr\",\"name\":\"克羅埃西亞文\"},{\"code\":\"he\",\"name\":\"希伯來文\"},{\"code\":\"el\",\"name\":\"希臘文\"},{\"code\":\"az\",\"name\":\"亞塞拜然文\"},{\"code\":\"lv\",\"name\":\"拉脫維亞文\"},{\"code\":\"fr\",\"name\":\"法文\"},{\"code\":\"fa\",\"name\":\"波斯文\"},{\"code\":\"pl\",\"name\":\"波蘭文\"},{\"code\":\"fi\",\"name\":\"芬蘭文\"},{\"code\":\"am\",\"name\":\"阿姆哈拉文\"},{\"code\":\"ar\",\"name\":\"阿拉伯文\"},{\"code\":\"ru\",\"name\":\"俄文\"},{\"code\":\"bg\",\"name\":\"保加利亞文\"},{\"code\":\"zu\",\"name\":\"南非祖魯文\"},{\"code\":\"cy\",\"name\":\"威爾斯文\"},{\"code\":\"en\",\"name\":\"英文\"},{\"code\":\"nb\",\"name\":\"挪威文\"},{\"code\":\"th\",\"name\":\"泰文\"},{\"code\":\"uk\",\"name\":\"烏克蘭文\"},{\"code\":\"cs\",\"name\":\"捷克文\"},{\"code\":\"nl\",\"name\":\"荷蘭文\"},{\"code\":\"sk\",\"name\":\"斯洛伐克文\"},{\"code\":\"sl\",\"name\":\"斯洛維尼亞文\"},{\"code\":\"vi\",\"name\":\"越南文\"},{\"code\":\"sr\",\"name\":\"塞爾維亞文\"},{\"code\":\"et\",\"name\":\"愛沙尼亞文\"},{\"code\":\"ga\",\"name\":\"愛爾蘭文\"},{\"code\":\"sv\",\"name\":\"瑞典文\"},{\"code\":\"it\",\"name\":\"義大利文\"},{\"code\":\"pt\",\"name\":\"葡萄牙文\"},{\"code\":\"de\",\"name\":\"德文\"},{\"code\":\"ko\",\"name\":\"韓文\"},{\"code\":\"ro\",\"name\":\"羅馬尼亞文\"},{\"code\":\"gd\",\"name\":\"蘇格蘭的蓋爾文\"}],\"pt\":[{\"code\":\"am\",\"name\":\"Amharic\"},{\"code\":\"ar\",\"name\":\"Arabic\"},{\"code\":\"az\",\"name\":\"Azerbaijani\"},{\"code\":\"eu\",\"name\":\"Basque\"},{\"code\":\"bg\",\"name\":\"Bulgarian\"},{\"code\":\"ca\",\"name\":\"Catalan\"},{\"code\":\"zh-cn\",\"name\":\"Chinese (Simplified)\"},{\"code\":\"zh-tw\",\"name\":\"Chinese (Traditional)\"},{\"code\":\"hr\",\"name\":\"Croatian\"},{\"code\":\"cs\",\"name\":\"Czech\"},{\"code\":\"da\",\"name\":\"Danish\"},{\"code\":\"nl\",\"name\":\"Dutch\"},{\"code\":\"en\",\"name\":\"English\"},{\"code\":\"et\",\"name\":\"Estonian\"},{\"code\":\"fi\",\"name\":\"Finnish\"},{\"code\":\"fr\",\"name\":\"French\"},{\"code\":\"gl\",\"name\":\"Galician\"},{\"code\":\"de\",\"name\":\"German\"},{\"code\":\"el\",\"name\":\"Greek\"},{\"code\":\"he\",\"name\":\"Hebrew\"},{\"code\":\"hu\",\"name\":\"Hungarian\"},{\"code\":\"is\",\"name\":\"Icelandic\"},{\"code\":\"id\",\"name\":\"Indonesian\"},{\"code\":\"ga\",\"name\":\"Irish\"},{\"code\":\"it\",\"name\":\"Italian\"},{\"code\":\"ja\",\"name\":\"Japanese\"},{\"code\":\"ko\",\"name\":\"Korean\"},{\"code\":\"lv\",\"name\":\"Latvian\"},{\"code\":\"lt\",\"name\":\"Lithuanian\"},{\"code\":\"mi\",\"name\":\"Maori\"},{\"code\":\"nb\",\"name\":\"Norwegian\"},{\"code\":\"fa\",\"name\":\"Persian\"},{\"code\":\"pl\",\"name\":\"Polish\"},{\"code\":\"pt\",\"name\":\"Portuguese\"},{\"code\":\"ro\",\"name\":\"Romanian\"},{\"code\":\"ru\",\"name\":\"Russian\"},{\"code\":\"gd\",\"name\":\"Scots Gaelic\"},{\"code\":\"sr\",\"name\":\"Serbian\"},{\"code\":\"sk\",\"name\":\"Slovak\"},{\"code\":\"sl\",\"name\":\"Slovenian\"},{\"code\":\"es\",\"name\":\"Spanish\"},{\"code\":\"sv\",\"name\":\"Swedish\"},{\"code\":\"th\",\"name\":\"Thai\"},{\"code\":\"tr\",\"name\":\"Turkish\"},{\"code\":\"uk\",\"name\":\"Ukrainian\"},{\"code\":\"vi\",\"name\":\"Vietnamese\"},{\"code\":\"cy\",\"name\":\"Welsh\"},{\"code\":\"zu\",\"name\":\"Zulu\"}],\"pt-br\":[{\"code\":\"de\",\"name\":\"Alemão\"},{\"code\":\"am\",\"name\":\"Amárico\"},{\"code\":\"ar\",\"name\":\"Árabe\"},{\"code\":\"az\",\"name\":\"Azerbaijano\"},{\"code\":\"eu\",\"name\":\"Basco\"},{\"code\":\"bg\",\"name\":\"Búlgaro\"},{\"code\":\"ca\",\"name\":\"Catalão\"},{\"code\":\"zh-cn\",\"name\":\"Chinês (simplificado)\"},{\"code\":\"zh-tw\",\"name\":\"Chinês (tradicional)\"},{\"code\":\"ko\",\"name\":\"Coreano\"},{\"code\":\"hr\",\"name\":\"Croata\"},{\"code\":\"da\",\"name\":\"Dinamarquês\"},{\"code\":\"sk\",\"name\":\"Eslovaco\"},{\"code\":\"sl\",\"name\":\"Esloveno\"},{\"code\":\"es\",\"name\":\"Espanhol\"},{\"code\":\"et\",\"name\":\"Estoniano\"},{\"code\":\"fi\",\"name\":\"Finlandês\"},{\"code\":\"fr\",\"name\":\"Francês\"},{\"code\":\"gd\",\"name\":\"Gaélico escocês\"},{\"code\":\"gl\",\"name\":\"Galego\"},{\"code\":\"cy\",\"name\":\"Galês\"},{\"code\":\"el\",\"name\":\"Grego\"},{\"code\":\"he\",\"name\":\"Hebraico\"},{\"code\":\"nl\",\"name\":\"Holandês\"},{\"code\":\"hu\",\"name\":\"Húngaro\"},{\"code\":\"id\",\"name\":\"Indonésio\"},{\"code\":\"en\",\"name\":\"Inglês\"},{\"code\":\"ga\",\"name\":\"Irlandês\"},{\"code\":\"is\",\"name\":\"Islandês\"},{\"code\":\"it\",\"name\":\"Italiano\"},{\"code\":\"ja\",\"name\":\"Japonês\"},{\"code\":\"lv\",\"name\":\"Letão\"},{\"code\":\"lt\",\"name\":\"Lituano\"},{\"code\":\"mi\",\"name\":\"Maori\"},{\"code\":\"nb\",\"name\":\"Norueguês\"},{\"code\":\"fa\",\"name\":\"Persa\"},{\"code\":\"pl\",\"name\":\"Polonês\"},{\"code\":\"pt\",\"name\":\"Português\"},{\"code\":\"ro\",\"name\":\"Romeno\"},{\"code\":\"ru\",\"name\":\"Russo\"},{\"code\":\"sr\",\"name\":\"Sérvio\"},{\"code\":\"sv\",\"name\":\"Sueco\"},{\"code\":\"th\",\"name\":\"Tailandês\"},{\"code\":\"cs\",\"name\":\"Tcheco\"},{\"code\":\"tr\",\"name\":\"Turco\"},{\"code\":\"uk\",\"name\":\"Ucraniano\"},{\"code\":\"vi\",\"name\":\"Vietnamita\"},{\"code\":\"zu\",\"name\":\"Zulu\"}],\"tr\":[{\"code\":\"de\",\"name\":\"Almanca\"},{\"code\":\"ar\",\"name\":\"Arapça\"},{\"code\":\"az\",\"name\":\"Azerice\"},{\"code\":\"eu\",\"name\":\"Baskça\"},{\"code\":\"bg\",\"name\":\"Bulgarca\"},{\"code\":\"cs\",\"name\":\"Çekçe\"},{\"code\":\"zh-cn\",\"name\":\"Çince (Basitleştirilmiş)\"},{\"code\":\"zh-tw\",\"name\":\"Çince (Geleneksel)\"},{\"code\":\"da\",\"name\":\"Danca\"},{\"code\":\"id\",\"name\":\"Endonezya Dili\"},{\"code\":\"et\",\"name\":\"Estonyaca\"},{\"code\":\"fa\",\"name\":\"Farsça\"},{\"code\":\"nl\",\"name\":\"Felemenkçe\"},{\"code\":\"fi\",\"name\":\"Fince\"},{\"code\":\"fr\",\"name\":\"Fransızca\"},{\"code\":\"cy\",\"name\":\"Galce\"},{\"code\":\"gl\",\"name\":\"Galiçyaca\"},{\"code\":\"am\",\"name\":\"Habeşçe\"},{\"code\":\"hr\",\"name\":\"Hırvatça\"},{\"code\":\"he\",\"name\":\"İbranice\"},{\"code\":\"en\",\"name\":\"İngilizce\"},{\"code\":\"ga\",\"name\":\"İrlandaca\"},{\"code\":\"es\",\"name\":\"İspanyolca\"},{\"code\":\"sv\",\"name\":\"İsveççe\"},{\"code\":\"it\",\"name\":\"İtalyanca\"},{\"code\":\"is\",\"name\":\"İzlandaca\"},{\"code\":\"ja\",\"name\":\"Japonca\"},{\"code\":\"ca\",\"name\":\"Katalanca\"},{\"code\":\"ko\",\"name\":\"Korece\"},{\"code\":\"gd\",\"name\":\"Kuzey İskoç Dili\"},{\"code\":\"pl\",\"name\":\"Lehçe\"},{\"code\":\"lv\",\"name\":\"Letonca\"},{\"code\":\"lt\",\"name\":\"Litvanca\"},{\"code\":\"hu\",\"name\":\"Macarca\"},{\"code\":\"mi\",\"name\":\"Maori Dili\"},{\"code\":\"nb\",\"name\":\"Norveççe\"},{\"code\":\"pt\",\"name\":\"Portekizce\"},{\"code\":\"ro\",\"name\":\"Romence\"},{\"code\":\"ru\",\"name\":\"Rusça\"},{\"code\":\"sr\",\"name\":\"Sırpça\"},{\"code\":\"sk\",\"name\":\"Slovakça\"},{\"code\":\"sl\",\"name\":\"Slovence\"},{\"code\":\"th\",\"name\":\"Tay Dili\"},{\"code\":\"tr\",\"name\":\"Türkçe\"},{\"code\":\"uk\",\"name\":\"Ukraynaca\"},{\"code\":\"vi\",\"name\":\"Vietnamca\"},{\"code\":\"el\",\"name\":\"Yunanca\"},{\"code\":\"zu\",\"name\":\"Zulu\"}],\"ga\":[{\"code\":\"am\",\"name\":\"Amárais\"},{\"code\":\"ar\",\"name\":\"Araibis\"},{\"code\":\"az\",\"name\":\"Asarbaiseáinis\"},{\"code\":\"eu\",\"name\":\"Bascais\"},{\"code\":\"en\",\"name\":\"Béarla\"},{\"code\":\"cy\",\"name\":\"Breatnais\"},{\"code\":\"bg\",\"name\":\"Bulgáiris\"},{\"code\":\"ca\",\"name\":\"Catalóinis\"},{\"code\":\"ko\",\"name\":\"Cóiréis\"},{\"code\":\"hr\",\"name\":\"Cróitis\"},{\"code\":\"da\",\"name\":\"Danmhairgis\"},{\"code\":\"he\",\"name\":\"Eabhrais\"},{\"code\":\"et\",\"name\":\"Eastóinis\"},{\"code\":\"fi\",\"name\":\"Fionlainnis\"},{\"code\":\"fr\",\"name\":\"Fraincis\"},{\"code\":\"ga\",\"name\":\"Gaeilge\"},{\"code\":\"gd\",\"name\":\"Gaeilge na hAlban\"},{\"code\":\"gl\",\"name\":\"Gailísis\"},{\"code\":\"de\",\"name\":\"Gearmáinis\"},{\"code\":\"el\",\"name\":\"Gréigis\"},{\"code\":\"id\",\"name\":\"Indinéisis\"},{\"code\":\"it\",\"name\":\"Iodáilis\"},{\"code\":\"nb\",\"name\":\"Ioruais\"},{\"code\":\"is\",\"name\":\"Íoslainnis\"},{\"code\":\"lv\",\"name\":\"Laitvis\"},{\"code\":\"lt\",\"name\":\"Liotuáinis\"},{\"code\":\"mi\",\"name\":\"Maorais\"},{\"code\":\"nl\",\"name\":\"Ollainnis\"},{\"code\":\"fa\",\"name\":\"Peirsis\"},{\"code\":\"pl\",\"name\":\"Polainnis\"},{\"code\":\"pt\",\"name\":\"Portaingéilis\"},{\"code\":\"ro\",\"name\":\"Rómáinis\"},{\"code\":\"ru\",\"name\":\"Rúisis\"},{\"code\":\"ja\",\"name\":\"Seapáinis\"},{\"code\":\"cs\",\"name\":\"Seicis\"},{\"code\":\"sr\",\"name\":\"Seirbis\"},{\"code\":\"zh-cn\",\"name\":\"Sínis (Simplithe)\"},{\"code\":\"zh-tw\",\"name\":\"Sínis (Traidisiúnta)\"},{\"code\":\"sl\",\"name\":\"Slóivéinis\"},{\"code\":\"sk\",\"name\":\"Slóvaicis\"},{\"code\":\"es\",\"name\":\"Spáinnis\"},{\"code\":\"sv\",\"name\":\"Sualainnis\"},{\"code\":\"zu\",\"name\":\"Súlúis\"},{\"code\":\"th\",\"name\":\"Téalainnis\"},{\"code\":\"tr\",\"name\":\"Tuircis\"},{\"code\":\"uk\",\"name\":\"Úcráinis\"},{\"code\":\"hu\",\"name\":\"Ungáiris\"},{\"code\":\"vi\",\"name\":\"Vítneaimis\"}],\"th\":[{\"code\":\"el\",\"name\":\"ภาษากรีก\"},{\"code\":\"gl\",\"name\":\"ภาษากาลิเชียน\"},{\"code\":\"gd\",\"name\":\"ภาษาเกลิกในสก็อต\"},{\"code\":\"ko\",\"name\":\"ภาษาเกาหลี\"},{\"code\":\"ca\",\"name\":\"ภาษาคาตาลัน\"},{\"code\":\"hr\",\"name\":\"ภาษาโครเอเชีย\"},{\"code\":\"zh-tw\",\"name\":\"ภาษาจีน (ดั้งเดิม)\"},{\"code\":\"zh-cn\",\"name\":\"ภาษาจีน (แบบย่อ)\"},{\"code\":\"cs\",\"name\":\"ภาษาเช็ก\"},{\"code\":\"zu\",\"name\":\"ภาษาซูลู\"},{\"code\":\"sr\",\"name\":\"ภาษาเซอร์เบียน\"},{\"code\":\"ja\",\"name\":\"ภาษาญี่ปุ่น\"},{\"code\":\"nl\",\"name\":\"ภาษาดัตช์\"},{\"code\":\"da\",\"name\":\"ภาษาเดนมาร์ก\"},{\"code\":\"tr\",\"name\":\"ภาษาตุรกี\"},{\"code\":\"th\",\"name\":\"ภาษาไทย\"},{\"code\":\"nb\",\"name\":\"ภาษานอร์เวย์\"},{\"code\":\"bg\",\"name\":\"ภาษาบัลกาเรีย\"},{\"code\":\"eu\",\"name\":\"ภาษาบาสก์\"},{\"code\":\"fa\",\"name\":\"ภาษาเปอร์เซีย\"},{\"code\":\"pt\",\"name\":\"ภาษาโปรตุเกส\"},{\"code\":\"pl\",\"name\":\"ภาษาโปแลนด์\"},{\"code\":\"fr\",\"name\":\"ภาษาฝรั่งเศส\"},{\"code\":\"fi\",\"name\":\"ภาษาฟินแลนด์\"},{\"code\":\"mi\",\"name\":\"ภาษาเมารี\"},{\"code\":\"uk\",\"name\":\"ภาษายูเครน\"},{\"code\":\"de\",\"name\":\"ภาษาเยอรมัน\"},{\"code\":\"ru\",\"name\":\"ภาษารัสเซีย\"},{\"code\":\"ro\",\"name\":\"ภาษาโรมาเนีย\"},{\"code\":\"lv\",\"name\":\"ภาษาลัทเวีย\"},{\"code\":\"lt\",\"name\":\"ภาษาลิทัวเนีย\"},{\"code\":\"cy\",\"name\":\"ภาษาเวลส์\"},{\"code\":\"vi\",\"name\":\"ภาษาเวียดนาม\"},{\"code\":\"es\",\"name\":\"ภาษาสเปน\"},{\"code\":\"sk\",\"name\":\"ภาษาสโลวัก\"},{\"code\":\"sl\",\"name\":\"ภาษาสโลเวเนีย\"},{\"code\":\"sv\",\"name\":\"ภาษาสวีเดน\"},{\"code\":\"en\",\"name\":\"ภาษาอังกฤษ\"},{\"code\":\"am\",\"name\":\"ภาษาอัมฮาริก\"},{\"code\":\"az\",\"name\":\"ภาษาอาร์เซอร์ไบจัน\"},{\"code\":\"ar\",\"name\":\"ภาษาอาหรับ\"},{\"code\":\"it\",\"name\":\"ภาษาอิตาลี\"},{\"code\":\"id\",\"name\":\"ภาษาอินโดนีเซีย\"},{\"code\":\"et\",\"name\":\"ภาษาเอสโทเนีย\"},{\"code\":\"is\",\"name\":\"ภาษาไอซ์แลนดิก\"},{\"code\":\"ga\",\"name\":\"ภาษาไอริช\"},{\"code\":\"hu\",\"name\":\"ภาษาฮังการี\"},{\"code\":\"he\",\"name\":\"ภาษาฮิบรู\"}],\"ja\":[{\"code\":\"is\",\"name\":\"アイスランド語\"},{\"code\":\"ga\",\"name\":\"アイルランド語\"},{\"code\":\"az\",\"name\":\"アゼルバイジャン語\"},{\"code\":\"am\",\"name\":\"アムハラ語\"},{\"code\":\"ar\",\"name\":\"アラビア語\"},{\"code\":\"it\",\"name\":\"イタリア語\"},{\"code\":\"id\",\"name\":\"インドネシア語\"},{\"code\":\"cy\",\"name\":\"ウェールズ語\"},{\"code\":\"uk\",\"name\":\"ウクライナ語\"},{\"code\":\"et\",\"name\":\"エストニア語\"},{\"code\":\"nl\",\"name\":\"オランダ語\"},{\"code\":\"ca\",\"name\":\"カタルーニャ語\"},{\"code\":\"gl\",\"name\":\"ガリシア語\"},{\"code\":\"el\",\"name\":\"ギリシャ語\"},{\"code\":\"hr\",\"name\":\"クロアチア語\"},{\"code\":\"sv\",\"name\":\"スウェーデン語\"},{\"code\":\"zu\",\"name\":\"ズールー語\"},{\"code\":\"gd\",\"name\":\"スコットランド ゲール語\"},{\"code\":\"es\",\"name\":\"スペイン語\"},{\"code\":\"sk\",\"name\":\"スロバキア語\"},{\"code\":\"sl\",\"name\":\"スロベニア語\"},{\"code\":\"sr\",\"name\":\"セルビア語\"},{\"code\":\"th\",\"name\":\"タイ語\"},{\"code\":\"cs\",\"name\":\"チェコ語\"},{\"code\":\"da\",\"name\":\"デンマーク語\"},{\"code\":\"de\",\"name\":\"ドイツ語\"},{\"code\":\"tr\",\"name\":\"トルコ語\"},{\"code\":\"nb\",\"name\":\"ノルウェー語\"},{\"code\":\"eu\",\"name\":\"バスク語\"},{\"code\":\"hu\",\"name\":\"ハンガリー語\"},{\"code\":\"fi\",\"name\":\"フィンランド語\"},{\"code\":\"fr\",\"name\":\"フランス語\"},{\"code\":\"bg\",\"name\":\"ブルガリア語\"},{\"code\":\"vi\",\"name\":\"ベトナム語\"},{\"code\":\"he\",\"name\":\"ヘブライ語\"},{\"code\":\"fa\",\"name\":\"ペルシャ語\"},{\"code\":\"pl\",\"name\":\"ポーランド語\"},{\"code\":\"pt\",\"name\":\"ポルトガル語\"},{\"code\":\"mi\",\"name\":\"マオリ語\"},{\"code\":\"lv\",\"name\":\"ラトビア語\"},{\"code\":\"lt\",\"name\":\"リトアニア語\"},{\"code\":\"ro\",\"name\":\"ルーマニア語\"},{\"code\":\"ru\",\"name\":\"ロシア語\"},{\"code\":\"en\",\"name\":\"英語\"},{\"code\":\"ko\",\"name\":\"韓国語\"},{\"code\":\"zh-cn\",\"name\":\"中国語(簡体)\"},{\"code\":\"zh-tw\",\"name\":\"中国語(繁体)\"},{\"code\":\"ja\",\"name\":\"日本語\"}],\"ja-hira\":[{\"code\":\"is\",\"name\":\"アイスランド語\"},{\"code\":\"ga\",\"name\":\"アイルランド語\"},{\"code\":\"az\",\"name\":\"アゼルバイジャン語\"},{\"code\":\"am\",\"name\":\"アムハラ語\"},{\"code\":\"ar\",\"name\":\"アラビア語\"},{\"code\":\"it\",\"name\":\"イタリア語\"},{\"code\":\"id\",\"name\":\"インドネシア語\"},{\"code\":\"cy\",\"name\":\"ウェールズ語\"},{\"code\":\"uk\",\"name\":\"ウクライナ語\"},{\"code\":\"et\",\"name\":\"エストニア語\"},{\"code\":\"nl\",\"name\":\"オランダ語\"},{\"code\":\"ca\",\"name\":\"カタルーニャ語\"},{\"code\":\"gl\",\"name\":\"ガリシア語\"},{\"code\":\"el\",\"name\":\"ギリシャ語\"},{\"code\":\"hr\",\"name\":\"クロアチア語\"},{\"code\":\"sv\",\"name\":\"スウェーデン語\"},{\"code\":\"zu\",\"name\":\"ズールー語\"},{\"code\":\"gd\",\"name\":\"スコットランド ゲール語\"},{\"code\":\"es\",\"name\":\"スペイン語\"},{\"code\":\"sk\",\"name\":\"スロバキア語\"},{\"code\":\"sl\",\"name\":\"スロベニア語\"},{\"code\":\"sr\",\"name\":\"セルビア語\"},{\"code\":\"th\",\"name\":\"タイ語\"},{\"code\":\"cs\",\"name\":\"チェコ語\"},{\"code\":\"da\",\"name\":\"デンマーク語\"},{\"code\":\"de\",\"name\":\"ドイツ語\"},{\"code\":\"tr\",\"name\":\"トルコ語\"},{\"code\":\"nb\",\"name\":\"ノルウェー語\"},{\"code\":\"eu\",\"name\":\"バスク語\"},{\"code\":\"hu\",\"name\":\"ハンガリー語\"},{\"code\":\"fi\",\"name\":\"フィンランド語\"},{\"code\":\"fr\",\"name\":\"フランス語\"},{\"code\":\"bg\",\"name\":\"ブルガリア語\"},{\"code\":\"vi\",\"name\":\"ベトナム語\"},{\"code\":\"he\",\"name\":\"ヘブライ語\"},{\"code\":\"fa\",\"name\":\"ペルシャ語\"},{\"code\":\"pl\",\"name\":\"ポーランド語\"},{\"code\":\"pt\",\"name\":\"ポルトガル語\"},{\"code\":\"mi\",\"name\":\"マオリ語\"},{\"code\":\"lv\",\"name\":\"ラトビア語\"},{\"code\":\"lt\",\"name\":\"リトアニア語\"},{\"code\":\"ro\",\"name\":\"ルーマニア語\"},{\"code\":\"ru\",\"name\":\"ロシア語\"},{\"code\":\"en\",\"name\":\"英語\"},{\"code\":\"ko\",\"name\":\"韓国語\"},{\"code\":\"zh-cn\",\"name\":\"中国語(簡体)\"},{\"code\":\"zh-tw\",\"name\":\"中国語(繁体)\"},{\"code\":\"ja\",\"name\":\"日本語\"}],\"nl\":[{\"code\":\"am\",\"name\":\"Amharisch\"},{\"code\":\"ar\",\"name\":\"Arabisch\"},{\"code\":\"az\",\"name\":\"Azerbeidzjaans\"},{\"code\":\"eu\",\"name\":\"Baskisch\"},{\"code\":\"bg\",\"name\":\"Bulgaars\"},{\"code\":\"ca\",\"name\":\"Catalaans\"},{\"code\":\"zh-tw\",\"name\":\"Chinees (traditioneel)\"},{\"code\":\"zh-cn\",\"name\":\"Chinees (vereenvoudigd)\"},{\"code\":\"da\",\"name\":\"Deens\"},{\"code\":\"de\",\"name\":\"Duits\"},{\"code\":\"en\",\"name\":\"Engels\"},{\"code\":\"et\",\"name\":\"Ests\"},{\"code\":\"fi\",\"name\":\"Fins\"},{\"code\":\"fr\",\"name\":\"Frans\"},{\"code\":\"gl\",\"name\":\"Galicisch\"},{\"code\":\"el\",\"name\":\"Grieks\"},{\"code\":\"he\",\"name\":\"Hebreeuws\"},{\"code\":\"hu\",\"name\":\"Hongaars\"},{\"code\":\"ga\",\"name\":\"Iers\"},{\"code\":\"is\",\"name\":\"IJslands\"},{\"code\":\"id\",\"name\":\"Indonesisch\"},{\"code\":\"it\",\"name\":\"Italiaans\"},{\"code\":\"ja\",\"name\":\"Japans\"},{\"code\":\"ko\",\"name\":\"Koreaans\"},{\"code\":\"hr\",\"name\":\"Kroatisch\"},{\"code\":\"lv\",\"name\":\"Lets\"},{\"code\":\"lt\",\"name\":\"Litouws\"},{\"code\":\"mi\",\"name\":\"Maori\"},{\"code\":\"nl\",\"name\":\"Nederlands\"},{\"code\":\"nb\",\"name\":\"Noors\"},{\"code\":\"uk\",\"name\":\"Oekraïens\"},{\"code\":\"fa\",\"name\":\"Perzisch\"},{\"code\":\"pl\",\"name\":\"Pools\"},{\"code\":\"pt\",\"name\":\"Portugees\"},{\"code\":\"ro\",\"name\":\"Roemeens\"},{\"code\":\"ru\",\"name\":\"Russisch\"},{\"code\":\"gd\",\"name\":\"Schots Keltisch\"},{\"code\":\"sr\",\"name\":\"Servisch\"},{\"code\":\"sk\",\"name\":\"Slovaaks\"},{\"code\":\"sl\",\"name\":\"Sloveens\"},{\"code\":\"es\",\"name\":\"Spaans\"},{\"code\":\"th\",\"name\":\"Thai\"},{\"code\":\"cs\",\"name\":\"Tsjechisch\"},{\"code\":\"tr\",\"name\":\"Turks\"},{\"code\":\"vi\",\"name\":\"Vietnamees\"},{\"code\":\"cy\",\"name\":\"Wels\"},{\"code\":\"zu\",\"name\":\"Zoeloe\"},{\"code\":\"sv\",\"name\":\"Zweeds\"}],\"gd\":[{\"code\":\"am\",\"name\":\"Amtharais\"},{\"code\":\"ar\",\"name\":\"Arabais\"},{\"code\":\"az\",\"name\":\"Asarbaideànais\"},{\"code\":\"eu\",\"name\":\"Basgais\"},{\"code\":\"en\",\"name\":\"Beurla\"},{\"code\":\"vi\",\"name\":\"Bhiet-Namais\"},{\"code\":\"bg\",\"name\":\"Bulgarais\"},{\"code\":\"th\",\"name\":\"Cànan nan Tàidh\"},{\"code\":\"ca\",\"name\":\"Catalanais\"},{\"code\":\"ko\",\"name\":\"Coirèanais\"},{\"code\":\"hr\",\"name\":\"Cròthaisis\"},{\"code\":\"cy\",\"name\":\"Cuimris\"},{\"code\":\"da\",\"name\":\"Danmhairgis\"},{\"code\":\"nl\",\"name\":\"Duitsis\"},{\"code\":\"he\",\"name\":\"Eabhra\"},{\"code\":\"it\",\"name\":\"Eadailtis\"},{\"code\":\"et\",\"name\":\"Eastoinis\"},{\"code\":\"fi\",\"name\":\"Fionnlannais\"},{\"code\":\"fr\",\"name\":\"Fraingis\"},{\"code\":\"ga\",\"name\":\"Gaeilge\"},{\"code\":\"gd\",\"name\":\"Gàidhlig\"},{\"code\":\"gl\",\"name\":\"Gailìsis\"},{\"code\":\"de\",\"name\":\"Gearmailtis\"},{\"code\":\"el\",\"name\":\"Grèigis\"},{\"code\":\"id\",\"name\":\"Innd-Innsis\"},{\"code\":\"is\",\"name\":\"Innis-Tìlis\"},{\"code\":\"lv\",\"name\":\"Laitbheis\"},{\"code\":\"lt\",\"name\":\"Liotuainis\"},{\"code\":\"mi\",\"name\":\"Māori\"},{\"code\":\"nb\",\"name\":\"Nirribhis\"},{\"code\":\"fa\",\"name\":\"Peirsis\"},{\"code\":\"pl\",\"name\":\"Pòlainnis\"},{\"code\":\"pt\",\"name\":\"Portagailis\"},{\"code\":\"ro\",\"name\":\"Romàinis\"},{\"code\":\"ru\",\"name\":\"Ruisis\"},{\"code\":\"cs\",\"name\":\"Seacais\"},{\"code\":\"ja\",\"name\":\"Seapanais\"},{\"code\":\"sr\",\"name\":\"Sèirbis\"},{\"code\":\"zh-tw\",\"name\":\"Sìonais (seann-nòsach)\"},{\"code\":\"zh-cn\",\"name\":\"Sìonais (sìmplichte)\"},{\"code\":\"sk\",\"name\":\"Slòbhacais\"},{\"code\":\"sl\",\"name\":\"Slòbhainis\"},{\"code\":\"es\",\"name\":\"Spàinntis\"},{\"code\":\"sv\",\"name\":\"Suainis\"},{\"code\":\"tr\",\"name\":\"Turcais\"},{\"code\":\"uk\",\"name\":\"Ucràinis\"},{\"code\":\"hu\",\"name\":\"Ungairis\"},{\"code\":\"zu\",\"name\":\"Zulu\"}],\"nb\":[{\"code\":\"am\",\"name\":\"amharisk\"},{\"code\":\"ar\",\"name\":\"arabisk\"},{\"code\":\"az\",\"name\":\"aserbajdsjansk\"},{\"code\":\"eu\",\"name\":\"baskisk\"},{\"code\":\"bg\",\"name\":\"bulgarsk\"},{\"code\":\"da\",\"name\":\"dansk\"},{\"code\":\"en\",\"name\":\"engelsk\"},{\"code\":\"et\",\"name\":\"estisk\"},{\"code\":\"fa\",\"name\":\"farsi\"},{\"code\":\"fi\",\"name\":\"finsk\"},{\"code\":\"fr\",\"name\":\"fransk\"},{\"code\":\"gl\",\"name\":\"galisisk\"},{\"code\":\"el\",\"name\":\"gresk\"},{\"code\":\"he\",\"name\":\"hebraisk\"},{\"code\":\"id\",\"name\":\"indonesisk\"},{\"code\":\"ga\",\"name\":\"irsk\"},{\"code\":\"is\",\"name\":\"islandsk\"},{\"code\":\"it\",\"name\":\"italiensk\"},{\"code\":\"ja\",\"name\":\"japansk\"},{\"code\":\"ca\",\"name\":\"katalansk\"},{\"code\":\"zh-cn\",\"name\":\"kinesisk (forenklet)\"},{\"code\":\"zh-tw\",\"name\":\"kinesisk (tradisjonell)\"},{\"code\":\"ko\",\"name\":\"koreansk\"},{\"code\":\"hr\",\"name\":\"kroatisk\"},{\"code\":\"lv\",\"name\":\"latvisk\"},{\"code\":\"lt\",\"name\":\"litauisk\"},{\"code\":\"mi\",\"name\":\"maori\"},{\"code\":\"nl\",\"name\":\"nederlandsk\"},{\"code\":\"nb\",\"name\":\"norsk\"},{\"code\":\"pl\",\"name\":\"polsk\"},{\"code\":\"pt\",\"name\":\"portugisisk\"},{\"code\":\"ro\",\"name\":\"rumensk\"},{\"code\":\"ru\",\"name\":\"russisk\"},{\"code\":\"sr\",\"name\":\"serbisk\"},{\"code\":\"gd\",\"name\":\"skotsk gælisk\"},{\"code\":\"sk\",\"name\":\"slovakisk\"},{\"code\":\"sl\",\"name\":\"slovensk\"},{\"code\":\"es\",\"name\":\"spansk\"},{\"code\":\"sv\",\"name\":\"svensk\"},{\"code\":\"th\",\"name\":\"thai\"},{\"code\":\"cs\",\"name\":\"tsjekkisk\"},{\"code\":\"tr\",\"name\":\"tyrkisk\"},{\"code\":\"de\",\"name\":\"tysk\"},{\"code\":\"uk\",\"name\":\"ukrainsk\"},{\"code\":\"hu\",\"name\":\"ungarsk\"},{\"code\":\"vi\",\"name\":\"vietnamesisk\"},{\"code\":\"cy\",\"name\":\"walisisk\"},{\"code\":\"zu\",\"name\":\"zulu\"}],\"de\":[{\"code\":\"am\",\"name\":\"Amharisch\"},{\"code\":\"ar\",\"name\":\"Arabisch\"},{\"code\":\"az\",\"name\":\"Aserbaidschanisch\"},{\"code\":\"eu\",\"name\":\"Baskisch\"},{\"code\":\"bg\",\"name\":\"Bulgarisch\"},{\"code\":\"zh-tw\",\"name\":\"Chinesisch (traditionell)\"},{\"code\":\"zh-cn\",\"name\":\"Chinesisch (vereinfacht)\"},{\"code\":\"da\",\"name\":\"Dänisch\"},{\"code\":\"de\",\"name\":\"Deutsch\"},{\"code\":\"en\",\"name\":\"Englisch\"},{\"code\":\"et\",\"name\":\"Estnisch\"},{\"code\":\"fi\",\"name\":\"Finnisch\"},{\"code\":\"fr\",\"name\":\"Französisch\"},{\"code\":\"gl\",\"name\":\"Galizisch\"},{\"code\":\"el\",\"name\":\"Griechisch\"},{\"code\":\"he\",\"name\":\"Hebräisch\"},{\"code\":\"id\",\"name\":\"Indonesisch\"},{\"code\":\"ga\",\"name\":\"Irisch\"},{\"code\":\"is\",\"name\":\"Isländisch\"},{\"code\":\"it\",\"name\":\"Italienisch\"},{\"code\":\"ja\",\"name\":\"Japanisch\"},{\"code\":\"ca\",\"name\":\"Katalanisch\"},{\"code\":\"ko\",\"name\":\"Koreanisch\"},{\"code\":\"hr\",\"name\":\"Kroatisch\"},{\"code\":\"lv\",\"name\":\"Lettisch\"},{\"code\":\"lt\",\"name\":\"Litauisch\"},{\"code\":\"mi\",\"name\":\"Maori\"},{\"code\":\"nl\",\"name\":\"Niederländisch\"},{\"code\":\"nb\",\"name\":\"Norwegisch\"},{\"code\":\"fa\",\"name\":\"Persisch\"},{\"code\":\"pl\",\"name\":\"Polnisch\"},{\"code\":\"pt\",\"name\":\"Portugiesisch\"},{\"code\":\"ro\",\"name\":\"Rumänisch\"},{\"code\":\"ru\",\"name\":\"Russisch\"},{\"code\":\"gd\",\"name\":\"Schottisch-Gälisch\"},{\"code\":\"sv\",\"name\":\"Schwedisch\"},{\"code\":\"sr\",\"name\":\"Serbisch\"},{\"code\":\"sk\",\"name\":\"Slowakisch\"},{\"code\":\"sl\",\"name\":\"Slowenisch\"},{\"code\":\"es\",\"name\":\"Spanisch\"},{\"code\":\"th\",\"name\":\"Thailändisch\"},{\"code\":\"cs\",\"name\":\"Tschechisch\"},{\"code\":\"tr\",\"name\":\"Türkisch\"},{\"code\":\"uk\",\"name\":\"Ukrainisch\"},{\"code\":\"hu\",\"name\":\"Ungarisch\"},{\"code\":\"vi\",\"name\":\"Vietnamesisch\"},{\"code\":\"cy\",\"name\":\"Walisisch\"},{\"code\":\"zu\",\"name\":\"Zulu\"}],\"he\":[{\"code\":\"uk\",\"name\":\"אוקראינית\"},{\"code\":\"az\",\"name\":\"אזרית\"},{\"code\":\"it\",\"name\":\"איטלקית\"},{\"code\":\"id\",\"name\":\"אינדונזית\"},{\"code\":\"is\",\"name\":\"איסלנדית\"},{\"code\":\"ga\",\"name\":\"אירית\"},{\"code\":\"am\",\"name\":\"אמהרית\"},{\"code\":\"en\",\"name\":\"אנגלית\"},{\"code\":\"et\",\"name\":\"אסטונית\"},{\"code\":\"eu\",\"name\":\"באסקית\"},{\"code\":\"bg\",\"name\":\"בולגרית\"},{\"code\":\"gl\",\"name\":\"גליציאנית\"},{\"code\":\"de\",\"name\":\"גרמנית\"},{\"code\":\"da\",\"name\":\"דנית\"},{\"code\":\"nl\",\"name\":\"הולנדית\"},{\"code\":\"hu\",\"name\":\"הונגרית\"},{\"code\":\"cy\",\"name\":\"וולשית\"},{\"code\":\"vi\",\"name\":\"וייטנאמית\"},{\"code\":\"zu\",\"name\":\"זולו\"},{\"code\":\"tr\",\"name\":\"טורקית\"},{\"code\":\"el\",\"name\":\"יוונית\"},{\"code\":\"ja\",\"name\":\"יפנית\"},{\"code\":\"lv\",\"name\":\"לטווית\"},{\"code\":\"lt\",\"name\":\"ליטאית\"},{\"code\":\"mi\",\"name\":\"מאורית\"},{\"code\":\"nb\",\"name\":\"נורווגית\"},{\"code\":\"zh-tw\",\"name\":\"סינית (מסורתית)\"},{\"code\":\"zh-cn\",\"name\":\"סינית (פשוטה)\"},{\"code\":\"sl\",\"name\":\"סלובנית\"},{\"code\":\"sk\",\"name\":\"סלובקית\"},{\"code\":\"es\",\"name\":\"ספרדית\"},{\"code\":\"gd\",\"name\":\"סקוטית גאלית\"},{\"code\":\"sr\",\"name\":\"סרבית\"},{\"code\":\"he\",\"name\":\"עברית\"},{\"code\":\"ar\",\"name\":\"ערבית\"},{\"code\":\"pl\",\"name\":\"פולנית\"},{\"code\":\"pt\",\"name\":\"פורטוגזית\"},{\"code\":\"fi\",\"name\":\"פינית\"},{\"code\":\"fa\",\"name\":\"פרסית\"},{\"code\":\"cs\",\"name\":\"צ'כית\"},{\"code\":\"fr\",\"name\":\"צרפתית\"},{\"code\":\"ko\",\"name\":\"קוריאנית\"},{\"code\":\"ca\",\"name\":\"קטלאנית\"},{\"code\":\"hr\",\"name\":\"קרואטית\"},{\"code\":\"ro\",\"name\":\"רומנית\"},{\"code\":\"ru\",\"name\":\"רוסית\"},{\"code\":\"sv\",\"name\":\"שוודית\"},{\"code\":\"th\",\"name\":\"תאילנדית\"}],\"sk\":[{\"code\":\"am\",\"name\":\"amharčina\"},{\"code\":\"en\",\"name\":\"angličtina\"},{\"code\":\"ar\",\"name\":\"arabčina\"},{\"code\":\"az\",\"name\":\"azerbajdžančina\"},{\"code\":\"eu\",\"name\":\"baskičtina\"},{\"code\":\"bg\",\"name\":\"bulharčina\"},{\"code\":\"cs\",\"name\":\"čeština\"},{\"code\":\"zh-tw\",\"name\":\"čínština (tradičná)\"},{\"code\":\"zh-cn\",\"name\":\"čínština (zjednodušená)\"},{\"code\":\"da\",\"name\":\"dánčina\"},{\"code\":\"et\",\"name\":\"estónčina\"},{\"code\":\"fi\",\"name\":\"fínčina\"},{\"code\":\"fr\",\"name\":\"francúzština\"},{\"code\":\"gl\",\"name\":\"galícijčina\"},{\"code\":\"el\",\"name\":\"gréčtina\"},{\"code\":\"he\",\"name\":\"hebrejčina\"},{\"code\":\"nl\",\"name\":\"holandčina\"},{\"code\":\"hr\",\"name\":\"chorvátčina\"},{\"code\":\"id\",\"name\":\"indonézština\"},{\"code\":\"ga\",\"name\":\"írčina\"},{\"code\":\"is\",\"name\":\"islandčina\"},{\"code\":\"ja\",\"name\":\"japončina\"},{\"code\":\"ca\",\"name\":\"katalánčina\"},{\"code\":\"ko\",\"name\":\"kórejčina\"},{\"code\":\"lt\",\"name\":\"litovčina\"},{\"code\":\"lv\",\"name\":\"lotyština\"},{\"code\":\"hu\",\"name\":\"maďarčina\"},{\"code\":\"mi\",\"name\":\"maorijčina\"},{\"code\":\"de\",\"name\":\"nemčina\"},{\"code\":\"nb\",\"name\":\"nórčina\"},{\"code\":\"fa\",\"name\":\"perzština\"},{\"code\":\"pl\",\"name\":\"poľština\"},{\"code\":\"pt\",\"name\":\"portugalčina\"},{\"code\":\"ro\",\"name\":\"rumunčina\"},{\"code\":\"ru\",\"name\":\"ruština\"},{\"code\":\"sk\",\"name\":\"slovenčina\"},{\"code\":\"sl\",\"name\":\"slovinčina\"},{\"code\":\"sr\",\"name\":\"srbčina\"},{\"code\":\"gd\",\"name\":\"škótska gaelčina\"},{\"code\":\"es\",\"name\":\"španielčina\"},{\"code\":\"sv\",\"name\":\"švédčina\"},{\"code\":\"it\",\"name\":\"taliančina\"},{\"code\":\"th\",\"name\":\"thajčina\"},{\"code\":\"tr\",\"name\":\"turečtina\"},{\"code\":\"uk\",\"name\":\"ukrajinčina\"},{\"code\":\"vi\",\"name\":\"vietnamčina\"},{\"code\":\"cy\",\"name\":\"waleština\"},{\"code\":\"zu\",\"name\":\"zuluština\"}],\"zu\":[{\"code\":\"am\",\"name\":\"isi-Amharic\"},{\"code\":\"ar\",\"name\":\"isi-Arabic\"},{\"code\":\"az\",\"name\":\"Isi-Azerbaijani\"},{\"code\":\"eu\",\"name\":\"isi-Basque\"},{\"code\":\"bg\",\"name\":\"isi-Bulgarian\"},{\"code\":\"ca\",\"name\":\"isi-Catalan\"},{\"code\":\"zh-cn\",\"name\":\"isi-Chinese (Simplified)\"},{\"code\":\"zh-tw\",\"name\":\"isi-Chinese (Traditional)\"},{\"code\":\"hr\",\"name\":\"isi-Croatian\"},{\"code\":\"cs\",\"name\":\"isi-Czech\"},{\"code\":\"da\",\"name\":\"isi-Danish\"},{\"code\":\"nl\",\"name\":\"isi-Dutch\"},{\"code\":\"en\",\"name\":\"isi-English\"},{\"code\":\"et\",\"name\":\"isi-Estonian\"},{\"code\":\"fi\",\"name\":\"isi-Finnish\"},{\"code\":\"fr\",\"name\":\"isi-French\"},{\"code\":\"gl\",\"name\":\"isi-Galician\"},{\"code\":\"de\",\"name\":\"isi-German\"},{\"code\":\"el\",\"name\":\"isi-Greek\"},{\"code\":\"hu\",\"name\":\"isi-Hangarian\"},{\"code\":\"he\",\"name\":\"isi-Hebrew\"},{\"code\":\"is\",\"name\":\"isi-Icelandic\"},{\"code\":\"id\",\"name\":\"isi-Indonesian\"},{\"code\":\"ga\",\"name\":\"isi-Irish\"},{\"code\":\"it\",\"name\":\"isi-Italian\"},{\"code\":\"ja\",\"name\":\"isi-Japanese\"},{\"code\":\"ko\",\"name\":\"isi-Korean\"},{\"code\":\"lv\",\"name\":\"isi-Latvian\"},{\"code\":\"lt\",\"name\":\"isi-Lithuanian\"},{\"code\":\"mi\",\"name\":\"isi-Maori\"},{\"code\":\"nb\",\"name\":\"isi-Norwegian\"},{\"code\":\"fa\",\"name\":\"isi-Persian\"},{\"code\":\"pl\",\"name\":\"isi-Polish\"},{\"code\":\"pt\",\"name\":\"isi-Portuguese\"},{\"code\":\"ro\",\"name\":\"isi-Romanian\"},{\"code\":\"ru\",\"name\":\"isi-Russian\"},{\"code\":\"gd\",\"name\":\"isi-Scots Gaelic\"},{\"code\":\"sr\",\"name\":\"isi-Serbian\"},{\"code\":\"sk\",\"name\":\"isi-Slovak\"},{\"code\":\"sl\",\"name\":\"isi-Slovenian\"},{\"code\":\"es\",\"name\":\"isi-Spanish\"},{\"code\":\"sv\",\"name\":\"isi-Swedish\"},{\"code\":\"th\",\"name\":\"isi-Thai\"},{\"code\":\"tr\",\"name\":\"isi-Turkish\"},{\"code\":\"uk\",\"name\":\"isi-Ukrainian\"},{\"code\":\"vi\",\"name\":\"isi-Vietnamese\"},{\"code\":\"cy\",\"name\":\"isi-Welsh\"},{\"code\":\"zu\",\"name\":\"isiZulu\"}],\"ru\":[{\"code\":\"az\",\"name\":\"азербайджанский\"},{\"code\":\"am\",\"name\":\"амхарский\"},{\"code\":\"en\",\"name\":\"английский\"},{\"code\":\"ar\",\"name\":\"арабский\"},{\"code\":\"eu\",\"name\":\"баскский\"},{\"code\":\"bg\",\"name\":\"болгарский\"},{\"code\":\"cy\",\"name\":\"валлийский\"},{\"code\":\"hu\",\"name\":\"венгерский\"},{\"code\":\"vi\",\"name\":\"вьетнамский\"},{\"code\":\"gl\",\"name\":\"галисийский\"},{\"code\":\"el\",\"name\":\"греческий\"},{\"code\":\"da\",\"name\":\"датский\"},{\"code\":\"zu\",\"name\":\"зулу\"},{\"code\":\"he\",\"name\":\"иврит\"},{\"code\":\"id\",\"name\":\"индонезийский\"},{\"code\":\"ga\",\"name\":\"ирландский\"},{\"code\":\"is\",\"name\":\"исландский\"},{\"code\":\"es\",\"name\":\"испанский\"},{\"code\":\"it\",\"name\":\"итальянский\"},{\"code\":\"ca\",\"name\":\"каталанский\"},{\"code\":\"zh-tw\",\"name\":\"китайский (традиционный)\"},{\"code\":\"zh-cn\",\"name\":\"китайский (упрощенный)\"},{\"code\":\"ko\",\"name\":\"корейский\"},{\"code\":\"lv\",\"name\":\"латышский\"},{\"code\":\"lt\",\"name\":\"литовский\"},{\"code\":\"mi\",\"name\":\"маори\"},{\"code\":\"de\",\"name\":\"немецкий\"},{\"code\":\"nl\",\"name\":\"нидерландский\"},{\"code\":\"nb\",\"name\":\"норвежский\"},{\"code\":\"fa\",\"name\":\"персидский\"},{\"code\":\"pl\",\"name\":\"польский\"},{\"code\":\"pt\",\"name\":\"португальский\"},{\"code\":\"ro\",\"name\":\"румынский\"},{\"code\":\"ru\",\"name\":\"русский\"},{\"code\":\"sr\",\"name\":\"сербский\"},{\"code\":\"sk\",\"name\":\"словацкий\"},{\"code\":\"sl\",\"name\":\"словенский\"},{\"code\":\"th\",\"name\":\"тайский\"},{\"code\":\"tr\",\"name\":\"турецкий\"},{\"code\":\"uk\",\"name\":\"украинский\"},{\"code\":\"fi\",\"name\":\"финский\"},{\"code\":\"fr\",\"name\":\"французский\"},{\"code\":\"hr\",\"name\":\"хорватский\"},{\"code\":\"cs\",\"name\":\"чешский\"},{\"code\":\"sv\",\"name\":\"шведский\"},{\"code\":\"gd\",\"name\":\"шотландский (гэльский)\"},{\"code\":\"et\",\"name\":\"эстонский\"},{\"code\":\"ja\",\"name\":\"японский\"}],\"pl\":[{\"code\":\"am\",\"name\":\"amharski\"},{\"code\":\"en\",\"name\":\"angielski\"},{\"code\":\"ar\",\"name\":\"arabski\"},{\"code\":\"az\",\"name\":\"azerski\"},{\"code\":\"eu\",\"name\":\"baskijski\"},{\"code\":\"bg\",\"name\":\"bułgarski\"},{\"code\":\"zh-tw\",\"name\":\"chiński (tradycyjny)\"},{\"code\":\"zh-cn\",\"name\":\"chiński (uproszczony)\"},{\"code\":\"hr\",\"name\":\"chorwacki\"},{\"code\":\"cs\",\"name\":\"czeski\"},{\"code\":\"da\",\"name\":\"duński\"},{\"code\":\"et\",\"name\":\"estoński\"},{\"code\":\"fi\",\"name\":\"fiński\"},{\"code\":\"fr\",\"name\":\"francuski\"},{\"code\":\"gl\",\"name\":\"galicyjski\"},{\"code\":\"el\",\"name\":\"grecki\"},{\"code\":\"he\",\"name\":\"hebrajski\"},{\"code\":\"es\",\"name\":\"hiszpański\"},{\"code\":\"id\",\"name\":\"indonezyjski\"},{\"code\":\"ga\",\"name\":\"irlandzki\"},{\"code\":\"is\",\"name\":\"islandzki\"},{\"code\":\"ja\",\"name\":\"japoński\"},{\"code\":\"ca\",\"name\":\"kataloński\"},{\"code\":\"ko\",\"name\":\"koreański\"},{\"code\":\"lt\",\"name\":\"litewski\"},{\"code\":\"lv\",\"name\":\"łotewski\"},{\"code\":\"mi\",\"name\":\"maori\"},{\"code\":\"nl\",\"name\":\"niderlandzki\"},{\"code\":\"de\",\"name\":\"niemiecki\"},{\"code\":\"nb\",\"name\":\"norweski\"},{\"code\":\"fa\",\"name\":\"perski\"},{\"code\":\"pl\",\"name\":\"polski\"},{\"code\":\"pt\",\"name\":\"portugalski\"},{\"code\":\"ru\",\"name\":\"rosyjski\"},{\"code\":\"ro\",\"name\":\"rumuński\"},{\"code\":\"sr\",\"name\":\"serbski\"},{\"code\":\"sk\",\"name\":\"słowacki\"},{\"code\":\"sl\",\"name\":\"słoweński\"},{\"code\":\"gd\",\"name\":\"szkocki gaelicki\"},{\"code\":\"sv\",\"name\":\"szwedzki\"},{\"code\":\"th\",\"name\":\"tajski\"},{\"code\":\"tr\",\"name\":\"turecki\"},{\"code\":\"uk\",\"name\":\"ukraiński\"},{\"code\":\"cy\",\"name\":\"walijski\"},{\"code\":\"hu\",\"name\":\"węgierski\"},{\"code\":\"vi\",\"name\":\"wietnamski\"},{\"code\":\"it\",\"name\":\"włoski\"},{\"code\":\"zu\",\"name\":\"zulu\"}],\"am\":[{\"code\":\"hu\",\"name\":\"ሀንጋሪኛ\"},{\"code\":\"lt\",\"name\":\"ሊትዌንኛ\"},{\"code\":\"lv\",\"name\":\"ላትቪያኛ\"},{\"code\":\"mi\",\"name\":\"ማዮሪኛ\"},{\"code\":\"ru\",\"name\":\"ራሽያኛ\"},{\"code\":\"ro\",\"name\":\"ሮማኒያንኛ\"},{\"code\":\"sr\",\"name\":\"ሰርቢያኛ\"},{\"code\":\"sk\",\"name\":\"ስሎቫክኛ\"},{\"code\":\"sl\",\"name\":\"ስሎቬንያኛ\"},{\"code\":\"sv\",\"name\":\"ስዊድንኛ\"},{\"code\":\"es\",\"name\":\"ስፓኒሽኛ\"},{\"code\":\"bg\",\"name\":\"ቡልጋሪያኛ\"},{\"code\":\"eu\",\"name\":\"ባስክኛ\"},{\"code\":\"vi\",\"name\":\"ቪትናምኛ\"},{\"code\":\"tr\",\"name\":\"ቱርክኛ\"},{\"code\":\"th\",\"name\":\"ታይኛ\"},{\"code\":\"zh-cn\",\"name\":\"ቻይንኛ (ቀላሉ)\"},{\"code\":\"zh-tw\",\"name\":\"ቻይንኛ (ባሕላዊው)\"},{\"code\":\"cs\",\"name\":\"ቼክኛ\"},{\"code\":\"nb\",\"name\":\"ኖርዌጅያንኛ\"},{\"code\":\"am\",\"name\":\"አማርኛ\"},{\"code\":\"az\",\"name\":\"አዜርባይጃንኛ\"},{\"code\":\"ga\",\"name\":\"አይሪሽ\"},{\"code\":\"is\",\"name\":\"አይስላንድኛ\"},{\"code\":\"et\",\"name\":\"ኤስቶኒያኛ\"},{\"code\":\"id\",\"name\":\"እንዶኔዢያኛ\"},{\"code\":\"en\",\"name\":\"እንግሊዝኛ\"},{\"code\":\"ca\",\"name\":\"ካታላንኛ\"},{\"code\":\"hr\",\"name\":\"ክሮኤሽያኛ\"},{\"code\":\"ko\",\"name\":\"ኮሪያኛ\"},{\"code\":\"cy\",\"name\":\"ዌልሽ\"},{\"code\":\"ar\",\"name\":\"ዐረብኛ\"},{\"code\":\"he\",\"name\":\"ዕብራይስጥ\"},{\"code\":\"zu\",\"name\":\"ዙሉኛ\"},{\"code\":\"gd\",\"name\":\"የስኮት ጌልክኛ\"},{\"code\":\"uk\",\"name\":\"ዩክሬንኛ\"},{\"code\":\"nl\",\"name\":\"ደችኛ\"},{\"code\":\"da\",\"name\":\"ዴንሽኛ\"},{\"code\":\"de\",\"name\":\"ጀርመንኛ\"},{\"code\":\"ja\",\"name\":\"ጃፓንኛ\"},{\"code\":\"gl\",\"name\":\"ጋሊሺያኛ\"},{\"code\":\"el\",\"name\":\"ግሪክኛ\"},{\"code\":\"it\",\"name\":\"ጣሊያንኛ\"},{\"code\":\"fr\",\"name\":\"ፈረንሳይኛ\"},{\"code\":\"fi\",\"name\":\"ፊኒሽኛ\"},{\"code\":\"fa\",\"name\":\"ፐርሺያኛ\"},{\"code\":\"pl\",\"name\":\"ፖሊሽኛ\"},{\"code\":\"pt\",\"name\":\"ፖርቱጋሊኛ\"}],\"az\":[{\"code\":\"de\",\"name\":\"Alman\"},{\"code\":\"am\",\"name\":\"Amarikcə\"},{\"code\":\"az\",\"name\":\"Azərbaycan dili\"},{\"code\":\"eu\",\"name\":\"Bask\"},{\"code\":\"bg\",\"name\":\"Bolqar\"},{\"code\":\"cs\",\"name\":\"Çex\"},{\"code\":\"zh-tw\",\"name\":\"Çin (Ən'ənəvi)\"},{\"code\":\"zh-cn\",\"name\":\"Çin (Sadələşdirilmiş)\"},{\"code\":\"da\",\"name\":\"Danimarka\"},{\"code\":\"et\",\"name\":\"Eston\"},{\"code\":\"ar\",\"name\":\"Ərəb\"},{\"code\":\"fa\",\"name\":\"Fars Dili\"},{\"code\":\"fi\",\"name\":\"Fin\"},{\"code\":\"fr\",\"name\":\"Fransız\"},{\"code\":\"nl\",\"name\":\"Holland\"},{\"code\":\"hr\",\"name\":\"Xorvat\"},{\"code\":\"es\",\"name\":\"Ispan\"},{\"code\":\"id\",\"name\":\"İndoneziya\"},{\"code\":\"en\",\"name\":\"İngilis\"},{\"code\":\"ga\",\"name\":\"İrland\"},{\"code\":\"is\",\"name\":\"İsland\"},{\"code\":\"sv\",\"name\":\"İsveç\"},{\"code\":\"it\",\"name\":\"İtalyan\"},{\"code\":\"he\",\"name\":\"İvrit\"},{\"code\":\"ca\",\"name\":\"Katalan\"},{\"code\":\"ko\",\"name\":\"Koreya\"},{\"code\":\"gl\",\"name\":\"Qalisian\"},{\"code\":\"lv\",\"name\":\"Latış\"},{\"code\":\"lt\",\"name\":\"Litva\"},{\"code\":\"hu\",\"name\":\"Macar\"},{\"code\":\"mi\",\"name\":\"Maoricə\"},{\"code\":\"nb\",\"name\":\"Norveç\"},{\"code\":\"pl\",\"name\":\"Polyak\"},{\"code\":\"pt\",\"name\":\"Portuqal\"},{\"code\":\"ro\",\"name\":\"Rumın\"},{\"code\":\"ru\",\"name\":\"Rus\"},{\"code\":\"sr\",\"name\":\"Serb\"},{\"code\":\"sk\",\"name\":\"Slovak\"},{\"code\":\"sl\",\"name\":\"Sloven\"},{\"code\":\"gd\",\"name\":\"Şotland (Kelt)\"},{\"code\":\"th\",\"name\":\"Tayca\"},{\"code\":\"tr\",\"name\":\"Türk\"},{\"code\":\"cy\",\"name\":\"Uels\"},{\"code\":\"uk\",\"name\":\"Ukrayna\"},{\"code\":\"vi\",\"name\":\"Vyetnam\"},{\"code\":\"ja\",\"name\":\"Yapon\"},{\"code\":\"el\",\"name\":\"Yunan\"},{\"code\":\"zu\",\"name\":\"Zulu dili\"}],\"hr\":[{\"code\":\"am\",\"name\":\"amharik\"},{\"code\":\"ar\",\"name\":\"arapski\"},{\"code\":\"az\",\"name\":\"azerbajdžanski\"},{\"code\":\"eu\",\"name\":\"baskijski\"},{\"code\":\"bg\",\"name\":\"bugarski\"},{\"code\":\"cs\",\"name\":\"češki\"},{\"code\":\"da\",\"name\":\"danski\"},{\"code\":\"en\",\"name\":\"engleski\"},{\"code\":\"et\",\"name\":\"estonski\"},{\"code\":\"fi\",\"name\":\"finski\"},{\"code\":\"fr\",\"name\":\"francuski\"},{\"code\":\"gl\",\"name\":\"galski\"},{\"code\":\"el\",\"name\":\"grčki\"},{\"code\":\"he\",\"name\":\"hebrejski\"},{\"code\":\"hr\",\"name\":\"hrvatski\"},{\"code\":\"id\",\"name\":\"indonezijski\"},{\"code\":\"ga\",\"name\":\"irski\"},{\"code\":\"is\",\"name\":\"islandski\"},{\"code\":\"ja\",\"name\":\"japanski\"},{\"code\":\"ca\",\"name\":\"katalonski\"},{\"code\":\"zh-cn\",\"name\":\"kineski (pojednost.)\"},{\"code\":\"zh-tw\",\"name\":\"kineski (tradicionalni)\"},{\"code\":\"ko\",\"name\":\"korejski\"},{\"code\":\"lv\",\"name\":\"latvijski/letonski\"},{\"code\":\"lt\",\"name\":\"litvanski\"},{\"code\":\"hu\",\"name\":\"mađarski\"},{\"code\":\"mi\",\"name\":\"maori\"},{\"code\":\"nl\",\"name\":\"nizozemski\"},{\"code\":\"nb\",\"name\":\"norveški\"},{\"code\":\"de\",\"name\":\"njemački\"},{\"code\":\"fa\",\"name\":\"perzijski\"},{\"code\":\"pl\",\"name\":\"poljski\"},{\"code\":\"pt\",\"name\":\"portugalski\"},{\"code\":\"ro\",\"name\":\"rumunjski\"},{\"code\":\"ru\",\"name\":\"ruski\"},{\"code\":\"sk\",\"name\":\"slovački\"},{\"code\":\"sl\",\"name\":\"slovenski\"},{\"code\":\"sr\",\"name\":\"srpski\"},{\"code\":\"gd\",\"name\":\"škotski keltski\"},{\"code\":\"es\",\"name\":\"španjolski\"},{\"code\":\"sv\",\"name\":\"švedski\"},{\"code\":\"th\",\"name\":\"tajlandski\"},{\"code\":\"it\",\"name\":\"talijanski\"},{\"code\":\"tr\",\"name\":\"turski\"},{\"code\":\"uk\",\"name\":\"ukrajinski\"},{\"code\":\"cy\",\"name\":\"velški\"},{\"code\":\"vi\",\"name\":\"vijetnamski\"},{\"code\":\"zu\",\"name\":\"zulu\"}],\"fa\":[{\"code\":\"az\",\"name\":\"آذرباﻳﺠﺎﻧﻰ\"},{\"code\":\"de\",\"name\":\"آلمانی\"},{\"code\":\"es\",\"name\":\"اسپانیایی\"},{\"code\":\"et\",\"name\":\"استونيايی\"},{\"code\":\"sk\",\"name\":\"اسلواکی\"},{\"code\":\"sl\",\"name\":\"اسلونیایی\"},{\"code\":\"uk\",\"name\":\"اکراينی\"},{\"code\":\"am\",\"name\":\"امهری\"},{\"code\":\"id\",\"name\":\"اندونزيايی\"},{\"code\":\"en\",\"name\":\"انگلیسی\"},{\"code\":\"it\",\"name\":\"ایتالیایی\"},{\"code\":\"ga\",\"name\":\"ایرلندی\"},{\"code\":\"is\",\"name\":\"ايسلندی\"},{\"code\":\"eu\",\"name\":\"باسکی\"},{\"code\":\"bg\",\"name\":\"بلغاری\"},{\"code\":\"pt\",\"name\":\"پرتغالی\"},{\"code\":\"th\",\"name\":\"تايلندی\"},{\"code\":\"tr\",\"name\":\"ترکی استانبولی\"},{\"code\":\"cs\",\"name\":\"چک\"},{\"code\":\"zh-cn\",\"name\":\"چینی (ساده‌شده)\"},{\"code\":\"zh-tw\",\"name\":\"چینی (سنتی)\"},{\"code\":\"da\",\"name\":\"دانمارکی\"},{\"code\":\"ru\",\"name\":\"روسی\"},{\"code\":\"ro\",\"name\":\"رومانيايی\"},{\"code\":\"zu\",\"name\":\"زولو\"},{\"code\":\"ja\",\"name\":\"ژاپنی\"},{\"code\":\"sv\",\"name\":\"سوئدی\"},{\"code\":\"sr\",\"name\":\"صربی\"},{\"code\":\"he\",\"name\":\"عبری\"},{\"code\":\"ar\",\"name\":\"عربی\"},{\"code\":\"fa\",\"name\":\"فارسی\"},{\"code\":\"fr\",\"name\":\"فرانسوی\"},{\"code\":\"fi\",\"name\":\"فنلاندی\"},{\"code\":\"ca\",\"name\":\"کاتالان\"},{\"code\":\"hr\",\"name\":\"کرواتی\"},{\"code\":\"ko\",\"name\":\"کره‌ای\"},{\"code\":\"gl\",\"name\":\"گالیسی\"},{\"code\":\"gd\",\"name\":\"گاليک اسکاتلندی\"},{\"code\":\"lv\",\"name\":\"لتونيايی\"},{\"code\":\"pl\",\"name\":\"لهستانی\"},{\"code\":\"lt\",\"name\":\"ليتوانيايی\"},{\"code\":\"mi\",\"name\":\"مائوری\"},{\"code\":\"hu\",\"name\":\"مجاری\"},{\"code\":\"nb\",\"name\":\"نروژی\"},{\"code\":\"cy\",\"name\":\"ولزی\"},{\"code\":\"vi\",\"name\":\"ويتنامی\"},{\"code\":\"nl\",\"name\":\"هلندی\"},{\"code\":\"el\",\"name\":\"يونانی\"}],\"mi\":[{\"code\":\"az\",\"name\":\"Ahepaitani\"},{\"code\":\"ga\",\"name\":\"Airihi\"},{\"code\":\"am\",\"name\":\"Amariki\"},{\"code\":\"ar\",\"name\":\"Arapi\"},{\"code\":\"et\",\"name\":\"Etōnia\"},{\"code\":\"zh-tw\",\"name\":\"Haina (Onamata)\"},{\"code\":\"zh-cn\",\"name\":\"Hainamana (Kua whakamāmātia)\"},{\"code\":\"hu\",\"name\":\"Hanekeria\"},{\"code\":\"ja\",\"name\":\"Hapanihi\"},{\"code\":\"sr\",\"name\":\"Herepia\"},{\"code\":\"fi\",\"name\":\"Hinerangi\"},{\"code\":\"he\",\"name\":\"Hiperu\"},{\"code\":\"sk\",\"name\":\"Horowākia\"},{\"code\":\"sl\",\"name\":\"Horowinia\"},{\"code\":\"sv\",\"name\":\"Huitene\"},{\"code\":\"zu\",\"name\":\"Huru\"},{\"code\":\"en\",\"name\":\"Ingarihi\"},{\"code\":\"id\",\"name\":\"Initonīhia\"},{\"code\":\"it\",\"name\":\"Itāriana\"},{\"code\":\"gl\",\"name\":\"Karihia\"},{\"code\":\"ca\",\"name\":\"Katarāna\"},{\"code\":\"el\",\"name\":\"Kiriki\"},{\"code\":\"ko\",\"name\":\"Kōreana\"},{\"code\":\"hr\",\"name\":\"Koroātiana\"},{\"code\":\"tr\",\"name\":\"Korukoru\"},{\"code\":\"mi\",\"name\":\"Māori\"},{\"code\":\"nb\",\"name\":\"Nōwei\"},{\"code\":\"eu\",\"name\":\"Pākihi\"},{\"code\":\"es\",\"name\":\"Pāniora\"},{\"code\":\"fa\",\"name\":\"Perēhia\"},{\"code\":\"pl\",\"name\":\"Pōrana\"},{\"code\":\"pt\",\"name\":\"Potukīhi\"},{\"code\":\"bg\",\"name\":\"Purukāriana\"},{\"code\":\"lv\",\"name\":\"Rāwhiana\"},{\"code\":\"lt\",\"name\":\"Rituānia\"},{\"code\":\"ro\",\"name\":\"Romānia\"},{\"code\":\"ru\",\"name\":\"Rūhia\"},{\"code\":\"th\",\"name\":\"Tai\"},{\"code\":\"nl\",\"name\":\"Tati\"},{\"code\":\"da\",\"name\":\"Tenemāka\"},{\"code\":\"de\",\"name\":\"Tiamana\"},{\"code\":\"cs\",\"name\":\"Tieke\"},{\"code\":\"is\",\"name\":\"Tiorangi\"},{\"code\":\"gd\",\"name\":\"Tuauri Kotarangi\"},{\"code\":\"uk\",\"name\":\"Ūkareiana\"},{\"code\":\"cy\",\"name\":\"Wēra\"},{\"code\":\"vi\",\"name\":\"Whitināmu\"},{\"code\":\"fr\",\"name\":\"Wīwī\"}],\"el\":[{\"code\":\"en\",\"name\":\"Αγγλικά\"},{\"code\":\"az\",\"name\":\"Αζερμπαϊτζανικά\"},{\"code\":\"am\",\"name\":\"Αμχαρικά\"},{\"code\":\"ar\",\"name\":\"Αραβικά\"},{\"code\":\"eu\",\"name\":\"Βασκικά\"},{\"code\":\"vi\",\"name\":\"Βιετναμεζικά\"},{\"code\":\"bg\",\"name\":\"Βουλγαρικά\"},{\"code\":\"gd\",\"name\":\"Γαελικά Σκοτίας\"},{\"code\":\"gl\",\"name\":\"Γαλικιακά\"},{\"code\":\"fr\",\"name\":\"Γαλλικά\"},{\"code\":\"de\",\"name\":\"Γερμανικά\"},{\"code\":\"da\",\"name\":\"Δανικά\"},{\"code\":\"he\",\"name\":\"Εβραϊκά\"},{\"code\":\"el\",\"name\":\"Ελληνικά\"},{\"code\":\"et\",\"name\":\"Εσθονικά\"},{\"code\":\"zu\",\"name\":\"Ζουλού\"},{\"code\":\"ja\",\"name\":\"Ιαπωνικά\"},{\"code\":\"id\",\"name\":\"Ινδονησιακά\"},{\"code\":\"ga\",\"name\":\"Ιρλανδικά\"},{\"code\":\"is\",\"name\":\"Ισλανδικά\"},{\"code\":\"es\",\"name\":\"Ισπανικά\"},{\"code\":\"it\",\"name\":\"Ιταλικά\"},{\"code\":\"ca\",\"name\":\"Καταλανικά\"},{\"code\":\"zh-cn\",\"name\":\"Κινέζικα (Απλοποιημένα)\"},{\"code\":\"zh-tw\",\"name\":\"Κινέζικα (Παραδοσιακά)\"},{\"code\":\"ko\",\"name\":\"Κορεατικά\"},{\"code\":\"hr\",\"name\":\"Κροατικά\"},{\"code\":\"lv\",\"name\":\"Λετονικά\"},{\"code\":\"lt\",\"name\":\"Λιθουανικά\"},{\"code\":\"mi\",\"name\":\"Μαορί\"},{\"code\":\"nb\",\"name\":\"Νορβηγικά\"},{\"code\":\"nl\",\"name\":\"Ολλανδικά\"},{\"code\":\"cy\",\"name\":\"Ουαλικά\"},{\"code\":\"hu\",\"name\":\"Ουγγρικά\"},{\"code\":\"uk\",\"name\":\"Ουκρανικά\"},{\"code\":\"fa\",\"name\":\"Περσικά\"},{\"code\":\"pl\",\"name\":\"Πολωνικά\"},{\"code\":\"pt\",\"name\":\"Πορτογαλικά\"},{\"code\":\"ro\",\"name\":\"Ρουμανικά\"},{\"code\":\"ru\",\"name\":\"Ρωσικά\"},{\"code\":\"sr\",\"name\":\"Σερβικά\"},{\"code\":\"sk\",\"name\":\"Σλοβακικά\"},{\"code\":\"sl\",\"name\":\"Σλοβενικά\"},{\"code\":\"sv\",\"name\":\"Σουηδικά\"},{\"code\":\"th\",\"name\":\"Ταϊλανδεζικά\"},{\"code\":\"tr\",\"name\":\"Τούρκικα\"},{\"code\":\"cs\",\"name\":\"Τσεχικά\"},{\"code\":\"fi\",\"name\":\"Φινλανδικά\"}],\"is\":[{\"code\":\"am\",\"name\":\"amharísku\"},{\"code\":\"ar\",\"name\":\"arabíska\"},{\"code\":\"az\",\"name\":\"aserska\"},{\"code\":\"eu\",\"name\":\"baskneska\"},{\"code\":\"bg\",\"name\":\"búlgarska\"},{\"code\":\"da\",\"name\":\"danska\"},{\"code\":\"et\",\"name\":\"eistneska\"},{\"code\":\"en\",\"name\":\"enska\"},{\"code\":\"fi\",\"name\":\"finnska\"},{\"code\":\"fr\",\"name\":\"franska\"},{\"code\":\"gl\",\"name\":\"galisíska\"},{\"code\":\"el\",\"name\":\"gríska\"},{\"code\":\"he\",\"name\":\"hebreska\"},{\"code\":\"nl\",\"name\":\"hollenska\"},{\"code\":\"id\",\"name\":\"indónesíska\"},{\"code\":\"ga\",\"name\":\"írska\"},{\"code\":\"is\",\"name\":\"íslenska\"},{\"code\":\"it\",\"name\":\"ítalska\"},{\"code\":\"ja\",\"name\":\"japanska\"},{\"code\":\"ca\",\"name\":\"katalónska\"},{\"code\":\"zh-cn\",\"name\":\"kínverska (einfölduð)\"},{\"code\":\"zh-tw\",\"name\":\"kínverska (hefðbundin)\"},{\"code\":\"ko\",\"name\":\"kóreska\"},{\"code\":\"hr\",\"name\":\"króatíska\"},{\"code\":\"lv\",\"name\":\"lettneska\"},{\"code\":\"lt\",\"name\":\"litháíska\"},{\"code\":\"mi\",\"name\":\"maoríska\"},{\"code\":\"nb\",\"name\":\"norska\"},{\"code\":\"fa\",\"name\":\"persneska\"},{\"code\":\"pt\",\"name\":\"portúgalska\"},{\"code\":\"pl\",\"name\":\"pólska\"},{\"code\":\"ro\",\"name\":\"rúmenska\"},{\"code\":\"ru\",\"name\":\"rússneska\"},{\"code\":\"sr\",\"name\":\"serbneska\"},{\"code\":\"gd\",\"name\":\"skosk-gelíska\"},{\"code\":\"sk\",\"name\":\"slóvakíska\"},{\"code\":\"sl\",\"name\":\"slóvenska\"},{\"code\":\"es\",\"name\":\"spænska\"},{\"code\":\"zu\",\"name\":\"súlú\"},{\"code\":\"sv\",\"name\":\"sænska\"},{\"code\":\"th\",\"name\":\"taílenska\"},{\"code\":\"cs\",\"name\":\"tékkneska\"},{\"code\":\"tr\",\"name\":\"tyrkneska\"},{\"code\":\"hu\",\"name\":\"ungverska\"},{\"code\":\"uk\",\"name\":\"úkraínska\"},{\"code\":\"cy\",\"name\":\"velska\"},{\"code\":\"vi\",\"name\":\"víetnamska\"},{\"code\":\"de\",\"name\":\"þýska\"}],\"fi\":[{\"code\":\"am\",\"name\":\"amhara\"},{\"code\":\"ar\",\"name\":\"arabia\"},{\"code\":\"az\",\"name\":\"azeri\"},{\"code\":\"eu\",\"name\":\"baski\"},{\"code\":\"bg\",\"name\":\"bulgaria\"},{\"code\":\"en\",\"name\":\"englanti\"},{\"code\":\"es\",\"name\":\"espanja\"},{\"code\":\"gl\",\"name\":\"galicia\"},{\"code\":\"he\",\"name\":\"heprea\"},{\"code\":\"nl\",\"name\":\"hollanti\"},{\"code\":\"ga\",\"name\":\"iiri\"},{\"code\":\"id\",\"name\":\"indonesia\"},{\"code\":\"is\",\"name\":\"islanti\"},{\"code\":\"it\",\"name\":\"italia\"},{\"code\":\"ja\",\"name\":\"japani\"},{\"code\":\"ca\",\"name\":\"katalaani\"},{\"code\":\"zh-tw\",\"name\":\"kiina (perinteinen)\"},{\"code\":\"zh-cn\",\"name\":\"kiina (yksinkert.)\"},{\"code\":\"ko\",\"name\":\"korea\"},{\"code\":\"el\",\"name\":\"kreikka\"},{\"code\":\"hr\",\"name\":\"kroatia\"},{\"code\":\"cy\",\"name\":\"kymri\"},{\"code\":\"lv\",\"name\":\"latvia\"},{\"code\":\"lt\",\"name\":\"liettua\"},{\"code\":\"mi\",\"name\":\"maori\"},{\"code\":\"nb\",\"name\":\"norja\"},{\"code\":\"fa\",\"name\":\"persia\"},{\"code\":\"pt\",\"name\":\"portugali\"},{\"code\":\"pl\",\"name\":\"puola\"},{\"code\":\"fr\",\"name\":\"ranska\"},{\"code\":\"ro\",\"name\":\"romania\"},{\"code\":\"sv\",\"name\":\"ruotsi\"},{\"code\":\"de\",\"name\":\"saksa\"},{\"code\":\"sr\",\"name\":\"serbia\"},{\"code\":\"gd\",\"name\":\"skottigaeli\"},{\"code\":\"sk\",\"name\":\"slovakia\"},{\"code\":\"sl\",\"name\":\"slovenia\"},{\"code\":\"fi\",\"name\":\"suomi\"},{\"code\":\"da\",\"name\":\"tanska\"},{\"code\":\"th\",\"name\":\"thai\"},{\"code\":\"cs\",\"name\":\"tsekki\"},{\"code\":\"tr\",\"name\":\"turkki\"},{\"code\":\"uk\",\"name\":\"ukraina\"},{\"code\":\"hu\",\"name\":\"unkari\"},{\"code\":\"ru\",\"name\":\"venäjä\"},{\"code\":\"vi\",\"name\":\"vietnam\"},{\"code\":\"et\",\"name\":\"viro\"},{\"code\":\"zu\",\"name\":\"zulu\"}],\"eu\":[{\"code\":\"de\",\"name\":\"alemana\"},{\"code\":\"am\",\"name\":\"amharera\"},{\"code\":\"ar\",\"name\":\"arabiera\"},{\"code\":\"az\",\"name\":\"azerbaijanera\"},{\"code\":\"bg\",\"name\":\"bulgariera\"},{\"code\":\"da\",\"name\":\"daniera\"},{\"code\":\"ro\",\"name\":\"errumaniera\"},{\"code\":\"ru\",\"name\":\"errusiera\"},{\"code\":\"gd\",\"name\":\"Eskoziako gaelera\"},{\"code\":\"sk\",\"name\":\"eslovakiera\"},{\"code\":\"sl\",\"name\":\"esloveniera\"},{\"code\":\"et\",\"name\":\"estoniera\"},{\"code\":\"eu\",\"name\":\"euskara\"},{\"code\":\"fr\",\"name\":\"frantsesa\"},{\"code\":\"cy\",\"name\":\"gaelera\"},{\"code\":\"gl\",\"name\":\"galiziera\"},{\"code\":\"es\",\"name\":\"gaztelania\"},{\"code\":\"el\",\"name\":\"greziera\"},{\"code\":\"he\",\"name\":\"hebreera\"},{\"code\":\"hu\",\"name\":\"hungariera\"},{\"code\":\"id\",\"name\":\"indonesiera\"},{\"code\":\"en\",\"name\":\"ingelesa\"},{\"code\":\"ga\",\"name\":\"irlandera\"},{\"code\":\"is\",\"name\":\"islandiera\"},{\"code\":\"it\",\"name\":\"italiera\"},{\"code\":\"ja\",\"name\":\"japoniera\"},{\"code\":\"ca\",\"name\":\"katalana\"},{\"code\":\"ko\",\"name\":\"koreera\"},{\"code\":\"hr\",\"name\":\"kroaziera\"},{\"code\":\"lv\",\"name\":\"letoniera\"},{\"code\":\"lt\",\"name\":\"lituaniera\"},{\"code\":\"mi\",\"name\":\"maoriera\"},{\"code\":\"nl\",\"name\":\"nederlandera\"},{\"code\":\"nb\",\"name\":\"norvegiera\"},{\"code\":\"fa\",\"name\":\"persiera\"},{\"code\":\"pl\",\"name\":\"poloniera\"},{\"code\":\"pt\",\"name\":\"portugesa\"},{\"code\":\"sr\",\"name\":\"serbiera\"},{\"code\":\"sv\",\"name\":\"suediera\"},{\"code\":\"fi\",\"name\":\"suomiera\"},{\"code\":\"th\",\"name\":\"thaiera\"},{\"code\":\"tr\",\"name\":\"turkiera\"},{\"code\":\"cs\",\"name\":\"txekiera\"},{\"code\":\"zh-cn\",\"name\":\"txinera (soildua)\"},{\"code\":\"zh-tw\",\"name\":\"txinera (tradizionala)\"},{\"code\":\"uk\",\"name\":\"ukrainera\"},{\"code\":\"vi\",\"name\":\"vietnamera\"},{\"code\":\"zu\",\"name\":\"zuluera\"}],\"ca\":[{\"code\":\"de\",\"name\":\"alemany\"},{\"code\":\"am\",\"name\":\"amhàric\"},{\"code\":\"en\",\"name\":\"anglès\"},{\"code\":\"ar\",\"name\":\"àrab\"},{\"code\":\"az\",\"name\":\"àzeri\"},{\"code\":\"eu\",\"name\":\"basc\"},{\"code\":\"bg\",\"name\":\"búlgar\"},{\"code\":\"es\",\"name\":\"castellà\"},{\"code\":\"ca\",\"name\":\"català\"},{\"code\":\"ko\",\"name\":\"coreà\"},{\"code\":\"hr\",\"name\":\"croat\"},{\"code\":\"da\",\"name\":\"danès\"},{\"code\":\"sk\",\"name\":\"eslovac\"},{\"code\":\"sl\",\"name\":\"eslovè\"},{\"code\":\"et\",\"name\":\"estonià\"},{\"code\":\"fi\",\"name\":\"finès\"},{\"code\":\"fr\",\"name\":\"francès\"},{\"code\":\"gd\",\"name\":\"gaèlic escocès\"},{\"code\":\"gl\",\"name\":\"gallec\"},{\"code\":\"cy\",\"name\":\"gal·lès\"},{\"code\":\"el\",\"name\":\"grec\"},{\"code\":\"he\",\"name\":\"hebreu\"},{\"code\":\"hu\",\"name\":\"hongarès\"},{\"code\":\"id\",\"name\":\"indonesi\"},{\"code\":\"ga\",\"name\":\"irlandès\"},{\"code\":\"is\",\"name\":\"islandès\"},{\"code\":\"it\",\"name\":\"italià\"},{\"code\":\"ja\",\"name\":\"japonès\"},{\"code\":\"lv\",\"name\":\"letó\"},{\"code\":\"lt\",\"name\":\"lituà\"},{\"code\":\"mi\",\"name\":\"maori\"},{\"code\":\"nl\",\"name\":\"neerlandès\"},{\"code\":\"nb\",\"name\":\"noruec\"},{\"code\":\"fa\",\"name\":\"persa\"},{\"code\":\"pl\",\"name\":\"polonès\"},{\"code\":\"pt\",\"name\":\"portuguès\"},{\"code\":\"ro\",\"name\":\"romanès\"},{\"code\":\"ru\",\"name\":\"rus\"},{\"code\":\"sr\",\"name\":\"serbi\"},{\"code\":\"sv\",\"name\":\"suec\"},{\"code\":\"th\",\"name\":\"tai\"},{\"code\":\"tr\",\"name\":\"turc\"},{\"code\":\"cs\",\"name\":\"txec\"},{\"code\":\"uk\",\"name\":\"ucraïnès\"},{\"code\":\"vi\",\"name\":\"vietnamita\"},{\"code\":\"zh-cn\",\"name\":\"xinès (simplificat)\"},{\"code\":\"zh-tw\",\"name\":\"xinès (tradicional)\"},{\"code\":\"zu\",\"name\":\"zulú\"}],\"lv\":[{\"code\":\"am\",\"name\":\"amharu\"},{\"code\":\"en\",\"name\":\"angļu\"},{\"code\":\"ar\",\"name\":\"arābu\"},{\"code\":\"az\",\"name\":\"azerbaidžāņu\"},{\"code\":\"eu\",\"name\":\"basku\"},{\"code\":\"bg\",\"name\":\"bulgāru\"},{\"code\":\"cs\",\"name\":\"čehu\"},{\"code\":\"da\",\"name\":\"dāņu\"},{\"code\":\"he\",\"name\":\"ebreju (ivrits)\"},{\"code\":\"fr\",\"name\":\"franču\"},{\"code\":\"gl\",\"name\":\"galisiešu\"},{\"code\":\"el\",\"name\":\"grieķu\"},{\"code\":\"nl\",\"name\":\"holandiešu\"},{\"code\":\"hr\",\"name\":\"horvātu\"},{\"code\":\"et\",\"name\":\"igauņu\"},{\"code\":\"id\",\"name\":\"indonēziešu\"},{\"code\":\"ga\",\"name\":\"īru\"},{\"code\":\"is\",\"name\":\"īslandiešu\"},{\"code\":\"it\",\"name\":\"itāļu\"},{\"code\":\"ja\",\"name\":\"japāņu\"},{\"code\":\"ca\",\"name\":\"katalāņu\"},{\"code\":\"ko\",\"name\":\"korejiešu\"},{\"code\":\"ru\",\"name\":\"krievu\"},{\"code\":\"zh-tw\",\"name\":\"ķīniešu (tradicionālā)\"},{\"code\":\"zh-cn\",\"name\":\"ķīniešu (vienkāršotā)\"},{\"code\":\"lv\",\"name\":\"latviešu\"},{\"code\":\"lt\",\"name\":\"lietuviešu\"},{\"code\":\"mi\",\"name\":\"maori\"},{\"code\":\"nb\",\"name\":\"norvēģu\"},{\"code\":\"fa\",\"name\":\"persiešu\"},{\"code\":\"pl\",\"name\":\"poļu\"},{\"code\":\"pt\",\"name\":\"portugāļu\"},{\"code\":\"ro\",\"name\":\"rumāņu\"},{\"code\":\"sr\",\"name\":\"serbu\"},{\"code\":\"gd\",\"name\":\"skotu gēlu\"},{\"code\":\"sk\",\"name\":\"slovāku\"},{\"code\":\"sl\",\"name\":\"slovēņu\"},{\"code\":\"fi\",\"name\":\"somu\"},{\"code\":\"es\",\"name\":\"spāņu\"},{\"code\":\"th\",\"name\":\"taju\"},{\"code\":\"tr\",\"name\":\"turku\"},{\"code\":\"uk\",\"name\":\"ukraiņu\"},{\"code\":\"hu\",\"name\":\"ungāru\"},{\"code\":\"de\",\"name\":\"vācu\"},{\"code\":\"cy\",\"name\":\"velsiešu\"},{\"code\":\"vi\",\"name\":\"vjetnamiešu\"},{\"code\":\"zu\",\"name\":\"zulu\"},{\"code\":\"sv\",\"name\":\"zviedru\"}],\"id\":[{\"code\":\"am\",\"name\":\"Amhara\"},{\"code\":\"ar\",\"name\":\"Arab\"},{\"code\":\"az\",\"name\":\"Azerbaijan\"},{\"code\":\"eu\",\"name\":\"Basque\"},{\"code\":\"nl\",\"name\":\"Belanda\"},{\"code\":\"bg\",\"name\":\"Bulgaria\"},{\"code\":\"cs\",\"name\":\"Cek\"},{\"code\":\"zh-cn\",\"name\":\"China (Aks. Sederhana)\"},{\"code\":\"zh-tw\",\"name\":\"China (Aks. Tradisional)\"},{\"code\":\"da\",\"name\":\"Denmark\"},{\"code\":\"et\",\"name\":\"Estonia\"},{\"code\":\"fa\",\"name\":\"Farsi\"},{\"code\":\"fi\",\"name\":\"Finlandia\"},{\"code\":\"ga\",\"name\":\"Gaelig\"},{\"code\":\"gd\",\"name\":\"Gaelik Skotlandia\"},{\"code\":\"gl\",\"name\":\"Galisia\"},{\"code\":\"he\",\"name\":\"Ibrani\"},{\"code\":\"id\",\"name\":\"Indonesia\"},{\"code\":\"en\",\"name\":\"Inggris\"},{\"code\":\"is\",\"name\":\"Islan\"},{\"code\":\"it\",\"name\":\"Italia\"},{\"code\":\"ja\",\"name\":\"Jepang\"},{\"code\":\"de\",\"name\":\"Jerman\"},{\"code\":\"ca\",\"name\":\"Katala\"},{\"code\":\"ko\",\"name\":\"Korea\"},{\"code\":\"hr\",\"name\":\"Kroat\"},{\"code\":\"lv\",\"name\":\"Latvia\"},{\"code\":\"lt\",\"name\":\"Lituania\"},{\"code\":\"hu\",\"name\":\"Magyar\"},{\"code\":\"mi\",\"name\":\"Maori\"},{\"code\":\"nb\",\"name\":\"Norsk\"},{\"code\":\"pl\",\"name\":\"Polandia\"},{\"code\":\"pt\",\"name\":\"Portugis\"},{\"code\":\"fr\",\"name\":\"Prancis\"},{\"code\":\"ro\",\"name\":\"Rumania\"},{\"code\":\"ru\",\"name\":\"Rusia\"},{\"code\":\"sr\",\"name\":\"Serb\"},{\"code\":\"sk\",\"name\":\"Slovakia\"},{\"code\":\"sl\",\"name\":\"Slovenia\"},{\"code\":\"es\",\"name\":\"Spanyol\"},{\"code\":\"sv\",\"name\":\"Swensk\"},{\"code\":\"th\",\"name\":\"Thai\"},{\"code\":\"tr\",\"name\":\"Turki\"},{\"code\":\"uk\",\"name\":\"Ukraina\"},{\"code\":\"vi\",\"name\":\"Vietnam\"},{\"code\":\"cy\",\"name\":\"Wales\"},{\"code\":\"el\",\"name\":\"Yunani\"},{\"code\":\"zu\",\"name\":\"Zulu\"}],\"es\":[{\"code\":\"de\",\"name\":\"alemán\"},{\"code\":\"am\",\"name\":\"amhárico\"},{\"code\":\"ar\",\"name\":\"árabe\"},{\"code\":\"az\",\"name\":\"azerí\"},{\"code\":\"bg\",\"name\":\"búlgaro\"},{\"code\":\"ca\",\"name\":\"catalán\"},{\"code\":\"cs\",\"name\":\"checo\"},{\"code\":\"zh-cn\",\"name\":\"chino (simplificado)\"},{\"code\":\"zh-tw\",\"name\":\"chino (tradicional)\"},{\"code\":\"ko\",\"name\":\"coreano\"},{\"code\":\"hr\",\"name\":\"croata\"},{\"code\":\"da\",\"name\":\"danés\"},{\"code\":\"sk\",\"name\":\"eslovaco\"},{\"code\":\"sl\",\"name\":\"esloveno\"},{\"code\":\"es\",\"name\":\"español\"},{\"code\":\"et\",\"name\":\"estonio\"},{\"code\":\"eu\",\"name\":\"euskera\"},{\"code\":\"fi\",\"name\":\"finlandés\"},{\"code\":\"fr\",\"name\":\"francés\"},{\"code\":\"gd\",\"name\":\"gaélico escocés\"},{\"code\":\"cy\",\"name\":\"galés\"},{\"code\":\"gl\",\"name\":\"gallego\"},{\"code\":\"el\",\"name\":\"griego\"},{\"code\":\"he\",\"name\":\"hebreo\"},{\"code\":\"hu\",\"name\":\"húngaro\"},{\"code\":\"id\",\"name\":\"indonesio\"},{\"code\":\"en\",\"name\":\"inglés\"},{\"code\":\"ga\",\"name\":\"irlandés\"},{\"code\":\"is\",\"name\":\"islandés\"},{\"code\":\"it\",\"name\":\"italiano\"},{\"code\":\"ja\",\"name\":\"japonés\"},{\"code\":\"lv\",\"name\":\"letón\"},{\"code\":\"lt\",\"name\":\"lituano\"},{\"code\":\"mi\",\"name\":\"maorí\"},{\"code\":\"nl\",\"name\":\"neerlandés\"},{\"code\":\"nb\",\"name\":\"noruego\"},{\"code\":\"fa\",\"name\":\"persa\"},{\"code\":\"pl\",\"name\":\"polaco\"},{\"code\":\"pt\",\"name\":\"portugués\"},{\"code\":\"ro\",\"name\":\"rumano\"},{\"code\":\"ru\",\"name\":\"ruso\"},{\"code\":\"sr\",\"name\":\"serbio\"},{\"code\":\"sv\",\"name\":\"sueco\"},{\"code\":\"th\",\"name\":\"tailandés\"},{\"code\":\"tr\",\"name\":\"turco\"},{\"code\":\"uk\",\"name\":\"ucraniano\"},{\"code\":\"vi\",\"name\":\"vietnamita\"},{\"code\":\"zu\",\"name\":\"zulú\"}],\"es-419\":[{\"code\":\"de\",\"name\":\"alemán\"},{\"code\":\"am\",\"name\":\"amhárico\"},{\"code\":\"ar\",\"name\":\"árabe\"},{\"code\":\"az\",\"name\":\"azerí\"},{\"code\":\"bg\",\"name\":\"búlgaro\"},{\"code\":\"ca\",\"name\":\"catalán\"},{\"code\":\"cs\",\"name\":\"checo\"},{\"code\":\"zh-cn\",\"name\":\"chino (simplificado)\"},{\"code\":\"zh-tw\",\"name\":\"chino (tradicional)\"},{\"code\":\"ko\",\"name\":\"coreano\"},{\"code\":\"hr\",\"name\":\"croata\"},{\"code\":\"da\",\"name\":\"danés\"},{\"code\":\"sk\",\"name\":\"eslovaco\"},{\"code\":\"sl\",\"name\":\"esloveno\"},{\"code\":\"es\",\"name\":\"español\"},{\"code\":\"et\",\"name\":\"estonio\"},{\"code\":\"eu\",\"name\":\"euskera\"},{\"code\":\"fi\",\"name\":\"finlandés\"},{\"code\":\"fr\",\"name\":\"francés\"},{\"code\":\"gd\",\"name\":\"gaélico escocés\"},{\"code\":\"cy\",\"name\":\"galés\"},{\"code\":\"gl\",\"name\":\"gallego\"},{\"code\":\"el\",\"name\":\"griego\"},{\"code\":\"he\",\"name\":\"hebreo\"},{\"code\":\"hu\",\"name\":\"húngaro\"},{\"code\":\"id\",\"name\":\"indonesio\"},{\"code\":\"en\",\"name\":\"inglés\"},{\"code\":\"ga\",\"name\":\"irlandés\"},{\"code\":\"is\",\"name\":\"islandés\"},{\"code\":\"it\",\"name\":\"italiano\"},{\"code\":\"ja\",\"name\":\"japonés\"},{\"code\":\"lv\",\"name\":\"letón\"},{\"code\":\"lt\",\"name\":\"lituano\"},{\"code\":\"mi\",\"name\":\"maorí\"},{\"code\":\"nl\",\"name\":\"neerlandés\"},{\"code\":\"nb\",\"name\":\"noruego\"},{\"code\":\"fa\",\"name\":\"persa\"},{\"code\":\"pl\",\"name\":\"polaco\"},{\"code\":\"pt\",\"name\":\"portugués\"},{\"code\":\"ro\",\"name\":\"rumano\"},{\"code\":\"ru\",\"name\":\"ruso\"},{\"code\":\"sr\",\"name\":\"serbio\"},{\"code\":\"sv\",\"name\":\"sueco\"},{\"code\":\"th\",\"name\":\"tailandés\"},{\"code\":\"tr\",\"name\":\"turco\"},{\"code\":\"uk\",\"name\":\"ucraniano\"},{\"code\":\"vi\",\"name\":\"vietnamita\"},{\"code\":\"zu\",\"name\":\"zulú\"}],\"et\":[{\"code\":\"am\",\"name\":\"amhaari\"},{\"code\":\"ar\",\"name\":\"araabia\"},{\"code\":\"az\",\"name\":\"aserbaidžaani\"},{\"code\":\"eu\",\"name\":\"baski\"},{\"code\":\"bg\",\"name\":\"bulgaaria\"},{\"code\":\"et\",\"name\":\"eesti\"},{\"code\":\"gl\",\"name\":\"galeegi\"},{\"code\":\"he\",\"name\":\"heebrea\"},{\"code\":\"es\",\"name\":\"hispaania\"},{\"code\":\"nl\",\"name\":\"hollandi\"},{\"code\":\"hr\",\"name\":\"horvaadi\"},{\"code\":\"ga\",\"name\":\"iiri\"},{\"code\":\"id\",\"name\":\"indoneesia\"},{\"code\":\"en\",\"name\":\"inglise\"},{\"code\":\"is\",\"name\":\"islandi\"},{\"code\":\"it\",\"name\":\"itaalia\"},{\"code\":\"ja\",\"name\":\"jaapani\"},{\"code\":\"ca\",\"name\":\"katalaani\"},{\"code\":\"ko\",\"name\":\"korea\"},{\"code\":\"el\",\"name\":\"kreeka\"},{\"code\":\"lt\",\"name\":\"leedu\"},{\"code\":\"zh-cn\",\"name\":\"lihtsustatud hiina\"},{\"code\":\"lv\",\"name\":\"läti\"},{\"code\":\"mi\",\"name\":\"maoori\"},{\"code\":\"nb\",\"name\":\"norra\"},{\"code\":\"pl\",\"name\":\"poola\"},{\"code\":\"pt\",\"name\":\"portugali\"},{\"code\":\"fr\",\"name\":\"prantsuse\"},{\"code\":\"fa\",\"name\":\"pärsia\"},{\"code\":\"sv\",\"name\":\"rootsi\"},{\"code\":\"ro\",\"name\":\"rumeenia\"},{\"code\":\"de\",\"name\":\"saksa\"},{\"code\":\"sr\",\"name\":\"serbia\"},{\"code\":\"sk\",\"name\":\"slovaki\"},{\"code\":\"sl\",\"name\":\"sloveeni\"},{\"code\":\"fi\",\"name\":\"soome\"},{\"code\":\"zu\",\"name\":\"suulu\"},{\"code\":\"gd\",\"name\":\"šoti\"},{\"code\":\"da\",\"name\":\"taani\"},{\"code\":\"th\",\"name\":\"tai\"},{\"code\":\"zh-tw\",\"name\":\"traditsiooniline hiina\"},{\"code\":\"cs\",\"name\":\"tšehhi\"},{\"code\":\"tr\",\"name\":\"türgi\"},{\"code\":\"cy\",\"name\":\"uelsi\"},{\"code\":\"uk\",\"name\":\"ukraina\"},{\"code\":\"hu\",\"name\":\"ungari\"},{\"code\":\"ru\",\"name\":\"vene\"},{\"code\":\"vi\",\"name\":\"vietnami\"}],\"cy\":[{\"code\":\"de\",\"name\":\"Almaeneg\"},{\"code\":\"am\",\"name\":\"Amharic\"},{\"code\":\"ar\",\"name\":\"Arabeg\"},{\"code\":\"az\",\"name\":\"Aserbaijaneg\"},{\"code\":\"eu\",\"name\":\"Basgeg\"},{\"code\":\"bg\",\"name\":\"Bwlgaraidd\"},{\"code\":\"ca\",\"name\":\"Catalaneg\"},{\"code\":\"hr\",\"name\":\"Croateg\"},{\"code\":\"cy\",\"name\":\"Cymraeg\"},{\"code\":\"da\",\"name\":\"Daneg\"},{\"code\":\"it\",\"name\":\"Eidaleg\"},{\"code\":\"et\",\"name\":\"Estoneg\"},{\"code\":\"vi\",\"name\":\"Fietnameg\"},{\"code\":\"fi\",\"name\":\"Ffineg\"},{\"code\":\"nl\",\"name\":\"Fflemeg\"},{\"code\":\"fr\",\"name\":\"Ffrangeg\"},{\"code\":\"gd\",\"name\":\"Gaeleg yr Alban\"},{\"code\":\"gl\",\"name\":\"Galisaidd\"},{\"code\":\"el\",\"name\":\"Groeg\"},{\"code\":\"ga\",\"name\":\"Gwyddeleg\"},{\"code\":\"he\",\"name\":\"Hebraeg\"},{\"code\":\"hu\",\"name\":\"Hwngareg\"},{\"code\":\"ko\",\"name\":\"Iaith Corea\"},{\"code\":\"id\",\"name\":\"Indonesieg\"},{\"code\":\"is\",\"name\":\"Islandeg\"},{\"code\":\"uk\",\"name\":\"Iwcraineg\"},{\"code\":\"ja\",\"name\":\"Japaneg\"},{\"code\":\"lv\",\"name\":\"Latfieg\"},{\"code\":\"lt\",\"name\":\"Lithwaneg\"},{\"code\":\"mi\",\"name\":\"Maori\"},{\"code\":\"nb\",\"name\":\"Norwyeg\"},{\"code\":\"fa\",\"name\":\"Perseg\"},{\"code\":\"pt\",\"name\":\"Portiwgaleg\"},{\"code\":\"pl\",\"name\":\"Pwyleg\"},{\"code\":\"ro\",\"name\":\"Rwmaneg\"},{\"code\":\"ru\",\"name\":\"Rwsieg\"},{\"code\":\"en\",\"name\":\"Saesneg\"},{\"code\":\"es\",\"name\":\"Sbaeneg\"},{\"code\":\"sr\",\"name\":\"Serbeg\"},{\"code\":\"sk\",\"name\":\"Slofac\"},{\"code\":\"sl\",\"name\":\"Slofenia\"},{\"code\":\"sv\",\"name\":\"Swedeg\"},{\"code\":\"zu\",\"name\":\"Swlw\"},{\"code\":\"th\",\"name\":\"Tai\"},{\"code\":\"cs\",\"name\":\"Tsieceg\"},{\"code\":\"zh-tw\",\"name\":\"Tsieineeg (Traddodiadol)\"},{\"code\":\"zh-cn\",\"name\":\"Tsieineeg (Wedi symleiddio)\"},{\"code\":\"tr\",\"name\":\"Twrceg\"}],\"zh-cn\":[{\"code\":\"ar\",\"name\":\"阿拉伯语\"},{\"code\":\"am\",\"name\":\"阿姆哈拉语\"},{\"code\":\"az\",\"name\":\"阿塞拜疆语\"},{\"code\":\"ga\",\"name\":\"爱尔兰语\"},{\"code\":\"et\",\"name\":\"爱沙尼亚语\"},{\"code\":\"eu\",\"name\":\"巴斯克语\"},{\"code\":\"bg\",\"name\":\"保加利亚语\"},{\"code\":\"is\",\"name\":\"冰岛语\"},{\"code\":\"pl\",\"name\":\"波兰语\"},{\"code\":\"fa\",\"name\":\"波斯语\"},{\"code\":\"da\",\"name\":\"丹麦语\"},{\"code\":\"de\",\"name\":\"德语\"},{\"code\":\"ru\",\"name\":\"俄语\"},{\"code\":\"fr\",\"name\":\"法语\"},{\"code\":\"fi\",\"name\":\"芬兰语\"},{\"code\":\"ko\",\"name\":\"韩语\"},{\"code\":\"nl\",\"name\":\"荷兰语\"},{\"code\":\"gl\",\"name\":\"加利西亚语\"},{\"code\":\"ca\",\"name\":\"加泰罗尼亚语\"},{\"code\":\"cs\",\"name\":\"捷克语\"},{\"code\":\"hr\",\"name\":\"克罗地亚语\"},{\"code\":\"lv\",\"name\":\"拉脱维亚语\"},{\"code\":\"lt\",\"name\":\"立陶宛语\"},{\"code\":\"ro\",\"name\":\"罗马尼亚语\"},{\"code\":\"mi\",\"name\":\"毛利语\"},{\"code\":\"zu\",\"name\":\"南非祖鲁语\"},{\"code\":\"nb\",\"name\":\"挪威语\"},{\"code\":\"pt\",\"name\":\"葡萄牙语\"},{\"code\":\"ja\",\"name\":\"日语\"},{\"code\":\"sv\",\"name\":\"瑞典语\"},{\"code\":\"sr\",\"name\":\"塞尔维亚语\"},{\"code\":\"sk\",\"name\":\"斯洛伐克语\"},{\"code\":\"sl\",\"name\":\"斯洛文尼亚语\"},{\"code\":\"gd\",\"name\":\"苏格兰盖尔语\"},{\"code\":\"th\",\"name\":\"泰语\"},{\"code\":\"tr\",\"name\":\"土耳其语\"},{\"code\":\"cy\",\"name\":\"威尔士语\"},{\"code\":\"uk\",\"name\":\"乌克兰语\"},{\"code\":\"es\",\"name\":\"西班牙语\"},{\"code\":\"he\",\"name\":\"希伯来语\"},{\"code\":\"el\",\"name\":\"希腊语\"},{\"code\":\"hu\",\"name\":\"匈牙利语\"},{\"code\":\"it\",\"name\":\"意大利语\"},{\"code\":\"id\",\"name\":\"印尼语\"},{\"code\":\"en\",\"name\":\"英语\"},{\"code\":\"vi\",\"name\":\"越南语\"},{\"code\":\"zh-tw\",\"name\":\"中文(繁体)\"},{\"code\":\"zh-cn\",\"name\":\"中文(简体)\"}],\"bg\":[{\"code\":\"az\",\"name\":\"азербайджански\"},{\"code\":\"am\",\"name\":\"амхарски\"},{\"code\":\"en\",\"name\":\"английски\"},{\"code\":\"ar\",\"name\":\"арабски\"},{\"code\":\"eu\",\"name\":\"баски\"},{\"code\":\"bg\",\"name\":\"български\"},{\"code\":\"vi\",\"name\":\"виетнамски\"},{\"code\":\"gl\",\"name\":\"галисийски\"},{\"code\":\"el\",\"name\":\"гръцки\"},{\"code\":\"da\",\"name\":\"датски\"},{\"code\":\"et\",\"name\":\"естонски\"},{\"code\":\"zu\",\"name\":\"зулу\"},{\"code\":\"he\",\"name\":\"иврит\"},{\"code\":\"id\",\"name\":\"индонезийски\"},{\"code\":\"ga\",\"name\":\"ирландски\"},{\"code\":\"is\",\"name\":\"исландски\"},{\"code\":\"es\",\"name\":\"испански\"},{\"code\":\"it\",\"name\":\"италиански\"},{\"code\":\"ca\",\"name\":\"каталонски\"},{\"code\":\"zh-cn\",\"name\":\"китайски (опростен)\"},{\"code\":\"zh-tw\",\"name\":\"китайски (традиционен)\"},{\"code\":\"ko\",\"name\":\"корейски\"},{\"code\":\"lv\",\"name\":\"латвийски\"},{\"code\":\"lt\",\"name\":\"литовски\"},{\"code\":\"mi\",\"name\":\"маорски\"},{\"code\":\"de\",\"name\":\"немски\"},{\"code\":\"nl\",\"name\":\"нидерландски\"},{\"code\":\"nb\",\"name\":\"норвежки\"},{\"code\":\"fa\",\"name\":\"персийски\"},{\"code\":\"pl\",\"name\":\"полски\"},{\"code\":\"pt\",\"name\":\"португалски\"},{\"code\":\"ro\",\"name\":\"румънски\"},{\"code\":\"ru\",\"name\":\"руски\"},{\"code\":\"sk\",\"name\":\"словашки\"},{\"code\":\"sl\",\"name\":\"словенски\"},{\"code\":\"sr\",\"name\":\"сръбски\"},{\"code\":\"th\",\"name\":\"тайландски\"},{\"code\":\"tr\",\"name\":\"турски\"},{\"code\":\"cy\",\"name\":\"уелски\"},{\"code\":\"uk\",\"name\":\"украински\"},{\"code\":\"hu\",\"name\":\"унгарски\"},{\"code\":\"fi\",\"name\":\"финландски\"},{\"code\":\"fr\",\"name\":\"френски\"},{\"code\":\"hr\",\"name\":\"хърватски\"},{\"code\":\"cs\",\"name\":\"чешки\"},{\"code\":\"sv\",\"name\":\"шведски\"},{\"code\":\"gd\",\"name\":\"шотландски келтски\"},{\"code\":\"ja\",\"name\":\"японски\"}],\"ar\":[{\"code\":\"is\",\"name\":\"الآيسلندية\"},{\"code\":\"az\",\"name\":\"الأذرية\"},{\"code\":\"es\",\"name\":\"الإسبانية\"},{\"code\":\"et\",\"name\":\"الإستونية\"},{\"code\":\"gd\",\"name\":\"الاسكتلندية الغالية\"},{\"code\":\"de\",\"name\":\"الألمانية\"},{\"code\":\"am\",\"name\":\"الأمهرية\"},{\"code\":\"en\",\"name\":\"الإنجليزية\"},{\"code\":\"id\",\"name\":\"الإندونيسية\"},{\"code\":\"uk\",\"name\":\"الأوكرانية\"},{\"code\":\"ga\",\"name\":\"الأيرلندية\"},{\"code\":\"it\",\"name\":\"الإيطالية\"},{\"code\":\"eu\",\"name\":\"الباسكية\"},{\"code\":\"pt\",\"name\":\"البرتغالية\"},{\"code\":\"bg\",\"name\":\"البلغارية\"},{\"code\":\"pl\",\"name\":\"البولندية\"},{\"code\":\"th\",\"name\":\"التايلاندية\"},{\"code\":\"tr\",\"name\":\"التركية\"},{\"code\":\"cs\",\"name\":\"التشيكية\"},{\"code\":\"gl\",\"name\":\"الجاليكية\"},{\"code\":\"da\",\"name\":\"الدانماركية\"},{\"code\":\"ru\",\"name\":\"الروسية\"},{\"code\":\"ro\",\"name\":\"الرومانية\"},{\"code\":\"zu\",\"name\":\"الزولوية\"},{\"code\":\"sk\",\"name\":\"السلوفاكية\"},{\"code\":\"sl\",\"name\":\"السلوفينية\"},{\"code\":\"sv\",\"name\":\"السويدية\"},{\"code\":\"sr\",\"name\":\"الصربية\"},{\"code\":\"zh-tw\",\"name\":\"الصينية (التقليدية)\"},{\"code\":\"zh-cn\",\"name\":\"الصينية (المبسطة)\"},{\"code\":\"he\",\"name\":\"العبرية\"},{\"code\":\"ar\",\"name\":\"العربية\"},{\"code\":\"fa\",\"name\":\"الفارسية\"},{\"code\":\"fr\",\"name\":\"الفرنسية\"},{\"code\":\"fi\",\"name\":\"الفنلندية\"},{\"code\":\"vi\",\"name\":\"الفيتنامية\"},{\"code\":\"ca\",\"name\":\"القطلونية\"},{\"code\":\"hr\",\"name\":\"الكرواتية\"},{\"code\":\"ko\",\"name\":\"الكورية\"},{\"code\":\"lv\",\"name\":\"اللاتفية\"},{\"code\":\"lt\",\"name\":\"الليتوانية\"},{\"code\":\"mi\",\"name\":\"الماورية\"},{\"code\":\"nb\",\"name\":\"النرويجية\"},{\"code\":\"hu\",\"name\":\"الهنغارية\"},{\"code\":\"nl\",\"name\":\"الهولندية\"},{\"code\":\"cy\",\"name\":\"الويلزية\"},{\"code\":\"ja\",\"name\":\"اليابانية\"},{\"code\":\"el\",\"name\":\"اليونانية\"}],\"en\":[{\"code\":\"am\",\"name\":\"Amharic\"},{\"code\":\"ar\",\"name\":\"Arabic\"},{\"code\":\"az\",\"name\":\"Azerbaijani\"},{\"code\":\"eu\",\"name\":\"Basque\"},{\"code\":\"bg\",\"name\":\"Bulgarian\"},{\"code\":\"ca\",\"name\":\"Catalan\"},{\"code\":\"zh-cn\",\"name\":\"Chinese (Simplified)\"},{\"code\":\"zh-tw\",\"name\":\"Chinese (Traditional)\"},{\"code\":\"hr\",\"name\":\"Croatian\"},{\"code\":\"cs\",\"name\":\"Czech\"},{\"code\":\"da\",\"name\":\"Danish\"},{\"code\":\"nl\",\"name\":\"Dutch\"},{\"code\":\"en\",\"name\":\"English\"},{\"code\":\"et\",\"name\":\"Estonian\"},{\"code\":\"fi\",\"name\":\"Finnish\"},{\"code\":\"fr\",\"name\":\"French\"},{\"code\":\"gl\",\"name\":\"Galician\"},{\"code\":\"de\",\"name\":\"German\"},{\"code\":\"el\",\"name\":\"Greek\"},{\"code\":\"he\",\"name\":\"Hebrew\"},{\"code\":\"hu\",\"name\":\"Hungarian\"},{\"code\":\"is\",\"name\":\"Icelandic\"},{\"code\":\"id\",\"name\":\"Indonesian\"},{\"code\":\"ga\",\"name\":\"Irish\"},{\"code\":\"it\",\"name\":\"Italian\"},{\"code\":\"ja\",\"name\":\"Japanese\"},{\"code\":\"ko\",\"name\":\"Korean\"},{\"code\":\"lv\",\"name\":\"Latvian\"},{\"code\":\"lt\",\"name\":\"Lithuanian\"},{\"code\":\"mi\",\"name\":\"Maori\"},{\"code\":\"nb\",\"name\":\"Norwegian\"},{\"code\":\"fa\",\"name\":\"Persian\"},{\"code\":\"pl\",\"name\":\"Polish\"},{\"code\":\"pt\",\"name\":\"Portuguese\"},{\"code\":\"ro\",\"name\":\"Romanian\"},{\"code\":\"ru\",\"name\":\"Russian\"},{\"code\":\"gd\",\"name\":\"Scots Gaelic\"},{\"code\":\"sr\",\"name\":\"Serbian\"},{\"code\":\"sk\",\"name\":\"Slovak\"},{\"code\":\"sl\",\"name\":\"Slovenian\"},{\"code\":\"es\",\"name\":\"Spanish\"},{\"code\":\"sv\",\"name\":\"Swedish\"},{\"code\":\"th\",\"name\":\"Thai\"},{\"code\":\"tr\",\"name\":\"Turkish\"},{\"code\":\"uk\",\"name\":\"Ukrainian\"},{\"code\":\"vi\",\"name\":\"Vietnamese\"},{\"code\":\"cy\",\"name\":\"Welsh\"},{\"code\":\"zu\",\"name\":\"Zulu\"}],\"sr\":[{\"code\":\"az\",\"name\":\"азербејџански\"},{\"code\":\"am\",\"name\":\"амхарски\"},{\"code\":\"ar\",\"name\":\"арапски\"},{\"code\":\"eu\",\"name\":\"баскијски\"},{\"code\":\"bg\",\"name\":\"бугарски\"},{\"code\":\"cy\",\"name\":\"велшки\"},{\"code\":\"vi\",\"name\":\"вијетнамски\"},{\"code\":\"gl\",\"name\":\"галски\"},{\"code\":\"el\",\"name\":\"грчки\"},{\"code\":\"da\",\"name\":\"дански\"},{\"code\":\"en\",\"name\":\"енглески\"},{\"code\":\"et\",\"name\":\"естонски\"},{\"code\":\"zu\",\"name\":\"зулу\"},{\"code\":\"id\",\"name\":\"индонежански\"},{\"code\":\"ga\",\"name\":\"ирски\"},{\"code\":\"is\",\"name\":\"исландски\"},{\"code\":\"it\",\"name\":\"италијански\"},{\"code\":\"ja\",\"name\":\"јапански\"},{\"code\":\"ca\",\"name\":\"каталонски\"},{\"code\":\"zh-cn\",\"name\":\"кинески (поједностављени)\"},{\"code\":\"zh-tw\",\"name\":\"кинески (традиционални)\"},{\"code\":\"ko\",\"name\":\"корејски\"},{\"code\":\"lv\",\"name\":\"летонски\"},{\"code\":\"lt\",\"name\":\"литвански\"},{\"code\":\"hu\",\"name\":\"мађарски\"},{\"code\":\"mi\",\"name\":\"маорски\"},{\"code\":\"de\",\"name\":\"немачки\"},{\"code\":\"nb\",\"name\":\"норвешки\"},{\"code\":\"fa\",\"name\":\"персијски\"},{\"code\":\"pl\",\"name\":\"пољски\"},{\"code\":\"pt\",\"name\":\"португалски\"},{\"code\":\"ro\",\"name\":\"румунски\"},{\"code\":\"ru\",\"name\":\"руски\"},{\"code\":\"sk\",\"name\":\"словачки\"},{\"code\":\"sl\",\"name\":\"словеначки\"},{\"code\":\"sr\",\"name\":\"српски\"},{\"code\":\"th\",\"name\":\"тајски\"},{\"code\":\"tr\",\"name\":\"турски\"},{\"code\":\"uk\",\"name\":\"украјински\"},{\"code\":\"fi\",\"name\":\"фински\"},{\"code\":\"fr\",\"name\":\"француски\"},{\"code\":\"he\",\"name\":\"хебрејски\"},{\"code\":\"nl\",\"name\":\"холандски\"},{\"code\":\"hr\",\"name\":\"хрватски\"},{\"code\":\"cs\",\"name\":\"чешки\"},{\"code\":\"sv\",\"name\":\"шведски\"},{\"code\":\"gd\",\"name\":\"шкотски галски\"},{\"code\":\"es\",\"name\":\"шпански\"}],\"sv\":[{\"code\":\"am\",\"name\":\"amhariska\"},{\"code\":\"ar\",\"name\":\"arabiska\"},{\"code\":\"az\",\"name\":\"azerbajdzjanska\"},{\"code\":\"eu\",\"name\":\"baskiska\"},{\"code\":\"bg\",\"name\":\"bulgariska\"},{\"code\":\"da\",\"name\":\"danska\"},{\"code\":\"en\",\"name\":\"engelska\"},{\"code\":\"et\",\"name\":\"estniska\"},{\"code\":\"fi\",\"name\":\"finska\"},{\"code\":\"fr\",\"name\":\"franska\"},{\"code\":\"gd\",\"name\":\"gaeliska\"},{\"code\":\"gl\",\"name\":\"galiciska\"},{\"code\":\"el\",\"name\":\"grekiska\"},{\"code\":\"he\",\"name\":\"hebreiska\"},{\"code\":\"id\",\"name\":\"indonesiska\"},{\"code\":\"ga\",\"name\":\"irländska\"},{\"code\":\"is\",\"name\":\"isländska\"},{\"code\":\"it\",\"name\":\"italienska\"},{\"code\":\"ja\",\"name\":\"japanska\"},{\"code\":\"ca\",\"name\":\"katalanska\"},{\"code\":\"zh-cn\",\"name\":\"kinesiska (förenklad)\"},{\"code\":\"zh-tw\",\"name\":\"kinesiska (traditionell)\"},{\"code\":\"ko\",\"name\":\"koreanska\"},{\"code\":\"hr\",\"name\":\"kroatiska\"},{\"code\":\"lv\",\"name\":\"lettiska\"},{\"code\":\"lt\",\"name\":\"litauiska\"},{\"code\":\"mi\",\"name\":\"maori\"},{\"code\":\"nl\",\"name\":\"nederländska\"},{\"code\":\"nb\",\"name\":\"norska\"},{\"code\":\"fa\",\"name\":\"persiska\"},{\"code\":\"pl\",\"name\":\"polska\"},{\"code\":\"pt\",\"name\":\"portugisiska\"},{\"code\":\"ro\",\"name\":\"rumänska\"},{\"code\":\"ru\",\"name\":\"ryska\"},{\"code\":\"sr\",\"name\":\"serbiska\"},{\"code\":\"sk\",\"name\":\"slovakiska\"},{\"code\":\"sl\",\"name\":\"slovenska\"},{\"code\":\"es\",\"name\":\"spanska\"},{\"code\":\"sv\",\"name\":\"svenska\"},{\"code\":\"th\",\"name\":\"thailändska\"},{\"code\":\"cs\",\"name\":\"tjeckiska\"},{\"code\":\"tr\",\"name\":\"turkiska\"},{\"code\":\"de\",\"name\":\"tyska\"},{\"code\":\"uk\",\"name\":\"ukrainska\"},{\"code\":\"hu\",\"name\":\"ungerska\"},{\"code\":\"vi\",\"name\":\"vietnamesiska\"},{\"code\":\"cy\",\"name\":\"walesiska\"},{\"code\":\"zu\",\"name\":\"zulu\"}],\"ro\":[{\"code\":\"am\",\"name\":\"Amharică\"},{\"code\":\"ar\",\"name\":\"Arabă\"},{\"code\":\"az\",\"name\":\"Azerbaidjană\"},{\"code\":\"eu\",\"name\":\"Bască\"},{\"code\":\"bg\",\"name\":\"Bulgară\"},{\"code\":\"ca\",\"name\":\"Catalană\"},{\"code\":\"cs\",\"name\":\"Cehă\"},{\"code\":\"zh-cn\",\"name\":\"Chineză (Simplificată)\"},{\"code\":\"zh-tw\",\"name\":\"Chineză (Tradițională)\"},{\"code\":\"ko\",\"name\":\"Coreeană\"},{\"code\":\"hr\",\"name\":\"Croată\"},{\"code\":\"da\",\"name\":\"Daneză\"},{\"code\":\"he\",\"name\":\"Ebraică\"},{\"code\":\"en\",\"name\":\"Engleză\"},{\"code\":\"et\",\"name\":\"Estonă\"},{\"code\":\"fi\",\"name\":\"Finlandeză\"},{\"code\":\"fr\",\"name\":\"Franceză\"},{\"code\":\"cy\",\"name\":\"Galeză\"},{\"code\":\"gd\",\"name\":\"Galica scoțiană\"},{\"code\":\"gl\",\"name\":\"Galiciană\"},{\"code\":\"de\",\"name\":\"Germană\"},{\"code\":\"el\",\"name\":\"Greacă\"},{\"code\":\"id\",\"name\":\"Indoneziană\"},{\"code\":\"ga\",\"name\":\"Irlandeză\"},{\"code\":\"is\",\"name\":\"Islandeză\"},{\"code\":\"it\",\"name\":\"Italiană\"},{\"code\":\"ja\",\"name\":\"Japoneză\"},{\"code\":\"lv\",\"name\":\"Letonă\"},{\"code\":\"lt\",\"name\":\"Lituaniană\"},{\"code\":\"hu\",\"name\":\"Maghiară\"},{\"code\":\"mi\",\"name\":\"Maori\"},{\"code\":\"nl\",\"name\":\"Neerlandeză\"},{\"code\":\"nb\",\"name\":\"Norvegiană\"},{\"code\":\"fa\",\"name\":\"Persană\"},{\"code\":\"pl\",\"name\":\"Poloneză\"},{\"code\":\"pt\",\"name\":\"Portugheză\"},{\"code\":\"ro\",\"name\":\"Română\"},{\"code\":\"ru\",\"name\":\"Rusă\"},{\"code\":\"sr\",\"name\":\"Sârbă\"},{\"code\":\"sk\",\"name\":\"Slovacă\"},{\"code\":\"sl\",\"name\":\"Slovenă\"},{\"code\":\"es\",\"name\":\"Spaniolă\"},{\"code\":\"sv\",\"name\":\"Suedeză\"},{\"code\":\"th\",\"name\":\"Thailandeză\"},{\"code\":\"tr\",\"name\":\"Turcă\"},{\"code\":\"uk\",\"name\":\"Ucraineană\"},{\"code\":\"vi\",\"name\":\"Vietnameză\"},{\"code\":\"zu\",\"name\":\"Zulu\"}],\"lt\":[{\"code\":\"ga\",\"name\":\"airių\"},{\"code\":\"am\",\"name\":\"amharų\"},{\"code\":\"en\",\"name\":\"anglų\"},{\"code\":\"ar\",\"name\":\"arabų\"},{\"code\":\"az\",\"name\":\"Azerbaidžaniečių\"},{\"code\":\"eu\",\"name\":\"baskų\"},{\"code\":\"bg\",\"name\":\"bulgarų\"},{\"code\":\"cs\",\"name\":\"čekų\"},{\"code\":\"da\",\"name\":\"danų\"},{\"code\":\"et\",\"name\":\"estų\"},{\"code\":\"gl\",\"name\":\"galisų\"},{\"code\":\"el\",\"name\":\"graikų\"},{\"code\":\"he\",\"name\":\"hebrajų\"},{\"code\":\"id\",\"name\":\"indoneziečių\"},{\"code\":\"is\",\"name\":\"islandų\"},{\"code\":\"es\",\"name\":\"ispanų\"},{\"code\":\"it\",\"name\":\"italų\"},{\"code\":\"ja\",\"name\":\"japonų\"},{\"code\":\"ca\",\"name\":\"kataloniečių\"},{\"code\":\"zh-cn\",\"name\":\"kinų (supaprastinta)\"},{\"code\":\"zh-tw\",\"name\":\"kinų (tradicinė)\"},{\"code\":\"ko\",\"name\":\"korėjiečių\"},{\"code\":\"hr\",\"name\":\"kroatų\"},{\"code\":\"lv\",\"name\":\"latvių\"},{\"code\":\"pl\",\"name\":\"lenkų\"},{\"code\":\"lt\",\"name\":\"lietuvių\"},{\"code\":\"mi\",\"name\":\"maorių\"},{\"code\":\"nb\",\"name\":\"norvegų\"},{\"code\":\"nl\",\"name\":\"olandų\"},{\"code\":\"fa\",\"name\":\"persų\"},{\"code\":\"pt\",\"name\":\"portugalų\"},{\"code\":\"fr\",\"name\":\"prancūzų\"},{\"code\":\"ro\",\"name\":\"rumunų\"},{\"code\":\"ru\",\"name\":\"rusų\"},{\"code\":\"sr\",\"name\":\"serbų\"},{\"code\":\"sk\",\"name\":\"slovakų\"},{\"code\":\"sl\",\"name\":\"slovėnų\"},{\"code\":\"fi\",\"name\":\"suomių\"},{\"code\":\"gd\",\"name\":\"škotų (gėlų)\"},{\"code\":\"sv\",\"name\":\"švedų\"},{\"code\":\"th\",\"name\":\"tajų\"},{\"code\":\"tr\",\"name\":\"turkų\"},{\"code\":\"uk\",\"name\":\"ukrainiečių\"},{\"code\":\"cy\",\"name\":\"valų\"},{\"code\":\"hu\",\"name\":\"vengrų\"},{\"code\":\"vi\",\"name\":\"vietnamiečių\"},{\"code\":\"de\",\"name\":\"vokiečių\"},{\"code\":\"zu\",\"name\":\"zulusų\"}],\"ko\":[{\"code\":\"gl\",\"name\":\"갈리시아어\"},{\"code\":\"el\",\"name\":\"그리스어\"},{\"code\":\"nl\",\"name\":\"네덜란드어\"},{\"code\":\"nb\",\"name\":\"노르웨이어\"},{\"code\":\"da\",\"name\":\"덴마크어\"},{\"code\":\"de\",\"name\":\"독일어\"},{\"code\":\"lv\",\"name\":\"라트비아어\"},{\"code\":\"ru\",\"name\":\"러시아어\"},{\"code\":\"ro\",\"name\":\"루마니아어\"},{\"code\":\"lt\",\"name\":\"리투아니아어\"},{\"code\":\"mi\",\"name\":\"마오리어\"},{\"code\":\"eu\",\"name\":\"바스크어\"},{\"code\":\"vi\",\"name\":\"베트남어\"},{\"code\":\"bg\",\"name\":\"불가리아어\"},{\"code\":\"sr\",\"name\":\"세르비아어\"},{\"code\":\"sv\",\"name\":\"스웨덴어\"},{\"code\":\"gd\",\"name\":\"스코틀랜드 게일어\"},{\"code\":\"es\",\"name\":\"스페인어\"},{\"code\":\"sk\",\"name\":\"슬로바키아어\"},{\"code\":\"sl\",\"name\":\"슬로베니아어\"},{\"code\":\"ar\",\"name\":\"아랍어\"},{\"code\":\"is\",\"name\":\"아이슬란드어\"},{\"code\":\"ga\",\"name\":\"아일랜드어\"},{\"code\":\"az\",\"name\":\"아제르바이잔어\"},{\"code\":\"am\",\"name\":\"암하라어\"},{\"code\":\"et\",\"name\":\"에스토니아어\"},{\"code\":\"en\",\"name\":\"영어\"},{\"code\":\"uk\",\"name\":\"우크라이나어\"},{\"code\":\"cy\",\"name\":\"웨일즈어\"},{\"code\":\"it\",\"name\":\"이탈리아어\"},{\"code\":\"id\",\"name\":\"인도네시아어\"},{\"code\":\"ja\",\"name\":\"일본어\"},{\"code\":\"zu\",\"name\":\"줄루어\"},{\"code\":\"zh-cn\",\"name\":\"중국어(간체)\"},{\"code\":\"zh-tw\",\"name\":\"중국어(번체)\"},{\"code\":\"cs\",\"name\":\"체코어\"},{\"code\":\"ca\",\"name\":\"카탈로니아어\"},{\"code\":\"hr\",\"name\":\"크로아티아어\"},{\"code\":\"th\",\"name\":\"태국어\"},{\"code\":\"tr\",\"name\":\"터키어\"},{\"code\":\"fa\",\"name\":\"페르시아어\"},{\"code\":\"pt\",\"name\":\"포르투갈어\"},{\"code\":\"pl\",\"name\":\"폴란드어\"},{\"code\":\"fr\",\"name\":\"프랑스어\"},{\"code\":\"fi\",\"name\":\"핀란드어\"},{\"code\":\"ko\",\"name\":\"한국어\"},{\"code\":\"hu\",\"name\":\"헝가리어\"},{\"code\":\"he\",\"name\":\"히브리어\"}],\"it\":[{\"code\":\"am\",\"name\":\"Amarico\"},{\"code\":\"ar\",\"name\":\"Arabo\"},{\"code\":\"az\",\"name\":\"Azero\"},{\"code\":\"eu\",\"name\":\"Basco\"},{\"code\":\"bg\",\"name\":\"Bulgaro\"},{\"code\":\"ca\",\"name\":\"Catalano\"},{\"code\":\"cs\",\"name\":\"Ceco\"},{\"code\":\"zh-cn\",\"name\":\"Cinese (semplificato)\"},{\"code\":\"zh-tw\",\"name\":\"Cinese (tradizionale)\"},{\"code\":\"ko\",\"name\":\"Coreano\"},{\"code\":\"hr\",\"name\":\"Croato\"},{\"code\":\"da\",\"name\":\"Danese\"},{\"code\":\"he\",\"name\":\"Ebraico\"},{\"code\":\"et\",\"name\":\"Estone\"},{\"code\":\"fi\",\"name\":\"Finlandese\"},{\"code\":\"fr\",\"name\":\"Francese\"},{\"code\":\"gd\",\"name\":\"Gaelico scozzese\"},{\"code\":\"gl\",\"name\":\"Galiziano\"},{\"code\":\"cy\",\"name\":\"Gallese\"},{\"code\":\"ja\",\"name\":\"Giapponese\"},{\"code\":\"el\",\"name\":\"Greco\"},{\"code\":\"id\",\"name\":\"Indonesiano\"},{\"code\":\"en\",\"name\":\"Inglese\"},{\"code\":\"ga\",\"name\":\"Irlandese\"},{\"code\":\"is\",\"name\":\"Islandese\"},{\"code\":\"it\",\"name\":\"Italiano\"},{\"code\":\"lv\",\"name\":\"Lettone\"},{\"code\":\"lt\",\"name\":\"Lituano\"},{\"code\":\"mi\",\"name\":\"Maori\"},{\"code\":\"nb\",\"name\":\"Norvegese\"},{\"code\":\"nl\",\"name\":\"Olandese\"},{\"code\":\"fa\",\"name\":\"Persiano\"},{\"code\":\"pl\",\"name\":\"Polacco\"},{\"code\":\"pt\",\"name\":\"Portoghese\"},{\"code\":\"ro\",\"name\":\"Rumeno\"},{\"code\":\"ru\",\"name\":\"Russo\"},{\"code\":\"sr\",\"name\":\"Serbo\"},{\"code\":\"sk\",\"name\":\"Slovacco\"},{\"code\":\"sl\",\"name\":\"Sloveno\"},{\"code\":\"es\",\"name\":\"Spagnolo\"},{\"code\":\"sv\",\"name\":\"Svedese\"},{\"code\":\"th\",\"name\":\"Tailandese\"},{\"code\":\"de\",\"name\":\"Tedesco\"},{\"code\":\"tr\",\"name\":\"Turco\"},{\"code\":\"uk\",\"name\":\"Ucraino\"},{\"code\":\"hu\",\"name\":\"Ungherese\"},{\"code\":\"vi\",\"name\":\"Vietnamita\"},{\"code\":\"zu\",\"name\":\"Zulu\"}],\"vi\":[{\"code\":\"ar\",\"name\":\"Tiếng Ả Rập\"},{\"code\":\"am\",\"name\":\"Tiếng Amharic\"},{\"code\":\"en\",\"name\":\"Tiếng Anh\"},{\"code\":\"az\",\"name\":\"Tiếng Azerbaijan\"},{\"code\":\"pl\",\"name\":\"Tiếng Ba Lan\"},{\"code\":\"fa\",\"name\":\"Tiếng Ba Tư\"},{\"code\":\"eu\",\"name\":\"Tiếng Basque\"},{\"code\":\"pt\",\"name\":\"Tiếng Bồ Đào Nha\"},{\"code\":\"bg\",\"name\":\"Tiếng Bulgaria\"},{\"code\":\"ca\",\"name\":\"Tiếng Catalan\"},{\"code\":\"hr\",\"name\":\"Tiếng Croatia\"},{\"code\":\"he\",\"name\":\"Tiếng Do Thái\"},{\"code\":\"da\",\"name\":\"Tiếng Đan Mạch\"},{\"code\":\"de\",\"name\":\"Tiếng Đức\"},{\"code\":\"et\",\"name\":\"Tiếng Estonia\"},{\"code\":\"gd\",\"name\":\"Tiếng Gael Scotland\"},{\"code\":\"gl\",\"name\":\"Tiếng Galicia\"},{\"code\":\"nl\",\"name\":\"Tiếng Hà Lan\"},{\"code\":\"ko\",\"name\":\"Tiếng Hàn\"},{\"code\":\"hu\",\"name\":\"Tiếng Hungary\"},{\"code\":\"el\",\"name\":\"Tiếng Hy Lạp\"},{\"code\":\"is\",\"name\":\"Tiếng Iceland\"},{\"code\":\"id\",\"name\":\"Tiếng Indonesia\"},{\"code\":\"ga\",\"name\":\"Tiếng Ireland\"},{\"code\":\"lv\",\"name\":\"Tiếng Latvia\"},{\"code\":\"lt\",\"name\":\"Tiếng Litva\"},{\"code\":\"mi\",\"name\":\"Tiếng Maori\"},{\"code\":\"nb\",\"name\":\"Tiếng Na Uy\"},{\"code\":\"ru\",\"name\":\"Tiếng Nga\"},{\"code\":\"ja\",\"name\":\"Tiếng Nhật\"},{\"code\":\"fr\",\"name\":\"Tiếng Pháp\"},{\"code\":\"fi\",\"name\":\"Tiếng Phần Lan\"},{\"code\":\"ro\",\"name\":\"Tiếng Rumani\"},{\"code\":\"cs\",\"name\":\"Tiếng Séc\"},{\"code\":\"sr\",\"name\":\"Tiếng Serbia\"},{\"code\":\"sk\",\"name\":\"Tiếng Slovak\"},{\"code\":\"sl\",\"name\":\"Tiếng Slovenia\"},{\"code\":\"es\",\"name\":\"Tiếng Tây Ban Nha\"},{\"code\":\"th\",\"name\":\"Tiếng Thái\"},{\"code\":\"tr\",\"name\":\"Tiếng Thổ Nhĩ Kỳ\"},{\"code\":\"sv\",\"name\":\"Tiếng Thụy Điển\"},{\"code\":\"zh-cn\",\"name\":\"Tiếng Trung (Giản Thể)\"},{\"code\":\"zh-tw\",\"name\":\"Tiếng Trung (Phồn thể)\"},{\"code\":\"uk\",\"name\":\"Tiếng Ukraina\"},{\"code\":\"vi\",\"name\":\"Tiếng Việt\"},{\"code\":\"cy\",\"name\":\"Tiếng Xứ Wales\"},{\"code\":\"it\",\"name\":\"Tiếng Ý\"},{\"code\":\"zu\",\"name\":\"Tiếng Zulu\"}]},\"nameMap\":{\"albánština\":\"sq\",\"amharština\":\"am\",\"angličtina\":\"en\",\"arabština\":\"ar\",\"arménština\":\"hy\",\"ázerbájdžánština\":\"az\",\"barmština\":\"my\",\"baskičtina\":\"eu\",\"běloruština\":\"be\",\"bulharština\":\"bg\",\"čeština\":\"cs\",\"čínština (tradiční)\":\"zh-tw\",\"čínština (zjednodušená)\":\"zh-cn\",\"dánština\":\"da\",\"esperanto\":\"eo\",\"estonština\":\"et\",\"finština\":\"fi\",\"francouzština\":\"fr\",\"galicijština\":\"gl\",\"haitská kreolština\":\"ht\",\"hebrejština\":\"he\",\"hindština\":\"hi\",\"holandština\":\"nl\",\"chorvatština\":\"hr\",\"indonéština\":\"id\",\"irština\":\"ga\",\"islandština\":\"is\",\"italština\":\"it\",\"japonština\":\"ja\",\"kannadština\":\"kn\",\"katalánština\":\"ca\",\"korejština\":\"ko\",\"kurdština\":\"ku\",\"latina\":\"la\",\"litevština\":\"lt\",\"lotyština\":\"lv\",\"maďarština\":\"hu\",\"makedonština\":\"mk\",\"malajálamština\":\"ml\",\"malajština\":\"ms\",\"maltština\":\"mt\",\"maorština\":\"mi\",\"marátština\":\"mr\",\"mongolština\":\"mn\",\"němčina\":\"de\",\"norština\":\"nb\",\"perština\":\"fa\",\"polština\":\"pl\",\"portugalština\":\"pt\",\"rumunština\":\"ro\",\"ruština\":\"ru\",\"řečtina\":\"el\",\"skotská gaelština\":\"gd\",\"slovenština\":\"sk\",\"slovinština\":\"sl\",\"srbština\":\"sr\",\"španělština\":\"es\",\"švédština\":\"sv\",\"telužština\":\"te\",\"thajština\":\"th\",\"turečtina\":\"tr\",\"ukrajinština\":\"uk\",\"uzbečtina\":\"uz\",\"velština\":\"cy\",\"vietnamština\":\"vi\",\"zulu\":\"zu\",\"albansk\":\"sq\",\"amharisk\":\"am\",\"arabisk\":\"ar\",\"armensk\":\"hy\",\"aserbajdsjansk\":\"az\",\"baskisk\":\"eu\",\"bulgarsk\":\"bg\",\"burmesisk\":\"my\",\"dansk\":\"da\",\"engelsk\":\"en\",\"estisk\":\"et\",\"finsk\":\"fi\",\"fransk\":\"fr\",\"galicisk\":\"gl\",\"græsk\":\"el\",\"haitisk kreolsk\":\"ht\",\"hebraisk\":\"he\",\"hindi\":\"hi\",\"hollandsk\":\"nl\",\"hviderussisk\":\"be\",\"indonesisk\":\"id\",\"irsk\":\"ga\",\"islandsk\":\"is\",\"italiensk\":\"it\",\"japansk\":\"ja\",\"kannada\":\"kn\",\"katalansk\":\"ca\",\"kinesisk (forenklet)\":\"zh-cn\",\"kinesisk (traditionelt)\":\"zh-tw\",\"koreansk\":\"ko\",\"kroatisk\":\"hr\",\"kurdisk\":\"ku\",\"latin\":\"la\",\"lettisk\":\"lv\",\"litauisk\":\"lt\",\"makedonsk\":\"mk\",\"malajisk\":\"ms\",\"malayalam\":\"ml\",\"maltesisk\":\"mt\",\"maori\":\"mi\",\"marathi\":\"mr\",\"mongolsk\":\"mn\",\"norsk\":\"nb\",\"persisk\":\"fa\",\"polsk\":\"pl\",\"portugisisk\":\"pt\",\"rumænsk\":\"ro\",\"russisk\":\"ru\",\"serbisk\":\"sr\",\"skotsk gælisk\":\"gd\",\"slovakisk\":\"sk\",\"slovensk\":\"sl\",\"spansk\":\"es\",\"svensk\":\"sv\",\"telugu\":\"te\",\"thailandsk\":\"th\",\"tjekkisk\":\"cs\",\"tyrkisk\":\"tr\",\"tysk\":\"de\",\"ukrainsk\":\"uk\",\"ungarsk\":\"hu\",\"usbekisk\":\"uz\",\"vietnamesisk\":\"vi\",\"walisisk\":\"cy\",\"acerbaixano\":\"az\",\"albanés\":\"sq\",\"alemán\":\"de\",\"amárico\":\"am\",\"árabe\":\"ar\",\"armenio\":\"hy\",\"bielorruso\":\"be\",\"birmano\":\"my\",\"búlgaro\":\"bg\",\"canarés\":\"kn\",\"catalán\":\"ca\",\"checo\":\"cs\",\"chinés (simplificado)\":\"zh-cn\",\"chinés (tradicional)\":\"zh-tw\",\"coreano\":\"ko\",\"crioulo haitiano\":\"ht\",\"croata\":\"hr\",\"curdo\":\"ku\",\"dinamarqués\":\"da\",\"eslovaco\":\"sk\",\"esloveno\":\"sl\",\"español\":\"es\",\"estoniano\":\"et\",\"éuscaro\":\"eu\",\"finés\":\"fi\",\"francés\":\"fr\",\"gaélico escocés\":\"gd\",\"galego\":\"gl\",\"galés\":\"cy\",\"grego\":\"el\",\"hebreo\":\"he\",\"húngaro\":\"hu\",\"indonesio\":\"id\",\"inglés\":\"en\",\"irlandés\":\"ga\",\"islandés\":\"is\",\"italiano\":\"it\",\"latín\":\"la\",\"letón\":\"lv\",\"lituano\":\"lt\",\"macedonio\":\"mk\",\"malabar\":\"ml\",\"malaio\":\"ms\",\"maltés\":\"mt\",\"maorí\":\"mi\",\"mongol\":\"mn\",\"neerlandés\":\"nl\",\"noruegués\":\"nb\",\"persa\":\"fa\",\"polaco\":\"pl\",\"portugués\":\"pt\",\"romanés\":\"ro\",\"ruso\":\"ru\",\"serbio\":\"sr\",\"sueco\":\"sv\",\"tailandés\":\"th\",\"telugú\":\"te\",\"turco\":\"tr\",\"ucraíno\":\"uk\",\"usbeco\":\"uz\",\"vietnamita\":\"vi\",\"xaponés\":\"ja\",\"zulú\":\"zu\",\"albanščina\":\"sq\",\"amharščina\":\"am\",\"angleščina\":\"en\",\"arabščina\":\"ar\",\"armenščina\":\"hy\",\"azerbajdžanščina\":\"az\",\"baskovščina\":\"eu\",\"beloruščina\":\"be\",\"bolgarščina\":\"bg\",\"burmanščina\":\"my\",\"češčina\":\"cs\",\"danščina\":\"da\",\"estonščina\":\"et\",\"finščina\":\"fi\",\"francoščina\":\"fr\",\"galicijščina\":\"gl\",\"grščina\":\"el\",\"haitijska kreolščina\":\"ht\",\"hebrejščina\":\"he\",\"hindijščina\":\"hi\",\"hrvaščina\":\"hr\",\"indonezijščina\":\"id\",\"irščina\":\"ga\",\"islandščina\":\"is\",\"italijanščina\":\"it\",\"japonščina\":\"ja\",\"kanareščina\":\"kn\",\"katalonščina\":\"ca\",\"kitajščina (poenostavljena)\":\"zh-cn\",\"kitajščina (tradicionalna)\":\"zh-tw\",\"korejščina\":\"ko\",\"kurdščina\":\"ku\",\"latinščina\":\"la\",\"latvijščina\":\"lv\",\"litovščina\":\"lt\",\"madžarščina\":\"hu\",\"makedonščina\":\"mk\",\"malajalščina\":\"ml\",\"malajščina\":\"ms\",\"malteščina\":\"mt\",\"maorščina\":\"mi\",\"maratščina\":\"mr\",\"mongolščina\":\"mn\",\"nemščina\":\"de\",\"nizozemščina\":\"nl\",\"norveščina\":\"nb\",\"perzijščina\":\"fa\",\"poljščina\":\"pl\",\"portugalščina\":\"pt\",\"romunščina\":\"ro\",\"ruščina\":\"ru\",\"slovaščina\":\"sk\",\"slovenščina\":\"sl\",\"srbščina\":\"sr\",\"škotska gelščina\":\"gd\",\"španščina\":\"es\",\"švedščina\":\"sv\",\"tajščina\":\"th\",\"teluščina\":\"te\",\"turščina\":\"tr\",\"ukrajinščina\":\"uk\",\"uzbeščina\":\"uz\",\"valižanščina\":\"cy\",\"vietnamščina\":\"vi\",\"zulujščina\":\"zu\",\"albanais\":\"sq\",\"allemand\":\"de\",\"amharique\":\"am\",\"anglais\":\"en\",\"arabe\":\"ar\",\"arménien\":\"hy\",\"azéri\":\"az\",\"basque\":\"eu\",\"biélorusse\":\"be\",\"birman\":\"my\",\"bulgare\":\"bg\",\"catalan\":\"ca\",\"chinois (simplifié)\":\"zh-cn\",\"chinois (traditionnel)\":\"zh-tw\",\"coréen\":\"ko\",\"créole haïtien\":\"ht\",\"croate\":\"hr\",\"danois\":\"da\",\"espagnol\":\"es\",\"espéranto\":\"eo\",\"estonien\":\"et\",\"finnois\":\"fi\",\"français\":\"fr\",\"gaélique (écosse)\":\"gd\",\"galicien\":\"gl\",\"gallois\":\"cy\",\"grec\":\"el\",\"hébreu\":\"he\",\"hongrois\":\"hu\",\"indonésien\":\"id\",\"irlandais\":\"ga\",\"islandais\":\"is\",\"italien\":\"it\",\"japonais\":\"ja\",\"kurde\":\"ku\",\"letton\":\"lv\",\"lituanien\":\"lt\",\"macédonien\":\"mk\",\"malaisien\":\"ms\",\"maltais\":\"mt\",\"néerlandais\":\"nl\",\"norvégien\":\"nb\",\"ouzbek\":\"uz\",\"persan\":\"fa\",\"polonais\":\"pl\",\"portugais\":\"pt\",\"roumain\":\"ro\",\"russe\":\"ru\",\"serbe\":\"sr\",\"slovaque\":\"sk\",\"slovène\":\"sl\",\"suédois\":\"sv\",\"tchèque\":\"cs\",\"thaï\":\"th\",\"turc\":\"tr\",\"ukrainien\":\"uk\",\"vietnamien\":\"vi\",\"zoulou\":\"zu\",\"albán\":\"sq\",\"amhara\":\"am\",\"angol\":\"en\",\"arab\":\"ar\",\"azeri\":\"az\",\"baszk\":\"eu\",\"belorusz\":\"be\",\"bolgár\":\"bg\",\"burmai\":\"my\",\"cseh\":\"cs\",\"dán\":\"da\",\"eszperantó\":\"eo\",\"észt\":\"et\",\"finn\":\"fi\",\"francia\":\"fr\",\"galíciai\":\"gl\",\"görög\":\"el\",\"haiti kreol\":\"ht\",\"héber\":\"he\",\"holland\":\"nl\",\"horvát\":\"hr\",\"indonéz\":\"id\",\"ír\":\"ga\",\"izlandi\":\"is\",\"japán\":\"ja\",\"katalán\":\"ca\",\"kínai (egyszerűsített)\":\"zh-cn\",\"kínai (hagyományos)\":\"zh-tw\",\"koreai\":\"ko\",\"kurd\":\"ku\",\"lengyel\":\"pl\",\"lett\":\"lv\",\"litván\":\"lt\",\"macedón\":\"mk\",\"magyar\":\"hu\",\"maláj\":\"ms\",\"malajálam\":\"ml\",\"máltai\":\"mt\",\"maráthi\":\"mr\",\"német\":\"de\",\"norvég\":\"nb\",\"olasz\":\"it\",\"orosz\":\"ru\",\"örmény\":\"hy\",\"perzsa\":\"fa\",\"portugál\":\"pt\",\"román\":\"ro\",\"skót-gael\":\"gd\",\"spanyol\":\"es\",\"svéd\":\"sv\",\"szerb\":\"sr\",\"szlovák\":\"sk\",\"szlovén\":\"sl\",\"thai\":\"th\",\"török\":\"tr\",\"ukrán\":\"uk\",\"üzbég\":\"uz\",\"vietnami\":\"vi\",\"walesi\":\"cy\",\"азербайджанська\":\"az\",\"албанська\":\"sq\",\"амхарська\":\"am\",\"англійська\":\"en\",\"арабська\":\"ar\",\"баскська\":\"eu\",\"білоруська\":\"be\",\"бірманська\":\"my\",\"болгарська\":\"bg\",\"в’єтнамська\":\"vi\",\"валлійська\":\"cy\",\"вірменська\":\"hy\",\"гаїтянська креольська\":\"ht\",\"гінді\":\"hi\",\"грецька\":\"el\",\"ґалісійська\":\"gl\",\"данська\":\"da\",\"есперанто\":\"eo\",\"естонська\":\"et\",\"зулу\":\"zu\",\"іврит\":\"he\",\"індонезійська\":\"id\",\"ірландська\":\"ga\",\"ісландська\":\"is\",\"іспанська\":\"es\",\"італійська\":\"it\",\"каннада\":\"kn\",\"каталанська\":\"ca\",\"китайська (спрощена)\":\"zh-cn\",\"китайська (традиційна)\":\"zh-tw\",\"корейська\":\"ko\",\"курдська\":\"ku\",\"латинська\":\"la\",\"латиська\":\"lv\",\"литовська\":\"lt\",\"македонська\":\"mk\",\"малайська\":\"ms\",\"малаялам\":\"ml\",\"мальтійська\":\"mt\",\"маорі\":\"mi\",\"маратхі\":\"mr\",\"монгольська\":\"mn\",\"нідерландська\":\"nl\",\"німецька\":\"de\",\"норвезька\":\"nb\",\"перська\":\"fa\",\"польська\":\"pl\",\"португальська\":\"pt\",\"російська\":\"ru\",\"румунська\":\"ro\",\"сербська\":\"sr\",\"словацька\":\"sk\",\"словенська\":\"sl\",\"тайська\":\"th\",\"телуґу\":\"te\",\"турецька\":\"tr\",\"угорська\":\"hu\",\"узбецька\":\"uz\",\"українська\":\"uk\",\"фінська\":\"fi\",\"французька\":\"fr\",\"хорватська\":\"hr\",\"чеська\":\"cs\",\"шведська\":\"sv\",\"шотландська (ґельська)\":\"gd\",\"японська\":\"ja\",\"土耳其文\":\"tr\",\"中文(繁體)\":\"zh-tw\",\"中文(簡體)\":\"zh-cn\",\"丹麥文\":\"da\",\"巴斯克文\":\"eu\",\"日文\":\"ja\",\"毛利文\":\"mi\",\"世界語\":\"eo\",\"加里西亞文\":\"gl\",\"加泰羅尼亞文\":\"ca\",\"卡納達文\":\"kn\",\"白俄羅斯文\":\"be\",\"立陶宛文\":\"lt\",\"冰島文\":\"is\",\"匈牙利文\":\"hu\",\"印尼文\":\"id\",\"印度文\":\"hi\",\"西班牙文\":\"es\",\"克羅埃西亞文\":\"hr\",\"希伯來文\":\"he\",\"希臘文\":\"el\",\"亞美尼亞文\":\"hy\",\"亞塞拜然文\":\"az\",\"拉丁文\":\"la\",\"拉脫維亞文\":\"lv\",\"法文\":\"fr\",\"波斯文\":\"fa\",\"波蘭文\":\"pl\",\"芬蘭文\":\"fi\",\"阿姆哈拉文\":\"am\",\"阿拉伯文\":\"ar\",\"阿爾巴尼亞文\":\"sq\",\"俄文\":\"ru\",\"保加利亞文\":\"bg\",\"南非祖魯文\":\"zu\",\"威爾斯文\":\"cy\",\"英文\":\"en\",\"庫德文\":\"ku\",\"挪威文\":\"nb\",\"泰文\":\"th\",\"泰盧固文\":\"te\",\"海地克里奧文\":\"ht\",\"烏克蘭文\":\"uk\",\"烏茲別克文\":\"uz\",\"馬耳他文\":\"mt\",\"馬來文\":\"ms\",\"馬其頓文\":\"mk\",\"馬拉地文\":\"mr\",\"馬拉雅拉姆文\":\"ml\",\"捷克文\":\"cs\",\"荷蘭文\":\"nl\",\"斯洛伐克文\":\"sk\",\"斯洛維尼亞文\":\"sl\",\"越南文\":\"vi\",\"塞爾維亞文\":\"sr\",\"愛沙尼亞文\":\"et\",\"愛爾蘭文\":\"ga\",\"瑞典文\":\"sv\",\"義大利文\":\"it\",\"葡萄牙文\":\"pt\",\"蒙古文\":\"mn\",\"德文\":\"de\",\"緬甸文\":\"my\",\"韓文\":\"ko\",\"羅馬尼亞文\":\"ro\",\"蘇格蘭的蓋爾文\":\"gd\",\"अझरबैजानी\":\"az\",\"अम्हारिक\":\"am\",\"अरबी\":\"ar\",\"अर्मेनियन\":\"hy\",\"अल्बानियन\":\"sq\",\"आइसलँडिक\":\"is\",\"आयरिश\":\"ga\",\"इंग्रजी\":\"en\",\"इंडोनेशियन\":\"id\",\"इटालियन\":\"it\",\"उझ्बेक\":\"uz\",\"एस्टोनियन\":\"et\",\"एस्परँटो\":\"eo\",\"कन्नड\":\"kn\",\"कुर्दिश (कुर्मांजी)\":\"ku\",\"कॅटलान\":\"ca\",\"कोरियन\":\"ko\",\"क्रोएशियन\":\"hr\",\"गॅलिशियन\":\"gl\",\"ग्रीक\":\"el\",\"चीनी (पारंपारिक)\":\"zh-tw\",\"चीनी (सरलीकृत)\":\"zh-cn\",\"जपानी\":\"ja\",\"जर्मन\":\"de\",\"झुलु\":\"zu\",\"झेक\":\"cs\",\"डच\":\"nl\",\"डॅनिश\":\"da\",\"तुर्की\":\"tr\",\"तेलगू\":\"te\",\"थाई\":\"th\",\"नॉर्वेजियन\":\"nb\",\"पोर्तुगीज\":\"pt\",\"पोलिश\":\"pl\",\"फारसी\":\"fa\",\"फिन्निश\":\"fi\",\"फ्रेंच\":\"fr\",\"बल्गेरियन\":\"bg\",\"बास्क\":\"eu\",\"बेलारुशियन\":\"be\",\"मंगोलियन\":\"mn\",\"मराठी\":\"mr\",\"मलय\":\"ms\",\"मल्याळम\":\"ml\",\"माओरी\":\"mi\",\"माल्टीज\":\"mt\",\"मॅसेडोनियन\":\"mk\",\"म्यानमार (बर्मीज)\":\"my\",\"युक्रेनियन\":\"uk\",\"रशियन\":\"ru\",\"रोमानियन\":\"ro\",\"लाट्वियन\":\"lv\",\"लिथुआनियन\":\"lt\",\"लॅटिन\":\"la\",\"वेल्श\":\"cy\",\"व्हिएतनामी\":\"vi\",\"सर्बियन\":\"sr\",\"स्कॉट्स गेलिक\":\"gd\",\"स्पॅनिश\":\"es\",\"स्लोव्हाक\":\"sk\",\"स्लोव्हेनियन\":\"sl\",\"स्वीडिश\":\"sv\",\"हंगेरियन\":\"hu\",\"हिन्दी\":\"hi\",\"हिब्रू\":\"he\",\"हैतीयन क्रेओल\":\"ht\",\"albanian\":\"sq\",\"amharic\":\"am\",\"arabic\":\"ar\",\"armenian\":\"hy\",\"azerbaijani\":\"az\",\"belarusian\":\"be\",\"bulgarian\":\"bg\",\"chinese (simplified)\":\"zh-cn\",\"chinese (traditional)\":\"zh-tw\",\"croatian\":\"hr\",\"czech\":\"cs\",\"danish\":\"da\",\"dutch\":\"nl\",\"english\":\"en\",\"estonian\":\"et\",\"finnish\":\"fi\",\"french\":\"fr\",\"galician\":\"gl\",\"german\":\"de\",\"greek\":\"el\",\"haitian creole\":\"ht\",\"hebrew\":\"he\",\"hungarian\":\"hu\",\"icelandic\":\"is\",\"indonesian\":\"id\",\"irish\":\"ga\",\"italian\":\"it\",\"japanese\":\"ja\",\"korean\":\"ko\",\"kurdish (kurmanji)\":\"ku\",\"latvian\":\"lv\",\"lithuanian\":\"lt\",\"macedonian\":\"mk\",\"malay\":\"ms\",\"maltese\":\"mt\",\"mongolian\":\"mn\",\"myanmar (burmese)\":\"my\",\"norwegian\":\"nb\",\"persian\":\"fa\",\"polish\":\"pl\",\"portuguese\":\"pt\",\"romanian\":\"ro\",\"russian\":\"ru\",\"scots gaelic\":\"gd\",\"serbian\":\"sr\",\"slovak\":\"sk\",\"slovenian\":\"sl\",\"spanish\":\"es\",\"swedish\":\"sv\",\"turkish\":\"tr\",\"ukrainian\":\"uk\",\"uzbek\":\"uz\",\"vietnamese\":\"vi\",\"welsh\":\"cy\",\"albanês\":\"sq\",\"alemão\":\"de\",\"armênio\":\"hy\",\"azerbaijano\":\"az\",\"basco\":\"eu\",\"bielo-russo\":\"be\",\"birmanês\":\"my\",\"canarês\":\"kn\",\"catalão\":\"ca\",\"chinês (simplificado)\":\"zh-cn\",\"chinês (tradicional)\":\"zh-tw\",\"dinamarquês\":\"da\",\"espanhol\":\"es\",\"finlandês\":\"fi\",\"francês\":\"fr\",\"gaélico escocês\":\"gd\",\"galês\":\"cy\",\"hebraico\":\"he\",\"holandês\":\"nl\",\"indonésio\":\"id\",\"inglês\":\"en\",\"irlandês\":\"ga\",\"islandês\":\"is\",\"japonês\":\"ja\",\"latim\":\"la\",\"letão\":\"lv\",\"macedônio\":\"mk\",\"malaiala\":\"ml\",\"maltês\":\"mt\",\"marata\":\"mr\",\"norueguês\":\"nb\",\"polonês\":\"pl\",\"português\":\"pt\",\"romeno\":\"ro\",\"russo\":\"ru\",\"sérvio\":\"sr\",\"tailandês\":\"th\",\"tcheco\":\"cs\",\"telugo\":\"te\",\"ucraniano\":\"uk\",\"uzbeque\":\"uz\",\"almanca\":\"de\",\"arapça\":\"ar\",\"arnavutça\":\"sq\",\"azerice\":\"az\",\"baskça\":\"eu\",\"belarusça\":\"be\",\"bulgarca\":\"bg\",\"burmaca\":\"my\",\"çekçe\":\"cs\",\"çince (basitleştirilmiş)\":\"zh-cn\",\"çince (geleneksel)\":\"zh-tw\",\"danca\":\"da\",\"endonezya dili\":\"id\",\"ermenice\":\"hy\",\"esperantoca\":\"eo\",\"estonyaca\":\"et\",\"farsça\":\"fa\",\"felemenkçe\":\"nl\",\"fince\":\"fi\",\"fransızca\":\"fr\",\"galce\":\"cy\",\"galiçyaca\":\"gl\",\"habeşçe\":\"am\",\"haiti creole dili\":\"ht\",\"hırvatça\":\"hr\",\"hintçe\":\"hi\",\"i̇branice\":\"he\",\"i̇ngilizce\":\"en\",\"i̇rlandaca\":\"ga\",\"i̇spanyolca\":\"es\",\"i̇sveççe\":\"sv\",\"i̇talyanca\":\"it\",\"i̇zlandaca\":\"is\",\"japonca\":\"ja\",\"katalanca\":\"ca\",\"korece\":\"ko\",\"kuzey i̇skoç dili\":\"gd\",\"kürtçe\":\"ku\",\"latince\":\"la\",\"lehçe\":\"pl\",\"letonca\":\"lv\",\"litvanca\":\"lt\",\"macarca\":\"hu\",\"makedonca\":\"mk\",\"malezya dili\":\"ms\",\"malta dili\":\"mt\",\"maori dili\":\"mi\",\"moğolca\":\"mn\",\"norveççe\":\"nb\",\"özbekçe\":\"uz\",\"portekizce\":\"pt\",\"romence\":\"ro\",\"rusça\":\"ru\",\"sırpça\":\"sr\",\"slovakça\":\"sk\",\"slovence\":\"sl\",\"tay dili\":\"th\",\"telugu dili\":\"te\",\"türkçe\":\"tr\",\"ukraynaca\":\"uk\",\"vietnamca\":\"vi\",\"yunanca\":\"el\",\"airméinis\":\"hy\",\"albáinis\":\"sq\",\"amárais\":\"am\",\"araibis\":\"ar\",\"asarbaiseáinis\":\"az\",\"bascais\":\"eu\",\"bealarúisis\":\"be\",\"béarla\":\"en\",\"breatnais\":\"cy\",\"bulgáiris\":\"bg\",\"cannadais\":\"kn\",\"catalóinis\":\"ca\",\"coirdis (curmainsis)\":\"ku\",\"cóiréis\":\"ko\",\"criól háítí\":\"ht\",\"cróitis\":\"hr\",\"danmhairgis\":\"da\",\"eabhrais\":\"he\",\"eastóinis\":\"et\",\"fionlainnis\":\"fi\",\"fraincis\":\"fr\",\"gaeilge\":\"ga\",\"gaeilge na halban\":\"gd\",\"gailísis\":\"gl\",\"gearmáinis\":\"de\",\"gréigis\":\"el\",\"hiondúis\":\"hi\",\"indinéisis\":\"id\",\"iodáilis\":\"it\",\"ioruais\":\"nb\",\"íoslainnis\":\"is\",\"laidin\":\"la\",\"laitvis\":\"lv\",\"liotuáinis\":\"lt\",\"macadóinis\":\"mk\",\"maenmar (burmais)\":\"my\",\"mailéalaimis\":\"ml\",\"malaeis\":\"ms\",\"máltais\":\"mt\",\"maorais\":\"mi\",\"maraitis\":\"mr\",\"mongóilis\":\"mn\",\"ollainnis\":\"nl\",\"peirsis\":\"fa\",\"polainnis\":\"pl\",\"portaingéilis\":\"pt\",\"rómáinis\":\"ro\",\"rúisis\":\"ru\",\"seapáinis\":\"ja\",\"seicis\":\"cs\",\"seirbis\":\"sr\",\"sínis (simplithe)\":\"zh-cn\",\"sínis (traidisiúnta)\":\"zh-tw\",\"slóivéinis\":\"sl\",\"slóvaicis\":\"sk\",\"spáinnis\":\"es\",\"sualainnis\":\"sv\",\"súlúis\":\"zu\",\"téalainnis\":\"th\",\"teileagúis\":\"te\",\"tuircis\":\"tr\",\"úcráinis\":\"uk\",\"úisbéiceastáinis\":\"uz\",\"ungáiris\":\"hu\",\"vítneaimis\":\"vi\",\"ภาษากรีก\":\"el\",\"ภาษากันนาดา\":\"kn\",\"ภาษากาลิเชียน\":\"gl\",\"ภาษาเกลิกในสก็อต\":\"gd\",\"ภาษาเกาหลี\":\"ko\",\"ภาษาคาตาลัน\":\"ca\",\"ภาษาเคิร์ด\":\"ku\",\"ภาษาโครเอเชีย\":\"hr\",\"ภาษาจีน (ดั้งเดิม)\":\"zh-tw\",\"ภาษาจีน (แบบย่อ)\":\"zh-cn\",\"ภาษาเช็ก\":\"cs\",\"ภาษาซูลู\":\"zu\",\"ภาษาเซอร์เบียน\":\"sr\",\"ภาษาญี่ปุ่น\":\"ja\",\"ภาษาดัตช์\":\"nl\",\"ภาษาเดนมาร์ก\":\"da\",\"ภาษาตุรกี\":\"tr\",\"ภาษาเตลูกู\":\"te\",\"ภาษาไทย\":\"th\",\"ภาษานอร์เวย์\":\"nb\",\"ภาษาบัลกาเรีย\":\"bg\",\"ภาษาบาสก์\":\"eu\",\"ภาษาเบลารูเชียน\":\"be\",\"ภาษาเปอร์เซีย\":\"fa\",\"ภาษาโปรตุเกส\":\"pt\",\"ภาษาโปแลนด์\":\"pl\",\"ภาษาฝรั่งเศส\":\"fr\",\"ภาษาฟินแลนด์\":\"fi\",\"ภาษามองโกเลีย\":\"mn\",\"ภาษามัลทีส\":\"mt\",\"ภาษามาซีโดเนีย\":\"mk\",\"ภาษามาราฐี\":\"mr\",\"ภาษามาลายาลัม\":\"ml\",\"ภาษามาเลย์\":\"ms\",\"ภาษาเมารี\":\"mi\",\"ภาษาเมียนมา (พม่า)\":\"my\",\"ภาษายูเครน\":\"uk\",\"ภาษาเยอรมัน\":\"de\",\"ภาษารัสเซีย\":\"ru\",\"ภาษาโรมาเนีย\":\"ro\",\"ภาษาละติน\":\"la\",\"ภาษาลัทเวีย\":\"lv\",\"ภาษาลิทัวเนีย\":\"lt\",\"ภาษาเวลส์\":\"cy\",\"ภาษาเวียดนาม\":\"vi\",\"ภาษาสเปน\":\"es\",\"ภาษาสโลวัก\":\"sk\",\"ภาษาสโลเวเนีย\":\"sl\",\"ภาษาสวีเดน\":\"sv\",\"ภาษาอังกฤษ\":\"en\",\"ภาษาอัมฮาริก\":\"am\",\"ภาษาอัลบาเนีย\":\"sq\",\"ภาษาอาร์เซอร์ไบจัน\":\"az\",\"ภาษาอาร์เมเนีย\":\"hy\",\"ภาษาอาหรับ\":\"ar\",\"ภาษาอิตาลี\":\"it\",\"ภาษาอินโดนีเซีย\":\"id\",\"ภาษาอุสเบกิสถาน\":\"uz\",\"ภาษาเอสโทเนีย\":\"et\",\"ภาษาเอสเปอแรนโต\":\"eo\",\"ภาษาไอซ์แลนดิก\":\"is\",\"ภาษาไอริช\":\"ga\",\"ภาษาฮังการี\":\"hu\",\"ภาษาฮินดี\":\"hi\",\"ภาษาฮิบรู\":\"he\",\"ภาษาเฮติครีโอล\":\"ht\",\"アイスランド語\":\"is\",\"アイルランド語\":\"ga\",\"アゼルバイジャン語\":\"az\",\"アムハラ語\":\"am\",\"アラビア語\":\"ar\",\"アルバニア語\":\"sq\",\"アルメニア語\":\"hy\",\"イタリア語\":\"it\",\"インドネシア語\":\"id\",\"ウェールズ語\":\"cy\",\"ウクライナ語\":\"uk\",\"ウズベク語\":\"uz\",\"エストニア語\":\"et\",\"エスペラント語\":\"eo\",\"オランダ語\":\"nl\",\"カタルーニャ語\":\"ca\",\"ガリシア語\":\"gl\",\"カンナダ語\":\"kn\",\"ギリシャ語\":\"el\",\"クルド語\":\"ku\",\"クロアチア語\":\"hr\",\"スウェーデン語\":\"sv\",\"ズールー語\":\"zu\",\"スコットランド ゲール語\":\"gd\",\"スペイン語\":\"es\",\"スロバキア語\":\"sk\",\"スロベニア語\":\"sl\",\"セルビア語\":\"sr\",\"タイ語\":\"th\",\"チェコ語\":\"cs\",\"テルグ語\":\"te\",\"デンマーク語\":\"da\",\"ドイツ語\":\"de\",\"トルコ語\":\"tr\",\"ノルウェー語\":\"nb\",\"ハイチ語\":\"ht\",\"バスク語\":\"eu\",\"ハンガリー語\":\"hu\",\"ヒンディー語\":\"hi\",\"フィンランド語\":\"fi\",\"フランス語\":\"fr\",\"ブルガリア語\":\"bg\",\"ベトナム語\":\"vi\",\"ヘブライ語\":\"he\",\"ベラルーシ語\":\"be\",\"ペルシャ語\":\"fa\",\"ポーランド語\":\"pl\",\"ポルトガル語\":\"pt\",\"マオリ語\":\"mi\",\"マケドニア語\":\"mk\",\"マラーティー語\":\"mr\",\"マラヤーラム語\":\"ml\",\"マルタ語\":\"mt\",\"マレー語\":\"ms\",\"ミャンマー語\":\"my\",\"モンゴル語\":\"mn\",\"ラテン語\":\"la\",\"ラトビア語\":\"lv\",\"リトアニア語\":\"lt\",\"ルーマニア語\":\"ro\",\"ロシア語\":\"ru\",\"英語\":\"en\",\"韓国語\":\"ko\",\"中国語(簡体)\":\"zh-cn\",\"中国語(繁体)\":\"zh-tw\",\"日本語\":\"ja\",\"albanees\":\"sq\",\"amharisch\":\"am\",\"arabisch\":\"ar\",\"armeens\":\"hy\",\"azerbeidzjaans\":\"az\",\"baskisch\":\"eu\",\"birmaans\":\"my\",\"bulgaars\":\"bg\",\"catalaans\":\"ca\",\"chinees (traditioneel)\":\"zh-tw\",\"chinees (vereenvoudigd)\":\"zh-cn\",\"deens\":\"da\",\"duits\":\"de\",\"engels\":\"en\",\"ests\":\"et\",\"fins\":\"fi\",\"frans\":\"fr\",\"galicisch\":\"gl\",\"grieks\":\"el\",\"haïtiaans creools\":\"ht\",\"hebreeuws\":\"he\",\"hongaars\":\"hu\",\"iers\":\"ga\",\"ijslands\":\"is\",\"indonesisch\":\"id\",\"italiaans\":\"it\",\"japans\":\"ja\",\"koerdisch\":\"ku\",\"koreaans\":\"ko\",\"kroatisch\":\"hr\",\"latijn\":\"la\",\"lets\":\"lv\",\"litouws\":\"lt\",\"macedonisch\":\"mk\",\"maleis\":\"ms\",\"maltees\":\"mt\",\"mongools\":\"mn\",\"nederlands\":\"nl\",\"noors\":\"nb\",\"oekraïens\":\"uk\",\"oezbeeks\":\"uz\",\"perzisch\":\"fa\",\"pools\":\"pl\",\"portugees\":\"pt\",\"roemeens\":\"ro\",\"russisch\":\"ru\",\"schots keltisch\":\"gd\",\"servisch\":\"sr\",\"slovaaks\":\"sk\",\"sloveens\":\"sl\",\"spaans\":\"es\",\"tsjechisch\":\"cs\",\"turks\":\"tr\",\"vietnamees\":\"vi\",\"wels\":\"cy\",\"wit-russisch\":\"be\",\"zoeloe\":\"zu\",\"zweeds\":\"sv\",\"airmeinis\":\"hy\",\"albàinis\":\"sq\",\"amtharais\":\"am\",\"arabais\":\"ar\",\"asarbaideànais\":\"az\",\"basgais\":\"eu\",\"bealaruisis\":\"be\",\"beurla\":\"en\",\"bhiet-namais\":\"vi\",\"bulgarais\":\"bg\",\"cànan nan tàidh\":\"th\",\"catalanais\":\"ca\",\"coirèanais\":\"ko\",\"crìtheol haidhti\":\"ht\",\"cròthaisis\":\"hr\",\"cuimris\":\"cy\",\"cùrdais (kurmanji)\":\"ku\",\"duitsis\":\"nl\",\"eabhra\":\"he\",\"eadailtis\":\"it\",\"eastoinis\":\"et\",\"fionnlannais\":\"fi\",\"fraingis\":\"fr\",\"gàidhlig\":\"gd\",\"gailìsis\":\"gl\",\"gearmailtis\":\"de\",\"grèigis\":\"el\",\"hindis\":\"hi\",\"innd-innsis\":\"id\",\"innis-tìlis\":\"is\",\"laideann\":\"la\",\"laitbheis\":\"lv\",\"liotuainis\":\"lt\",\"malaidhis\":\"ms\",\"māori\":\"mi\",\"masadonais\":\"mk\",\"miànmar (burmais)\":\"my\",\"mongolais\":\"mn\",\"nirribhis\":\"nb\",\"pòlainnis\":\"pl\",\"portagailis\":\"pt\",\"romàinis\":\"ro\",\"ruisis\":\"ru\",\"seacais\":\"cs\",\"seapanais\":\"ja\",\"sèirbis\":\"sr\",\"sìonais (seann-nòsach)\":\"zh-tw\",\"sìonais (sìmplichte)\":\"zh-cn\",\"slòbhacais\":\"sk\",\"slòbhainis\":\"sl\",\"spàinntis\":\"es\",\"suainis\":\"sv\",\"turcais\":\"tr\",\"ucràinis\":\"uk\",\"ungairis\":\"hu\",\"usbagais\":\"uz\",\"farsi\":\"fa\",\"galisisk\":\"gl\",\"gresk\":\"el\",\"hviterussisk\":\"be\",\"kinesisk (tradisjonell)\":\"zh-tw\",\"kreol (haiti)\":\"ht\",\"latvisk\":\"lv\",\"malayisk\":\"ms\",\"nederlandsk\":\"nl\",\"rumensk\":\"ro\",\"tsjekkisk\":\"cs\",\"albanisch\":\"sq\",\"armenisch\":\"hy\",\"aserbaidschanisch\":\"az\",\"birmanisch\":\"my\",\"bulgarisch\":\"bg\",\"chinesisch (traditionell)\":\"zh-tw\",\"chinesisch (vereinfacht)\":\"zh-cn\",\"dänisch\":\"da\",\"deutsch\":\"de\",\"englisch\":\"en\",\"estnisch\":\"et\",\"finnisch\":\"fi\",\"französisch\":\"fr\",\"galizisch\":\"gl\",\"griechisch\":\"el\",\"haitianisch\":\"ht\",\"hebräisch\":\"he\",\"irisch\":\"ga\",\"isländisch\":\"is\",\"italienisch\":\"it\",\"japanisch\":\"ja\",\"katalanisch\":\"ca\",\"koreanisch\":\"ko\",\"kurdisch (kurmandschi)\":\"ku\",\"lateinisch\":\"la\",\"lettisch\":\"lv\",\"litauisch\":\"lt\",\"malaysisch\":\"ms\",\"maltesisch\":\"mt\",\"mazedonisch\":\"mk\",\"mongolisch\":\"mn\",\"niederländisch\":\"nl\",\"norwegisch\":\"nb\",\"persisch\":\"fa\",\"polnisch\":\"pl\",\"portugiesisch\":\"pt\",\"rumänisch\":\"ro\",\"schottisch-gälisch\":\"gd\",\"schwedisch\":\"sv\",\"serbisch\":\"sr\",\"slowakisch\":\"sk\",\"slowenisch\":\"sl\",\"spanisch\":\"es\",\"thailändisch\":\"th\",\"tschechisch\":\"cs\",\"türkisch\":\"tr\",\"ukrainisch\":\"uk\",\"ungarisch\":\"hu\",\"usbekisch\":\"uz\",\"vietnamesisch\":\"vi\",\"walisisch\":\"cy\",\"weißrussisch\":\"be\",\"ကနာဒါ\":\"kn\",\"ကာ့ဒ် (ကာမန်ဂျီ)\":\"ku\",\"ကိုရီးယား\":\"ko\",\"ကက်တလန်\":\"ca\",\"ခရိုအေးရှား\":\"hr\",\"ချက်\":\"cs\",\"ဂရိ\":\"el\",\"ဂယ်လိရှ\":\"gl\",\"ဂျပန်\":\"ja\",\"ဂျာမန်\":\"de\",\"စကော့ ဂေးလစ်\":\"gd\",\"စပိန်\":\"es\",\"ဆလိုဗေးနီးယား\":\"sl\",\"ဆလိုဗက်\":\"sk\",\"ဆားဘီးယား\":\"sr\",\"ဆွီဒင်\":\"sv\",\"ဇူးလူး\":\"zu\",\"တရုတ် (ရိုးရာ)\":\"zh-tw\",\"တရုတ် (အလွယ်)\":\"zh-cn\",\"တူ​ရ​ကီ\":\"tr\",\"တယ်လူဂူ\":\"te\",\"ထိုင်း\":\"th\",\"ဒတ်ချ်\":\"nl\",\"ဒိန်းမတ်\":\"da\",\"နော်ဝေ\":\"nb\",\"ပါရှန်\":\"fa\",\"ပေါ်တူဂီ\":\"pt\",\"ပိုလန်\":\"pl\",\"ပြင်သစ်\":\"fr\",\"ဖင်လန်\":\"fi\",\"ဗီယက်နမ်\":\"vi\",\"ဘာ့စ်\":\"eu\",\"ဘူဂေးရီးယား\":\"bg\",\"ဘယ်လာရုစ်\":\"be\",\"မလေယာလမ်\":\"ml\",\"မလေး\":\"ms\",\"မာရာသီ\":\"mr\",\"မော်ရီ\":\"mi\",\"မော်လတာ\":\"mt\",\"မက်ဆီဒိုးနီးယား\":\"mk\",\"မြန်မာ (မြန်မာ)\":\"my\",\"မွန်ဂိုလီးယား\":\"mn\",\"ယူ​က​ရိန်း​\":\"uk\",\"ရုရှား\":\"ru\",\"ရိုမေးနီးယား\":\"ro\",\"လက်တင်\":\"la\",\"လစ်သူယေးနီးယား\":\"lt\",\"လတ်ဗီယာ\":\"lv\",\"ဝေလ\":\"cy\",\"ဟီဘရူး\":\"he\",\"ဟေတီ ခရီအိုး\":\"ht\",\"ဟင်ဒီ\":\"hi\",\"ဟန်ဂေရီ\":\"hu\",\"အဇာဘိုင်ဂျန်\":\"az\",\"အာမေးနီးယား\":\"hy\",\"အာရေဗျ\":\"ar\",\"အီတလီ\":\"it\",\"ဥဇဘက်\":\"uz\",\"အက်စတိုးနီးယား\":\"et\",\"အက်စ်ပဲရန်တို\":\"eo\",\"အိုက်စလန်\":\"is\",\"အင်္ဂလိပ်\":\"en\",\"အင်ဒိုနီးရှား\":\"id\",\"အိုင်းရစ်ရှ်\":\"ga\",\"အမ်ဟဲရစ်ခ်\":\"am\",\"အယ်လ်ဘေးနီးယား\":\"sq\",\"אוזבקית\":\"uz\",\"אוקראינית\":\"uk\",\"אזרית\":\"az\",\"איטלקית\":\"it\",\"אינדונזית\":\"id\",\"איסלנדית\":\"is\",\"אירית\":\"ga\",\"אלבנית\":\"sq\",\"אמהרית\":\"am\",\"אנגלית\":\"en\",\"אסטונית\":\"et\",\"אספרנטו\":\"eo\",\"ארמנית\":\"hy\",\"באסקית\":\"eu\",\"בולגרית\":\"bg\",\"בורמזית\":\"my\",\"בלארוסית\":\"be\",\"גליציאנית\":\"gl\",\"גרמנית\":\"de\",\"דנית\":\"da\",\"הולנדית\":\"nl\",\"הונגרית\":\"hu\",\"הינדי\":\"hi\",\"וולשית\":\"cy\",\"וייטנאמית\":\"vi\",\"זולו\":\"zu\",\"טורקית\":\"tr\",\"טלוגו\":\"te\",\"יוונית\":\"el\",\"יפנית\":\"ja\",\"כורדית\":\"ku\",\"לטווית\":\"lv\",\"לטינית\":\"la\",\"ליטאית\":\"lt\",\"מאורית\":\"mi\",\"מאלאיאלם\":\"ml\",\"מאלזית\":\"ms\",\"מאראתי\":\"mr\",\"מונגולית\":\"mn\",\"מלטית\":\"mt\",\"מקדונית\":\"mk\",\"נורווגית\":\"nb\",\"סינית (מסורתית)\":\"zh-tw\",\"סינית (פשוטה)\":\"zh-cn\",\"סלובנית\":\"sl\",\"סלובקית\":\"sk\",\"ספרדית\":\"es\",\"סקוטית גאלית\":\"gd\",\"סרבית\":\"sr\",\"עברית\":\"he\",\"ערבית\":\"ar\",\"פולנית\":\"pl\",\"פורטוגזית\":\"pt\",\"פינית\":\"fi\",\"פרסית\":\"fa\",\"צ'כית\":\"cs\",\"צרפתית\":\"fr\",\"קאנאדה\":\"kn\",\"קוריאנית\":\"ko\",\"קטלאנית\":\"ca\",\"קרואטית\":\"hr\",\"קריאולית האיטית\":\"ht\",\"רומנית\":\"ro\",\"רוסית\":\"ru\",\"שוודית\":\"sv\",\"תאילנדית\":\"th\",\"азербејџански\":\"az\",\"албански\":\"sq\",\"амхарски\":\"am\",\"англиски\":\"en\",\"арапски\":\"ar\",\"баскиски\":\"eu\",\"белоруски\":\"be\",\"бугарски\":\"bg\",\"бурмански\":\"my\",\"велшки\":\"cy\",\"виетнамски\":\"vi\",\"галициски\":\"gl\",\"германски\":\"de\",\"грчки\":\"el\",\"дански\":\"da\",\"ерменски\":\"hy\",\"естонски\":\"et\",\"индонезиски\":\"id\",\"ирски\":\"ga\",\"исландски\":\"is\",\"италијански\":\"it\",\"јапонски\":\"ja\",\"канада\":\"kn\",\"каталонски\":\"ca\",\"кинески (поедноставен)\":\"zh-cn\",\"кинески (традиционален)\":\"zh-tw\",\"корејски\":\"ko\",\"курдски\":\"ku\",\"латвиски\":\"lv\",\"латински\":\"la\",\"литвански\":\"lt\",\"македонски\":\"mk\",\"малајалам\":\"ml\",\"малајски\":\"ms\",\"малтешки\":\"mt\",\"маорски\":\"mi\",\"маратхи\":\"mr\",\"монголски\":\"mn\",\"норвешки\":\"nb\",\"персиски\":\"fa\",\"полски\":\"pl\",\"португалски\":\"pt\",\"романски\":\"ro\",\"руски\":\"ru\",\"словачки\":\"sk\",\"словенечки\":\"sl\",\"српски\":\"sr\",\"тајландски\":\"th\",\"телугу\":\"te\",\"турски\":\"tr\",\"узбечки\":\"uz\",\"украински\":\"uk\",\"унгарски\":\"hu\",\"фински\":\"fi\",\"француски\":\"fr\",\"хаитски креолски\":\"ht\",\"хебрејски\":\"he\",\"хиндиски\":\"hi\",\"холандски\":\"nl\",\"хрватски\":\"hr\",\"чешки\":\"cs\",\"шведски\":\"sv\",\"шкотски галски\":\"gd\",\"шпански\":\"es\",\"ಅಜರ್ಬೈಜಾನಿ\":\"az\",\"ಅಮಹಾರಿಕ್\":\"am\",\"ಅರಬ್ಬಿ\":\"ar\",\"ಆರ್ಮೇನಿಯನ್\":\"hy\",\"ಆಲ್ಬೇನಿಯನ್\":\"sq\",\"ಇಂಗ್ಲಿಷ್‌‌\":\"en\",\"ಇಂಡೋನೇಷಿಯನ್\":\"id\",\"ಇಟಾಲಿಯನ್\":\"it\",\"ಉಜ್ಬೆಕ್\":\"uz\",\"ಎಸ್ಟೋನಿಯನ್\":\"et\",\"ಎಸ್ಪೆರಾಂಟೋ\":\"eo\",\"ಐರಿಷ್\":\"ga\",\"ಐಸ್‌ಲ್ಯಾಂಡಿಕ್‌\":\"is\",\"ಕನ್ನಡ\":\"kn\",\"ಕುರ್ದಿಶ್\":\"ku\",\"ಕೊರಿಯನ್\":\"ko\",\"ಕ್ಯಾಟಲನ್\":\"ca\",\"ಕ್ರೊಯೇಷಿಯನ್\":\"hr\",\"ಗ್ಯಾಲೀಷಿಯನ್\":\"gl\",\"ಗ್ರೀಕ್\":\"el\",\"ಚೀನಿ (ಸರಳೀಕೃತ)\":\"zh-cn\",\"ಚೀನಿ (ಸಾಂಪ್ರದಾಯಿಕ)\":\"zh-tw\",\"ಜಪಾನಿ\":\"ja\",\"ಜರ್ಮನ್\":\"de\",\"ಜುಲು\":\"zu\",\"ಝೆಕ್‌\":\"cs\",\"ಟರ್ಕಿಷ್\":\"tr\",\"ಡಚ್\":\"nl\",\"ಡ್ಯಾನಿಷ್\":\"da\",\"ತೆಲುಗು\":\"te\",\"ಥಾಯ್\":\"th\",\"ನಾರ್ವೇಜಿಯನ್‌\":\"nb\",\"ಪೋರ್ಚುಗೀಸ್\":\"pt\",\"ಪೋಲಿಷ್\":\"pl\",\"ಫಾರ್ಸಿ\":\"fa\",\"ಫಿನ್ನಿಷ್\":\"fi\",\"ಫ್ರೆಂಚ್\":\"fr\",\"ಬರ್ಮೀಸ್\":\"my\",\"ಬಲ್ಗೇರಿಯನ್\":\"bg\",\"ಬಾಸ್ಕ್\":\"eu\",\"ಬೆಲರೂಸಿಯನ್\":\"be\",\"ಮಂಗೋಲಿಯನ್\":\"mn\",\"ಮರಾಠಿ\":\"mr\",\"ಮಲಯ\":\"ms\",\"ಮಲಯಾಳಂ\":\"ml\",\"ಮಾಲ್ಟೀಸ್\":\"mt\",\"ಮಾವೋರಿ\":\"mi\",\"ಮ್ಯಾಸೆಡೋನಿಯನ್\":\"mk\",\"ಯುಕ್ರೇನಿಯನ್\":\"uk\",\"ರಷಿಯನ್\":\"ru\",\"ರೊಮೇನಿಯನ್\":\"ro\",\"ಲಿಥುವೇನಿಯನ್\":\"lt\",\"ಲ್ಯಾಟಿನ್\":\"la\",\"ಲ್ಯಾಟ್ವಿಯನ್‌\":\"lv\",\"ವಿಯೆಟ್ನಾಮಿ\":\"vi\",\"ವೆಲ್ಶ್\":\"cy\",\"ಸರ್ಬಿಯನ್\":\"sr\",\"ಸ್ಕಾಟ್ಸ್ ಗ್ಯಾಲಿಕ್\":\"gd\",\"ಸ್ಪ್ಯಾನಿಷ್\":\"es\",\"ಸ್ಲೊವಾಕ್\":\"sk\",\"ಸ್ಲೊವೆನಿಯನ್\":\"sl\",\"ಸ್ವೀಡಿಷ್\":\"sv\",\"ಹಂಗೇರಿಯನ್\":\"hu\",\"ಹಯಥಿಯನ್‌ ಕ್ರಿಯೋಲ್‌\":\"ht\",\"ಹಿಂದಿ\":\"hi\",\"ಹೀಬ್ರೂ\":\"he\",\"അമാറിക്\":\"am\",\"അർമേനിയൻ\":\"hy\",\"അൽബേനിയൻ\":\"sq\",\"അസർബൈജാനി\":\"az\",\"അറബിക്\":\"ar\",\"ഇന്തോനേഷ്യൻ\":\"id\",\"ഇംഗ്ലീഷ്\":\"en\",\"ഇറ്റാലിയൻ\":\"it\",\"ഉക്രേനിയൻ\":\"uk\",\"ഉസ്ബെക്ക്\":\"uz\",\"എസ്‌പെരന്തോ\":\"eo\",\"എസ്റ്റോണിയൻ\":\"et\",\"ഐസ്‌ലാൻഡിക്\":\"is\",\"ഐറിഷ്\":\"ga\",\"കന്നട\":\"kn\",\"കാറ്റലൻ\":\"ca\",\"കുർദ്ദിഷ്\":\"ku\",\"കൊറിയൻ\":\"ko\",\"ക്രൊയേഷ്യൻ\":\"hr\",\"ഗലീഷ്യൻ\":\"gl\",\"ഗ്രീക്ക്\":\"el\",\"ചെക്ക്\":\"cs\",\"ചൈനീസ് (പരമ്പരാഗതം)\":\"zh-tw\",\"ചൈനീസ് (ലഘൂകരിച്ചത്)\":\"zh-cn\",\"ജർമ്മൻ\":\"de\",\"ജാപ്പനീസ്‌\":\"ja\",\"ടർക്കിഷ്\":\"tr\",\"ഡച്ച്\":\"nl\",\"ഡാനിഷ്\":\"da\",\"തായ്\":\"th\",\"തെലുങ്ക്\":\"te\",\"നോർവീജിയൻ\":\"nb\",\"പേർഷ്യൻ\":\"fa\",\"പോർച്ചുഗീസ്\":\"pt\",\"പോളിഷ്\":\"pl\",\"ഫിന്നിഷ്\":\"fi\",\"ഫ്രെഞ്ച്\":\"fr\",\"ബർമീസ്\":\"my\",\"ബൾഗേറിയൻ\":\"bg\",\"ബാസ്ക്\":\"eu\",\"ബെലാറുഷ്യൻ\":\"be\",\"മംഗോളിയൻ\":\"mn\",\"മലയാളം\":\"ml\",\"മലയ്\":\"ms\",\"മറാഠി\":\"mr\",\"മാസഡോണിയൻ\":\"mk\",\"മാൾട്ടീസ്\":\"mt\",\"മൗറി\":\"mi\",\"ലാറ്റിൻ\":\"la\",\"ലാറ്റ്‌വിയൻ\":\"lv\",\"ലിത്വേനിയൻ\":\"lt\",\"വിയറ്റ്നാമീസ്\":\"vi\",\"വെൽഷ്\":\"cy\",\"സുളു\":\"zu\",\"സെർബിയൻ\":\"sr\",\"സ്കോട്ട്സ് ഗ്യാലിക്\":\"gd\",\"സ്പാനിഷ്\":\"es\",\"സ്ലോവാക്\":\"sk\",\"സ്ലോവേനിയൻ\":\"sl\",\"സ്വീഡിഷ്\":\"sv\",\"ഹംഗേറിയൻ\":\"hu\",\"ഹിന്ദി\":\"hi\",\"ഹീബ്രു\":\"he\",\"ഹെയ്തിയൻ ക്രയോൾ\":\"ht\",\"റഷ്യൻ\":\"ru\",\"റൊമേനിയൻ\":\"ro\",\"albánčina\":\"sq\",\"amharčina\":\"am\",\"arabčina\":\"ar\",\"arménčina\":\"hy\",\"azerbajdžančina\":\"az\",\"barmčina\":\"my\",\"bieloruština\":\"be\",\"bulharčina\":\"bg\",\"čínština (tradičná)\":\"zh-tw\",\"dánčina\":\"da\",\"estónčina\":\"et\",\"fínčina\":\"fi\",\"francúzština\":\"fr\",\"galícijčina\":\"gl\",\"gréčtina\":\"el\",\"haitská kreolčina\":\"ht\",\"hebrejčina\":\"he\",\"hindčina\":\"hi\",\"holandčina\":\"nl\",\"chorvátčina\":\"hr\",\"indonézština\":\"id\",\"írčina\":\"ga\",\"islandčina\":\"is\",\"japončina\":\"ja\",\"kannadčina\":\"kn\",\"katalánčina\":\"ca\",\"kórejčina\":\"ko\",\"kurdčina\":\"ku\",\"latinčina\":\"la\",\"litovčina\":\"lt\",\"macedónčina\":\"mk\",\"maďarčina\":\"hu\",\"malajámčina\":\"ml\",\"malajčina\":\"ms\",\"maltčina\":\"mt\",\"maorijčina\":\"mi\",\"maratčina\":\"mr\",\"mongolčina\":\"mn\",\"nemčina\":\"de\",\"nórčina\":\"nb\",\"perzština\":\"fa\",\"poľština\":\"pl\",\"portugalčina\":\"pt\",\"rumunčina\":\"ro\",\"slovenčina\":\"sk\",\"slovinčina\":\"sl\",\"srbčina\":\"sr\",\"škótska gaelčina\":\"gd\",\"španielčina\":\"es\",\"švédčina\":\"sv\",\"taliančina\":\"it\",\"telugčina\":\"te\",\"thajčina\":\"th\",\"ukrajinčina\":\"uk\",\"vietnamčina\":\"vi\",\"waleština\":\"cy\",\"zuluština\":\"zu\",\"isi-albania\":\"sq\",\"isi-amharic\":\"am\",\"isi-arabic\":\"ar\",\"isi-armenian\":\"hy\",\"isi-azerbaijani\":\"az\",\"isi-basque\":\"eu\",\"isi-belarusian\":\"be\",\"isi-bulgarian\":\"bg\",\"isi-burmese\":\"my\",\"isi-catalan\":\"ca\",\"isi-chinese (simplified)\":\"zh-cn\",\"isi-chinese (traditional)\":\"zh-tw\",\"isi-croatian\":\"hr\",\"isi-czech\":\"cs\",\"isi-danish\":\"da\",\"isi-dutch\":\"nl\",\"isi-english\":\"en\",\"isi-esperanto\":\"eo\",\"isi-estonian\":\"et\",\"isi-finnish\":\"fi\",\"isi-french\":\"fr\",\"isi-galician\":\"gl\",\"isi-german\":\"de\",\"isi-greek\":\"el\",\"isi-haitian creole\":\"ht\",\"isi-hangarian\":\"hu\",\"isi-hebrew\":\"he\",\"isi-hindi\":\"hi\",\"isi-icelandic\":\"is\",\"isi-indonesian\":\"id\",\"isi-irish\":\"ga\",\"isi-italian\":\"it\",\"isi-japanese\":\"ja\",\"isi-kannada\":\"kn\",\"isi-korean\":\"ko\",\"isi-kurdish\":\"ku\",\"isi-latin\":\"la\",\"isi-latvian\":\"lv\",\"isi-lithuanian\":\"lt\",\"isi-macedonian\":\"mk\",\"isi-malay\":\"ms\",\"isi-malayalam\":\"ml\",\"isi-maltese\":\"mt\",\"isi-maori\":\"mi\",\"isi-marathi\":\"mr\",\"isi-mongolian\":\"mn\",\"isi-norwegian\":\"nb\",\"isi-persian\":\"fa\",\"isi-polish\":\"pl\",\"isi-portuguese\":\"pt\",\"isi-romanian\":\"ro\",\"isi-russian\":\"ru\",\"isi-scots gaelic\":\"gd\",\"isi-serbian\":\"sr\",\"isi-slovak\":\"sk\",\"isi-slovenian\":\"sl\",\"isi-spanish\":\"es\",\"isi-swedish\":\"sv\",\"isi-telugu\":\"te\",\"isi-thai\":\"th\",\"isi-turkish\":\"tr\",\"isi-ukrainian\":\"uk\",\"isi-uzbek\":\"uz\",\"isi-vietnamese\":\"vi\",\"isi-welsh\":\"cy\",\"isizulu\":\"zu\",\"albania\":\"sq\",\"armenia\":\"hy\",\"azerbaijan\":\"az\",\"belanda\":\"nl\",\"belarus\":\"be\",\"bulgaria\":\"bg\",\"cina (mudah)\":\"zh-cn\",\"cina (tradisional)\":\"zh-tw\",\"croatia\":\"hr\",\"denmark\":\"da\",\"estonia\":\"et\",\"finland\":\"fi\",\"gaelic scotland\":\"gd\",\"galicia\":\"gl\",\"hungary\":\"hu\",\"ibrani\":\"he\",\"iceland\":\"is\",\"indonesia\":\"id\",\"inggeris\":\"en\",\"ireland\":\"ga\",\"itali\":\"it\",\"jepun\":\"ja\",\"jerman\":\"de\",\"korea\":\"ko\",\"kreol haiti\":\"ht\",\"kurdistan\":\"ku\",\"latvia\":\"lv\",\"lithuania\":\"lt\",\"macedonia\":\"mk\",\"malta\":\"mt\",\"melayu\":\"ms\",\"mongolia\":\"mn\",\"myanmar\":\"my\",\"norway\":\"nb\",\"parsi\":\"fa\",\"perancis\":\"fr\",\"poland\":\"pl\",\"portugis\":\"pt\",\"romania\":\"ro\",\"rusia\":\"ru\",\"sepanyol\":\"es\",\"serbia\":\"sr\",\"slovenia\":\"sl\",\"sweden\":\"sv\",\"turki\":\"tr\",\"ukraine\":\"uk\",\"vietnam\":\"vi\",\"wales\":\"cy\",\"азербайджанский\":\"az\",\"албанский\":\"sq\",\"амхарский\":\"am\",\"английский\":\"en\",\"арабский\":\"ar\",\"армянский\":\"hy\",\"баскский\":\"eu\",\"белорусский\":\"be\",\"бирманский\":\"my\",\"болгарский\":\"bg\",\"валлийский\":\"cy\",\"венгерский\":\"hu\",\"вьетнамский\":\"vi\",\"галисийский\":\"gl\",\"греческий\":\"el\",\"датский\":\"da\",\"иврит\":\"he\",\"индонезийский\":\"id\",\"ирландский\":\"ga\",\"исландский\":\"is\",\"испанский\":\"es\",\"итальянский\":\"it\",\"каталанский\":\"ca\",\"китайский (традиционный)\":\"zh-tw\",\"китайский (упрощенный)\":\"zh-cn\",\"корейский\":\"ko\",\"креольский (гаити)\":\"ht\",\"курманджи\":\"ku\",\"латинский\":\"la\",\"латышский\":\"lv\",\"литовский\":\"lt\",\"македонский\":\"mk\",\"малайский\":\"ms\",\"мальтийский\":\"mt\",\"маори\":\"mi\",\"монгольский\":\"mn\",\"немецкий\":\"de\",\"нидерландский\":\"nl\",\"норвежский\":\"nb\",\"персидский\":\"fa\",\"польский\":\"pl\",\"португальский\":\"pt\",\"румынский\":\"ro\",\"русский\":\"ru\",\"сербский\":\"sr\",\"словацкий\":\"sk\",\"словенский\":\"sl\",\"тайский\":\"th\",\"турецкий\":\"tr\",\"узбекский\":\"uz\",\"украинский\":\"uk\",\"финский\":\"fi\",\"французский\":\"fr\",\"хинди\":\"hi\",\"хорватский\":\"hr\",\"чешский\":\"cs\",\"шведский\":\"sv\",\"шотландский (гэльский)\":\"gd\",\"эсперанто\":\"eo\",\"эстонский\":\"et\",\"японский\":\"ja\",\"albański\":\"sq\",\"amharski\":\"am\",\"angielski\":\"en\",\"arabski\":\"ar\",\"azerski\":\"az\",\"baskijski\":\"eu\",\"białoruski\":\"be\",\"birmański\":\"my\",\"bułgarski\":\"bg\",\"chiński (tradycyjny)\":\"zh-tw\",\"chiński (uproszczony)\":\"zh-cn\",\"chorwacki\":\"hr\",\"czeski\":\"cs\",\"duński\":\"da\",\"estoński\":\"et\",\"fiński\":\"fi\",\"francuski\":\"fr\",\"galicyjski\":\"gl\",\"grecki\":\"el\",\"hebrajski\":\"he\",\"hiszpański\":\"es\",\"indonezyjski\":\"id\",\"irlandzki\":\"ga\",\"islandzki\":\"is\",\"japoński\":\"ja\",\"kataloński\":\"ca\",\"koreański\":\"ko\",\"kreolski (haiti)\":\"ht\",\"kurdyjski\":\"ku\",\"litewski\":\"lt\",\"łaciński\":\"la\",\"łotewski\":\"lv\",\"macedoński\":\"mk\",\"malajalam\":\"ml\",\"malajski\":\"ms\",\"maltański\":\"mt\",\"mongolski\":\"mn\",\"niderlandzki\":\"nl\",\"niemiecki\":\"de\",\"norweski\":\"nb\",\"ormiański\":\"hy\",\"perski\":\"fa\",\"polski\":\"pl\",\"portugalski\":\"pt\",\"rosyjski\":\"ru\",\"rumuński\":\"ro\",\"serbski\":\"sr\",\"słowacki\":\"sk\",\"słoweński\":\"sl\",\"szkocki gaelicki\":\"gd\",\"szwedzki\":\"sv\",\"tajski\":\"th\",\"turecki\":\"tr\",\"ukraiński\":\"uk\",\"uzbecki\":\"uz\",\"walijski\":\"cy\",\"węgierski\":\"hu\",\"wietnamski\":\"vi\",\"włoski\":\"it\",\"азербайджанская\":\"az\",\"албанская\":\"sq\",\"амхарская\":\"am\",\"англійская\":\"en\",\"арабская\":\"ar\",\"армянская\":\"hy\",\"балгарская\":\"bg\",\"баскская\":\"eu\",\"беларуская\":\"be\",\"в'етнамская\":\"vi\",\"валійская\":\"cy\",\"венгерская\":\"hu\",\"гаіцянская крэольская\":\"ht\",\"галандская\":\"nl\",\"галісійская\":\"gl\",\"грэчаская\":\"el\",\"дацкая\":\"da\",\"інданезійская\":\"id\",\"ірландская\":\"ga\",\"ісландская\":\"is\",\"іспанская\":\"es\",\"італьянская\":\"it\",\"іўрыт\":\"he\",\"карэйская\":\"ko\",\"каталонская\":\"ca\",\"кітайская (спрошчаная)\":\"zh-cn\",\"кітайская (традыцыйная)\":\"zh-tw\",\"курдская (курманджы)\":\"ku\",\"латышская\":\"lv\",\"лацінская\":\"la\",\"літоўская\":\"lt\",\"м'янманская (бірманская)\":\"my\",\"маары\":\"mi\",\"македонская\":\"mk\",\"малайская\":\"ms\",\"мальтыйская\":\"mt\",\"мангольская\":\"mn\",\"нарвежская\":\"nb\",\"нямецкая\":\"de\",\"партугальская\":\"pt\",\"персідская\":\"fa\",\"польская\":\"pl\",\"румынская\":\"ro\",\"руская\":\"ru\",\"сербская\":\"sr\",\"славацкая\":\"sk\",\"славенская\":\"sl\",\"тайская\":\"th\",\"турэцкая\":\"tr\",\"тэлугу\":\"te\",\"узбекская\":\"uz\",\"украінская\":\"uk\",\"фінская\":\"fi\",\"французская\":\"fr\",\"харвацкая\":\"hr\",\"хіндзі\":\"hi\",\"чэшская\":\"cs\",\"шатландская гэльская\":\"gd\",\"шведская\":\"sv\",\"эсперанта\":\"eo\",\"эстонская\":\"et\",\"японская\":\"ja\",\"amarikisht\":\"am\",\"anglisht\":\"en\",\"arabisht\":\"ar\",\"armenisht\":\"hy\",\"azerisht\":\"az\",\"baskisht\":\"eu\",\"birmanisht\":\"my\",\"bjellorusisht\":\"be\",\"bullgarisht\":\"bg\",\"çekisht\":\"cs\",\"danisht\":\"da\",\"estonisht\":\"et\",\"finlandisht\":\"fi\",\"frëngjisht\":\"fr\",\"galicianisht\":\"gl\",\"galishte skoceze\":\"gd\",\"greqisht\":\"el\",\"gjermanisht\":\"de\",\"hebraisht\":\"he\",\"hindisht\":\"hi\",\"holandisht\":\"nl\",\"hungarisht\":\"hu\",\"indonezisht\":\"id\",\"irlandisht\":\"ga\",\"islandisht\":\"is\",\"italisht\":\"it\",\"japonisht\":\"ja\",\"kanada\":\"kn\",\"katalonisht\":\"ca\",\"kinezisht (e thjeshtuar)\":\"zh-cn\",\"kinezisht (tradicionale)\":\"zh-tw\",\"koreanisht\":\"ko\",\"kreolishte haitiane\":\"ht\",\"kroatisht\":\"hr\",\"latinisht\":\"la\",\"letonisht\":\"lv\",\"lituanisht\":\"lt\",\"malajalamisht\":\"ml\",\"malajzisht\":\"ms\",\"malteze\":\"mt\",\"maorisht\":\"mi\",\"maqedonisht\":\"mk\",\"maratisht\":\"mr\",\"mongolisht\":\"mn\",\"norvegjisht\":\"nb\",\"persisht\":\"fa\",\"polonisht\":\"pl\",\"portugalisht\":\"pt\",\"rumanisht\":\"ro\",\"rusisht\":\"ru\",\"serbisht\":\"sr\",\"sllovakisht\":\"sk\",\"sllovenisht\":\"sl\",\"spanjisht\":\"es\",\"suedisht\":\"sv\",\"shqip\":\"sq\",\"tajlandisht\":\"th\",\"telugisht\":\"te\",\"turqisht\":\"tr\",\"uellsisht\":\"cy\",\"ukrainisht\":\"uk\",\"uzbekisht\":\"uz\",\"vietnamisht\":\"vi\",\"ሀንጋሪኛ\":\"hu\",\"ህንድኛ\":\"hi\",\"ሊትዌንኛ\":\"lt\",\"ላቲንኛ\":\"la\",\"ላትቪያኛ\":\"lv\",\"ማላያላምኛ\":\"ml\",\"ማላይኛ\":\"ms\",\"ማልቲስኛ\":\"mt\",\"ማራቲኛ\":\"mr\",\"ማዮሪኛ\":\"mi\",\"ሜቄዶኒያኛ\":\"mk\",\"ሞንጎሊያኛ\":\"mn\",\"ራሽያኛ\":\"ru\",\"ሮማኒያንኛ\":\"ro\",\"ሰርቢያኛ\":\"sr\",\"ስሎቫክኛ\":\"sk\",\"ስሎቬንያኛ\":\"sl\",\"ስዊድንኛ\":\"sv\",\"ስፓኒሽኛ\":\"es\",\"በርማኛ\":\"my\",\"ቡልጋሪያኛ\":\"bg\",\"ባስክኛ\":\"eu\",\"ቤላሩስኛ\":\"be\",\"ቪትናምኛ\":\"vi\",\"ቱርክኛ\":\"tr\",\"ታይኛ\":\"th\",\"ቴሉጉኛ\":\"te\",\"ቻይንኛ (ቀላሉ)\":\"zh-cn\",\"ቻይንኛ (ባሕላዊው)\":\"zh-tw\",\"ቼክኛ\":\"cs\",\"ኖርዌጅያንኛ\":\"nb\",\"አልባንያኛ\":\"sq\",\"አማርኛ\":\"am\",\"አርመኒያኛ\":\"hy\",\"አዜርባይጃንኛ\":\"az\",\"አይሪሽ\":\"ga\",\"አይስላንድኛ\":\"is\",\"ኡዝቤክኛ\":\"uz\",\"ኤስቶኒያኛ\":\"et\",\"ኤስፐራንቶ\":\"eo\",\"እንዶኔዢያኛ\":\"id\",\"እንግሊዝኛ\":\"en\",\"ኩርድሽኛ\":\"ku\",\"ካታላንኛ\":\"ca\",\"ካናዳኛ\":\"kn\",\"ክሮኤሽያኛ\":\"hr\",\"ኮሪያኛ\":\"ko\",\"ዌልሽ\":\"cy\",\"ዐረብኛ\":\"ar\",\"ዕብራይስጥ\":\"he\",\"ዙሉኛ\":\"zu\",\"የሃይቲ ክረኦሌኛ\":\"ht\",\"የስኮት ጌልክኛ\":\"gd\",\"ዩክሬንኛ\":\"uk\",\"ደችኛ\":\"nl\",\"ዴንሽኛ\":\"da\",\"ጀርመንኛ\":\"de\",\"ጃፓንኛ\":\"ja\",\"ጋሊሺያኛ\":\"gl\",\"ግሪክኛ\":\"el\",\"ጣሊያንኛ\":\"it\",\"ፈረንሳይኛ\":\"fr\",\"ፊኒሽኛ\":\"fi\",\"ፐርሺያኛ\":\"fa\",\"ፖሊሽኛ\":\"pl\",\"ፖርቱጋሊኛ\":\"pt\",\"alban\":\"sq\",\"alman\":\"de\",\"amarikcə\":\"am\",\"azərbaycan dili\":\"az\",\"bask\":\"eu\",\"belarusca\":\"be\",\"bolqar\":\"bg\",\"çex\":\"cs\",\"çin (ən'ənəvi)\":\"zh-tw\",\"çin (sadələşdirilmiş)\":\"zh-cn\",\"danimarka\":\"da\",\"erməni\":\"hy\",\"eston\":\"et\",\"ərəb\":\"ar\",\"fars dili\":\"fa\",\"fin\":\"fi\",\"fransız\":\"fr\",\"haiti kreol dili\":\"ht\",\"hind\":\"hi\",\"xorvat\":\"hr\",\"ispan\":\"es\",\"i̇ndoneziya\":\"id\",\"i̇ngilis\":\"en\",\"i̇rland\":\"ga\",\"i̇sland\":\"is\",\"i̇sveç\":\"sv\",\"i̇talyan\":\"it\",\"i̇vrit\":\"he\",\"katalan\":\"ca\",\"koreya\":\"ko\",\"kürd dili (kurmanci)\":\"ku\",\"qalisian\":\"gl\",\"latın\":\"la\",\"latış\":\"lv\",\"litva\":\"lt\",\"macar\":\"hu\",\"makedoniya\":\"mk\",\"maoricə\":\"mi\",\"monqolca\":\"mn\",\"myanma (birma) dili\":\"my\",\"norveç\":\"nb\",\"özbək\":\"uz\",\"polyak\":\"pl\",\"portuqal\":\"pt\",\"rumın\":\"ro\",\"rus\":\"ru\",\"serb\":\"sr\",\"sloven\":\"sl\",\"şotland (kelt)\":\"gd\",\"tayca\":\"th\",\"teluqu\":\"te\",\"türk\":\"tr\",\"uels\":\"cy\",\"ukrayna\":\"uk\",\"vyetnam\":\"vi\",\"yapon\":\"ja\",\"yunan\":\"el\",\"zulu dili\":\"zu\",\"albaniż\":\"sq\",\"amħari\":\"am\",\"armen\":\"hy\",\"ażerbajġani\":\"az\",\"belarussu\":\"be\",\"bulgaru\":\"bg\",\"ċek\":\"cs\",\"ċiniż (semplifikat)\":\"zh-cn\",\"ċiniż (tradizzjonali)\":\"zh-tw\",\"creole haiti\":\"ht\",\"daniż\":\"da\",\"ebrajk\":\"he\",\"estonjan\":\"et\",\"finlandiż\":\"fi\",\"franċiż\":\"fr\",\"ġappuniż\":\"ja\",\"ġermaniż\":\"de\",\"gaelic tal-iskoċċiżi\":\"gd\",\"galizjan\":\"gl\",\"grieg\":\"el\",\"għarbi\":\"ar\",\"ħindi\":\"hi\",\"indoneżjan\":\"id\",\"ingliż\":\"en\",\"irlandiż\":\"ga\",\"islandiż\":\"is\",\"kroat\":\"hr\",\"kurd (kurmanji)\":\"ku\",\"latvjan\":\"lv\",\"litwen\":\"lt\",\"maċedonjan\":\"mk\",\"malasjan\":\"ms\",\"malti\":\"mt\",\"marati\":\"mr\",\"mjanmar (burma)\":\"my\",\"mongoljan\":\"mn\",\"norveġiż\":\"nb\",\"olandiż\":\"nl\",\"persjan\":\"fa\",\"pollakk\":\"pl\",\"portugiż\":\"pt\",\"rumen\":\"ro\",\"russu\":\"ru\",\"slovakk\":\"sk\",\"spanjol\":\"es\",\"svediż\":\"sv\",\"tajlandiż\":\"th\",\"taljan\":\"it\",\"tork\":\"tr\",\"ukren\":\"uk\",\"ungeriż\":\"hu\",\"użbek\":\"uz\",\"vjetnamiż\":\"vi\",\"żulu\":\"zu\",\"albanski\":\"sq\",\"amharik\":\"am\",\"arapski\":\"ar\",\"armenijski\":\"hy\",\"azerbajdžanski\":\"az\",\"bjeloruski\":\"be\",\"bugarski\":\"bg\",\"burmanski\":\"my\",\"češki\":\"cs\",\"danski\":\"da\",\"engleski\":\"en\",\"estonski\":\"et\",\"finski\":\"fi\",\"galski\":\"gl\",\"grčki\":\"el\",\"haićansko-kreolski\":\"ht\",\"hebrejski\":\"he\",\"hindu\":\"hi\",\"hrvatski\":\"hr\",\"indonezijski\":\"id\",\"irski\":\"ga\",\"islandski\":\"is\",\"japanski\":\"ja\",\"katalonski\":\"ca\",\"kineski (pojednost.)\":\"zh-cn\",\"kineski (tradicionalni)\":\"zh-tw\",\"korejski\":\"ko\",\"kurdski\":\"ku\",\"latinski\":\"la\",\"latvijski/letonski\":\"lv\",\"litvanski\":\"lt\",\"mađarski\":\"hu\",\"makedonski\":\"mk\",\"malezijski\":\"ms\",\"malteški\":\"mt\",\"nizozemski\":\"nl\",\"norveški\":\"nb\",\"njemački\":\"de\",\"perzijski\":\"fa\",\"poljski\":\"pl\",\"rumunjski\":\"ro\",\"ruski\":\"ru\",\"slovački\":\"sk\",\"slovenski\":\"sl\",\"srpski\":\"sr\",\"škotski keltski\":\"gd\",\"španjolski\":\"es\",\"švedski\":\"sv\",\"tajlandski\":\"th\",\"talijanski\":\"it\",\"turski\":\"tr\",\"ukrajinski\":\"uk\",\"uzbekistanski\":\"uz\",\"velški\":\"cy\",\"vijetnamski\":\"vi\",\"آذرباﻳﺠﺎﻧﻰ\":\"az\",\"آلبانیایی\":\"sq\",\"آلمانی\":\"de\",\"ارمنی\":\"hy\",\"ازبکی\":\"uz\",\"اسپانیایی\":\"es\",\"اسپرانتو\":\"eo\",\"استونيايی\":\"et\",\"اسلواکی\":\"sk\",\"اسلونیایی\":\"sl\",\"اکراينی\":\"uk\",\"امهری\":\"am\",\"اندونزيايی\":\"id\",\"انگلیسی\":\"en\",\"ایتالیایی\":\"it\",\"ایرلندی\":\"ga\",\"ايسلندی\":\"is\",\"باسکی\":\"eu\",\"برمه‌ای\":\"my\",\"بلاروسی\":\"be\",\"بلغاری\":\"bg\",\"پرتغالی\":\"pt\",\"تايلندی\":\"th\",\"ترکی استانبولی\":\"tr\",\"تلوگو\":\"te\",\"چک\":\"cs\",\"چینی (ساده‌شده)\":\"zh-cn\",\"چینی (سنتی)\":\"zh-tw\",\"دانمارکی\":\"da\",\"روسی\":\"ru\",\"رومانيايی\":\"ro\",\"زولو\":\"zu\",\"ژاپنی\":\"ja\",\"سوئدی\":\"sv\",\"صربی\":\"sr\",\"عبری\":\"he\",\"عربی\":\"ar\",\"فارسی\":\"fa\",\"فرانسوی\":\"fr\",\"فنلاندی\":\"fi\",\"کاتالان\":\"ca\",\"کانارا\":\"kn\",\"کرئول هائیتی\":\"ht\",\"کردی\":\"ku\",\"کرواتی\":\"hr\",\"کره‌ای\":\"ko\",\"گالیسی\":\"gl\",\"گاليک اسکاتلندی\":\"gd\",\"لاتين\":\"la\",\"لتونيايی\":\"lv\",\"لهستانی\":\"pl\",\"ليتوانيايی\":\"lt\",\"مائوری\":\"mi\",\"مالایالمی\":\"ml\",\"مالايی\":\"ms\",\"مالتی\":\"mt\",\"مجاری\":\"hu\",\"مراتی\":\"mr\",\"مغولی\":\"mn\",\"مقدونيه‌ای\":\"mk\",\"نروژی\":\"nb\",\"ولزی\":\"cy\",\"ويتنامی\":\"vi\",\"هلندی\":\"nl\",\"هندی\":\"hi\",\"يونانی\":\"el\",\"ahepaitani\":\"az\",\"airihi\":\"ga\",\"amariki\":\"am\",\"amēniana\":\"hy\",\"arapeinia\":\"sq\",\"arapi\":\"ar\",\"eperānato\":\"eo\",\"etōnia\":\"et\",\"haina (onamata)\":\"zh-tw\",\"hainamana (kua whakamāmātia)\":\"zh-cn\",\"hanekeria\":\"hu\",\"hapanihi\":\"ja\",\"herepia\":\"sr\",\"hinerangi\":\"fi\",\"hīni\":\"hi\",\"hiperu\":\"he\",\"horowākia\":\"sk\",\"horowinia\":\"sl\",\"huitene\":\"sv\",\"huru\":\"zu\",\"ingarihi\":\"en\",\"initonīhia\":\"id\",\"itāriana\":\"it\",\"kanata\":\"kn\",\"karihia\":\"gl\",\"katarāna\":\"ca\",\"kereore haiti\":\"ht\",\"kiriki\":\"el\",\"kōreana\":\"ko\",\"koroātiana\":\"hr\",\"korukoru\":\"tr\",\"kūrihi\":\"ku\",\"makerōnia\":\"mk\",\"māratihi\":\"mt\",\"marei\":\"ms\",\"mareiarama\":\"ml\",\"mongōriana\":\"mn\",\"nōwei\":\"nb\",\"pākihi\":\"eu\",\"pāniora\":\"es\",\"pēma (purumīhi)\":\"my\",\"peraruhia\":\"be\",\"perēhia\":\"fa\",\"pōrana\":\"pl\",\"potukīhi\":\"pt\",\"purukāriana\":\"bg\",\"rātini\":\"la\",\"rāwhiana\":\"lv\",\"rituānia\":\"lt\",\"romānia\":\"ro\",\"rūhia\":\"ru\",\"tai\":\"th\",\"tati\":\"nl\",\"tenemāka\":\"da\",\"teruku\":\"te\",\"tiamana\":\"de\",\"tieke\":\"cs\",\"tiorangi\":\"is\",\"tuauri kotarangi\":\"gd\",\"uhipeke\":\"uz\",\"ūkareiana\":\"uk\",\"wēra\":\"cy\",\"whitināmu\":\"vi\",\"wīwī\":\"fr\",\"αγγλικά\":\"en\",\"αζερμπαϊτζανικά\":\"az\",\"αλβανικά\":\"sq\",\"αμχαρικά\":\"am\",\"αραβικά\":\"ar\",\"αρμενικά\":\"hy\",\"βασκικά\":\"eu\",\"βιετναμεζικά\":\"vi\",\"βιρμανικά\":\"my\",\"βουλγαρικά\":\"bg\",\"γαελικά σκοτίας\":\"gd\",\"γαλικιακά\":\"gl\",\"γαλλικά\":\"fr\",\"γερμανικά\":\"de\",\"δανικά\":\"da\",\"εβραϊκά\":\"he\",\"ελληνικά\":\"el\",\"εσθονικά\":\"et\",\"εσπεράντο\":\"eo\",\"ζουλού\":\"zu\",\"ιαπωνικά\":\"ja\",\"ινδονησιακά\":\"id\",\"ιρλανδικά\":\"ga\",\"ισλανδικά\":\"is\",\"ισπανικά\":\"es\",\"ιταλικά\":\"it\",\"κανάντα\":\"kn\",\"καταλανικά\":\"ca\",\"κινέζικα (απλοποιημένα)\":\"zh-cn\",\"κινέζικα (παραδοσιακά)\":\"zh-tw\",\"κορεατικά\":\"ko\",\"κουρδικά\":\"ku\",\"κρεόλ αϊτής\":\"ht\",\"κροατικά\":\"hr\",\"λατινικά\":\"la\",\"λετονικά\":\"lv\",\"λευκορωσικά\":\"be\",\"λιθουανικά\":\"lt\",\"μαλαγιάλαμ\":\"ml\",\"μαλέι\":\"ms\",\"μαλτεζικά\":\"mt\",\"μαορί\":\"mi\",\"μαραθικά\":\"mr\",\"μογγολικά\":\"mn\",\"νορβηγικά\":\"nb\",\"ολλανδικά\":\"nl\",\"ουαλικά\":\"cy\",\"ουγγρικά\":\"hu\",\"ουζμπεκικά\":\"uz\",\"ουκρανικά\":\"uk\",\"περσικά\":\"fa\",\"πολωνικά\":\"pl\",\"πορτογαλικά\":\"pt\",\"ρουμανικά\":\"ro\",\"ρωσικά\":\"ru\",\"σερβικά\":\"sr\",\"σλαβομακεδονικά\":\"mk\",\"σλοβακικά\":\"sk\",\"σλοβενικά\":\"sl\",\"σουηδικά\":\"sv\",\"ταϊλανδεζικά\":\"th\",\"τελούγκου\":\"te\",\"τούρκικα\":\"tr\",\"τσεχικά\":\"cs\",\"φινλανδικά\":\"fi\",\"χίντι\":\"hi\",\"amxar\":\"am\",\"arman\":\"hy\",\"bolgar\":\"bg\",\"dat\":\"da\",\"fors\":\"fa\",\"fransuz\":\"fr\",\"gaiti-kreol\":\"ht\",\"galisiy\":\"gl\",\"golland\":\"nl\",\"grek\":\"el\",\"ibroniy\":\"he\",\"indonez\":\"id\",\"ingliz\":\"en\",\"irland\":\"ga\",\"island\":\"is\",\"italyan\":\"it\",\"koreys\":\"ko\",\"kurd (kurmonji)\":\"ku\",\"latish\":\"lv\",\"lotin\":\"la\",\"makedon\":\"mk\",\"maltiy\":\"mt\",\"maratxi\":\"mr\",\"mo‘g‘ul\":\"mn\",\"nemis\":\"de\",\"norveg\":\"nb\",\"ozarbayjon\":\"az\",\"portugal\":\"pt\",\"rumin\":\"ro\",\"tay\":\"th\",\"turk\":\"tr\",\"ukrain\":\"uk\",\"valliy\":\"cy\",\"venger\":\"hu\",\"xitoy (an’anaviy)\":\"zh-tw\",\"xitoy (soddalashgan)\":\"zh-cn\",\"o‘zbek\":\"uz\",\"shotland-gel\":\"gd\",\"shved\":\"sv\",\"chex\":\"cs\",\"albanska\":\"sq\",\"amharísku\":\"am\",\"arabíska\":\"ar\",\"armenska\":\"hy\",\"aserska\":\"az\",\"baskneska\":\"eu\",\"búlgarska\":\"bg\",\"búrmíska\":\"my\",\"danska\":\"da\",\"eistneska\":\"et\",\"enska\":\"en\",\"esperantó\":\"eo\",\"finnska\":\"fi\",\"franska\":\"fr\",\"galisíska\":\"gl\",\"gríska\":\"el\",\"haítískt kreólamál\":\"ht\",\"hebreska\":\"he\",\"hindí\":\"hi\",\"hollenska\":\"nl\",\"hvítrússneska\":\"be\",\"indónesíska\":\"id\",\"írska\":\"ga\",\"íslenska\":\"is\",\"ítalska\":\"it\",\"japanska\":\"ja\",\"katalónska\":\"ca\",\"kínverska (einfölduð)\":\"zh-cn\",\"kínverska (hefðbundin)\":\"zh-tw\",\"kóreska\":\"ko\",\"króatíska\":\"hr\",\"kúrdíska\":\"ku\",\"latína\":\"la\",\"lettneska\":\"lv\",\"litháíska\":\"lt\",\"makedónska\":\"mk\",\"malajíska\":\"ms\",\"maltneska\":\"mt\",\"maoríska\":\"mi\",\"maratí\":\"mr\",\"mongólska\":\"mn\",\"norska\":\"nb\",\"persneska\":\"fa\",\"portúgalska\":\"pt\",\"pólska\":\"pl\",\"rúmenska\":\"ro\",\"rússneska\":\"ru\",\"serbneska\":\"sr\",\"skosk-gelíska\":\"gd\",\"slóvakíska\":\"sk\",\"slóvenska\":\"sl\",\"spænska\":\"es\",\"súlú\":\"zu\",\"sænska\":\"sv\",\"taílenska\":\"th\",\"tékkneska\":\"cs\",\"tyrkneska\":\"tr\",\"ungverska\":\"hu\",\"úkraínska\":\"uk\",\"úsbekíska\":\"uz\",\"velska\":\"cy\",\"víetnamska\":\"vi\",\"þýska\":\"de\",\"ադրբեջաներեն\":\"az\",\"ալբաներեն\":\"sq\",\"ամհարերեն\":\"am\",\"անգլերեն\":\"en\",\"արաբերեն\":\"ar\",\"բասկերեն\":\"eu\",\"բելառուսերեն\":\"be\",\"բիրմաներեն\":\"my\",\"բուլղարերեն\":\"bg\",\"գալիսերեն\":\"gl\",\"գերմաներեն\":\"de\",\"դանիերեն\":\"da\",\"եբրայերեն\":\"he\",\"զուլուսերեն\":\"zu\",\"էսպերանտո\":\"eo\",\"էստոներեն\":\"et\",\"թայերեն\":\"th\",\"թուրքերեն\":\"tr\",\"ինդոնեզերեն\":\"id\",\"իռլանդերեն\":\"ga\",\"իսլանդերեն\":\"is\",\"իսպաներեն\":\"es\",\"իտալերեն\":\"it\",\"լատիներեն\":\"la\",\"լատվիերեն\":\"lv\",\"լեհերեն\":\"pl\",\"լիտվերեն\":\"lt\",\"խորվաթերեն\":\"hr\",\"կաննադա\":\"kn\",\"կատալաներեն\":\"ca\",\"կելտական շոտլանդերեն\":\"gd\",\"կորեերեն\":\"ko\",\"կրեոլերեն (հայիթի)\":\"ht\",\"հայերեն\":\"hy\",\"հինդի\":\"hi\",\"հոլանդերեն\":\"nl\",\"հունարեն\":\"el\",\"հունգարերեն\":\"hu\",\"ճապոներեն\":\"ja\",\"մալայալամ\":\"ml\",\"մալայերեն\":\"ms\",\"մալթերեն\":\"mt\",\"մակեդոներեն\":\"mk\",\"մաորի\":\"mi\",\"մարաթի\":\"mr\",\"մոնղոլերեն\":\"mn\",\"նորվեգերեն\":\"nb\",\"շվեդերեն\":\"sv\",\"ուզբեկերեն\":\"uz\",\"ուկրաիներեն\":\"uk\",\"չեխերեն\":\"cs\",\"չինարեն (ավանդական)\":\"zh-tw\",\"չինարեն (պարզեցված)\":\"zh-cn\",\"պարսկերեն\":\"fa\",\"պորտուգալերեն\":\"pt\",\"ռումիներեն\":\"ro\",\"ռուսերեն\":\"ru\",\"սերբերեն\":\"sr\",\"սլովակերեն\":\"sk\",\"սլովեներեն\":\"sl\",\"վալերեն\":\"cy\",\"վիետնամերեն\":\"vi\",\"տելուգու\":\"te\",\"քրդերեն (քուրմանջի)\":\"ku\",\"ֆիններեն\":\"fi\",\"ֆրանսերեն\":\"fr\",\"arabia\":\"ar\",\"baski\":\"eu\",\"burma\":\"my\",\"englanti\":\"en\",\"espanja\":\"es\",\"haitinkreoli\":\"ht\",\"heprea\":\"he\",\"hollanti\":\"nl\",\"iiri\":\"ga\",\"islanti\":\"is\",\"italia\":\"it\",\"japani\":\"ja\",\"katalaani\":\"ca\",\"kiina (perinteinen)\":\"zh-tw\",\"kiina (yksinkert.)\":\"zh-cn\",\"kreikka\":\"el\",\"kroatia\":\"hr\",\"kurdi\":\"ku\",\"kymri\":\"cy\",\"liettua\":\"lt\",\"makedonia\":\"mk\",\"malaiji\":\"ms\",\"norja\":\"nb\",\"persia\":\"fa\",\"portugali\":\"pt\",\"puola\":\"pl\",\"ranska\":\"fr\",\"ruotsi\":\"sv\",\"saksa\":\"de\",\"skottigaeli\":\"gd\",\"slovakia\":\"sk\",\"suomi\":\"fi\",\"tanska\":\"da\",\"tsekki\":\"cs\",\"turkki\":\"tr\",\"ukraina\":\"uk\",\"unkari\":\"hu\",\"uzbekki\":\"uz\",\"valkovenäjä\":\"be\",\"venäjä\":\"ru\",\"viro\":\"et\",\"albaniera\":\"sq\",\"alemana\":\"de\",\"amharera\":\"am\",\"arabiera\":\"ar\",\"armeniera\":\"hy\",\"azerbaijanera\":\"az\",\"bielorrusiera\":\"be\",\"birmaniera\":\"my\",\"bulgariera\":\"bg\",\"daniera\":\"da\",\"errumaniera\":\"ro\",\"errusiera\":\"ru\",\"eskoziako gaelera\":\"gd\",\"eslovakiera\":\"sk\",\"esloveniera\":\"sl\",\"esperantoa\":\"eo\",\"estoniera\":\"et\",\"euskara\":\"eu\",\"frantsesa\":\"fr\",\"gaelera\":\"cy\",\"galiziera\":\"gl\",\"gaztelania\":\"es\",\"greziera\":\"el\",\"hebreera\":\"he\",\"hindia\":\"hi\",\"hungariera\":\"hu\",\"indonesiera\":\"id\",\"ingelesa\":\"en\",\"irlandera\":\"ga\",\"islandiera\":\"is\",\"italiera\":\"it\",\"japoniera\":\"ja\",\"katalana\":\"ca\",\"koreera\":\"ko\",\"kreolera (haiti)\":\"ht\",\"kroaziera\":\"hr\",\"kurduera\":\"ku\",\"letoniera\":\"lv\",\"lituaniera\":\"lt\",\"malabarera\":\"ml\",\"malaysiera\":\"ms\",\"maltera\":\"mt\",\"maoriera\":\"mi\",\"marathera\":\"mr\",\"mazedoniera\":\"mk\",\"mongoliera\":\"mn\",\"nederlandera\":\"nl\",\"norvegiera\":\"nb\",\"persiera\":\"fa\",\"poloniera\":\"pl\",\"portugesa\":\"pt\",\"serbiera\":\"sr\",\"suediera\":\"sv\",\"suomiera\":\"fi\",\"telugua\":\"te\",\"thaiera\":\"th\",\"turkiera\":\"tr\",\"txekiera\":\"cs\",\"txinera (soildua)\":\"zh-cn\",\"txinera (tradizionala)\":\"zh-tw\",\"ukrainera\":\"uk\",\"uzbekera\":\"uz\",\"vietnamera\":\"vi\",\"zuluera\":\"zu\",\"albanès\":\"sq\",\"alemany\":\"de\",\"amhàric\":\"am\",\"anglès\":\"en\",\"àrab\":\"ar\",\"armeni\":\"hy\",\"àzeri\":\"az\",\"basc\":\"eu\",\"bielorús\":\"be\",\"birmà\":\"my\",\"búlgar\":\"bg\",\"castellà\":\"es\",\"català\":\"ca\",\"coreà\":\"ko\",\"crioll d'haití\":\"ht\",\"croat\":\"hr\",\"danès\":\"da\",\"eslovac\":\"sk\",\"eslovè\":\"sl\",\"estonià\":\"et\",\"finès\":\"fi\",\"francès\":\"fr\",\"gaèlic escocès\":\"gd\",\"gallec\":\"gl\",\"gal·lès\":\"cy\",\"hebreu\":\"he\",\"hongarès\":\"hu\",\"indonesi\":\"id\",\"irlandès\":\"ga\",\"islandès\":\"is\",\"italià\":\"it\",\"japonès\":\"ja\",\"letó\":\"lv\",\"lituà\":\"lt\",\"llatí\":\"la\",\"macedònic\":\"mk\",\"malai\":\"ms\",\"malaiàlam\":\"ml\",\"maltès\":\"mt\",\"neerlandès\":\"nl\",\"noruec\":\"nb\",\"polonès\":\"pl\",\"portuguès\":\"pt\",\"romanès\":\"ro\",\"serbi\":\"sr\",\"suec\":\"sv\",\"txec\":\"cs\",\"ucraïnès\":\"uk\",\"xinès (simplificat)\":\"zh-cn\",\"xinès (tradicional)\":\"zh-tw\",\"albāņu\":\"sq\",\"amharu\":\"am\",\"angļu\":\"en\",\"arābu\":\"ar\",\"armēņu\":\"hy\",\"azerbaidžāņu\":\"az\",\"baltkrievu\":\"be\",\"basku\":\"eu\",\"birmiešu\":\"my\",\"bulgāru\":\"bg\",\"čehu\":\"cs\",\"dāņu\":\"da\",\"ebreju (ivrits)\":\"he\",\"franču\":\"fr\",\"galisiešu\":\"gl\",\"grieķu\":\"el\",\"holandiešu\":\"nl\",\"horvātu\":\"hr\",\"igauņu\":\"et\",\"indonēziešu\":\"id\",\"īru\":\"ga\",\"īslandiešu\":\"is\",\"itāļu\":\"it\",\"japāņu\":\"ja\",\"katalāņu\":\"ca\",\"korejiešu\":\"ko\",\"kreolu (haiti)\":\"ht\",\"krievu\":\"ru\",\"kurdu\":\"ku\",\"ķīniešu (tradicionālā)\":\"zh-tw\",\"ķīniešu (vienkāršotā)\":\"zh-cn\",\"latīņu\":\"la\",\"latviešu\":\"lv\",\"lietuviešu\":\"lt\",\"maķedoniešu\":\"mk\",\"malajalamiešu\":\"ml\",\"malajiešu\":\"ms\",\"maltiešu\":\"mt\",\"maratu\":\"mr\",\"mongoļu\":\"mn\",\"norvēģu\":\"nb\",\"persiešu\":\"fa\",\"poļu\":\"pl\",\"portugāļu\":\"pt\",\"rumāņu\":\"ro\",\"serbu\":\"sr\",\"skotu gēlu\":\"gd\",\"slovāku\":\"sk\",\"slovēņu\":\"sl\",\"somu\":\"fi\",\"spāņu\":\"es\",\"taju\":\"th\",\"turku\":\"tr\",\"ukraiņu\":\"uk\",\"ungāru\":\"hu\",\"uzbeku\":\"uz\",\"vācu\":\"de\",\"velsiešu\":\"cy\",\"vjetnamiešu\":\"vi\",\"zviedru\":\"sv\",\"belarussia\":\"be\",\"cek\":\"cs\",\"china (aks. sederhana)\":\"zh-cn\",\"china (aks. tradisional)\":\"zh-tw\",\"finlandia\":\"fi\",\"gaelig\":\"ga\",\"gaelik skotlandia\":\"gd\",\"galisia\":\"gl\",\"inggris\":\"en\",\"islan\":\"is\",\"jepang\":\"ja\",\"katala\":\"ca\",\"lituania\":\"lt\",\"polandia\":\"pl\",\"prancis\":\"fr\",\"rumania\":\"ro\",\"swensk\":\"sv\",\"yunani\":\"el\",\"అజర్‌బైజాని\":\"az\",\"అర్మేనియన్\":\"hy\",\"అల్బేనియన్\":\"sq\",\"ఆంగ్లము\":\"en\",\"ఆమ్హారిక్\":\"am\",\"ఆరబిక్\":\"ar\",\"ఇండొనేసియన్\":\"id\",\"ఇటాలియన్\":\"it\",\"ఉజ్బెక్\":\"uz\",\"ఎస్పెరాంటో\":\"eo\",\"ఏస్టోనియన్\":\"et\",\"ఐరిష్\":\"ga\",\"ఐస్ లాండిక్\":\"is\",\"కన్నడ\":\"kn\",\"కర్డిష్\":\"ku\",\"కొరియన్\":\"ko\",\"క్యాటలాన్\":\"ca\",\"క్రొయేషియన్\":\"hr\",\"గాలిసియన్\":\"gl\",\"గ్రీక్\":\"el\",\"చెక్\":\"cs\",\"చైనీస్ (సరళమైన)\":\"zh-cn\",\"చైనీస్ (సామ్ప్రదాయమైన)\":\"zh-tw\",\"జపనీస్\":\"ja\",\"జర్మన్\":\"de\",\"జులు\":\"zu\",\"టర్కిష్\":\"tr\",\"డచ్\":\"nl\",\"డానిష్\":\"da\",\"తెలుగు\":\"te\",\"థాయ్\":\"th\",\"నార్విజియన్\":\"nb\",\"పర్షియన్\":\"fa\",\"పోర్చుగీస్\":\"pt\",\"పోలిష్\":\"pl\",\"ఫిన్నిష్\":\"fi\",\"ఫ్రెంచ్\":\"fr\",\"బర్మీస్\":\"my\",\"బల్గేరియన్\":\"bg\",\"బాస్క్\":\"eu\",\"బెలారుషియన్\":\"be\",\"మంగోలియన్\":\"mn\",\"మయోరి\":\"mi\",\"మరాఠీ\":\"mr\",\"మలయాళం\":\"ml\",\"మాలై\":\"ms\",\"మాల్టీస్\":\"mt\",\"మాసిడోనియన్\":\"mk\",\"యుక్రేనియన్\":\"uk\",\"రష్యన్\":\"ru\",\"రొమేనియన్\":\"ro\",\"లాటిన్\":\"la\",\"లాట్వియన్\":\"lv\",\"లిథువేనియన్\":\"lt\",\"వియత్నామీస్\":\"vi\",\"వెల్ష్\":\"cy\",\"సెర్బియన్\":\"sr\",\"స్కాట్స్ గేలిక్\":\"gd\",\"స్పానిష్\":\"es\",\"స్లోవక్\":\"sk\",\"స్లోవేనియన్\":\"sl\",\"స్వీడిష్\":\"sv\",\"హంగేరియన్\":\"hu\",\"హిందీ\":\"hi\",\"హీబ్రూ\":\"he\",\"హైయేటియన్ క్రియోల్\":\"ht\",\"amhárico\":\"am\",\"azerí\":\"az\",\"chino (simplificado)\":\"zh-cn\",\"chino (tradicional)\":\"zh-tw\",\"criollo haitiano\":\"ht\",\"danés\":\"da\",\"estonio\":\"et\",\"euskera\":\"eu\",\"finlandés\":\"fi\",\"gallego\":\"gl\",\"griego\":\"el\",\"japonés\":\"ja\",\"kurdo\":\"ku\",\"malayo\":\"ms\",\"noruego\":\"nb\",\"rumano\":\"ro\",\"uzbeco\":\"uz\",\"albaania\":\"sq\",\"amhaari\":\"am\",\"araabia\":\"ar\",\"armeenia\":\"hy\",\"aserbaidžaani\":\"az\",\"birma\":\"my\",\"bulgaaria\":\"bg\",\"eesti\":\"et\",\"galeegi\":\"gl\",\"haitikreooli\":\"ht\",\"heebrea\":\"he\",\"hispaania\":\"es\",\"hollandi\":\"nl\",\"horvaadi\":\"hr\",\"indoneesia\":\"id\",\"inglise\":\"en\",\"islandi\":\"is\",\"itaalia\":\"it\",\"jaapani\":\"ja\",\"kreeka\":\"el\",\"ladina\":\"la\",\"leedu\":\"lt\",\"lihtsustatud hiina\":\"zh-cn\",\"läti\":\"lv\",\"makedoonia\":\"mk\",\"malajalaami\":\"ml\",\"maoori\":\"mi\",\"mongoli\":\"mn\",\"norra\":\"nb\",\"poola\":\"pl\",\"prantsuse\":\"fr\",\"pärsia\":\"fa\",\"rootsi\":\"sv\",\"rumeenia\":\"ro\",\"slovaki\":\"sk\",\"sloveeni\":\"sl\",\"soome\":\"fi\",\"suulu\":\"zu\",\"šoti\":\"gd\",\"taani\":\"da\",\"traditsiooniline hiina\":\"zh-tw\",\"tšehhi\":\"cs\",\"türgi\":\"tr\",\"uelsi\":\"cy\",\"ungari\":\"hu\",\"usbeki\":\"uz\",\"valgevene\":\"be\",\"vene\":\"ru\",\"albanyen\":\"sq\",\"amenyen\":\"hy\",\"anglè\":\"en\",\"azèbajani\":\"az\",\"belarisyen\":\"be\",\"bilgaryen\":\"bg\",\"chinwa (senp)\":\"zh-cn\",\"chinwa (tradisyonèl)\":\"zh-tw\",\"danwa\":\"da\",\"ebre\":\"he\",\"endonezyen\":\"id\",\"endou\":\"hi\",\"estonyen\":\"et\",\"fenlandè\":\"fi\",\"franse\":\"fr\",\"gaelik ekosè\":\"gd\",\"galisyen\":\"gl\",\"grèk\":\"el\",\"ikrenyen\":\"uk\",\"ilandè\":\"ga\",\"islandè\":\"is\",\"italyen\":\"it\",\"izbèk\":\"uz\",\"japonè\":\"ja\",\"koreyen\":\"ko\",\"kreyòl ayisyen\":\"ht\",\"kurde (kurmandji)\":\"ku\",\"kwoasyen\":\"hr\",\"laten\":\"la\",\"letonyen\":\"lv\",\"lityanyen\":\"lt\",\"malè\":\"ms\",\"malt\":\"mt\",\"masedonyen\":\"mk\",\"mongolyen\":\"mn\",\"myanma (burmese)\":\"my\",\"nòvejyen\":\"nb\",\"olandè, neyèlandè\":\"nl\",\"onngaryen\":\"hu\",\"panyòl\":\"es\",\"pèsyen\":\"fa\",\"polonè\":\"pl\",\"pòtigè\":\"pt\",\"ris\":\"ru\",\"romanyen\":\"ro\",\"sèb\":\"sr\",\"slovenyen\":\"sl\",\"syedwa\":\"sv\",\"tuk\":\"tr\",\"tyèk\":\"cs\",\"vyetnamyen\":\"vi\",\"albaneg\":\"sq\",\"almaeneg\":\"de\",\"arabeg\":\"ar\",\"armeneg\":\"hy\",\"aserbaijaneg\":\"az\",\"basgeg\":\"eu\",\"belarwseg\":\"be\",\"bwlgaraidd\":\"bg\",\"catalaneg\":\"ca\",\"creol haiti\":\"ht\",\"croateg\":\"hr\",\"cymraeg\":\"cy\",\"cyrdeg (kurmandji)\":\"ku\",\"daneg\":\"da\",\"eidaleg\":\"it\",\"estoneg\":\"et\",\"fietnameg\":\"vi\",\"ffineg\":\"fi\",\"fflemeg\":\"nl\",\"ffrangeg\":\"fr\",\"gaeleg yr alban\":\"gd\",\"galisaidd\":\"gl\",\"groeg\":\"el\",\"gwyddeleg\":\"ga\",\"hebraeg\":\"he\",\"hwngareg\":\"hu\",\"iaith corea\":\"ko\",\"indonesieg\":\"id\",\"islandeg\":\"is\",\"iwcraineg\":\"uk\",\"japaneg\":\"ja\",\"latfieg\":\"lv\",\"lithwaneg\":\"lt\",\"lladin\":\"la\",\"macedoneg\":\"mk\",\"malteseg\":\"mt\",\"mongoleg\":\"mn\",\"myanmar (byrma)\":\"my\",\"norwyeg\":\"nb\",\"perseg\":\"fa\",\"portiwgaleg\":\"pt\",\"pwyleg\":\"pl\",\"rwmaneg\":\"ro\",\"rwsieg\":\"ru\",\"saesneg\":\"en\",\"sbaeneg\":\"es\",\"serbeg\":\"sr\",\"slofac\":\"sk\",\"slofenia\":\"sl\",\"swedeg\":\"sv\",\"swlw\":\"zu\",\"tsieceg\":\"cs\",\"tsieineeg (traddodiadol)\":\"zh-tw\",\"tsieineeg (wedi symleiddio)\":\"zh-cn\",\"twrceg\":\"tr\",\"usbec\":\"uz\",\"अंग्रेज़ी\":\"en\",\"अज़रबैजानी\":\"az\",\"अल्बेनियन\":\"sq\",\"आइसलैंडिक\":\"is\",\"आर्मेनियन\":\"hy\",\"इटैलियन\":\"it\",\"उज़्बेक\":\"uz\",\"एस्तोनियन\":\"et\",\"एस्पेरांटो\":\"eo\",\"ऐम्हेरिक\":\"am\",\"कन्नड़\":\"kn\",\"कुर्दिश (करमंजी)\":\"ku\",\"कैटेलन\":\"ca\",\"गैलिशियन\":\"gl\",\"चीनी (परंपरागत)\":\"zh-tw\",\"चेक\":\"cs\",\"जापानी\":\"ja\",\"ज़ुलु\":\"zu\",\"डैनिश\":\"da\",\"तुर्क\":\"tr\",\"तेलुगु\":\"te\",\"पुर्तगाली\":\"pt\",\"फ़िनिश\":\"fi\",\"फ़्रेंच\":\"fr\",\"बर्मी\":\"my\",\"बुल्गारियन\":\"bg\",\"बेलारूसीयन\":\"be\",\"बैस्क\":\"eu\",\"मलयालम\":\"ml\",\"माऔरी\":\"mi\",\"माल्टी\":\"mt\",\"मेसीडोनियन\":\"mk\",\"यूक्रेनियन\":\"uk\",\"रूसी\":\"ru\",\"रोमेनियन\":\"ro\",\"लातवियन\":\"lv\",\"लैटिन\":\"la\",\"वियतनामी\":\"vi\",\"सर्बियाई\":\"sr\",\"स्पैनिश\":\"es\",\"स्लोवाक\":\"sk\",\"स्लोवेनियन\":\"sl\",\"हंगरियन\":\"hu\",\"हीब्रू\":\"he\",\"हैतियन क्रिओल\":\"ht\",\"阿尔巴尼亚语\":\"sq\",\"阿拉伯语\":\"ar\",\"阿姆哈拉语\":\"am\",\"阿塞拜疆语\":\"az\",\"爱尔兰语\":\"ga\",\"爱沙尼亚语\":\"et\",\"巴斯克语\":\"eu\",\"白俄罗斯语\":\"be\",\"保加利亚语\":\"bg\",\"冰岛语\":\"is\",\"波兰语\":\"pl\",\"波斯语\":\"fa\",\"丹麦语\":\"da\",\"德语\":\"de\",\"俄语\":\"ru\",\"法语\":\"fr\",\"芬兰语\":\"fi\",\"海地克里奥尔语\":\"ht\",\"韩语\":\"ko\",\"荷兰语\":\"nl\",\"加利西亚语\":\"gl\",\"加泰罗尼亚语\":\"ca\",\"捷克语\":\"cs\",\"卡纳达语\":\"kn\",\"克罗地亚语\":\"hr\",\"库尔德语\":\"ku\",\"拉丁语\":\"la\",\"拉脱维亚语\":\"lv\",\"立陶宛语\":\"lt\",\"罗马尼亚语\":\"ro\",\"马耳他语\":\"mt\",\"马拉地语\":\"mr\",\"马拉雅拉姆语\":\"ml\",\"马来语\":\"ms\",\"马其顿语\":\"mk\",\"毛利语\":\"mi\",\"蒙古语\":\"mn\",\"缅甸语\":\"my\",\"南非祖鲁语\":\"zu\",\"挪威语\":\"nb\",\"葡萄牙语\":\"pt\",\"日语\":\"ja\",\"瑞典语\":\"sv\",\"塞尔维亚语\":\"sr\",\"世界语\":\"eo\",\"斯洛伐克语\":\"sk\",\"斯洛文尼亚语\":\"sl\",\"苏格兰盖尔语\":\"gd\",\"泰卢固语\":\"te\",\"泰语\":\"th\",\"土耳其语\":\"tr\",\"威尔士语\":\"cy\",\"乌克兰语\":\"uk\",\"乌兹别克语\":\"uz\",\"西班牙语\":\"es\",\"希伯来语\":\"he\",\"希腊语\":\"el\",\"匈牙利语\":\"hu\",\"亚美尼亚语\":\"hy\",\"意大利语\":\"it\",\"印地语\":\"hi\",\"印尼语\":\"id\",\"英语\":\"en\",\"越南语\":\"vi\",\"中文(繁体)\":\"zh-tw\",\"中文(简体)\":\"zh-cn\",\"азербайджански\":\"az\",\"английски\":\"en\",\"арабски\":\"ar\",\"арменски\":\"hy\",\"баски\":\"eu\",\"беларуски\":\"be\",\"бирмански\":\"my\",\"български\":\"bg\",\"галисийски\":\"gl\",\"гръцки\":\"el\",\"датски\":\"da\",\"индонезийски\":\"id\",\"ирландски\":\"ga\",\"испански\":\"es\",\"италиански\":\"it\",\"китайски (опростен)\":\"zh-cn\",\"китайски (традиционен)\":\"zh-tw\",\"корейски\":\"ko\",\"кюрдски\":\"ku\",\"латвийски\":\"lv\",\"литовски\":\"lt\",\"малайски\":\"ms\",\"малтийски\":\"mt\",\"немски\":\"de\",\"нидерландски\":\"nl\",\"норвежки\":\"nb\",\"персийски\":\"fa\",\"румънски\":\"ro\",\"словашки\":\"sk\",\"словенски\":\"sl\",\"сръбски\":\"sr\",\"тайландски\":\"th\",\"уелски\":\"cy\",\"узбекски\":\"uz\",\"финландски\":\"fi\",\"френски\":\"fr\",\"хаитянски креолски\":\"ht\",\"хърватски\":\"hr\",\"шотландски келтски\":\"gd\",\"японски\":\"ja\",\"الآيسلندية\":\"is\",\"الأذرية\":\"az\",\"الارمنية\":\"hy\",\"الإسبانية\":\"es\",\"الاسبرانتو\":\"eo\",\"الإستونية\":\"et\",\"الاسكتلندية الغالية\":\"gd\",\"الألبانية\":\"sq\",\"الألمانية\":\"de\",\"الأمهرية\":\"am\",\"الإنجليزية\":\"en\",\"الإندونيسية\":\"id\",\"الأوزبكية\":\"uz\",\"الأوكرانية\":\"uk\",\"الأيرلندية\":\"ga\",\"الإيطالية\":\"it\",\"الباسكية\":\"eu\",\"البرتغالية\":\"pt\",\"البلغارية\":\"bg\",\"البورمية\":\"my\",\"البولندية\":\"pl\",\"البيلاروسية\":\"be\",\"التايلاندية\":\"th\",\"التركية\":\"tr\",\"التشيكية\":\"cs\",\"التيلوجو\":\"te\",\"الجاليكية\":\"gl\",\"الدانماركية\":\"da\",\"الروسية\":\"ru\",\"الرومانية\":\"ro\",\"الزولوية\":\"zu\",\"السلوفاكية\":\"sk\",\"السلوفينية\":\"sl\",\"السويدية\":\"sv\",\"الصربية\":\"sr\",\"الصينية (التقليدية)\":\"zh-tw\",\"الصينية (المبسطة)\":\"zh-cn\",\"العبرية\":\"he\",\"العربية\":\"ar\",\"الفارسية\":\"fa\",\"الفرنسية\":\"fr\",\"الفنلندية\":\"fi\",\"الفيتنامية\":\"vi\",\"القطلونية\":\"ca\",\"الكانادا\":\"kn\",\"الكردية\":\"ku\",\"الكرواتية\":\"hr\",\"الكورية\":\"ko\",\"اللاتفية\":\"lv\",\"اللاتينية\":\"la\",\"اللغة الكريولية الهايتية\":\"ht\",\"الليتوانية\":\"lt\",\"المالايالامية\":\"ml\",\"المالطيّة\":\"mt\",\"الماورية\":\"mi\",\"المقدونية\":\"mk\",\"الملايو\":\"ms\",\"المنغولية\":\"mn\",\"المهراتية\":\"mr\",\"النرويجية\":\"nb\",\"الهندية\":\"hi\",\"الهنغارية\":\"hu\",\"الهولندية\":\"nl\",\"الويلزية\":\"cy\",\"اليابانية\":\"ja\",\"اليونانية\":\"el\",\"баскијски\":\"eu\",\"вијетнамски\":\"vi\",\"галски\":\"gl\",\"енглески\":\"en\",\"индонежански\":\"id\",\"јапански\":\"ja\",\"јерменски\":\"hy\",\"кинески (поједностављени)\":\"zh-cn\",\"кинески (традиционални)\":\"zh-tw\",\"креолски (хаити)\":\"ht\",\"летонски\":\"lv\",\"мађарски\":\"hu\",\"марати\":\"mr\",\"немачки\":\"de\",\"персијски\":\"fa\",\"пољски\":\"pl\",\"румунски\":\"ro\",\"словеначки\":\"sl\",\"тајски\":\"th\",\"украјински\":\"uk\",\"азербайжан\":\"az\",\"албани\":\"sq\",\"амхарик\":\"am\",\"англи\":\"en\",\"араб\":\"ar\",\"армени\":\"hy\",\"баск\":\"eu\",\"беларусь\":\"be\",\"бирм\":\"my\",\"болгар\":\"bg\",\"вьетнам\":\"vi\",\"гаити креол\":\"ht\",\"галик\":\"gl\",\"гаэл\":\"gd\",\"герман\":\"de\",\"голланд\":\"nl\",\"грек\":\"el\",\"дани\":\"da\",\"индонези\":\"id\",\"ирланд\":\"ga\",\"исланд\":\"is\",\"испани\":\"es\",\"итали\":\"it\",\"каталан\":\"ca\",\"кипр\":\"he\",\"курд\":\"ku\",\"латви\":\"lv\",\"латин\":\"la\",\"литва\":\"lt\",\"македон\":\"mk\",\"малай\":\"ms\",\"малайлам\":\"ml\",\"малти\":\"mt\",\"монгол\":\"mn\",\"норвеги\":\"nb\",\"орос\":\"ru\",\"перс\":\"fa\",\"польш\":\"pl\",\"португаль\":\"pt\",\"румын\":\"ro\",\"серби\":\"sr\",\"словак\":\"sk\",\"словени\":\"sl\",\"солонгос\":\"ko\",\"тай\":\"th\",\"турк\":\"tr\",\"тэлүгү\":\"te\",\"узбек\":\"uz\",\"украин\":\"uk\",\"унгар\":\"hu\",\"уэльс\":\"cy\",\"финлянд\":\"fi\",\"франц\":\"fr\",\"хорват\":\"hr\",\"хятад (ердийн)\":\"zh-cn\",\"хятад (уламжлалт)\":\"zh-tw\",\"чех\":\"cs\",\"швед\":\"sv\",\"эстони\":\"et\",\"япон\":\"ja\",\"amhariska\":\"am\",\"arabiska\":\"ar\",\"armeniska\":\"hy\",\"azerbajdzjanska\":\"az\",\"baskiska\":\"eu\",\"bulgariska\":\"bg\",\"burmesiska\":\"my\",\"engelska\":\"en\",\"estniska\":\"et\",\"finska\":\"fi\",\"gaeliska\":\"gd\",\"galiciska\":\"gl\",\"grekiska\":\"el\",\"haitiska\":\"ht\",\"hebreiska\":\"he\",\"indonesiska\":\"id\",\"irländska\":\"ga\",\"isländska\":\"is\",\"italienska\":\"it\",\"kanaresiska\":\"kn\",\"katalanska\":\"ca\",\"kinesiska (förenklad)\":\"zh-cn\",\"kinesiska (traditionell)\":\"zh-tw\",\"koreanska\":\"ko\",\"kroatiska\":\"hr\",\"kurdiska\":\"ku\",\"lettiska\":\"lv\",\"litauiska\":\"lt\",\"makedonska\":\"mk\",\"malaysiska\":\"ms\",\"maltesiska\":\"mt\",\"mongoliska\":\"mn\",\"nederländska\":\"nl\",\"persiska\":\"fa\",\"polska\":\"pl\",\"portugisiska\":\"pt\",\"rumänska\":\"ro\",\"ryska\":\"ru\",\"serbiska\":\"sr\",\"slovakiska\":\"sk\",\"slovenska\":\"sl\",\"spanska\":\"es\",\"svenska\":\"sv\",\"thailändska\":\"th\",\"tjeckiska\":\"cs\",\"turkiska\":\"tr\",\"tyska\":\"de\",\"ukrainska\":\"uk\",\"ungerska\":\"hu\",\"uzbekiska\":\"uz\",\"vietnamesiska\":\"vi\",\"vitryska\":\"be\",\"walesiska\":\"cy\",\"albaneză\":\"sq\",\"amharică\":\"am\",\"arabă\":\"ar\",\"armeană\":\"hy\",\"azerbaidjană\":\"az\",\"bască\":\"eu\",\"bielorusă\":\"be\",\"birmană\":\"my\",\"bulgară\":\"bg\",\"catalană\":\"ca\",\"cehă\":\"cs\",\"chineză (simplificată)\":\"zh-cn\",\"chineză (tradițională)\":\"zh-tw\",\"coreeană\":\"ko\",\"creolă haitiană\":\"ht\",\"croată\":\"hr\",\"daneză\":\"da\",\"ebraică\":\"he\",\"engleză\":\"en\",\"estonă\":\"et\",\"finlandeză\":\"fi\",\"franceză\":\"fr\",\"galeză\":\"cy\",\"galica scoțiană\":\"gd\",\"galiciană\":\"gl\",\"germană\":\"de\",\"greacă\":\"el\",\"indoneziană\":\"id\",\"irlandeză\":\"ga\",\"islandeză\":\"is\",\"italiană\":\"it\",\"japoneză\":\"ja\",\"kurdă\":\"ku\",\"latină\":\"la\",\"letonă\":\"lv\",\"lituaniană\":\"lt\",\"macedoneană\":\"mk\",\"maghiară\":\"hu\",\"malaeză\":\"ms\",\"malteză\":\"mt\",\"mongolă\":\"mn\",\"neerlandeză\":\"nl\",\"norvegiană\":\"nb\",\"persană\":\"fa\",\"poloneză\":\"pl\",\"portugheză\":\"pt\",\"română\":\"ro\",\"rusă\":\"ru\",\"sârbă\":\"sr\",\"slovacă\":\"sk\",\"slovenă\":\"sl\",\"spaniolă\":\"es\",\"suedeză\":\"sv\",\"thailandeză\":\"th\",\"turcă\":\"tr\",\"ucraineană\":\"uk\",\"uzbecă\":\"uz\",\"vietnameză\":\"vi\",\"airių\":\"ga\",\"albanų\":\"sq\",\"amharų\":\"am\",\"anglų\":\"en\",\"arabų\":\"ar\",\"armėnų\":\"hy\",\"azerbaidžaniečių\":\"az\",\"baltarusių\":\"be\",\"baskų\":\"eu\",\"birmiečių\":\"my\",\"bulgarų\":\"bg\",\"čekų\":\"cs\",\"danų\":\"da\",\"estų\":\"et\",\"galisų\":\"gl\",\"graikų\":\"el\",\"haičio kreolų\":\"ht\",\"hebrajų\":\"he\",\"indoneziečių\":\"id\",\"islandų\":\"is\",\"ispanų\":\"es\",\"italų\":\"it\",\"japonų\":\"ja\",\"kanadų\":\"kn\",\"kataloniečių\":\"ca\",\"kinų (supaprastinta)\":\"zh-cn\",\"kinų (tradicinė)\":\"zh-tw\",\"korėjiečių\":\"ko\",\"kroatų\":\"hr\",\"kurdų\":\"ku\",\"latvių\":\"lv\",\"lenkų\":\"pl\",\"lietuvių\":\"lt\",\"lotynų\":\"la\",\"makedoniečių\":\"mk\",\"malajalių\":\"ml\",\"malajiečių\":\"ms\",\"maltiečių\":\"mt\",\"maorių\":\"mi\",\"maratų\":\"mr\",\"mongolų\":\"mn\",\"norvegų\":\"nb\",\"olandų\":\"nl\",\"persų\":\"fa\",\"portugalų\":\"pt\",\"prancūzų\":\"fr\",\"rumunų\":\"ro\",\"rusų\":\"ru\",\"serbų\":\"sr\",\"slovakų\":\"sk\",\"slovėnų\":\"sl\",\"suomių\":\"fi\",\"škotų (gėlų)\":\"gd\",\"švedų\":\"sv\",\"tajų\":\"th\",\"telugų\":\"te\",\"turkų\":\"tr\",\"ukrainiečių\":\"uk\",\"uzbekų\":\"uz\",\"valų\":\"cy\",\"vengrų\":\"hu\",\"vietnamiečių\":\"vi\",\"vokiečių\":\"de\",\"zulusų\":\"zu\",\"갈리시아어\":\"gl\",\"그리스어\":\"el\",\"네덜란드어\":\"nl\",\"노르웨이어\":\"nb\",\"덴마크어\":\"da\",\"독일어\":\"de\",\"라트비아어\":\"lv\",\"라틴어\":\"la\",\"러시아어\":\"ru\",\"루마니아어\":\"ro\",\"리투아니아어\":\"lt\",\"마라티어\":\"mr\",\"마오리어\":\"mi\",\"마케도니아어\":\"mk\",\"말라얄람어\":\"ml\",\"말레이어\":\"ms\",\"몰타어\":\"mt\",\"몽골어\":\"mn\",\"미얀마어 (버마어)\":\"my\",\"바스크어\":\"eu\",\"베트남어\":\"vi\",\"벨라루스어\":\"be\",\"불가리아어\":\"bg\",\"세르비아어\":\"sr\",\"스웨덴어\":\"sv\",\"스코틀랜드 게일어\":\"gd\",\"스페인어\":\"es\",\"슬로바키아어\":\"sk\",\"슬로베니아어\":\"sl\",\"아랍어\":\"ar\",\"아르메니아어\":\"hy\",\"아이슬란드어\":\"is\",\"아이티 크리올어\":\"ht\",\"아일랜드어\":\"ga\",\"아제르바이잔어\":\"az\",\"알바니아어\":\"sq\",\"암하라어\":\"am\",\"에스토니아어\":\"et\",\"에스페란토어\":\"eo\",\"영어\":\"en\",\"우즈베크어\":\"uz\",\"우크라이나어\":\"uk\",\"웨일즈어\":\"cy\",\"이탈리아어\":\"it\",\"인도네시아어\":\"id\",\"일본어\":\"ja\",\"줄루어\":\"zu\",\"중국어(간체)\":\"zh-cn\",\"중국어(번체)\":\"zh-tw\",\"체코어\":\"cs\",\"카탈로니아어\":\"ca\",\"칸나다어\":\"kn\",\"쿠르드어\":\"ku\",\"크로아티아어\":\"hr\",\"태국어\":\"th\",\"터키어\":\"tr\",\"텔루구어\":\"te\",\"페르시아어\":\"fa\",\"포르투갈어\":\"pt\",\"폴란드어\":\"pl\",\"프랑스어\":\"fr\",\"핀란드어\":\"fi\",\"한국어\":\"ko\",\"헝가리어\":\"hu\",\"히브리어\":\"he\",\"힌디어\":\"hi\",\"albanese\":\"sq\",\"amarico\":\"am\",\"arabo\":\"ar\",\"armeno\":\"hy\",\"azero\":\"az\",\"bielorusso\":\"be\",\"bulgaro\":\"bg\",\"catalano\":\"ca\",\"ceco\":\"cs\",\"cinese (semplificato)\":\"zh-cn\",\"cinese (tradizionale)\":\"zh-tw\",\"creolo haitiano\":\"ht\",\"croato\":\"hr\",\"curdo (kurmanji)\":\"ku\",\"danese\":\"da\",\"ebraico\":\"he\",\"estone\":\"et\",\"finlandese\":\"fi\",\"francese\":\"fr\",\"gaelico scozzese\":\"gd\",\"galiziano\":\"gl\",\"gallese\":\"cy\",\"giapponese\":\"ja\",\"greco\":\"el\",\"indonesiano\":\"id\",\"inglese\":\"en\",\"irlandese\":\"ga\",\"islandese\":\"is\",\"latino\":\"la\",\"lettone\":\"lv\",\"macedone\":\"mk\",\"malese\":\"ms\",\"mongolo\":\"mn\",\"norvegese\":\"nb\",\"olandese\":\"nl\",\"persiano\":\"fa\",\"polacco\":\"pl\",\"portoghese\":\"pt\",\"rumeno\":\"ro\",\"serbo\":\"sr\",\"slovacco\":\"sk\",\"sloveno\":\"sl\",\"spagnolo\":\"es\",\"svedese\":\"sv\",\"tailandese\":\"th\",\"tedesco\":\"de\",\"ucraino\":\"uk\",\"ungherese\":\"hu\",\"quốc tế ngữ\":\"eo\",\"tiếng ả rập\":\"ar\",\"tiếng albania\":\"sq\",\"tiếng amharic\":\"am\",\"tiếng anh\":\"en\",\"tiếng armenia\":\"hy\",\"tiếng azerbaijan\":\"az\",\"tiếng ba lan\":\"pl\",\"tiếng ba tư\":\"fa\",\"tiếng basque\":\"eu\",\"tiếng belarus\":\"be\",\"tiếng bồ đào nha\":\"pt\",\"tiếng bulgaria\":\"bg\",\"tiếng catalan\":\"ca\",\"tiếng creole ở haiti\":\"ht\",\"tiếng croatia\":\"hr\",\"tiếng do thái\":\"he\",\"tiếng đan mạch\":\"da\",\"tiếng đức\":\"de\",\"tiếng estonia\":\"et\",\"tiếng gael scotland\":\"gd\",\"tiếng galicia\":\"gl\",\"tiếng hà lan\":\"nl\",\"tiếng hàn\":\"ko\",\"tiếng hindi\":\"hi\",\"tiếng hungary\":\"hu\",\"tiếng hy lạp\":\"el\",\"tiếng iceland\":\"is\",\"tiếng indonesia\":\"id\",\"tiếng ireland\":\"ga\",\"tiếng kannada\":\"kn\",\"tiếng kurd\":\"ku\",\"tiếng latinh\":\"la\",\"tiếng latvia\":\"lv\",\"tiếng litva\":\"lt\",\"tiếng mã lai\":\"ms\",\"tiếng macedonia\":\"mk\",\"tiếng malayalam\":\"ml\",\"tiếng malta\":\"mt\",\"tiếng maori\":\"mi\",\"tiếng marathi\":\"mr\",\"tiếng mông cổ\":\"mn\",\"tiếng myanmar\":\"my\",\"tiếng na uy\":\"nb\",\"tiếng nga\":\"ru\",\"tiếng nhật\":\"ja\",\"tiếng pháp\":\"fr\",\"tiếng phần lan\":\"fi\",\"tiếng rumani\":\"ro\",\"tiếng séc\":\"cs\",\"tiếng serbia\":\"sr\",\"tiếng slovak\":\"sk\",\"tiếng slovenia\":\"sl\",\"tiếng tây ban nha\":\"es\",\"tiếng telugu\":\"te\",\"tiếng thái\":\"th\",\"tiếng thổ nhĩ kỳ\":\"tr\",\"tiếng thụy điển\":\"sv\",\"tiếng trung (giản thể)\":\"zh-cn\",\"tiếng trung (phồn thể)\":\"zh-tw\",\"tiếng ukraina\":\"uk\",\"tiếng uzbek\":\"uz\",\"tiếng việt\":\"vi\",\"tiếng xứ wales\":\"cy\",\"tiếng ý\":\"it\",\"tiếng zulu\":\"zu\",\"にほんご\":\"ja\"},\"scratchToGoogleMap\":{\"zh-cn\":\"zh\",\"nb\":\"no\",\"he\":\"iw\",\"es-419\":\"es\",\"pt-br\":\"pt\",\"ja-hira\":\"ja\"},\"previouslySupported\":[\"ab\",\"ms\",\"be\",\"eo\",\"hy\",\"hi\",\"kn\",\"ht\",\"ku\",\"la\",\"mk\",\"ml\",\"mt\",\"mr\",\"mn\",\"my\",\"nn\",\"sq\",\"te\",\"uz\"],\"spokenLanguages\":{\"en\":[{\"code\":\"zh-cn\",\"name\":\"Chinese (Mandarin)\"}],\"cy\":[{\"code\":\"zh-cn\",\"name\":\"Tsieineaidd (Mandarin)\"},{\"code\":\"hi\",\"name\":\"Hindi\"},{\"code\":\"pt-br\",\"name\":\"Portiwgaleg (Brasil)\"},{\"code\":\"es-419\",\"name\":\"Sbaeneg (America Ladin)\"}],\"zu\":[{\"code\":\"zh-cn\",\"name\":\"IsiShayina (isiMandarin)\"},{\"code\":\"hi\",\"name\":\"IsiHindi\"},{\"code\":\"pt-br\",\"name\":\"IsiPutukezi (saseBrazil)\"},{\"code\":\"es-419\",\"name\":\"ISpanishi (Latin American)\"}],\"ko\":[{\"code\":\"zh-cn\",\"name\":\"중국어 (북경어)\"},{\"code\":\"hi\",\"name\":\"힌디 어\"},{\"code\":\"pt-br\",\"name\":\"포르투갈어 (브라질)\"},{\"code\":\"es-419\",\"name\":\"스페인어 (라틴 아메리카)\"}],\"az\":[{\"code\":\"zh-cn\",\"name\":\"Çin (Mandarin)\"},{\"code\":\"hi\",\"name\":\"Hindi\"},{\"code\":\"pt-br\",\"name\":\"Portuqal (Braziliya)\"},{\"code\":\"es-419\",\"name\":\"İspan (Latın Amerikası)\"}],\"he\":[{\"code\":\"zh-cn\",\"name\":\"סינית (מנדרינית)\"},{\"code\":\"hi\",\"name\":\"הינדי\"},{\"code\":\"pt-br\",\"name\":\"פורטוגזית (ברזילאית)\"},{\"code\":\"es-419\",\"name\":\"ספרדית (אמריקה הלטינית)\"}],\"mk\":[{\"code\":\"zh-cn\",\"name\":\"Кинески (мандарински)\"},{\"code\":\"hi\",\"name\":\"Хинди\"},{\"code\":\"pt-br\",\"name\":\"Португалски (бразилски)\"},{\"code\":\"es-419\",\"name\":\"Шпански (Латинска Америка)\"}],\"am\":[{\"code\":\"zh-cn\",\"name\":\"ቻይንኛ (ማንዳሪን)\"},{\"code\":\"hi\",\"name\":\"ሂንዲ\"},{\"code\":\"pt-br\",\"name\":\"ፖርቱጋልኛ (ብራዚላዊ)\"},{\"code\":\"es-419\",\"name\":\"ስፓኒሽ (ላቲን አሜሪካ)\"}],\"mr\":[{\"code\":\"zh-cn\",\"name\":\"चीनी (मंदारिन)\"},{\"code\":\"hi\",\"name\":\"हिंदी\"},{\"code\":\"pt-br\",\"name\":\"पोर्तुगीज (ब्राझिलियन)\"},{\"code\":\"es-419\",\"name\":\"स्पॅनिश (लॅटिन अमेरिकन)\"}],\"cs\":[{\"code\":\"zh-cn\",\"name\":\"Čínština (mandarinka)\"},{\"code\":\"hi\",\"name\":\"hindština\"},{\"code\":\"pt-br\",\"name\":\"Portugalština (brazilská)\"},{\"code\":\"es-419\",\"name\":\"Španělština (latinskoamerická)\"}],\"zh-cn\":[{\"code\":\"zh-cn\",\"name\":\"中文\"},{\"code\":\"hi\",\"name\":\"印地语\"},{\"code\":\"pt-br\",\"name\":\"葡萄牙语(巴西)\"},{\"code\":\"es-419\",\"name\":\"西班牙语(拉丁美洲)\"}],\"la\":[{\"code\":\"zh-cn\",\"name\":\"Seres (Latin)\"},{\"code\":\"hi\",\"name\":\"Hibernica\"},{\"code\":\"pt-br\",\"name\":\"Portuguese (Spanish)\"},{\"code\":\"es-419\",\"name\":\"Hispanica (Latin American)\"}],\"nn\":[{\"code\":\"zh-cn\",\"name\":\"Kinesisk (mandarin)\"},{\"code\":\"hi\",\"name\":\"hindi\"},{\"code\":\"pt-br\",\"name\":\"Portugisisk (brasiliansk)\"},{\"code\":\"es-419\",\"name\":\"Spansk (latinamerikansk)\"}],\"my\":[{\"code\":\"zh-cn\",\"name\":\"တရုတ် (တရုတ်)\"},{\"code\":\"hi\",\"name\":\"ဟိန္ဒီ\"},{\"code\":\"pt-br\",\"name\":\"ပေါ်တူဂီ (ဘရာဇီး)\"},{\"code\":\"es-419\",\"name\":\"စပိန်ဘာသာစကား (လက်တင်အမေရိက)\"}],\"ga\":[{\"code\":\"zh-cn\",\"name\":\"Sínis (Mandairínis)\"},{\"code\":\"hi\",\"name\":\"Hiondúis\"},{\"code\":\"pt-br\",\"name\":\"Portaingéilis (Brasaíle)\"},{\"code\":\"es-419\",\"name\":\"Spáinnis (Meiriceá Laidineach)\"}],\"es\":[{\"code\":\"zh-cn\",\"name\":\"Chino (Mandarín)\"},{\"code\":\"hi\",\"name\":\"hindi\"},{\"code\":\"pt-br\",\"name\":\"Portugués (brasileño)\"},{\"code\":\"es-419\",\"name\":\"Español (latinoamericano)\"}],\"nl\":[{\"code\":\"zh-cn\",\"name\":\"Chinees (Mandarijn)\"},{\"code\":\"hi\",\"name\":\"Hindi\"},{\"code\":\"pt-br\",\"name\":\"Portugees (Braziliaans)\"},{\"code\":\"es-419\",\"name\":\"Spaans (Latijns-Amerikaans)\"}],\"zh-tw\":[{\"code\":\"zh-cn\",\"name\":\"中文\"},{\"code\":\"hi\",\"name\":\"印地語\"},{\"code\":\"pt-br\",\"name\":\"葡萄牙語(巴西)\"},{\"code\":\"es-419\",\"name\":\"西班牙語(拉丁美洲)\"}],\"pt-br\":[{\"code\":\"zh-cn\",\"name\":\"Mandarim (chinês)\"},{\"code\":\"hi\",\"name\":\"hindi\"},{\"code\":\"pt-br\",\"name\":\"Português (brasileiro)\"},{\"code\":\"es-419\",\"name\":\"Espanhol (latino-americano)\"}],\"kn\":[{\"code\":\"zh-cn\",\"name\":\"ಚೈನೀಸ್ (ಮ್ಯಾಂಡರಿನ್)\"},{\"code\":\"hi\",\"name\":\"ಹಿಂದಿ\"},{\"code\":\"pt-br\",\"name\":\"ಪೋರ್ಚುಗೀಸ್ (ಬ್ರೆಜಿಲಿಯನ್)\"},{\"code\":\"es-419\",\"name\":\"ಸ್ಪ್ಯಾನಿಷ್ (ಲ್ಯಾಟಿನ್ ಅಮೇರಿಕನ್)\"}],\"uz\":[{\"code\":\"zh-cn\",\"name\":\"Xitoy (Mandarin)\"},{\"code\":\"hi\",\"name\":\"Hindcha\"},{\"code\":\"pt-br\",\"name\":\"Portugal (Braziliya)\"},{\"code\":\"es-419\",\"name\":\"Ispan (Lotin Amerikasi)\"}],\"ja\":[{\"code\":\"zh-cn\",\"name\":\"中国語(標準語)\"},{\"code\":\"hi\",\"name\":\"ヒンディー語\"},{\"code\":\"pt-br\",\"name\":\"ポルトガル語(ブラジル)\"},{\"code\":\"es-419\",\"name\":\"スペイン語(ラテンアメリカ)\"}],\"is\":[{\"code\":\"zh-cn\",\"name\":\"Kínverska (Mandarin)\"},{\"code\":\"hi\",\"name\":\"Hindí\"},{\"code\":\"pt-br\",\"name\":\"Portúgalska (brasilíska)\"},{\"code\":\"es-419\",\"name\":\"Spænska (rómönsku-ameríska)\"}],\"sk\":[{\"code\":\"zh-cn\",\"name\":\"Čínština (mandarínska)\"},{\"code\":\"hi\",\"name\":\"hindčina\"},{\"code\":\"pt-br\",\"name\":\"Portugalčina (brazílska)\"},{\"code\":\"es-419\",\"name\":\"Španielčina (latinskoamerická)\"}],\"ht\":[{\"code\":\"zh-cn\",\"name\":\"Chinwa (Mandaren)\"},{\"code\":\"hi\",\"name\":\"Hindi\"},{\"code\":\"pt-br\",\"name\":\"Pòtigè (brezilyen)\"},{\"code\":\"es-419\",\"name\":\"Panyòl (Amerik Latin)\"}],\"bg\":[{\"code\":\"zh-cn\",\"name\":\"Китайски (мандарин)\"},{\"code\":\"hi\",\"name\":\"хинди\"},{\"code\":\"pt-br\",\"name\":\"Португалски (бразилски)\"},{\"code\":\"es-419\",\"name\":\"Испански (латиноамерикански)\"}],\"de\":[{\"code\":\"zh-cn\",\"name\":\"Chinesisch (Mandarin)\"},{\"code\":\"hi\",\"name\":\"Hindi\"},{\"code\":\"pt-br\",\"name\":\"Portugiesisch (brasilianisch)\"},{\"code\":\"es-419\",\"name\":\"Spanisch (Lateinamerikanisch)\"}],\"gd\":[{\"code\":\"zh-cn\",\"name\":\"Sìneach (Mandarin)\"},{\"code\":\"hi\",\"name\":\"Indeach\"},{\"code\":\"pt-br\",\"name\":\"Portuguese (Brazilian)\"},{\"code\":\"es-419\",\"name\":\"Spàinntis (Ameireagaidh Laidinn)\"}],\"et\":[{\"code\":\"zh-cn\",\"name\":\"Hiina (mandariini)\"},{\"code\":\"hi\",\"name\":\"Hindi keel\"},{\"code\":\"pt-br\",\"name\":\"Portugali (Brasiilia)\"},{\"code\":\"es-419\",\"name\":\"Hispaania keel (Ladina-Ameerika)\"}],\"fi\":[{\"code\":\"zh-cn\",\"name\":\"Kiina (mandariini)\"},{\"code\":\"hi\",\"name\":\"hindi\"},{\"code\":\"pt-br\",\"name\":\"Portugali (brasilia)\"},{\"code\":\"es-419\",\"name\":\"Espanja (Latinalainen Amerikka)\"}],\"ar\":[{\"code\":\"zh-cn\",\"name\":\"الصينية (الماندرين)\"},{\"code\":\"hi\",\"name\":\"الهندية\"},{\"code\":\"pt-br\",\"name\":\"البرتغالية (البرازيلية)\"},{\"code\":\"es-419\",\"name\":\"الإسبانية (أمريكا اللاتينية)\"}],\"hu\":[{\"code\":\"zh-cn\",\"name\":\"Kínai (mandarin)\"},{\"code\":\"hi\",\"name\":\"hindi\"},{\"code\":\"pt-br\",\"name\":\"Portugál (brazil)\"},{\"code\":\"es-419\",\"name\":\"Spanyol (latin-amerikai)\"}],\"mt\":[{\"code\":\"zh-cn\",\"name\":\"Ċiniż (Mandarin)\"},{\"code\":\"hi\",\"name\":\"Ħindi\"},{\"code\":\"pt-br\",\"name\":\"Portugiż (Brażiljan)\"},{\"code\":\"es-419\",\"name\":\"Spanjol (Latin-Amerikan)\"}],\"ro\":[{\"code\":\"zh-cn\",\"name\":\"Chineză (mandarină)\"},{\"code\":\"hi\",\"name\":\"hindi\"},{\"code\":\"pt-br\",\"name\":\"Portugheză (braziliană)\"},{\"code\":\"es-419\",\"name\":\"Spaniolă (latino-americană)\"}],\"fa\":[{\"code\":\"zh-cn\",\"name\":\"چینی (ماندارین)\"},{\"code\":\"hi\",\"name\":\"هندی\"},{\"code\":\"pt-br\",\"name\":\"پرتغالی (برزیلی)\"},{\"code\":\"es-419\",\"name\":\"اسپانیایی (آمریکای لاتین)\"}],\"hi\":[{\"code\":\"zh-cn\",\"name\":\"चीनी (मंदारिन)\"},{\"code\":\"hi\",\"name\":\"हिन्दी\"},{\"code\":\"pt-br\",\"name\":\"पुर्तगाली (ब्राजील)\"},{\"code\":\"es-419\",\"name\":\"स्पेनिश (लैटिन अमेरिकी)\"}],\"eo\":[{\"code\":\"zh-cn\",\"name\":\"Ĉina (mandarena)\"},{\"code\":\"hi\",\"name\":\"Hinda\"},{\"code\":\"pt-br\",\"name\":\"Portugala (brazila)\"},{\"code\":\"es-419\",\"name\":\"Hispana (latina)\"}],\"lt\":[{\"code\":\"zh-cn\",\"name\":\"Kinų (mandarinų)\"},{\"code\":\"hi\",\"name\":\"Hindi\"},{\"code\":\"pt-br\",\"name\":\"Portugalų (Brazilijos)\"},{\"code\":\"es-419\",\"name\":\"Ispanų (Lotynų Amerikos)\"}],\"it\":[{\"code\":\"zh-cn\",\"name\":\"Cinese (mandarino)\"},{\"code\":\"hi\",\"name\":\"hindi\"},{\"code\":\"pt-br\",\"name\":\"Portoghese (brasiliano)\"},{\"code\":\"es-419\",\"name\":\"Spagnolo (latino-americano)\"}],\"el\":[{\"code\":\"zh-cn\",\"name\":\"Κινέζικα (μανταρινικά)\"},{\"code\":\"hi\",\"name\":\"Χίντι\"},{\"code\":\"pt-br\",\"name\":\"Πορτογαλικά (Βραζιλίας)\"},{\"code\":\"es-419\",\"name\":\"Ισπανικά (Λατινικής Αμερικής)\"}],\"mi\":[{\"code\":\"zh-cn\",\"name\":\"Hainamana (Mandarin)\"},{\"code\":\"hi\",\"name\":\"Hindi\"},{\"code\":\"pt-br\",\"name\":\"Potukua (Brazil)\"},{\"code\":\"es-419\",\"name\":\"Pāniora (Latin American)\"}],\"hr\":[{\"code\":\"zh-cn\",\"name\":\"Kineski (mandarinski)\"},{\"code\":\"hi\",\"name\":\"hindski\"},{\"code\":\"pt-br\",\"name\":\"Portugalski (brazilski)\"},{\"code\":\"es-419\",\"name\":\"Španjolski (latinoamerički)\"}],\"ca\":[{\"code\":\"zh-cn\",\"name\":\"Xinès (mandarí)\"},{\"code\":\"hi\",\"name\":\"Hindi\"},{\"code\":\"pt-br\",\"name\":\"Portuguès (brasiler)\"},{\"code\":\"es-419\",\"name\":\"Espanyol (llatinoamericà)\"}],\"th\":[{\"code\":\"zh-cn\",\"name\":\"จีน (แมนดาริน)\"},{\"code\":\"hi\",\"name\":\"ภาษาฮินดี\"},{\"code\":\"pt-br\",\"name\":\"โปรตุเกส (บราซิล)\"},{\"code\":\"es-419\",\"name\":\"สเปน (ละตินอเมริกา)\"}],\"hy\":[{\"code\":\"zh-cn\",\"name\":\"Չինարեն (մանդարին)\"},{\"code\":\"hi\",\"name\":\"Հինդի\"},{\"code\":\"pt-br\",\"name\":\"Պորտուգալերեն (բրազիլական)\"},{\"code\":\"es-419\",\"name\":\"Իսպաներեն (լատինաամերիկյան)\"}],\"id\":[{\"code\":\"zh-cn\",\"name\":\"Mandarin (Mandarin)\"},{\"code\":\"hi\",\"name\":\"Hindi\"},{\"code\":\"pt-br\",\"name\":\"Portugis (Brasil)\"},{\"code\":\"es-419\",\"name\":\"Spanyol (Amerika Latin)\"}],\"eu\":[{\"code\":\"zh-cn\",\"name\":\"Txinera (mandarina)\"},{\"code\":\"hi\",\"name\":\"Hindi\"},{\"code\":\"pt-br\",\"name\":\"Portugesa (brasildarra)\"},{\"code\":\"es-419\",\"name\":\"Espainiera (latinoamerikarra)\"}],\"da\":[{\"code\":\"zh-cn\",\"name\":\"Kinesisk (mandarin)\"},{\"code\":\"hi\",\"name\":\"Hindi\"},{\"code\":\"pt-br\",\"name\":\"Portugisisk (brasiliansk)\"},{\"code\":\"es-419\",\"name\":\"Spansk (latinamerikansk)\"}],\"ru\":[{\"code\":\"zh-cn\",\"name\":\"Китайский (мандарин)\"},{\"code\":\"hi\",\"name\":\"хинди\"},{\"code\":\"pt-br\",\"name\":\"Португальский (бразильский)\"},{\"code\":\"es-419\",\"name\":\"Испанский (латиноамериканский)\"}],\"sr\":[{\"code\":\"zh-cn\",\"name\":\"Кинески (мандарински)\"},{\"code\":\"hi\",\"name\":\"Хиндски\"},{\"code\":\"pt-br\",\"name\":\"Португалски (бразилски)\"},{\"code\":\"es-419\",\"name\":\"Шпански (латиноамерички)\"}],\"gl\":[{\"code\":\"zh-cn\",\"name\":\"Chinés (mandarín)\"},{\"code\":\"hi\",\"name\":\"Hindi\"},{\"code\":\"pt-br\",\"name\":\"Portugués (brasileiro)\"},{\"code\":\"es-419\",\"name\":\"Español (latinoamericano)\"}],\"lv\":[{\"code\":\"zh-cn\",\"name\":\"Ķīniešu (mandarīnu)\"},{\"code\":\"hi\",\"name\":\"Hindi\"},{\"code\":\"pt-br\",\"name\":\"Portugāļu (Brazīlijas)\"},{\"code\":\"es-419\",\"name\":\"Spāņu (latīņamerikāņu)\"}],\"nb\":[{\"code\":\"zh-cn\",\"name\":\"Kinesisk (mandarin)\"},{\"code\":\"hi\",\"name\":\"hindi\"},{\"code\":\"pt-br\",\"name\":\"Portugisisk (brasiliansk)\"},{\"code\":\"es-419\",\"name\":\"Spansk (latinamerikansk)\"}],\"tr\":[{\"code\":\"zh-cn\",\"name\":\"Çin (mandalinası)\"},{\"code\":\"hi\",\"name\":\"Hintçe\"},{\"code\":\"pt-br\",\"name\":\"Portekizce (Brezilya)\"},{\"code\":\"es-419\",\"name\":\"İspanyolca (Latin Amerika)\"}],\"fr\":[{\"code\":\"zh-cn\",\"name\":\"Mandarin (chinois)\"},{\"code\":\"hi\",\"name\":\"hindi\"},{\"code\":\"pt-br\",\"name\":\"Portugais (brésilien)\"},{\"code\":\"es-419\",\"name\":\"Espagnol (latino-américain)\"}],\"sv\":[{\"code\":\"zh-cn\",\"name\":\"Kinesiska (mandarin)\"},{\"code\":\"hi\",\"name\":\"Hindi\"},{\"code\":\"pt-br\",\"name\":\"Portugisiska (brasilianska)\"},{\"code\":\"es-419\",\"name\":\"Spanska (latinamerikanska)\"}],\"sl\":[{\"code\":\"zh-cn\",\"name\":\"Kitajščina (mandarina)\"},{\"code\":\"hi\",\"name\":\"Hindujščina\"},{\"code\":\"pt-br\",\"name\":\"Portugalščina (brazilska)\"},{\"code\":\"es-419\",\"name\":\"Španščina (latinskoameriška)\"}],\"ml\":[{\"code\":\"zh-cn\",\"name\":\"ചൈനീസ് (മന്ദാരിൻ)\"},{\"code\":\"hi\",\"name\":\"ഹിന്ദി\"},{\"code\":\"pt-br\",\"name\":\"പോർച്ചുഗീസ് (ബ്രസീൽ)\"},{\"code\":\"es-419\",\"name\":\"സ്പാനിഷ് (ലാറ്റിൻ അമേരിക്കൻ)\"}],\"be\":[{\"code\":\"zh-cn\",\"name\":\"Кітайская (мандарын)\"},{\"code\":\"hi\",\"name\":\"Хіндзі\"},{\"code\":\"pt-br\",\"name\":\"Партугальская (бразільскі)\"},{\"code\":\"es-419\",\"name\":\"Іспанская (лацінаамерыканская)\"}],\"pl\":[{\"code\":\"zh-cn\",\"name\":\"Chiński (mandaryński)\"},{\"code\":\"hi\",\"name\":\"hinduski\"},{\"code\":\"pt-br\",\"name\":\"Portugalski (brazylijski)\"},{\"code\":\"es-419\",\"name\":\"Hiszpański (latynoamerykański)\"}],\"pt\":[{\"code\":\"zh-cn\",\"name\":\"Mandarim (chinês)\"},{\"code\":\"hi\",\"name\":\"hindi\"},{\"code\":\"pt-br\",\"name\":\"Português (brasileiro)\"},{\"code\":\"es-419\",\"name\":\"Espanhol (latino-americano)\"}],\"ku\":[{\"code\":\"zh-cn\",\"name\":\"Chinese (Mandarin)\"},{\"code\":\"hi\",\"name\":\"Hindî\"},{\"code\":\"pt-br\",\"name\":\"Portekîz (Brazilian)\"},{\"code\":\"es-419\",\"name\":\"Spanish (Amerîkaya Latîn)\"}],\"sq\":[{\"code\":\"zh-cn\",\"name\":\"Kinezisht (Mandarin)\"},{\"code\":\"hi\",\"name\":\"Hindi\"},{\"code\":\"pt-br\",\"name\":\"Portugeze (Braziliane)\"},{\"code\":\"es-419\",\"name\":\"Spanjisht (Amerika Latine)\"}],\"ms\":[{\"code\":\"zh-cn\",\"name\":\"Cina (Mandarin)\"},{\"code\":\"hi\",\"name\":\"Hindi\"},{\"code\":\"pt-br\",\"name\":\"Portugis (Brazil)\"},{\"code\":\"es-419\",\"name\":\"Sepanyol (Amerika Latin)\"}],\"vi\":[{\"code\":\"zh-cn\",\"name\":\"Tiếng trung quốc\"},{\"code\":\"hi\",\"name\":\"Tiếng Hindi\"},{\"code\":\"pt-br\",\"name\":\"Bồ Đào Nha (Brazil)\"},{\"code\":\"es-419\",\"name\":\"Tây Ban Nha (Mỹ Latinh)\"}],\"te\":[{\"code\":\"zh-cn\",\"name\":\"చైనీస్ (మాండరిన్)\"},{\"code\":\"hi\",\"name\":\"హిందీ\"},{\"code\":\"pt-br\",\"name\":\"పోర్చుగీస్ (బ్రెజిలియన్)\"},{\"code\":\"es-419\",\"name\":\"స్పానిష్ (లాటిన్ అమెరికన్)\"}],\"uk\":[{\"code\":\"zh-cn\",\"name\":\"Китайська (мандарин)\"},{\"code\":\"hi\",\"name\":\"Хінді\"},{\"code\":\"pt-br\",\"name\":\"Португальська (бразильська)\"},{\"code\":\"es-419\",\"name\":\"Іспанська (латиноамериканська)\"}],\"mn\":[{\"code\":\"zh-cn\",\"name\":\"Хятад хэл (Мандарин)\"},{\"code\":\"hi\",\"name\":\"Хинди хэл\"},{\"code\":\"pt-br\",\"name\":\"Португал хэл (Бразил)\"},{\"code\":\"es-419\",\"name\":\"Испани хэл (Латин Америк)\"}],\"es-419\":[{\"code\":\"zh-cn\",\"name\":\"Chino (Mandarín)\"},{\"code\":\"hi\",\"name\":\"hindi\"},{\"code\":\"pt-br\",\"name\":\"Portugués (brasileño)\"},{\"code\":\"es-419\",\"name\":\"Español (latinoamericano)\"}],\"ja-hira\":[{\"code\":\"zh-cn\",\"name\":\"中国語(標準語)\"},{\"code\":\"hi\",\"name\":\"ヒンディー語\"},{\"code\":\"pt-br\",\"name\":\"ポルトガル語(ブラジル)\"},{\"code\":\"es-419\",\"name\":\"スペイン語(ラテンアメリカ)\"}]}}"); /***/ }), /***/ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/CollectingHandler.js": /*!***********************************************************************************!*\ !*** ./node_modules/scratch-vm/node_modules/htmlparser2/lib/CollectingHandler.js ***! \***********************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = CollectingHandler; function CollectingHandler(cbs){ this._cbs = cbs || {}; this.events = []; } var EVENTS = __webpack_require__(/*! ./ */ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/index.js").EVENTS; Object.keys(EVENTS).forEach(function(name){ if(EVENTS[name] === 0){ name = "on" + name; CollectingHandler.prototype[name] = function(){ this.events.push([name]); if(this._cbs[name]) this._cbs[name](); }; } else if(EVENTS[name] === 1){ name = "on" + name; CollectingHandler.prototype[name] = function(a){ this.events.push([name, a]); if(this._cbs[name]) this._cbs[name](a); }; } else if(EVENTS[name] === 2){ name = "on" + name; CollectingHandler.prototype[name] = function(a, b){ this.events.push([name, a, b]); if(this._cbs[name]) this._cbs[name](a, b); }; } else { throw Error("wrong number of arguments"); } }); CollectingHandler.prototype.onreset = function(){ this.events = []; if(this._cbs.onreset) this._cbs.onreset(); }; CollectingHandler.prototype.restart = function(){ if(this._cbs.onreset) this._cbs.onreset(); for(var i = 0, len = this.events.length; i < len; i++){ if(this._cbs[this.events[i][0]]){ var num = this.events[i].length; if(num === 1){ this._cbs[this.events[i][0]](); } else if(num === 2){ this._cbs[this.events[i][0]](this.events[i][1]); } else { this._cbs[this.events[i][0]](this.events[i][1], this.events[i][2]); } } } }; /***/ }), /***/ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/FeedHandler.js": /*!*****************************************************************************!*\ !*** ./node_modules/scratch-vm/node_modules/htmlparser2/lib/FeedHandler.js ***! \*****************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var index = __webpack_require__(/*! ./index.js */ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/index.js"); var DomHandler = index.DomHandler; var DomUtils = index.DomUtils; //TODO: make this a streamable handler function FeedHandler(callback, options){ this.init(callback, options); } __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js")(FeedHandler, DomHandler); FeedHandler.prototype.init = DomHandler; function getElements(what, where){ return DomUtils.getElementsByTagName(what, where, true); } function getOneElement(what, where){ return DomUtils.getElementsByTagName(what, where, true, 1)[0]; } function fetch(what, where, recurse){ return DomUtils.getText( DomUtils.getElementsByTagName(what, where, recurse, 1) ).trim(); } function addConditionally(obj, prop, what, where, recurse){ var tmp = fetch(what, where, recurse); if(tmp) obj[prop] = tmp; } var isValidFeed = function(value){ return value === "rss" || value === "feed" || value === "rdf:RDF"; }; FeedHandler.prototype.onend = function(){ var feed = {}, feedRoot = getOneElement(isValidFeed, this.dom), tmp, childs; if(feedRoot){ if(feedRoot.name === "feed"){ childs = feedRoot.children; feed.type = "atom"; addConditionally(feed, "id", "id", childs); addConditionally(feed, "title", "title", childs); if((tmp = getOneElement("link", childs)) && (tmp = tmp.attribs) && (tmp = tmp.href)) feed.link = tmp; addConditionally(feed, "description", "subtitle", childs); if((tmp = fetch("updated", childs))) feed.updated = new Date(tmp); addConditionally(feed, "author", "email", childs, true); feed.items = getElements("entry", childs).map(function(item){ var entry = {}, tmp; item = item.children; addConditionally(entry, "id", "id", item); addConditionally(entry, "title", "title", item); if((tmp = getOneElement("link", item)) && (tmp = tmp.attribs) && (tmp = tmp.href)) entry.link = tmp; if((tmp = fetch("summary", item) || fetch("content", item))) entry.description = tmp; if((tmp = fetch("updated", item))) entry.pubDate = new Date(tmp); return entry; }); } else { childs = getOneElement("channel", feedRoot.children).children; feed.type = feedRoot.name.substr(0, 3); feed.id = ""; addConditionally(feed, "title", "title", childs); addConditionally(feed, "link", "link", childs); addConditionally(feed, "description", "description", childs); if((tmp = fetch("lastBuildDate", childs))) feed.updated = new Date(tmp); addConditionally(feed, "author", "managingEditor", childs, true); feed.items = getElements("item", feedRoot.children).map(function(item){ var entry = {}, tmp; item = item.children; addConditionally(entry, "id", "guid", item); addConditionally(entry, "title", "title", item); addConditionally(entry, "link", "link", item); addConditionally(entry, "description", "description", item); if((tmp = fetch("pubDate", item))) entry.pubDate = new Date(tmp); return entry; }); } } this.dom = feed; DomHandler.prototype._handleCallback.call( this, feedRoot ? null : Error("couldn't find root of feed") ); }; module.exports = FeedHandler; /***/ }), /***/ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/Parser.js": /*!************************************************************************!*\ !*** ./node_modules/scratch-vm/node_modules/htmlparser2/lib/Parser.js ***! \************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var Tokenizer = __webpack_require__(/*! ./Tokenizer.js */ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/Tokenizer.js"); /* Options: xmlMode: Disables the special behavior for script/style tags (false by default) lowerCaseAttributeNames: call .toLowerCase for each attribute name (true if xmlMode is `false`) lowerCaseTags: call .toLowerCase for each tag name (true if xmlMode is `false`) */ /* Callbacks: oncdataend, oncdatastart, onclosetag, oncomment, oncommentend, onerror, onopentag, onprocessinginstruction, onreset, ontext */ var formTags = { input: true, option: true, optgroup: true, select: true, button: true, datalist: true, textarea: true }; var openImpliesClose = { tr : { tr:true, th:true, td:true }, th : { th:true }, td : { thead:true, th:true, td:true }, body : { head:true, link:true, script:true }, li : { li:true }, p : { p:true }, h1 : { p:true }, h2 : { p:true }, h3 : { p:true }, h4 : { p:true }, h5 : { p:true }, h6 : { p:true }, select : formTags, input : formTags, output : formTags, button : formTags, datalist: formTags, textarea: formTags, option : { option:true }, optgroup: { optgroup:true } }; var voidElements = { __proto__: null, area: true, base: true, basefont: true, br: true, col: true, command: true, embed: true, frame: true, hr: true, img: true, input: true, isindex: true, keygen: true, link: true, meta: true, param: true, source: true, track: true, wbr: true, }; var foreignContextElements = { __proto__: null, math: true, svg: true } var htmlIntegrationElements = { __proto__: null, mi: true, mo: true, mn: true, ms: true, mtext: true, "annotation-xml": true, foreignObject: true, desc: true, title: true } var re_nameEnd = /\s|\//; function Parser(cbs, options){ this._options = options || {}; this._cbs = cbs || {}; this._tagname = ""; this._attribname = ""; this._attribvalue = ""; this._attribs = null; this._stack = []; this._foreignContext = []; this.startIndex = 0; this.endIndex = null; this._lowerCaseTagNames = "lowerCaseTags" in this._options ? !!this._options.lowerCaseTags : !this._options.xmlMode; this._lowerCaseAttributeNames = "lowerCaseAttributeNames" in this._options ? !!this._options.lowerCaseAttributeNames : !this._options.xmlMode; if(this._options.Tokenizer) { Tokenizer = this._options.Tokenizer; } this._tokenizer = new Tokenizer(this._options, this); if(this._cbs.onparserinit) this._cbs.onparserinit(this); } __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js")(Parser, __webpack_require__(/*! events */ "./node_modules/events/events.js").EventEmitter); Parser.prototype._updatePosition = function(initialOffset){ if(this.endIndex === null){ if(this._tokenizer._sectionStart <= initialOffset){ this.startIndex = 0; } else { this.startIndex = this._tokenizer._sectionStart - initialOffset; } } else this.startIndex = this.endIndex + 1; this.endIndex = this._tokenizer.getAbsoluteIndex(); }; //Tokenizer event handlers Parser.prototype.ontext = function(data){ this._updatePosition(1); this.endIndex--; if(this._cbs.ontext) this._cbs.ontext(data); }; Parser.prototype.onopentagname = function(name){ if(this._lowerCaseTagNames){ name = name.toLowerCase(); } this._tagname = name; if(!this._options.xmlMode && name in openImpliesClose) { for( var el; (el = this._stack[this._stack.length - 1]) in openImpliesClose[name]; this.onclosetag(el) ); } if(this._options.xmlMode || !(name in voidElements)){ this._stack.push(name); if(name in foreignContextElements) this._foreignContext.push(true); else if(name in htmlIntegrationElements) this._foreignContext.push(false); } if(this._cbs.onopentagname) this._cbs.onopentagname(name); if(this._cbs.onopentag) this._attribs = {}; }; Parser.prototype.onopentagend = function(){ this._updatePosition(1); if(this._attribs){ if(this._cbs.onopentag) this._cbs.onopentag(this._tagname, this._attribs); this._attribs = null; } if(!this._options.xmlMode && this._cbs.onclosetag && this._tagname in voidElements){ this._cbs.onclosetag(this._tagname); } this._tagname = ""; }; Parser.prototype.onclosetag = function(name){ this._updatePosition(1); if(this._lowerCaseTagNames){ name = name.toLowerCase(); } if(this._stack.length && (!(name in voidElements) || this._options.xmlMode)){ var pos = this._stack.lastIndexOf(name); if(pos !== -1){ if(this._cbs.onclosetag){ pos = this._stack.length - pos; while(pos--) this._cbs.onclosetag(this._stack.pop()); } else this._stack.length = pos; } else if(name === "p" && !this._options.xmlMode){ this.onopentagname(name); this._closeCurrentTag(); } } else if(!this._options.xmlMode && (name === "br" || name === "p")){ this.onopentagname(name); this._closeCurrentTag(); } }; Parser.prototype.onselfclosingtag = function(){ if(this._options.xmlMode || this._options.recognizeSelfClosing || this._foreignContext[this._foreignContext.length - 1]){ this._closeCurrentTag(); } else { this.onopentagend(); } }; Parser.prototype._closeCurrentTag = function(){ var name = this._tagname; this.onopentagend(); //self-closing tags will be on the top of the stack //(cheaper check than in onclosetag) if(this._stack[this._stack.length - 1] === name){ if(this._cbs.onclosetag){ this._cbs.onclosetag(name); } this._stack.pop(); if((name in foreignContextElements) || (name in htmlIntegrationElements)){ this._foreignContext.pop(); } } }; Parser.prototype.onattribname = function(name){ if(this._lowerCaseAttributeNames){ name = name.toLowerCase(); } this._attribname = name; }; Parser.prototype.onattribdata = function(value){ this._attribvalue += value; }; Parser.prototype.onattribend = function(){ if(this._cbs.onattribute) this._cbs.onattribute(this._attribname, this._attribvalue); if( this._attribs && !Object.prototype.hasOwnProperty.call(this._attribs, this._attribname) ){ this._attribs[this._attribname] = this._attribvalue; } this._attribname = ""; this._attribvalue = ""; }; Parser.prototype._getInstructionName = function(value){ var idx = value.search(re_nameEnd), name = idx < 0 ? value : value.substr(0, idx); if(this._lowerCaseTagNames){ name = name.toLowerCase(); } return name; }; Parser.prototype.ondeclaration = function(value){ if(this._cbs.onprocessinginstruction){ var name = this._getInstructionName(value); this._cbs.onprocessinginstruction("!" + name, "!" + value); } }; Parser.prototype.onprocessinginstruction = function(value){ if(this._cbs.onprocessinginstruction){ var name = this._getInstructionName(value); this._cbs.onprocessinginstruction("?" + name, "?" + value); } }; Parser.prototype.oncomment = function(value){ this._updatePosition(4); if(this._cbs.oncomment) this._cbs.oncomment(value); if(this._cbs.oncommentend) this._cbs.oncommentend(); }; Parser.prototype.oncdata = function(value){ this._updatePosition(1); if(this._options.xmlMode || this._options.recognizeCDATA){ if(this._cbs.oncdatastart) this._cbs.oncdatastart(); if(this._cbs.ontext) this._cbs.ontext(value); if(this._cbs.oncdataend) this._cbs.oncdataend(); } else { this.oncomment("[CDATA[" + value + "]]"); } }; Parser.prototype.onerror = function(err){ if(this._cbs.onerror) this._cbs.onerror(err); }; Parser.prototype.onend = function(){ if(this._cbs.onclosetag){ for( var i = this._stack.length; i > 0; this._cbs.onclosetag(this._stack[--i]) ); } if(this._cbs.onend) this._cbs.onend(); }; //Resets the parser to a blank state, ready to parse a new HTML document Parser.prototype.reset = function(){ if(this._cbs.onreset) this._cbs.onreset(); this._tokenizer.reset(); this._tagname = ""; this._attribname = ""; this._attribs = null; this._stack = []; if(this._cbs.onparserinit) this._cbs.onparserinit(this); }; //Parses a complete HTML document and pushes it to the handler Parser.prototype.parseComplete = function(data){ this.reset(); this.end(data); }; Parser.prototype.write = function(chunk){ this._tokenizer.write(chunk); }; Parser.prototype.end = function(chunk){ this._tokenizer.end(chunk); }; Parser.prototype.pause = function(){ this._tokenizer.pause(); }; Parser.prototype.resume = function(){ this._tokenizer.resume(); }; //alias for backwards compat Parser.prototype.parseChunk = Parser.prototype.write; Parser.prototype.done = Parser.prototype.end; module.exports = Parser; /***/ }), /***/ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/ProxyHandler.js": /*!******************************************************************************!*\ !*** ./node_modules/scratch-vm/node_modules/htmlparser2/lib/ProxyHandler.js ***! \******************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = ProxyHandler; function ProxyHandler(cbs){ this._cbs = cbs || {}; } var EVENTS = __webpack_require__(/*! ./ */ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/index.js").EVENTS; Object.keys(EVENTS).forEach(function(name){ if(EVENTS[name] === 0){ name = "on" + name; ProxyHandler.prototype[name] = function(){ if(this._cbs[name]) this._cbs[name](); }; } else if(EVENTS[name] === 1){ name = "on" + name; ProxyHandler.prototype[name] = function(a){ if(this._cbs[name]) this._cbs[name](a); }; } else if(EVENTS[name] === 2){ name = "on" + name; ProxyHandler.prototype[name] = function(a, b){ if(this._cbs[name]) this._cbs[name](a, b); }; } else { throw Error("wrong number of arguments"); } }); /***/ }), /***/ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/Stream.js": /*!************************************************************************!*\ !*** ./node_modules/scratch-vm/node_modules/htmlparser2/lib/Stream.js ***! \************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = Stream; var Parser = __webpack_require__(/*! ./WritableStream.js */ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/WritableStream.js"); function Stream(options){ Parser.call(this, new Cbs(this), options); } __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js")(Stream, Parser); Stream.prototype.readable = true; function Cbs(scope){ this.scope = scope; } var EVENTS = __webpack_require__(/*! ../ */ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/index.js").EVENTS; Object.keys(EVENTS).forEach(function(name){ if(EVENTS[name] === 0){ Cbs.prototype["on" + name] = function(){ this.scope.emit(name); }; } else if(EVENTS[name] === 1){ Cbs.prototype["on" + name] = function(a){ this.scope.emit(name, a); }; } else if(EVENTS[name] === 2){ Cbs.prototype["on" + name] = function(a, b){ this.scope.emit(name, a, b); }; } else { throw Error("wrong number of arguments!"); } }); /***/ }), /***/ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/Tokenizer.js": /*!***************************************************************************!*\ !*** ./node_modules/scratch-vm/node_modules/htmlparser2/lib/Tokenizer.js ***! \***************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = Tokenizer; var decodeCodePoint = __webpack_require__(/*! entities/lib/decode_codepoint.js */ "./node_modules/entities/lib/decode_codepoint.js"); var entityMap = __webpack_require__(/*! entities/maps/entities.json */ "./node_modules/entities/maps/entities.json"); var legacyMap = __webpack_require__(/*! entities/maps/legacy.json */ "./node_modules/entities/maps/legacy.json"); var xmlMap = __webpack_require__(/*! entities/maps/xml.json */ "./node_modules/entities/maps/xml.json"); var i = 0; var TEXT = i++; var BEFORE_TAG_NAME = i++; //after < var IN_TAG_NAME = i++; var IN_SELF_CLOSING_TAG = i++; var BEFORE_CLOSING_TAG_NAME = i++; var IN_CLOSING_TAG_NAME = i++; var AFTER_CLOSING_TAG_NAME = i++; //attributes var BEFORE_ATTRIBUTE_NAME = i++; var IN_ATTRIBUTE_NAME = i++; var AFTER_ATTRIBUTE_NAME = i++; var BEFORE_ATTRIBUTE_VALUE = i++; var IN_ATTRIBUTE_VALUE_DQ = i++; // " var IN_ATTRIBUTE_VALUE_SQ = i++; // ' var IN_ATTRIBUTE_VALUE_NQ = i++; //declarations var BEFORE_DECLARATION = i++; // ! var IN_DECLARATION = i++; //processing instructions var IN_PROCESSING_INSTRUCTION = i++; // ? //comments var BEFORE_COMMENT = i++; var IN_COMMENT = i++; var AFTER_COMMENT_1 = i++; var AFTER_COMMENT_2 = i++; //cdata var BEFORE_CDATA_1 = i++; // [ var BEFORE_CDATA_2 = i++; // C var BEFORE_CDATA_3 = i++; // D var BEFORE_CDATA_4 = i++; // A var BEFORE_CDATA_5 = i++; // T var BEFORE_CDATA_6 = i++; // A var IN_CDATA = i++; // [ var AFTER_CDATA_1 = i++; // ] var AFTER_CDATA_2 = i++; // ] //special tags var BEFORE_SPECIAL = i++; //S var BEFORE_SPECIAL_END = i++; //S var BEFORE_SCRIPT_1 = i++; //C var BEFORE_SCRIPT_2 = i++; //R var BEFORE_SCRIPT_3 = i++; //I var BEFORE_SCRIPT_4 = i++; //P var BEFORE_SCRIPT_5 = i++; //T var AFTER_SCRIPT_1 = i++; //C var AFTER_SCRIPT_2 = i++; //R var AFTER_SCRIPT_3 = i++; //I var AFTER_SCRIPT_4 = i++; //P var AFTER_SCRIPT_5 = i++; //T var BEFORE_STYLE_1 = i++; //T var BEFORE_STYLE_2 = i++; //Y var BEFORE_STYLE_3 = i++; //L var BEFORE_STYLE_4 = i++; //E var AFTER_STYLE_1 = i++; //T var AFTER_STYLE_2 = i++; //Y var AFTER_STYLE_3 = i++; //L var AFTER_STYLE_4 = i++; //E var BEFORE_ENTITY = i++; //& var BEFORE_NUMERIC_ENTITY = i++; //# var IN_NAMED_ENTITY = i++; var IN_NUMERIC_ENTITY = i++; var IN_HEX_ENTITY = i++; //X var j = 0; var SPECIAL_NONE = j++; var SPECIAL_SCRIPT = j++; var SPECIAL_STYLE = j++; function whitespace(c){ return c === " " || c === "\n" || c === "\t" || c === "\f" || c === "\r"; } function ifElseState(upper, SUCCESS, FAILURE){ var lower = upper.toLowerCase(); if(upper === lower){ return function(c){ if(c === lower){ this._state = SUCCESS; } else { this._state = FAILURE; this._index--; } }; } else { return function(c){ if(c === lower || c === upper){ this._state = SUCCESS; } else { this._state = FAILURE; this._index--; } }; } } function consumeSpecialNameChar(upper, NEXT_STATE){ var lower = upper.toLowerCase(); return function(c){ if(c === lower || c === upper){ this._state = NEXT_STATE; } else { this._state = IN_TAG_NAME; this._index--; //consume the token again } }; } function Tokenizer(options, cbs){ this._state = TEXT; this._buffer = ""; this._sectionStart = 0; this._index = 0; this._bufferOffset = 0; //chars removed from _buffer this._baseState = TEXT; this._special = SPECIAL_NONE; this._cbs = cbs; this._running = true; this._ended = false; this._xmlMode = !!(options && options.xmlMode); this._decodeEntities = !!(options && options.decodeEntities); } Tokenizer.prototype._stateText = function(c){ if(c === "<"){ if(this._index > this._sectionStart){ this._cbs.ontext(this._getSection()); } this._state = BEFORE_TAG_NAME; this._sectionStart = this._index; } else if(this._decodeEntities && this._special === SPECIAL_NONE && c === "&"){ if(this._index > this._sectionStart){ this._cbs.ontext(this._getSection()); } this._baseState = TEXT; this._state = BEFORE_ENTITY; this._sectionStart = this._index; } }; Tokenizer.prototype._stateBeforeTagName = function(c){ if(c === "/"){ this._state = BEFORE_CLOSING_TAG_NAME; } else if(c === "<"){ this._cbs.ontext(this._getSection()); this._sectionStart = this._index; } else if(c === ">" || this._special !== SPECIAL_NONE || whitespace(c)) { this._state = TEXT; } else if(c === "!"){ this._state = BEFORE_DECLARATION; this._sectionStart = this._index + 1; } else if(c === "?"){ this._state = IN_PROCESSING_INSTRUCTION; this._sectionStart = this._index + 1; } else { this._state = (!this._xmlMode && (c === "s" || c === "S")) ? BEFORE_SPECIAL : IN_TAG_NAME; this._sectionStart = this._index; } }; Tokenizer.prototype._stateInTagName = function(c){ if(c === "/" || c === ">" || whitespace(c)){ this._emitToken("onopentagname"); this._state = BEFORE_ATTRIBUTE_NAME; this._index--; } }; Tokenizer.prototype._stateBeforeCloseingTagName = function(c){ if(whitespace(c)); else if(c === ">"){ this._state = TEXT; } else if(this._special !== SPECIAL_NONE){ if(c === "s" || c === "S"){ this._state = BEFORE_SPECIAL_END; } else { this._state = TEXT; this._index--; } } else { this._state = IN_CLOSING_TAG_NAME; this._sectionStart = this._index; } }; Tokenizer.prototype._stateInCloseingTagName = function(c){ if(c === ">" || whitespace(c)){ this._emitToken("onclosetag"); this._state = AFTER_CLOSING_TAG_NAME; this._index--; } }; Tokenizer.prototype._stateAfterCloseingTagName = function(c){ //skip everything until ">" if(c === ">"){ this._state = TEXT; this._sectionStart = this._index + 1; } }; Tokenizer.prototype._stateBeforeAttributeName = function(c){ if(c === ">"){ this._cbs.onopentagend(); this._state = TEXT; this._sectionStart = this._index + 1; } else if(c === "/"){ this._state = IN_SELF_CLOSING_TAG; } else if(!whitespace(c)){ this._state = IN_ATTRIBUTE_NAME; this._sectionStart = this._index; } }; Tokenizer.prototype._stateInSelfClosingTag = function(c){ if(c === ">"){ this._cbs.onselfclosingtag(); this._state = TEXT; this._sectionStart = this._index + 1; } else if(!whitespace(c)){ this._state = BEFORE_ATTRIBUTE_NAME; this._index--; } }; Tokenizer.prototype._stateInAttributeName = function(c){ if(c === "=" || c === "/" || c === ">" || whitespace(c)){ this._cbs.onattribname(this._getSection()); this._sectionStart = -1; this._state = AFTER_ATTRIBUTE_NAME; this._index--; } }; Tokenizer.prototype._stateAfterAttributeName = function(c){ if(c === "="){ this._state = BEFORE_ATTRIBUTE_VALUE; } else if(c === "/" || c === ">"){ this._cbs.onattribend(); this._state = BEFORE_ATTRIBUTE_NAME; this._index--; } else if(!whitespace(c)){ this._cbs.onattribend(); this._state = IN_ATTRIBUTE_NAME; this._sectionStart = this._index; } }; Tokenizer.prototype._stateBeforeAttributeValue = function(c){ if(c === "\""){ this._state = IN_ATTRIBUTE_VALUE_DQ; this._sectionStart = this._index + 1; } else if(c === "'"){ this._state = IN_ATTRIBUTE_VALUE_SQ; this._sectionStart = this._index + 1; } else if(!whitespace(c)){ this._state = IN_ATTRIBUTE_VALUE_NQ; this._sectionStart = this._index; this._index--; //reconsume token } }; Tokenizer.prototype._stateInAttributeValueDoubleQuotes = function(c){ if(c === "\""){ this._emitToken("onattribdata"); this._cbs.onattribend(); this._state = BEFORE_ATTRIBUTE_NAME; } else if(this._decodeEntities && c === "&"){ this._emitToken("onattribdata"); this._baseState = this._state; this._state = BEFORE_ENTITY; this._sectionStart = this._index; } }; Tokenizer.prototype._stateInAttributeValueSingleQuotes = function(c){ if(c === "'"){ this._emitToken("onattribdata"); this._cbs.onattribend(); this._state = BEFORE_ATTRIBUTE_NAME; } else if(this._decodeEntities && c === "&"){ this._emitToken("onattribdata"); this._baseState = this._state; this._state = BEFORE_ENTITY; this._sectionStart = this._index; } }; Tokenizer.prototype._stateInAttributeValueNoQuotes = function(c){ if(whitespace(c) || c === ">"){ this._emitToken("onattribdata"); this._cbs.onattribend(); this._state = BEFORE_ATTRIBUTE_NAME; this._index--; } else if(this._decodeEntities && c === "&"){ this._emitToken("onattribdata"); this._baseState = this._state; this._state = BEFORE_ENTITY; this._sectionStart = this._index; } }; Tokenizer.prototype._stateBeforeDeclaration = function(c){ this._state = c === "[" ? BEFORE_CDATA_1 : c === "-" ? BEFORE_COMMENT : IN_DECLARATION; }; Tokenizer.prototype._stateInDeclaration = function(c){ if(c === ">"){ this._cbs.ondeclaration(this._getSection()); this._state = TEXT; this._sectionStart = this._index + 1; } }; Tokenizer.prototype._stateInProcessingInstruction = function(c){ if(c === ">"){ this._cbs.onprocessinginstruction(this._getSection()); this._state = TEXT; this._sectionStart = this._index + 1; } }; Tokenizer.prototype._stateBeforeComment = function(c){ if(c === "-"){ this._state = IN_COMMENT; this._sectionStart = this._index + 1; } else { this._state = IN_DECLARATION; } }; Tokenizer.prototype._stateInComment = function(c){ if(c === "-") this._state = AFTER_COMMENT_1; }; Tokenizer.prototype._stateAfterComment1 = function(c){ if(c === "-"){ this._state = AFTER_COMMENT_2; } else { this._state = IN_COMMENT; } }; Tokenizer.prototype._stateAfterComment2 = function(c){ if(c === ">"){ //remove 2 trailing chars this._cbs.oncomment(this._buffer.substring(this._sectionStart, this._index - 2)); this._state = TEXT; this._sectionStart = this._index + 1; } else if(c !== "-"){ this._state = IN_COMMENT; } // else: stay in AFTER_COMMENT_2 (`--->`) }; Tokenizer.prototype._stateBeforeCdata1 = ifElseState("C", BEFORE_CDATA_2, IN_DECLARATION); Tokenizer.prototype._stateBeforeCdata2 = ifElseState("D", BEFORE_CDATA_3, IN_DECLARATION); Tokenizer.prototype._stateBeforeCdata3 = ifElseState("A", BEFORE_CDATA_4, IN_DECLARATION); Tokenizer.prototype._stateBeforeCdata4 = ifElseState("T", BEFORE_CDATA_5, IN_DECLARATION); Tokenizer.prototype._stateBeforeCdata5 = ifElseState("A", BEFORE_CDATA_6, IN_DECLARATION); Tokenizer.prototype._stateBeforeCdata6 = function(c){ if(c === "["){ this._state = IN_CDATA; this._sectionStart = this._index + 1; } else { this._state = IN_DECLARATION; this._index--; } }; Tokenizer.prototype._stateInCdata = function(c){ if(c === "]") this._state = AFTER_CDATA_1; }; Tokenizer.prototype._stateAfterCdata1 = function(c){ if(c === "]") this._state = AFTER_CDATA_2; else this._state = IN_CDATA; }; Tokenizer.prototype._stateAfterCdata2 = function(c){ if(c === ">"){ //remove 2 trailing chars this._cbs.oncdata(this._buffer.substring(this._sectionStart, this._index - 2)); this._state = TEXT; this._sectionStart = this._index + 1; } else if(c !== "]") { this._state = IN_CDATA; } //else: stay in AFTER_CDATA_2 (`]]]>`) }; Tokenizer.prototype._stateBeforeSpecial = function(c){ if(c === "c" || c === "C"){ this._state = BEFORE_SCRIPT_1; } else if(c === "t" || c === "T"){ this._state = BEFORE_STYLE_1; } else { this._state = IN_TAG_NAME; this._index--; //consume the token again } }; Tokenizer.prototype._stateBeforeSpecialEnd = function(c){ if(this._special === SPECIAL_SCRIPT && (c === "c" || c === "C")){ this._state = AFTER_SCRIPT_1; } else if(this._special === SPECIAL_STYLE && (c === "t" || c === "T")){ this._state = AFTER_STYLE_1; } else this._state = TEXT; }; Tokenizer.prototype._stateBeforeScript1 = consumeSpecialNameChar("R", BEFORE_SCRIPT_2); Tokenizer.prototype._stateBeforeScript2 = consumeSpecialNameChar("I", BEFORE_SCRIPT_3); Tokenizer.prototype._stateBeforeScript3 = consumeSpecialNameChar("P", BEFORE_SCRIPT_4); Tokenizer.prototype._stateBeforeScript4 = consumeSpecialNameChar("T", BEFORE_SCRIPT_5); Tokenizer.prototype._stateBeforeScript5 = function(c){ if(c === "/" || c === ">" || whitespace(c)){ this._special = SPECIAL_SCRIPT; } this._state = IN_TAG_NAME; this._index--; //consume the token again }; Tokenizer.prototype._stateAfterScript1 = ifElseState("R", AFTER_SCRIPT_2, TEXT); Tokenizer.prototype._stateAfterScript2 = ifElseState("I", AFTER_SCRIPT_3, TEXT); Tokenizer.prototype._stateAfterScript3 = ifElseState("P", AFTER_SCRIPT_4, TEXT); Tokenizer.prototype._stateAfterScript4 = ifElseState("T", AFTER_SCRIPT_5, TEXT); Tokenizer.prototype._stateAfterScript5 = function(c){ if(c === ">" || whitespace(c)){ this._special = SPECIAL_NONE; this._state = IN_CLOSING_TAG_NAME; this._sectionStart = this._index - 6; this._index--; //reconsume the token } else this._state = TEXT; }; Tokenizer.prototype._stateBeforeStyle1 = consumeSpecialNameChar("Y", BEFORE_STYLE_2); Tokenizer.prototype._stateBeforeStyle2 = consumeSpecialNameChar("L", BEFORE_STYLE_3); Tokenizer.prototype._stateBeforeStyle3 = consumeSpecialNameChar("E", BEFORE_STYLE_4); Tokenizer.prototype._stateBeforeStyle4 = function(c){ if(c === "/" || c === ">" || whitespace(c)){ this._special = SPECIAL_STYLE; } this._state = IN_TAG_NAME; this._index--; //consume the token again }; Tokenizer.prototype._stateAfterStyle1 = ifElseState("Y", AFTER_STYLE_2, TEXT); Tokenizer.prototype._stateAfterStyle2 = ifElseState("L", AFTER_STYLE_3, TEXT); Tokenizer.prototype._stateAfterStyle3 = ifElseState("E", AFTER_STYLE_4, TEXT); Tokenizer.prototype._stateAfterStyle4 = function(c){ if(c === ">" || whitespace(c)){ this._special = SPECIAL_NONE; this._state = IN_CLOSING_TAG_NAME; this._sectionStart = this._index - 5; this._index--; //reconsume the token } else this._state = TEXT; }; Tokenizer.prototype._stateBeforeEntity = ifElseState("#", BEFORE_NUMERIC_ENTITY, IN_NAMED_ENTITY); Tokenizer.prototype._stateBeforeNumericEntity = ifElseState("X", IN_HEX_ENTITY, IN_NUMERIC_ENTITY); //for entities terminated with a semicolon Tokenizer.prototype._parseNamedEntityStrict = function(){ //offset = 1 if(this._sectionStart + 1 < this._index){ var entity = this._buffer.substring(this._sectionStart + 1, this._index), map = this._xmlMode ? xmlMap : entityMap; if(map.hasOwnProperty(entity)){ this._emitPartial(map[entity]); this._sectionStart = this._index + 1; } } }; //parses legacy entities (without trailing semicolon) Tokenizer.prototype._parseLegacyEntity = function(){ var start = this._sectionStart + 1, limit = this._index - start; if(limit > 6) limit = 6; //the max length of legacy entities is 6 while(limit >= 2){ //the min length of legacy entities is 2 var entity = this._buffer.substr(start, limit); if(legacyMap.hasOwnProperty(entity)){ this._emitPartial(legacyMap[entity]); this._sectionStart += limit + 1; return; } else { limit--; } } }; Tokenizer.prototype._stateInNamedEntity = function(c){ if(c === ";"){ this._parseNamedEntityStrict(); if(this._sectionStart + 1 < this._index && !this._xmlMode){ this._parseLegacyEntity(); } this._state = this._baseState; } else if((c < "a" || c > "z") && (c < "A" || c > "Z") && (c < "0" || c > "9")){ if(this._xmlMode); else if(this._sectionStart + 1 === this._index); else if(this._baseState !== TEXT){ if(c !== "="){ this._parseNamedEntityStrict(); } } else { this._parseLegacyEntity(); } this._state = this._baseState; this._index--; } }; Tokenizer.prototype._decodeNumericEntity = function(offset, base){ var sectionStart = this._sectionStart + offset; if(sectionStart !== this._index){ //parse entity var entity = this._buffer.substring(sectionStart, this._index); var parsed = parseInt(entity, base); this._emitPartial(decodeCodePoint(parsed)); this._sectionStart = this._index; } else { this._sectionStart--; } this._state = this._baseState; }; Tokenizer.prototype._stateInNumericEntity = function(c){ if(c === ";"){ this._decodeNumericEntity(2, 10); this._sectionStart++; } else if(c < "0" || c > "9"){ if(!this._xmlMode){ this._decodeNumericEntity(2, 10); } else { this._state = this._baseState; } this._index--; } }; Tokenizer.prototype._stateInHexEntity = function(c){ if(c === ";"){ this._decodeNumericEntity(3, 16); this._sectionStart++; } else if((c < "a" || c > "f") && (c < "A" || c > "F") && (c < "0" || c > "9")){ if(!this._xmlMode){ this._decodeNumericEntity(3, 16); } else { this._state = this._baseState; } this._index--; } }; Tokenizer.prototype._cleanup = function (){ if(this._sectionStart < 0){ this._buffer = ""; this._bufferOffset += this._index; this._index = 0; } else if(this._running){ if(this._state === TEXT){ if(this._sectionStart !== this._index){ this._cbs.ontext(this._buffer.substr(this._sectionStart)); } this._buffer = ""; this._bufferOffset += this._index; this._index = 0; } else if(this._sectionStart === this._index){ //the section just started this._buffer = ""; this._bufferOffset += this._index; this._index = 0; } else { //remove everything unnecessary this._buffer = this._buffer.substr(this._sectionStart); this._index -= this._sectionStart; this._bufferOffset += this._sectionStart; } this._sectionStart = 0; } }; //TODO make events conditional Tokenizer.prototype.write = function(chunk){ if(this._ended) this._cbs.onerror(Error(".write() after done!")); this._buffer += chunk; this._parse(); }; Tokenizer.prototype._parse = function(){ while(this._index < this._buffer.length && this._running){ var c = this._buffer.charAt(this._index); if(this._state === TEXT) { this._stateText(c); } else if(this._state === BEFORE_TAG_NAME){ this._stateBeforeTagName(c); } else if(this._state === IN_TAG_NAME) { this._stateInTagName(c); } else if(this._state === BEFORE_CLOSING_TAG_NAME){ this._stateBeforeCloseingTagName(c); } else if(this._state === IN_CLOSING_TAG_NAME){ this._stateInCloseingTagName(c); } else if(this._state === AFTER_CLOSING_TAG_NAME){ this._stateAfterCloseingTagName(c); } else if(this._state === IN_SELF_CLOSING_TAG){ this._stateInSelfClosingTag(c); } /* * attributes */ else if(this._state === BEFORE_ATTRIBUTE_NAME){ this._stateBeforeAttributeName(c); } else if(this._state === IN_ATTRIBUTE_NAME){ this._stateInAttributeName(c); } else if(this._state === AFTER_ATTRIBUTE_NAME){ this._stateAfterAttributeName(c); } else if(this._state === BEFORE_ATTRIBUTE_VALUE){ this._stateBeforeAttributeValue(c); } else if(this._state === IN_ATTRIBUTE_VALUE_DQ){ this._stateInAttributeValueDoubleQuotes(c); } else if(this._state === IN_ATTRIBUTE_VALUE_SQ){ this._stateInAttributeValueSingleQuotes(c); } else if(this._state === IN_ATTRIBUTE_VALUE_NQ){ this._stateInAttributeValueNoQuotes(c); } /* * declarations */ else if(this._state === BEFORE_DECLARATION){ this._stateBeforeDeclaration(c); } else if(this._state === IN_DECLARATION){ this._stateInDeclaration(c); } /* * processing instructions */ else if(this._state === IN_PROCESSING_INSTRUCTION){ this._stateInProcessingInstruction(c); } /* * comments */ else if(this._state === BEFORE_COMMENT){ this._stateBeforeComment(c); } else if(this._state === IN_COMMENT){ this._stateInComment(c); } else if(this._state === AFTER_COMMENT_1){ this._stateAfterComment1(c); } else if(this._state === AFTER_COMMENT_2){ this._stateAfterComment2(c); } /* * cdata */ else if(this._state === BEFORE_CDATA_1){ this._stateBeforeCdata1(c); } else if(this._state === BEFORE_CDATA_2){ this._stateBeforeCdata2(c); } else if(this._state === BEFORE_CDATA_3){ this._stateBeforeCdata3(c); } else if(this._state === BEFORE_CDATA_4){ this._stateBeforeCdata4(c); } else if(this._state === BEFORE_CDATA_5){ this._stateBeforeCdata5(c); } else if(this._state === BEFORE_CDATA_6){ this._stateBeforeCdata6(c); } else if(this._state === IN_CDATA){ this._stateInCdata(c); } else if(this._state === AFTER_CDATA_1){ this._stateAfterCdata1(c); } else if(this._state === AFTER_CDATA_2){ this._stateAfterCdata2(c); } /* * special tags */ else if(this._state === BEFORE_SPECIAL){ this._stateBeforeSpecial(c); } else if(this._state === BEFORE_SPECIAL_END){ this._stateBeforeSpecialEnd(c); } /* * script */ else if(this._state === BEFORE_SCRIPT_1){ this._stateBeforeScript1(c); } else if(this._state === BEFORE_SCRIPT_2){ this._stateBeforeScript2(c); } else if(this._state === BEFORE_SCRIPT_3){ this._stateBeforeScript3(c); } else if(this._state === BEFORE_SCRIPT_4){ this._stateBeforeScript4(c); } else if(this._state === BEFORE_SCRIPT_5){ this._stateBeforeScript5(c); } else if(this._state === AFTER_SCRIPT_1){ this._stateAfterScript1(c); } else if(this._state === AFTER_SCRIPT_2){ this._stateAfterScript2(c); } else if(this._state === AFTER_SCRIPT_3){ this._stateAfterScript3(c); } else if(this._state === AFTER_SCRIPT_4){ this._stateAfterScript4(c); } else if(this._state === AFTER_SCRIPT_5){ this._stateAfterScript5(c); } /* * style */ else if(this._state === BEFORE_STYLE_1){ this._stateBeforeStyle1(c); } else if(this._state === BEFORE_STYLE_2){ this._stateBeforeStyle2(c); } else if(this._state === BEFORE_STYLE_3){ this._stateBeforeStyle3(c); } else if(this._state === BEFORE_STYLE_4){ this._stateBeforeStyle4(c); } else if(this._state === AFTER_STYLE_1){ this._stateAfterStyle1(c); } else if(this._state === AFTER_STYLE_2){ this._stateAfterStyle2(c); } else if(this._state === AFTER_STYLE_3){ this._stateAfterStyle3(c); } else if(this._state === AFTER_STYLE_4){ this._stateAfterStyle4(c); } /* * entities */ else if(this._state === BEFORE_ENTITY){ this._stateBeforeEntity(c); } else if(this._state === BEFORE_NUMERIC_ENTITY){ this._stateBeforeNumericEntity(c); } else if(this._state === IN_NAMED_ENTITY){ this._stateInNamedEntity(c); } else if(this._state === IN_NUMERIC_ENTITY){ this._stateInNumericEntity(c); } else if(this._state === IN_HEX_ENTITY){ this._stateInHexEntity(c); } else { this._cbs.onerror(Error("unknown _state"), this._state); } this._index++; } this._cleanup(); }; Tokenizer.prototype.pause = function(){ this._running = false; }; Tokenizer.prototype.resume = function(){ this._running = true; if(this._index < this._buffer.length){ this._parse(); } if(this._ended){ this._finish(); } }; Tokenizer.prototype.end = function(chunk){ if(this._ended) this._cbs.onerror(Error(".end() after done!")); if(chunk) this.write(chunk); this._ended = true; if(this._running) this._finish(); }; Tokenizer.prototype._finish = function(){ //if there is remaining data, emit it in a reasonable way if(this._sectionStart < this._index){ this._handleTrailingData(); } this._cbs.onend(); }; Tokenizer.prototype._handleTrailingData = function(){ var data = this._buffer.substr(this._sectionStart); if(this._state === IN_CDATA || this._state === AFTER_CDATA_1 || this._state === AFTER_CDATA_2){ this._cbs.oncdata(data); } else if(this._state === IN_COMMENT || this._state === AFTER_COMMENT_1 || this._state === AFTER_COMMENT_2){ this._cbs.oncomment(data); } else if(this._state === IN_NAMED_ENTITY && !this._xmlMode){ this._parseLegacyEntity(); if(this._sectionStart < this._index){ this._state = this._baseState; this._handleTrailingData(); } } else if(this._state === IN_NUMERIC_ENTITY && !this._xmlMode){ this._decodeNumericEntity(2, 10); if(this._sectionStart < this._index){ this._state = this._baseState; this._handleTrailingData(); } } else if(this._state === IN_HEX_ENTITY && !this._xmlMode){ this._decodeNumericEntity(3, 16); if(this._sectionStart < this._index){ this._state = this._baseState; this._handleTrailingData(); } } else if( this._state !== IN_TAG_NAME && this._state !== BEFORE_ATTRIBUTE_NAME && this._state !== BEFORE_ATTRIBUTE_VALUE && this._state !== AFTER_ATTRIBUTE_NAME && this._state !== IN_ATTRIBUTE_NAME && this._state !== IN_ATTRIBUTE_VALUE_SQ && this._state !== IN_ATTRIBUTE_VALUE_DQ && this._state !== IN_ATTRIBUTE_VALUE_NQ && this._state !== IN_CLOSING_TAG_NAME ){ this._cbs.ontext(data); } //else, ignore remaining data //TODO add a way to remove current tag }; Tokenizer.prototype.reset = function(){ Tokenizer.call(this, {xmlMode: this._xmlMode, decodeEntities: this._decodeEntities}, this._cbs); }; Tokenizer.prototype.getAbsoluteIndex = function(){ return this._bufferOffset + this._index; }; Tokenizer.prototype._getSection = function(){ return this._buffer.substring(this._sectionStart, this._index); }; Tokenizer.prototype._emitToken = function(name){ this._cbs[name](this._getSection()); this._sectionStart = -1; }; Tokenizer.prototype._emitPartial = function(value){ if(this._baseState !== TEXT){ this._cbs.onattribdata(value); //TODO implement the new event } else { this._cbs.ontext(value); } }; /***/ }), /***/ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/WritableStream.js": /*!********************************************************************************!*\ !*** ./node_modules/scratch-vm/node_modules/htmlparser2/lib/WritableStream.js ***! \********************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = Stream; var Parser = __webpack_require__(/*! ./Parser.js */ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/Parser.js"); var WritableStream = __webpack_require__(/*! readable-stream */ 5).Writable; var StringDecoder = __webpack_require__(/*! string_decoder */ "./node_modules/string_decoder/lib/string_decoder.js").StringDecoder; var Buffer = __webpack_require__(/*! buffer */ "./node_modules/buffer/index.js").Buffer; function Stream(cbs, options){ var parser = this._parser = new Parser(cbs, options); var decoder = this._decoder = new StringDecoder(); WritableStream.call(this, {decodeStrings: false}); this.once("finish", function(){ parser.end(decoder.end()); }); } __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js")(Stream, WritableStream); WritableStream.prototype._write = function(chunk, encoding, cb){ if(chunk instanceof Buffer) chunk = this._decoder.write(chunk); this._parser.write(chunk); cb(); }; /***/ }), /***/ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/index.js": /*!***********************************************************************!*\ !*** ./node_modules/scratch-vm/node_modules/htmlparser2/lib/index.js ***! \***********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var Parser = __webpack_require__(/*! ./Parser.js */ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/Parser.js"); var DomHandler = __webpack_require__(/*! domhandler */ "./node_modules/domhandler/index.js"); function defineProp(name, value){ delete module.exports[name]; module.exports[name] = value; return value; } module.exports = { Parser: Parser, Tokenizer: __webpack_require__(/*! ./Tokenizer.js */ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/Tokenizer.js"), ElementType: __webpack_require__(/*! domelementtype */ "./node_modules/domelementtype/index.js"), DomHandler: DomHandler, get FeedHandler(){ return defineProp("FeedHandler", __webpack_require__(/*! ./FeedHandler.js */ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/FeedHandler.js")); }, get Stream(){ return defineProp("Stream", __webpack_require__(/*! ./Stream.js */ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/Stream.js")); }, get WritableStream(){ return defineProp("WritableStream", __webpack_require__(/*! ./WritableStream.js */ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/WritableStream.js")); }, get ProxyHandler(){ return defineProp("ProxyHandler", __webpack_require__(/*! ./ProxyHandler.js */ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/ProxyHandler.js")); }, get DomUtils(){ return defineProp("DomUtils", __webpack_require__(/*! domutils */ "./node_modules/domutils/index.js")); }, get CollectingHandler(){ return defineProp("CollectingHandler", __webpack_require__(/*! ./CollectingHandler.js */ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/CollectingHandler.js")); }, // For legacy support DefaultHandler: DomHandler, get RssHandler(){ return defineProp("RssHandler", this.FeedHandler); }, //helper methods parseDOM: function(data, options){ var handler = new DomHandler(options); new Parser(handler, options).end(data); return handler.dom; }, parseFeed: function(feed, options){ var handler = new module.exports.FeedHandler(options); new Parser(handler, options).end(feed); return handler.dom; }, createDomStream: function(cb, options, elementCb){ var handler = new DomHandler(cb, options, elementCb); return new Parser(handler, options); }, // List of all events that the parser emits EVENTS: { /* Format: eventname: number of arguments */ attribute: 2, cdatastart: 0, cdataend: 0, text: 1, processinginstruction: 2, comment: 1, commentend: 0, closetag: 1, opentag: 2, opentagname: 1, error: 1, end: 0 } }; /***/ }), /***/ "./node_modules/scratch-vm/node_modules/worker-loader/dist/cjs.js?name=js/extension-worker/extension-worker.[hash].js!./node_modules/scratch-vm/src/extension-support/extension-worker.js": /*!************************************************************************************************************************************************************************************************!*\ !*** ./node_modules/scratch-vm/node_modules/worker-loader/dist/cjs.js?name=js/extension-worker/extension-worker.[hash].js!./node_modules/scratch-vm/src/extension-support/extension-worker.js ***! \************************************************************************************************************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = function() { return new Worker(__webpack_require__.p + "js/extension-worker/extension-worker.6862f7d9a00ef5285990.js"); }; /***/ }), /***/ "./node_modules/scratch-vm/src/blocks/scratch3_control.js": /*!****************************************************************!*\ !*** ./node_modules/scratch-vm/src/blocks/scratch3_control.js ***! \****************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const Cast = __webpack_require__(/*! ../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); class Scratch3ControlBlocks { constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; /** * The "counter" block value. For compatibility with 2.0. * @type {number} */ this._counter = 0; this.runtime.on('RUNTIME_DISPOSED', this.clearCounter.bind(this)); } /** * Retrieve the block primitives implemented by this package. * @return {object.} Mapping of opcode to Function. */ getPrimitives() { return { control_repeat: this.repeat, control_repeat_until: this.repeatUntil, control_while: this.repeatWhile, control_for_each: this.forEach, control_forever: this.forever, control_wait: this.wait, control_wait_until: this.waitUntil, control_if: this.if, control_if_else: this.ifElse, control_stop: this.stop, control_create_clone_of: this.createClone, control_delete_this_clone: this.deleteClone, control_get_counter: this.getCounter, control_incr_counter: this.incrCounter, control_clear_counter: this.clearCounter, control_all_at_once: this.allAtOnce }; } getHats() { return { control_start_as_clone: { restartExistingThreads: false } }; } repeat(args, util) { const times = Math.round(Cast.toNumber(args.TIMES)); // Initialize loop if (typeof util.stackFrame.loopCounter === 'undefined') { util.stackFrame.loopCounter = times; } // Only execute once per frame. // When the branch finishes, `repeat` will be executed again and // the second branch will be taken, yielding for the rest of the frame. // Decrease counter util.stackFrame.loopCounter--; // If we still have some left, start the branch. if (util.stackFrame.loopCounter >= 0) { util.startBranch(1, true); } } repeatUntil(args, util) { const condition = Cast.toBoolean(args.CONDITION); // If the condition is false (repeat UNTIL), start the branch. if (!condition) { util.startBranch(1, true); } } repeatWhile(args, util) { const condition = Cast.toBoolean(args.CONDITION); // If the condition is true (repeat WHILE), start the branch. if (condition) { util.startBranch(1, true); } } forEach(args, util) { const variable = util.target.lookupOrCreateVariable(args.VARIABLE.id, args.VARIABLE.name); if (typeof util.stackFrame.index === 'undefined') { util.stackFrame.index = 0; } if (util.stackFrame.index < Number(args.VALUE)) { util.stackFrame.index++; variable.value = util.stackFrame.index; util.startBranch(1, true); } } waitUntil(args, util) { const condition = Cast.toBoolean(args.CONDITION); if (!condition) { util.yield(); } } forever(args, util) { util.startBranch(1, true); } wait(args, util) { if (util.stackTimerNeedsInit()) { const duration = Math.max(0, 1000 * Cast.toNumber(args.DURATION)); util.startStackTimer(duration); this.runtime.requestRedraw(); util.yield(); } else if (!util.stackTimerFinished()) { util.yield(); } } if(args, util) { const condition = Cast.toBoolean(args.CONDITION); if (condition) { util.startBranch(1, false); } } ifElse(args, util) { const condition = Cast.toBoolean(args.CONDITION); if (condition) { util.startBranch(1, false); } else { util.startBranch(2, false); } } stop(args, util) { const option = args.STOP_OPTION; if (option === 'all') { util.stopAll(); } else if (option === 'other scripts in sprite' || option === 'other scripts in stage') { util.stopOtherTargetThreads(); } else if (option === 'this script') { util.stopThisScript(); } } createClone(args, util) { this._createClone(Cast.toString(args.CLONE_OPTION), util.target); } _createClone(cloneOption, target) { // used by compiler // Set clone target let cloneTarget; if (cloneOption === '_myself_') { cloneTarget = target; } else { cloneTarget = this.runtime.getSpriteTargetByName(cloneOption); } // If clone target is not found, return if (!cloneTarget) return; // Create clone const newClone = cloneTarget.makeClone(); if (newClone) { this.runtime.addTarget(newClone); // Place behind the original target. newClone.goBehindOther(cloneTarget); } } deleteClone(args, util) { if (util.target.isOriginal) return; this.runtime.disposeTarget(util.target); this.runtime.stopForTarget(util.target); } getCounter() { return this._counter; } clearCounter() { this._counter = 0; } incrCounter() { this._counter++; } allAtOnce(args, util) { // Since the "all at once" block is implemented for compatiblity with // Scratch 2.0 projects, it behaves the same way it did in 2.0, which // is to simply run the contained script (like "if 1 = 1"). // (In early versions of Scratch 2.0, it would work the same way as // "run without screen refresh" custom blocks do now, but this was // removed before the release of 2.0.) util.startBranch(1, false); } } module.exports = Scratch3ControlBlocks; /***/ }), /***/ "./node_modules/scratch-vm/src/blocks/scratch3_core_example.js": /*!*********************************************************************!*\ !*** ./node_modules/scratch-vm/src/blocks/scratch3_core_example.js ***! \*********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const BlockType = __webpack_require__(/*! ../extension-support/block-type */ "./node_modules/scratch-vm/src/extension-support/block-type.js"); const ArgumentType = __webpack_require__(/*! ../extension-support/argument-type */ "./node_modules/scratch-vm/src/extension-support/argument-type.js"); /* eslint-disable-next-line max-len */ const blockIconURI = 'data:image/svg+xml,%3Csvg id="rotate-counter-clockwise" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill:%233d79cc;%7D.cls-2%7Bfill:%23fff;%7D%3C/style%3E%3C/defs%3E%3Ctitle%3Erotate-counter-clockwise%3C/title%3E%3Cpath class="cls-1" d="M22.68,12.2a1.6,1.6,0,0,1-1.27.63H13.72a1.59,1.59,0,0,1-1.16-2.58l1.12-1.41a4.82,4.82,0,0,0-3.14-.77,4.31,4.31,0,0,0-2,.8,4.25,4.25,0,0,0-1.34,1.73,5.06,5.06,0,0,0,.54,4.62A5.58,5.58,0,0,0,12,17.74h0a2.26,2.26,0,0,1-.16,4.52A10.25,10.25,0,0,1,3.74,18,10.14,10.14,0,0,1,2.25,8.78,9.7,9.7,0,0,1,5.08,4.64,9.92,9.92,0,0,1,9.66,2.5a10.66,10.66,0,0,1,7.72,1.68l1.08-1.35a1.57,1.57,0,0,1,1.24-.6,1.6,1.6,0,0,1,1.54,1.21l1.7,7.37A1.57,1.57,0,0,1,22.68,12.2Z"/%3E%3Cpath class="cls-2" d="M21.38,11.83H13.77a.59.59,0,0,1-.43-1l1.75-2.19a5.9,5.9,0,0,0-4.7-1.58,5.07,5.07,0,0,0-4.11,3.17A6,6,0,0,0,7,15.77a6.51,6.51,0,0,0,5,2.92,1.31,1.31,0,0,1-.08,2.62,9.3,9.3,0,0,1-7.35-3.82A9.16,9.16,0,0,1,3.17,9.12,8.51,8.51,0,0,1,5.71,5.4,8.76,8.76,0,0,1,9.82,3.48a9.71,9.71,0,0,1,7.75,2.07l1.67-2.1a.59.59,0,0,1,1,.21L22,11.08A.59.59,0,0,1,21.38,11.83Z"/%3E%3C/svg%3E'; /** * An example core block implemented using the extension spec. * This is not loaded as part of the core blocks in the VM but it is provided * and used as part of tests. */ class Scratch3CoreExample { constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; } /** * @returns {object} metadata for this extension and its blocks. */ getInfo() { return { id: 'coreExample', name: 'CoreEx', // This string does not need to be translated as this extension is only used as an example. blocks: [{ func: 'MAKE_A_VARIABLE', blockType: BlockType.BUTTON, text: 'make a variable (CoreEx)' }, { opcode: 'exampleOpcode', blockType: BlockType.REPORTER, text: 'example block' }, { opcode: 'exampleWithInlineImage', blockType: BlockType.COMMAND, text: 'block with image [CLOCKWISE] inline', arguments: { CLOCKWISE: { type: ArgumentType.IMAGE, dataURI: blockIconURI } } }] }; } /** * Example opcode just returns the name of the stage target. * @returns {string} The name of the first target in the project. */ exampleOpcode() { const stage = this.runtime.getTargetForStage(); return stage ? stage.getName() : 'no stage yet'; } exampleWithInlineImage() { return; } } module.exports = Scratch3CoreExample; /***/ }), /***/ "./node_modules/scratch-vm/src/blocks/scratch3_data.js": /*!*************************************************************!*\ !*** ./node_modules/scratch-vm/src/blocks/scratch3_data.js ***! \*************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const Cast = __webpack_require__(/*! ../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); class Scratch3DataBlocks { constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; } /** * Retrieve the block primitives implemented by this package. * @return {object.} Mapping of opcode to Function. */ getPrimitives() { return { data_variable: this.getVariable, data_setvariableto: this.setVariableTo, data_changevariableby: this.changeVariableBy, data_hidevariable: this.hideVariable, data_showvariable: this.showVariable, data_listcontents: this.getListContents, data_addtolist: this.addToList, data_deleteoflist: this.deleteOfList, data_deletealloflist: this.deleteAllOfList, data_insertatlist: this.insertAtList, data_replaceitemoflist: this.replaceItemOfList, data_itemoflist: this.getItemOfList, data_itemnumoflist: this.getItemNumOfList, data_lengthoflist: this.lengthOfList, data_listcontainsitem: this.listContainsItem, data_hidelist: this.hideList, data_showlist: this.showList }; } getVariable(args, util) { const variable = util.target.lookupOrCreateVariable(args.VARIABLE.id, args.VARIABLE.name); return variable.value; } setVariableTo(args, util) { const variable = util.target.lookupOrCreateVariable(args.VARIABLE.id, args.VARIABLE.name); variable.value = args.VALUE; if (variable.isCloud) { util.ioQuery('cloud', 'requestUpdateVariable', [variable.name, args.VALUE]); } } changeVariableBy(args, util) { const variable = util.target.lookupOrCreateVariable(args.VARIABLE.id, args.VARIABLE.name); const castedValue = Cast.toNumber(variable.value); const dValue = Cast.toNumber(args.VALUE); const newValue = castedValue + dValue; variable.value = newValue; if (variable.isCloud) { util.ioQuery('cloud', 'requestUpdateVariable', [variable.name, newValue]); } } changeMonitorVisibility(id, visible) { // Send the monitor blocks an event like the flyout checkbox event. // This both updates the monitor state and changes the isMonitored block flag. this.runtime.monitorBlocks.changeBlock({ id: id, // Monitor blocks for variables are the variable ID. element: 'checkbox', // Mimic checkbox event from flyout. value: visible }, this.runtime); } showVariable(args) { this.changeMonitorVisibility(args.VARIABLE.id, true); } hideVariable(args) { this.changeMonitorVisibility(args.VARIABLE.id, false); } showList(args) { this.changeMonitorVisibility(args.LIST.id, true); } hideList(args) { this.changeMonitorVisibility(args.LIST.id, false); } getListContents(args, util) { const list = util.target.lookupOrCreateList(args.LIST.id, args.LIST.name); // If block is running for monitors, return copy of list as an array if changed. if (util.thread.updateMonitor) { // Return original list value if up-to-date, which doesn't trigger monitor update. if (list._monitorUpToDate) return list.value; // If value changed, reset the flag and return a copy to trigger monitor update. // Because monitors use Immutable data structures, only new objects trigger updates. list._monitorUpToDate = true; return list.value.slice(); } // Determine if the list is all single letters. // If it is, report contents joined together with no separator. // If it's not, report contents joined together with a space. let allSingleLetters = true; for (let i = 0; i < list.value.length; i++) { const listItem = list.value[i]; if (!(typeof listItem === 'string' && listItem.length === 1)) { allSingleLetters = false; break; } } if (allSingleLetters) { return list.value.join(''); } return list.value.join(' '); } addToList(args, util) { const list = util.target.lookupOrCreateList(args.LIST.id, args.LIST.name); list.value.push(args.ITEM); list._monitorUpToDate = false; } deleteOfList(args, util) { const list = util.target.lookupOrCreateList(args.LIST.id, args.LIST.name); const index = Cast.toListIndex(args.INDEX, list.value.length, true); if (index === Cast.LIST_INVALID) { return; } else if (index === Cast.LIST_ALL) { list.value = []; return; } list.value.splice(index - 1, 1); list._monitorUpToDate = false; } deleteAllOfList(args, util) { const list = util.target.lookupOrCreateList(args.LIST.id, args.LIST.name); list.value = []; return; } insertAtList(args, util) { const item = args.ITEM; const list = util.target.lookupOrCreateList(args.LIST.id, args.LIST.name); const index = Cast.toListIndex(args.INDEX, list.value.length + 1, false); if (index === Cast.LIST_INVALID) { return; } list.value.splice(index - 1, 0, item); list._monitorUpToDate = false; } replaceItemOfList(args, util) { const item = args.ITEM; const list = util.target.lookupOrCreateList(args.LIST.id, args.LIST.name); const index = Cast.toListIndex(args.INDEX, list.value.length, false); if (index === Cast.LIST_INVALID) { return; } list.value[index - 1] = item; list._monitorUpToDate = false; } getItemOfList(args, util) { const list = util.target.lookupOrCreateList(args.LIST.id, args.LIST.name); const index = Cast.toListIndex(args.INDEX, list.value.length, false); if (index === Cast.LIST_INVALID) { return ''; } return list.value[index - 1]; } getItemNumOfList(args, util) { const item = args.ITEM; const list = util.target.lookupOrCreateList(args.LIST.id, args.LIST.name); // Go through the list items one-by-one using Cast.compare. This is for // cases like checking if 123 is contained in a list [4, 7, '123'] -- // Scratch considers 123 and '123' to be equal. for (let i = 0; i < list.value.length; i++) { if (Cast.compare(list.value[i], item) === 0) { return i + 1; } } // We don't bother using .indexOf() at all, because it would end up with // edge cases such as the index of '123' in [4, 7, 123, '123', 9]. // If we use indexOf(), this block would return 4 instead of 3, because // indexOf() sees the first occurence of the string 123 as the fourth // item in the list. With Scratch, this would be confusing -- after all, // '123' and 123 look the same, so one would expect the block to say // that the first occurrence of '123' (or 123) to be the third item. // Default to 0 if there's no match. Since Scratch lists are 1-indexed, // we don't have to worry about this conflicting with the "this item is // the first value" number (in JS that is 0, but in Scratch it's 1). return 0; } lengthOfList(args, util) { const list = util.target.lookupOrCreateList(args.LIST.id, args.LIST.name); return list.value.length; } listContainsItem(args, util) { const item = args.ITEM; const list = util.target.lookupOrCreateList(args.LIST.id, args.LIST.name); if (list.value.indexOf(item) >= 0) { return true; } // Try using Scratch comparison operator on each item. // (Scratch considers the string '123' equal to the number 123). for (let i = 0; i < list.value.length; i++) { if (Cast.compare(list.value[i], item) === 0) { return true; } } return false; } } module.exports = Scratch3DataBlocks; /***/ }), /***/ "./node_modules/scratch-vm/src/blocks/scratch3_event.js": /*!**************************************************************!*\ !*** ./node_modules/scratch-vm/src/blocks/scratch3_event.js ***! \**************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const Cast = __webpack_require__(/*! ../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); class Scratch3EventBlocks { constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; this.runtime.on('KEY_PRESSED', key => { this.runtime.startHats('event_whenkeypressed', { KEY_OPTION: key }); this.runtime.startHats('event_whenkeypressed', { KEY_OPTION: 'any' }); }); } /** * Retrieve the block primitives implemented by this package. * @return {object.} Mapping of opcode to Function. */ getPrimitives() { return { event_whentouchingobject: this.touchingObject, event_broadcast: this.broadcast, event_broadcastandwait: this.broadcastAndWait, event_whengreaterthan: this.hatGreaterThanPredicate }; } getHats() { return { event_whenflagclicked: { restartExistingThreads: true }, event_whenkeypressed: { restartExistingThreads: false }, event_whenthisspriteclicked: { restartExistingThreads: true }, event_whentouchingobject: { restartExistingThreads: false, edgeActivated: true }, event_whenstageclicked: { restartExistingThreads: true }, event_whenbackdropswitchesto: { restartExistingThreads: true }, event_whengreaterthan: { restartExistingThreads: false, edgeActivated: true }, event_whenbroadcastreceived: { restartExistingThreads: true } }; } touchingObject(args, util) { return util.target.isTouchingObject(args.TOUCHINGOBJECTMENU); } hatGreaterThanPredicate(args, util) { const option = Cast.toString(args.WHENGREATERTHANMENU).toLowerCase(); const value = Cast.toNumber(args.VALUE); switch (option) { case 'timer': return util.ioQuery('clock', 'projectTimer') > value; case 'loudness': return this.runtime.audioEngine && this.runtime.audioEngine.getLoudness() > value; } return false; } broadcast(args, util) { const broadcastVar = util.runtime.getTargetForStage().lookupBroadcastMsg(args.BROADCAST_OPTION.id, args.BROADCAST_OPTION.name); if (broadcastVar) { const broadcastOption = broadcastVar.name; util.startHats('event_whenbroadcastreceived', { BROADCAST_OPTION: broadcastOption }); } } broadcastAndWait(args, util) { if (!util.stackFrame.broadcastVar) { util.stackFrame.broadcastVar = util.runtime.getTargetForStage().lookupBroadcastMsg(args.BROADCAST_OPTION.id, args.BROADCAST_OPTION.name); } if (util.stackFrame.broadcastVar) { const broadcastOption = util.stackFrame.broadcastVar.name; // Have we run before, starting threads? if (!util.stackFrame.startedThreads) { // No - start hats for this broadcast. util.stackFrame.startedThreads = util.startHats('event_whenbroadcastreceived', { BROADCAST_OPTION: broadcastOption }); if (util.stackFrame.startedThreads.length === 0) { // Nothing was started. return; } } // We've run before; check if the wait is still going on. const instance = this; // Scratch 2 considers threads to be waiting if they are still in // runtime.threads. Threads that have run all their blocks, or are // marked done but still in runtime.threads are still considered to // be waiting. const waiting = util.stackFrame.startedThreads.some(thread => instance.runtime.threads.indexOf(thread) !== -1); if (waiting) { // If all threads are waiting for the next tick or later yield // for a tick as well. Otherwise yield until the next loop of // the threads. if (util.stackFrame.startedThreads.every(thread => instance.runtime.isWaitingThread(thread))) { util.yieldTick(); } else { util.yield(); } } } } } module.exports = Scratch3EventBlocks; /***/ }), /***/ "./node_modules/scratch-vm/src/blocks/scratch3_looks.js": /*!**************************************************************!*\ !*** ./node_modules/scratch-vm/src/blocks/scratch3_looks.js ***! \**************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const Cast = __webpack_require__(/*! ../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); const Clone = __webpack_require__(/*! ../util/clone */ "./node_modules/scratch-vm/src/util/clone.js"); const RenderedTarget = __webpack_require__(/*! ../sprites/rendered-target */ "./node_modules/scratch-vm/src/sprites/rendered-target.js"); const uid = __webpack_require__(/*! ../util/uid */ "./node_modules/scratch-vm/src/util/uid.js"); const StageLayering = __webpack_require__(/*! ../engine/stage-layering */ "./node_modules/scratch-vm/src/engine/stage-layering.js"); const getMonitorIdForBlockWithArgs = __webpack_require__(/*! ../util/get-monitor-id */ "./node_modules/scratch-vm/src/util/get-monitor-id.js"); const MathUtil = __webpack_require__(/*! ../util/math-util */ "./node_modules/scratch-vm/src/util/math-util.js"); /** * @typedef {object} BubbleState - the bubble state associated with a particular target. * @property {Boolean} onSpriteRight - tracks whether the bubble is right or left of the sprite. * @property {?int} drawableId - the ID of the associated bubble Drawable, null if none. * @property {string} text - the text of the bubble. * @property {string} type - the type of the bubble, "say" or "think" * @property {?string} usageId - ID indicating the most recent usage of the say/think bubble. * Used for comparison when determining whether to clear a say/think bubble. */ class Scratch3LooksBlocks { constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; this._onTargetChanged = this._onTargetChanged.bind(this); this._onResetBubbles = this._onResetBubbles.bind(this); this._onTargetWillExit = this._onTargetWillExit.bind(this); this._updateBubble = this._updateBubble.bind(this); // Reset all bubbles on start/stop this.runtime.on('PROJECT_STOP_ALL', this._onResetBubbles); this.runtime.on('targetWasRemoved', this._onTargetWillExit); // Enable other blocks to use bubbles like ask/answer this.runtime.on(Scratch3LooksBlocks.SAY_OR_THINK, this._updateBubble); } /** * The default bubble state, to be used when a target has no existing bubble state. * @type {BubbleState} */ static get DEFAULT_BUBBLE_STATE() { return { drawableId: null, onSpriteRight: true, skinId: null, text: '', type: 'say', usageId: null }; } /** * The key to load & store a target's bubble-related state. * @type {string} */ static get STATE_KEY() { return 'Scratch.looks'; } /** * Event name for a text bubble being created or updated. * @const {string} */ static get SAY_OR_THINK() { // There are currently many places in the codebase which explicitly refer to this event by the string 'SAY', // so keep this as the string 'SAY' for now rather than changing it to 'SAY_OR_THINK' and breaking things. return 'SAY'; } /** * Limit for say bubble string. * @const {string} */ static get SAY_BUBBLE_LIMIT() { return 330; } /** * Limit for ghost effect * @const {object} */ static get EFFECT_GHOST_LIMIT() { return { min: 0, max: 100 }; } /** * Limit for brightness effect * @const {object} */ static get EFFECT_BRIGHTNESS_LIMIT() { return { min: -100, max: 100 }; } /** * @param {Target} target - collect bubble state for this target. Probably, but not necessarily, a RenderedTarget. * @returns {BubbleState} the mutable bubble state associated with that target. This will be created if necessary. * @private */ _getBubbleState(target) { let bubbleState = target.getCustomState(Scratch3LooksBlocks.STATE_KEY); if (!bubbleState) { bubbleState = Clone.simple(Scratch3LooksBlocks.DEFAULT_BUBBLE_STATE); target.setCustomState(Scratch3LooksBlocks.STATE_KEY, bubbleState); } return bubbleState; } /** * Handle a target which has moved. * @param {RenderedTarget} target - the target which has moved. * @private */ _onTargetChanged(target) { const bubbleState = this._getBubbleState(target); if (bubbleState.drawableId) { this._positionBubble(target); } } /** * Handle a target which is exiting. * @param {RenderedTarget} target - the target. * @private */ _onTargetWillExit(target) { const bubbleState = this._getBubbleState(target); if (bubbleState.drawableId && bubbleState.skinId) { this.runtime.renderer.destroyDrawable(bubbleState.drawableId, StageLayering.SPRITE_LAYER); this.runtime.renderer.destroySkin(bubbleState.skinId); bubbleState.drawableId = null; bubbleState.skinId = null; this.runtime.requestRedraw(); } target.onTargetVisualChange = null; } /** * Handle project start/stop by clearing all visible bubbles. * @private */ _onResetBubbles() { for (let n = 0; n < this.runtime.targets.length; n++) { const bubbleState = this._getBubbleState(this.runtime.targets[n]); bubbleState.text = ''; this._onTargetWillExit(this.runtime.targets[n]); } clearTimeout(this._bubbleTimeout); } /** * Position the bubble of a target. If it doesn't fit on the specified side, flip and rerender. * @param {!Target} target Target whose bubble needs positioning. * @private */ _positionBubble(target) { if (!target.visible) return; const bubbleState = this._getBubbleState(target); const [bubbleWidth, bubbleHeight] = this.runtime.renderer.getCurrentSkinSize(bubbleState.drawableId); let targetBounds; try { targetBounds = target.getBoundsForBubble(); } catch (error_) { // Bounds calculation could fail (e.g. on empty costumes), in that case // use the x/y position of the target. targetBounds = { left: target.x, right: target.x, top: target.y, bottom: target.y }; } const stageSize = this.runtime.renderer.getNativeSize(); const stageBounds = { left: -stageSize[0] / 2, right: stageSize[0] / 2, top: stageSize[1] / 2, bottom: -stageSize[1] / 2 }; if (bubbleState.onSpriteRight && bubbleWidth + targetBounds.right > stageBounds.right && targetBounds.left - bubbleWidth > stageBounds.left) { // Only flip if it would fit bubbleState.onSpriteRight = false; this._renderBubble(target); } else if (!bubbleState.onSpriteRight && targetBounds.left - bubbleWidth < stageBounds.left && bubbleWidth + targetBounds.right < stageBounds.right) { // Only flip if it would fit bubbleState.onSpriteRight = true; this._renderBubble(target); } else { this.runtime.renderer.updateDrawablePosition(bubbleState.drawableId, [bubbleState.onSpriteRight ? Math.max(stageBounds.left, // Bubble should not extend past left edge of stage Math.min(stageBounds.right - bubbleWidth, targetBounds.right)) : Math.min(stageBounds.right - bubbleWidth, // Bubble should not extend past right edge of stage Math.max(stageBounds.left, targetBounds.left - bubbleWidth)), // Bubble should not extend past the top of the stage Math.min(stageBounds.top, targetBounds.bottom + bubbleHeight)]); this.runtime.requestRedraw(); } } /** * Create a visible bubble for a target. If a bubble exists for the target, * just set it to visible and update the type/text. Otherwise create a new * bubble and update the relevant custom state. * @param {!Target} target Target who needs a bubble. * @return {undefined} Early return if text is empty string. * @private */ _renderBubble(target) { // used by compiler if (!this.runtime.renderer) return; const bubbleState = this._getBubbleState(target); const { type, text, onSpriteRight } = bubbleState; // Remove the bubble if target is not visible, or text is being set to blank. if (!target.visible || text === '') { this._onTargetWillExit(target); return; } if (bubbleState.skinId) { this.runtime.renderer.updateTextSkin(bubbleState.skinId, type, text, onSpriteRight, [0, 0]); } else { target.onTargetVisualChange = this._onTargetChanged; bubbleState.drawableId = this.runtime.renderer.createDrawable(StageLayering.SPRITE_LAYER); bubbleState.skinId = this.runtime.renderer.createTextSkin(type, text, bubbleState.onSpriteRight, [0, 0]); this.runtime.renderer.updateDrawableSkinId(bubbleState.drawableId, bubbleState.skinId); } this._positionBubble(target); } /** * Properly format text for a text bubble. * @param {string} text The text to be formatted * @return {string} The formatted text * @private */ _formatBubbleText(text) { if (text === '') return text; // Non-integers should be rounded to 2 decimal places (no more, no less), unless they're small enough that // rounding would display them as 0.00. This matches 2.0's behavior: // https://github.com/LLK/scratch-flash/blob/2e4a402ceb205a042887f54b26eebe1c2e6da6c0/src/scratch/ScratchSprite.as#L579-L585 if (typeof text === 'number' && Math.abs(text) >= 0.01 && text % 1 !== 0) { text = text.toFixed(2); } // Limit the length of the string. text = String(text).substr(0, Scratch3LooksBlocks.SAY_BUBBLE_LIMIT); return text; } /** * The entry point for say/think blocks. Clears existing bubble if the text is empty. * Set the bubble custom state and then call _renderBubble. * @param {!Target} target Target that say/think blocks are being called on. * @param {!string} type Either "say" or "think" * @param {!string} text The text for the bubble, empty string clears the bubble. * @private */ _updateBubble(target, type, text) { const bubbleState = this._getBubbleState(target); bubbleState.type = type; bubbleState.text = this._formatBubbleText(text); bubbleState.usageId = uid(); this._renderBubble(target); } /** * Retrieve the block primitives implemented by this package. * @return {object.} Mapping of opcode to Function. */ getPrimitives() { return { looks_say: this.say, looks_sayforsecs: this.sayforsecs, looks_think: this.think, looks_thinkforsecs: this.thinkforsecs, looks_show: this.show, looks_hide: this.hide, looks_hideallsprites: () => {}, // legacy no-op block looks_switchcostumeto: this.switchCostume, looks_switchbackdropto: this.switchBackdrop, looks_switchbackdroptoandwait: this.switchBackdropAndWait, looks_nextcostume: this.nextCostume, looks_nextbackdrop: this.nextBackdrop, looks_changeeffectby: this.changeEffect, looks_seteffectto: this.setEffect, looks_cleargraphiceffects: this.clearEffects, looks_changesizeby: this.changeSize, looks_setsizeto: this.setSize, looks_changestretchby: () => {}, // legacy no-op blocks looks_setstretchto: () => {}, looks_gotofrontback: this.goToFrontBack, looks_goforwardbackwardlayers: this.goForwardBackwardLayers, looks_size: this.getSize, looks_costumenumbername: this.getCostumeNumberName, looks_backdropnumbername: this.getBackdropNumberName }; } getMonitored() { return { looks_size: { isSpriteSpecific: true, getId: targetId => "".concat(targetId, "_size") }, looks_costumenumbername: { isSpriteSpecific: true, getId: (targetId, fields) => getMonitorIdForBlockWithArgs("".concat(targetId, "_costumenumbername"), fields) }, looks_backdropnumbername: { getId: (_, fields) => getMonitorIdForBlockWithArgs('backdropnumbername', fields) } }; } say(args, util) { // @TODO in 2.0 calling say/think resets the right/left bias of the bubble const message = args.MESSAGE; this._say(message, util.target); } _say(message, target) { // used by compiler this.runtime.emit(Scratch3LooksBlocks.SAY_OR_THINK, target, 'say', message); } sayforsecs(args, util) { this.say(args, util); const target = util.target; const usageId = this._getBubbleState(target).usageId; return new Promise(resolve => { this._bubbleTimeout = setTimeout(() => { this._bubbleTimeout = null; // Clear say bubble if it hasn't been changed and proceed. if (this._getBubbleState(target).usageId === usageId) { this._updateBubble(target, 'say', ''); } resolve(); }, 1000 * args.SECS); }); } think(args, util) { this.runtime.emit(Scratch3LooksBlocks.SAY_OR_THINK, util.target, 'think', args.MESSAGE); } thinkforsecs(args, util) { this.think(args, util); const target = util.target; const usageId = this._getBubbleState(target).usageId; return new Promise(resolve => { this._bubbleTimeout = setTimeout(() => { this._bubbleTimeout = null; // Clear think bubble if it hasn't been changed and proceed. if (this._getBubbleState(target).usageId === usageId) { this._updateBubble(target, 'think', ''); } resolve(); }, 1000 * args.SECS); }); } show(args, util) { util.target.setVisible(true); this._renderBubble(util.target); } hide(args, util) { util.target.setVisible(false); this._renderBubble(util.target); } /** * Utility function to set the costume of a target. * Matches the behavior of Scratch 2.0 for different types of arguments. * @param {!Target} target Target to set costume to. * @param {Any} requestedCostume Costume requested, e.g., 0, 'name', etc. * @param {boolean=} optZeroIndex Set to zero-index the requestedCostume. * @return {Array.} Any threads started by this switch. */ _setCostume(target, requestedCostume, optZeroIndex) { // used by compiler if (typeof requestedCostume === 'number') { // Numbers should be treated as costume indices, always target.setCostume(optZeroIndex ? requestedCostume : requestedCostume - 1); } else { // Strings should be treated as costume names, where possible const costumeIndex = target.getCostumeIndexByName(requestedCostume.toString()); if (costumeIndex !== -1) { target.setCostume(costumeIndex); } else if (requestedCostume === 'next costume') { target.setCostume(target.currentCostume + 1); } else if (requestedCostume === 'previous costume') { target.setCostume(target.currentCostume - 1); // Try to cast the string to a number (and treat it as a costume index) // Pure whitespace should not be treated as a number // Note: isNaN will cast the string to a number before checking if it's NaN } else if (!(isNaN(requestedCostume) || Cast.isWhiteSpace(requestedCostume))) { target.setCostume(optZeroIndex ? Number(requestedCostume) : Number(requestedCostume) - 1); } } // Per 2.0, 'switch costume' can't start threads even in the Stage. return []; } /** * Utility function to set the backdrop of a target. * Matches the behavior of Scratch 2.0 for different types of arguments. * @param {!Target} stage Target to set backdrop to. * @param {Any} requestedBackdrop Backdrop requested, e.g., 0, 'name', etc. * @param {boolean=} optZeroIndex Set to zero-index the requestedBackdrop. * @return {Array.} Any threads started by this switch. */ _setBackdrop(stage, requestedBackdrop, optZeroIndex) { // used by compiler if (typeof requestedBackdrop === 'number') { // Numbers should be treated as backdrop indices, always stage.setCostume(optZeroIndex ? requestedBackdrop : requestedBackdrop - 1); } else { // Strings should be treated as backdrop names where possible const costumeIndex = stage.getCostumeIndexByName(requestedBackdrop.toString()); if (costumeIndex !== -1) { stage.setCostume(costumeIndex); } else if (requestedBackdrop === 'next backdrop') { stage.setCostume(stage.currentCostume + 1); } else if (requestedBackdrop === 'previous backdrop') { stage.setCostume(stage.currentCostume - 1); } else if (requestedBackdrop === 'random backdrop') { const numCostumes = stage.getCostumes().length; if (numCostumes > 1) { // Don't pick the current backdrop, so that the block // will always have an observable effect. const lowerBound = 0; const upperBound = numCostumes - 1; const costumeToExclude = stage.currentCostume; const nextCostume = MathUtil.inclusiveRandIntWithout(lowerBound, upperBound, costumeToExclude); stage.setCostume(nextCostume); } // Try to cast the string to a number (and treat it as a costume index) // Pure whitespace should not be treated as a number // Note: isNaN will cast the string to a number before checking if it's NaN } else if (!(isNaN(requestedBackdrop) || Cast.isWhiteSpace(requestedBackdrop))) { stage.setCostume(optZeroIndex ? Number(requestedBackdrop) : Number(requestedBackdrop) - 1); } } const newName = stage.getCostumes()[stage.currentCostume].name; return this.runtime.startHats('event_whenbackdropswitchesto', { BACKDROP: newName }); } switchCostume(args, util) { this._setCostume(util.target, args.COSTUME); // used by compiler } nextCostume(args, util) { this._setCostume(util.target, util.target.currentCostume + 1, true); } switchBackdrop(args) { this._setBackdrop(this.runtime.getTargetForStage(), args.BACKDROP); } switchBackdropAndWait(args, util) { // Have we run before, starting threads? if (!util.stackFrame.startedThreads) { // No - switch the backdrop. util.stackFrame.startedThreads = this._setBackdrop(this.runtime.getTargetForStage(), args.BACKDROP); if (util.stackFrame.startedThreads.length === 0) { // Nothing was started. return; } } // We've run before; check if the wait is still going on. const instance = this; // Scratch 2 considers threads to be waiting if they are still in // runtime.threads. Threads that have run all their blocks, or are // marked done but still in runtime.threads are still considered to // be waiting. const waiting = util.stackFrame.startedThreads.some(thread => instance.runtime.threads.indexOf(thread) !== -1); if (waiting) { // If all threads are waiting for the next tick or later yield // for a tick as well. Otherwise yield until the next loop of // the threads. if (util.stackFrame.startedThreads.every(thread => instance.runtime.isWaitingThread(thread))) { util.yieldTick(); } else { util.yield(); } } } nextBackdrop() { const stage = this.runtime.getTargetForStage(); this._setBackdrop(stage, stage.currentCostume + 1, true); } clampEffect(effect, value) { // used by compiler let clampedValue = value; switch (effect) { case 'ghost': clampedValue = MathUtil.clamp(value, Scratch3LooksBlocks.EFFECT_GHOST_LIMIT.min, Scratch3LooksBlocks.EFFECT_GHOST_LIMIT.max); break; case 'brightness': clampedValue = MathUtil.clamp(value, Scratch3LooksBlocks.EFFECT_BRIGHTNESS_LIMIT.min, Scratch3LooksBlocks.EFFECT_BRIGHTNESS_LIMIT.max); break; } return clampedValue; } changeEffect(args, util) { const effect = Cast.toString(args.EFFECT).toLowerCase(); const change = Cast.toNumber(args.CHANGE); if (!util.target.effects.hasOwnProperty(effect)) return; let newValue = change + util.target.effects[effect]; newValue = this.clampEffect(effect, newValue); util.target.setEffect(effect, newValue); } setEffect(args, util) { const effect = Cast.toString(args.EFFECT).toLowerCase(); let value = Cast.toNumber(args.VALUE); value = this.clampEffect(effect, value); util.target.setEffect(effect, value); } clearEffects(args, util) { util.target.clearEffects(); } changeSize(args, util) { const change = Cast.toNumber(args.CHANGE); util.target.setSize(util.target.size + change); } setSize(args, util) { const size = Cast.toNumber(args.SIZE); util.target.setSize(size); } goToFrontBack(args, util) { if (!util.target.isStage) { if (args.FRONT_BACK === 'front') { util.target.goToFront(); } else { util.target.goToBack(); } } } goForwardBackwardLayers(args, util) { if (!util.target.isStage) { if (args.FORWARD_BACKWARD === 'forward') { util.target.goForwardLayers(Cast.toNumber(args.NUM)); } else { util.target.goBackwardLayers(Cast.toNumber(args.NUM)); } } } getSize(args, util) { return Math.round(util.target.size); } getBackdropNumberName(args) { const stage = this.runtime.getTargetForStage(); if (args.NUMBER_NAME === 'number') { return stage.currentCostume + 1; } // Else return name return stage.getCostumes()[stage.currentCostume].name; } getCostumeNumberName(args, util) { if (args.NUMBER_NAME === 'number') { return util.target.currentCostume + 1; } // Else return name return util.target.getCostumes()[util.target.currentCostume].name; } } module.exports = Scratch3LooksBlocks; /***/ }), /***/ "./node_modules/scratch-vm/src/blocks/scratch3_motion.js": /*!***************************************************************!*\ !*** ./node_modules/scratch-vm/src/blocks/scratch3_motion.js ***! \***************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const Cast = __webpack_require__(/*! ../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); const MathUtil = __webpack_require__(/*! ../util/math-util */ "./node_modules/scratch-vm/src/util/math-util.js"); const Timer = __webpack_require__(/*! ../util/timer */ "./node_modules/scratch-vm/src/util/timer.js"); class Scratch3MotionBlocks { constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; } /** * Retrieve the block primitives implemented by this package. * @return {object.} Mapping of opcode to Function. */ getPrimitives() { return { motion_movesteps: this.moveSteps, motion_gotoxy: this.goToXY, motion_goto: this.goTo, motion_turnright: this.turnRight, motion_turnleft: this.turnLeft, motion_pointindirection: this.pointInDirection, motion_pointtowards: this.pointTowards, motion_glidesecstoxy: this.glide, motion_glideto: this.glideTo, motion_ifonedgebounce: this.ifOnEdgeBounce, motion_setrotationstyle: this.setRotationStyle, motion_changexby: this.changeX, motion_setx: this.setX, motion_changeyby: this.changeY, motion_sety: this.setY, motion_xposition: this.getX, motion_yposition: this.getY, motion_direction: this.getDirection, // Legacy no-op blocks: motion_scroll_right: () => {}, motion_scroll_up: () => {}, motion_align_scene: () => {}, motion_xscroll: () => {}, motion_yscroll: () => {} }; } getMonitored() { return { motion_xposition: { isSpriteSpecific: true, getId: targetId => "".concat(targetId, "_xposition") }, motion_yposition: { isSpriteSpecific: true, getId: targetId => "".concat(targetId, "_yposition") }, motion_direction: { isSpriteSpecific: true, getId: targetId => "".concat(targetId, "_direction") } }; } moveSteps(args, util) { const steps = Cast.toNumber(args.STEPS); this._moveSteps(steps, util.target); } _moveSteps(steps, target) { // used by compiler const radians = MathUtil.degToRad(90 - target.direction); const dx = steps * Math.cos(radians); const dy = steps * Math.sin(radians); target.setXY(target.x + dx, target.y + dy); } goToXY(args, util) { const x = Cast.toNumber(args.X); const y = Cast.toNumber(args.Y); util.target.setXY(x, y); } getTargetXY(targetName, util) { let targetX = 0; let targetY = 0; if (targetName === '_mouse_') { targetX = util.ioQuery('mouse', 'getScratchX'); targetY = util.ioQuery('mouse', 'getScratchY'); } else if (targetName === '_random_') { const stageWidth = this.runtime.stageWidth; const stageHeight = this.runtime.stageHeight; targetX = Math.round(stageWidth * (Math.random() - 0.5)); targetY = Math.round(stageHeight * (Math.random() - 0.5)); } else { targetName = Cast.toString(targetName); const goToTarget = this.runtime.getSpriteTargetByName(targetName); if (!goToTarget) return; targetX = goToTarget.x; targetY = goToTarget.y; } return [targetX, targetY]; } goTo(args, util) { const targetXY = this.getTargetXY(args.TO, util); if (targetXY) { util.target.setXY(targetXY[0], targetXY[1]); } } turnRight(args, util) { const degrees = Cast.toNumber(args.DEGREES); util.target.setDirection(util.target.direction + degrees); } turnLeft(args, util) { const degrees = Cast.toNumber(args.DEGREES); util.target.setDirection(util.target.direction - degrees); } pointInDirection(args, util) { const direction = Cast.toNumber(args.DIRECTION); util.target.setDirection(direction); } pointTowards(args, util) { let targetX = 0; let targetY = 0; if (args.TOWARDS === '_mouse_') { targetX = util.ioQuery('mouse', 'getScratchX'); targetY = util.ioQuery('mouse', 'getScratchY'); } else if (args.TOWARDS === '_random_') { util.target.setDirection(Math.round(Math.random() * 360) - 180); return; } else { args.TOWARDS = Cast.toString(args.TOWARDS); const pointTarget = this.runtime.getSpriteTargetByName(args.TOWARDS); if (!pointTarget) return; targetX = pointTarget.x; targetY = pointTarget.y; } const dx = targetX - util.target.x; const dy = targetY - util.target.y; const direction = 90 - MathUtil.radToDeg(Math.atan2(dy, dx)); util.target.setDirection(direction); } glide(args, util) { if (util.stackFrame.timer) { const timeElapsed = util.stackFrame.timer.timeElapsed(); if (timeElapsed < util.stackFrame.duration * 1000) { // In progress: move to intermediate position. const frac = timeElapsed / (util.stackFrame.duration * 1000); const dx = frac * (util.stackFrame.endX - util.stackFrame.startX); const dy = frac * (util.stackFrame.endY - util.stackFrame.startY); util.target.setXY(util.stackFrame.startX + dx, util.stackFrame.startY + dy); util.yield(); } else { // Finished: move to final position. util.target.setXY(util.stackFrame.endX, util.stackFrame.endY); } } else { // First time: save data for future use. util.stackFrame.timer = new Timer(); util.stackFrame.timer.start(); util.stackFrame.duration = Cast.toNumber(args.SECS); util.stackFrame.startX = util.target.x; util.stackFrame.startY = util.target.y; util.stackFrame.endX = Cast.toNumber(args.X); util.stackFrame.endY = Cast.toNumber(args.Y); if (util.stackFrame.duration <= 0) { // Duration too short to glide. util.target.setXY(util.stackFrame.endX, util.stackFrame.endY); return; } util.yield(); } } glideTo(args, util) { const targetXY = this.getTargetXY(args.TO, util); if (targetXY) { this.glide({ SECS: args.SECS, X: targetXY[0], Y: targetXY[1] }, util); } } ifOnEdgeBounce(args, util) { this._ifOnEdgeBounce(util.target); } _ifOnEdgeBounce(target) { // used by compiler const bounds = target.getBounds(); if (!bounds) { return; } // Measure distance to edges. // Values are positive when the sprite is far away, // and clamped to zero when the sprite is beyond. const stageWidth = this.runtime.stageWidth; const stageHeight = this.runtime.stageHeight; const distLeft = Math.max(0, stageWidth / 2 + bounds.left); const distTop = Math.max(0, stageHeight / 2 - bounds.top); const distRight = Math.max(0, stageWidth / 2 - bounds.right); const distBottom = Math.max(0, stageHeight / 2 + bounds.bottom); // Find the nearest edge. let nearestEdge = ''; let minDist = Infinity; if (distLeft < minDist) { minDist = distLeft; nearestEdge = 'left'; } if (distTop < minDist) { minDist = distTop; nearestEdge = 'top'; } if (distRight < minDist) { minDist = distRight; nearestEdge = 'right'; } if (distBottom < minDist) { minDist = distBottom; nearestEdge = 'bottom'; } if (minDist > 0) { return; // Not touching any edge. } // Point away from the nearest edge. const radians = MathUtil.degToRad(90 - target.direction); let dx = Math.cos(radians); let dy = -Math.sin(radians); if (nearestEdge === 'left') { dx = Math.max(0.2, Math.abs(dx)); } else if (nearestEdge === 'top') { dy = Math.max(0.2, Math.abs(dy)); } else if (nearestEdge === 'right') { dx = 0 - Math.max(0.2, Math.abs(dx)); } else if (nearestEdge === 'bottom') { dy = 0 - Math.max(0.2, Math.abs(dy)); } const newDirection = MathUtil.radToDeg(Math.atan2(dy, dx)) + 90; target.setDirection(newDirection); // Keep within the stage. const fencedPosition = target.keepInFence(target.x, target.y); target.setXY(fencedPosition[0], fencedPosition[1]); } setRotationStyle(args, util) { util.target.setRotationStyle(args.STYLE); } changeX(args, util) { const dx = Cast.toNumber(args.DX); util.target.setXY(util.target.x + dx, util.target.y); } setX(args, util) { const x = Cast.toNumber(args.X); util.target.setXY(x, util.target.y); } changeY(args, util) { const dy = Cast.toNumber(args.DY); util.target.setXY(util.target.x, util.target.y + dy); } setY(args, util) { const y = Cast.toNumber(args.Y); util.target.setXY(util.target.x, y); } getX(args, util) { return this.limitPrecision(util.target.x); } getY(args, util) { return this.limitPrecision(util.target.y); } getDirection(args, util) { return util.target.direction; } // This corresponds to snapToInteger in Scratch 2 limitPrecision(coordinate) { const rounded = Math.round(coordinate); const delta = coordinate - rounded; const limitedCoord = Math.abs(delta) < 1e-9 ? rounded : coordinate; return limitedCoord; } } module.exports = Scratch3MotionBlocks; /***/ }), /***/ "./node_modules/scratch-vm/src/blocks/scratch3_operators.js": /*!******************************************************************!*\ !*** ./node_modules/scratch-vm/src/blocks/scratch3_operators.js ***! \******************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const Cast = __webpack_require__(/*! ../util/cast.js */ "./node_modules/scratch-vm/src/util/cast.js"); const MathUtil = __webpack_require__(/*! ../util/math-util.js */ "./node_modules/scratch-vm/src/util/math-util.js"); class Scratch3OperatorsBlocks { constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; } /** * Retrieve the block primitives implemented by this package. * @return {object.} Mapping of opcode to Function. */ getPrimitives() { return { operator_add: this.add, operator_subtract: this.subtract, operator_multiply: this.multiply, operator_divide: this.divide, operator_lt: this.lt, operator_equals: this.equals, operator_gt: this.gt, operator_and: this.and, operator_or: this.or, operator_not: this.not, operator_random: this.random, operator_join: this.join, operator_letter_of: this.letterOf, operator_length: this.length, operator_contains: this.contains, operator_mod: this.mod, operator_round: this.round, operator_mathop: this.mathop }; } add(args) { return Cast.toNumber(args.NUM1) + Cast.toNumber(args.NUM2); } subtract(args) { return Cast.toNumber(args.NUM1) - Cast.toNumber(args.NUM2); } multiply(args) { return Cast.toNumber(args.NUM1) * Cast.toNumber(args.NUM2); } divide(args) { return Cast.toNumber(args.NUM1) / Cast.toNumber(args.NUM2); } lt(args) { return Cast.compare(args.OPERAND1, args.OPERAND2) < 0; } equals(args) { return Cast.compare(args.OPERAND1, args.OPERAND2) === 0; } gt(args) { return Cast.compare(args.OPERAND1, args.OPERAND2) > 0; } and(args) { return Cast.toBoolean(args.OPERAND1) && Cast.toBoolean(args.OPERAND2); } or(args) { return Cast.toBoolean(args.OPERAND1) || Cast.toBoolean(args.OPERAND2); } not(args) { return !Cast.toBoolean(args.OPERAND); } random(args) { return this._random(args.FROM, args.TO); } _random(from, to) { // used by compiler const nFrom = Cast.toNumber(from); const nTo = Cast.toNumber(to); const low = nFrom <= nTo ? nFrom : nTo; const high = nFrom <= nTo ? nTo : nFrom; if (low === high) return low; // If both arguments are ints, truncate the result to an int. if (Cast.isInt(from) && Cast.isInt(to)) { return low + Math.floor(Math.random() * (high + 1 - low)); } return Math.random() * (high - low) + low; } join(args) { return Cast.toString(args.STRING1) + Cast.toString(args.STRING2); } letterOf(args) { const index = Cast.toNumber(args.LETTER) - 1; const str = Cast.toString(args.STRING); // Out of bounds? if (index < 0 || index >= str.length) { return ''; } return str.charAt(index); } length(args) { return Cast.toString(args.STRING).length; } contains(args) { const format = function format(string) { return Cast.toString(string).toLowerCase(); }; return format(args.STRING1).includes(format(args.STRING2)); } mod(args) { const n = Cast.toNumber(args.NUM1); const modulus = Cast.toNumber(args.NUM2); let result = n % modulus; // Scratch mod uses floored division instead of truncated division. if (result / modulus < 0) result += modulus; return result; } round(args) { return Math.round(Cast.toNumber(args.NUM)); } mathop(args) { const operator = Cast.toString(args.OPERATOR).toLowerCase(); const n = Cast.toNumber(args.NUM); switch (operator) { case 'abs': return Math.abs(n); case 'floor': return Math.floor(n); case 'ceiling': return Math.ceil(n); case 'sqrt': return Math.sqrt(n); case 'sin': return Math.round(Math.sin(Math.PI * n / 180) * 1e10) / 1e10; case 'cos': return Math.round(Math.cos(Math.PI * n / 180) * 1e10) / 1e10; case 'tan': return MathUtil.tan(n); case 'asin': return Math.asin(n) * 180 / Math.PI; case 'acos': return Math.acos(n) * 180 / Math.PI; case 'atan': return Math.atan(n) * 180 / Math.PI; case 'ln': return Math.log(n); case 'log': return Math.log(n) / Math.LN10; case 'e ^': return Math.exp(n); case '10 ^': return Math.pow(10, n); } return 0; } } module.exports = Scratch3OperatorsBlocks; /***/ }), /***/ "./node_modules/scratch-vm/src/blocks/scratch3_procedures.js": /*!*******************************************************************!*\ !*** ./node_modules/scratch-vm/src/blocks/scratch3_procedures.js ***! \*******************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { class Scratch3ProcedureBlocks { constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; } /** * Retrieve the block primitives implemented by this package. * @return {object.} Mapping of opcode to Function. */ getPrimitives() { return { procedures_definition: this.definition, procedures_call: this.call, argument_reporter_string_number: this.argumentReporterStringNumber, argument_reporter_boolean: this.argumentReporterBoolean }; } definition() {// No-op: execute the blocks. } call(args, util) { if (!util.stackFrame.executed) { const procedureCode = args.mutation.proccode; const paramNamesIdsAndDefaults = util.getProcedureParamNamesIdsAndDefaults(procedureCode); // If null, procedure could not be found, which can happen if custom // block is dragged between sprites without the definition. // Match Scratch 2.0 behavior and noop. if (paramNamesIdsAndDefaults === null) { return; } const [paramNames, paramIds, paramDefaults] = paramNamesIdsAndDefaults; // Initialize params for the current stackFrame to {}, even if the procedure does // not take any arguments. This is so that `getParam` down the line does not look // at earlier stack frames for the values of a given parameter (#1729) util.initParams(); for (let i = 0; i < paramIds.length; i++) { if (args.hasOwnProperty(paramIds[i])) { util.pushParam(paramNames[i], args[paramIds[i]]); } else { util.pushParam(paramNames[i], paramDefaults[i]); } } util.stackFrame.executed = true; util.startProcedure(procedureCode); } } argumentReporterStringNumber(args, util) { const value = util.getParam(args.VALUE); if (value === null) { // tw: support legacy block if (String(args.VALUE).toLowerCase() === 'last key pressed') { return util.ioQuery('keyboard', 'getLastKeyPressed'); } // When the parameter is not found in the most recent procedure // call, the default is always 0. return 0; } return value; } argumentReporterBoolean(args, util) { const value = util.getParam(args.VALUE); if (value === null) { // tw: implement is compiled? and is turbowarp? const lowercaseValue = String(args.VALUE).toLowerCase(); if (util.target.runtime.compilerOptions.enabled && lowercaseValue === 'is compiled?') { return true; } if (lowercaseValue === 'is turbowarp?') { return true; } // When the parameter is not found in the most recent procedure // call, the default is always 0. return 0; } return value; } } module.exports = Scratch3ProcedureBlocks; /***/ }), /***/ "./node_modules/scratch-vm/src/blocks/scratch3_sensing.js": /*!****************************************************************!*\ !*** ./node_modules/scratch-vm/src/blocks/scratch3_sensing.js ***! \****************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const Cast = __webpack_require__(/*! ../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); const Timer = __webpack_require__(/*! ../util/timer */ "./node_modules/scratch-vm/src/util/timer.js"); const getMonitorIdForBlockWithArgs = __webpack_require__(/*! ../util/get-monitor-id */ "./node_modules/scratch-vm/src/util/get-monitor-id.js"); class Scratch3SensingBlocks { constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; /** * The "answer" block value. * @type {string} */ this._answer = ''; // used by compiler /** * The timer utility. * @type {Timer} */ this._timer = new Timer(); /** * The stored microphone loudness measurement. * @type {number} */ this._cachedLoudness = -1; /** * The time of the most recent microphone loudness measurement. * @type {number} */ this._cachedLoudnessTimestamp = 0; /** * The list of queued questions and respective `resolve` callbacks. * @type {!Array} */ this._questionList = []; this.runtime.on('ANSWER', this._onAnswer.bind(this)); this.runtime.on('PROJECT_START', this._resetAnswer.bind(this)); this.runtime.on('PROJECT_STOP_ALL', this._clearAllQuestions.bind(this)); this.runtime.on('STOP_FOR_TARGET', this._clearTargetQuestions.bind(this)); this.runtime.on('RUNTIME_DISPOSED', this._resetAnswer.bind(this)); } /** * Retrieve the block primitives implemented by this package. * @return {object.} Mapping of opcode to Function. */ getPrimitives() { return { sensing_touchingobject: this.touchingObject, sensing_touchingcolor: this.touchingColor, sensing_coloristouchingcolor: this.colorTouchingColor, sensing_distanceto: this.distanceTo, sensing_timer: this.getTimer, sensing_resettimer: this.resetTimer, sensing_of: this.getAttributeOf, sensing_mousex: this.getMouseX, sensing_mousey: this.getMouseY, sensing_setdragmode: this.setDragMode, sensing_mousedown: this.getMouseDown, sensing_keypressed: this.getKeyPressed, sensing_current: this.current, sensing_dayssince2000: this.daysSince2000, sensing_loudness: this.getLoudness, sensing_loud: this.isLoud, sensing_askandwait: this.askAndWait, sensing_answer: this.getAnswer, sensing_username: this.getUsername, sensing_userid: () => {} // legacy no-op block }; } getMonitored() { return { sensing_answer: { getId: () => 'answer' }, sensing_mousedown: { getId: () => 'mousedown' }, sensing_mousex: { getId: () => 'mousex' }, sensing_mousey: { getId: () => 'mousey' }, sensing_loudness: { getId: () => 'loudness' }, sensing_timer: { getId: () => 'timer' }, sensing_dayssince2000: { getId: () => 'dayssince2000' }, sensing_current: { // This is different from the default toolbox xml id in order to support // importing multiple monitors from the same opcode from sb2 files, // something that is not currently supported in scratch 3. getId: (_, fields) => getMonitorIdForBlockWithArgs('current', fields) // _${param}` } }; } _onAnswer(answer) { this._answer = answer; const questionObj = this._questionList.shift(); if (questionObj) { const [_question, resolve, target, wasVisible, wasStage] = questionObj; // If the target was visible when asked, hide the say bubble unless the target was the stage. if (wasVisible && !wasStage) { this.runtime.emit('SAY', target, 'say', ''); } resolve(); this._askNextQuestion(); } } _resetAnswer() { this._answer = ''; } _enqueueAsk(question, resolve, target, wasVisible, wasStage) { this._questionList.push([question, resolve, target, wasVisible, wasStage]); } _askNextQuestion() { if (this._questionList.length > 0) { const [question, _resolve, target, wasVisible, wasStage] = this._questionList[0]; // If the target is visible, emit a blank question and use the // say event to trigger a bubble unless the target was the stage. if (wasVisible && !wasStage) { this.runtime.emit('SAY', target, 'say', question); this.runtime.emit('QUESTION', ''); } else { this.runtime.emit('QUESTION', question); } } } _clearAllQuestions() { this._questionList = []; this.runtime.emit('QUESTION', null); } _clearTargetQuestions(stopTarget) { const currentlyAsking = this._questionList.length > 0 && this._questionList[0][2] === stopTarget; this._questionList = this._questionList.filter(question => question[2] !== stopTarget); if (currentlyAsking) { this.runtime.emit('SAY', stopTarget, 'say', ''); if (this._questionList.length > 0) { this._askNextQuestion(); } else { this.runtime.emit('QUESTION', null); } } } askAndWait(args, util) { const _target = util.target; return new Promise(resolve => { const isQuestionAsked = this._questionList.length > 0; this._enqueueAsk(String(args.QUESTION), resolve, _target, _target.visible, _target.isStage); if (!isQuestionAsked) { this._askNextQuestion(); } }); } getAnswer() { return this._answer; } touchingObject(args, util) { return util.target.isTouchingObject(args.TOUCHINGOBJECTMENU); } touchingColor(args, util) { const color = Cast.toRgbColorList(args.COLOR); return util.target.isTouchingColor(color); } colorTouchingColor(args, util) { const maskColor = Cast.toRgbColorList(args.COLOR); const targetColor = Cast.toRgbColorList(args.COLOR2); return util.target.colorIsTouchingColor(targetColor, maskColor); } distanceTo(args, util) { if (util.target.isStage) return 10000; let targetX = 0; let targetY = 0; if (args.DISTANCETOMENU === '_mouse_') { targetX = util.ioQuery('mouse', 'getScratchX'); targetY = util.ioQuery('mouse', 'getScratchY'); } else { args.DISTANCETOMENU = Cast.toString(args.DISTANCETOMENU); const distTarget = this.runtime.getSpriteTargetByName(args.DISTANCETOMENU); if (!distTarget) return 10000; targetX = distTarget.x; targetY = distTarget.y; } const dx = util.target.x - targetX; const dy = util.target.y - targetY; return Math.sqrt(dx * dx + dy * dy); } setDragMode(args, util) { util.target.setDraggable(args.DRAG_MODE === 'draggable'); } getTimer(args, util) { return util.ioQuery('clock', 'projectTimer'); } resetTimer(args, util) { util.ioQuery('clock', 'resetProjectTimer'); } getMouseX(args, util) { return util.ioQuery('mouse', 'getScratchX'); } getMouseY(args, util) { return util.ioQuery('mouse', 'getScratchY'); } getMouseDown(args, util) { return util.ioQuery('mouse', 'getIsDown'); } current(args) { const menuOption = Cast.toString(args.CURRENTMENU).toLowerCase(); const date = new Date(); switch (menuOption) { case 'year': return date.getFullYear(); case 'month': return date.getMonth() + 1; // getMonth is zero-based case 'date': return date.getDate(); case 'dayofweek': return date.getDay() + 1; // getDay is zero-based, Sun=0 case 'hour': return date.getHours(); case 'minute': return date.getMinutes(); case 'second': return date.getSeconds(); } return 0; } getKeyPressed(args, util) { return util.ioQuery('keyboard', 'getKeyIsDown', [args.KEY_OPTION]); } daysSince2000() { const msPerDay = 24 * 60 * 60 * 1000; const start = new Date(2000, 0, 1); // Months are 0-indexed. const today = new Date(); const dstAdjust = today.getTimezoneOffset() - start.getTimezoneOffset(); let mSecsSinceStart = today.valueOf() - start.valueOf(); mSecsSinceStart += (today.getTimezoneOffset() - dstAdjust) * 60 * 1000; return mSecsSinceStart / msPerDay; } getLoudness() { if (typeof this.runtime.audioEngine === 'undefined') return -1; if (this.runtime.currentStepTime === null) return -1; // Only measure loudness once per step const timeSinceLoudness = this._timer.time() - this._cachedLoudnessTimestamp; if (timeSinceLoudness < this.runtime.currentStepTime) { return this._cachedLoudness; } this._cachedLoudnessTimestamp = this._timer.time(); this._cachedLoudness = this.runtime.audioEngine.getLoudness(); return this._cachedLoudness; } isLoud() { return this.getLoudness() > 10; } getAttributeOf(args) { let attrTarget; if (args.OBJECT === '_stage_') { attrTarget = this.runtime.getTargetForStage(); } else { args.OBJECT = Cast.toString(args.OBJECT); attrTarget = this.runtime.getSpriteTargetByName(args.OBJECT); } // attrTarget can be undefined if the target does not exist // (e.g. single sprite uploaded from larger project referencing // another sprite that wasn't uploaded) if (!attrTarget) return 0; // Generic attributes if (attrTarget.isStage) { switch (args.PROPERTY) { // Scratch 1.4 support case 'background #': return attrTarget.currentCostume + 1; case 'backdrop #': return attrTarget.currentCostume + 1; case 'backdrop name': return attrTarget.getCostumes()[attrTarget.currentCostume].name; case 'volume': return attrTarget.volume; } } else { switch (args.PROPERTY) { case 'x position': return attrTarget.x; case 'y position': return attrTarget.y; case 'direction': return attrTarget.direction; case 'costume #': return attrTarget.currentCostume + 1; case 'costume name': return attrTarget.getCostumes()[attrTarget.currentCostume].name; case 'size': return attrTarget.size; case 'volume': return attrTarget.volume; } } // Target variables. const varName = args.PROPERTY; const variable = attrTarget.lookupVariableByNameAndType(varName, '', true); if (variable) { return variable.value; } // Otherwise, 0 return 0; } getUsername(args, util) { return util.ioQuery('userData', 'getUsername'); } } module.exports = Scratch3SensingBlocks; /***/ }), /***/ "./node_modules/scratch-vm/src/blocks/scratch3_sound.js": /*!**************************************************************!*\ !*** ./node_modules/scratch-vm/src/blocks/scratch3_sound.js ***! \**************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const MathUtil = __webpack_require__(/*! ../util/math-util */ "./node_modules/scratch-vm/src/util/math-util.js"); const Cast = __webpack_require__(/*! ../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); const Clone = __webpack_require__(/*! ../util/clone */ "./node_modules/scratch-vm/src/util/clone.js"); /** * Occluded boolean value to make its use more understandable. * @const {boolean} */ const STORE_WAITING = true; class Scratch3SoundBlocks { constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; this.waitingSounds = {}; // Clear sound effects on green flag and stop button events. this.stopAllSounds = this.stopAllSounds.bind(this); this._stopWaitingSoundsForTarget = this._stopWaitingSoundsForTarget.bind(this); this._clearEffectsForAllTargets = this._clearEffectsForAllTargets.bind(this); if (this.runtime) { this.runtime.on('PROJECT_STOP_ALL', this.stopAllSounds); this.runtime.on('PROJECT_STOP_ALL', this._clearEffectsForAllTargets); this.runtime.on('STOP_FOR_TARGET', this._stopWaitingSoundsForTarget); this.runtime.on('PROJECT_START', this._clearEffectsForAllTargets); } this._onTargetCreated = this._onTargetCreated.bind(this); if (this.runtime) { runtime.on('targetWasCreated', this._onTargetCreated); } } /** * The key to load & store a target's sound-related state. * @type {string} */ static get STATE_KEY() { return 'Scratch.sound'; } /** * The default sound-related state, to be used when a target has no existing sound state. * @type {SoundState} */ static get DEFAULT_SOUND_STATE() { return { effects: { pitch: 0, pan: 0 } }; } /** * The minimum and maximum MIDI note numbers, for clamping the input to play note. * @type {{min: number, max: number}} */ static get MIDI_NOTE_RANGE() { return { min: 36, max: 96 }; // C2 to C7 } /** * The minimum and maximum beat values, for clamping the duration of play note, play drum and rest. * 100 beats at the default tempo of 60bpm is 100 seconds. * @type {{min: number, max: number}} */ static get BEAT_RANGE() { return { min: 0, max: 100 }; } /** The minimum and maximum tempo values, in bpm. * @type {{min: number, max: number}} */ static get TEMPO_RANGE() { return { min: 20, max: 500 }; } /** The minimum and maximum values for each sound effect. * @type {{effect:{min: number, max: number}}} */ static get EFFECT_RANGE() { return { pitch: { min: -360, max: 360 }, // -3 to 3 octaves pan: { min: -100, max: 100 } // 100% left to 100% right }; } /** The minimum and maximum values for sound effects when miscellaneous limits are removed. */ static get LARGER_EFFECT_RANGE() { return { // scratch-audio throws if pitch is too big because some math results in Infinity pitch: { min: -1000, max: 1000 }, // No reason for these to go beyond 100 pan: { min: -100, max: 100 } }; } /** * @param {Target} target - collect sound state for this target. * @returns {SoundState} the mutable sound state associated with that target. This will be created if necessary. * @private */ _getSoundState(target) { let soundState = target.getCustomState(Scratch3SoundBlocks.STATE_KEY); if (!soundState) { soundState = Clone.simple(Scratch3SoundBlocks.DEFAULT_SOUND_STATE); target.setCustomState(Scratch3SoundBlocks.STATE_KEY, soundState); target.soundEffects = soundState.effects; } return soundState; } /** * When a Target is cloned, clone the sound state. * @param {Target} newTarget - the newly created target. * @param {Target} [sourceTarget] - the target used as a source for the new clone, if any. * @listens Runtime#event:targetWasCreated * @private */ _onTargetCreated(newTarget, sourceTarget) { if (sourceTarget) { const soundState = sourceTarget.getCustomState(Scratch3SoundBlocks.STATE_KEY); if (soundState && newTarget) { newTarget.setCustomState(Scratch3SoundBlocks.STATE_KEY, Clone.simple(soundState)); this._syncEffectsForTarget(newTarget); } } } /** * Retrieve the block primitives implemented by this package. * @return {object.} Mapping of opcode to Function. */ getPrimitives() { return { sound_play: this.playSound, sound_playuntildone: this.playSoundAndWait, sound_stopallsounds: this.stopAllSounds, sound_seteffectto: this.setEffect, sound_changeeffectby: this.changeEffect, sound_cleareffects: this.clearEffects, sound_sounds_menu: this.soundsMenu, sound_beats_menu: this.beatsMenu, sound_effects_menu: this.effectsMenu, sound_setvolumeto: this.setVolume, sound_changevolumeby: this.changeVolume, sound_volume: this.getVolume }; } getMonitored() { return { sound_volume: { isSpriteSpecific: true, getId: targetId => "".concat(targetId, "_volume") } }; } playSound(args, util) { // Don't return the promise, it's the only difference for AndWait this._playSound(args, util); } playSoundAndWait(args, util) { return this._playSound(args, util, STORE_WAITING); } _playSound(args, util, storeWaiting) { const index = this._getSoundIndex(args.SOUND_MENU, util); if (index >= 0) { const { target } = util; const { sprite } = target; const { soundId } = sprite.sounds[index]; if (sprite.soundBank) { if (storeWaiting === STORE_WAITING) { this._addWaitingSound(target.id, soundId); } else { this._removeWaitingSound(target.id, soundId); } return sprite.soundBank.playSound(target, soundId); } } } _addWaitingSound(targetId, soundId) { if (!this.waitingSounds[targetId]) { this.waitingSounds[targetId] = new Set(); } this.waitingSounds[targetId].add(soundId); } _removeWaitingSound(targetId, soundId) { if (!this.waitingSounds[targetId]) { return; } this.waitingSounds[targetId].delete(soundId); } _getSoundIndex(soundName, util) { // if the sprite has no sounds, return -1 const len = util.target.sprite.sounds.length; if (len === 0) { return -1; } // look up by name first const index = this.getSoundIndexByName(soundName, util); if (index !== -1) { return index; } // then try using the sound name as a 1-indexed index const oneIndexedIndex = parseInt(soundName, 10); if (!isNaN(oneIndexedIndex)) { return MathUtil.wrapClamp(oneIndexedIndex - 1, 0, len - 1); } // could not be found as a name or converted to index, return -1 return -1; } getSoundIndexByName(soundName, util) { const sounds = util.target.sprite.sounds; for (let i = 0; i < sounds.length; i++) { if (sounds[i].name === soundName) { return i; } } // if there is no sound by that name, return -1 return -1; } stopAllSounds() { if (this.runtime.targets === null) return; const allTargets = this.runtime.targets; for (let i = 0; i < allTargets.length; i++) { this._stopAllSoundsForTarget(allTargets[i]); } } _stopAllSoundsForTarget(target) { if (target.sprite.soundBank) { target.sprite.soundBank.stopAllSounds(target); if (this.waitingSounds[target.id]) { this.waitingSounds[target.id].clear(); } } } _stopWaitingSoundsForTarget(target) { if (target.sprite.soundBank) { if (this.waitingSounds[target.id]) { for (const soundId of this.waitingSounds[target.id].values()) { target.sprite.soundBank.stop(target, soundId); } this.waitingSounds[target.id].clear(); } } } setEffect(args, util) { return this._updateEffect(args, util, false); } changeEffect(args, util) { return this._updateEffect(args, util, true); } _updateEffect(args, util, change) { const effect = Cast.toString(args.EFFECT).toLowerCase(); const value = Cast.toNumber(args.VALUE); const soundState = this._getSoundState(util.target); if (!soundState.effects.hasOwnProperty(effect)) return; if (change) { soundState.effects[effect] += value; } else { soundState.effects[effect] = value; } const miscLimits = this.runtime.runtimeOptions.miscLimits; const { min, max } = miscLimits ? Scratch3SoundBlocks.EFFECT_RANGE[effect] : Scratch3SoundBlocks.LARGER_EFFECT_RANGE[effect]; soundState.effects[effect] = MathUtil.clamp(soundState.effects[effect], min, max); this._syncEffectsForTarget(util.target); if (miscLimits) { // Yield until the next tick. return Promise.resolve(); } // Requesting a redraw makes sure that "forever: change pitch by 1" still work but without // yielding unnecessarily in other cases this.runtime.requestRedraw(); } _syncEffectsForTarget(target) { if (!target || !target.sprite.soundBank) return; target.soundEffects = this._getSoundState(target).effects; target.sprite.soundBank.setEffects(target); } clearEffects(args, util) { this._clearEffectsForTarget(util.target); } _clearEffectsForTarget(target) { const soundState = this._getSoundState(target); for (const effect in soundState.effects) { if (!soundState.effects.hasOwnProperty(effect)) continue; soundState.effects[effect] = 0; } this._syncEffectsForTarget(target); } _clearEffectsForAllTargets() { if (this.runtime.targets === null) return; const allTargets = this.runtime.targets; for (let i = 0; i < allTargets.length; i++) { this._clearEffectsForTarget(allTargets[i]); } } setVolume(args, util) { const volume = Cast.toNumber(args.VOLUME); return this._updateVolume(volume, util); } changeVolume(args, util) { const volume = Cast.toNumber(args.VOLUME) + util.target.volume; return this._updateVolume(volume, util); } _updateVolume(volume, util) { volume = MathUtil.clamp(volume, 0, 100); util.target.volume = volume; this._syncEffectsForTarget(util.target); if (this.runtime.runtimeOptions.miscLimits) { // Yield until the next tick. return Promise.resolve(); } this.runtime.requestRedraw(); } getVolume(args, util) { return util.target.volume; } soundsMenu(args) { return args.SOUND_MENU; } beatsMenu(args) { return args.BEATS; } effectsMenu(args) { return args.EFFECT; } } module.exports = Scratch3SoundBlocks; /***/ }), /***/ "./node_modules/scratch-vm/src/compiler/compat-block-utility.js": /*!**********************************************************************!*\ !*** ./node_modules/scratch-vm/src/compiler/compat-block-utility.js ***! \**********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const BlockUtility = __webpack_require__(/*! ../engine/block-utility */ "./node_modules/scratch-vm/src/engine/block-utility.js"); class CompatibilityLayerBlockUtility extends BlockUtility { // Branching operations are not supported. startBranch() { throw new Error('startBranch is not supported by this BlockUtility'); } startProcedure() { throw new Error('startProcedure is not supported by this BlockUtility'); } // Parameters are not used by compiled scripts. initParams() { throw new Error('initParams is not supported by this BlockUtility'); } pushParam() { throw new Error('pushParam is not supported by this BlockUtility'); } getParam() { throw new Error('getParam is not supported by this BlockUtility'); } } // Export a single instance to be reused. module.exports = new CompatibilityLayerBlockUtility(); /***/ }), /***/ "./node_modules/scratch-vm/src/compiler/compat-blocks.js": /*!***************************************************************!*\ !*** ./node_modules/scratch-vm/src/compiler/compat-blocks.js ***! \***************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /** * @fileoverview List of blocks to be supported in the compiler compatibility layer. * This is only for native blocks. Extensions should not be listed here. */ // Please keep these lists alphabetical. const stacked = ['control_clear_counter', 'control_incr_counter', 'looks_changestretchby', 'looks_hideallsprites', 'looks_say', 'looks_sayforsecs', 'looks_setstretchto', 'looks_switchbackdroptoandwait', 'looks_think', 'looks_thinkforsecs', 'motion_align_scene', 'motion_glidesecstoxy', 'motion_glideto', 'motion_goto', 'motion_pointtowards', 'motion_scroll_right', 'motion_scroll_up', 'sensing_askandwait', 'sensing_setdragmode', 'sound_changeeffectby', 'sound_changevolumeby', 'sound_cleareffects', 'sound_play', 'sound_playuntildone', 'sound_seteffectto', 'sound_setvolumeto', 'sound_stopallsounds']; const inputs = ['control_get_counter', 'motion_xscroll', 'motion_yscroll', 'sensing_loud', 'sensing_loudness', 'sensing_userid', 'sound_volume']; module.exports = { stacked, inputs }; /***/ }), /***/ "./node_modules/scratch-vm/src/compiler/compile.js": /*!*********************************************************!*\ !*** ./node_modules/scratch-vm/src/compiler/compile.js ***! \*********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const IRGenerator = __webpack_require__(/*! ./irgen */ "./node_modules/scratch-vm/src/compiler/irgen.js"); const JSGenerator = __webpack_require__(/*! ./jsgen */ "./node_modules/scratch-vm/src/compiler/jsgen.js"); const compile = thread => { const irGenerator = new IRGenerator(thread); const ir = irGenerator.generate(); const procedures = {}; const target = thread.target; const compileScript = script => { if (script.cachedCompileResult) { return script.cachedCompileResult; } const compiler = new JSGenerator(script, ir, target); const result = compiler.compile(); script.cachedCompileResult = result; return result; }; const entry = compileScript(ir.entry); for (const procedureVariant of Object.keys(ir.procedures)) { const procedureData = ir.procedures[procedureVariant]; const procedureTree = compileScript(procedureData); procedures[procedureVariant] = procedureTree; } return { startingFunction: entry, procedures }; }; module.exports = compile; /***/ }), /***/ "./node_modules/scratch-vm/src/compiler/environment.js": /*!*************************************************************!*\ !*** ./node_modules/scratch-vm/src/compiler/environment.js ***! \*************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /* eslint-disable no-eval */ /** * @returns {boolean} true if the nullish coalescing operator (x ?? y) is supported. * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator */ const supportsNullishCoalescing = () => { try { // eslint-disable-next-line no-unused-vars const fn = new Function('undefined ?? 3'); // if function construction succeeds, the browser understood the syntax. return true; } catch (e) { return false; } }; module.exports = { supportsNullishCoalescing: supportsNullishCoalescing() }; /***/ }), /***/ "./node_modules/scratch-vm/src/compiler/intermediate.js": /*!**************************************************************!*\ !*** ./node_modules/scratch-vm/src/compiler/intermediate.js ***! \**************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /** * @fileoverview Common intermediates shared amongst parts of the compiler. */ /** * An IntermediateScript describes a single script. * Scripts do not necessarily have hats. */ class IntermediateScript { constructor() { /** * The ID of the top block of this script. * @type {string} */ this.topBlockId = null; /** * List of nodes that make up this script. * @type {Array|null} */ this.stack = null; /** * Whether this script is a procedure. * @type {boolean} */ this.isProcedure = false; /** * This procedure's code, if any. * @type {string} */ this.procedureCode = ''; /** * List of names of arguments accepted by this function, if it is a procedure. * @type {string[]} */ this.arguments = []; /** * Whether this script should be run in warp mode. * @type {boolean} */ this.isWarp = false; /** * Whether this script can `yield` * If false, this script will be compiled as a regular JavaScript function (function) * If true, this script will be compiled as a generator function (function*) * @type {boolean} */ this.yields = true; /** * Whether this script should use the "warp timer" * @type {boolean} */ this.warpTimer = false; /** * List of procedure IDs that this script needs. * @readonly */ this.dependedProcedures = []; /** * Cached result of compiling this script. * @type {Function|null} */ this.cachedCompileResult = null; } } /** * An IntermediateRepresentation contains scripts. */ class IntermediateRepresentation { constructor() { /** * The entry point of this IR. * @type {IntermediateScript} */ this.entry = null; /** * Maps procedure variants to their intermediate script. * @type {Object.} */ this.procedures = {}; } } module.exports = { IntermediateScript, IntermediateRepresentation }; /***/ }), /***/ "./node_modules/scratch-vm/src/compiler/irgen.js": /*!*******************************************************!*\ !*** ./node_modules/scratch-vm/src/compiler/irgen.js ***! \*******************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const Cast = __webpack_require__(/*! ../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); const StringUtil = __webpack_require__(/*! ../util/string-util */ "./node_modules/scratch-vm/src/util/string-util.js"); const BlockType = __webpack_require__(/*! ../extension-support/block-type */ "./node_modules/scratch-vm/src/extension-support/block-type.js"); const Variable = __webpack_require__(/*! ../engine/variable */ "./node_modules/scratch-vm/src/engine/variable.js"); const log = __webpack_require__(/*! ../util/log */ "./node_modules/scratch-vm/src/util/log.js"); const { IntermediateScript, IntermediateRepresentation } = __webpack_require__(/*! ./intermediate */ "./node_modules/scratch-vm/src/compiler/intermediate.js"); const compatBlocks = __webpack_require__(/*! ./compat-blocks */ "./node_modules/scratch-vm/src/compiler/compat-blocks.js"); /** * @fileoverview Generate intermediate representations from Scratch blocks. */ const SCALAR_TYPE = ''; const LIST_TYPE = 'list'; /** * @typedef {Object.} Node * @property {string} kind */ /** * Create a variable codegen object. * @param {'target'|'stage'} scope The scope of this variable -- which object owns it. * @param {import('../engine/variable.js')} varObj The Scratch Variable * @returns {*} A variable codegen object. */ const createVariableData = (scope, varObj) => ({ scope, id: varObj.id, name: varObj.name, isCloud: varObj.isCloud }); /** * @param {string} code * @param {boolean} warp * @returns {string} */ const generateProcedureVariant = (code, warp) => { if (warp) { return "W".concat(code); } return "Z".concat(code); }; /** * @param {string} variant Variant generated by generateProcedureVariant() * @returns {string} original procedure code */ const parseProcedureCode = variant => variant.substring(1); /** * @param {string} variant Variant generated by generateProcedureVariant() * @returns {boolean} true if warp enabled */ const parseIsWarp = variant => variant.charAt(0) === 'W'; class ScriptTreeGenerator { constructor(thread) { /** @private */ this.thread = thread; /** @private */ this.target = thread.target; /** @private */ this.blocks = thread.blockContainer; /** @private */ this.runtime = this.target.runtime; /** @private */ this.stage = this.runtime.getTargetForStage(); /** * This script's intermediate representation. */ this.script = new IntermediateScript(); this.script.warpTimer = this.target.runtime.compilerOptions.warpTimer; /** * Cache of variable ID to variable data object. * @type {Object.} * @private */ this.variableCache = {}; this.usesTimer = false; } setProcedureVariant(procedureVariant) { const procedureCode = parseProcedureCode(procedureVariant); this.script.procedureCode = procedureCode; this.script.isProcedure = true; this.script.yields = false; const paramNamesIdsAndDefaults = this.blocks.getProcedureParamNamesIdsAndDefaults(procedureCode); if (paramNamesIdsAndDefaults === null) { throw new Error("IR: cannot find procedure: ".concat(procedureVariant)); } const [paramNames, _paramIds, _paramDefaults] = paramNamesIdsAndDefaults; this.script.arguments = paramNames; } enableWarp() { this.script.isWarp = true; } getBlockById(blockId) { // Flyout blocks are stored in a special container. return this.blocks.getBlock(blockId) || this.blocks.runtime.flyoutBlocks.getBlock(blockId); } getBlockInfo(fullOpcode) { const [category, opcode] = StringUtil.splitFirst(fullOpcode, '_'); if (!category || !opcode) { return null; } const categoryInfo = this.runtime._blockInfo.find(ci => ci.id === category); if (!categoryInfo) { return null; } const blockInfo = categoryInfo.blocks.find(b => b.info.opcode === opcode); if (!blockInfo) { return null; } return blockInfo; } /** * Descend into a child input of a block. (eg. the input STRING of "length of ( )") * @param {*} parentBlock The parent Scratch block that contains the input. * @param {string} inputName The name of the input to descend into. * @private * @returns {Node} Compiled input node for this input. */ descendInputOfBlock(parentBlock, inputName) { const input = parentBlock.inputs[inputName]; if (!input) { log.warn("IR: ".concat(parentBlock.opcode, ": missing input ").concat(inputName), parentBlock); return { kind: 'constant', value: 0 }; } const inputId = input.block; const block = this.getBlockById(inputId); if (!block) { log.warn("IR: ".concat(parentBlock.opcode, ": could not find input ").concat(inputName, " with ID ").concat(inputId)); return { kind: 'constant', value: 0 }; } return this.descendInput(block); } /** * Descend into an input. (eg. "length of ( )") * @param {*} block The parent Scratch block input. * @private * @returns {Node} Compiled input node for this input. */ descendInput(block) { switch (block.opcode) { case 'colour_picker': { const color = block.fields.COLOUR.value; const hex = color.substr(1); if (/^[0-9a-f]{6,8}$/.test(hex)) { return { kind: 'constant', value: Number.parseInt(hex, 16) }; } return { kind: 'constant', value: color }; } case 'math_angle': case 'math_integer': case 'math_number': case 'math_positive_number': case 'math_whole_number': return { kind: 'constant', value: block.fields.NUM.value }; case 'text': return { kind: 'constant', value: block.fields.TEXT.value }; case 'argument_reporter_string_number': { const name = block.fields.VALUE.value; // lastIndexOf because multiple parameters with the same name will use the value of the last definition const index = this.script.arguments.lastIndexOf(name); if (index === -1) { // Legacy support if (name.toLowerCase() === 'last key pressed') { return { kind: 'tw.lastKeyPressed' }; } } if (index === -1) { return { kind: 'constant', value: 0 }; } return { kind: 'args.stringNumber', index: index }; } case 'argument_reporter_boolean': { // see argument_reporter_string_number above const name = block.fields.VALUE.value; const index = this.script.arguments.lastIndexOf(name); if (index === -1) { if (name.toLowerCase() === 'is compiled?' || name.toLowerCase() === 'is turbowarp?') { return { kind: 'constant', value: true }; } return { kind: 'constant', value: 0 }; } return { kind: 'args.boolean', index: index }; } case 'data_variable': return { kind: 'var.get', variable: this.descendVariable(block, 'VARIABLE', SCALAR_TYPE) }; case 'data_itemoflist': return { kind: 'list.get', list: this.descendVariable(block, 'LIST', LIST_TYPE), index: this.descendInputOfBlock(block, 'INDEX') }; case 'data_lengthoflist': return { kind: 'list.length', list: this.descendVariable(block, 'LIST', LIST_TYPE) }; case 'data_listcontainsitem': return { kind: 'list.contains', list: this.descendVariable(block, 'LIST', LIST_TYPE), item: this.descendInputOfBlock(block, 'ITEM') }; case 'data_itemnumoflist': return { kind: 'list.indexOf', list: this.descendVariable(block, 'LIST', LIST_TYPE), item: this.descendInputOfBlock(block, 'ITEM') }; case 'data_listcontents': return { kind: 'list.contents', list: this.descendVariable(block, 'LIST', LIST_TYPE) }; case 'event_broadcast_menu': { const broadcastOption = block.fields.BROADCAST_OPTION; const broadcastVariable = this.target.lookupBroadcastMsg(broadcastOption.id, broadcastOption.value); // TODO: empty string probably isn't the correct fallback const broadcastName = broadcastVariable ? broadcastVariable.name : ''; return { kind: 'constant', value: broadcastName }; } case 'looks_backdropnumbername': if (block.fields.NUMBER_NAME.value === 'number') { return { kind: 'looks.backdropNumber' }; } return { kind: 'looks.backdropName' }; case 'looks_costumenumbername': if (block.fields.NUMBER_NAME.value === 'number') { return { kind: 'looks.costumeNumber' }; } return { kind: 'looks.costumeName' }; case 'looks_size': return { kind: 'looks.size' }; case 'motion_direction': return { kind: 'motion.direction' }; case 'motion_xposition': return { kind: 'motion.x' }; case 'motion_yposition': return { kind: 'motion.y' }; case 'operator_add': return { kind: 'op.add', left: this.descendInputOfBlock(block, 'NUM1'), right: this.descendInputOfBlock(block, 'NUM2') }; case 'operator_and': return { kind: 'op.and', left: this.descendInputOfBlock(block, 'OPERAND1'), right: this.descendInputOfBlock(block, 'OPERAND2') }; case 'operator_contains': return { kind: 'op.contains', string: this.descendInputOfBlock(block, 'STRING1'), contains: this.descendInputOfBlock(block, 'STRING2') }; case 'operator_divide': return { kind: 'op.divide', left: this.descendInputOfBlock(block, 'NUM1'), right: this.descendInputOfBlock(block, 'NUM2') }; case 'operator_equals': return { kind: 'op.equals', left: this.descendInputOfBlock(block, 'OPERAND1'), right: this.descendInputOfBlock(block, 'OPERAND2') }; case 'operator_gt': return { kind: 'op.greater', left: this.descendInputOfBlock(block, 'OPERAND1'), right: this.descendInputOfBlock(block, 'OPERAND2') }; case 'operator_join': return { kind: 'op.join', left: this.descendInputOfBlock(block, 'STRING1'), right: this.descendInputOfBlock(block, 'STRING2') }; case 'operator_length': return { kind: 'op.length', string: this.descendInputOfBlock(block, 'STRING') }; case 'operator_letter_of': return { kind: 'op.letterOf', letter: this.descendInputOfBlock(block, 'LETTER'), string: this.descendInputOfBlock(block, 'STRING') }; case 'operator_lt': return { kind: 'op.less', left: this.descendInputOfBlock(block, 'OPERAND1'), right: this.descendInputOfBlock(block, 'OPERAND2') }; case 'operator_mathop': { const value = this.descendInputOfBlock(block, 'NUM'); const operator = block.fields.OPERATOR.value.toLowerCase(); switch (operator) { case 'abs': return { kind: 'op.abs', value }; case 'floor': return { kind: 'op.floor', value }; case 'ceiling': return { kind: 'op.ceiling', value }; case 'sqrt': return { kind: 'op.sqrt', value }; case 'sin': return { kind: 'op.sin', value }; case 'cos': return { kind: 'op.cos', value }; case 'tan': return { kind: 'op.tan', value }; case 'asin': return { kind: 'op.asin', value }; case 'acos': return { kind: 'op.acos', value }; case 'atan': return { kind: 'op.atan', value }; case 'ln': return { kind: 'op.ln', value }; case 'log': return { kind: 'op.log', value }; case 'e ^': return { kind: 'op.e^', value }; case '10 ^': return { kind: 'op.10^', value }; default: return { kind: 'constant', value: 0 }; } } case 'operator_mod': return { kind: 'op.mod', left: this.descendInputOfBlock(block, 'NUM1'), right: this.descendInputOfBlock(block, 'NUM2') }; case 'operator_multiply': return { kind: 'op.multiply', left: this.descendInputOfBlock(block, 'NUM1'), right: this.descendInputOfBlock(block, 'NUM2') }; case 'operator_not': return { kind: 'op.not', operand: this.descendInputOfBlock(block, 'OPERAND') }; case 'operator_or': return { kind: 'op.or', left: this.descendInputOfBlock(block, 'OPERAND1'), right: this.descendInputOfBlock(block, 'OPERAND2') }; case 'operator_random': { const from = this.descendInputOfBlock(block, 'FROM'); const to = this.descendInputOfBlock(block, 'TO'); // If both values are known at compile time, we can do some optimizations. // TODO: move optimizations to jsgen? if (from.kind === 'constant' && to.kind === 'constant') { const sFrom = from.value; const sTo = to.value; const nFrom = Cast.toNumber(sFrom); const nTo = Cast.toNumber(sTo); // If both numbers are the same, random is unnecessary. // todo: this probably never happens so consider removing if (nFrom === nTo) { return { kind: 'constant', value: nFrom }; } // If both are ints, hint this to the compiler if (Cast.isInt(sFrom) && Cast.isInt(sTo)) { return { kind: 'op.random', low: nFrom <= nTo ? from : to, high: nFrom <= nTo ? to : from, useInts: true, useFloats: false }; } // Otherwise hint that these are floats return { kind: 'op.random', low: nFrom <= nTo ? from : to, high: nFrom <= nTo ? to : from, useInts: false, useFloats: true }; } else if (from.kind === 'constant') { // If only one value is known at compile-time, we can still attempt some optimizations. if (!Cast.isInt(Cast.toNumber(from.value))) { return { kind: 'op.random', low: from, high: to, useInts: false, useFloats: true }; } } else if (to.kind === 'constant') { if (!Cast.isInt(Cast.toNumber(to.value))) { return { kind: 'op.random', low: from, high: to, useInts: false, useFloats: true }; } } // No optimizations possible return { kind: 'op.random', low: from, high: to, useInts: false, useFloats: false }; } case 'operator_round': return { kind: 'op.round', value: this.descendInputOfBlock(block, 'NUM') }; case 'operator_subtract': return { kind: 'op.subtract', left: this.descendInputOfBlock(block, 'NUM1'), right: this.descendInputOfBlock(block, 'NUM2') }; case 'sensing_answer': return { kind: 'sensing.answer' }; case 'sensing_coloristouchingcolor': return { kind: 'sensing.colorTouchingColor', target: this.descendInputOfBlock(block, 'COLOR2'), mask: this.descendInputOfBlock(block, 'COLOR') }; case 'sensing_current': switch (block.fields.CURRENTMENU.value.toLowerCase()) { case 'year': return { kind: 'sensing.year' }; case 'month': return { kind: 'sensing.month' }; case 'date': return { kind: 'sensing.date' }; case 'dayofweek': return { kind: 'sensing.dayofweek' }; case 'hour': return { kind: 'sensing.hour' }; case 'minute': return { kind: 'sensing.minute' }; case 'second': return { kind: 'sensing.second' }; } return { kind: 'constant', value: 0 }; case 'sensing_dayssince2000': return { kind: 'sensing.daysSince2000' }; case 'sensing_distanceto': return { kind: 'sensing.distance', target: this.descendInputOfBlock(block, 'DISTANCETOMENU') }; case 'sensing_keypressed': return { kind: 'keyboard.pressed', key: this.descendInputOfBlock(block, 'KEY_OPTION') }; case 'sensing_mousedown': return { kind: 'mouse.down' }; case 'sensing_mousex': return { kind: 'mouse.x' }; case 'sensing_mousey': return { kind: 'mouse.y' }; case 'sensing_of': return { kind: 'sensing.of', property: block.fields.PROPERTY.value, object: this.descendInputOfBlock(block, 'OBJECT') }; case 'sensing_timer': this.usesTimer = true; return { kind: 'timer.get' }; case 'sensing_touchingcolor': return { kind: 'sensing.touchingColor', color: this.descendInputOfBlock(block, 'COLOR') }; case 'sensing_touchingobject': return { kind: 'sensing.touching', object: this.descendInputOfBlock(block, 'TOUCHINGOBJECTMENU') }; case 'sensing_username': return { kind: 'sensing.username' }; case 'sound_sounds_menu': // This menu is special compared to other menus -- it actually has an opcode function. return { kind: 'constant', value: block.fields.SOUND_MENU.value }; case 'tw_getLastKeyPressed': return { kind: 'tw.lastKeyPressed' }; default: { const opcodeFunction = this.runtime.getOpcodeFunction(block.opcode); if (opcodeFunction) { // It might be a non-compiled primitive from a standard category if (compatBlocks.inputs.includes(block.opcode)) { return this.descendCompatLayer(block); } // It might be an extension block. const blockInfo = this.getBlockInfo(block.opcode); if (blockInfo) { const type = blockInfo.info.blockType; if (type === BlockType.REPORTER || type === BlockType.BOOLEAN) { return this.descendCompatLayer(block); } } } // It might be a menu. const inputs = Object.keys(block.inputs); const fields = Object.keys(block.fields); if (inputs.length === 0 && fields.length === 1) { return { kind: 'constant', value: block.fields[fields[0]].value }; } log.warn("IR: Unknown input: ".concat(block.opcode), block); throw new Error("IR: Unknown input: ".concat(block.opcode)); } } } /** * Descend into a stacked block. (eg. "move ( ) steps") * @param {*} block The Scratch block to parse. * @private * @returns {Node} Compiled node for this block. */ descendStackedBlock(block) { switch (block.opcode) { case 'control_all_at_once': // In Scratch 3, this block behaves like "if 1 = 1" return { kind: 'control.if', condition: { kind: 'constant', value: true }, whenTrue: this.descendSubstack(block, 'SUBSTACK'), whenFalse: [] }; case 'control_create_clone_of': return { kind: 'control.createClone', target: this.descendInputOfBlock(block, 'CLONE_OPTION') }; case 'control_delete_this_clone': this.script.yields = true; return { kind: 'control.deleteClone' }; case 'control_forever': this.analyzeLoop(); return { kind: 'control.while', condition: { kind: 'constant', value: true }, do: this.descendSubstack(block, 'SUBSTACK') }; case 'control_for_each': this.analyzeLoop(); return { kind: 'control.for', variable: this.descendVariable(block, 'VARIABLE', SCALAR_TYPE), count: this.descendInputOfBlock(block, 'VALUE'), do: this.descendSubstack(block, 'SUBSTACK') }; case 'control_if': return { kind: 'control.if', condition: this.descendInputOfBlock(block, 'CONDITION'), whenTrue: this.descendSubstack(block, 'SUBSTACK'), whenFalse: [] }; case 'control_if_else': return { kind: 'control.if', condition: this.descendInputOfBlock(block, 'CONDITION'), whenTrue: this.descendSubstack(block, 'SUBSTACK'), whenFalse: this.descendSubstack(block, 'SUBSTACK2') }; case 'control_repeat': this.analyzeLoop(); return { kind: 'control.repeat', times: this.descendInputOfBlock(block, 'TIMES'), do: this.descendSubstack(block, 'SUBSTACK') }; case 'control_repeat_until': { this.analyzeLoop(); // Dirty hack: automatically enable warp timer for this block if it uses timer // This fixes project that do things like "repeat until timer > 0.5" this.usesTimer = false; const condition = this.descendInputOfBlock(block, 'CONDITION'); const needsWarpTimer = this.usesTimer; if (needsWarpTimer) { this.script.yields = true; } return { kind: 'control.while', condition: { kind: 'op.not', operand: condition }, do: this.descendSubstack(block, 'SUBSTACK'), warpTimer: needsWarpTimer }; } case 'control_stop': { const level = block.fields.STOP_OPTION.value; if (level === 'all') { this.script.yields = true; return { kind: 'control.stopAll' }; } else if (level === 'other scripts in sprite' || level === 'other scripts in stage') { return { kind: 'control.stopOthers' }; } else if (level === 'this script') { return { kind: 'control.stopScript' }; } return { kind: 'noop' }; } case 'control_wait': this.script.yields = true; return { kind: 'control.wait', seconds: this.descendInputOfBlock(block, 'DURATION') }; case 'control_wait_until': this.script.yields = true; return { kind: 'control.waitUntil', condition: this.descendInputOfBlock(block, 'CONDITION') }; case 'control_while': this.analyzeLoop(); return { kind: 'control.while', condition: this.descendInputOfBlock(block, 'CONDITION'), do: this.descendSubstack(block, 'SUBSTACK'), // We should consider analyzing this like we do for control_repeat_until warpTimer: false }; case 'data_addtolist': return { kind: 'list.add', list: this.descendVariable(block, 'LIST', LIST_TYPE), item: this.descendInputOfBlock(block, 'ITEM') }; case 'data_changevariableby': { const variable = this.descendVariable(block, 'VARIABLE', SCALAR_TYPE); return { kind: 'var.set', variable, value: { kind: 'op.add', left: { kind: 'var.get', variable }, right: this.descendInputOfBlock(block, 'VALUE') } }; } case 'data_deletealloflist': return { kind: 'list.deleteAll', list: this.descendVariable(block, 'LIST', LIST_TYPE) }; case 'data_deleteoflist': { const index = this.descendInputOfBlock(block, 'INDEX'); if (index.kind === 'constant' && index.value === 'all') { return { kind: 'list.deleteAll', list: this.descendVariable(block, 'LIST', LIST_TYPE) }; } return { kind: 'list.delete', list: this.descendVariable(block, 'LIST', LIST_TYPE), index: index }; } case 'data_hidelist': return { kind: 'list.hide', list: this.descendVariable(block, 'LIST', LIST_TYPE) }; case 'data_hidevariable': return { kind: 'var.hide', variable: this.descendVariable(block, 'VARIABLE', SCALAR_TYPE) }; case 'data_insertatlist': return { kind: 'list.insert', list: this.descendVariable(block, 'LIST', LIST_TYPE), index: this.descendInputOfBlock(block, 'INDEX'), item: this.descendInputOfBlock(block, 'ITEM') }; case 'data_replaceitemoflist': return { kind: 'list.replace', list: this.descendVariable(block, 'LIST', LIST_TYPE), index: this.descendInputOfBlock(block, 'INDEX'), item: this.descendInputOfBlock(block, 'ITEM') }; case 'data_setvariableto': return { kind: 'var.set', variable: this.descendVariable(block, 'VARIABLE', SCALAR_TYPE), value: this.descendInputOfBlock(block, 'VALUE') }; case 'data_showlist': return { kind: 'list.show', list: this.descendVariable(block, 'LIST', LIST_TYPE) }; case 'data_showvariable': return { kind: 'var.show', variable: this.descendVariable(block, 'VARIABLE', SCALAR_TYPE) }; case 'event_broadcast': return { kind: 'event.broadcast', broadcast: this.descendInputOfBlock(block, 'BROADCAST_INPUT') }; case 'event_broadcastandwait': this.script.yields = true; return { kind: 'event.broadcastAndWait', broadcast: this.descendInputOfBlock(block, 'BROADCAST_INPUT') }; case 'looks_changeeffectby': return { kind: 'looks.changeEffect', effect: block.fields.EFFECT.value.toLowerCase(), value: this.descendInputOfBlock(block, 'CHANGE') }; case 'looks_changesizeby': return { kind: 'looks.changeSize', size: this.descendInputOfBlock(block, 'CHANGE') }; case 'looks_cleargraphiceffects': return { kind: 'looks.clearEffects' }; case 'looks_goforwardbackwardlayers': if (block.fields.FORWARD_BACKWARD.value === 'forward') { return { kind: 'looks.forwardLayers', layers: this.descendInputOfBlock(block, 'NUM') }; } return { kind: 'looks.backwardLayers', layers: this.descendInputOfBlock(block, 'NUM') }; case 'looks_gotofrontback': if (block.fields.FRONT_BACK.value === 'front') { return { kind: 'looks.goToFront' }; } return { kind: 'looks.goToBack' }; case 'looks_hide': return { kind: 'looks.hide' }; case 'looks_nextbackdrop': return { kind: 'looks.nextBackdrop' }; case 'looks_nextcostume': return { kind: 'looks.nextCostume' }; case 'looks_seteffectto': return { kind: 'looks.setEffect', effect: block.fields.EFFECT.value.toLowerCase(), value: this.descendInputOfBlock(block, 'VALUE') }; case 'looks_setsizeto': return { kind: 'looks.setSize', size: this.descendInputOfBlock(block, 'SIZE') }; case 'looks_show': return { kind: 'looks.show' }; case 'looks_switchbackdropto': return { kind: 'looks.switchBackdrop', backdrop: this.descendInputOfBlock(block, 'BACKDROP') }; case 'looks_switchcostumeto': return { kind: 'looks.switchCostume', costume: this.descendInputOfBlock(block, 'COSTUME') }; case 'motion_changexby': return { kind: 'motion.changeX', dx: this.descendInputOfBlock(block, 'DX') }; case 'motion_changeyby': return { kind: 'motion.changeY', dy: this.descendInputOfBlock(block, 'DY') }; case 'motion_gotoxy': return { kind: 'motion.setXY', x: this.descendInputOfBlock(block, 'X'), y: this.descendInputOfBlock(block, 'Y') }; case 'motion_ifonedgebounce': return { kind: 'motion.ifOnEdgeBounce' }; case 'motion_movesteps': return { kind: 'motion.step', steps: this.descendInputOfBlock(block, 'STEPS') }; case 'motion_pointindirection': return { kind: 'motion.setDirection', direction: this.descendInputOfBlock(block, 'DIRECTION') }; case 'motion_setrotationstyle': return { kind: 'motion.setRotationStyle', style: block.fields.STYLE.value }; case 'motion_setx': return { kind: 'motion.setX', x: this.descendInputOfBlock(block, 'X') }; case 'motion_sety': return { kind: 'motion.setY', y: this.descendInputOfBlock(block, 'Y') }; case 'motion_turnleft': return { kind: 'motion.setDirection', direction: { kind: 'op.subtract', left: { kind: 'motion.direction' }, right: this.descendInputOfBlock(block, 'DEGREES') } }; case 'motion_turnright': return { kind: 'motion.setDirection', direction: { kind: 'op.add', left: { kind: 'motion.direction' }, right: this.descendInputOfBlock(block, 'DEGREES') } }; case 'pen_clear': return { kind: 'pen.clear' }; case 'pen_changePenColorParamBy': return { kind: 'pen.changeParam', param: this.descendInputOfBlock(block, 'COLOR_PARAM'), value: this.descendInputOfBlock(block, 'VALUE') }; case 'pen_changePenHueBy': return { kind: 'pen.legacyChangeHue', hue: this.descendInputOfBlock(block, 'HUE') }; case 'pen_changePenShadeBy': return { kind: 'pen.legacyChangeShade', shade: this.descendInputOfBlock(block, 'SHADE') }; case 'pen_penDown': return { kind: 'pen.down' }; case 'pen_penUp': return { kind: 'pen.up' }; case 'pen_setPenColorParamTo': return { kind: 'pen.setParam', param: this.descendInputOfBlock(block, 'COLOR_PARAM'), value: this.descendInputOfBlock(block, 'VALUE') }; case 'pen_setPenColorToColor': return { kind: 'pen.setColor', color: this.descendInputOfBlock(block, 'COLOR') }; case 'pen_setPenHueToNumber': return { kind: 'pen.legacySetHue', hue: this.descendInputOfBlock(block, 'HUE') }; case 'pen_setPenShadeToNumber': return { kind: 'pen.legacySetShade', shade: this.descendInputOfBlock(block, 'SHADE') }; case 'pen_setPenSizeTo': return { kind: 'pen.setSize', size: this.descendInputOfBlock(block, 'SIZE') }; case 'pen_changePenSizeBy': return { kind: 'pen.changeSize', size: this.descendInputOfBlock(block, 'SIZE') }; case 'pen_stamp': return { kind: 'pen.stamp' }; case 'procedures_call': { // setting of yields will be handled later in the analysis phase const procedureCode = block.mutation.proccode; if (procedureCode === 'tw:debugger;') { return { kind: 'tw.debugger' }; } const paramNamesIdsAndDefaults = this.blocks.getProcedureParamNamesIdsAndDefaults(procedureCode); if (paramNamesIdsAndDefaults === null) { return { kind: 'noop' }; } const [paramNames, paramIds, paramDefaults] = paramNamesIdsAndDefaults; const addonBlock = this.runtime.getAddonBlock(procedureCode); if (addonBlock) { this.script.yields = true; const args = {}; for (let i = 0; i < paramIds.length; i++) { let value; if (block.inputs[paramIds[i]] && block.inputs[paramIds[i]].block) { value = this.descendInputOfBlock(block, paramIds[i]); } else { value = { kind: 'constant', value: paramDefaults[i] }; } args[paramNames[i]] = value; } return { kind: 'addons.call', code: procedureCode, arguments: args, blockId: block.id }; } const definitionId = this.blocks.getProcedureDefinition(procedureCode); const definitionBlock = this.blocks.getBlock(definitionId); if (!definitionBlock) { return { kind: 'noop' }; } const innerDefinition = this.blocks.getBlock(definitionBlock.inputs.custom_block.block); let isWarp = this.script.isWarp; if (!isWarp) { if (innerDefinition && innerDefinition.mutation) { const warp = innerDefinition.mutation.warp; if (typeof warp === 'boolean') { isWarp = warp; } else if (typeof warp === 'string') { isWarp = JSON.parse(warp); } } } const variant = generateProcedureVariant(procedureCode, isWarp); if (!this.script.dependedProcedures.includes(variant)) { this.script.dependedProcedures.push(variant); } // Non-warp direct recursion yields. if (!this.script.isWarp) { if (procedureCode === this.script.procedureCode) { this.script.yields = true; } } const args = []; for (let i = 0; i < paramIds.length; i++) { let value; if (block.inputs[paramIds[i]] && block.inputs[paramIds[i]].block) { value = this.descendInputOfBlock(block, paramIds[i]); } else { value = { kind: 'constant', value: paramDefaults[i] }; } args.push(value); } return { kind: 'procedures.call', code: procedureCode, variant, arguments: args }; } case 'sensing_resettimer': return { kind: 'timer.reset' }; default: { const opcodeFunction = this.runtime.getOpcodeFunction(block.opcode); if (opcodeFunction) { // It might be a non-compiled primitive from a standard category if (compatBlocks.stacked.includes(block.opcode)) { return this.descendCompatLayer(block); } // It might be an extension block. const blockInfo = this.getBlockInfo(block.opcode); if (blockInfo) { const type = blockInfo.info.blockType; if (type === BlockType.COMMAND) { return this.descendCompatLayer(block); } } } // When this thread was triggered by a stack click, attempt to compile as an input. // TODO: perhaps this should be moved to generate()? if (this.thread.stackClick) { try { const inputNode = this.descendInput(block); return { kind: 'visualReport', input: inputNode }; } catch (e) {// Ignore } } log.warn("IR: Unknown stacked block: ".concat(block.opcode), block); throw new Error("IR: Unknown stacked block: ".concat(block.opcode)); } } } /** * Descend into a stack of blocks (eg. the blocks contained within an "if" block) * @param {*} parentBlock The parent Scratch block that contains the stack to parse. * @param {*} substackName The name of the stack to descend into. * @private * @returns {Node[]} List of stacked block nodes. */ descendSubstack(parentBlock, substackName) { const input = parentBlock.inputs[substackName]; if (!input) { return []; } const stackId = input.block; return this.walkStack(stackId); } /** * Descend into and walk the siblings of a stack. * @param {string} startingBlockId The ID of the first block of a stack. * @private * @returns {Node[]} List of stacked block nodes. */ walkStack(startingBlockId) { const result = []; let blockId = startingBlockId; while (blockId !== null) { const block = this.getBlockById(blockId); if (!block) { break; } const node = this.descendStackedBlock(block); result.push(node); blockId = block.next; } return result; } /** * Descend into a variable. * @param {*} block The block that has the variable. * @param {string} fieldName The name of the field that the variable is stored in. * @param {''|'list'} type Variable type, '' for scalar and 'list' for list. * @private * @returns {*} A parsed variable object. */ descendVariable(block, fieldName, type) { const variable = block.fields[fieldName]; const id = variable.id; if (this.variableCache.hasOwnProperty(id)) { return this.variableCache[id]; } const data = this._descendVariable(id, variable.value, type); this.variableCache[id] = data; return data; } /** * @param {string} id The ID of the variable. * @param {string} name The name of the variable. * @param {''|'list'} type The variable type. * @private * @returns {*} A parsed variable object. */ _descendVariable(id, name, type) { const target = this.target; const stage = this.stage; // Look for by ID in target... if (target.variables.hasOwnProperty(id)) { return createVariableData('target', target.variables[id]); } // Look for by ID in stage... if (!target.isStage) { if (stage && stage.variables.hasOwnProperty(id)) { return createVariableData('stage', stage.variables[id]); } } // Look for by name and type in target... for (const varId in target.variables) { if (target.variables.hasOwnProperty(varId)) { const currVar = target.variables[varId]; if (currVar.name === name && currVar.type === type) { return createVariableData('target', currVar); } } } // Look for by name and type in stage... if (!target.isStage && stage) { for (const varId in stage.variables) { if (stage.variables.hasOwnProperty(varId)) { const currVar = stage.variables[varId]; if (currVar.name === name && currVar.type === type) { return createVariableData('stage', currVar); } } } } // Create it locally... const newVariable = new Variable(id, name, type, false); target.variables[id] = newVariable; if (target.sprite) { // Create the variable in all instances of this sprite. // This is necessary because the script cache is shared between clones. // sprite.clones has all instances of this sprite including the original and all clones for (const clone of target.sprite.clones) { if (!clone.variables.hasOwnProperty(id)) { clone.variables[id] = new Variable(id, name, type, false); } } } return createVariableData('target', newVariable); } /** * Descend into a block that uses the compatibility layer. * @param {*} block The block to use the compatibility layer for. * @private * @returns {Node} The parsed node. */ descendCompatLayer(block) { this.script.yields = true; const inputs = {}; const fields = {}; for (const name of Object.keys(block.inputs)) { inputs[name] = this.descendInputOfBlock(block, name); } for (const name of Object.keys(block.fields)) { fields[name] = block.fields[name].value; } return { kind: 'compat', opcode: block.opcode, inputs, fields }; } analyzeLoop() { if (!this.script.isWarp || this.script.warpTimer) { this.script.yields = true; } } readTopBlockComment(commentId) { const comment = this.target.comments[commentId]; if (!comment) { // can't find the comment // this is safe to ignore return; } const text = comment.text; for (const line of text.split('\n')) { if (!/^tw\b/.test(line)) { continue; } const flags = line.split(' '); for (const flag of flags) { switch (flag) { case 'nocompile': throw new Error('Script explicitly disables compilation'); case 'stuck': this.script.warpTimer = true; break; } } // Only the first 'tw' line is parsed. break; } } /** * @param {string} topBlockId The ID of the top block of the script. * @returns {IntermediateScript} */ generate(topBlockId) { this.blocks.populateProcedureCache(); this.script.topBlockId = topBlockId; const topBlock = this.getBlockById(topBlockId); if (!topBlock) { if (this.script.isProcedure) { // Empty procedure return this.script; } throw new Error('Cannot find top block'); } if (topBlock.comment) { this.readTopBlockComment(topBlock.comment); } // If the top block is a hat, advance to its child. let entryBlock; if (this.runtime.getIsHat(topBlock.opcode) || topBlock.opcode === 'procedures_definition') { if (this.runtime.getIsEdgeActivatedHat(topBlock.opcode)) { throw new Error("Not compiling an edge-activated hat: ".concat(topBlock.opcode)); } entryBlock = topBlock.next; } else { entryBlock = topBlockId; } if (!entryBlock) { // This is an empty script. return this.script; } this.script.stack = this.walkStack(entryBlock); return this.script; } } class IRGenerator { constructor(thread) { this.thread = thread; this.blocks = thread.blockContainer; this.proceduresToCompile = new Map(); this.compilingProcedures = new Map(); /** @type {Object.} */ this.procedures = {}; this.analyzedProcedures = []; } addProcedureDependencies(dependencies) { for (const procedureVariant of dependencies) { if (this.procedures.hasOwnProperty(procedureVariant)) { continue; } if (this.compilingProcedures.has(procedureVariant)) { continue; } if (this.proceduresToCompile.has(procedureVariant)) { continue; } const procedureCode = parseProcedureCode(procedureVariant); const definition = this.blocks.getProcedureDefinition(procedureCode); this.proceduresToCompile.set(procedureVariant, definition); } } /** * @param {ScriptTreeGenerator} generator The generator to run. * @param {string} topBlockId The ID of the top block in the stack. * @returns {IntermediateScript} Intermediate script. */ generateScriptTree(generator, topBlockId) { const result = generator.generate(topBlockId); this.addProcedureDependencies(result.dependedProcedures); return result; } /** * Recursively analyze a script and its dependencies. * @param {IntermediateScript} script Intermediate script. */ analyzeScript(script) { let madeChanges = false; for (const procedureCode of script.dependedProcedures) { const procedureData = this.procedures[procedureCode]; // Analyze newly found procedures. if (!this.analyzedProcedures.includes(procedureCode)) { this.analyzedProcedures.push(procedureCode); if (this.analyzeScript(procedureData)) { madeChanges = true; } this.analyzedProcedures.pop(); } // If a procedure used by a script may yield, the script itself may yield. if (procedureData.yields && !script.yields) { script.yields = true; madeChanges = true; } } return madeChanges; } /** * @returns {IntermediateRepresentation} Intermediate representation. */ generate() { const entry = this.generateScriptTree(new ScriptTreeGenerator(this.thread), this.thread.topBlock); // Compile any required procedures. // As procedures can depend on other procedures, this process may take several iterations. const procedureTreeCache = this.blocks._cache.compiledProcedures; while (this.proceduresToCompile.size > 0) { this.compilingProcedures = this.proceduresToCompile; this.proceduresToCompile = new Map(); for (const [procedureVariant, definitionId] of this.compilingProcedures.entries()) { if (procedureTreeCache[procedureVariant]) { const result = procedureTreeCache[procedureVariant]; this.procedures[procedureVariant] = result; this.addProcedureDependencies(result.dependedProcedures); } else { const isWarp = parseIsWarp(procedureVariant); const generator = new ScriptTreeGenerator(this.thread); generator.setProcedureVariant(procedureVariant); if (isWarp) generator.enableWarp(); const compiledProcedure = this.generateScriptTree(generator, definitionId); this.procedures[procedureVariant] = compiledProcedure; procedureTreeCache[procedureVariant] = compiledProcedure; } } } // Analyze scripts until no changes are made. while (this.analyzeScript(entry)); const ir = new IntermediateRepresentation(); ir.entry = entry; ir.procedures = this.procedures; return ir; } } module.exports = IRGenerator; /***/ }), /***/ "./node_modules/scratch-vm/src/compiler/jsexecute.js": /*!***********************************************************!*\ !*** ./node_modules/scratch-vm/src/compiler/jsexecute.js ***! \***********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /** * @fileoverview Runtime for scripts generated by jsgen */ /* eslint-disable no-unused-vars */ /* eslint-disable prefer-template */ /* eslint-disable valid-jsdoc */ /* eslint-disable max-len */ const globalState = { Timer: __webpack_require__(/*! ../util/timer */ "./node_modules/scratch-vm/src/util/timer.js"), Cast: __webpack_require__(/*! ../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"), log: __webpack_require__(/*! ../util/log */ "./node_modules/scratch-vm/src/util/log.js"), compatibilityLayerBlockUtility: __webpack_require__(/*! ./compat-block-utility */ "./node_modules/scratch-vm/src/compiler/compat-block-utility.js"), thread: null }; let baseRuntime = ''; const runtimeFunctions = {}; /** * Determine whether the current tick is likely stuck. * This implements similar functionality to the warp timer found in Scratch. * @returns {boolean} true if the current tick is likely stuck. */ baseRuntime += "let stuckCounter = 0;\nconst isStuck = () => {\n // The real time is not checked on every call for performance.\n stuckCounter++;\n if (stuckCounter === 100) {\n stuckCounter = 0;\n return globalState.thread.target.runtime.sequencer.timer.timeElapsed() > 500;\n }\n return false;\n};"; /** * Start hats by opcode. * @param {string} requestedHat The opcode of the hat to start. * @param {*} optMatchFields Fields to match. * @returns {Array} A list of threads that were started. */ runtimeFunctions.startHats = "const startHats = (requestedHat, optMatchFields) => {\n const thread = globalState.thread;\n const threads = thread.target.runtime.startHats(requestedHat, optMatchFields);\n return threads;\n}"; /** * Implements "thread waiting", where scripts are halted until all the scripts have finished executing. * @param {Array} threads The list of threads. */ runtimeFunctions.waitThreads = "const waitThreads = function*(threads) {\n const thread = globalState.thread;\n const runtime = thread.target.runtime;\n\n while (true) {\n // determine whether any threads are running\n let anyRunning = false;\n for (let i = 0; i < threads.length; i++) {\n if (runtime.threads.indexOf(threads[i]) !== -1) {\n anyRunning = true;\n break;\n }\n }\n if (!anyRunning) {\n // all threads are finished, can resume\n return;\n }\n\n let allWaiting = true;\n for (let i = 0; i < threads.length; i++) {\n if (!runtime.isWaitingThread(threads[i])) {\n allWaiting = false;\n break;\n }\n }\n if (allWaiting) {\n thread.status = 3; // STATUS_YIELD_TICK\n }\n\n yield;\n }\n}"; /** * Wait until a Promise resolves or rejects before continuing. * @param {Promise} promise The promise to wait for. * @returns {*} the value that the promise resolves to, otherwise undefined if the promise rejects */ /** * Execute a scratch-vm primitive. * @param {*} inputs The inputs to pass to the block. * @param {function} blockFunction The primitive's function. * @param {boolean} useFlags Whether to set flags (hasResumedFromPromise) * @returns {*} the value returned by the block, if any. */ runtimeFunctions.executeInCompatibilityLayer = "let hasResumedFromPromise = false;\nconst waitPromise = function*(promise) {\n const thread = globalState.thread;\n let returnValue;\n\n promise\n .then(value => {\n returnValue = value;\n thread.status = 0; // STATUS_RUNNING\n })\n .catch(error => {\n thread.status = 0; // STATUS_RUNNING\n globalState.log.warn('Promise rejected in compiled script:', error);\n });\n\n // enter STATUS_PROMISE_WAIT and yield\n // this will stop script execution until the promise handlers reset the thread status\n thread.status = 1; // STATUS_PROMISE_WAIT\n yield;\n\n return returnValue;\n};\nconst executeInCompatibilityLayer = function*(inputs, blockFunction, isWarp, useFlags) {\n const thread = globalState.thread;\n\n // reset the stackframe\n // we only ever use one stackframe at a time, so this shouldn't cause issues\n thread.stackFrames[thread.stackFrames.length - 1].reuse(isWarp);\n\n const executeBlock = () => {\n const compatibilityLayerBlockUtility = globalState.compatibilityLayerBlockUtility;\n compatibilityLayerBlockUtility.thread = thread;\n compatibilityLayerBlockUtility.sequencer = thread.target.runtime.sequencer;\n return blockFunction(inputs, compatibilityLayerBlockUtility);\n };\n\n const isPromise = value => (\n // see engine/execute.js\n value !== null &&\n typeof value === 'object' &&\n typeof value.then === 'function'\n );\n\n let returnValue = executeBlock();\n\n if (isPromise(returnValue)) {\n returnValue = yield* waitPromise(returnValue);\n if (useFlags) {\n hasResumedFromPromise = true;\n }\n return returnValue;\n }\n\n while (thread.status === 2 /* STATUS_YIELD */ || thread.status === 3 /* STATUS_YIELD_TICK */) {\n // Yielded threads will run next iteration.\n if (thread.status === 2 /* STATUS_YIELD */) {\n thread.status = 0; // STATUS_RUNNING\n // Yield back to the event loop when stuck or not in warp mode.\n if (!isWarp || isStuck()) {\n yield;\n }\n } else {\n // status is STATUS_YIELD_TICK, always yield to the event loop\n yield;\n }\n\n returnValue = executeBlock();\n\n if (isPromise(returnValue)) {\n returnValue = yield* waitPromise(returnValue);\n if (useFlags) {\n hasResumedFromPromise = true;\n }\n return returnValue;\n }\n }\n\n // todo: do we have to do anything extra if status is STATUS_DONE?\n\n return returnValue;\n}"; /** * Run an addon block. * @param {string} procedureCode The block's procedure code * @param {string} blockId The ID of the block being run * @param {object} args The arguments to pass to the block */ runtimeFunctions.callAddonBlock = "const callAddonBlock = function*(procedureCode, blockId, args) {\n const thread = globalState.thread;\n const addonBlock = thread.target.runtime.getAddonBlock(procedureCode);\n if (addonBlock) {\n const target = thread.target;\n addonBlock.callback(args, {\n // Shim enough of BlockUtility to make addons work\n peekStack () {\n return blockId;\n },\n target\n });\n if (thread.status === 1 /* STATUS_PROMISE_WAIT */) {\n yield;\n }\n }\n}"; /** * End the current script. */ runtimeFunctions.retire = "const retire = () => {\n const thread = globalState.thread;\n thread.target.runtime.sequencer.retireThread(thread);\n}"; /** * Scratch cast to boolean. * Similar to Cast.toBoolean() * @param {*} value The value to cast * @returns {boolean} The value cast to a boolean */ runtimeFunctions.toBoolean = "const toBoolean = value => {\n if (typeof value === 'boolean') {\n return value;\n }\n if (typeof value === 'string') {\n if (value === '' || value === '0' || value.toLowerCase() === 'false') {\n return false;\n }\n return true;\n }\n return !!value;\n}"; /** * If a number is very close to a whole number, round to that whole number. * @param {number} value Value to round * @returns {number} Rounded number or original number */ runtimeFunctions.limitPrecision = "const limitPrecision = value => {\n const rounded = Math.round(value);\n const delta = value - rounded;\n return (Math.abs(delta) < 1e-9) ? rounded : value;\n}"; /** * Check if a value is considered whitespace. * Similar to Cast.isWhiteSpace() * @param {*} val Value to check * @returns {boolean} true if the value is whitespace */ baseRuntime += "const isWhiteSpace = val => typeof val === 'string' && val.trim().length === 0;"; /** * Determine if two values are equal. * @param {*} v1 First value * @param {*} v2 Second value * @returns {boolean} true if v1 is equal to v2 */ baseRuntime += "const compareEqualSlow = (v1, v2) => {\n const n1 = +v1;\n if (isNaN(n1) || (n1 === 0 && isWhiteSpace(v1))) return ('' + v1).toLowerCase() === ('' + v2).toLowerCase();\n const n2 = +v2;\n if (isNaN(n2) || (n2 === 0 && isWhiteSpace(v2))) return ('' + v1).toLowerCase() === ('' + v2).toLowerCase();\n return n1 === n2;\n};\nconst compareEqual = (v1, v2) => (typeof v1 === 'number' && typeof v2 === 'number' && !isNaN(v1) && !isNaN(v2) || v1 === v2) ? v1 === v2 : compareEqualSlow(v1, v2);"; /** * Determine if one value is greater than another. * @param {*} v1 First value * @param {*} v2 Second value * @returns {boolean} true if v1 is greater than v2 */ runtimeFunctions.compareGreaterThan = "const compareGreaterThanSlow = (v1, v2) => {\n let n1 = +v1;\n let n2 = +v2;\n if (n1 === 0 && isWhiteSpace(v1)) {\n n1 = NaN;\n } else if (n2 === 0 && isWhiteSpace(v2)) {\n n2 = NaN;\n }\n if (isNaN(n1) || isNaN(n2)) {\n const s1 = ('' + v1).toLowerCase();\n const s2 = ('' + v2).toLowerCase();\n return s1 > s2;\n }\n return n1 > n2;\n};\nconst compareGreaterThan = (v1, v2) => typeof v1 === 'number' && typeof v2 === 'number' && !isNaN(v1) ? v1 > v2 : compareGreaterThanSlow(v1, v2)"; /** * Determine if one value is less than another. * @param {*} v1 First value * @param {*} v2 Second value * @returns {boolean} true if v1 is less than v2 */ runtimeFunctions.compareLessThan = "const compareLessThanSlow = (v1, v2) => {\n let n1 = +v1;\n let n2 = +v2;\n if (n1 === 0 && isWhiteSpace(v1)) {\n n1 = NaN;\n } else if (n2 === 0 && isWhiteSpace(v2)) {\n n2 = NaN;\n }\n if (isNaN(n1) || isNaN(n2)) {\n const s1 = ('' + v1).toLowerCase();\n const s2 = ('' + v2).toLowerCase();\n return s1 < s2;\n }\n return n1 < n2;\n};\nconst compareLessThan = (v1, v2) => typeof v1 === 'number' && typeof v2 === 'number' && !isNaN(v2) ? v1 < v2 : compareLessThanSlow(v1, v2)"; /** * Generate a random integer. * @param {number} low Lower bound * @param {number} high Upper bound * @returns {number} A random integer between low and high, inclusive. */ runtimeFunctions.randomInt = "const randomInt = (low, high) => low + Math.floor(Math.random() * ((high + 1) - low))"; /** * Generate a random float. * @param {number} low Lower bound * @param {number} high Upper bound * @returns {number} A random floating point number between low and high. */ runtimeFunctions.randomFloat = "const randomFloat = (low, high) => (Math.random() * (high - low)) + low"; /** * Create and start a timer. * @returns {Timer} A started timer */ runtimeFunctions.timer = "const timer = () => {\n const t = new globalState.Timer({\n now: () => globalState.thread.target.runtime.currentMSecs\n });\n t.start();\n return t;\n}"; /** * Returns the amount of days since January 1st, 2000. * @returns {number} Days since 2000. */ // Date.UTC(2000, 0, 1) === 946684800000 // Hardcoding it is marginally faster runtimeFunctions.daysSince2000 = "const daysSince2000 = () => (Date.now() - 946684800000) / (24 * 60 * 60 * 1000)"; /** * Determine distance to a sprite or point. * @param {string} menu The name of the sprite or location to find. * @returns {number} Distance to the point, or 10000 if it cannot be calculated. */ runtimeFunctions.distance = "const distance = menu => {\n const thread = globalState.thread;\n if (thread.target.isStage) return 10000;\n\n let targetX = 0;\n let targetY = 0;\n if (menu === '_mouse_') {\n targetX = thread.target.runtime.ioDevices.mouse.getScratchX();\n targetY = thread.target.runtime.ioDevices.mouse.getScratchY();\n } else {\n const distTarget = thread.target.runtime.getSpriteTargetByName(menu);\n if (!distTarget) return 10000;\n targetX = distTarget.x;\n targetY = distTarget.y;\n }\n\n const dx = thread.target.x - targetX;\n const dy = thread.target.y - targetY;\n return Math.sqrt((dx * dx) + (dy * dy));\n}"; /** * Convert a Scratch list index to a JavaScript list index. * "all" is not considered as a list index. * Similar to Cast.toListIndex() * @param {number} index Scratch list index. * @param {number} length Length of the list. * @returns {number} 0 based list index, or -1 if invalid. */ baseRuntime += "const listIndexSlow = (index, length) => {\n if (index === 'last') {\n return length - 1;\n } else if (index === 'random' || index === 'any') {\n if (length > 0) {\n return (Math.random() * length) | 0;\n }\n return -1;\n }\n index = (+index || 0) | 0;\n if (index < 1 || index > length) {\n return -1;\n }\n return index - 1;\n};\nconst listIndex = (index, length) => {\n if (typeof index !== 'number') {\n return listIndexSlow(index, length);\n }\n index = index | 0;\n return index < 1 || index > length ? -1 : index - 1;\n};"; /** * Get a value from a list. * @param {Array} list The list * @param {*} idx The 1-indexed index in the list. * @returns {*} The list item, otherwise empty string if it does not exist. */ runtimeFunctions.listGet = "const listGet = (list, idx) => {\n const index = listIndex(idx, list.length);\n if (index === -1) {\n return '';\n }\n return list[index];\n}"; /** * Replace a value in a list. * @param {import('../engine/variable')} list The list * @param {*} idx List index, Scratch style. * @param {*} value The new value. */ runtimeFunctions.listReplace = "const listReplace = (list, idx, value) => {\n const index = listIndex(idx, list.value.length);\n if (index === -1) {\n return;\n }\n list.value[index] = value;\n list._monitorUpToDate = false;\n}"; /** * Insert a value in a list. * @param {import('../engine/variable')} list The list. * @param {*} idx The Scratch index in the list. * @param {*} value The value to insert. */ runtimeFunctions.listInsert = "const listInsert = (list, idx, value) => {\n const index = listIndex(idx, list.value.length + 1);\n if (index === -1) {\n return;\n }\n list.value.splice(index, 0, value);\n list._monitorUpToDate = false;\n}"; /** * Delete a value from a list. * @param {import('../engine/variable')} list The list. * @param {*} idx The Scratch index in the list. */ runtimeFunctions.listDelete = "const listDelete = (list, idx) => {\n if (idx === 'all') {\n list.value = [];\n return;\n }\n const index = listIndex(idx, list.value.length);\n if (index === -1) {\n return;\n }\n list.value.splice(index, 1);\n list._monitorUpToDate = false;\n}"; /** * Return whether a list contains a value. * @param {import('../engine/variable')} list The list. * @param {*} item The value to search for. * @returns {boolean} True if the list contains the item */ runtimeFunctions.listContains = "const listContains = (list, item) => {\n // TODO: evaluate whether indexOf is worthwhile here\n if (list.value.indexOf(item) !== -1) {\n return true;\n }\n for (let i = 0; i < list.value.length; i++) {\n if (compareEqual(list.value[i], item)) {\n return true;\n }\n }\n return false;\n}"; /** * Find the 1-indexed index of an item in a list. * @param {import('../engine/variable')} list The list. * @param {*} item The item to search for * @returns {number} The 1-indexed index of the item in the list, otherwise 0 */ runtimeFunctions.listIndexOf = "const listIndexOf = (list, item) => {\n for (let i = 0; i < list.value.length; i++) {\n if (compareEqual(list.value[i], item)) {\n return i + 1;\n }\n }\n return 0;\n}"; /** * Get the stringified form of a list. * @param {import('../engine/variable')} list The list. * @returns {string} Stringified form of the list. */ runtimeFunctions.listContents = "const listContents = list => {\n for (let i = 0; i < list.value.length; i++) {\n const listItem = list.value[i];\n // this is an intentional break from what scratch 3 does to address our automatic string -> number conversions\n // it fixes more than it breaks\n if ((listItem + '').length !== 1) {\n return list.value.join(' ');\n }\n }\n return list.value.join('');\n}"; /** * Convert a color to an RGB list * @param {*} color The color value to convert * @return {Array.} [r,g,b], values between 0-255. */ runtimeFunctions.colorToList = "const colorToList = color => globalState.Cast.toRgbColorList(color)"; /** * Implements Scratch modulo (floored division instead of truncated division) * @param {number} n Number * @param {number} modulus Base * @returns {number} n % modulus (floored division) */ runtimeFunctions.mod = "const mod = (n, modulus) => {\n let result = n % modulus;\n if (result / modulus < 0) result += modulus;\n return result;\n}"; /** * Implements Scratch tangent. * @param {number} angle Angle in degrees. * @returns {number} value of tangent or Infinity or -Infinity */ runtimeFunctions.tan = "const tan = (angle) => {\n switch (angle % 360) {\n case -270: case 90: return Infinity;\n case -90: case 270: return -Infinity;\n }\n return Math.round(Math.tan((Math.PI * angle) / 180) * 1e10) / 1e10;\n}"; /** * Step a compiled thread. * @param {Thread} thread The thread to step. */ const execute = thread => { globalState.thread = thread; thread.generator.next(); }; const insertRuntime = source => { let result = baseRuntime; for (const functionName of Object.keys(runtimeFunctions)) { if (source.includes(functionName)) { result += "".concat(runtimeFunctions[functionName], ";"); } } result += "return ".concat(source); return result; }; /** * Evaluate arbitrary JS in the context of the runtime. * @param {string} source The string to evaluate. * @returns {*} The result of evaluating the string. */ const scopedEval = source => { const withRuntime = insertRuntime(source); try { return new Function('globalState', withRuntime)(globalState); } catch (e) { globalState.log.error('was unable to compile script', withRuntime); throw e; } }; execute.scopedEval = scopedEval; execute.runtimeFunctions = runtimeFunctions; module.exports = execute; /***/ }), /***/ "./node_modules/scratch-vm/src/compiler/jsgen.js": /*!*******************************************************!*\ !*** ./node_modules/scratch-vm/src/compiler/jsgen.js ***! \*******************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const log = __webpack_require__(/*! ../util/log */ "./node_modules/scratch-vm/src/util/log.js"); const Cast = __webpack_require__(/*! ../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); const VariablePool = __webpack_require__(/*! ./variable-pool */ "./node_modules/scratch-vm/src/compiler/variable-pool.js"); const jsexecute = __webpack_require__(/*! ./jsexecute */ "./node_modules/scratch-vm/src/compiler/jsexecute.js"); const environment = __webpack_require__(/*! ./environment */ "./node_modules/scratch-vm/src/compiler/environment.js"); // Imported for JSDoc types, not to actually use // eslint-disable-next-line no-unused-vars const { IntermediateScript, IntermediateRepresentation } = __webpack_require__(/*! ./intermediate */ "./node_modules/scratch-vm/src/compiler/intermediate.js"); /** * @fileoverview Convert intermediate representations to JavaScript functions. */ /* eslint-disable max-len */ /* eslint-disable prefer-template */ const sanitize = string => { if (typeof string !== 'string') { log.warn("sanitize got unexpected type: ".concat(typeof string)); string = '' + string; } return JSON.stringify(string).slice(1, -1); }; const TYPE_NUMBER = 1; const TYPE_STRING = 2; const TYPE_BOOLEAN = 3; const TYPE_UNKNOWN = 4; const TYPE_NUMBER_NAN = 5; // Pen-related constants const PEN_EXT = 'runtime.ext_pen'; const PEN_STATE = "".concat(PEN_EXT, "._getPenState(target)"); /** * Variable pool used for factory function names. */ const factoryNameVariablePool = new VariablePool('factory'); /** * Variable pool used for generated functions (non-generator) */ const functionNameVariablePool = new VariablePool('fun'); /** * Variable pool used for generated generator functions. */ const generatorNameVariablePool = new VariablePool('gen'); /** * @typedef Input * @property {() => string} asNumber * @property {() => string} asNumberOrNaN * @property {() => string} asString * @property {() => string} asBoolean * @property {() => string} asUnknown * @property {() => string} asSafe * @property {() => boolean} isAlwaysNumber * @property {() => boolean} isAlwaysNumberOrNaN * @property {() => boolean} isNeverNumber */ /** * @implements {Input} */ class TypedInput { constructor(source, type) { // for debugging if (typeof type !== 'number') throw new Error('type is invalid'); this.source = source; this.type = type; } asNumber() { if (this.type === TYPE_NUMBER) return this.source; if (this.type === TYPE_NUMBER_NAN) return "(".concat(this.source, " || 0)"); return "(+".concat(this.source, " || 0)"); } asNumberOrNaN() { if (this.type === TYPE_NUMBER || this.type === TYPE_NUMBER_NAN) return this.source; return "(+".concat(this.source, ")"); } asString() { if (this.type === TYPE_STRING) return this.source; return "(\"\" + ".concat(this.source, ")"); } asBoolean() { if (this.type === TYPE_BOOLEAN) return this.source; return "toBoolean(".concat(this.source, ")"); } asUnknown() { return this.source; } asSafe() { return this.asUnknown(); } isAlwaysNumber() { return this.type === TYPE_NUMBER; } isAlwaysNumberOrNaN() { return this.type === TYPE_NUMBER || this.type === TYPE_NUMBER_NAN; } isNeverNumber() { return false; } } /** * @implements {Input} */ class ConstantInput { constructor(constantValue, safe) { this.constantValue = constantValue; this.safe = safe; } asNumber() { // Compute at compilation time const numberValue = +this.constantValue; if (numberValue) { // It's important that we use the number's stringified value and not the constant value // Using the constant value allows numbers such as "010" to be interpreted as 8 (or SyntaxError in strict mode) instead of 10. return numberValue.toString(); } // numberValue is one of 0, -0, or NaN if (Object.is(numberValue, -0)) { return '-0'; } return '0'; } asNumberOrNaN() { return this.asNumber(); } asString() { return "\"".concat(sanitize('' + this.constantValue), "\""); } asBoolean() { // Compute at compilation time return Cast.toBoolean(this.constantValue).toString(); } asUnknown() { // Attempt to convert strings to numbers if it is unlikely to break things if (typeof this.constantValue === 'number') { // todo: handle NaN? return this.constantValue; } const numberValue = +this.constantValue; if (numberValue.toString() === this.constantValue) { return this.constantValue; } return this.asString(); } asSafe() { if (this.safe) { return this.asUnknown(); } return this.asString(); } isAlwaysNumber() { const value = +this.constantValue; if (Number.isNaN(value)) { return false; } // Empty strings evaluate to 0 but should not be considered a number. if (value === 0) { return this.constantValue.toString().trim() !== ''; } return true; } isAlwaysNumberOrNaN() { return this.isAlwaysNumber(); } isNeverNumber() { return Number.isNaN(+this.constantValue); } } /** * @implements {Input} */ class VariableInput { constructor(source) { this.source = source; this.type = TYPE_UNKNOWN; /** * The value this variable was most recently set to, if any. * @type {Input} * @private */ this._value = null; } /** * @param {Input} input The input this variable was most recently set to. */ setInput(input) { if (input instanceof VariableInput) { // When being set to another variable, extract the value it was set to. // Otherwise, you may end up with infinite recursion in analysis methods when a variable is set to itself. if (input._value) { input = input._value; } else { this.type = TYPE_UNKNOWN; this._value = null; return; } } this._value = input; if (input instanceof TypedInput) { this.type = input.type; } else { this.type = TYPE_UNKNOWN; } } asNumber() { if (this.type === TYPE_NUMBER) return this.source; if (this.type === TYPE_NUMBER_NAN) return "(".concat(this.source, " || 0)"); return "(+".concat(this.source, " || 0)"); } asNumberOrNaN() { if (this.type === TYPE_NUMBER || this.type === TYPE_NUMBER_NAN) return this.source; return "(+".concat(this.source, ")"); } asString() { if (this.type === TYPE_STRING) return this.source; return "(\"\" + ".concat(this.source, ")"); } asBoolean() { if (this.type === TYPE_BOOLEAN) return this.source; return "toBoolean(".concat(this.source, ")"); } asUnknown() { return this.source; } asSafe() { return this.asUnknown(); } isAlwaysNumber() { if (this._value) { return this._value.isAlwaysNumber(); } return false; } isAlwaysNumberOrNaN() { if (this._value) { return this._value.isAlwaysNumberOrNaN(); } return false; } isNeverNumber() { if (this._value) { return this._value.isNeverNumber(); } return false; } } const getNamesOfCostumesAndSounds = runtime => { const result = new Set(); for (const target of runtime.targets) { if (target.isOriginal) { const sprite = target.sprite; for (const costume of sprite.costumes) { result.add(costume.name); } for (const sound of sprite.sounds) { result.add(sound.name); } } } return result; }; const isSafeConstantForEqualsOptimization = input => { const numberValue = +input.constantValue; // Do not optimize 0 if (!numberValue) { return false; } // Do not optimize numbers when the original form does not match return numberValue.toString() === input.constantValue.toString(); }; /** * A frame contains some information about the current substack being compiled. */ class Frame { constructor(isLoop) { /** * Whether the current stack runs in a loop (while, for) * @type {boolean} * @readonly */ this.isLoop = isLoop; /** * Whether the current block is the last block in the stack. * @type {boolean} */ this.isLastBlock = false; } } class JSGenerator { /** * @param {IntermediateScript} script * @param {IntermediateRepresentation} ir * @param {Target} target */ constructor(script, ir, target) { this.script = script; this.ir = ir; this.target = target; this.source = ''; /** * @type {Object.} */ this.variableInputs = {}; this.isWarp = script.isWarp; this.isProcedure = script.isProcedure; this.warpTimer = script.warpTimer; /** * Stack of frames, most recent is last item. * @type {Frame[]} */ this.frames = []; /** * The current Frame. * @type {Frame} */ this.currentFrame = null; this.namesOfCostumesAndSounds = getNamesOfCostumesAndSounds(target.runtime); this.localVariables = new VariablePool('a'); this._setupVariablesPool = new VariablePool('b'); this._setupVariables = {}; this.descendedIntoModulo = false; this.debug = this.target.runtime.debug; } /** * Enter a new frame * @param {Frame} frame New frame. */ pushFrame(frame) { this.frames.push(frame); this.currentFrame = frame; } /** * Exit the current frame */ popFrame() { this.frames.pop(); this.currentFrame = this.frames[this.frames.length - 1]; } /** * @returns {boolean} true if the current block is the last command of a loop */ isLastBlockInLoop() { for (let i = this.frames.length - 1; i >= 0; i--) { const frame = this.frames[i]; if (!frame.isLastBlock) { return false; } if (frame.isLoop) { return true; } } return false; } /** * @param {object} node Input node to compile. * @returns {Input} Compiled input. */ descendInput(node) { switch (node.kind) { case 'args.boolean': return new TypedInput("toBoolean(p".concat(node.index, ")"), TYPE_BOOLEAN); case 'args.stringNumber': return new TypedInput("p".concat(node.index), TYPE_UNKNOWN); case 'compat': // Compatibility layer inputs never use flags. return new TypedInput("(".concat(this.generateCompatibilityLayerCall(node, false), ")"), TYPE_UNKNOWN); case 'constant': return this.safeConstantInput(node.value); case 'keyboard.pressed': return new TypedInput("runtime.ioDevices.keyboard.getKeyIsDown(".concat(this.descendInput(node.key).asSafe(), ")"), TYPE_BOOLEAN); case 'list.contains': return new TypedInput("listContains(".concat(this.referenceVariable(node.list), ", ").concat(this.descendInput(node.item).asUnknown(), ")"), TYPE_BOOLEAN); case 'list.contents': return new TypedInput("listContents(".concat(this.referenceVariable(node.list), ")"), TYPE_STRING); case 'list.get': { const index = this.descendInput(node.index); if (environment.supportsNullishCoalescing) { if (index.isAlwaysNumberOrNaN()) { return new TypedInput("(".concat(this.referenceVariable(node.list), ".value[(").concat(index.asNumber(), " | 0) - 1] ?? \"\")"), TYPE_UNKNOWN); } if (index instanceof ConstantInput && index.constantValue === 'last') { return new TypedInput("(".concat(this.referenceVariable(node.list), ".value[").concat(this.referenceVariable(node.list), ".value.length - 1] ?? \"\")"), TYPE_UNKNOWN); } } return new TypedInput("listGet(".concat(this.referenceVariable(node.list), ".value, ").concat(index.asUnknown(), ")"), TYPE_UNKNOWN); } case 'list.indexOf': return new TypedInput("listIndexOf(".concat(this.referenceVariable(node.list), ", ").concat(this.descendInput(node.item).asUnknown(), ")"), TYPE_NUMBER); case 'list.length': return new TypedInput("".concat(this.referenceVariable(node.list), ".value.length"), TYPE_NUMBER); case 'looks.size': return new TypedInput('Math.round(target.size)', TYPE_NUMBER); case 'looks.backdropName': return new TypedInput('stage.getCostumes()[stage.currentCostume].name', TYPE_STRING); case 'looks.backdropNumber': return new TypedInput('(stage.currentCostume + 1)', TYPE_NUMBER); case 'looks.costumeName': return new TypedInput('target.getCostumes()[target.currentCostume].name', TYPE_STRING); case 'looks.costumeNumber': return new TypedInput('(target.currentCostume + 1)', TYPE_NUMBER); case 'motion.direction': return new TypedInput('target.direction', TYPE_NUMBER); case 'motion.x': return new TypedInput('limitPrecision(target.x)', TYPE_NUMBER); case 'motion.y': return new TypedInput('limitPrecision(target.y)', TYPE_NUMBER); case 'mouse.down': return new TypedInput('runtime.ioDevices.mouse.getIsDown()', TYPE_BOOLEAN); case 'mouse.x': return new TypedInput('runtime.ioDevices.mouse.getScratchX()', TYPE_NUMBER); case 'mouse.y': return new TypedInput('runtime.ioDevices.mouse.getScratchY()', TYPE_NUMBER); case 'op.abs': return new TypedInput("Math.abs(".concat(this.descendInput(node.value).asNumber(), ")"), TYPE_NUMBER); case 'op.acos': // Needs to be marked as NaN because Math.acos(1.0001) === NaN return new TypedInput("((Math.acos(".concat(this.descendInput(node.value).asNumber(), ") * 180) / Math.PI)"), TYPE_NUMBER_NAN); case 'op.add': // Needs to be marked as NaN because Infinity + -Infinity === NaN return new TypedInput("(".concat(this.descendInput(node.left).asNumber(), " + ").concat(this.descendInput(node.right).asNumber(), ")"), TYPE_NUMBER_NAN); case 'op.and': return new TypedInput("(".concat(this.descendInput(node.left).asBoolean(), " && ").concat(this.descendInput(node.right).asBoolean(), ")"), TYPE_BOOLEAN); case 'op.asin': // Needs to be marked as NaN because Math.asin(1.0001) === NaN return new TypedInput("((Math.asin(".concat(this.descendInput(node.value).asNumber(), ") * 180) / Math.PI)"), TYPE_NUMBER_NAN); case 'op.atan': return new TypedInput("((Math.atan(".concat(this.descendInput(node.value).asNumber(), ") * 180) / Math.PI)"), TYPE_NUMBER); case 'op.ceiling': return new TypedInput("Math.ceil(".concat(this.descendInput(node.value).asNumber(), ")"), TYPE_NUMBER); case 'op.contains': return new TypedInput("(".concat(this.descendInput(node.string).asString(), ".toLowerCase().indexOf(").concat(this.descendInput(node.contains).asString(), ".toLowerCase()) !== -1)"), TYPE_BOOLEAN); case 'op.cos': return new TypedInput("(Math.round(Math.cos((Math.PI * ".concat(this.descendInput(node.value).asNumber(), ") / 180) * 1e10) / 1e10)"), TYPE_NUMBER); case 'op.divide': // Needs to be marked as NaN because 0 / 0 === NaN return new TypedInput("(".concat(this.descendInput(node.left).asNumber(), " / ").concat(this.descendInput(node.right).asNumber(), ")"), TYPE_NUMBER_NAN); case 'op.equals': { const left = this.descendInput(node.left); const right = this.descendInput(node.right); // When both operands are known to never be numbers, only use string comparison to avoid all number parsing. if (left.isNeverNumber() || right.isNeverNumber()) { return new TypedInput("(".concat(left.asString(), ".toLowerCase() === ").concat(right.asString(), ".toLowerCase())"), TYPE_BOOLEAN); } const leftAlwaysNumber = left.isAlwaysNumber(); const rightAlwaysNumber = right.isAlwaysNumber(); // When both operands are known to be numbers, we can use === if (leftAlwaysNumber && rightAlwaysNumber) { return new TypedInput("(".concat(left.asNumber(), " === ").concat(right.asNumber(), ")"), TYPE_BOOLEAN); } // In certain conditions, we can use === when one of the operands is known to be a safe number. if (leftAlwaysNumber && left instanceof ConstantInput && isSafeConstantForEqualsOptimization(left)) { return new TypedInput("(".concat(left.asNumber(), " === ").concat(right.asNumber(), ")"), TYPE_BOOLEAN); } if (rightAlwaysNumber && right instanceof ConstantInput && isSafeConstantForEqualsOptimization(right)) { return new TypedInput("(".concat(left.asNumber(), " === ").concat(right.asNumber(), ")"), TYPE_BOOLEAN); } // No compile-time optimizations possible - use fallback method. return new TypedInput("compareEqual(".concat(left.asUnknown(), ", ").concat(right.asUnknown(), ")"), TYPE_BOOLEAN); } case 'op.e^': return new TypedInput("Math.exp(".concat(this.descendInput(node.value).asNumber(), ")"), TYPE_NUMBER); case 'op.floor': return new TypedInput("Math.floor(".concat(this.descendInput(node.value).asNumber(), ")"), TYPE_NUMBER); case 'op.greater': { const left = this.descendInput(node.left); const right = this.descendInput(node.right); // When the left operand is a number and the right operand is a number or NaN, we can use > if (left.isAlwaysNumber() && right.isAlwaysNumberOrNaN()) { return new TypedInput("(".concat(left.asNumber(), " > ").concat(right.asNumberOrNaN(), ")"), TYPE_BOOLEAN); } // When the left operand is a number or NaN and the right operand is a number, we can negate <= if (left.isAlwaysNumberOrNaN() && right.isAlwaysNumber()) { return new TypedInput("!(".concat(left.asNumberOrNaN(), " <= ").concat(right.asNumber(), ")"), TYPE_BOOLEAN); } // When either operand is known to never be a number, avoid all number parsing. if (left.isNeverNumber() || right.isNeverNumber()) { return new TypedInput("(".concat(left.asString(), ".toLowerCase() > ").concat(right.asString(), ".toLowerCase())"), TYPE_BOOLEAN); } // No compile-time optimizations possible - use fallback method. return new TypedInput("compareGreaterThan(".concat(left.asUnknown(), ", ").concat(right.asUnknown(), ")"), TYPE_BOOLEAN); } case 'op.join': return new TypedInput("(".concat(this.descendInput(node.left).asString(), " + ").concat(this.descendInput(node.right).asString(), ")"), TYPE_STRING); case 'op.length': return new TypedInput("".concat(this.descendInput(node.string).asString(), ".length"), TYPE_NUMBER); case 'op.less': { const left = this.descendInput(node.left); const right = this.descendInput(node.right); // When the left operand is a number or NaN and the right operand is a number, we can use < if (left.isAlwaysNumberOrNaN() && right.isAlwaysNumber()) { return new TypedInput("(".concat(left.asNumberOrNaN(), " < ").concat(right.asNumber(), ")"), TYPE_BOOLEAN); } // When the left operand is a number and the right operand is a number or NaN, we can negate >= if (left.isAlwaysNumber() && right.isAlwaysNumberOrNaN()) { return new TypedInput("!(".concat(left.asNumber(), " >= ").concat(right.asNumberOrNaN(), ")"), TYPE_BOOLEAN); } // When either operand is known to never be a number, avoid all number parsing. if (left.isNeverNumber() || right.isNeverNumber()) { return new TypedInput("(".concat(left.asString(), ".toLowerCase() < ").concat(right.asString(), ".toLowerCase())"), TYPE_BOOLEAN); } // No compile-time optimizations possible - use fallback method. return new TypedInput("compareLessThan(".concat(left.asUnknown(), ", ").concat(right.asUnknown(), ")"), TYPE_BOOLEAN); } case 'op.letterOf': return new TypedInput("((".concat(this.descendInput(node.string).asString(), ")[(").concat(this.descendInput(node.letter).asNumber(), " | 0) - 1] || \"\")"), TYPE_STRING); case 'op.ln': // Needs to be marked as NaN because Math.log(-1) == NaN return new TypedInput("Math.log(".concat(this.descendInput(node.value).asNumber(), ")"), TYPE_NUMBER_NAN); case 'op.log': // Needs to be marked as NaN because Math.log(-1) == NaN return new TypedInput("(Math.log(".concat(this.descendInput(node.value).asNumber(), ") / Math.LN10)"), TYPE_NUMBER_NAN); case 'op.mod': this.descendedIntoModulo = true; // Needs to be marked as NaN because mod(0, 0) (and others) == NaN return new TypedInput("mod(".concat(this.descendInput(node.left).asNumber(), ", ").concat(this.descendInput(node.right).asNumber(), ")"), TYPE_NUMBER_NAN); case 'op.multiply': // Needs to be marked as NaN because Infinity * 0 === NaN return new TypedInput("(".concat(this.descendInput(node.left).asNumber(), " * ").concat(this.descendInput(node.right).asNumber(), ")"), TYPE_NUMBER_NAN); case 'op.not': return new TypedInput("!".concat(this.descendInput(node.operand).asBoolean()), TYPE_BOOLEAN); case 'op.or': return new TypedInput("(".concat(this.descendInput(node.left).asBoolean(), " || ").concat(this.descendInput(node.right).asBoolean(), ")"), TYPE_BOOLEAN); case 'op.random': if (node.useInts) { return new TypedInput("randomInt(".concat(this.descendInput(node.low).asNumber(), ", ").concat(this.descendInput(node.high).asNumber(), ")"), TYPE_NUMBER); } if (node.useFloats) { return new TypedInput("randomFloat(".concat(this.descendInput(node.low).asNumber(), ", ").concat(this.descendInput(node.high).asNumber(), ")"), TYPE_NUMBER); } return new TypedInput("runtime.ext_scratch3_operators._random(".concat(this.descendInput(node.low).asUnknown(), ", ").concat(this.descendInput(node.high).asUnknown(), ")"), TYPE_NUMBER); case 'op.round': return new TypedInput("Math.round(".concat(this.descendInput(node.value).asNumber(), ")"), TYPE_NUMBER); case 'op.sin': return new TypedInput("(Math.round(Math.sin((Math.PI * ".concat(this.descendInput(node.value).asNumber(), ") / 180) * 1e10) / 1e10)"), TYPE_NUMBER); case 'op.sqrt': // Needs to be marked as NaN because Math.sqrt(-1) === NaN return new TypedInput("Math.sqrt(".concat(this.descendInput(node.value).asNumber(), ")"), TYPE_NUMBER_NAN); case 'op.subtract': // Needs to be marked as NaN because Infinity - Infinity === NaN return new TypedInput("(".concat(this.descendInput(node.left).asNumber(), " - ").concat(this.descendInput(node.right).asNumber(), ")"), TYPE_NUMBER_NAN); case 'op.tan': return new TypedInput("tan(".concat(this.descendInput(node.value).asNumber(), ")"), TYPE_NUMBER); case 'op.10^': return new TypedInput("(10 ** ".concat(this.descendInput(node.value).asNumber(), ")"), TYPE_NUMBER); case 'sensing.answer': return new TypedInput("runtime.ext_scratch3_sensing._answer", TYPE_STRING); case 'sensing.colorTouchingColor': return new TypedInput("target.colorIsTouchingColor(colorToList(".concat(this.descendInput(node.target).asUnknown(), "), colorToList(").concat(this.descendInput(node.mask).asUnknown(), "))"), TYPE_BOOLEAN); case 'sensing.date': return new TypedInput("(new Date().getDate())", TYPE_NUMBER); case 'sensing.dayofweek': return new TypedInput("(new Date().getDay() + 1)", TYPE_NUMBER); case 'sensing.daysSince2000': return new TypedInput('daysSince2000()', TYPE_NUMBER); case 'sensing.distance': // TODO: on stages, this can be computed at compile time return new TypedInput("distance(".concat(this.descendInput(node.target).asString(), ")"), TYPE_NUMBER); case 'sensing.hour': return new TypedInput("(new Date().getHours())", TYPE_NUMBER); case 'sensing.minute': return new TypedInput("(new Date().getMinutes())", TYPE_NUMBER); case 'sensing.month': return new TypedInput("(new Date().getMonth() + 1)", TYPE_NUMBER); case 'sensing.of': { const object = this.descendInput(node.object).asString(); const property = node.property; if (node.object.kind === 'constant') { const isStage = node.object.value === '_stage_'; // Note that if target isn't a stage, we can't assume it exists const objectReference = isStage ? 'stage' : this.evaluateOnce("runtime.getSpriteTargetByName(".concat(object, ")")); if (property === 'volume') { return new TypedInput("(".concat(objectReference, " ? ").concat(objectReference, ".volume : 0)"), TYPE_NUMBER); } if (isStage) { switch (property) { case 'background #': // fallthrough for scratch 1.0 compatibility case 'backdrop #': return new TypedInput("(".concat(objectReference, ".currentCostume + 1)"), TYPE_NUMBER); case 'backdrop name': return new TypedInput("".concat(objectReference, ".getCostumes()[").concat(objectReference, ".currentCostume].name"), TYPE_STRING); } } else { switch (property) { case 'x position': return new TypedInput("(".concat(objectReference, " ? ").concat(objectReference, ".x : 0)"), TYPE_NUMBER); case 'y position': return new TypedInput("(".concat(objectReference, " ? ").concat(objectReference, ".y : 0)"), TYPE_NUMBER); case 'direction': return new TypedInput("(".concat(objectReference, " ? ").concat(objectReference, ".direction : 0)"), TYPE_NUMBER); case 'costume #': return new TypedInput("(".concat(objectReference, " ? ").concat(objectReference, ".currentCostume + 1 : 0)"), TYPE_NUMBER); case 'costume name': return new TypedInput("(".concat(objectReference, " ? ").concat(objectReference, ".getCostumes()[").concat(objectReference, ".currentCostume].name : 0)"), TYPE_UNKNOWN); case 'size': return new TypedInput("(".concat(objectReference, " ? ").concat(objectReference, ".size : 0)"), TYPE_NUMBER); } } const variableReference = this.evaluateOnce("".concat(objectReference, " && ").concat(objectReference, ".lookupVariableByNameAndType(\"").concat(sanitize(property), "\", \"\", true)")); return new TypedInput("(".concat(variableReference, " ? ").concat(variableReference, ".value : 0)"), TYPE_UNKNOWN); } return new TypedInput("runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ".concat(object, ", PROPERTY: \"").concat(sanitize(property), "\" })"), TYPE_UNKNOWN); } case 'sensing.second': return new TypedInput("(new Date().getSeconds())", TYPE_NUMBER); case 'sensing.touching': return new TypedInput("target.isTouchingObject(".concat(this.descendInput(node.object).asUnknown(), ")"), TYPE_BOOLEAN); case 'sensing.touchingColor': return new TypedInput("target.isTouchingColor(colorToList(".concat(this.descendInput(node.color).asUnknown(), "))"), TYPE_BOOLEAN); case 'sensing.username': return new TypedInput('runtime.ioDevices.userData.getUsername()', TYPE_STRING); case 'sensing.year': return new TypedInput("(new Date().getFullYear())", TYPE_NUMBER); case 'timer.get': return new TypedInput('runtime.ioDevices.clock.projectTimer()', TYPE_NUMBER); case 'tw.lastKeyPressed': return new TypedInput('runtime.ioDevices.keyboard.getLastKeyPressed()', TYPE_STRING); case 'var.get': return this.descendVariable(node.variable); default: log.warn("JS: Unknown input: ".concat(node.kind), node); throw new Error("JS: Unknown input: ".concat(node.kind)); } } /** * @param {*} node Stacked node to compile. */ descendStackedBlock(node) { switch (node.kind) { case 'addons.call': this.source += "yield* callAddonBlock(\"".concat(sanitize(node.code), "\",\"").concat(sanitize(node.blockId), "\",{"); this.yielded(); for (const argumentName of Object.keys(node.arguments)) { const argumentValue = node.arguments[argumentName]; this.source += "\"".concat(sanitize(argumentName), "\":").concat(this.descendInput(argumentValue).asSafe(), ","); } this.source += '});\n'; break; case 'compat': { // If the last command in a loop returns a promise, immediately continue to the next iteration. // If you don't do this, the loop effectively yields twice per iteration and will run at half-speed. const isLastInLoop = this.isLastBlockInLoop(); this.source += "".concat(this.generateCompatibilityLayerCall(node, isLastInLoop), ";\n"); if (isLastInLoop) { this.source += 'if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;}\n'; } break; } case 'control.createClone': this.source += "runtime.ext_scratch3_control._createClone(".concat(this.descendInput(node.target).asString(), ", target);\n"); break; case 'control.deleteClone': this.source += 'if (!target.isOriginal) {\n'; this.source += ' runtime.disposeTarget(target);\n'; this.source += ' runtime.stopForTarget(target);\n'; this.retire(); this.source += '}\n'; break; case 'control.for': { this.resetVariableInputs(); const index = this.localVariables.next(); this.source += "var ".concat(index, " = 0; "); this.source += "while (".concat(index, " < ").concat(this.descendInput(node.count).asNumber(), ") { "); this.source += "".concat(index, "++; "); this.source += "".concat(this.referenceVariable(node.variable), ".value = ").concat(index, ";\n"); this.descendStack(node.do, new Frame(true)); this.yieldLoop(); this.source += '}\n'; break; } case 'control.if': this.source += "if (".concat(this.descendInput(node.condition).asBoolean(), ") {\n"); this.descendStack(node.whenTrue, new Frame(false)); // only add the else branch if it won't be empty // this makes scripts have a bit less useless noise in them if (node.whenFalse.length) { this.source += "} else {\n"; this.descendStack(node.whenFalse, new Frame(false)); } this.source += "}\n"; break; case 'control.repeat': { const i = this.localVariables.next(); this.source += "for (var ".concat(i, " = ").concat(this.descendInput(node.times).asNumber(), "; ").concat(i, " >= 0.5; ").concat(i, "--) {\n"); this.descendStack(node.do, new Frame(true)); this.yieldLoop(); this.source += "}\n"; break; } case 'control.stopAll': this.source += 'runtime.stopAll();\n'; this.retire(); break; case 'control.stopOthers': this.source += 'runtime.stopForTarget(target, thread);\n'; break; case 'control.stopScript': if (this.isProcedure) { this.source += 'return;\n'; } else { this.retire(); } break; case 'control.wait': { const duration = this.localVariables.next(); this.source += "thread.timer = timer();\n"; this.source += "var ".concat(duration, " = Math.max(0, 1000 * ").concat(this.descendInput(node.seconds).asNumber(), ");\n"); this.requestRedraw(); // always yield at least once, even on 0 second durations this.yieldNotWarp(); this.source += "while (thread.timer.timeElapsed() < ".concat(duration, ") {\n"); this.yieldStuckOrNotWarp(); this.source += '}\n'; this.source += 'thread.timer = null;\n'; break; } case 'control.waitUntil': { this.resetVariableInputs(); this.source += "while (!".concat(this.descendInput(node.condition).asBoolean(), ") {\n"); this.yieldStuckOrNotWarp(); this.source += "}\n"; break; } case 'control.while': this.resetVariableInputs(); this.source += "while (".concat(this.descendInput(node.condition).asBoolean(), ") {\n"); this.descendStack(node.do, new Frame(true)); if (node.warpTimer) { this.yieldStuckOrNotWarp(); } else { this.yieldLoop(); } this.source += "}\n"; break; case 'event.broadcast': this.source += "startHats(\"event_whenbroadcastreceived\", { BROADCAST_OPTION: ".concat(this.descendInput(node.broadcast).asString(), " });\n"); this.resetVariableInputs(); break; case 'event.broadcastAndWait': this.source += "yield* waitThreads(startHats(\"event_whenbroadcastreceived\", { BROADCAST_OPTION: ".concat(this.descendInput(node.broadcast).asString(), " }));\n"); this.yielded(); break; case 'list.add': { const list = this.referenceVariable(node.list); this.source += "".concat(list, ".value.push(").concat(this.descendInput(node.item).asSafe(), ");\n"); this.source += "".concat(list, "._monitorUpToDate = false;\n"); break; } case 'list.delete': { const list = this.referenceVariable(node.list); const index = this.descendInput(node.index); if (index instanceof ConstantInput) { if (index.constantValue === 'last') { this.source += "".concat(list, ".value.pop();\n"); this.source += "".concat(list, "._monitorUpToDate = false;\n"); break; } if (+index.constantValue === 1) { this.source += "".concat(list, ".value.shift();\n"); this.source += "".concat(list, "._monitorUpToDate = false;\n"); break; } // do not need a special case for all as that is handled in IR generation (list.deleteAll) } this.source += "listDelete(".concat(list, ", ").concat(index.asUnknown(), ");\n"); break; } case 'list.deleteAll': this.source += "".concat(this.referenceVariable(node.list), ".value = [];\n"); break; case 'list.hide': this.source += "runtime.monitorBlocks.changeBlock({ id: \"".concat(sanitize(node.list.id), "\", element: \"checkbox\", value: false }, runtime);\n"); break; case 'list.insert': { const list = this.referenceVariable(node.list); const index = this.descendInput(node.index); const item = this.descendInput(node.item); if (index instanceof ConstantInput && +index.constantValue === 1) { this.source += "".concat(list, ".value.unshift(").concat(item.asSafe(), ");\n"); this.source += "".concat(list, "._monitorUpToDate = false;\n"); break; } this.source += "listInsert(".concat(list, ", ").concat(index.asUnknown(), ", ").concat(item.asSafe(), ");\n"); break; } case 'list.replace': this.source += "listReplace(".concat(this.referenceVariable(node.list), ", ").concat(this.descendInput(node.index).asUnknown(), ", ").concat(this.descendInput(node.item).asSafe(), ");\n"); break; case 'list.show': this.source += "runtime.monitorBlocks.changeBlock({ id: \"".concat(sanitize(node.list.id), "\", element: \"checkbox\", value: true }, runtime);\n"); break; case 'looks.backwardLayers': if (!this.target.isStage) { this.source += "target.goBackwardLayers(".concat(this.descendInput(node.layers).asNumber(), ");\n"); } break; case 'looks.clearEffects': this.source += 'target.clearEffects();\n'; break; case 'looks.changeEffect': if (this.target.effects.hasOwnProperty(node.effect)) { this.source += "target.setEffect(\"".concat(sanitize(node.effect), "\", runtime.ext_scratch3_looks.clampEffect(\"").concat(sanitize(node.effect), "\", ").concat(this.descendInput(node.value).asNumber(), " + target.effects[\"").concat(sanitize(node.effect), "\"]));\n"); } break; case 'looks.changeSize': this.source += "target.setSize(target.size + ".concat(this.descendInput(node.size).asNumber(), ");\n"); break; case 'looks.forwardLayers': if (!this.target.isStage) { this.source += "target.goForwardLayers(".concat(this.descendInput(node.layers).asNumber(), ");\n"); } break; case 'looks.goToBack': if (!this.target.isStage) { this.source += 'target.goToBack();\n'; } break; case 'looks.goToFront': if (!this.target.isStage) { this.source += 'target.goToFront();\n'; } break; case 'looks.hide': this.source += 'target.setVisible(false);\n'; this.source += 'runtime.ext_scratch3_looks._renderBubble(target);\n'; break; case 'looks.nextBackdrop': this.source += 'runtime.ext_scratch3_looks._setBackdrop(stage, stage.currentCostume + 1, true);\n'; break; case 'looks.nextCostume': this.source += 'target.setCostume(target.currentCostume + 1);\n'; break; case 'looks.setEffect': if (this.target.effects.hasOwnProperty(node.effect)) { this.source += "target.setEffect(\"".concat(sanitize(node.effect), "\", runtime.ext_scratch3_looks.clampEffect(\"").concat(sanitize(node.effect), "\", ").concat(this.descendInput(node.value).asNumber(), "));\n"); } break; case 'looks.setSize': this.source += "target.setSize(".concat(this.descendInput(node.size).asNumber(), ");\n"); break; case 'looks.show': this.source += 'target.setVisible(true);\n'; this.source += 'runtime.ext_scratch3_looks._renderBubble(target);\n'; break; case 'looks.switchBackdrop': this.source += "runtime.ext_scratch3_looks._setBackdrop(stage, ".concat(this.descendInput(node.backdrop).asSafe(), ");\n"); break; case 'looks.switchCostume': this.source += "runtime.ext_scratch3_looks._setCostume(target, ".concat(this.descendInput(node.costume).asSafe(), ");\n"); break; case 'motion.changeX': this.source += "target.setXY(target.x + ".concat(this.descendInput(node.dx).asNumber(), ", target.y);\n"); break; case 'motion.changeY': this.source += "target.setXY(target.x, target.y + ".concat(this.descendInput(node.dy).asNumber(), ");\n"); break; case 'motion.ifOnEdgeBounce': this.source += "runtime.ext_scratch3_motion._ifOnEdgeBounce(target);\n"; break; case 'motion.setDirection': this.source += "target.setDirection(".concat(this.descendInput(node.direction).asNumber(), ");\n"); break; case 'motion.setRotationStyle': this.source += "target.setRotationStyle(\"".concat(sanitize(node.style), "\");\n"); break; case 'motion.setX': // fallthrough case 'motion.setY': // fallthrough case 'motion.setXY': { this.descendedIntoModulo = false; const x = 'x' in node ? this.descendInput(node.x).asNumber() : 'target.x'; const y = 'y' in node ? this.descendInput(node.y).asNumber() : 'target.y'; this.source += "target.setXY(".concat(x, ", ").concat(y, ");\n"); if (this.descendedIntoModulo) { this.source += "if (target.interpolationData) target.interpolationData = null;\n"; } break; } case 'motion.step': this.source += "runtime.ext_scratch3_motion._moveSteps(".concat(this.descendInput(node.steps).asNumber(), ", target);\n"); break; case 'noop': // todo: remove noop entirely break; case 'pen.clear': this.source += "".concat(PEN_EXT, ".clear();\n"); break; case 'pen.down': this.source += "".concat(PEN_EXT, "._penDown(target);\n"); break; case 'pen.changeParam': this.source += "".concat(PEN_EXT, "._setOrChangeColorParam(").concat(this.descendInput(node.param).asString(), ", ").concat(this.descendInput(node.value).asNumber(), ", ").concat(PEN_STATE, ", true);\n"); break; case 'pen.changeSize': this.source += "".concat(PEN_EXT, "._changePenSizeBy(").concat(this.descendInput(node.size).asNumber(), ", target);\n"); break; case 'pen.legacyChangeHue': this.source += "".concat(PEN_EXT, "._changePenHueBy(").concat(this.descendInput(node.hue).asNumber(), ", target);\n"); break; case 'pen.legacyChangeShade': this.source += "".concat(PEN_EXT, "._changePenShadeBy(").concat(this.descendInput(node.shade).asNumber(), ", target);\n"); break; case 'pen.legacySetHue': this.source += "".concat(PEN_EXT, "._setPenHueToNumber(").concat(this.descendInput(node.hue).asNumber(), ", target);\n"); break; case 'pen.legacySetShade': this.source += "".concat(PEN_EXT, "._setPenShadeToNumber(").concat(this.descendInput(node.shade).asNumber(), ", target);\n"); break; case 'pen.setColor': this.source += "".concat(PEN_EXT, "._setPenColorToColor(").concat(this.descendInput(node.color).asUnknown(), ", target);\n"); break; case 'pen.setParam': this.source += "".concat(PEN_EXT, "._setOrChangeColorParam(").concat(this.descendInput(node.param).asString(), ", ").concat(this.descendInput(node.value).asNumber(), ", ").concat(PEN_STATE, ", false);\n"); break; case 'pen.setSize': this.source += "".concat(PEN_EXT, "._setPenSizeTo(").concat(this.descendInput(node.size).asNumber(), ", target);\n"); break; case 'pen.stamp': this.source += "".concat(PEN_EXT, "._stamp(target);\n"); break; case 'pen.up': this.source += "".concat(PEN_EXT, "._penUp(target);\n"); break; case 'procedures.call': { const procedureCode = node.code; const procedureVariant = node.variant; // Do not generate any code for empty procedures. const procedureData = this.ir.procedures[procedureVariant]; if (procedureData.stack === null) { break; } if (!this.isWarp && procedureCode === this.script.procedureCode) { // Direct recursion yields. this.yieldNotWarp(); } if (procedureData.yields) { this.source += 'yield* '; if (!this.script.yields) { throw new Error('Script uses yielding procedure but is not marked as yielding.'); } } this.source += "thread.procedures[\"".concat(sanitize(procedureVariant), "\"]("); // Only include arguments if the procedure accepts any. if (procedureData.arguments.length) { const args = []; for (const input of node.arguments) { args.push(this.descendInput(input).asSafe()); } this.source += args.join(','); } this.source += ");\n"; // Variable input types may have changes after a procedure call. this.resetVariableInputs(); break; } case 'timer.reset': this.source += 'runtime.ioDevices.clock.resetProjectTimer();\n'; break; case 'tw.debugger': this.source += 'debugger;\n'; break; case 'var.hide': this.source += "runtime.monitorBlocks.changeBlock({ id: \"".concat(sanitize(node.variable.id), "\", element: \"checkbox\", value: false }, runtime);\n"); break; case 'var.set': { const variable = this.descendVariable(node.variable); const value = this.descendInput(node.value); variable.setInput(value); this.source += "".concat(variable.source, " = ").concat(value.asSafe(), ";\n"); if (node.variable.isCloud) { this.source += "runtime.ioDevices.cloud.requestUpdateVariable(\"".concat(sanitize(node.variable.name), "\", ").concat(variable.source, ");\n"); } break; } case 'var.show': this.source += "runtime.monitorBlocks.changeBlock({ id: \"".concat(sanitize(node.variable.id), "\", element: \"checkbox\", value: true }, runtime);\n"); break; case 'visualReport': { const value = this.localVariables.next(); this.source += "const ".concat(value, " = ").concat(this.descendInput(node.input).asUnknown(), ";"); // blocks like legacy no-ops can return a literal `undefined` this.source += "if (".concat(value, " !== undefined) runtime.visualReport(\"").concat(sanitize(this.script.topBlockId), "\", ").concat(value, ");\n"); break; } default: log.warn("JS: Unknown stacked block: ".concat(node.kind), node); throw new Error("JS: Unknown stacked block: ".concat(node.kind)); } } resetVariableInputs() { this.variableInputs = {}; } descendStack(nodes, frame) { // Entering a stack -- all bets are off. // TODO: allow if/else to inherit values this.resetVariableInputs(); this.pushFrame(frame); for (let i = 0; i < nodes.length; i++) { frame.isLastBlock = i === nodes.length - 1; this.descendStackedBlock(nodes[i]); } // Leaving a stack -- any assumptions made in the current stack do not apply outside of it // TODO: in if/else this might create an extra unused object this.resetVariableInputs(); this.popFrame(); } descendVariable(variable) { if (this.variableInputs.hasOwnProperty(variable.id)) { return this.variableInputs[variable.id]; } const input = new VariableInput("".concat(this.referenceVariable(variable), ".value")); this.variableInputs[variable.id] = input; return input; } referenceVariable(variable) { if (variable.scope === 'target') { return this.evaluateOnce("target.variables[\"".concat(sanitize(variable.id), "\"]")); } return this.evaluateOnce("stage.variables[\"".concat(sanitize(variable.id), "\"]")); } evaluateOnce(source) { if (this._setupVariables.hasOwnProperty(source)) { return this._setupVariables[source]; } const variable = this._setupVariablesPool.next(); this._setupVariables[source] = variable; return variable; } retire() { // After running retire() (sets thread status and cleans up some unused data), we need to return to the event loop. // When in a procedure, return will only send us back to the previous procedure, so instead we yield back to the sequencer. // Outside of a procedure, return will correctly bring us back to the sequencer. if (this.isProcedure) { this.source += 'retire(); yield;\n'; } else { this.source += 'retire(); return;\n'; } } yieldLoop() { if (this.warpTimer) { this.yieldStuckOrNotWarp(); } else { this.yieldNotWarp(); } } /** * Write JS to yield the current thread if warp mode is disabled. */ yieldNotWarp() { if (!this.isWarp) { this.source += 'yield;\n'; this.yielded(); } } /** * Write JS to yield the current thread if warp mode is disabled or if the script seems to be stuck. */ yieldStuckOrNotWarp() { if (this.isWarp) { this.source += 'if (isStuck()) yield;\n'; } else { this.source += 'yield;\n'; } this.yielded(); } yielded() { if (!this.script.yields) { throw new Error('Script yielded but is not marked as yielding.'); } // Control may have been yielded to another script -- all bets are off. this.resetVariableInputs(); } /** * Write JS to request a redraw. */ requestRedraw() { this.source += 'runtime.requestRedraw();\n'; } safeConstantInput(value) { const unsafe = typeof value === 'string' && this.namesOfCostumesAndSounds.has(value); return new ConstantInput(value, !unsafe); } /** * Generate a call into the compatibility layer. * @param {*} node The "compat" kind node to generate from. * @param {boolean} setFlags Whether flags should be set describing how this function was processed. * @returns {string} The JS of the call. */ generateCompatibilityLayerCall(node, setFlags) { const opcode = node.opcode; let result = 'yield* executeInCompatibilityLayer({'; for (const inputName of Object.keys(node.inputs)) { const input = node.inputs[inputName]; const compiledInput = this.descendInput(input).asSafe(); result += "\"".concat(sanitize(inputName), "\":").concat(compiledInput, ","); } for (const fieldName of Object.keys(node.fields)) { const field = node.fields[fieldName]; result += "\"".concat(sanitize(fieldName), "\":\"").concat(sanitize(field), "\","); } const opcodeFunction = this.evaluateOnce("runtime.getOpcodeFunction(\"".concat(sanitize(opcode), "\")")); result += "}, ".concat(opcodeFunction, ", ").concat(this.isWarp, ", ").concat(setFlags, ")"); return result; } getScriptFactoryName() { return factoryNameVariablePool.next(); } getScriptName(yields) { let name = yields ? generatorNameVariablePool.next() : functionNameVariablePool.next(); if (this.isProcedure) { const simplifiedProcedureCode = this.script.procedureCode.replace(/%[\w]/g, '') // remove arguments .replace(/[^a-zA-Z0-9]/g, '_') // remove unsafe .substring(0, 20); // keep length reasonable name += "_".concat(simplifiedProcedureCode); } return name; } /** * Generate the JS to pass into eval() based on the current state of the compiler. * @returns {string} JS to pass into eval() */ createScriptFactory() { let script = ''; // Setup the factory script += "(function ".concat(this.getScriptFactoryName(), "(thread) { "); script += 'const target = thread.target; '; script += 'const runtime = target.runtime; '; script += 'const stage = runtime.getTargetForStage();\n'; for (const varValue of Object.keys(this._setupVariables)) { const varName = this._setupVariables[varValue]; script += "const ".concat(varName, " = ").concat(varValue, ";\n"); } // Generated script script += 'return '; if (this.script.yields) { script += "function* "; } else { script += "function "; } script += this.getScriptName(this.script.yields); script += ' ('; if (this.script.arguments.length) { const args = []; for (let i = 0; i < this.script.arguments.length; i++) { args.push("p".concat(i)); } script += args.join(','); } script += ') {\n'; script += this.source; if (!this.isProcedure) { script += 'retire();\n'; } script += '}; })'; return script; } /** * Compile this script. * @returns {Function} The factory function for the script. */ compile() { if (this.script.stack) { this.descendStack(this.script.stack, new Frame(false)); } const factory = this.createScriptFactory(); const fn = jsexecute.scopedEval(factory); if (this.debug) { log.info("JS: ".concat(this.target.getName(), ": compiled ").concat(this.script.procedureCode || 'script'), factory); } return fn; } } module.exports = JSGenerator; /***/ }), /***/ "./node_modules/scratch-vm/src/compiler/variable-pool.js": /*!***************************************************************!*\ !*** ./node_modules/scratch-vm/src/compiler/variable-pool.js ***! \***************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { class VariablePool { /** * @param {string} prefix The prefix at the start of the variable name. */ constructor(prefix) { if (prefix.trim().length === 0) { throw new Error('prefix cannot be empty'); } this.prefix = prefix; /** * @private */ this.count = 0; } next() { return "".concat(this.prefix).concat(this.count++); } } module.exports = VariablePool; /***/ }), /***/ "./node_modules/scratch-vm/src/dispatch/central-dispatch.js": /*!******************************************************************!*\ !*** ./node_modules/scratch-vm/src/dispatch/central-dispatch.js ***! \******************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const SharedDispatch = __webpack_require__(/*! ./shared-dispatch */ "./node_modules/scratch-vm/src/dispatch/shared-dispatch.js"); const log = __webpack_require__(/*! ../util/log */ "./node_modules/scratch-vm/src/util/log.js"); /** * This class serves as the central broker for message dispatch. It expects to operate on the main thread / Window and * it must be informed of any Worker threads which will participate in the messaging system. From any context in the * messaging system, the dispatcher's "call" method can call any method on any "service" provided in any participating * context. The dispatch system will forward function arguments and return values across worker boundaries as needed. * @see {WorkerDispatch} */ class CentralDispatch extends SharedDispatch { constructor() { super(); /** * Map of channel name to worker or local service provider. * If the entry is a Worker, the service is provided by an object on that worker. * Otherwise, the service is provided locally and methods on the service will be called directly. * @see {setService} * @type {object.} */ this.services = {}; /** * The constructor we will use to recognize workers. * @type {Function} */ this.workerClass = typeof Worker === 'undefined' ? null : Worker; /** * List of workers attached to this dispatcher. * @type {Array} */ this.workers = []; } /** * Synchronously call a particular method on a particular service provided locally. * Calling this function on a remote service will fail. * @param {string} service - the name of the service. * @param {string} method - the name of the method. * @param {*} [args] - the arguments to be copied to the method, if any. * @returns {*} - the return value of the service method. */ callSync(service, method, ...args) { const { provider, isRemote } = this._getServiceProvider(service); if (provider) { if (isRemote) { throw new Error("Cannot use 'callSync' on remote provider for service ".concat(service, ".")); } return provider[method].apply(provider, args); } throw new Error("Provider not found for service: ".concat(service)); } /** * Synchronously set a local object as the global provider of the specified service. * WARNING: Any method on the provider can be called from any worker within the dispatch system. * @param {string} service - a globally unique string identifying this service. Examples: 'vm', 'gui', 'extension9'. * @param {object} provider - a local object which provides this service. */ setServiceSync(service, provider) { if (this.services.hasOwnProperty(service)) { log.warn("Central dispatch replacing existing service provider for ".concat(service)); } this.services[service] = provider; } /** * Set a local object as the global provider of the specified service. * WARNING: Any method on the provider can be called from any worker within the dispatch system. * @param {string} service - a globally unique string identifying this service. Examples: 'vm', 'gui', 'extension9'. * @param {object} provider - a local object which provides this service. * @returns {Promise} - a promise which will resolve once the service is registered. */ setService(service, provider) { /** Return a promise for consistency with {@link WorkerDispatch#setService} */ try { this.setServiceSync(service, provider); return Promise.resolve(); } catch (e) { return Promise.reject(e); } } /** * Add a worker to the message dispatch system. The worker must implement a compatible message dispatch framework. * The dispatcher will immediately attempt to "handshake" with the worker. * @param {Worker} worker - the worker to add into the dispatch system. */ addWorker(worker) { if (this.workers.indexOf(worker) === -1) { this.workers.push(worker); worker.onmessage = this._onMessage.bind(this, worker); this._remoteCall(worker, 'dispatch', 'handshake').catch(e => { log.error("Could not handshake with worker: ".concat(e)); }); } else { log.warn('Central dispatch ignoring attempt to add duplicate worker'); } } /** * Fetch the service provider object for a particular service name. * @override * @param {string} service - the name of the service to look up * @returns {{provider:(object|Worker), isRemote:boolean}} - the means to contact the service, if found * @protected */ _getServiceProvider(service) { const provider = this.services[service]; return provider && { provider, isRemote: Boolean(this.workerClass && provider instanceof this.workerClass || provider.isRemote) }; } /** * Handle a call message sent to the dispatch service itself * @override * @param {Worker} worker - the worker which sent the message. * @param {DispatchCallMessage} message - the message to be handled. * @returns {Promise|undefined} - a promise for the results of this operation, if appropriate * @protected */ _onDispatchMessage(worker, message) { let promise; switch (message.method) { case 'setService': promise = this.setService(message.args[0], worker); break; default: log.error("Central dispatch received message for unknown method: ".concat(message.method)); } return promise; } } module.exports = new CentralDispatch(); /***/ }), /***/ "./node_modules/scratch-vm/src/dispatch/shared-dispatch.js": /*!*****************************************************************!*\ !*** ./node_modules/scratch-vm/src/dispatch/shared-dispatch.js ***! \*****************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const log = __webpack_require__(/*! ../util/log */ "./node_modules/scratch-vm/src/util/log.js"); /** * @typedef {object} DispatchCallMessage - a message to the dispatch system representing a service method call * @property {*} responseId - send a response message with this response ID. See {@link DispatchResponseMessage} * @property {string} service - the name of the service to be called * @property {string} method - the name of the method to be called * @property {Array|undefined} args - the arguments to be passed to the method */ /** * @typedef {object} DispatchResponseMessage - a message to the dispatch system representing the results of a call * @property {*} responseId - a copy of the response ID from the call which generated this response * @property {*|undefined} error - if this is truthy, then it contains results from a failed call (such as an exception) * @property {*|undefined} result - if error is not truthy, then this contains the return value of the call (if any) */ /** * @typedef {DispatchCallMessage|DispatchResponseMessage} DispatchMessage * Any message to the dispatch system. */ /** * The SharedDispatch class is responsible for dispatch features shared by * {@link CentralDispatch} and {@link WorkerDispatch}. */ class SharedDispatch { constructor() { /** * List of callback registrations for promises waiting for a response from a call to a service on another * worker. A callback registration is an array of [resolve,reject] Promise functions. * Calls to local services don't enter this list. * @type {Array.} */ this.callbacks = []; /** * The next response ID to be used. * @type {int} */ this.nextResponseId = 0; } /** * Call a particular method on a particular service, regardless of whether that service is provided locally or on * a worker. If the service is provided by a worker, the `args` will be copied using the Structured Clone * algorithm, except for any items which are also in the `transfer` list. Ownership of those items will be * transferred to the worker, and they should not be used after this call. * @example * dispatcher.call('vm', 'setData', 'cat', 42); * // this finds the worker for the 'vm' service, then on that worker calls: * vm.setData('cat', 42); * @param {string} service - the name of the service. * @param {string} method - the name of the method. * @param {*} [args] - the arguments to be copied to the method, if any. * @returns {Promise} - a promise for the return value of the service method. */ call(service, method, ...args) { return this.transferCall(service, method, null, ...args); } /** * Call a particular method on a particular service, regardless of whether that service is provided locally or on * a worker. If the service is provided by a worker, the `args` will be copied using the Structured Clone * algorithm, except for any items which are also in the `transfer` list. Ownership of those items will be * transferred to the worker, and they should not be used after this call. * @example * dispatcher.transferCall('vm', 'setData', [myArrayBuffer], 'cat', myArrayBuffer); * // this finds the worker for the 'vm' service, transfers `myArrayBuffer` to it, then on that worker calls: * vm.setData('cat', myArrayBuffer); * @param {string} service - the name of the service. * @param {string} method - the name of the method. * @param {Array} [transfer] - objects to be transferred instead of copied. Must be present in `args` to be useful. * @param {*} [args] - the arguments to be copied to the method, if any. * @returns {Promise} - a promise for the return value of the service method. */ transferCall(service, method, transfer, ...args) { try { const { provider, isRemote } = this._getServiceProvider(service); if (provider) { if (isRemote) { return this._remoteTransferCall(provider, service, method, transfer, ...args); } const result = provider[method].apply(provider, args); return Promise.resolve(result); } return Promise.reject(new Error("Service not found: ".concat(service))); } catch (e) { return Promise.reject(e); } } /** * Check if a particular service lives on another worker. * @param {string} service - the service to check. * @returns {boolean} - true if the service is remote (calls must cross a Worker boundary), false otherwise. * @private */ _isRemoteService(service) { return this._getServiceProvider(service).isRemote; } /** * Like {@link call}, but force the call to be posted through a particular communication channel. * @param {object} provider - send the call through this object's `postMessage` function. * @param {string} service - the name of the service. * @param {string} method - the name of the method. * @param {*} [args] - the arguments to be copied to the method, if any. * @returns {Promise} - a promise for the return value of the service method. */ _remoteCall(provider, service, method, ...args) { return this._remoteTransferCall(provider, service, method, null, ...args); } /** * Like {@link transferCall}, but force the call to be posted through a particular communication channel. * @param {object} provider - send the call through this object's `postMessage` function. * @param {string} service - the name of the service. * @param {string} method - the name of the method. * @param {Array} [transfer] - objects to be transferred instead of copied. Must be present in `args` to be useful. * @param {*} [args] - the arguments to be copied to the method, if any. * @returns {Promise} - a promise for the return value of the service method. */ _remoteTransferCall(provider, service, method, transfer, ...args) { return new Promise((resolve, reject) => { const responseId = this._storeCallbacks(resolve, reject); /** @TODO: remove this hack! this is just here so we don't try to send `util` to a worker */ // tw: upstream's logic is broken // Args is actually a 3 length list of [args, util, real block info] // We only want to send args. The others will throw errors when they try to be cloned if (args.length > 0 && typeof args[args.length - 1].func === 'function') { args.pop(); args.pop(); } if (transfer) { provider.postMessage({ service, method, responseId, args }, transfer); } else { provider.postMessage({ service, method, responseId, args }); } }); } /** * Store callback functions pending a response message. * @param {Function} resolve - function to call if the service method returns. * @param {Function} reject - function to call if the service method throws. * @returns {*} - a unique response ID for this set of callbacks. See {@link _deliverResponse}. * @protected */ _storeCallbacks(resolve, reject) { const responseId = this.nextResponseId++; this.callbacks[responseId] = [resolve, reject]; return responseId; } /** * Deliver call response from a worker. This should only be called as the result of a message from a worker. * @param {int} responseId - the response ID of the callback set to call. * @param {DispatchResponseMessage} message - the message containing the response value(s). * @protected */ _deliverResponse(responseId, message) { try { const [resolve, reject] = this.callbacks[responseId]; delete this.callbacks[responseId]; if (message.error) { reject(message.error); } else { resolve(message.result); } } catch (e) { log.error("Dispatch callback failed: ".concat(e)); } } /** * Handle a message event received from a connected worker. * @param {Worker} worker - the worker which sent the message, or the global object if running in a worker. * @param {MessageEvent} event - the message event to be handled. * @protected */ _onMessage(worker, event) { /** @type {DispatchMessage} */ const message = event.data; message.args = message.args || []; let promise; if (message.service) { if (message.service === 'dispatch') { promise = this._onDispatchMessage(worker, message); } else { promise = this.call(message.service, message.method, ...message.args); } } else if (typeof message.responseId === 'undefined') { log.error("Dispatch caught malformed message from a worker: ".concat(JSON.stringify(event))); } else { this._deliverResponse(message.responseId, message); } if (promise) { if (typeof message.responseId === 'undefined') { log.error("Dispatch message missing required response ID: ".concat(JSON.stringify(event))); } else { promise.then(result => worker.postMessage({ responseId: message.responseId, result }), error => worker.postMessage({ responseId: message.responseId, error: "".concat(error) })); } } } /** * Fetch the service provider object for a particular service name. * @abstract * @param {string} service - the name of the service to look up * @returns {{provider:(object|Worker), isRemote:boolean}} - the means to contact the service, if found * @protected */ _getServiceProvider(service) { throw new Error("Could not get provider for ".concat(service, ": _getServiceProvider not implemented")); } /** * Handle a call message sent to the dispatch service itself * @abstract * @param {Worker} worker - the worker which sent the message. * @param {DispatchCallMessage} message - the message to be handled. * @returns {Promise|undefined} - a promise for the results of this operation, if appropriate * @private */ _onDispatchMessage(worker, message) { throw new Error("Unimplemented dispatch message handler cannot handle ".concat(message.method, " method")); } } module.exports = SharedDispatch; /***/ }), /***/ "./node_modules/scratch-vm/src/engine/adapter.js": /*!*******************************************************!*\ !*** ./node_modules/scratch-vm/src/engine/adapter.js ***! \*******************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const mutationAdapter = __webpack_require__(/*! ./mutation-adapter */ "./node_modules/scratch-vm/src/engine/mutation-adapter.js"); const html = __webpack_require__(/*! htmlparser2 */ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/index.js"); const uid = __webpack_require__(/*! ../util/uid */ "./node_modules/scratch-vm/src/util/uid.js"); /** * Convert and an individual block DOM to the representation tree. * Based on Blockly's `domToBlockHeadless_`. * @param {Element} blockDOM DOM tree for an individual block. * @param {object} blocks Collection of blocks to add to. * @param {boolean} isTopBlock Whether blocks at this level are "top blocks." * @param {?string} parent Parent block ID. * @return {undefined} */ const domToBlock = function domToBlock(blockDOM, blocks, isTopBlock, parent) { if (!blockDOM.attribs.id) { blockDOM.attribs.id = uid(); } // Block skeleton. const block = { id: blockDOM.attribs.id, // Block ID opcode: blockDOM.attribs.type, // For execution, "event_whengreenflag". inputs: {}, // Inputs to this block and the blocks they point to. fields: {}, // Fields on this block and their values. next: null, // Next block in the stack, if one exists. topLevel: isTopBlock, // If this block starts a stack. parent: parent, // Parent block ID, if available. shadow: blockDOM.name === 'shadow', // If this represents a shadow/slot. x: blockDOM.attribs.x, // X position of script, if top-level. y: blockDOM.attribs.y // Y position of script, if top-level. }; // Add the block to the representation tree. blocks[block.id] = block; // Process XML children and find enclosed blocks, fields, etc. for (let i = 0; i < blockDOM.children.length; i++) { const xmlChild = blockDOM.children[i]; // Enclosed blocks and shadows let childBlockNode = null; let childShadowNode = null; for (let j = 0; j < xmlChild.children.length; j++) { const grandChildNode = xmlChild.children[j]; if (!grandChildNode.name) { // Non-XML tag node. continue; } const grandChildNodeName = grandChildNode.name.toLowerCase(); if (grandChildNodeName === 'block') { childBlockNode = grandChildNode; } else if (grandChildNodeName === 'shadow') { childShadowNode = grandChildNode; } } // Use shadow block only if there's no real block node. if (!childBlockNode && childShadowNode) { childBlockNode = childShadowNode; } // Not all Blockly-type blocks are handled here, // as we won't be using all of them for Scratch. switch (xmlChild.name.toLowerCase()) { case 'field': { // Add the field to this block. const fieldName = xmlChild.attribs.name; // Add id in case it is a variable field const fieldId = xmlChild.attribs.id; let fieldData = ''; if (xmlChild.children.length > 0 && xmlChild.children[0].data) { fieldData = xmlChild.children[0].data; } else { // If the child of the field with a data property // doesn't exist, set the data to an empty string. fieldData = ''; } block.fields[fieldName] = { name: fieldName, id: fieldId, value: fieldData }; const fieldVarType = xmlChild.attribs.variabletype; if (typeof fieldVarType === 'string') { block.fields[fieldName].variableType = fieldVarType; } break; } case 'comment': { block.comment = xmlChild.attribs.id; break; } case 'value': case 'statement': { // Recursively generate block structure for input block. domToBlock(childBlockNode, blocks, false, block.id); if (childShadowNode && childBlockNode !== childShadowNode) { // Also generate the shadow block. domToBlock(childShadowNode, blocks, false, block.id); } // Link this block's input to the child block. const inputName = xmlChild.attribs.name; block.inputs[inputName] = { name: inputName, block: childBlockNode.attribs.id, shadow: childShadowNode ? childShadowNode.attribs.id : null }; break; } case 'next': { if (!childBlockNode || !childBlockNode.attribs) { // Invalid child block. continue; } // Recursively generate block structure for next block. domToBlock(childBlockNode, blocks, false, block.id); // Link next block to this block. block.next = childBlockNode.attribs.id; break; } case 'mutation': { block.mutation = mutationAdapter(xmlChild); break; } } } }; /** * Convert outer blocks DOM from a Blockly CREATE event * to a usable form for the Scratch runtime. * This structure is based on Blockly xml.js:`domToWorkspace` and `domToBlock`. * @param {Element} blocksDOM DOM tree for this event. * @return {Array.} Usable list of blocks from this CREATE event. */ const domToBlocks = function domToBlocks(blocksDOM) { // At this level, there could be multiple blocks adjacent in the DOM tree. const blocks = {}; for (let i = 0; i < blocksDOM.length; i++) { const block = blocksDOM[i]; if (!block.name || !block.attribs) { continue; } const tagName = block.name.toLowerCase(); if (tagName === 'block' || tagName === 'shadow') { domToBlock(block, blocks, true, null); } } // Flatten blocks object into a list. const blocksList = []; for (const b in blocks) { if (!blocks.hasOwnProperty(b)) continue; blocksList.push(blocks[b]); } return blocksList; }; /** * Adapter between block creation events and block representation which can be * used by the Scratch runtime. * @param {object} e `Blockly.events.create` or `Blockly.events.endDrag` * @return {Array.} List of blocks from this CREATE event. */ const adapter = function adapter(e) { // Validate input if (typeof e !== 'object') return; if (typeof e.xml !== 'object') return; return domToBlocks(html.parseDOM(e.xml.outerHTML, { decodeEntities: true })); }; module.exports = adapter; /***/ }), /***/ "./node_modules/scratch-vm/src/engine/block-utility.js": /*!*************************************************************!*\ !*** ./node_modules/scratch-vm/src/engine/block-utility.js ***! \*************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const Thread = __webpack_require__(/*! ./thread */ "./node_modules/scratch-vm/src/engine/thread.js"); const Timer = __webpack_require__(/*! ../util/timer */ "./node_modules/scratch-vm/src/util/timer.js"); /** * @fileoverview * Interface provided to block primitive functions for interacting with the * runtime, thread, target, and convenient methods. */ class BlockUtility { constructor(sequencer = null, thread = null) { /** * A sequencer block primitives use to branch or start procedures with * @type {?Sequencer} */ this.sequencer = sequencer; /** * The block primitives thread with the block's target, stackFrame and * modifiable status. * @type {?Thread} */ this.thread = thread; this._nowObj = { now: () => this.sequencer.runtime.currentMSecs }; } /** * The target the primitive is working on. * @type {Target} */ get target() { return this.thread.target; } /** * The runtime the block primitive is running in. * @type {Runtime} */ get runtime() { return this.sequencer.runtime; } /** * Use the runtime's currentMSecs value as a timestamp value for now * This is useful in some cases where we need compatibility with Scratch 2 * @type {function} */ get nowObj() { if (this.runtime) { return this._nowObj; } return null; } /** * The stack frame used by loop and other blocks to track internal state. * @type {object} */ get stackFrame() { const frame = this.thread.peekStackFrame(); if (frame.executionContext === null) { frame.executionContext = {}; } return frame.executionContext; } /** * Check the stack timer and return a boolean based on whether it has finished or not. * @return {boolean} - true if the stack timer has finished. */ stackTimerFinished() { const timeElapsed = this.stackFrame.timer.timeElapsed(); if (timeElapsed < this.stackFrame.duration) { return false; } return true; } /** * Check if the stack timer needs initialization. * @return {boolean} - true if the stack timer needs to be initialized. */ stackTimerNeedsInit() { return !this.stackFrame.timer; } /** * Create and start a stack timer * @param {number} duration - a duration in milliseconds to set the timer for. */ startStackTimer(duration) { if (this.nowObj) { this.stackFrame.timer = new Timer(this.nowObj); } else { this.stackFrame.timer = new Timer(); } this.stackFrame.timer.start(); this.stackFrame.duration = duration; } /** * Set the thread to yield. */ yield() { this.thread.status = Thread.STATUS_YIELD; } /** * Set the thread to yield until the next tick of the runtime. */ yieldTick() { this.thread.status = Thread.STATUS_YIELD_TICK; } /** * Start a branch in the current block. * @param {number} branchNum Which branch to step to (i.e., 1, 2). * @param {boolean} isLoop Whether this block is a loop. */ startBranch(branchNum, isLoop) { this.sequencer.stepToBranch(this.thread, branchNum, isLoop); } /** * Stop all threads. */ stopAll() { this.sequencer.runtime.stopAll(); } /** * Stop threads other on this target other than the thread holding the * executed block. */ stopOtherTargetThreads() { this.sequencer.runtime.stopForTarget(this.thread.target, this.thread); } /** * Stop this thread. */ stopThisScript() { this.thread.stopThisScript(); } /** * Start a specified procedure on this thread. * @param {string} procedureCode Procedure code for procedure to start. */ startProcedure(procedureCode) { const addonBlock = this.runtime.getAddonBlock(procedureCode); if (addonBlock) { addonBlock.callback(this.thread.getAllparams(), this.thread); return; } this.sequencer.stepToProcedure(this.thread, procedureCode); } /** * Get names and ids of parameters for the given procedure. * @param {string} procedureCode Procedure code for procedure to query. * @return {Array.} List of param names for a procedure. */ getProcedureParamNamesAndIds(procedureCode) { return this.thread.target.blocks.getProcedureParamNamesAndIds(procedureCode); } /** * Get names, ids, and defaults of parameters for the given procedure. * @param {string} procedureCode Procedure code for procedure to query. * @return {Array.} List of param names for a procedure. */ getProcedureParamNamesIdsAndDefaults(procedureCode) { return this.thread.target.blocks.getProcedureParamNamesIdsAndDefaults(procedureCode); } /** * Initialize procedure parameters in the thread before pushing parameters. */ initParams() { this.thread.initParams(); } /** * Store a procedure parameter value by its name. * @param {string} paramName The procedure's parameter name. * @param {*} paramValue The procedure's parameter value. */ pushParam(paramName, paramValue) { this.thread.pushParam(paramName, paramValue); } /** * Retrieve the stored parameter value for a given parameter name. * @param {string} paramName The procedure's parameter name. * @return {*} The parameter's current stored value. */ getParam(paramName) { return this.thread.getParam(paramName); } /** * Start all relevant hats. * @param {!string} requestedHat Opcode of hats to start. * @param {object=} optMatchFields Optionally, fields to match on the hat. * @param {Target=} optTarget Optionally, a target to restrict to. * @return {Array.} List of threads started by this function. */ startHats(requestedHat, optMatchFields, optTarget) { // Store thread and sequencer to ensure we can return to the calling block's context. // startHats may execute further blocks and dirty the BlockUtility's execution context // and confuse the calling block when we return to it. const callerThread = this.thread; const callerSequencer = this.sequencer; const result = this.sequencer.runtime.startHats(requestedHat, optMatchFields, optTarget); // Restore thread and sequencer to prior values before we return to the calling block. this.thread = callerThread; this.sequencer = callerSequencer; return result; } /** * Query a named IO device. * @param {string} device The name of like the device, like keyboard. * @param {string} func The name of the device's function to query. * @param {Array.<*>} args Arguments to pass to the device's function. * @return {*} The expected output for the device's function. */ ioQuery(device, func, args) { // Find the I/O device and execute the query/function call. if (this.sequencer.runtime.ioDevices[device] && this.sequencer.runtime.ioDevices[device][func]) { const devObject = this.sequencer.runtime.ioDevices[device]; return devObject[func].apply(devObject, args); } } } module.exports = BlockUtility; /***/ }), /***/ "./node_modules/scratch-vm/src/engine/blocks-execute-cache.js": /*!********************************************************************!*\ !*** ./node_modules/scratch-vm/src/engine/blocks-execute-cache.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /** * @fileoverview * Access point for private method shared between blocks.js and execute.js for * caching execute information. */ /** * A private method shared with execute to build an object containing the block * information execute needs and that is reset when other cached Blocks info is * reset. * @param {Blocks} blocks Blocks containing the expected blockId * @param {string} blockId blockId for the desired execute cache */ exports.getCached = function () { throw new Error('blocks.js has not initialized BlocksExecuteCache'); }; // Call after the default throwing getCached is assigned for Blocks to replace. __webpack_require__(/*! ./blocks */ "./node_modules/scratch-vm/src/engine/blocks.js"); /***/ }), /***/ "./node_modules/scratch-vm/src/engine/blocks-runtime-cache.js": /*!********************************************************************!*\ !*** ./node_modules/scratch-vm/src/engine/blocks-runtime-cache.js ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /** * @fileoverview * The BlocksRuntimeCache caches data about the top block of scripts so that * Runtime can iterate a targeted opcode and iterate the returned set faster. * Many top blocks need to match fields as well as opcode, since that matching * compares strings in uppercase we can go ahead and uppercase the cached value * so we don't need to in the future. */ /** * A set of cached data about the top block of a script. * @param {Blocks} container - Container holding the block and related data * @param {string} blockId - Id for whose block data is cached in this instance */ class RuntimeScriptCache { constructor(container, blockId) { /** * Container with block data for blockId. * @type {Blocks} */ this.container = container; /** * ID for block this instance caches. * @type {string} */ this.blockId = blockId; const block = container.getBlock(blockId); const fields = container.getFields(block); /** * Formatted fields or fields of input blocks ready for comparison in * runtime. * * This is a clone of parts of the targeted blocks. Changes to these * clones are limited to copies under RuntimeScriptCache and will not * appear in the original blocks in their container. This copy is * modified changing the case of strings to uppercase. These uppercase * values will be compared later by the VM. * @type {object} */ this.fieldsOfInputs = Object.assign({}, fields); if (Object.keys(fields).length === 0) { const inputs = container.getInputs(block); for (const input in inputs) { if (!inputs.hasOwnProperty(input)) continue; const id = inputs[input].block; const inputBlock = container.getBlock(id); const inputFields = container.getFields(inputBlock); Object.assign(this.fieldsOfInputs, inputFields); } } for (const key in this.fieldsOfInputs) { const field = this.fieldsOfInputs[key] = Object.assign({}, this.fieldsOfInputs[key]); if (field.value.toUpperCase) { field.value = field.value.toUpperCase(); } } } } /** * Get an array of scripts from a block container prefiltered to match opcode. * @param {Blocks} container - Container of blocks * @param {string} opcode - Opcode to filter top blocks by */ exports.getScripts = function () { throw new Error('blocks.js has not initialized BlocksRuntimeCache'); }; /** * Exposed RuntimeScriptCache class used by integration in blocks.js. * @private */ exports._RuntimeScriptCache = RuntimeScriptCache; __webpack_require__(/*! ./blocks */ "./node_modules/scratch-vm/src/engine/blocks.js"); /***/ }), /***/ "./node_modules/scratch-vm/src/engine/blocks.js": /*!******************************************************!*\ !*** ./node_modules/scratch-vm/src/engine/blocks.js ***! \******************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const adapter = __webpack_require__(/*! ./adapter */ "./node_modules/scratch-vm/src/engine/adapter.js"); const mutationAdapter = __webpack_require__(/*! ./mutation-adapter */ "./node_modules/scratch-vm/src/engine/mutation-adapter.js"); const xmlEscape = __webpack_require__(/*! ../util/xml-escape */ "./node_modules/scratch-vm/src/util/xml-escape.js"); const MonitorRecord = __webpack_require__(/*! ./monitor-record */ "./node_modules/scratch-vm/src/engine/monitor-record.js"); const Clone = __webpack_require__(/*! ../util/clone */ "./node_modules/scratch-vm/src/util/clone.js"); const { Map } = __webpack_require__(/*! immutable */ "./node_modules/immutable/dist/immutable.js"); const BlocksExecuteCache = __webpack_require__(/*! ./blocks-execute-cache */ "./node_modules/scratch-vm/src/engine/blocks-execute-cache.js"); const BlocksRuntimeCache = __webpack_require__(/*! ./blocks-runtime-cache */ "./node_modules/scratch-vm/src/engine/blocks-runtime-cache.js"); const log = __webpack_require__(/*! ../util/log */ "./node_modules/scratch-vm/src/util/log.js"); const Variable = __webpack_require__(/*! ./variable */ "./node_modules/scratch-vm/src/engine/variable.js"); const getMonitorIdForBlockWithArgs = __webpack_require__(/*! ../util/get-monitor-id */ "./node_modules/scratch-vm/src/util/get-monitor-id.js"); /** * @fileoverview * Store and mutate the VM block representation, * and handle updates from Scratch Blocks events. */ /** * Create a block container. * @param {Runtime} runtime The runtime this block container operates within * @param {boolean} optNoGlow Optional flag to indicate that blocks in this container * should not request glows. This does not affect glows when clicking on a block to execute it. */ class Blocks { constructor(runtime, optNoGlow) { this.runtime = runtime; /** * All blocks in the workspace. * Keys are block IDs, values are metadata about the block. * @type {Object.} */ this._blocks = {}; /** * All top-level scripts in the workspace. * A list of block IDs that represent scripts (i.e., first block in script). * @type {Array.} */ this._scripts = []; /** * Runtime Cache * @type {{inputs: {}, procedureParamNames: {}, procedureDefinitions: {}}} * @private */ Object.defineProperty(this, '_cache', { writable: true, enumerable: false }); this._cache = { /** * Cache block inputs by block id * @type {object.>} */ inputs: {}, /** * Cache procedure Param Names by block id * @type {object.>} */ procedureParamNames: {}, /** * Cache procedure definitions by block id * @type {object.} */ procedureDefinitions: {}, /** * A cache for execute to use and store on. Only available to * execute. * @type {object.} */ _executeCached: {}, /** * A cache of block IDs and targets to start threads on as they are * actively monitored. * @type {Array<{blockId: string, target: Target}>} */ _monitored: null, /** * A cache of hat opcodes to collection of theads to execute. * @type {object.} */ scripts: {}, /** * tw: A cache of top block (usually hat, but not always) opcodes to compiled scripts. * @type {object.} */ compiledScripts: {}, /** * tw: A cache of procedure code opcodes to a parsed intermediate representation * @type {object.} */ compiledProcedures: {}, /** * tw: Whether populateProcedureCache has been run */ proceduresPopulated: false }; /** * Flag which indicates that blocks in this container should not glow. * Blocks will still glow when clicked on, but this flag is used to control * whether the blocks in this container can request a glow as part of * a running stack. E.g. the flyout block container and the monitor block container * should not be able to request a glow, but blocks containers belonging to * sprites should. * @type {boolean} */ this.forceNoGlow = optNoGlow || false; } /** * Get the cached compilation result of a block. * @param {string} blockId ID of the top block. * @returns {{success: boolean; value: any}|null} Cached success or error, or null if there is no cached value. */ getCachedCompileResult(blockId) { if (this._cache.compiledScripts.hasOwnProperty(blockId)) { return this._cache.compiledScripts[blockId]; } return null; } /** * Set the cached compilation result of a script. * @param {string} blockId ID of the top block. * @param {*} value The compilation result to store. */ cacheCompileResult(blockId, value) { this._cache.compiledScripts[blockId] = { success: true, value: value }; } /** * Set the cached error of a script. * @param {string} blockId ID of the top block. * @param {*} error The error to store. */ cacheCompileError(blockId, error) { this._cache.compiledScripts[blockId] = { success: false, value: error }; } /** * Blockly inputs that represent statements/branch. * are prefixed with this string. * @const{string} */ static get BRANCH_INPUT_PREFIX() { return 'SUBSTACK'; } /** * Provide an object with metadata for the requested block ID. * @param {!string} blockId ID of block we have stored. * @return {?object} Metadata about the block, if it exists. */ getBlock(blockId) { return this._blocks[blockId]; } /** * Get all known top-level blocks that start scripts. * @return {Array.} List of block IDs. */ getScripts() { return this._scripts; } /** * Get the next block for a particular block * @param {?string} id ID of block to get the next block for * @return {?string} ID of next block in the sequence */ getNextBlock(id) { const block = this._blocks[id]; return typeof block === 'undefined' ? null : block.next; } /** * Get the branch for a particular C-shaped block. * @param {?string} id ID for block to get the branch for. * @param {?number} branchNum Which branch to select (e.g. for if-else). * @return {?string} ID of block in the branch. */ getBranch(id, branchNum) { const block = this._blocks[id]; if (typeof block === 'undefined') return null; if (!branchNum) branchNum = 1; let inputName = Blocks.BRANCH_INPUT_PREFIX; if (branchNum > 1) { inputName += branchNum; } // Empty C-block? const input = block.inputs[inputName]; return typeof input === 'undefined' ? null : input.block; } /** * Get the opcode for a particular block * @param {?object} block The block to query * @return {?string} the opcode corresponding to that block */ getOpcode(block) { return typeof block === 'undefined' ? null : block.opcode; } /** * Get all fields and their values for a block. * @param {?object} block The block to query. * @return {?object} All fields and their values. */ getFields(block) { return typeof block === 'undefined' ? null : block.fields; } /** * Get all non-branch inputs for a block. * @param {?object} block the block to query. * @return {?Array.} All non-branch inputs and their associated blocks. */ getInputs(block) { if (typeof block === 'undefined') return null; let inputs = this._cache.inputs[block.id]; if (typeof inputs !== 'undefined') { return inputs; } inputs = {}; for (const input in block.inputs) { // Ignore blocks prefixed with branch prefix. if (input.substring(0, Blocks.BRANCH_INPUT_PREFIX.length) !== Blocks.BRANCH_INPUT_PREFIX) { inputs[input] = block.inputs[input]; } } this._cache.inputs[block.id] = inputs; return inputs; } /** * Get mutation data for a block. * @param {?object} block The block to query. * @return {?object} Mutation for the block. */ getMutation(block) { return typeof block === 'undefined' ? null : block.mutation; } /** * Get the top-level script for a given block. * @param {?string} id ID of block to query. * @return {?string} ID of top-level script block. */ getTopLevelScript(id) { let block = this._blocks[id]; if (typeof block === 'undefined') return null; while (block.parent !== null) { block = this._blocks[block.parent]; } return block.id; } /** * Get the procedure definition for a given name. * @param {?string} name Name of procedure to query. * @return {?string} ID of procedure definition. */ getProcedureDefinition(name) { const blockID = this._cache.procedureDefinitions[name]; if (typeof blockID !== 'undefined') { return blockID; } for (const id in this._blocks) { if (!this._blocks.hasOwnProperty(id)) continue; const block = this._blocks[id]; if (block.opcode === 'procedures_definition') { // tw: make sure that populateProcedureCache is kept up to date with this method const internal = this._getCustomBlockInternal(block); if (internal && internal.mutation.proccode === name) { this._cache.procedureDefinitions[name] = id; // The outer define block id return id; } } } this._cache.procedureDefinitions[name] = null; return null; } /** * Get names and ids of parameters for the given procedure. * @param {?string} name Name of procedure to query. * @return {?Array.} List of param names for a procedure. */ getProcedureParamNamesAndIds(name) { return this.getProcedureParamNamesIdsAndDefaults(name).slice(0, 2); } /** * Get names, ids, and defaults of parameters for the given procedure. * @param {?string} name Name of procedure to query. * @return {?Array.} List of param names for a procedure. */ getProcedureParamNamesIdsAndDefaults(name) { const cachedNames = this._cache.procedureParamNames[name]; if (typeof cachedNames !== 'undefined') { return cachedNames; } for (const id in this._blocks) { if (!this._blocks.hasOwnProperty(id)) continue; const block = this._blocks[id]; if (block.opcode === 'procedures_prototype' && block.mutation.proccode === name) { // tw: make sure that populateProcedureCache is kept up to date with this method const names = JSON.parse(block.mutation.argumentnames); const ids = JSON.parse(block.mutation.argumentids); const defaults = JSON.parse(block.mutation.argumentdefaults); this._cache.procedureParamNames[name] = [names, ids, defaults]; return this._cache.procedureParamNames[name]; } } const addonBlock = this.runtime.getAddonBlock(name); if (addonBlock) { this._cache.procedureParamNames[name] = addonBlock.namesIdsDefaults; return addonBlock.namesIdsDefaults; } this._cache.procedureParamNames[name] = null; return null; } /** * tw: Setup the procedureParamNames and procedureDefinitions caches all at once. * This makes subsequent calls to these methods faster. */ populateProcedureCache() { if (this._cache.proceduresPopulated) { return; } for (const id in this._blocks) { if (!this._blocks.hasOwnProperty(id)) continue; const block = this._blocks[id]; if (block.opcode === 'procedures_prototype') { const name = block.mutation.proccode; if (!this._cache.procedureParamNames[name]) { const names = JSON.parse(block.mutation.argumentnames); const ids = JSON.parse(block.mutation.argumentids); const defaults = JSON.parse(block.mutation.argumentdefaults); this._cache.procedureParamNames[name] = [names, ids, defaults]; } continue; } if (block.opcode === 'procedures_definition') { const internal = this._getCustomBlockInternal(block); if (internal) { const name = internal.mutation.proccode; if (!this._cache.procedureDefinitions[name]) { this._cache.procedureDefinitions[name] = id; } continue; } } } this._cache.proceduresPopulated = true; } duplicate() { const newBlocks = new Blocks(this.runtime, this.forceNoGlow); newBlocks._blocks = Clone.simple(this._blocks); newBlocks._scripts = Clone.simple(this._scripts); return newBlocks; } // --------------------------------------------------------------------- /** * Create event listener for blocks, variables, and comments. Handles validation and * serves as a generic adapter between the blocks, variables, and the * runtime interface. * @param {object} e Blockly "block" or "variable" event */ blocklyListen(e) { // Validate event if (typeof e !== 'object') return; if (typeof e.blockId !== 'string' && typeof e.varId !== 'string' && typeof e.commentId !== 'string') { return; } const stage = this.runtime.getTargetForStage(); const editingTarget = this.runtime.getEditingTarget(); // UI event: clicked scripts toggle in the runtime. if (e.element === 'stackclick') { this.runtime.toggleScript(e.blockId, { stackClick: true }); return; } // Block create/update/destroy switch (e.type) { case 'create': { const newBlocks = adapter(e); // A create event can create many blocks. Add them all. for (let i = 0; i < newBlocks.length; i++) { this.createBlock(newBlocks[i]); } break; } case 'change': this.changeBlock({ id: e.blockId, element: e.element, name: e.name, value: e.newValue }); break; case 'move': this.moveBlock({ id: e.blockId, oldParent: e.oldParentId, oldInput: e.oldInputName, newParent: e.newParentId, newInput: e.newInputName, newCoordinate: e.newCoordinate }); break; case 'dragOutside': this.runtime.emitBlockDragUpdate(e.isOutside); break; case 'endDrag': this.runtime.emitBlockDragUpdate(false /* areBlocksOverGui */ ); // Drag blocks onto another sprite if (e.isOutside) { const newBlocks = adapter(e); this.runtime.emitBlockEndDrag(newBlocks, e.blockId); } break; case 'delete': // Don't accept delete events for missing blocks, // or shadow blocks being obscured. if (!this._blocks.hasOwnProperty(e.blockId) || this._blocks[e.blockId].shadow) { return; } // Inform any runtime to forget about glows on this script. if (this._blocks[e.blockId].topLevel) { this.runtime.quietGlow(e.blockId); } this.deleteBlock(e.blockId); break; case 'var_create': this.resetCache(); // tw: more aggressive cache resetting // Check if the variable being created is global or local // If local, create a local var on the current editing target, as long // as there are no conflicts, and the current target is actually a sprite // If global or if the editing target is not present or we somehow got // into a state where a local var was requested for the stage, // create a stage (global) var after checking for name conflicts // on all the sprites. if (e.isLocal && editingTarget && !editingTarget.isStage && !e.isCloud) { if (!editingTarget.lookupVariableById(e.varId)) { editingTarget.createVariable(e.varId, e.varName, e.varType); this.emitProjectChanged(); } } else { if (stage.lookupVariableById(e.varId)) { // Do not re-create a variable if it already exists return; } // Check for name conflicts in all of the targets const allTargets = this.runtime.targets.filter(t => t.isOriginal); for (const target of allTargets) { if (target.lookupVariableByNameAndType(e.varName, e.varType, true)) { return; } } stage.createVariable(e.varId, e.varName, e.varType, e.isCloud); this.emitProjectChanged(); } break; case 'var_rename': if (editingTarget && editingTarget.variables.hasOwnProperty(e.varId)) { // This is a local variable, rename on the current target editingTarget.renameVariable(e.varId, e.newName); // Update all the blocks on the current target that use // this variable editingTarget.blocks.updateBlocksAfterVarRename(e.varId, e.newName); } else { // This is a global variable stage.renameVariable(e.varId, e.newName); // Update all blocks on all targets that use the renamed variable const targets = this.runtime.targets; for (let i = 0; i < targets.length; i++) { const currTarget = targets[i]; currTarget.blocks.updateBlocksAfterVarRename(e.varId, e.newName); } } this.emitProjectChanged(); break; case 'var_delete': { this.resetCache(); // tw: more aggressive cache resetting const target = editingTarget && editingTarget.variables.hasOwnProperty(e.varId) ? editingTarget : stage; target.deleteVariable(e.varId); this.emitProjectChanged(); break; } case 'comment_create': this.resetCache(); // tw: comments can affect compilation if (this.runtime.getEditingTarget()) { const currTarget = this.runtime.getEditingTarget(); currTarget.createComment(e.commentId, e.blockId, e.text, e.xy.x, e.xy.y, e.width, e.height, e.minimized); if (currTarget.comments[e.commentId].x === null && currTarget.comments[e.commentId].y === null) { // Block comments imported from 2.0 projects are imported with their // x and y coordinates set to null so that scratch-blocks can // auto-position them. If we are receiving a create event for these // comments, then the auto positioning should have taken place. // Update the x and y position of these comments to match the // one from the event. currTarget.comments[e.commentId].x = e.xy.x; currTarget.comments[e.commentId].y = e.xy.y; } } this.emitProjectChanged(); break; case 'comment_change': this.resetCache(); // tw: comments can affect compilation if (this.runtime.getEditingTarget()) { const currTarget = this.runtime.getEditingTarget(); if (!currTarget.comments.hasOwnProperty(e.commentId)) { log.warn("Cannot change comment with id ".concat(e.commentId, " because it does not exist.")); return; } const comment = currTarget.comments[e.commentId]; const change = e.newContents_; if (change.hasOwnProperty('minimized')) { comment.minimized = change.minimized; } if (change.hasOwnProperty('width') && change.hasOwnProperty('height')) { comment.width = change.width; comment.height = change.height; } if (change.hasOwnProperty('text')) { comment.text = change.text; } this.emitProjectChanged(); } break; case 'comment_move': if (this.runtime.getEditingTarget()) { const currTarget = this.runtime.getEditingTarget(); if (currTarget && !currTarget.comments.hasOwnProperty(e.commentId)) { log.warn("Cannot change comment with id ".concat(e.commentId, " because it does not exist.")); return; } const comment = currTarget.comments[e.commentId]; const newCoord = e.newCoordinate_; comment.x = newCoord.x; comment.y = newCoord.y; this.emitProjectChanged(); } break; case 'comment_delete': this.resetCache(); // tw: comments can affect compilation if (this.runtime.getEditingTarget()) { const currTarget = this.runtime.getEditingTarget(); if (!currTarget.comments.hasOwnProperty(e.commentId)) { // If we're in this state, we have probably received // a delete event from a workspace that we switched from // (e.g. a delete event for a comment on sprite a's workspace // when switching from sprite a to sprite b) return; } delete currTarget.comments[e.commentId]; if (e.blockId) { const block = currTarget.blocks.getBlock(e.blockId); if (!block) { log.warn("Could not find block referenced by comment with id: ".concat(e.commentId)); return; } delete block.comment; } this.emitProjectChanged(); } break; } } // --------------------------------------------------------------------- /** * Reset all runtime caches. */ resetCache() { this._cache.inputs = {}; this._cache.procedureParamNames = {}; this._cache.procedureDefinitions = {}; this._cache._executeCached = {}; this._cache._monitored = null; this._cache.scripts = {}; this._cache.compiledScripts = {}; this._cache.compiledProcedures = {}; this._cache.proceduresPopulated = false; } /** * Emit a project changed event if this is a block container * that can affect the project state. */ emitProjectChanged() { if (!this.forceNoGlow) { this.runtime.emitProjectChanged(); } } /** * Block management: create blocks and scripts from a `create` event * @param {!object} block Blockly create event to be processed */ createBlock(block) { // Does the block already exist? // Could happen, e.g., for an unobscured shadow. if (this._blocks.hasOwnProperty(block.id)) { return; } // Create new block. this._blocks[block.id] = block; // Push block id to scripts array. // Blocks are added as a top-level stack if they are marked as a top-block // (if they were top-level XML in the event). if (block.topLevel) { this._addScript(block.id); } this.resetCache(); // A new block was actually added to the block container, // emit a project changed event this.emitProjectChanged(); } /** * Block management: change block field values * @param {!object} args Blockly change event to be processed */ changeBlock(args) { // Validate if (['field', 'mutation', 'checkbox'].indexOf(args.element) === -1) return; let block = this._blocks[args.id]; if (typeof block === 'undefined') return; switch (args.element) { case 'field': // TODO when the field of a monitored block changes, // update the checkbox in the flyout based on whether // a monitor for that current combination of selected parameters exists // e.g. // 1. check (current [v year]) // 2. switch dropdown in flyout block to (current [v minute]) // 3. the checkbox should become unchecked if we're not already // monitoring current minute // Update block value if (!block.fields[args.name]) return; if (args.name === 'VARIABLE' || args.name === 'LIST' || args.name === 'BROADCAST_OPTION') { // Get variable name using the id in args.value. const variable = this.runtime.getEditingTarget().lookupVariableById(args.value); if (variable) { block.fields[args.name].value = variable.name; block.fields[args.name].id = args.value; } } else { // Changing the value in a dropdown block.fields[args.name].value = args.value; // The selected item in the sensing of block menu needs to change based on the // selected target. Set it to the first item in the menu list. // TODO: (#1787) if (block.opcode === 'sensing_of_object_menu') { if (block.fields.OBJECT.value === '_stage_') { this._blocks[block.parent].fields.PROPERTY.value = 'backdrop #'; } else { this._blocks[block.parent].fields.PROPERTY.value = 'x position'; } this.runtime.requestBlocksUpdate(); } const flyoutBlock = block.shadow && block.parent ? this._blocks[block.parent] : block; if (flyoutBlock.isMonitored) { this.runtime.requestUpdateMonitor(Map({ id: flyoutBlock.id, params: this._getBlockParams(flyoutBlock) })); } } break; case 'mutation': block.mutation = mutationAdapter(args.value); break; case 'checkbox': { // A checkbox usually has a one to one correspondence with the monitor // block but in the case of monitored reporters that have arguments, // map the old id to a new id, creating a new monitor block if necessary if (block.fields && Object.keys(block.fields).length > 0 && block.opcode !== 'data_variable' && block.opcode !== 'data_listcontents') { // This block has an argument which needs to get separated out into // multiple monitor blocks with ids based on the selected argument const newId = getMonitorIdForBlockWithArgs(block.id, block.fields); // Note: we're not just constantly creating a longer and longer id everytime we check // the checkbox because we're using the id of the block in the flyout as the base // check if a block with the new id already exists, otherwise create let newBlock = this.runtime.monitorBlocks.getBlock(newId); if (!newBlock) { newBlock = JSON.parse(JSON.stringify(block)); newBlock.id = newId; this.runtime.monitorBlocks.createBlock(newBlock); } block = newBlock; // Carry on through the rest of this code with newBlock } const wasMonitored = block.isMonitored; block.isMonitored = args.value; // Variable blocks may be sprite specific depending on the owner of the variable let isSpriteLocalVariable = false; if (block.opcode === 'data_variable') { isSpriteLocalVariable = !this.runtime.getTargetForStage().variables[block.fields.VARIABLE.id]; } else if (block.opcode === 'data_listcontents') { isSpriteLocalVariable = !this.runtime.getTargetForStage().variables[block.fields.LIST.id]; } const isSpriteSpecific = isSpriteLocalVariable || this.runtime.monitorBlockInfo.hasOwnProperty(block.opcode) && this.runtime.monitorBlockInfo[block.opcode].isSpriteSpecific; if (isSpriteSpecific) { // If creating a new sprite specific monitor, the only possible target is // the current editing one b/c you cannot dynamically create monitors. // Also, do not change the targetId if it has already been assigned block.targetId = block.targetId || this.runtime.getEditingTarget().id; } else { block.targetId = null; } if (wasMonitored && !block.isMonitored) { this.runtime.requestHideMonitor(block.id); } else if (!wasMonitored && block.isMonitored) { // Tries to show the monitor for specified block. If it doesn't exist, add the monitor. if (!this.runtime.requestShowMonitor(block.id)) { this.runtime.requestAddMonitor(MonitorRecord({ id: block.id, targetId: block.targetId, spriteName: block.targetId ? this.runtime.getTargetById(block.targetId).getName() : null, opcode: block.opcode, params: this._getBlockParams(block), // @todo(vm#565) for numerical values with decimals, some countries use comma value: '', mode: block.opcode === 'data_listcontents' ? 'list' : 'default' })); } } break; } } this.emitProjectChanged(); this.resetCache(); } /** * Block management: move blocks from parent to parent * @param {!object} e Blockly move event to be processed */ moveBlock(e) { if (!this._blocks.hasOwnProperty(e.id)) { return; } const block = this._blocks[e.id]; // Track whether a change actually occurred // ignoring changes like routine re-positioning // of a block when loading a workspace let didChange = false; // Move coordinate changes. if (e.newCoordinate) { didChange = block.x !== e.newCoordinate.x || block.y !== e.newCoordinate.y; block.x = e.newCoordinate.x; block.y = e.newCoordinate.y; } // Remove from any old parent. if (typeof e.oldParent !== 'undefined') { const oldParent = this._blocks[e.oldParent]; if (typeof e.oldInput !== 'undefined' && oldParent.inputs[e.oldInput].block === e.id) { // This block was connected to the old parent's input. oldParent.inputs[e.oldInput].block = null; } else if (oldParent.next === e.id) { // This block was connected to the old parent's next connection. oldParent.next = null; } this._blocks[e.id].parent = null; didChange = true; } // Is this block a top-level block? if (typeof e.newParent === 'undefined') { this._addScript(e.id); } else { // Remove script, if one exists. this._deleteScript(e.id); // Otherwise, try to connect it in its new place. if (typeof e.newInput === 'undefined') { // Moved to the new parent's next connection. this._blocks[e.newParent].next = e.id; } else { // Moved to the new parent's input. // Don't obscure the shadow block. let oldShadow = null; if (this._blocks[e.newParent].inputs.hasOwnProperty(e.newInput)) { oldShadow = this._blocks[e.newParent].inputs[e.newInput].shadow; } // If the block being attached is itself a shadow, make sure to set // both block and shadow to that blocks ID. This happens when adding // inputs to a custom procedure. if (this._blocks[e.id].shadow) oldShadow = e.id; this._blocks[e.newParent].inputs[e.newInput] = { name: e.newInput, block: e.id, shadow: oldShadow }; } this._blocks[e.id].parent = e.newParent; didChange = true; } this.resetCache(); if (didChange) this.emitProjectChanged(); } /** * Block management: run all blocks. * @param {!object} runtime Runtime to run all blocks in. */ runAllMonitored(runtime) { if (this._cache._monitored === null) { this._cache._monitored = Object.keys(this._blocks).filter(blockId => this.getBlock(blockId).isMonitored).map(blockId => { const targetId = this.getBlock(blockId).targetId; return { blockId, target: targetId ? runtime.getTargetById(targetId) : null }; }); } const monitored = this._cache._monitored; for (let i = 0; i < monitored.length; i++) { const { blockId, target } = monitored[i]; runtime.addMonitorScript(blockId, target); } } /** * Block management: delete blocks and their associated scripts. Does nothing if a block * with the given ID does not exist. * @param {!string} blockId Id of block to delete */ deleteBlock(blockId) { // @todo In runtime, stop threads running on this script. // Get block const block = this._blocks[blockId]; if (!block) { // No block with the given ID exists return; } // Delete children if (block.next !== null) { this.deleteBlock(block.next); } // Delete inputs (including branches) for (const input in block.inputs) { // If it's null, the block in this input moved away. if (block.inputs[input].block !== null) { this.deleteBlock(block.inputs[input].block); } // Delete obscured shadow blocks. if (block.inputs[input].shadow !== null && block.inputs[input].shadow !== block.inputs[input].block) { this.deleteBlock(block.inputs[input].shadow); } } // Delete any script starting with this block. this._deleteScript(blockId); // Delete block itself. delete this._blocks[blockId]; this.resetCache(); this.emitProjectChanged(); } /** * Returns a map of all references to variables or lists from blocks * in this block container. * @param {Array} optBlocks Optional list of blocks to constrain the search to. * This is useful for getting variable/list references for a stack of blocks instead * of all blocks on the workspace * @param {?boolean} optIncludeBroadcast Optional whether to include broadcast fields. * @return {object} A map of variable ID to a list of all variable references * for that ID. A variable reference contains the field referencing that variable * and also the type of the variable being referenced. */ getAllVariableAndListReferences(optBlocks, optIncludeBroadcast) { const blocks = optBlocks ? optBlocks : this._blocks; const allReferences = Object.create(null); for (const blockId in blocks) { let varOrListField = null; let varType = null; if (blocks[blockId].fields.VARIABLE) { varOrListField = blocks[blockId].fields.VARIABLE; varType = Variable.SCALAR_TYPE; } else if (blocks[blockId].fields.LIST) { varOrListField = blocks[blockId].fields.LIST; varType = Variable.LIST_TYPE; } else if (optIncludeBroadcast && blocks[blockId].fields.BROADCAST_OPTION) { varOrListField = blocks[blockId].fields.BROADCAST_OPTION; varType = Variable.BROADCAST_MESSAGE_TYPE; } if (varOrListField) { const currVarId = varOrListField.id; if (allReferences[currVarId]) { allReferences[currVarId].push({ referencingField: varOrListField, type: varType }); } else { allReferences[currVarId] = [{ referencingField: varOrListField, type: varType }]; } } } return allReferences; } /** * Keep blocks up to date after a variable gets renamed. * @param {string} varId The id of the variable that was renamed * @param {string} newName The new name of the variable that was renamed */ updateBlocksAfterVarRename(varId, newName) { const blocks = this._blocks; for (const blockId in blocks) { let varOrListField = null; if (blocks[blockId].fields.VARIABLE) { varOrListField = blocks[blockId].fields.VARIABLE; } else if (blocks[blockId].fields.LIST) { varOrListField = blocks[blockId].fields.LIST; } if (varOrListField) { const currFieldId = varOrListField.id; if (varId === currFieldId) { varOrListField.value = newName; } } } } /** * Keep blocks up to date after they are shared between targets. * @param {boolean} isStage If the new target is a stage. */ updateTargetSpecificBlocks(isStage) { const blocks = this._blocks; for (const blockId in blocks) { if (isStage && blocks[blockId].opcode === 'event_whenthisspriteclicked') { blocks[blockId].opcode = 'event_whenstageclicked'; } else if (!isStage && blocks[blockId].opcode === 'event_whenstageclicked') { blocks[blockId].opcode = 'event_whenthisspriteclicked'; } } } /** * Update blocks after a sound, costume, or backdrop gets renamed. * Any block referring to the old name of the asset should get updated * to refer to the new name. * @param {string} oldName The old name of the asset that was renamed. * @param {string} newName The new name of the asset that was renamed. * @param {string} assetType String representation of the kind of asset * that was renamed. This can be one of 'sprite','costume', 'sound', or * 'backdrop'. */ updateAssetName(oldName, newName, assetType) { let getAssetField; if (assetType === 'costume') { getAssetField = this._getCostumeField.bind(this); } else if (assetType === 'sound') { getAssetField = this._getSoundField.bind(this); } else if (assetType === 'backdrop') { getAssetField = this._getBackdropField.bind(this); } else if (assetType === 'sprite') { getAssetField = this._getSpriteField.bind(this); } else { return; } const blocks = this._blocks; for (const blockId in blocks) { const assetField = getAssetField(blockId); if (assetField && assetField.value === oldName) { assetField.value = newName; } } this.resetCache(); } /** * Update sensing_of blocks after a variable gets renamed. * @param {string} oldName The old name of the variable that was renamed. * @param {string} newName The new name of the variable that was renamed. * @param {string} targetName The name of the target the variable belongs to. * @return {boolean} Returns true if any of the blocks were updated. */ updateSensingOfReference(oldName, newName, targetName) { const blocks = this._blocks; let blockUpdated = false; for (const blockId in blocks) { const block = blocks[blockId]; if (block.opcode === 'sensing_of' && block.fields.PROPERTY.value === oldName && // If block and shadow are different, it means a block is inserted to OBJECT, and should be ignored. block.inputs.OBJECT.block === block.inputs.OBJECT.shadow) { const inputBlock = this.getBlock(block.inputs.OBJECT.block); if (inputBlock.fields.OBJECT.value === targetName) { block.fields.PROPERTY.value = newName; blockUpdated = true; } } } if (blockUpdated) this.resetCache(); return blockUpdated; } /** * Helper function to retrieve a costume menu field from a block given its id. * @param {string} blockId A unique identifier for a block * @return {?object} The costume menu field of the block with the given block id. * Null if either a block with the given id doesn't exist or if a costume menu field * does not exist on the block with the given id. */ _getCostumeField(blockId) { const block = this.getBlock(blockId); if (block && block.fields.hasOwnProperty('COSTUME')) { return block.fields.COSTUME; } return null; } /** * Helper function to retrieve a sound menu field from a block given its id. * @param {string} blockId A unique identifier for a block * @return {?object} The sound menu field of the block with the given block id. * Null, if either a block with the given id doesn't exist or if a sound menu field * does not exist on the block with the given id. */ _getSoundField(blockId) { const block = this.getBlock(blockId); if (block && block.fields.hasOwnProperty('SOUND_MENU')) { return block.fields.SOUND_MENU; } return null; } /** * Helper function to retrieve a backdrop menu field from a block given its id. * @param {string} blockId A unique identifier for a block * @return {?object} The backdrop menu field of the block with the given block id. * Null, if either a block with the given id doesn't exist or if a backdrop menu field * does not exist on the block with the given id. */ _getBackdropField(blockId) { const block = this.getBlock(blockId); if (block && block.fields.hasOwnProperty('BACKDROP')) { return block.fields.BACKDROP; } return null; } /** * Helper function to retrieve a sprite menu field from a block given its id. * @param {string} blockId A unique identifier for a block * @return {?object} The sprite menu field of the block with the given block id. * Null, if either a block with the given id doesn't exist or if a sprite menu field * does not exist on the block with the given id. */ _getSpriteField(blockId) { const block = this.getBlock(blockId); if (!block) { return null; } const spriteMenuNames = ['TOWARDS', 'TO', 'OBJECT', 'VIDEOONMENU2', 'DISTANCETOMENU', 'TOUCHINGOBJECTMENU', 'CLONE_OPTION']; for (let i = 0; i < spriteMenuNames.length; i++) { const menuName = spriteMenuNames[i]; if (block.fields.hasOwnProperty(menuName)) { return block.fields[menuName]; } } return null; } // --------------------------------------------------------------------- /** * Encode all of `this._blocks` as an XML string usable * by a Blockly/scratch-blocks workspace. * @param {object} comments Map of comments referenced by id * @return {string} String of XML representing this object's blocks. */ toXML(comments) { return this._scripts.map(script => this.blockToXML(script, comments)).join(); } /** * Recursively encode an individual block and its children * into a Blockly/scratch-blocks XML string. * @param {!string} blockId ID of block to encode. * @param {object} comments Map of comments referenced by id * @return {string} String of XML representing this block and any children. */ blockToXML(blockId, comments) { const block = this._blocks[blockId]; // block should exist, but currently some blocks' next property point // to a blockId for non-existent blocks. Until we track down that behavior, // this early exit allows the project to load. if (!block) return; // Encode properties of this block. const tagName = block.shadow ? 'shadow' : 'block'; let xmlString = "<".concat(tagName, "\n id=\"").concat(block.id, "\"\n type=\"").concat(block.opcode, "\"\n ").concat(block.topLevel ? "x=\"".concat(block.x, "\" y=\"").concat(block.y, "\"") : '', "\n >"); const commentId = block.comment; if (commentId) { if (comments) { if (comments.hasOwnProperty(commentId)) { xmlString += comments[commentId].toXML(); } else { log.warn("Could not find comment with id: ".concat(commentId, " in provided comment descriptions.")); } } else { log.warn("Cannot serialize comment with id: ".concat(commentId, "; no comment descriptions provided.")); } } // Add any mutation. Must come before inputs. if (block.mutation) { xmlString += this.mutationToXML(block.mutation); } // Add any inputs on this block. for (const input in block.inputs) { if (!block.inputs.hasOwnProperty(input)) continue; const blockInput = block.inputs[input]; // Only encode a value tag if the value input is occupied. if (blockInput.block || blockInput.shadow) { xmlString += ""); if (blockInput.block) { xmlString += this.blockToXML(blockInput.block, comments); } if (blockInput.shadow && blockInput.shadow !== blockInput.block) { // Obscured shadow. xmlString += this.blockToXML(blockInput.shadow, comments); } xmlString += ''; } } // Add any fields on this block. for (const field in block.fields) { if (!block.fields.hasOwnProperty(field)) continue; const blockField = block.fields[field]; xmlString += ""); } // Add blocks connected to the next connection. if (block.next) { xmlString += "".concat(this.blockToXML(block.next, comments), ""); } xmlString += ""); return xmlString; } /** * Recursively encode a mutation object to XML. * @param {!object} mutation Object representing a mutation. * @return {string} XML string representing a mutation. */ mutationToXML(mutation) { let mutationString = "<".concat(mutation.tagName); for (const prop in mutation) { if (prop === 'children' || prop === 'tagName') continue; let mutationValue = typeof mutation[prop] === 'string' ? xmlEscape(mutation[prop]) : mutation[prop]; // Handle dynamic extension blocks if (prop === 'blockInfo') { mutationValue = xmlEscape(JSON.stringify(mutation[prop])); } mutationString += " ".concat(prop, "=\"").concat(mutationValue, "\""); } mutationString += '>'; for (let i = 0; i < mutation.children.length; i++) { mutationString += this.mutationToXML(mutation.children[i]); } mutationString += ""); return mutationString; } // --------------------------------------------------------------------- /** * Helper to serialize block fields and input fields for reporting new monitors * @param {!object} block Block to be paramified. * @return {!object} object of param key/values. */ _getBlockParams(block) { const params = {}; for (const key in block.fields) { params[key] = block.fields[key].value; } for (const inputKey in block.inputs) { const inputBlock = this._blocks[block.inputs[inputKey].block]; for (const key in inputBlock.fields) { params[key] = inputBlock.fields[key].value; } } return params; } /** * Helper to get the corresponding internal procedure definition block * @param {!object} defineBlock Outer define block. * @return {!object} internal definition block which has the mutation. */ _getCustomBlockInternal(defineBlock) { if (defineBlock.inputs && defineBlock.inputs.custom_block) { return this._blocks[defineBlock.inputs.custom_block.block]; } } /** * Helper to add a stack to `this._scripts`. * @param {?string} topBlockId ID of block that starts the script. */ _addScript(topBlockId) { const i = this._scripts.indexOf(topBlockId); if (i > -1) return; // Already in scripts. this._scripts.push(topBlockId); // Update `topLevel` property on the top block. this._blocks[topBlockId].topLevel = true; } /** * Helper to remove a script from `this._scripts`. * @param {?string} topBlockId ID of block that starts the script. */ _deleteScript(topBlockId) { const i = this._scripts.indexOf(topBlockId); if (i > -1) this._scripts.splice(i, 1); // Update `topLevel` property on the top block. if (this._blocks[topBlockId]) this._blocks[topBlockId].topLevel = false; } } /** * A private method shared with execute to build an object containing the block * information execute needs and that is reset when other cached Blocks info is * reset. * @param {Blocks} blocks Blocks containing the expected blockId * @param {string} blockId blockId for the desired execute cache * @param {function} CacheType constructor for cached block information * @return {object} execute cache object */ BlocksExecuteCache.getCached = function (blocks, blockId, CacheType) { let cached = blocks._cache._executeCached[blockId]; if (typeof cached !== 'undefined') { return cached; } const block = blocks.getBlock(blockId); if (typeof block === 'undefined') return null; if (typeof CacheType === 'undefined') { cached = { id: blockId, opcode: blocks.getOpcode(block), fields: blocks.getFields(block), inputs: blocks.getInputs(block), mutation: blocks.getMutation(block) }; } else { cached = new CacheType(blocks, { id: blockId, opcode: blocks.getOpcode(block), fields: blocks.getFields(block), inputs: blocks.getInputs(block), mutation: blocks.getMutation(block) }); } blocks._cache._executeCached[blockId] = cached; return cached; }; /** * Cache class constructor for runtime. Used to consider what threads should * start based on hat data. * @type {function} */ const RuntimeScriptCache = BlocksRuntimeCache._RuntimeScriptCache; /** * Get an array of scripts from a block container prefiltered to match opcode. * @param {Blocks} blocks - Container of blocks * @param {string} opcode - Opcode to filter top blocks by * @returns {Array.} - Array of RuntimeScriptCache cache * objects */ BlocksRuntimeCache.getScripts = function (blocks, opcode) { let scripts = blocks._cache.scripts[opcode]; if (!scripts) { scripts = blocks._cache.scripts[opcode] = []; const allScripts = blocks._scripts; for (let i = 0; i < allScripts.length; i++) { const topBlockId = allScripts[i]; const block = blocks.getBlock(topBlockId); if (block.opcode === opcode) { scripts.push(new RuntimeScriptCache(blocks, topBlockId)); } } } return scripts; }; module.exports = Blocks; /***/ }), /***/ "./node_modules/scratch-vm/src/engine/comment.js": /*!*******************************************************!*\ !*** ./node_modules/scratch-vm/src/engine/comment.js ***! \*******************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /** * @fileoverview * Object representing a Scratch Comment (block or workspace). */ const uid = __webpack_require__(/*! ../util/uid */ "./node_modules/scratch-vm/src/util/uid.js"); const xmlEscape = __webpack_require__(/*! ../util/xml-escape */ "./node_modules/scratch-vm/src/util/xml-escape.js"); class Comment { /** * @param {string} id Id of the comment. * @param {string} text Text content of the comment. * @param {number} x X position of the comment on the workspace. * @param {number} y Y position of the comment on the workspace. * @param {number} width The width of the comment when it is full size. * @param {number} height The height of the comment when it is full size. * @param {boolean} minimized Whether the comment is minimized. * @constructor */ constructor(id, text, x, y, width, height, minimized) { this.id = id || uid(); this.text = text; this.x = x; this.y = y; this.width = Math.max(Number(width), Comment.MIN_WIDTH); this.height = Math.max(Number(height), Comment.MIN_HEIGHT); this.minimized = minimized || false; this.blockId = null; } toXML() { return "").concat(xmlEscape(this.text), ""); } // TODO choose min and defaults for width and height static get MIN_WIDTH() { return 20; } static get MIN_HEIGHT() { return 20; } static get DEFAULT_WIDTH() { return 100; } static get DEFAULT_HEIGHT() { return 100; } } module.exports = Comment; /***/ }), /***/ "./node_modules/scratch-vm/src/engine/execute.js": /*!*******************************************************!*\ !*** ./node_modules/scratch-vm/src/engine/execute.js ***! \*******************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const BlockUtility = __webpack_require__(/*! ./block-utility */ "./node_modules/scratch-vm/src/engine/block-utility.js"); const BlocksExecuteCache = __webpack_require__(/*! ./blocks-execute-cache */ "./node_modules/scratch-vm/src/engine/blocks-execute-cache.js"); const log = __webpack_require__(/*! ../util/log */ "./node_modules/scratch-vm/src/util/log.js"); const Thread = __webpack_require__(/*! ./thread */ "./node_modules/scratch-vm/src/engine/thread.js"); const { Map } = __webpack_require__(/*! immutable */ "./node_modules/immutable/dist/immutable.js"); const cast = __webpack_require__(/*! ../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); /** * Single BlockUtility instance reused by execute for every pritimive ran. * @const */ const blockUtility = new BlockUtility(); /** * Profiler frame name for block functions. * @const {string} */ const blockFunctionProfilerFrame = 'blockFunction'; /** * Profiler frame ID for 'blockFunction'. * @type {number} */ let blockFunctionProfilerId = -1; /** * Utility function to determine if a value is a Promise. * @param {*} value Value to check for a Promise. * @return {boolean} True if the value appears to be a Promise. */ const isPromise = function isPromise(value) { return value !== null && typeof value === 'object' && typeof value.then === 'function'; }; /** * Handle any reported value from the primitive, either directly returned * or after a promise resolves. * @param {*} resolvedValue Value eventually returned from the primitive. * @param {!Sequencer} sequencer Sequencer stepping the thread for the ran * primitive. * @param {!Thread} thread Thread containing the primitive. * @param {!string} currentBlockId Id of the block in its thread for value from * the primitive. * @param {!string} opcode opcode used to identify a block function primitive. * @param {!boolean} isHat Is the current block a hat? */ // @todo move this to callback attached to the thread when we have performance // metrics (dd) const handleReport = function handleReport(resolvedValue, sequencer, thread, blockCached, lastOperation) { const currentBlockId = blockCached.id; const opcode = blockCached.opcode; const isHat = blockCached._isHat; thread.pushReportedValue(resolvedValue); if (isHat) { // Hat predicate was evaluated. if (sequencer.runtime.getIsEdgeActivatedHat(opcode)) { // If this is an edge-activated hat, only proceed if the value is // true and used to be false, or the stack was activated explicitly // via stack click if (!thread.stackClick) { const hasOldEdgeValue = thread.target.hasEdgeActivatedValue(currentBlockId); const oldEdgeValue = thread.target.updateEdgeActivatedValue(currentBlockId, resolvedValue); const edgeWasActivated = hasOldEdgeValue ? !oldEdgeValue && resolvedValue : resolvedValue; if (edgeWasActivated) { // TW: Resume the thread if we were paused for a promise. thread.status = Thread.STATUS_RUNNING; } else { sequencer.retireThread(thread); } } } else if (!resolvedValue) { // Not an edge-activated hat: retire the thread // if predicate was false. sequencer.retireThread(thread); } } else { // In a non-hat, report the value visually if necessary if // at the top of the thread stack. if (lastOperation && typeof resolvedValue !== 'undefined' && thread.atStackTop()) { if (thread.stackClick) { sequencer.runtime.visualReport(currentBlockId, resolvedValue); } if (thread.updateMonitor) { const targetId = sequencer.runtime.monitorBlocks.getBlock(currentBlockId).targetId; if (targetId && !sequencer.runtime.getTargetById(targetId)) { // Target no longer exists return; } sequencer.runtime.requestUpdateMonitor(Map({ id: currentBlockId, spriteName: targetId ? sequencer.runtime.getTargetById(targetId).getName() : null, value: resolvedValue })); } } // Finished any yields. thread.status = Thread.STATUS_RUNNING; } }; const handlePromise = (primitiveReportedValue, sequencer, thread, blockCached, lastOperation) => { if (thread.status === Thread.STATUS_RUNNING) { // Primitive returned a promise; automatically yield thread. thread.status = Thread.STATUS_PROMISE_WAIT; } // Promise handlers primitiveReportedValue.then(resolvedValue => { handleReport(resolvedValue, sequencer, thread, blockCached, lastOperation); // If it's a command block or a top level reporter in a stackClick. // TW: Don't mangle the stack when we just finished executing a hat block. // Hat block is always the top and first block of the script. There are no loops to find. if (lastOperation && !blockCached._isHat) { let stackFrame; let nextBlockId; do { // In the case that the promise is the last block in the current thread stack // We need to pop out repeatedly until we find the next block. const popped = thread.popStack(); if (popped === null) { return; } nextBlockId = thread.target.blocks.getNextBlock(popped); if (nextBlockId !== null) { // A next block exists so break out this loop break; } // Investigate the next block and if not in a loop, // then repeat and pop the next item off the stack frame stackFrame = thread.peekStackFrame(); } while (stackFrame !== null && !stackFrame.isLoop); thread.pushStack(nextBlockId); } }, rejectionReason => { // Promise rejected: the primitive had some error. // Log it and proceed. log.warn('Primitive rejected promise: ', rejectionReason); thread.status = Thread.STATUS_RUNNING; thread.popStack(); }); }; /** * A execute.js internal representation of a block to reduce the time spent in * execute as the same blocks are called the most. * * With the help of the Blocks class create a mutable copy of block * information. The members of BlockCached derived values of block information * that does not need to be reevaluated until a change in Blocks. Since Blocks * handles where the cache instance is stored, it drops all cache versions of a * block when any change happens to it. This way we can quickly execute blocks * and keep perform the right action according to the current block information * in the editor. * * @param {Blocks} blockContainer the related Blocks instance * @param {object} cached default set of cached values */ class BlockCached { constructor(blockContainer, cached) { /** * Block id in its parent set of blocks. * @type {string} */ this.id = cached.id; /** * Block operation code for this block. * @type {string} */ this.opcode = cached.opcode; /** * Original block object containing argument values for static fields. * @type {object} */ this.fields = cached.fields; /** * Original block object containing argument values for executable inputs. * @type {object} */ this.inputs = cached.inputs; /** * Procedure mutation. * @type {?object} */ this.mutation = cached.mutation; /** * The profiler the block is configured with. * @type {?Profiler} */ this._profiler = null; /** * Profiler information frame. * @type {?ProfilerFrame} */ this._profilerFrame = null; /** * Is the opcode a hat (event responder) block. * @type {boolean} */ this._isHat = false; /** * The block opcode's implementation function. * @type {?function} */ this._blockFunction = null; /** * Is the block function defined for this opcode? * @type {boolean} */ this._definedBlockFunction = false; /** * Is this block a block with no function but a static value to return. * @type {boolean} */ this._isShadowBlock = false; /** * The static value of this block if it is a shadow block. * @type {?any} */ this._shadowValue = null; /** * A copy of the block's fields that may be modified. * @type {object} */ this._fields = Object.assign({}, this.fields); /** * A copy of the block's inputs that may be modified. * @type {object} */ this._inputs = Object.assign({}, this.inputs); /** * An arguments object for block implementations. All executions of this * specific block will use this objecct. * @type {object} */ this._argValues = { mutation: this.mutation }; /** * The inputs key the parent refers to this BlockCached by. * @type {string} */ this._parentKey = null; /** * The target object where the parent wants the resulting value stored * with _parentKey as the key. * @type {object} */ this._parentValues = null; /** * A sequence of non-shadow operations that can must be performed. This * list recreates the order this block and its children are executed. * Since the order is always the same we can safely store that order * and iterate over the operations instead of dynamically walking the * tree every time. * @type {Array} */ this._ops = []; const { runtime } = blockUtility.sequencer; const { opcode, fields, inputs } = this; // Assign opcode isHat and blockFunction data to avoid dynamic lookups. this._isHat = runtime.getIsHat(opcode); this._blockFunction = runtime.getOpcodeFunction(opcode); this._definedBlockFunction = typeof this._blockFunction !== 'undefined'; // Store the current shadow value if there is a shadow value. const fieldKeys = Object.keys(fields); this._isShadowBlock = !this._definedBlockFunction && fieldKeys.length === 1 && Object.keys(inputs).length === 0; this._shadowValue = this._isShadowBlock && fields[fieldKeys[0]].value; // Store the static fields onto _argValues. for (const fieldName in fields) { if (fieldName === 'VARIABLE' || fieldName === 'LIST' || fieldName === 'BROADCAST_OPTION') { this._argValues[fieldName] = { id: fields[fieldName].id, name: fields[fieldName].value }; } else { this._argValues[fieldName] = fields[fieldName].value; } } // Remove custom_block. It is not part of block execution. delete this._inputs.custom_block; if ('BROADCAST_INPUT' in this._inputs) { // BROADCAST_INPUT is called BROADCAST_OPTION in the args and is an // object with an unchanging shape. this._argValues.BROADCAST_OPTION = { id: null, name: null }; // We can go ahead and compute BROADCAST_INPUT if it is a shadow // value. const broadcastInput = this._inputs.BROADCAST_INPUT; if (broadcastInput.block === broadcastInput.shadow) { // Shadow dropdown menu is being used. // Get the appropriate information out of it. const shadow = blockContainer.getBlock(broadcastInput.shadow); const broadcastField = shadow.fields.BROADCAST_OPTION; this._argValues.BROADCAST_OPTION.id = broadcastField.id; this._argValues.BROADCAST_OPTION.name = broadcastField.value; // Evaluating BROADCAST_INPUT here we do not need to do so // later. delete this._inputs.BROADCAST_INPUT; } } // Cache all input children blocks in the operation lists. The // operations can later be run in the order they appear in correctly // executing the operations quickly in a flat loop instead of needing to // recursivly iterate them. for (const inputName in this._inputs) { const input = this._inputs[inputName]; if (input.block) { const inputCached = BlocksExecuteCache.getCached(blockContainer, input.block, BlockCached); if (inputCached._isHat) { continue; } this._ops.push(...inputCached._ops); inputCached._parentKey = inputName; inputCached._parentValues = this._argValues; // Shadow values are static and do not change, go ahead and // store their value on args. if (inputCached._isShadowBlock) { this._argValues[inputName] = inputCached._shadowValue; } } } // The final operation is this block itself. At the top most block is a // command block or a block that is being run as a monitor. if (this._definedBlockFunction) { this._ops.push(this); } } } /** * Initialize a BlockCached instance so its command/hat * block and reporters can be profiled during execution. * @param {Profiler} profiler - The profiler that is currently enabled. * @param {BlockCached} blockCached - The blockCached instance to profile. */ const _prepareBlockProfiling = function _prepareBlockProfiling(profiler, blockCached) { blockCached._profiler = profiler; if (blockFunctionProfilerId === -1) { blockFunctionProfilerId = profiler.idByName(blockFunctionProfilerFrame); } const ops = blockCached._ops; for (let i = 0; i < ops.length; i++) { ops[i]._profilerFrame = profiler.frame(blockFunctionProfilerId, ops[i].opcode); } }; /** * Execute a block. * @param {!Sequencer} sequencer Which sequencer is executing. * @param {!Thread} thread Thread which to read and execute. */ const execute = function execute(sequencer, thread) { const runtime = sequencer.runtime; // store sequencer and thread so block functions can access them through // convenience methods. blockUtility.sequencer = sequencer; blockUtility.thread = thread; // Current block to execute is the one on the top of the stack. const currentBlockId = thread.peekStack(); const currentStackFrame = thread.peekStackFrame(); let blockContainer = thread.blockContainer; let blockCached = BlocksExecuteCache.getCached(blockContainer, currentBlockId, BlockCached); if (blockCached === null) { blockContainer = runtime.flyoutBlocks; blockCached = BlocksExecuteCache.getCached(blockContainer, currentBlockId, BlockCached); // Stop if block or target no longer exists. if (blockCached === null) { // No block found: stop the thread; script no longer exists. sequencer.retireThread(thread); return; } } const ops = blockCached._ops; const length = ops.length; let i = 0; if (currentStackFrame.reported !== null) { const reported = currentStackFrame.reported; // Reinstate all the previous values. for (; i < reported.length; i++) { const { opCached: oldOpCached, inputValue } = reported[i]; const opCached = ops.find(op => op.id === oldOpCached); if (opCached) { const inputName = opCached._parentKey; const argValues = opCached._parentValues; if (inputName === 'BROADCAST_INPUT') { // Something is plugged into the broadcast input. // Cast it to a string. We don't need an id here. argValues.BROADCAST_OPTION.id = null; argValues.BROADCAST_OPTION.name = cast.toString(inputValue); } else { argValues[inputName] = inputValue; } } } // Find the last reported block that is still in the set of operations. // This way if the last operation was removed, we'll find the next // candidate. If an earlier block that was performed was removed then // we'll find the index where the last operation is now. if (reported.length > 0) { const lastExisting = reported.reverse().find(report => ops.find(op => op.id === report.opCached)); if (lastExisting) { i = ops.findIndex(opCached => opCached.id === lastExisting.opCached) + 1; } else { i = 0; } } // The reporting block must exist and must be the next one in the sequence of operations. if (thread.justReported !== null && ops[i] && ops[i].id === currentStackFrame.reporting) { const opCached = ops[i]; const inputValue = thread.justReported; thread.justReported = null; const inputName = opCached._parentKey; const argValues = opCached._parentValues; if (inputName === 'BROADCAST_INPUT') { // Something is plugged into the broadcast input. // Cast it to a string. We don't need an id here. argValues.BROADCAST_OPTION.id = null; argValues.BROADCAST_OPTION.name = cast.toString(inputValue); } else { argValues[inputName] = inputValue; } i += 1; } currentStackFrame.reporting = null; currentStackFrame.reported = null; } const start = i; for (; i < length; i++) { const lastOperation = i === length - 1; const opCached = ops[i]; const blockFunction = opCached._blockFunction; // Update values for arguments (inputs). const argValues = opCached._argValues; // Fields are set during opCached initialization. // Blocks should glow when a script is starting, // not after it has finished (see #1404). // Only blocks in blockContainers that don't forceNoGlow // should request a glow. if (!blockContainer.forceNoGlow) { thread.requestScriptGlowInFrame = true; } // Inputs are set during previous steps in the loop. const primitiveReportedValue = blockFunction(argValues, blockUtility); // If it's a promise, wait until promise resolves. if (isPromise(primitiveReportedValue)) { handlePromise(primitiveReportedValue, sequencer, thread, opCached, lastOperation); // Store the already reported values. They will be thawed into the // future versions of the same operations by block id. The reporting // operation if it is promise waiting will set its parent value at // that time. thread.justReported = null; currentStackFrame.reporting = ops[i].id; currentStackFrame.reported = ops.slice(0, i).map(reportedCached => { const inputName = reportedCached._parentKey; const reportedValues = reportedCached._parentValues; if (inputName === 'BROADCAST_INPUT') { return { opCached: reportedCached.id, inputValue: reportedValues[inputName].BROADCAST_OPTION.name }; } return { opCached: reportedCached.id, inputValue: reportedValues[inputName] }; }); // We are waiting for a promise. Stop running this set of operations // and continue them later after thawing the reported values. break; } else if (thread.status === Thread.STATUS_RUNNING) { if (lastOperation) { handleReport(primitiveReportedValue, sequencer, thread, opCached, lastOperation); } else { // By definition a block that is not last in the list has a // parent. const inputName = opCached._parentKey; const parentValues = opCached._parentValues; if (inputName === 'BROADCAST_INPUT') { // Something is plugged into the broadcast input. // Cast it to a string. We don't need an id here. parentValues.BROADCAST_OPTION.id = null; parentValues.BROADCAST_OPTION.name = cast.toString(primitiveReportedValue); } else { parentValues[inputName] = primitiveReportedValue; } } } } if (runtime.profiler !== null) { if (blockCached._profiler !== runtime.profiler) { _prepareBlockProfiling(runtime.profiler, blockCached); } // Determine the index that is after the last executed block. `i` is // currently the block that was just executed. `i + 1` will be the block // after that. `length` with the min call makes sure we don't try to // reference an operation outside of the set of operations. const end = Math.min(i + 1, length); for (let p = start; p < end; p++) { ops[p]._profilerFrame.count += 1; } } }; module.exports = execute; /***/ }), /***/ "./node_modules/scratch-vm/src/engine/monitor-record.js": /*!**************************************************************!*\ !*** ./node_modules/scratch-vm/src/engine/monitor-record.js ***! \**************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const { Record } = __webpack_require__(/*! immutable */ "./node_modules/immutable/dist/immutable.js"); const MonitorRecord = Record({ id: null, // Block Id /** Present only if the monitor is sprite-specific, such as x position */ spriteName: null, /** Present only if the monitor is sprite-specific, such as x position */ targetId: null, opcode: null, value: null, params: null, mode: 'default', sliderMin: 0, sliderMax: 100, isDiscrete: true, x: null, // (x: null, y: null) Indicates that the monitor should be auto-positioned y: null, width: 0, height: 0, visible: true }); module.exports = MonitorRecord; /***/ }), /***/ "./node_modules/scratch-vm/src/engine/mutation-adapter.js": /*!****************************************************************!*\ !*** ./node_modules/scratch-vm/src/engine/mutation-adapter.js ***! \****************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const html = __webpack_require__(/*! htmlparser2 */ "./node_modules/scratch-vm/node_modules/htmlparser2/lib/index.js"); const decodeHtml = __webpack_require__(/*! decode-html */ "./node_modules/decode-html/index.js"); /** * Convert a part of a mutation DOM to a mutation VM object, recursively. * @param {object} dom DOM object for mutation tag. * @return {object} Object representing useful parts of this mutation. */ const mutatorTagToObject = function mutatorTagToObject(dom) { const obj = Object.create(null); obj.tagName = dom.name; obj.children = []; for (const prop in dom.attribs) { if (prop === 'xmlns') continue; obj[prop] = decodeHtml(dom.attribs[prop]); // Note: the capitalization of block info in the following lines is important. // The lowercase is read in from xml which normalizes case. The VM uses camel case everywhere else. if (prop === 'blockinfo') { obj.blockInfo = JSON.parse(obj.blockinfo); delete obj.blockinfo; } } for (let i = 0; i < dom.children.length; i++) { obj.children.push(mutatorTagToObject(dom.children[i])); } return obj; }; /** * Adapter between mutator XML or DOM and block representation which can be * used by the Scratch runtime. * @param {(object|string)} mutation Mutation XML string or DOM. * @return {object} Object representing the mutation. */ const mutationAdpater = function mutationAdpater(mutation) { let mutationParsed; // Check if the mutation is already parsed; if not, parse it. if (typeof mutation === 'object') { mutationParsed = mutation; } else { mutationParsed = html.parseDOM(mutation)[0]; } return mutatorTagToObject(mutationParsed); }; module.exports = mutationAdpater; /***/ }), /***/ "./node_modules/scratch-vm/src/engine/profiler.js": /*!********************************************************!*\ !*** ./node_modules/scratch-vm/src/engine/profiler.js ***! \********************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /** * @fileoverview * A way to profile Scratch internal performance. Like what blocks run during a * step? How much time do they take? How much time is spent inbetween blocks? * * Profiler aims for to spend as little time inside its functions while * recording. For this it has a simple internal record structure that records a * series of values for each START and STOP event in a single array. This lets * all the values be pushed in one call for the array. This simplicity allows * the contents of the start() and stop() calls to be inlined in areas that are * called frequently enough to want even greater performance from Profiler so * what is recorded better reflects on the profiled code and not Profiler * itself. */ /** * The next id returned for a new profile'd function. * @type {number} */ let nextId = 0; /** * The mapping of names to ids. * @const {Object.} */ const profilerNames = {}; /** * The START event identifier in Profiler records. * @const {number} */ const START = 0; /** * The STOP event identifier in Profiler records. * @const {number} */ const STOP = 1; /** * The number of cells used in the records array by a START event. * @const {number} */ const START_SIZE = 4; /** * The number of cells used in the records array by a STOP event. * @const {number} */ const STOP_SIZE = 2; /** * Stored reference to Performance instance provided by the Browser. * @const {Performance} */ const performance = typeof window === 'object' && window.performance; /** * Callback handle called by Profiler for each frame it decodes from its * records. * @callback FrameCallback * @param {ProfilerFrame} frame */ /** * A set of information about a frame of execution that was recorded. */ class ProfilerFrame { /** * @param {number} depth Depth of the frame in the recorded stack. */ constructor(depth) { /** * The numeric id of a record symbol like Runtime._step or * blockFunction. * @type {number} */ this.id = -1; /** * The amount of time spent inside the recorded frame and any deeper * frames. * @type {number} */ this.totalTime = 0; /** * The amount of time spent only inside this record frame. Not * including time in any deeper frames. * @type {number} */ this.selfTime = 0; /** * An arbitrary argument for the recorded frame. For example a block * function might record its opcode as an argument. * @type {*} */ this.arg = null; /** * The depth of the recorded frame. This can help compare recursive * funtions that are recorded. Each level of recursion with have a * different depth value. * @type {number} */ this.depth = depth; /** * A summarized count of the number of calls to this frame. * @type {number} */ this.count = 0; } } class Profiler { /** * @param {FrameCallback} onFrame a handle called for each recorded frame. * The passed frame value may not be stored as it'll be updated with later * frame information. Any information that is further stored by the handler * should make copies or reduce the information. */ constructor(onFrame = function () {}) { /** * A series of START and STOP values followed by arguments. After * recording is complete the full set of records is reported back by * stepping through the series to connect the relative START and STOP * information. * @type {Array.<*>} */ this.records = []; /** * An array of frames incremented on demand instead as part of start * and stop. * @type {Array.} */ this.increments = []; /** * An array of profiler frames separated by counter argument. Generally * for Scratch these frames are separated by block function opcode. * This tracks each time an opcode is called. * @type {Array.} */ this.counters = []; /** * A frame with no id or argument. * @type {ProfilerFrame} */ this.nullFrame = new ProfilerFrame(-1); /** * A cache of ProfilerFrames to reuse when reporting the recorded * frames in records. * @type {Array.} */ this._stack = [new ProfilerFrame(0)]; /** * A callback handle called with each decoded frame when reporting back * all the recorded times. * @type {FrameCallback} */ this.onFrame = onFrame; /** * A reference to the START record id constant. * @const {number} */ this.START = START; /** * A reference to the STOP record id constant. * @const {number} */ this.STOP = STOP; } /** * Start recording a frame of time for an id and optional argument. * @param {number} id The id returned by idByName for a name symbol like * Runtime._step. * @param {?*} arg An arbitrary argument value to store with the frame. */ start(id, arg) { this.records.push(START, id, arg, performance.now()); } /** * Stop the current frame. */ stop() { this.records.push(STOP, performance.now()); } /** * Increment the number of times this symbol is called. * @param {number} id The id returned by idByName for a name symbol. */ increment(id) { if (!this.increments[id]) { this.increments[id] = new ProfilerFrame(-1); this.increments[id].id = id; } this.increments[id].count += 1; } /** * Find or create a ProfilerFrame-like object whose counter can be * incremented outside of the Profiler. * @param {number} id The id returned by idByName for a name symbol. * @param {*} arg The argument for a frame that identifies it in addition * to the id. * @return {{count: number}} A ProfilerFrame-like whose count should be * incremented for each call. */ frame(id, arg) { for (let i = 0; i < this.counters.length; i++) { if (this.counters[i].id === id && this.counters[i].arg === arg) { return this.counters[i]; } } const newCounter = new ProfilerFrame(-1); newCounter.id = id; newCounter.arg = arg; this.counters.push(newCounter); return newCounter; } /** * Decode records and report all frames to `this.onFrame`. */ reportFrames() { const stack = this._stack; let depth = 1; // Step through the records and initialize Frame instances from the // START and STOP events. START and STOP events are separated by events // for deeper frames run by higher frames. Frames are stored on a stack // and reinitialized for each START event. When a stop event is reach // the Frame for the current depth has its final values stored and its // passed to the current onFrame callback. This way Frames are "pushed" // for each START event and "popped" for each STOP and handed to an // outside handle to any desired reduction of the collected data. for (let i = 0; i < this.records.length;) { if (this.records[i] === START) { if (depth >= stack.length) { stack.push(new ProfilerFrame(depth)); } // Store id, arg, totalTime, and initialize selfTime. const frame = stack[depth++]; frame.id = this.records[i + 1]; frame.arg = this.records[i + 2]; // totalTime is first set as the time recorded by this START // event. Once the STOP event is reached the stored start time // is subtracted from the recorded stop time. The resulting // difference is the actual totalTime, and replaces the start // time in frame.totalTime. // // totalTime is used this way as a convenient member to store a // value between the two events without needing additional // members on the Frame or in a shadow map. frame.totalTime = this.records[i + 3]; // selfTime is decremented until we reach the STOP event for // this frame. totalTime will be added to it then to get the // time difference. frame.selfTime = 0; i += START_SIZE; } else if (this.records[i] === STOP) { const now = this.records[i + 1]; const frame = stack[--depth]; // totalTime is the difference between the start event time // stored in totalTime and the stop event time pulled from this // record. frame.totalTime = now - frame.totalTime; // selfTime is the difference of this frame's totalTime and the // sum of totalTime of deeper frames. frame.selfTime += frame.totalTime; // Remove this frames totalTime from the parent's selfTime. stack[depth - 1].selfTime -= frame.totalTime; // This frame occured once. frame.count = 1; this.onFrame(frame); i += STOP_SIZE; } else { this.records.length = 0; throw new Error('Unable to decode Profiler records.'); } } for (let j = 0; j < this.increments.length; j++) { if (this.increments[j] && this.increments[j].count > 0) { this.onFrame(this.increments[j]); this.increments[j].count = 0; } } for (let k = 0; k < this.counters.length; k++) { if (this.counters[k].count > 0) { this.onFrame(this.counters[k]); this.counters[k].count = 0; } } this.records.length = 0; } /** * Lookup or create an id for a frame name. * @param {string} name The name to return an id for. * @return {number} The id for the passed name. */ idByName(name) { return Profiler.idByName(name); } /** * Reverse lookup the name from a given frame id. * @param {number} id The id to search for. * @return {string} The name for the given id. */ nameById(id) { return Profiler.nameById(id); } /** * Lookup or create an id for a frame name. * @static * @param {string} name The name to return an id for. * @return {number} The id for the passed name. */ static idByName(name) { if (typeof profilerNames[name] !== 'number') { profilerNames[name] = nextId++; } return profilerNames[name]; } /** * Reverse lookup the name from a given frame id. * @static * @param {number} id The id to search for. * @return {string} The name for the given id. */ static nameById(id) { for (const name in profilerNames) { if (profilerNames[name] === id) { return name; } } return null; } /** * Profiler is only available on platforms with the Performance API. * @return {boolean} Can the Profiler run in this browser? */ static available() { return typeof window === 'object' && typeof window.performance !== 'undefined'; } } /** * A reference to the START record id constant. * @const {number} */ Profiler.START = START; /** * A reference to the STOP record id constant. * @const {number} */ Profiler.STOP = STOP; module.exports = Profiler; /***/ }), /***/ "./node_modules/scratch-vm/src/engine/runtime.js": /*!*******************************************************!*\ !*** ./node_modules/scratch-vm/src/engine/runtime.js ***! \*******************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } const EventEmitter = __webpack_require__(/*! events */ "./node_modules/events/events.js"); const { OrderedMap } = __webpack_require__(/*! immutable */ "./node_modules/immutable/dist/immutable.js"); const ExtendedJSON = __webpack_require__(/*! @turbowarp/json */ "./node_modules/@turbowarp/json/src/index.js"); const ArgumentType = __webpack_require__(/*! ../extension-support/argument-type */ "./node_modules/scratch-vm/src/extension-support/argument-type.js"); const Blocks = __webpack_require__(/*! ./blocks */ "./node_modules/scratch-vm/src/engine/blocks.js"); const BlocksRuntimeCache = __webpack_require__(/*! ./blocks-runtime-cache */ "./node_modules/scratch-vm/src/engine/blocks-runtime-cache.js"); const BlockType = __webpack_require__(/*! ../extension-support/block-type */ "./node_modules/scratch-vm/src/extension-support/block-type.js"); const Profiler = __webpack_require__(/*! ./profiler */ "./node_modules/scratch-vm/src/engine/profiler.js"); const Sequencer = __webpack_require__(/*! ./sequencer */ "./node_modules/scratch-vm/src/engine/sequencer.js"); const execute = __webpack_require__(/*! ./execute.js */ "./node_modules/scratch-vm/src/engine/execute.js"); const ScratchBlocksConstants = __webpack_require__(/*! ./scratch-blocks-constants */ "./node_modules/scratch-vm/src/engine/scratch-blocks-constants.js"); const TargetType = __webpack_require__(/*! ../extension-support/target-type */ "./node_modules/scratch-vm/src/extension-support/target-type.js"); const Thread = __webpack_require__(/*! ./thread */ "./node_modules/scratch-vm/src/engine/thread.js"); const log = __webpack_require__(/*! ../util/log */ "./node_modules/scratch-vm/src/util/log.js"); const maybeFormatMessage = __webpack_require__(/*! ../util/maybe-format-message */ "./node_modules/scratch-vm/src/util/maybe-format-message.js"); const StageLayering = __webpack_require__(/*! ./stage-layering */ "./node_modules/scratch-vm/src/engine/stage-layering.js"); const Variable = __webpack_require__(/*! ./variable */ "./node_modules/scratch-vm/src/engine/variable.js"); const xmlEscape = __webpack_require__(/*! ../util/xml-escape */ "./node_modules/scratch-vm/src/util/xml-escape.js"); const ScratchLinkWebSocket = __webpack_require__(/*! ../util/scratch-link-websocket */ "./node_modules/scratch-vm/src/util/scratch-link-websocket.js"); // Virtual I/O devices. const Clock = __webpack_require__(/*! ../io/clock */ "./node_modules/scratch-vm/src/io/clock.js"); const Cloud = __webpack_require__(/*! ../io/cloud */ "./node_modules/scratch-vm/src/io/cloud.js"); const Keyboard = __webpack_require__(/*! ../io/keyboard */ "./node_modules/scratch-vm/src/io/keyboard.js"); const Mouse = __webpack_require__(/*! ../io/mouse */ "./node_modules/scratch-vm/src/io/mouse.js"); const MouseWheel = __webpack_require__(/*! ../io/mouseWheel */ "./node_modules/scratch-vm/src/io/mouseWheel.js"); const UserData = __webpack_require__(/*! ../io/userData */ "./node_modules/scratch-vm/src/io/userData.js"); const Video = __webpack_require__(/*! ../io/video */ "./node_modules/scratch-vm/src/io/video.js"); const StringUtil = __webpack_require__(/*! ../util/string-util */ "./node_modules/scratch-vm/src/util/string-util.js"); const uid = __webpack_require__(/*! ../util/uid */ "./node_modules/scratch-vm/src/util/uid.js"); const defaultBlockPackages = { scratch3_control: __webpack_require__(/*! ../blocks/scratch3_control */ "./node_modules/scratch-vm/src/blocks/scratch3_control.js"), scratch3_event: __webpack_require__(/*! ../blocks/scratch3_event */ "./node_modules/scratch-vm/src/blocks/scratch3_event.js"), scratch3_looks: __webpack_require__(/*! ../blocks/scratch3_looks */ "./node_modules/scratch-vm/src/blocks/scratch3_looks.js"), scratch3_motion: __webpack_require__(/*! ../blocks/scratch3_motion */ "./node_modules/scratch-vm/src/blocks/scratch3_motion.js"), scratch3_operators: __webpack_require__(/*! ../blocks/scratch3_operators */ "./node_modules/scratch-vm/src/blocks/scratch3_operators.js"), scratch3_sound: __webpack_require__(/*! ../blocks/scratch3_sound */ "./node_modules/scratch-vm/src/blocks/scratch3_sound.js"), scratch3_sensing: __webpack_require__(/*! ../blocks/scratch3_sensing */ "./node_modules/scratch-vm/src/blocks/scratch3_sensing.js"), scratch3_data: __webpack_require__(/*! ../blocks/scratch3_data */ "./node_modules/scratch-vm/src/blocks/scratch3_data.js"), scratch3_procedures: __webpack_require__(/*! ../blocks/scratch3_procedures */ "./node_modules/scratch-vm/src/blocks/scratch3_procedures.js") }; const interpolate = __webpack_require__(/*! ./tw-interpolate */ "./node_modules/scratch-vm/src/engine/tw-interpolate.js"); const FrameLoop = __webpack_require__(/*! ./tw-frame-loop */ "./node_modules/scratch-vm/src/engine/tw-frame-loop.js"); const defaultExtensionColors = ['#0FBD8C', '#0DA57A', '#0B8E69']; const COMMENT_CONFIG_MAGIC = ' // _twconfig_'; /** * Information used for converting Scratch argument types into scratch-blocks data. * @type {object.} */ const ArgumentTypeMap = (() => { const map = {}; map[ArgumentType.ANGLE] = { shadow: { type: 'math_angle', // We specify fieldNames here so that we can pick // create and populate a field with the defaultValue // specified in the extension. // When the `fieldName` property is not specified, // the will be left out of the XML and // the scratch-blocks defaults for that field will be // used instead (e.g. default of 0 for number fields) fieldName: 'NUM' } }; map[ArgumentType.COLOR] = { shadow: { type: 'colour_picker', fieldName: 'COLOUR' } }; map[ArgumentType.NUMBER] = { shadow: { type: 'math_number', fieldName: 'NUM' } }; map[ArgumentType.STRING] = { shadow: { type: 'text', fieldName: 'TEXT' } }; map[ArgumentType.BOOLEAN] = { check: 'Boolean' }; map[ArgumentType.MATRIX] = { shadow: { type: 'matrix', fieldName: 'MATRIX' } }; map[ArgumentType.NOTE] = { shadow: { type: 'note', fieldName: 'NOTE' } }; map[ArgumentType.IMAGE] = { // Inline images are weird because they're not actually "arguments". // They are more analagous to the label on a block. fieldType: 'field_image' }; return map; })(); /** * A pair of functions used to manage the cloud variable limit, * to be used when adding (or attempting to add) or removing a cloud variable. * @typedef {object} CloudDataManager * @property {function} canAddCloudVariable A function to call to check that * a cloud variable can be added. * @property {function} addCloudVariable A function to call to track a new * cloud variable on the runtime. * @property {function} removeCloudVariable A function to call when * removing an existing cloud variable. * @property {function} hasCloudVariables A function to call to check that * the runtime has any cloud variables. * @property {function} getNumberOfCloudVariables A function that returns the * number of cloud variables in the project. */ /** * Creates and manages cloud variable limit in a project, * and returns two functions to be used to add a new * cloud variable (while checking that it can be added) * and remove an existing cloud variable. * These are to be called whenever attempting to create or delete * a cloud variable. * @param {Object} cloudOptions * @param {number} cloudOptions.limit Maximum number of cloud variables * @return {CloudDataManager} The functions to be used when adding or removing a * cloud variable. */ const cloudDataManager = cloudOptions => { let count = 0; const canAddCloudVariable = () => count < cloudOptions.limit; const addCloudVariable = () => { count++; }; const removeCloudVariable = () => { count--; }; const hasCloudVariables = () => count > 0; const getNumberOfCloudVariables = () => count; return { canAddCloudVariable, addCloudVariable, removeCloudVariable, hasCloudVariables, getNumberOfCloudVariables }; }; /** * Numeric ID for Runtime._step in Profiler instances. * @type {number} */ let stepProfilerId = -1; /** * Numeric ID for Sequencer.stepThreads in Profiler instances. * @type {number} */ let stepThreadsProfilerId = -1; /** * Numeric ID for RenderWebGL.draw in Profiler instances. * @type {number} */ let rendererDrawProfilerId = -1; /** * Manages targets, scripts, and the sequencer. * @constructor */ class Runtime extends EventEmitter { constructor() { super(); /** * Target management and storage. * @type {Array.} */ this.targets = []; /** * Targets in reverse order of execution. Shares its order with drawables. * @type {Array.} */ this.executableTargets = []; /** * A list of threads that are currently running in the VM. * Threads are added when execution starts and pruned when execution ends. * @type {Array.} */ this.threads = []; this.threadMap = new Map(); /** @type {!Sequencer} */ this.sequencer = new Sequencer(this); /** * Storage container for flyout blocks. * These will execute on `_editingTarget.` * @type {!Blocks} */ this.flyoutBlocks = new Blocks(this, true /* force no glow */ ); /** * Storage container for monitor blocks. * These will execute on a target maybe * @type {!Blocks} */ this.monitorBlocks = new Blocks(this, true /* force no glow */ ); /** * Currently known editing target for the VM. * @type {?Target} */ this._editingTarget = null; /** * Map to look up a block primitive's implementation function by its opcode. * This is a two-step lookup: package name first, then primitive name. * @type {Object.} */ this._primitives = {}; /** * Map to look up all block information by extended opcode. * @type {Array.} * @private */ this._blockInfo = []; /** * Map to look up hat blocks' metadata. * Keys are opcode for hat, values are metadata objects. * @type {Object.} */ this._hats = {}; /** * A list of script block IDs that were glowing during the previous frame. * @type {!Array.} */ this._scriptGlowsPreviousFrame = []; /** * Number of non-monitor threads running during the previous frame. * @type {number} */ this._nonMonitorThreadCount = 0; /** * All threads that finished running and were removed from this.threads * by behaviour in Sequencer.stepThreads. * @type {Array} */ this._lastStepDoneThreads = null; /** * Currently known number of clones, used to enforce clone limit. * @type {number} */ this._cloneCounter = 0; /** * Flag to emit a targets update at the end of a step. When target data * changes, this flag is set to true. * @type {boolean} */ this._refreshTargets = false; /** * Map to look up all monitor block information by opcode. * @type {object} * @private */ this.monitorBlockInfo = {}; /** * Ordered map of all monitors, which are MonitorReporter objects. */ this._monitorState = OrderedMap({}); /** * Monitor state from last tick */ this._prevMonitorState = OrderedMap({}); /** * Whether the project is in "turbo mode." * @type {Boolean} */ this.turboMode = false; /** * tw: Responsible for managing the VM's many timers. */ this.frameLoop = new FrameLoop(this); /** * Current length of a step. * Changes as mode switches, and used by the sequencer to calculate * WORK_TIME. * @type {!number} */ this.currentStepTime = 1000 / 30; // Set an intial value for this.currentMSecs this.updateCurrentMSecs(); /** * Whether any primitive has requested a redraw. * Affects whether `Sequencer.stepThreads` will yield * after stepping each thread. * Reset on every frame. * @type {boolean} */ this.redrawRequested = false; // Register all given block packages. this._registerBlockPackages(); // Register and initialize "IO devices", containers for processing // I/O related data. /** @type {Object.} */ this.ioDevices = { clock: new Clock(this), cloud: new Cloud(this), keyboard: new Keyboard(this), mouse: new Mouse(this), mouseWheel: new MouseWheel(this), userData: new UserData(), video: new Video(this) }; /** * A list of extensions, used to manage hardware connection. */ this.peripheralExtensions = {}; /** * A runtime profiler that records timed events for later playback to * diagnose Scratch performance. * @type {Profiler} */ this.profiler = null; this.cloudOptions = { limit: 10 }; const newCloudDataManager = cloudDataManager(this.cloudOptions); /** * Check wether the runtime has any cloud data. * @type {function} * @return {boolean} Whether or not the runtime currently has any * cloud variables. */ this.hasCloudData = newCloudDataManager.hasCloudVariables; /** * A function which checks whether a new cloud variable can be added * to the runtime. * @type {function} * @return {boolean} Whether or not a new cloud variable can be added * to the runtime. */ this.canAddCloudVariable = newCloudDataManager.canAddCloudVariable; /** * A function which returns the number of cloud variables in the runtime. * @returns {number} */ this.getNumberOfCloudVariables = newCloudDataManager.getNumberOfCloudVariables; /** * A function that tracks a new cloud variable in the runtime, * updating the cloud variable limit. Calling this function will * emit a cloud data update event if this is the first cloud variable * being added. * @type {function} */ this.addCloudVariable = this._initializeAddCloudVariable(newCloudDataManager); /** * A function which updates the runtime's cloud variable limit * when removing a cloud variable and emits a cloud update event * if the last of the cloud variables is being removed. * @type {function} */ this.removeCloudVariable = this._initializeRemoveCloudVariable(newCloudDataManager); /** * A string representing the origin of the current project from outside of the * Scratch community, such as CSFirst. * @type {?string} */ this.origin = null; this._stageTarget = null; this.addonBlocks = {}; this.stageWidth = Runtime.STAGE_WIDTH; this.stageHeight = Runtime.STAGE_HEIGHT; this.runtimeOptions = { maxClones: Runtime.MAX_CLONES, miscLimits: true, fencing: true }; this.compilerOptions = { enabled: true, warpTimer: false }; this.debug = false; this._lastStepTime = Date.now(); this.interpolationEnabled = false; this._defaultStoredSettings = this._generateAllProjectOptions(); /** * TW: We support a "packaged runtime" mode. This can be used when: * - there will never be an editor attached such as scratch-gui or scratch-blocks * - the project will never be exported with saveProjectSb3() * - original costume and sound data is not needed * In this mode, the runtime is able to discard large amounts of data and avoid some processing * to make projects load faster and use less memory. * This is not designed to protect projects from copying as someone can still copy the data that * gets fed into the runtime in the first place. * This mode is used by the TurboWarp Packager. */ this.isPackaged = false; } /** * Width of the stage, in pixels. * @const {number} */ static get STAGE_WIDTH() { // tw: stage size is set per-runtime, this is only the initial value return 480; } /** * Height of the stage, in pixels. * @const {number} */ static get STAGE_HEIGHT() { // tw: stage size is set per-runtime, this is only the initial value return 360; } /** * Event name for glowing a script. * @const {string} */ static get SCRIPT_GLOW_ON() { return 'SCRIPT_GLOW_ON'; } /** * Event name for unglowing a script. * @const {string} */ static get SCRIPT_GLOW_OFF() { return 'SCRIPT_GLOW_OFF'; } /** * Event name for glowing a block. * @const {string} */ static get BLOCK_GLOW_ON() { return 'BLOCK_GLOW_ON'; } /** * Event name for unglowing a block. * @const {string} */ static get BLOCK_GLOW_OFF() { return 'BLOCK_GLOW_OFF'; } /** * Event name for a cloud data update * to this project. * @const {string} */ static get HAS_CLOUD_DATA_UPDATE() { return 'HAS_CLOUD_DATA_UPDATE'; } /** * Event name for turning on turbo mode. * @const {string} */ static get TURBO_MODE_ON() { return 'TURBO_MODE_ON'; } /** * Event name for turning off turbo mode. * @const {string} */ static get TURBO_MODE_OFF() { return 'TURBO_MODE_OFF'; } /** * Event name for runtime options changing. * @const {string} */ static get RUNTIME_OPTIONS_CHANGED() { return 'RUNTIME_OPTIONS_CHANGED'; } /** * Event name for compiler options changing. * @const {string} */ static get COMPILER_OPTIONS_CHANGED() { return 'COMPILER_OPTIONS_CHANGED'; } /** * Event name for framerate changing. * @const {string} */ static get FRAMERATE_CHANGED() { return 'FRAMERATE_CHANGED'; } /** * Event name for interpolation changing. * @const {string} */ static get INTERPOLATION_CHANGED() { return 'INTERPOLATION_CHANGED'; } /** * Event name for stage size changing. * @const {string} */ static get STAGE_SIZE_CHANGED() { return 'STAGE_SIZE_CHANGED'; } /** * Event name for compiler errors. * @const {string} */ static get COMPILE_ERROR() { return 'COMPILE_ERROR'; } /** * Event name when the project is started (threads may not necessarily be * running). * @const {string} */ static get PROJECT_START() { return 'PROJECT_START'; } /** * Event name when threads start running. * Used by the UI to indicate running status. * @const {string} */ static get PROJECT_RUN_START() { return 'PROJECT_RUN_START'; } /** * Event name when threads stop running * Used by the UI to indicate not-running status. * @const {string} */ static get PROJECT_RUN_STOP() { return 'PROJECT_RUN_STOP'; } /** * Event name for project being stopped or restarted by the user. * Used by blocks that need to reset state. * @const {string} */ static get PROJECT_STOP_ALL() { return 'PROJECT_STOP_ALL'; } /** * Event name for target being stopped by a stop for target call. * Used by blocks that need to stop individual targets. * @const {string} */ static get STOP_FOR_TARGET() { return 'STOP_FOR_TARGET'; } /** * Event name for visual value report. * @const {string} */ static get VISUAL_REPORT() { return 'VISUAL_REPORT'; } /** * Event name for project loaded report. * @const {string} */ static get PROJECT_LOADED() { return 'PROJECT_LOADED'; } /** * Event name for report that a change was made that can be saved * @const {string} */ static get PROJECT_CHANGED() { return 'PROJECT_CHANGED'; } /** * Event name for report that a change was made to an extension in the toolbox. * @const {string} */ static get TOOLBOX_EXTENSIONS_NEED_UPDATE() { return 'TOOLBOX_EXTENSIONS_NEED_UPDATE'; } /** * Event name for targets update report. * @const {string} */ static get TARGETS_UPDATE() { return 'TARGETS_UPDATE'; } /** * Event name for monitors update. * @const {string} */ static get MONITORS_UPDATE() { return 'MONITORS_UPDATE'; } /** * Event name for block drag update. * @const {string} */ static get BLOCK_DRAG_UPDATE() { return 'BLOCK_DRAG_UPDATE'; } /** * Event name for block drag end. * @const {string} */ static get BLOCK_DRAG_END() { return 'BLOCK_DRAG_END'; } /** * Event name for reporting that an extension was added. * @const {string} */ static get EXTENSION_ADDED() { return 'EXTENSION_ADDED'; } /** * Event name for reporting that an extension as asked for a custom field to be added * @const {string} */ static get EXTENSION_FIELD_ADDED() { return 'EXTENSION_FIELD_ADDED'; } /** * Event name for updating the available set of peripheral devices. * This causes the peripheral connection modal to update a list of * available peripherals. * @const {string} */ static get PERIPHERAL_LIST_UPDATE() { return 'PERIPHERAL_LIST_UPDATE'; } /** * Event name for when the user picks a bluetooth device to connect to * via Companion Device Manager (CDM) * @const {string} */ static get USER_PICKED_PERIPHERAL() { return 'USER_PICKED_PERIPHERAL'; } /** * Event name for reporting that a peripheral has connected. * This causes the status button in the blocks menu to indicate 'connected'. * @const {string} */ static get PERIPHERAL_CONNECTED() { return 'PERIPHERAL_CONNECTED'; } /** * Event name for reporting that a peripheral has been intentionally disconnected. * This causes the status button in the blocks menu to indicate 'disconnected'. * @const {string} */ static get PERIPHERAL_DISCONNECTED() { return 'PERIPHERAL_DISCONNECTED'; } /** * Event name for reporting that a peripheral has encountered a request error. * This causes the peripheral connection modal to switch to an error state. * @const {string} */ static get PERIPHERAL_REQUEST_ERROR() { return 'PERIPHERAL_REQUEST_ERROR'; } /** * Event name for reporting that a peripheral connection has been lost. * This causes a 'peripheral connection lost' error alert to display. * @const {string} */ static get PERIPHERAL_CONNECTION_LOST_ERROR() { return 'PERIPHERAL_CONNECTION_LOST_ERROR'; } /** * Event name for reporting that a peripheral has not been discovered. * This causes the peripheral connection modal to show a timeout state. * @const {string} */ static get PERIPHERAL_SCAN_TIMEOUT() { return 'PERIPHERAL_SCAN_TIMEOUT'; } /** * Event name to indicate that the microphone is being used to stream audio. * @const {string} */ static get MIC_LISTENING() { return 'MIC_LISTENING'; } /** * Event name for reporting that blocksInfo was updated. * @const {string} */ static get BLOCKSINFO_UPDATE() { return 'BLOCKSINFO_UPDATE'; } /** * Event name when the runtime tick loop has been started. * @const {string} */ static get RUNTIME_STARTED() { return 'RUNTIME_STARTED'; } /** * Event name when the runtime tick loop has been stopped. * @const {string} */ static get RUNTIME_STOPPED() { return 'RUNTIME_STOPPED'; } /** * Event name when the runtime dispose has been called. * @const {string} */ static get RUNTIME_DISPOSED() { return 'RUNTIME_DISPOSED'; } /** * Event name for reporting that a block was updated and needs to be rerendered. * @const {string} */ static get BLOCKS_NEED_UPDATE() { return 'BLOCKS_NEED_UPDATE'; } /** * How rapidly we try to step threads by default, in ms. */ static get THREAD_STEP_INTERVAL() { // tw: not used, only exists for compatibility return 1000 / 60; } /** * In compatibility mode, how rapidly we try to step threads, in ms. */ static get THREAD_STEP_INTERVAL_COMPATIBILITY() { // tw: not used, only exists for compatibility return 1000 / 30; } /** * How many clones can be created at a time. * @const {number} */ static get MAX_CLONES() { // tw: clone limit is set per-runtime in runtimeOptions, this is only the initial value return 300; } // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // Helper function for initializing the addCloudVariable function _initializeAddCloudVariable(newCloudDataManager) { // The addCloudVariable function return () => { const hadCloudVarsBefore = this.hasCloudData(); newCloudDataManager.addCloudVariable(); if (!hadCloudVarsBefore && this.hasCloudData()) { this.emit(Runtime.HAS_CLOUD_DATA_UPDATE, true); } }; } // Helper function for initializing the removeCloudVariable function _initializeRemoveCloudVariable(newCloudDataManager) { return () => { const hadCloudVarsBefore = this.hasCloudData(); newCloudDataManager.removeCloudVariable(); if (hadCloudVarsBefore && !this.hasCloudData()) { this.emit(Runtime.HAS_CLOUD_DATA_UPDATE, false); } }; } /** * Register default block packages with this runtime. * @todo Prefix opcodes with package name. * @private */ _registerBlockPackages() { for (const packageName in defaultBlockPackages) { if (defaultBlockPackages.hasOwnProperty(packageName)) { // @todo pass a different runtime depending on package privilege? const packageObject = new defaultBlockPackages[packageName](this); // Collect primitives from package. if (packageObject.getPrimitives) { const packagePrimitives = packageObject.getPrimitives(); for (const op in packagePrimitives) { if (packagePrimitives.hasOwnProperty(op)) { this._primitives[op] = packagePrimitives[op].bind(packageObject); } } } // Collect hat metadata from package. if (packageObject.getHats) { const packageHats = packageObject.getHats(); for (const hatName in packageHats) { if (packageHats.hasOwnProperty(hatName)) { this._hats[hatName] = packageHats[hatName]; } } } // Collect monitored from package. if (packageObject.getMonitored) { this.monitorBlockInfo = Object.assign({}, this.monitorBlockInfo, packageObject.getMonitored()); } this.compilerRegisterExtension(packageName, packageObject); } } } compilerRegisterExtension(name, extensionObject) { this["ext_".concat(name)] = extensionObject; } getMonitorState() { return this._monitorState; } /** * Generate an extension-specific menu ID. * @param {string} menuName - the name of the menu. * @param {string} extensionId - the ID of the extension hosting the menu. * @returns {string} - the constructed ID. * @private */ _makeExtensionMenuId(menuName, extensionId) { return "".concat(extensionId, "_menu_").concat(xmlEscape(menuName)); } /** * Create a context ("args") object for use with `formatMessage` on messages which might be target-specific. * @param {Target} [target] - the target to use as context. If a target is not provided, default to the current * editing target or the stage. */ makeMessageContextForTarget(target) { const context = {}; target = target || this.getEditingTarget() || this.getTargetForStage(); if (target) { context.targetType = target.isStage ? TargetType.STAGE : TargetType.SPRITE; } } /** * Register the primitives provided by an extension. * @param {ExtensionMetadata} extensionInfo - information about the extension (id, blocks, etc.) * @private */ _registerExtensionPrimitives(extensionInfo) { const categoryInfo = { id: extensionInfo.id, name: maybeFormatMessage(extensionInfo.name), showStatusButton: extensionInfo.showStatusButton, blockIconURI: extensionInfo.blockIconURI, menuIconURI: extensionInfo.menuIconURI }; if (extensionInfo.color1) { categoryInfo.color1 = extensionInfo.color1; categoryInfo.color2 = extensionInfo.color2; categoryInfo.color3 = extensionInfo.color3; } else { categoryInfo.color1 = defaultExtensionColors[0]; categoryInfo.color2 = defaultExtensionColors[1]; categoryInfo.color3 = defaultExtensionColors[2]; } this._blockInfo.push(categoryInfo); this._fillExtensionCategory(categoryInfo, extensionInfo); for (const fieldTypeName in categoryInfo.customFieldTypes) { if (extensionInfo.customFieldTypes.hasOwnProperty(fieldTypeName)) { const fieldTypeInfo = categoryInfo.customFieldTypes[fieldTypeName]; // Emit events for custom field types from extension this.emit(Runtime.EXTENSION_FIELD_ADDED, { name: "field_".concat(fieldTypeInfo.extendedName), implementation: fieldTypeInfo.fieldImplementation }); } } this.emit(Runtime.EXTENSION_ADDED, categoryInfo); } /** * Reregister the primitives for an extension * @param {ExtensionMetadata} extensionInfo - new info (results of running getInfo) for an extension * @private */ _refreshExtensionPrimitives(extensionInfo) { const categoryInfo = this._blockInfo.find(info => info.id === extensionInfo.id); if (categoryInfo) { categoryInfo.name = maybeFormatMessage(extensionInfo.name); this._fillExtensionCategory(categoryInfo, extensionInfo); this.emit(Runtime.BLOCKSINFO_UPDATE, categoryInfo); } } /** * Read extension information, convert menus, blocks and custom field types * and store the results in the provided category object. * @param {CategoryInfo} categoryInfo - the category to be filled * @param {ExtensionMetadata} extensionInfo - the extension metadata to read * @private */ _fillExtensionCategory(categoryInfo, extensionInfo) { categoryInfo.blocks = []; categoryInfo.customFieldTypes = {}; categoryInfo.menus = []; categoryInfo.menuInfo = {}; for (const menuName in extensionInfo.menus) { if (extensionInfo.menus.hasOwnProperty(menuName)) { const menuInfo = extensionInfo.menus[menuName]; const convertedMenu = this._buildMenuForScratchBlocks(menuName, menuInfo, categoryInfo); categoryInfo.menus.push(convertedMenu); categoryInfo.menuInfo[menuName] = menuInfo; } } for (const fieldTypeName in extensionInfo.customFieldTypes) { if (extensionInfo.customFieldTypes.hasOwnProperty(fieldTypeName)) { const fieldType = extensionInfo.customFieldTypes[fieldTypeName]; const fieldTypeInfo = this._buildCustomFieldInfo(fieldTypeName, fieldType, extensionInfo.id, categoryInfo); categoryInfo.customFieldTypes[fieldTypeName] = fieldTypeInfo; } } if (extensionInfo.docsURI) { try { const url = new URL(extensionInfo.docsURI); if (url.protocol !== 'http:' && url.protocol !== 'https:') { throw new Error('invalid protocol'); } const xml = '"); const block = { info: {}, xml }; categoryInfo.blocks.push(block); } catch (e) { log.warn('cannot create docsURI button', e); } } for (const blockInfo of extensionInfo.blocks) { try { const convertedBlock = this._convertForScratchBlocks(blockInfo, categoryInfo); categoryInfo.blocks.push(convertedBlock); if (convertedBlock.json) { const opcode = convertedBlock.json.type; if (blockInfo.blockType !== BlockType.EVENT) { this._primitives[opcode] = convertedBlock.info.func; } if (blockInfo.blockType === BlockType.EVENT || blockInfo.blockType === BlockType.HAT) { this._hats[opcode] = { edgeActivated: blockInfo.isEdgeActivated, restartExistingThreads: blockInfo.shouldRestartExistingThreads }; } } } catch (e) { log.error('Error parsing block: ', { block: blockInfo, error: e }); } } } /** * Convert the given extension menu items into the scratch-blocks style of list of pairs. * If the menu is dynamic (e.g. the passed in argument is a function), return the input unmodified. * @param {object} menuItems - an array of menu items or a function to retrieve such an array * @returns {object} - an array of 2 element arrays or the original input function * @private */ _convertMenuItems(menuItems) { if (typeof menuItems !== 'function') { const extensionMessageContext = this.makeMessageContextForTarget(); return menuItems.map(item => { const formattedItem = maybeFormatMessage(item, extensionMessageContext); switch (typeof formattedItem) { case 'string': return [formattedItem, formattedItem]; case 'object': return [maybeFormatMessage(item.text, extensionMessageContext), item.value]; default: throw new Error("Can't interpret menu item: ".concat(JSON.stringify(item))); } }); } return menuItems; } /** * Build the scratch-blocks JSON for a menu. Note that scratch-blocks treats menus as a special kind of block. * @param {string} menuName - the name of the menu * @param {object} menuInfo - a description of this menu and its items * @property {*} items - an array of menu items or a function to retrieve such an array * @property {boolean} [acceptReporters] - if true, allow dropping reporters onto this menu * @param {CategoryInfo} categoryInfo - the category for this block * @returns {object} - a JSON-esque object ready for scratch-blocks' consumption * @private */ _buildMenuForScratchBlocks(menuName, menuInfo, categoryInfo) { const menuId = this._makeExtensionMenuId(menuName, categoryInfo.id); const menuItems = this._convertMenuItems(menuInfo.items); return { json: { message0: '%1', type: menuId, inputsInline: true, output: 'String', colour: categoryInfo.color1, colourSecondary: categoryInfo.color2, colourTertiary: categoryInfo.color3, outputShape: menuInfo.acceptReporters ? ScratchBlocksConstants.OUTPUT_SHAPE_ROUND : ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE, args0: [{ type: 'field_dropdown', name: menuName, options: menuItems }] } }; } _buildCustomFieldInfo(fieldName, fieldInfo, extensionId, categoryInfo) { const extendedName = "".concat(extensionId, "_").concat(fieldName); return { fieldName: fieldName, extendedName: extendedName, argumentTypeInfo: { shadow: { type: extendedName, fieldName: "field_".concat(extendedName) } }, scratchBlocksDefinition: this._buildCustomFieldTypeForScratchBlocks(extendedName, fieldInfo.output, fieldInfo.outputShape, categoryInfo), fieldImplementation: fieldInfo.implementation }; } /** * Build the scratch-blocks JSON needed for a fieldType. * Custom field types need to be namespaced to the extension so that extensions can't interfere with each other * @param {string} fieldName - The name of the field * @param {string} output - The output of the field * @param {number} outputShape - Shape of the field (from ScratchBlocksConstants) * @param {object} categoryInfo - The category the field belongs to (Used to set its colors) * @returns {object} - Object to be inserted into scratch-blocks */ _buildCustomFieldTypeForScratchBlocks(fieldName, output, outputShape, categoryInfo) { return { json: { type: fieldName, message0: '%1', inputsInline: true, output: output, colour: categoryInfo.color1, colourSecondary: categoryInfo.color2, colourTertiary: categoryInfo.color3, outputShape: outputShape, args0: [{ name: "field_".concat(fieldName), type: "field_".concat(fieldName) }] } }; } /** * Convert ExtensionBlockMetadata into data ready for scratch-blocks. * @param {ExtensionBlockMetadata} blockInfo - the block info to convert * @param {CategoryInfo} categoryInfo - the category for this block * @returns {ConvertedBlockInfo} - the converted & original block information * @private */ _convertForScratchBlocks(blockInfo, categoryInfo) { if (blockInfo === '---') { return this._convertSeparatorForScratchBlocks(blockInfo); } if (blockInfo.blockType === BlockType.BUTTON) { return this._convertButtonForScratchBlocks(blockInfo); } return this._convertBlockForScratchBlocks(blockInfo, categoryInfo); } /** * Convert ExtensionBlockMetadata into scratch-blocks JSON & XML, and generate a proxy function. * @param {ExtensionBlockMetadata} blockInfo - the block to convert * @param {CategoryInfo} categoryInfo - the category for this block * @returns {ConvertedBlockInfo} - the converted & original block information * @private */ _convertBlockForScratchBlocks(blockInfo, categoryInfo) { const extendedOpcode = "".concat(categoryInfo.id, "_").concat(blockInfo.opcode); const blockJSON = { type: extendedOpcode, inputsInline: true, category: categoryInfo.name, colour: categoryInfo.color1, colourSecondary: categoryInfo.color2, colourTertiary: categoryInfo.color3 }; const context = { // TODO: store this somewhere so that we can map args appropriately after translation. // This maps an arg name to its relative position in the original (usually English) block text. // When displaying a block in another language we'll need to run a `replace` action similar to the one // below, but each `[ARG]` will need to be replaced with the number in this map. argsMap: {}, blockJSON, categoryInfo, blockInfo, inputList: [] }; // If an icon for the extension exists, prepend it to each block, with a vertical separator. // We can overspecify an icon for each block, but if no icon exists on a block, fall back to // the category block icon. const iconURI = blockInfo.blockIconURI || categoryInfo.blockIconURI; if (iconURI) { blockJSON.extensions = ['scratch_extension']; blockJSON.message0 = '%1 %2'; const iconJSON = { type: 'field_image', src: iconURI, width: 40, height: 40 }; const separatorJSON = { type: 'field_vertical_separator' }; blockJSON.args0 = [iconJSON, separatorJSON]; } switch (blockInfo.blockType) { case BlockType.COMMAND: blockJSON.outputShape = ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE; blockJSON.previousStatement = null; // null = available connection; undefined = hat if (!blockInfo.isTerminal) { blockJSON.nextStatement = null; // null = available connection; undefined = terminal } break; case BlockType.REPORTER: blockJSON.output = 'String'; // TODO: distinguish number & string here? blockJSON.outputShape = ScratchBlocksConstants.OUTPUT_SHAPE_ROUND; break; case BlockType.BOOLEAN: blockJSON.output = 'Boolean'; blockJSON.outputShape = ScratchBlocksConstants.OUTPUT_SHAPE_HEXAGONAL; break; case BlockType.HAT: case BlockType.EVENT: if (!blockInfo.hasOwnProperty('isEdgeActivated')) { // if absent, this property defaults to true blockInfo.isEdgeActivated = true; } blockJSON.outputShape = ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE; blockJSON.nextStatement = null; // null = available connection; undefined = terminal break; case BlockType.CONDITIONAL: case BlockType.LOOP: blockInfo.branchCount = blockInfo.branchCount || 1; blockJSON.outputShape = ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE; blockJSON.previousStatement = null; // null = available connection; undefined = hat if (!blockInfo.isTerminal) { blockJSON.nextStatement = null; // null = available connection; undefined = terminal } break; } const blockText = Array.isArray(blockInfo.text) ? blockInfo.text : [blockInfo.text]; let inTextNum = 0; // text for the next block "arm" is blockText[inTextNum] let inBranchNum = 0; // how many branches have we placed into the JSON so far? let outLineNum = 0; // used for scratch-blocks `message${outLineNum}` and `args${outLineNum}` const convertPlaceholders = this._convertPlaceholders.bind(this, context); const extensionMessageContext = this.makeMessageContextForTarget(); // alternate between a block "arm" with text on it and an open slot for a substack while (inTextNum < blockText.length || inBranchNum < blockInfo.branchCount) { if (inTextNum < blockText.length) { context.outLineNum = outLineNum; const lineText = maybeFormatMessage(blockText[inTextNum], extensionMessageContext); const convertedText = lineText.replace(/\[(.+?)]/g, convertPlaceholders); if (blockJSON["message".concat(outLineNum)]) { blockJSON["message".concat(outLineNum)] += convertedText; } else { blockJSON["message".concat(outLineNum)] = convertedText; } ++inTextNum; ++outLineNum; } if (inBranchNum < blockInfo.branchCount) { blockJSON["message".concat(outLineNum)] = '%1'; blockJSON["args".concat(outLineNum)] = [{ type: 'input_statement', name: "SUBSTACK".concat(inBranchNum > 0 ? inBranchNum + 1 : '') }]; ++inBranchNum; ++outLineNum; } } if (blockInfo.blockType === BlockType.REPORTER) { if (!blockInfo.disableMonitor && context.inputList.length === 0) { blockJSON.checkboxInFlyout = true; } } else if (blockInfo.blockType === BlockType.LOOP) { // Add icon to the bottom right of a loop block blockJSON["lastDummyAlign".concat(outLineNum)] = 'RIGHT'; blockJSON["message".concat(outLineNum)] = '%1'; blockJSON["args".concat(outLineNum)] = [{ type: 'field_image', src: './static/blocks-media/repeat.svg', // TODO: use a constant or make this configurable? width: 24, height: 24, alt: '*', // TODO remove this since we don't use collapsed blocks in scratch flip_rtl: true }]; ++outLineNum; } const mutation = blockInfo.isDynamic ? "") : ''; const inputs = context.inputList.join(''); const blockXML = "").concat(mutation).concat(inputs, ""); return { info: context.blockInfo, json: context.blockJSON, xml: blockXML }; } /** * Generate a separator between blocks categories or sub-categories. * @param {ExtensionBlockMetadata} blockInfo - the block to convert * @param {CategoryInfo} categoryInfo - the category for this block * @returns {ConvertedBlockInfo} - the converted & original block information * @private */ _convertSeparatorForScratchBlocks(blockInfo) { return { info: blockInfo, xml: '' }; } /** * Convert a button for scratch-blocks. A button has no opcode but specifies a callback name in the `func` field. * @param {ExtensionBlockMetadata} buttonInfo - the button to convert * @property {string} func - the callback name * @param {CategoryInfo} categoryInfo - the category for this button * @returns {ConvertedBlockInfo} - the converted & original button information * @private */ _convertButtonForScratchBlocks(buttonInfo) { // for now we only support these pre-defined callbacks handled in scratch-blocks const supportedCallbackKeys = ['MAKE_A_LIST', 'MAKE_A_PROCEDURE', 'MAKE_A_VARIABLE']; if (supportedCallbackKeys.indexOf(buttonInfo.func) < 0) { log.error("Custom button callbacks not supported yet: ".concat(buttonInfo.func)); } const extensionMessageContext = this.makeMessageContextForTarget(); const buttonText = maybeFormatMessage(buttonInfo.text, extensionMessageContext); return { info: buttonInfo, xml: "") }; } /** * Helper for _convertPlaceholdes which handles inline images which are a specialized case of block "arguments". * @param {object} argInfo Metadata about the inline image as specified by the extension * @return {object} JSON blob for a scratch-blocks image field. * @private */ _constructInlineImageJson(argInfo) { if (!argInfo.dataURI) { log.warn('Missing data URI in extension block with argument type IMAGE'); } return { type: 'field_image', src: argInfo.dataURI || '', // TODO these probably shouldn't be hardcoded...? width: 24, height: 24, // Whether or not the inline image should be flipped horizontally // in RTL languages. Defaults to false, indicating that the // image will not be flipped. flip_rtl: argInfo.flipRTL || false }; } /** * Helper for _convertForScratchBlocks which handles linearization of argument placeholders. Called as a callback * from string#replace. In addition to the return value the JSON and XML items in the context will be filled. * @param {object} context - information shared with _convertForScratchBlocks about the block, etc. * @param {string} match - the overall string matched by the placeholder regex, including brackets: '[FOO]'. * @param {string} placeholder - the name of the placeholder being matched: 'FOO'. * @return {string} scratch-blocks placeholder for the argument: '%1'. * @private */ _convertPlaceholders(context, match, placeholder) { // Sanitize the placeholder to ensure valid XML placeholder = placeholder.replace(/[<"&]/, '_'); // Determine whether the argument type is one of the known standard field types const argInfo = context.blockInfo.arguments[placeholder] || {}; let argTypeInfo = ArgumentTypeMap[argInfo.type] || {}; // Field type not a standard field type, see if extension has registered custom field type if (!ArgumentTypeMap[argInfo.type] && context.categoryInfo.customFieldTypes[argInfo.type]) { argTypeInfo = context.categoryInfo.customFieldTypes[argInfo.type].argumentTypeInfo; } // Start to construct the scratch-blocks style JSON defining how the block should be // laid out let argJSON; // Most field types are inputs (slots on the block that can have other blocks plugged into them) // check if this is not one of those cases. E.g. an inline image on a block. if (argTypeInfo.fieldType === 'field_image') { argJSON = this._constructInlineImageJson(argInfo); } else { // Construct input value // Layout a block argument (e.g. an input slot on the block) argJSON = { type: 'input_value', name: placeholder }; const defaultValue = typeof argInfo.defaultValue === 'undefined' ? '' : xmlEscape(maybeFormatMessage(argInfo.defaultValue, this.makeMessageContextForTarget()).toString()); if (argTypeInfo.check) { // Right now the only type of 'check' we have specifies that the // input slot on the block accepts Boolean reporters, so it should be // shaped like a hexagon argJSON.check = argTypeInfo.check; } let valueName; let shadowType; let fieldName; if (argInfo.menu) { const menuInfo = context.categoryInfo.menuInfo[argInfo.menu]; if (menuInfo.acceptReporters) { valueName = placeholder; shadowType = this._makeExtensionMenuId(argInfo.menu, context.categoryInfo.id); fieldName = argInfo.menu; } else { argJSON.type = 'field_dropdown'; argJSON.options = this._convertMenuItems(menuInfo.items); valueName = null; shadowType = null; fieldName = placeholder; } } else { valueName = placeholder; shadowType = argTypeInfo.shadow && argTypeInfo.shadow.type || null; fieldName = argTypeInfo.shadow && argTypeInfo.shadow.fieldName || null; } // is the ScratchBlocks name for a block input. if (valueName) { context.inputList.push("")); } // The is a placeholder for a reporter and is visible when there's no reporter in this input. // Boolean inputs don't need to specify a shadow in the XML. if (shadowType) { context.inputList.push("")); } // A displays a dynamic value: a user-editable text field, a drop-down menu, etc. // Leave out the field if defaultValue or fieldName are not specified if (defaultValue && fieldName) { context.inputList.push("").concat(defaultValue, "")); } if (shadowType) { context.inputList.push(''); } if (valueName) { context.inputList.push(''); } } const argsName = "args".concat(context.outLineNum); const blockArgs = context.blockJSON[argsName] = context.blockJSON[argsName] || []; if (argJSON) blockArgs.push(argJSON); const argNum = blockArgs.length; context.argsMap[placeholder] = argNum; return "%".concat(argNum); } /** * @returns {Array.} scratch-blocks XML for each category of extension blocks, in category order. * @param {?Target} [target] - the active editing target (optional) * @property {string} id - the category / extension ID * @property {string} xml - the XML text for this category, starting with `` and ending with `` */ getBlocksXML(target) { return this._blockInfo.map(categoryInfo => { const { name, color1, color2 } = categoryInfo; // Filter out blocks that aren't supposed to be shown on this target, as determined by the block info's // `hideFromPalette` and `filter` properties. const paletteBlocks = categoryInfo.blocks.filter(block => { let blockFilterIncludesTarget = true; // If an editing target is not passed, include all blocks // If the block info doesn't include a `filter` property, always include it if (target && block.info.filter) { blockFilterIncludesTarget = block.info.filter.includes(target.isStage ? TargetType.STAGE : TargetType.SPRITE); } // If the block info's `hideFromPalette` is true, then filter out this block return blockFilterIncludesTarget && !block.info.hideFromPalette; }); const colorXML = "colour=\"".concat(color1, "\" secondaryColour=\"").concat(color2, "\""); // Use a menu icon if there is one. Otherwise, use the block icon. If there's no icon, // the category menu will show its default colored circle. let menuIconURI = ''; if (categoryInfo.menuIconURI) { menuIconURI = categoryInfo.menuIconURI; } else if (categoryInfo.blockIconURI) { menuIconURI = categoryInfo.blockIconURI; } const menuIconXML = menuIconURI ? "iconURI=\"".concat(menuIconURI, "\"") : ''; let statusButtonXML = ''; if (categoryInfo.showStatusButton) { statusButtonXML = 'showStatusButton="true"'; } return { id: categoryInfo.id, xml: "").concat(paletteBlocks.map(block => block.xml).join(''), "") }; }); } /** * @returns {Array.} - an array containing the scratch-blocks JSON information for each dynamic block. */ getBlocksJSON() { return this._blockInfo.reduce((result, categoryInfo) => result.concat(categoryInfo.blocks.map(blockInfo => blockInfo.json)), []); } /** * Get a scratch link socket. * @param {string} type Either BLE or BT * @returns {ScratchLinkSocket} The scratch link socket. */ getScratchLinkSocket(type) { const factory = this._linkSocketFactory || this._defaultScratchLinkSocketFactory; return factory(type); } /** * Configure how ScratchLink sockets are created. Factory must consume a "type" parameter * either BT or BLE. * @param {Function} factory The new factory for creating ScratchLink sockets. */ configureScratchLinkSocketFactory(factory) { this._linkSocketFactory = factory; } /** * The default scratch link socket creator, using websockets to the installed device manager. * @param {string} type Either BLE or BT * @returns {ScratchLinkSocket} The new scratch link socket (a WebSocket object) */ _defaultScratchLinkSocketFactory(type) { return new ScratchLinkWebSocket(type); } /** * Register an extension that communications with a hardware peripheral by id, * to have access to it and its peripheral functions in the future. * @param {string} extensionId - the id of the extension. * @param {object} extension - the extension to register. */ registerPeripheralExtension(extensionId, extension) { this.peripheralExtensions[extensionId] = extension; } /** * Tell the specified extension to scan for a peripheral. * @param {string} extensionId - the id of the extension. */ scanForPeripheral(extensionId) { if (this.peripheralExtensions[extensionId]) { this.peripheralExtensions[extensionId].scan(); } } /** * Connect to the extension's specified peripheral. * @param {string} extensionId - the id of the extension. * @param {number} peripheralId - the id of the peripheral. */ connectPeripheral(extensionId, peripheralId) { if (this.peripheralExtensions[extensionId]) { this.peripheralExtensions[extensionId].connect(peripheralId); } } /** * Disconnect from the extension's connected peripheral. * @param {string} extensionId - the id of the extension. */ disconnectPeripheral(extensionId) { if (this.peripheralExtensions[extensionId]) { this.peripheralExtensions[extensionId].disconnect(); } } /** * Returns whether the extension has a currently connected peripheral. * @param {string} extensionId - the id of the extension. * @return {boolean} - whether the extension has a connected peripheral. */ getPeripheralIsConnected(extensionId) { let isConnected = false; if (this.peripheralExtensions[extensionId]) { isConnected = this.peripheralExtensions[extensionId].isConnected(); } return isConnected; } /** * Emit an event to indicate that the microphone is being used to stream audio. * @param {boolean} listening - true if the microphone is currently listening. */ emitMicListening(listening) { this.emit(Runtime.MIC_LISTENING, listening); } /** * Retrieve the function associated with the given opcode. * @param {!string} opcode The opcode to look up. * @return {Function} The function which implements the opcode. */ getOpcodeFunction(opcode) { return this._primitives[opcode]; } /** * Return whether an opcode represents a hat block. * @param {!string} opcode The opcode to look up. * @return {boolean} True if the op is known to be a hat. */ getIsHat(opcode) { return this._hats.hasOwnProperty(opcode); } /** * Return whether an opcode represents an edge-activated hat block. * @param {!string} opcode The opcode to look up. * @return {boolean} True if the op is known to be a edge-activated hat. */ getIsEdgeActivatedHat(opcode) { return this._hats.hasOwnProperty(opcode) && this._hats[opcode].edgeActivated; } /** * Attach the audio engine * @param {!AudioEngine} audioEngine The audio engine to attach */ attachAudioEngine(audioEngine) { this.audioEngine = audioEngine; } /** * Attach the renderer * @param {!RenderWebGL} renderer The renderer to attach */ attachRenderer(renderer) { this.renderer = renderer; this.renderer.setLayerGroupOrdering(StageLayering.LAYER_GROUPS); this.renderer.offscreenTouching = !this.runtimeOptions.fencing; } /** * Set the bitmap adapter for the VM/runtime, which converts scratch 2 * bitmaps to scratch 3 bitmaps. (Scratch 3 bitmaps are all bitmap resolution 2) * @param {!function} bitmapAdapter The adapter to attach */ attachV2BitmapAdapter(bitmapAdapter) { this.v2BitmapAdapter = bitmapAdapter; } /** * Attach the storage module * @param {!ScratchStorage} storage The storage module to attach */ attachStorage(storage) { this.storage = storage; if (this.isPackaged) { // In packaged runtime mode, generating real asset IDs is a waste of time. // We do still want to preserve every asset having a unique ID. const originalCreateAsset = storage.createAsset; let assetIdCounter = 0; // eslint-disable-next-line no-unused-vars storage.createAsset = function packagedCreateAsset(assetType, dataFormat, data, assetId, generateId) { if (!assetId) { assetId = (++assetIdCounter).toString(); } return originalCreateAsset.call(this, assetType, dataFormat, data, assetId, // Never generate real asset ID false); }; } } // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- /** * Create a thread and push it to the list of threads. * @param {!string} id ID of block that starts the stack. * @param {!Target} target Target to run thread on. * @param {?object} opts optional arguments * @param {?boolean} opts.stackClick true if the script was activated by clicking on the stack * @param {?boolean} opts.updateMonitor true if the script should update a monitor value * @return {!Thread} The newly created thread. */ _pushThread(id, target, opts) { const thread = new Thread(id); thread.target = target; thread.stackClick = Boolean(opts && opts.stackClick); thread.updateMonitor = Boolean(opts && opts.updateMonitor); thread.blockContainer = thread.updateMonitor ? this.monitorBlocks : target.blocks; thread.pushStack(id); this.threads.push(thread); if (!thread.stackClick && !thread.updateMonitor) { this.threadMap.set(thread.getId(), thread); } // tw: compile new threads. Do not attempt to compile monitor threads. if (!(opts && opts.updateMonitor) && this.compilerOptions.enabled) { thread.tryCompile(); } return thread; } /** * Stop a thread: stop running it immediately, and remove it from the thread list later. * @param {!Thread} thread Thread object to remove from actives */ _stopThread(thread) { // Mark the thread for later removal thread.isKilled = true; // Inform sequencer to stop executing that thread. this.sequencer.retireThread(thread); } /** * Restart a thread in place, maintaining its position in the list of threads. * This is used by `startHats` to and is necessary to ensure 2.0-like execution order. * Test project: https://scratch.mit.edu/projects/130183108/ * @param {!Thread} thread Thread object to restart. * @return {Thread} The restarted thread. */ _restartThread(thread) { const newThread = new Thread(thread.topBlock); newThread.target = thread.target; newThread.stackClick = thread.stackClick; newThread.updateMonitor = thread.updateMonitor; newThread.blockContainer = thread.blockContainer; newThread.pushStack(thread.topBlock); // tw: when a thread is restarted, we have to check whether the previous script was attempted to be compiled. if (thread.triedToCompile && this.compilerOptions.enabled) { newThread.tryCompile(); } if (!newThread.stackClick && !newThread.updateMonitor) { this.threadMap.set(newThread.getId(), newThread); } const i = this.threads.indexOf(thread); if (i > -1) { this.threads[i] = newThread; return newThread; } this.threads.push(thread); return thread; } emitCompileError(target, error) { this.emit(Runtime.COMPILE_ERROR, target, error); } /** * Return whether a thread is currently active/running. * @param {?Thread} thread Thread object to check. * @return {boolean} True if the thread is active/running. */ isActiveThread(thread) { return thread.stack.length > 0 && thread.status !== Thread.STATUS_DONE && this.threads.indexOf(thread) > -1; } /** * Return whether a thread is waiting for more information or done. * @param {?Thread} thread Thread object to check. * @return {boolean} True if the thread is waiting */ isWaitingThread(thread) { return thread.status === Thread.STATUS_PROMISE_WAIT || thread.status === Thread.STATUS_YIELD_TICK || !this.isActiveThread(thread); } /** * Toggle a script. * @param {!string} topBlockId ID of block that starts the script. * @param {?object} opts optional arguments to toggle script * @param {?string} opts.target target ID for target to run script on. If not supplied, uses editing target. * @param {?boolean} opts.stackClick true if the user activated the stack by clicking, false if not. This * determines whether we show a visual report when turning on the script. */ toggleScript(topBlockId, opts) { opts = Object.assign({ target: this._editingTarget, stackClick: false }, opts); // Remove any existing thread. for (let i = 0; i < this.threads.length; i++) { // Toggling a script that's already running turns it off if (this.threads[i].topBlock === topBlockId && this.threads[i].status !== Thread.STATUS_DONE) { const blockContainer = opts.target.blocks; const opcode = blockContainer.getOpcode(blockContainer.getBlock(topBlockId)); if (this.getIsEdgeActivatedHat(opcode) && this.threads[i].stackClick !== opts.stackClick) { // Allow edge activated hat thread stack click to coexist with // edge activated hat thread that runs every frame continue; } this._stopThread(this.threads[i]); return; } } // Otherwise add it. this._pushThread(topBlockId, opts.target, opts); } /** * Enqueue a script that when finished will update the monitor for the block. * @param {!string} topBlockId ID of block that starts the script. * @param {?Target} optTarget target Target to run script on. If not supplied, uses editing target. */ addMonitorScript(topBlockId, optTarget) { if (!optTarget) optTarget = this._editingTarget; for (let i = 0; i < this.threads.length; i++) { // Don't re-add the script if it's already running if (this.threads[i].topBlock === topBlockId && this.threads[i].status !== Thread.STATUS_DONE && this.threads[i].updateMonitor) { return; } } // Otherwise add it. this._pushThread(topBlockId, optTarget, { updateMonitor: true }); } /** * Run a function `f` for all scripts in a workspace. * `f` will be called with two parameters: * - the top block ID of the script. * - the target that owns the script. * @param {!Function} f Function to call for each script. * @param {Target=} optTarget Optionally, a target to restrict to. */ allScriptsDo(f, optTarget) { let targets = this.executableTargets; if (optTarget) { targets = [optTarget]; } for (let t = targets.length - 1; t >= 0; t--) { const target = targets[t]; const scripts = target.blocks.getScripts(); for (let j = 0; j < scripts.length; j++) { const topBlockId = scripts[j]; f(topBlockId, target); } } } allScriptsByOpcodeDo(opcode, f, optTarget) { let targets = this.executableTargets; if (optTarget) { targets = [optTarget]; } for (let t = targets.length - 1; t >= 0; t--) { const target = targets[t]; const scripts = BlocksRuntimeCache.getScripts(target.blocks, opcode); for (let j = 0; j < scripts.length; j++) { f(scripts[j], target); } } } /** * Start all relevant hats. * @param {!string} requestedHatOpcode Opcode of hats to start. * @param {object=} optMatchFields Optionally, fields to match on the hat. * @param {Target=} optTarget Optionally, a target to restrict to. * @return {Array.} List of threads started by this function. */ startHats(requestedHatOpcode, optMatchFields, optTarget) { if (!this._hats.hasOwnProperty(requestedHatOpcode)) { // No known hat with this opcode. return; } const instance = this; const newThreads = []; // Look up metadata for the relevant hat. const hatMeta = instance._hats[requestedHatOpcode]; for (const opts in optMatchFields) { if (!optMatchFields.hasOwnProperty(opts)) continue; optMatchFields[opts] = optMatchFields[opts].toUpperCase(); } // tw: By assuming that all new threads will not interfere with eachother, we can optimize the loops // inside the allScriptsByOpcodeDo callback below. const startingThreadListLength = this.threads.length; // Consider all scripts, looking for hats with opcode `requestedHatOpcode`. this.allScriptsByOpcodeDo(requestedHatOpcode, (script, target) => { const { blockId: topBlockId, fieldsOfInputs: hatFields } = script; // Match any requested fields. // For example: ensures that broadcasts match. // This needs to happen before the block is evaluated // (i.e., before the predicate can be run) because "broadcast and wait" // needs to have a precise collection of started threads. for (const matchField in optMatchFields) { if (hatFields[matchField].value !== optMatchFields[matchField]) { // Field mismatch. return; } } if (hatMeta.restartExistingThreads) { // If `restartExistingThreads` is true, we should stop // any existing threads starting with the top block. const existingThread = this.threadMap.get(Thread.getIdFromTargetAndBlock(target, topBlockId)); if (existingThread) { newThreads.push(this._restartThread(existingThread)); return; } } else { // If `restartExistingThreads` is false, we should // give up if any threads with the top block are running. for (let j = 0; j < startingThreadListLength; j++) { if (this.threads[j].target === target && this.threads[j].topBlock === topBlockId && // stack click threads and hat threads can coexist !this.threads[j].stackClick && this.threads[j].status !== Thread.STATUS_DONE) { // Some thread is already running. return; } } } // Start the thread with this top block. newThreads.push(this._pushThread(topBlockId, target)); }, optTarget); // For compatibility with Scratch 2, edge triggered hats need to be processed before // threads are stepped. See ScratchRuntime.as for original implementation newThreads.forEach(thread => { // tw: do not step compiled threads, the hat block can't be executed if (!thread.isCompiled) { execute(this.sequencer, thread); thread.goToNextBlock(); } }); return newThreads; } /** * Dispose all targets. Return to clean state. */ dispose() { this.stopAll(); // Deleting each target's variable's monitors. this.targets.forEach(target => { if (target.isOriginal) target.deleteMonitors(); }); this.targets.map(this.disposeTarget, this); // tw: explicitly emit a MONITORS_UPDATE instead of relying on implicit behavior of _step() const emptyMonitorState = OrderedMap({}); if (!emptyMonitorState.equals(this._monitorState)) { this._monitorState = emptyMonitorState; this.emit(Runtime.MONITORS_UPDATE, this._monitorState); } this.emit(Runtime.RUNTIME_DISPOSED); this.ioDevices.clock.resetProjectTimer(); // @todo clear out extensions? turboMode? etc. // *********** Cloud ******************* // If the runtime currently has cloud data, // emit a has cloud data update event resetting // it to false if (this.hasCloudData()) { this.emit(Runtime.HAS_CLOUD_DATA_UPDATE, false); } this.ioDevices.cloud.clear(); // Reset runtime cloud data info const newCloudDataManager = cloudDataManager(this.cloudOptions); this.hasCloudData = newCloudDataManager.hasCloudVariables; this.canAddCloudVariable = newCloudDataManager.canAddCloudVariable; this.getNumberOfCloudVariables = newCloudDataManager.getNumberOfCloudVariables; this.addCloudVariable = this._initializeAddCloudVariable(newCloudDataManager); this.removeCloudVariable = this._initializeRemoveCloudVariable(newCloudDataManager); } /** * Add a target to the runtime. This tracks the sprite pane * ordering of the target. The target still needs to be put * into the correct execution order after calling this function. * @param {Target} target target to add */ addTarget(target) { this.targets.push(target); this.executableTargets.push(target); if (target.isStage && !this._stageTarget) { this._stageTarget = target; } } /** * Move a target in the execution order by a relative amount. * * A positve number will make the target execute earlier. A negative number * will make the target execute later in the order. * * @param {Target} executableTarget target to move * @param {number} delta number of positions to move target by * @returns {number} new position in execution order */ moveExecutable(executableTarget, delta) { const oldIndex = this.executableTargets.indexOf(executableTarget); this.executableTargets.splice(oldIndex, 1); let newIndex = oldIndex + delta; if (newIndex > this.executableTargets.length) { newIndex = this.executableTargets.length; } if (newIndex <= 0) { if (this.executableTargets.length > 0 && this.executableTargets[0].isStage) { newIndex = 1; } else { newIndex = 0; } } this.executableTargets.splice(newIndex, 0, executableTarget); return newIndex; } /** * Set a target to execute at a specific position in the execution order. * * Infinity will set the target to execute first. 0 will set the target to * execute last (before the stage). * * @param {Target} executableTarget target to move * @param {number} newIndex position in execution order to place the target * @returns {number} new position in the execution order */ setExecutablePosition(executableTarget, newIndex) { const oldIndex = this.executableTargets.indexOf(executableTarget); return this.moveExecutable(executableTarget, newIndex - oldIndex); } /** * Remove a target from the execution set. * @param {Target} executableTarget target to remove */ removeExecutable(executableTarget) { const oldIndex = this.executableTargets.indexOf(executableTarget); if (oldIndex > -1) { this.executableTargets.splice(oldIndex, 1); } } /** * Dispose of a target. * @param {!Target} disposingTarget Target to dispose of. */ disposeTarget(disposingTarget) { this.targets = this.targets.filter(target => { if (disposingTarget !== target) return true; // Allow target to do dispose actions. target.dispose(); // Remove from list of targets. return false; }); if (this._stageTarget === disposingTarget) { this._stageTarget = null; } } /** * Stop any threads acting on the target. * @param {!Target} target Target to stop threads for. * @param {Thread=} optThreadException Optional thread to skip. */ stopForTarget(target, optThreadException) { // Emit stop event to allow blocks to clean up any state. this.emit(Runtime.STOP_FOR_TARGET, target, optThreadException); // Stop any threads on the target. for (let i = 0; i < this.threads.length; i++) { if (this.threads[i] === optThreadException) { continue; } if (this.threads[i].target === target) { this._stopThread(this.threads[i]); } } } /** * Start all threads that start with the green flag. */ greenFlag() { this.stopAll(); this.emit(Runtime.PROJECT_START); this.updateCurrentMSecs(); this.ioDevices.clock.resetProjectTimer(); this.targets.forEach(target => target.clearEdgeActivatedValues()); // Inform all targets of the green flag. for (let i = 0; i < this.targets.length; i++) { this.targets[i].onGreenFlag(); } this.startHats('event_whenflagclicked'); } /** * Stop "everything." */ stopAll() { // Emit stop event to allow blocks to clean up any state. this.emit(Runtime.PROJECT_STOP_ALL); // Dispose all clones. const newTargets = []; for (let i = 0; i < this.targets.length; i++) { this.targets[i].onStopAll(); if (this.targets[i].hasOwnProperty('isOriginal') && !this.targets[i].isOriginal) { this.targets[i].dispose(); } else { newTargets.push(this.targets[i]); } } this.targets = newTargets; // Dispose of the active thread. if (this.sequencer.activeThread !== null) { this._stopThread(this.sequencer.activeThread); } // Remove all remaining threads from executing in the next tick. this.threads = []; this.threadMap.clear(); } _renderInterpolatedPositions() { const frameStarted = this._lastStepTime; const now = Date.now(); const timeSinceStart = now - frameStarted; const progressInFrame = Math.min(1, Math.max(0, timeSinceStart / this.currentStepTime)); interpolate.interpolate(this, progressInFrame); if (this.renderer) { this.renderer.draw(); } } updateThreadMap() { this.threadMap.clear(); for (const thread of this.threads) { if (!thread.stackClick && !thread.updateMonitor) { this.threadMap.set(thread.getId(), thread); } } } /** * Repeatedly run `sequencer.stepThreads` and filter out * inactive threads after each iteration. */ _step() { if (this.interpolationEnabled) { interpolate.setupInitialState(this); } if (this.profiler !== null) { if (stepProfilerId === -1) { stepProfilerId = this.profiler.idByName('Runtime._step'); } this.profiler.start(stepProfilerId); } // Clean up threads that were told to stop during or since the last step this.threads = this.threads.filter(thread => !thread.isKilled); this.updateThreadMap(); // Find all edge-activated hats, and add them to threads to be evaluated. for (const hatType in this._hats) { if (!this._hats.hasOwnProperty(hatType)) continue; const hat = this._hats[hatType]; if (hat.edgeActivated) { this.startHats(hatType); } } this.redrawRequested = false; this._pushMonitors(); if (this.profiler !== null) { if (stepThreadsProfilerId === -1) { stepThreadsProfilerId = this.profiler.idByName('Sequencer.stepThreads'); } this.profiler.start(stepThreadsProfilerId); } const doneThreads = this.sequencer.stepThreads(); if (this.profiler !== null) { this.profiler.stop(); } this._updateGlows(doneThreads); // Add done threads so that even if a thread finishes within 1 frame, the green // flag will still indicate that a script ran. this._emitProjectRunStatus(this.threads.length + doneThreads.length - this._getMonitorThreadCount([...this.threads, ...doneThreads])); // Store threads that completed this iteration for testing and other // internal purposes. this._lastStepDoneThreads = doneThreads; if (this.renderer) { // @todo: Only render when this.redrawRequested or clones rendered. if (this.profiler !== null) { if (rendererDrawProfilerId === -1) { rendererDrawProfilerId = this.profiler.idByName('RenderWebGL.draw'); } this.profiler.start(rendererDrawProfilerId); } // tw: do not draw if document is hidden or a rAF loop is running // Checking for the animation frame loop is more reliable than using // interpolationEnabled in some edge cases if (!document.hidden && !this.frameLoop._interpolationAnimation) { this.renderer.draw(); } if (this.profiler !== null) { this.profiler.stop(); } } if (this._refreshTargets) { this.emit(Runtime.TARGETS_UPDATE, false /* Don't emit project changed */ ); this._refreshTargets = false; } if (!this._prevMonitorState.equals(this._monitorState)) { this.emit(Runtime.MONITORS_UPDATE, this._monitorState); this._prevMonitorState = this._monitorState; } if (this.profiler !== null) { this.profiler.stop(); this.profiler.reportFrames(); } if (this.interpolationEnabled) { this._lastStepTime = Date.now(); } } /** * Get the number of threads in the given array that are monitor threads (threads * that update monitor values, and don't count as running a script). * @param {!Array.} threads The set of threads to look through. * @return {number} The number of monitor threads in threads. */ _getMonitorThreadCount(threads) { let count = 0; threads.forEach(thread => { if (thread.updateMonitor) count++; }); return count; } /** * Queue monitor blocks to sequencer to be run. */ _pushMonitors() { this.monitorBlocks.runAllMonitored(this); } /** * Set the current editing target known by the runtime. * @param {!Target} editingTarget New editing target. */ setEditingTarget(editingTarget) { const oldEditingTarget = this._editingTarget; this._editingTarget = editingTarget; // Script glows must be cleared. this._scriptGlowsPreviousFrame = []; this._updateGlows(); if (oldEditingTarget !== this._editingTarget) { this.requestToolboxExtensionsUpdate(); } } /** * Set whether we are in 30 TPS compatibility mode. * @param {boolean} compatibilityModeOn True iff in compatibility mode. */ setCompatibilityMode(compatibilityModeOn) { // tw: "compatibility mode" is replaced with a generic framerate setter, // but this method is kept for compatibility if (compatibilityModeOn) { this.setFramerate(30); } else { this.setFramerate(60); } } /** * tw: Change runtime target frames per second * @param {number} framerate Target frames per second */ setFramerate(framerate) { // Setting framerate to anything greater than this is unnecessary and can break the sequencer // Additionally, the JS spec says intervals can't run more than once every 4ms (250/s) anyways if (framerate > 250) framerate = 250; // Convert negative framerates to 1FPS // Note that 0 is a special value which means "matching device screen refresh rate" if (framerate < 0) framerate = 1; this.frameLoop.setFramerate(framerate); this.emit(Runtime.FRAMERATE_CHANGED, framerate); } /** * tw: Enable or disable interpolation. * @param {boolean} interpolationEnabled True if interpolation should be enabled. */ setInterpolation(interpolationEnabled) { this.interpolationEnabled = interpolationEnabled; this.frameLoop.setInterpolation(this.interpolationEnabled); this.emit(Runtime.INTERPOLATION_CHANGED, interpolationEnabled); } /** * tw: Update runtime options * @param {*} runtimeOptions New options */ setRuntimeOptions(runtimeOptions) { this.runtimeOptions = Object.assign({}, this.runtimeOptions, runtimeOptions); this.emit(Runtime.RUNTIME_OPTIONS_CHANGED, this.runtimeOptions); if (this.renderer) { this.renderer.offscreenTouching = !this.runtimeOptions.fencing; } } /** * tw: Update compiler options * @param {*} compilerOptions New options */ setCompilerOptions(compilerOptions) { this.compilerOptions = Object.assign({}, this.compilerOptions, compilerOptions); this.resetAllCaches(); this.emit(Runtime.COMPILER_OPTIONS_CHANGED, this.compilerOptions); } /** * Change width and height of stage. This will also inform the renderer of the new stage size. * @param {number} width New stage width * @param {number} height New stage height */ setStageSize(width, height) { width = Math.round(Math.max(1, width)); height = Math.round(Math.max(1, height)); if (this.stageWidth !== width || this.stageHeight !== height) { const deltaX = width - this.stageWidth; const deltaY = height - this.stageHeight; // Preserve monitor location relative to the center of the stage if (this._monitorState.size > 0) { const offsetX = deltaX / 2; const offsetY = deltaY / 2; for (const monitor of this._monitorState.valueSeq()) { const newMonitor = monitor.set('x', monitor.get('x') + offsetX).set('y', monitor.get('y') + offsetY); this.requestUpdateMonitor(newMonitor); } this.emit(Runtime.MONITORS_UPDATE, this._monitorState); } this.stageWidth = width; this.stageHeight = height; if (this.renderer) { this.renderer.setStageSize(-width / 2, width / 2, -height / 2, height / 2); } } this.emit(Runtime.STAGE_SIZE_CHANGED, width, height); } setInEditor(inEditor) {// no-op } /** * TW: Enable "packaged runtime" mode. This is a one-way operation. */ convertToPackagedRuntime() { if (this.storage) { throw new Error('convertToPackagedRuntime must be called before attachStorage'); } this.isPackaged = true; } /** * tw: Reset the cache of all block containers. */ resetAllCaches() { for (const target of this.targets) { if (target.isOriginal) { target.blocks.resetCache(); } } this.flyoutBlocks.resetCache(); this.monitorBlocks.resetCache(); } /** * Add an "addon block" * @param {object} options Options object * @param {string} options.procedureCode The ID of the block * @param {function} options.callback The callback, called with (args, BlockUtility) * @param {string[]} options.arguments Names of the arguments accepted * @param {string} options.color Primary color * @param {string} options.secondaryColor Secondary color */ addAddonBlock(options) { const procedureCode = options.procedureCode; const names = options.arguments; const ids = options.arguments.map((_, i) => "arg".concat(i)); const defaults = options.arguments.map(() => ''); this.addonBlocks[procedureCode] = _objectSpread({ namesIdsDefaults: [names, ids, defaults] }, options); const ID = 'a-b'; let blockInfo = this._blockInfo.find(i => i.id === ID); if (!blockInfo) { blockInfo = { id: ID, name: 'Addons', color1: options.color, color2: options.secondaryColor, color3: options.secondaryColor, blocks: [], customFieldTypes: {}, menus: [] }; this._blockInfo.unshift(blockInfo); } blockInfo.blocks.push({ info: {}, xml: '' }); this.resetAllCaches(); } getAddonBlock(procedureCode) { if (Object.prototype.hasOwnProperty.call(this.addonBlocks, procedureCode)) { return this.addonBlocks[procedureCode]; } return null; } findProjectOptionsComment() { const target = this.getTargetForStage(); const comments = target.comments; for (const comment of Object.values(comments)) { if (comment.text.includes(COMMENT_CONFIG_MAGIC)) { return comment; } } return null; } parseProjectOptions() { const comment = this.findProjectOptionsComment(); if (!comment) return; const lineWithMagic = comment.text.split('\n').find(i => i.endsWith(COMMENT_CONFIG_MAGIC)); if (!lineWithMagic) { log.warn('Config comment does not contain valid line'); return; } const jsonText = lineWithMagic.substr(0, lineWithMagic.length - COMMENT_CONFIG_MAGIC.length); let parsed; try { parsed = ExtendedJSON.parse(jsonText); if (!parsed || typeof parsed !== 'object') { throw new Error('Invalid object'); } } catch (e) { log.warn('Config comment has invalid JSON', e); return; } if (typeof parsed.framerate === 'number') { this.setFramerate(parsed.framerate); } if (parsed.turbo) { this.turboMode = true; this.emit(Runtime.TURBO_MODE_ON); } if (parsed.interpolation) { this.setInterpolation(true); } if (parsed.runtimeOptions) { this.setRuntimeOptions(parsed.runtimeOptions); } if (parsed.hq && this.renderer) { this.renderer.setUseHighQualityRender(true); } const storedWidth = +parsed.width || this.stageWidth; const storedHeight = +parsed.height || this.stageHeight; if (storedWidth !== this.stageWidth || storedHeight !== this.stageHeight) { this.setStageSize(storedWidth, storedHeight); } } _generateAllProjectOptions() { return { framerate: this.frameLoop.framerate, runtimeOptions: this.runtimeOptions, interpolation: this.interpolationEnabled, turbo: this.turboMode, hq: this.renderer ? this.renderer.useHighQualityRender : false, width: this.stageWidth, height: this.stageHeight }; } generateDifferingProjectOptions() { const difference = (oldObject, newObject) => { const result = {}; for (const key of Object.keys(newObject)) { const newValue = newObject[key]; const oldValue = oldObject[key]; if (typeof newValue === 'object' && newValue) { const valueDiffering = difference(oldValue, newValue); if (Object.keys(valueDiffering).length > 0) { result[key] = valueDiffering; } } else if (newValue !== oldValue) { result[key] = newValue; } } return result; }; return difference(this._defaultStoredSettings, this._generateAllProjectOptions()); } storeProjectOptions() { const options = this.generateDifferingProjectOptions(); // TODO: translate const text = "Configuration for https://turbowarp.org/\nYou can move, resize, and minimize this comment, but don't edit it by hand. This comment can be deleted to remove the stored settings.\n".concat(ExtendedJSON.stringify(options)).concat(COMMENT_CONFIG_MAGIC); const existingComment = this.findProjectOptionsComment(); if (existingComment) { existingComment.text = text; } else { const target = this.getTargetForStage(); // TODO: smarter position logic target.createComment(uid(), null, text, 50, 50, 350, 170, false); } this.emitProjectChanged(); } /** * Eagerly (re)compile all scripts within this project. */ precompile() { this.allScriptsDo((topBlockId, target) => { const topBlock = target.blocks.getBlock(topBlockId); if (this.getIsHat(topBlock.opcode)) { const thread = new Thread(topBlockId); thread.target = target; thread.blockContainer = target.blocks; thread.tryCompile(); } }); } enableDebug() { this.resetAllCaches(); this.debug = true; } /** * Emit glows/glow clears for scripts after a single tick. * Looks at `this.threads` and notices which have turned on/off new glows. * @param {Array.=} optExtraThreads Optional list of inactive threads. */ _updateGlows(optExtraThreads) { const searchThreads = []; searchThreads.push.apply(searchThreads, this.threads); if (optExtraThreads) { searchThreads.push.apply(searchThreads, optExtraThreads); } // Set of scripts that request a glow this frame. const requestedGlowsThisFrame = []; // Final set of scripts glowing during this frame. const finalScriptGlows = []; // Find all scripts that should be glowing. for (let i = 0; i < searchThreads.length; i++) { const thread = searchThreads[i]; const target = thread.target; if (target === this._editingTarget) { const blockForThread = thread.blockGlowInFrame; if (thread.requestScriptGlowInFrame || thread.stackClick) { let script = target.blocks.getTopLevelScript(blockForThread); if (!script) { // Attempt to find in flyout blocks. script = this.flyoutBlocks.getTopLevelScript(blockForThread); } if (script) { requestedGlowsThisFrame.push(script); } } } } // Compare to previous frame. for (let j = 0; j < this._scriptGlowsPreviousFrame.length; j++) { const previousFrameGlow = this._scriptGlowsPreviousFrame[j]; if (requestedGlowsThisFrame.indexOf(previousFrameGlow) < 0) { // Glow turned off. this.glowScript(previousFrameGlow, false); } else { // Still glowing. finalScriptGlows.push(previousFrameGlow); } } for (let k = 0; k < requestedGlowsThisFrame.length; k++) { const currentFrameGlow = requestedGlowsThisFrame[k]; if (this._scriptGlowsPreviousFrame.indexOf(currentFrameGlow) < 0) { // Glow turned on. this.glowScript(currentFrameGlow, true); finalScriptGlows.push(currentFrameGlow); } } this._scriptGlowsPreviousFrame = finalScriptGlows; } /** * Emit run start/stop after each tick. Emits when `this.threads.length` goes * between non-zero and zero * * @param {number} nonMonitorThreadCount The new nonMonitorThreadCount */ _emitProjectRunStatus(nonMonitorThreadCount) { if (this._nonMonitorThreadCount === 0 && nonMonitorThreadCount > 0) { this.emit(Runtime.PROJECT_RUN_START); } if (this._nonMonitorThreadCount > 0 && nonMonitorThreadCount === 0) { this.emit(Runtime.PROJECT_RUN_STOP); } this._nonMonitorThreadCount = nonMonitorThreadCount; } /** * "Quiet" a script's glow: stop the VM from generating glow/unglow events * about that script. Use when a script has just been deleted, but we may * still be tracking glow data about it. * @param {!string} scriptBlockId Id of top-level block in script to quiet. */ quietGlow(scriptBlockId) { const index = this._scriptGlowsPreviousFrame.indexOf(scriptBlockId); if (index > -1) { this._scriptGlowsPreviousFrame.splice(index, 1); } } /** * Emit feedback for block glowing (used in the sequencer). * @param {?string} blockId ID for the block to update glow * @param {boolean} isGlowing True to turn on glow; false to turn off. */ glowBlock(blockId, isGlowing) { if (isGlowing) { this.emit(Runtime.BLOCK_GLOW_ON, { id: blockId }); } else { this.emit(Runtime.BLOCK_GLOW_OFF, { id: blockId }); } } /** * Emit feedback for script glowing. * @param {?string} topBlockId ID for the top block to update glow * @param {boolean} isGlowing True to turn on glow; false to turn off. */ glowScript(topBlockId, isGlowing) { if (isGlowing) { this.emit(Runtime.SCRIPT_GLOW_ON, { id: topBlockId }); } else { this.emit(Runtime.SCRIPT_GLOW_OFF, { id: topBlockId }); } } /** * Emit whether blocks are being dragged over gui * @param {boolean} areBlocksOverGui True if blocks are dragged out of blocks workspace, false otherwise */ emitBlockDragUpdate(areBlocksOverGui) { this.emit(Runtime.BLOCK_DRAG_UPDATE, areBlocksOverGui); } /** * Emit event to indicate that the block drag has ended with the blocks outside the blocks workspace * @param {Array.} blocks The set of blocks dragged to the GUI * @param {string} topBlockId The original id of the top block being dragged */ emitBlockEndDrag(blocks, topBlockId) { this.emit(Runtime.BLOCK_DRAG_END, blocks, topBlockId); } /** * Emit value for reporter to show in the blocks. * @param {string} blockId ID for the block. * @param {string} value Value to show associated with the block. */ visualReport(blockId, value) { this.emit(Runtime.VISUAL_REPORT, { id: blockId, value: String(value) }); } /** * Add a monitor to the state. If the monitor already exists in the state, * updates those properties that are defined in the given monitor record. * @param {!MonitorRecord} monitor Monitor to add. */ requestAddMonitor(monitor) { const id = monitor.get('id'); if (!this.requestUpdateMonitor(monitor)) { // update monitor if it exists in the state // if the monitor did not exist in the state, add it this._monitorState = this._monitorState.set(id, monitor); } } /** * Update a monitor in the state and report success/failure of update. * @param {!Map} monitor Monitor values to update. Values on the monitor with overwrite * values on the old monitor with the same ID. If a value isn't defined on the new monitor, * the old monitor will keep its old value. * @return {boolean} true if monitor exists in the state and was updated, false if it did not exist. */ requestUpdateMonitor(monitor) { const id = monitor.get('id'); if (this._monitorState.has(id)) { this._monitorState = // Use mergeWith here to prevent undefined values from overwriting existing ones this._monitorState.set(id, this._monitorState.get(id).mergeWith((prev, next) => { if (typeof next === 'undefined' || next === null) { return prev; } return next; }, monitor)); return true; } return false; } /** * Removes a monitor from the state. Does nothing if the monitor already does * not exist in the state. * @param {!string} monitorId ID of the monitor to remove. */ requestRemoveMonitor(monitorId) { this._monitorState = this._monitorState.delete(monitorId); } /** * Hides a monitor and returns success/failure of action. * @param {!string} monitorId ID of the monitor to hide. * @return {boolean} true if monitor exists and was updated, false otherwise */ requestHideMonitor(monitorId) { return this.requestUpdateMonitor(new Map([['id', monitorId], ['visible', false]])); } /** * Shows a monitor and returns success/failure of action. * not exist in the state. * @param {!string} monitorId ID of the monitor to show. * @return {boolean} true if monitor exists and was updated, false otherwise */ requestShowMonitor(monitorId) { return this.requestUpdateMonitor(new Map([['id', monitorId], ['visible', true]])); } /** * Removes all monitors with the given target ID from the state. Does nothing if * the monitor already does not exist in the state. * @param {!string} targetId Remove all monitors with given target ID. */ requestRemoveMonitorByTargetId(targetId) { this._monitorState = this._monitorState.filterNot(value => value.targetId === targetId); } /** * Get a target by its id. * @param {string} targetId Id of target to find. * @return {?Target} The target, if found. */ getTargetById(targetId) { for (let i = 0; i < this.targets.length; i++) { const target = this.targets[i]; if (target.id === targetId) { return target; } } } /** * Get the first original (non-clone-block-created) sprite given a name. * @param {string} spriteName Name of sprite to look for. * @return {?Target} Target representing a sprite of the given name. */ getSpriteTargetByName(spriteName) { for (let i = 0; i < this.targets.length; i++) { const target = this.targets[i]; if (target.isStage) { continue; } if (target.sprite && target.sprite.name === spriteName) { return target; } } } /** * Get a target by its drawable id. * @param {number} drawableID drawable id of target to find * @return {?Target} The target, if found */ getTargetByDrawableId(drawableID) { for (let i = 0; i < this.targets.length; i++) { const target = this.targets[i]; if (target.drawableID === drawableID) return target; } } /** * Update the clone counter to track how many clones are created. * @param {number} changeAmount How many clones have been created/destroyed. */ changeCloneCounter(changeAmount) { this._cloneCounter += changeAmount; } /** * Return whether there are clones available. * @return {boolean} True until the number of clones hits runtimeOptions.maxClones */ clonesAvailable() { return this._cloneCounter < this.runtimeOptions.maxClones; } /** * Report that the project has loaded in the Virtual Machine. */ emitProjectLoaded() { this.emit(Runtime.PROJECT_LOADED); } /** * Report that the project has changed in a way that would affect serialization */ emitProjectChanged() { this.emit(Runtime.PROJECT_CHANGED); } /** * Report that a new target has been created, possibly by cloning an existing target. * @param {Target} newTarget - the newly created target. * @param {Target} [sourceTarget] - the target used as a source for the new clone, if any. * @fires Runtime#targetWasCreated */ fireTargetWasCreated(newTarget, sourceTarget) { this.emit('targetWasCreated', newTarget, sourceTarget); } /** * Report that a clone target is being removed. * @param {Target} target - the target being removed * @fires Runtime#targetWasRemoved */ fireTargetWasRemoved(target) { this.emit('targetWasRemoved', target); } /** * Get a target representing the Scratch stage, if one exists. * @return {?Target} The target, if found. */ getTargetForStage() { if (this._stageTarget) { return this._stageTarget; } for (let i = 0; i < this.targets.length; i++) { const target = this.targets[i]; if (target.isStage) { this._stageTarget = target; return target; } } } /** * Get the editing target. * @return {?Target} The editing target. */ getEditingTarget() { return this._editingTarget; } getAllVarNamesOfType(varType) { let varNames = []; for (const target of this.targets) { const targetVarNames = target.getAllVariableNamesInScopeByType(varType, true); varNames = varNames.concat(targetVarNames); } return varNames; } /** * Get the label or label function for an opcode * @param {string} extendedOpcode - the opcode you want a label for * @return {object} - object with label and category * @property {string} category - the category for this opcode * @property {Function} [labelFn] - function to generate the label for this opcode * @property {string} [label] - the label for this opcode if `labelFn` is absent */ getLabelForOpcode(extendedOpcode) { const [category, opcode] = StringUtil.splitFirst(extendedOpcode, '_'); if (!(category && opcode)) return; const categoryInfo = this._blockInfo.find(ci => ci.id === category); if (!categoryInfo) return; const block = categoryInfo.blocks.find(b => b.info.opcode === opcode); if (!block) return; // TODO: we may want to format the label in a locale-specific way. return { category: 'extension', // This assumes that all extensions have the same monitor color. label: "".concat(categoryInfo.name, ": ").concat(block.info.text) }; } /** * Create a new global variable avoiding conflicts with other variable names. * @param {string} variableName The desired variable name for the new global variable. * This can be turned into a fresh name as necessary. * @param {string} optVarId An optional ID to use for the variable. A new one will be generated * if a falsey value for this parameter is provided. * @param {string} optVarType The type of the variable to create. Defaults to Variable.SCALAR_TYPE. * @return {Variable} The new variable that was created. */ createNewGlobalVariable(variableName, optVarId, optVarType) { const varType = typeof optVarType === 'string' ? optVarType : Variable.SCALAR_TYPE; const allVariableNames = this.getAllVarNamesOfType(varType); const newName = StringUtil.unusedName(variableName, allVariableNames); const variable = new Variable(optVarId || uid(), newName, varType); const stage = this.getTargetForStage(); stage.variables[variable.id] = variable; return variable; } /** * Tell the runtime to request a redraw. * Use after a clone/sprite has completed some visible operation on the stage. */ requestRedraw() { this.redrawRequested = true; } /** * Emit a targets update at the end of the step if the provided target is * the original sprite * @param {!Target} target Target requesting the targets update */ requestTargetsUpdate(target) { if (!target.isOriginal) return; this._refreshTargets = true; } /** * Emit an event that indicates that the blocks on the workspace need updating. */ requestBlocksUpdate() { this.emit(Runtime.BLOCKS_NEED_UPDATE); } /** * Emit an event that indicates that the toolbox extension blocks need updating. */ requestToolboxExtensionsUpdate() { this.emit(Runtime.TOOLBOX_EXTENSIONS_NEED_UPDATE); } /** * Set up timers to repeatedly step in a browser. */ start() { // Do not start if we are already running if (this.frameLoop.running) return; this.frameLoop.start(); this.emit(Runtime.RUNTIME_STARTED); } /** * tw: Stop the tick loop * Note: This only stops the loop. It will not stop any threads the next time the VM starts */ stop() { if (!this.frameLoop.running) { return; } this.frameLoop.stop(); this.emit(Runtime.RUNTIME_STOPPED); } /** * Turn on profiling. * @param {Profiler/FrameCallback} onFrame A callback handle passed a * profiling frame when the profiler reports its collected data. */ enableProfiling(onFrame) { if (Profiler.available()) { this.profiler = new Profiler(onFrame); } } /** * Turn off profiling. */ disableProfiling() { this.profiler = null; } /** * Update a millisecond timestamp value that is saved on the Runtime. * This value is helpful in certain instances for compatibility with Scratch 2, * which sometimes uses a `currentMSecs` timestamp value in Interpreter.as */ updateCurrentMSecs() { this.currentMSecs = Date.now(); } } /** * Event fired after a new target has been created, possibly by cloning an existing target. * * @event Runtime#targetWasCreated * @param {Target} newTarget - the newly created target. * @param {Target} [sourceTarget] - the target used as a source for the new clone, if any. */ module.exports = Runtime; /***/ }), /***/ "./node_modules/scratch-vm/src/engine/scratch-blocks-constants.js": /*!************************************************************************!*\ !*** ./node_modules/scratch-vm/src/engine/scratch-blocks-constants.js ***! \************************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /** * These constants are copied from scratch-blocks/core/constants.js * @TODO find a way to require() these straight from scratch-blocks... maybe make a scratch-blocks/dist/constants.js? * @readonly * @enum {int} */ const ScratchBlocksConstants = { /** * ENUM for output shape: hexagonal (booleans/predicates). * @const */ OUTPUT_SHAPE_HEXAGONAL: 1, /** * ENUM for output shape: rounded (numbers). * @const */ OUTPUT_SHAPE_ROUND: 2, /** * ENUM for output shape: squared (any/all values; strings). * @const */ OUTPUT_SHAPE_SQUARE: 3 }; module.exports = ScratchBlocksConstants; /***/ }), /***/ "./node_modules/scratch-vm/src/engine/sequencer.js": /*!*********************************************************!*\ !*** ./node_modules/scratch-vm/src/engine/sequencer.js ***! \*********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const Timer = __webpack_require__(/*! ../util/timer */ "./node_modules/scratch-vm/src/util/timer.js"); const Thread = __webpack_require__(/*! ./thread */ "./node_modules/scratch-vm/src/engine/thread.js"); const execute = __webpack_require__(/*! ./execute.js */ "./node_modules/scratch-vm/src/engine/execute.js"); const compilerExecute = __webpack_require__(/*! ../compiler/jsexecute */ "./node_modules/scratch-vm/src/compiler/jsexecute.js"); /** * Profiler frame name for stepping a single thread. * @const {string} */ const stepThreadProfilerFrame = 'Sequencer.stepThread'; /** * Profiler frame name for the inner loop of stepThreads. * @const {string} */ const stepThreadsInnerProfilerFrame = 'Sequencer.stepThreads#inner'; /** * Profiler frame name for execute. * @const {string} */ const executeProfilerFrame = 'execute'; /** * Profiler frame ID for stepThreadProfilerFrame. * @type {number} */ let stepThreadProfilerId = -1; /** * Profiler frame ID for stepThreadsInnerProfilerFrame. * @type {number} */ let stepThreadsInnerProfilerId = -1; /** * Profiler frame ID for executeProfilerFrame. * @type {number} */ let executeProfilerId = -1; class Sequencer { constructor(runtime) { /** * A utility timer for timing thread sequencing. * @type {!Timer} */ this.timer = new Timer(); /** * Reference to the runtime owning this sequencer. * @type {!Runtime} */ this.runtime = runtime; this.activeThread = null; } /** * Time to run a warp-mode thread, in ms. * @type {number} */ static get WARP_TIME() { return 500; } /** * Step through all threads in `this.runtime.threads`, running them in order. * @return {Array.} List of inactive threads after stepping. */ stepThreads() { // Work time is 75% of the thread stepping interval. const WORK_TIME = 0.75 * this.runtime.currentStepTime; // For compatibility with Scatch 2, update the millisecond clock // on the Runtime once per step (see Interpreter.as in Scratch 2 // for original use of `currentMSecs`) this.runtime.updateCurrentMSecs(); // Start counting toward WORK_TIME. this.timer.start(); // Count of active threads. let numActiveThreads = Infinity; // Whether `stepThreads` has run through a full single tick. let ranFirstTick = false; const doneThreads = []; // Conditions for continuing to stepping threads: // 1. We must have threads in the list, and some must be active. // 2. Time elapsed must be less than WORK_TIME. // 3. Either turbo mode, or no redraw has been requested by a primitive. while (this.runtime.threads.length > 0 && numActiveThreads > 0 && this.timer.timeElapsed() < WORK_TIME && (this.runtime.turboMode || !this.runtime.redrawRequested)) { if (this.runtime.profiler !== null) { if (stepThreadsInnerProfilerId === -1) { stepThreadsInnerProfilerId = this.runtime.profiler.idByName(stepThreadsInnerProfilerFrame); } this.runtime.profiler.start(stepThreadsInnerProfilerId); } numActiveThreads = 0; let stoppedThread = false; // Attempt to run each thread one time. const threads = this.runtime.threads; for (let i = 0; i < threads.length; i++) { const activeThread = this.activeThread = threads[i]; // Check if the thread is done so it is not executed. if (activeThread.stack.length === 0 || activeThread.status === Thread.STATUS_DONE) { // Finished with this thread. stoppedThread = true; continue; } if (activeThread.status === Thread.STATUS_YIELD_TICK && !ranFirstTick) { // Clear single-tick yield from the last call of `stepThreads`. activeThread.status = Thread.STATUS_RUNNING; } if (activeThread.status === Thread.STATUS_RUNNING || activeThread.status === Thread.STATUS_YIELD) { // Normal-mode thread: step. if (this.runtime.profiler !== null) { if (stepThreadProfilerId === -1) { stepThreadProfilerId = this.runtime.profiler.idByName(stepThreadProfilerFrame); } // Increment the number of times stepThread is called. this.runtime.profiler.increment(stepThreadProfilerId); } this.stepThread(activeThread); activeThread.warpTimer = null; if (activeThread.isKilled) { i--; // if the thread is removed from the list (killed), do not increase index } } if (activeThread.status === Thread.STATUS_RUNNING) { numActiveThreads++; } // Check if the thread completed while it just stepped to make // sure we remove it before the next iteration of all threads. if (activeThread.stack.length === 0 || activeThread.status === Thread.STATUS_DONE) { // Finished with this thread. stoppedThread = true; } } // We successfully ticked once. Prevents running STATUS_YIELD_TICK // threads on the next tick. ranFirstTick = true; if (this.runtime.profiler !== null) { this.runtime.profiler.stop(); } // Filter inactive threads from `this.runtime.threads`. if (stoppedThread) { let nextActiveThread = 0; for (let i = 0; i < this.runtime.threads.length; i++) { const thread = this.runtime.threads[i]; if (thread.stack.length !== 0 && thread.status !== Thread.STATUS_DONE) { this.runtime.threads[nextActiveThread] = thread; nextActiveThread++; } else { this.runtime.threadMap.delete(thread.getId()); doneThreads.push(thread); } } this.runtime.threads.length = nextActiveThread; } } this.activeThread = null; return doneThreads; } /** * Step the requested thread for as long as necessary. * @param {!Thread} thread Thread object to step. */ stepThread(thread) { if (thread.isCompiled) { compilerExecute(thread); return; } let currentBlockId = thread.peekStack(); if (!currentBlockId) { // A "null block" - empty branch. thread.popStack(); // Did the null follow a hat block? if (thread.stack.length === 0) { thread.status = Thread.STATUS_DONE; return; } } // Save the current block ID to notice if we did control flow. while (currentBlockId = thread.peekStack()) { let isWarpMode = thread.peekStackFrame().warpMode; if (isWarpMode && !thread.warpTimer) { // Initialize warp-mode timer if it hasn't been already. // This will start counting the thread toward `Sequencer.WARP_TIME`. thread.warpTimer = new Timer(); thread.warpTimer.start(); } // Execute the current block. if (this.runtime.profiler !== null) { if (executeProfilerId === -1) { executeProfilerId = this.runtime.profiler.idByName(executeProfilerFrame); } // Increment the number of times execute is called. this.runtime.profiler.increment(executeProfilerId); } if (thread.target === null) { this.retireThread(thread); } else { execute(this, thread); } thread.blockGlowInFrame = currentBlockId; // If the thread has yielded or is waiting, yield to other threads. if (thread.status === Thread.STATUS_YIELD) { // Mark as running for next iteration. thread.status = Thread.STATUS_RUNNING; // In warp mode, yielded blocks are re-executed immediately. if (isWarpMode && thread.warpTimer.timeElapsed() <= Sequencer.WARP_TIME) { continue; } return; } else if (thread.status === Thread.STATUS_PROMISE_WAIT) { // A promise was returned by the primitive. Yield the thread // until the promise resolves. Promise resolution should reset // thread.status to Thread.STATUS_RUNNING. return; } else if (thread.status === Thread.STATUS_YIELD_TICK) { // stepThreads will reset the thread to Thread.STATUS_RUNNING return; } // If no control flow has happened, switch to next block. if (thread.peekStack() === currentBlockId) { thread.goToNextBlock(); } // If no next block has been found at this point, look on the stack. while (!thread.peekStack()) { thread.popStack(); if (thread.stack.length === 0) { // No more stack to run! thread.status = Thread.STATUS_DONE; return; } const stackFrame = thread.peekStackFrame(); isWarpMode = stackFrame.warpMode; if (stackFrame.isLoop) { // The current level of the stack is marked as a loop. // Return to yield for the frame/tick in general. // Unless we're in warp mode - then only return if the // warp timer is up. if (!isWarpMode || thread.warpTimer.timeElapsed() > Sequencer.WARP_TIME) { // Don't do anything to the stack, since loops need // to be re-executed. return; } // Don't go to the next block for this level of the stack, // since loops need to be re-executed. continue; } else if (stackFrame.waitingReporter) { // This level of the stack was waiting for a value. // This means a reporter has just returned - so don't go // to the next block for this level of the stack. return; } // Get next block of existing block on the stack. thread.goToNextBlock(); } } } /** * Step a thread into a block's branch. * @param {!Thread} thread Thread object to step to branch. * @param {number} branchNum Which branch to step to (i.e., 1, 2). * @param {boolean} isLoop Whether this block is a loop. */ stepToBranch(thread, branchNum, isLoop) { if (!branchNum) { branchNum = 1; } const currentBlockId = thread.peekStack(); const branchId = thread.target.blocks.getBranch(currentBlockId, branchNum); thread.peekStackFrame().isLoop = isLoop; if (branchId) { // Push branch ID to the thread's stack. thread.pushStack(branchId); } else { thread.pushStack(null); } } /** * Step a procedure. * @param {!Thread} thread Thread object to step to procedure. * @param {!string} procedureCode Procedure code of procedure to step to. */ stepToProcedure(thread, procedureCode) { const definition = thread.target.blocks.getProcedureDefinition(procedureCode); if (!definition) { return; } // Check if the call is recursive. // If so, set the thread to yield after pushing. const isRecursive = thread.isRecursiveCall(procedureCode); // To step to a procedure, we put its definition on the stack. // Execution for the thread will proceed through the definition hat // and on to the main definition of the procedure. // When that set of blocks finishes executing, it will be popped // from the stack by the sequencer, returning control to the caller. thread.pushStack(definition); // In known warp-mode threads, only yield when time is up. if (thread.peekStackFrame().warpMode && thread.warpTimer.timeElapsed() > Sequencer.WARP_TIME) { thread.status = Thread.STATUS_YIELD; } else { // Look for warp-mode flag on definition, and set the thread // to warp-mode if needed. const definitionBlock = thread.target.blocks.getBlock(definition); const innerBlock = thread.target.blocks.getBlock(definitionBlock.inputs.custom_block.block); let doWarp = false; if (innerBlock && innerBlock.mutation) { const warp = innerBlock.mutation.warp; if (typeof warp === 'boolean') { doWarp = warp; } else if (typeof warp === 'string') { doWarp = JSON.parse(warp); } } if (doWarp) { thread.peekStackFrame().warpMode = true; } else if (isRecursive) { // In normal-mode threads, yield any time we have a recursive call. thread.status = Thread.STATUS_YIELD; } } } /** * Retire a thread in the middle, without considering further blocks. * @param {!Thread} thread Thread object to retire. */ retireThread(thread) { thread.stack = []; thread.stackFrame = []; thread.requestScriptGlowInFrame = false; thread.status = Thread.STATUS_DONE; if (thread.isCompiled) { thread.procedures = null; thread.generator = null; } } } module.exports = Sequencer; /***/ }), /***/ "./node_modules/scratch-vm/src/engine/stage-layering.js": /*!**************************************************************!*\ !*** ./node_modules/scratch-vm/src/engine/stage-layering.js ***! \**************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { class StageLayering { static get BACKGROUND_LAYER() { return 'background'; } static get VIDEO_LAYER() { return 'video'; } static get PEN_LAYER() { return 'pen'; } static get SPRITE_LAYER() { return 'sprite'; } // Order of layer groups relative to each other, static get LAYER_GROUPS() { return [StageLayering.BACKGROUND_LAYER, StageLayering.VIDEO_LAYER, StageLayering.PEN_LAYER, StageLayering.SPRITE_LAYER]; } } module.exports = StageLayering; /***/ }), /***/ "./node_modules/scratch-vm/src/engine/target.js": /*!******************************************************!*\ !*** ./node_modules/scratch-vm/src/engine/target.js ***! \******************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const EventEmitter = __webpack_require__(/*! events */ "./node_modules/events/events.js"); const Blocks = __webpack_require__(/*! ./blocks */ "./node_modules/scratch-vm/src/engine/blocks.js"); const Variable = __webpack_require__(/*! ../engine/variable */ "./node_modules/scratch-vm/src/engine/variable.js"); const Comment = __webpack_require__(/*! ../engine/comment */ "./node_modules/scratch-vm/src/engine/comment.js"); const uid = __webpack_require__(/*! ../util/uid */ "./node_modules/scratch-vm/src/util/uid.js"); const { Map } = __webpack_require__(/*! immutable */ "./node_modules/immutable/dist/immutable.js"); const log = __webpack_require__(/*! ../util/log */ "./node_modules/scratch-vm/src/util/log.js"); const StringUtil = __webpack_require__(/*! ../util/string-util */ "./node_modules/scratch-vm/src/util/string-util.js"); const VariableUtil = __webpack_require__(/*! ../util/variable-util */ "./node_modules/scratch-vm/src/util/variable-util.js"); /** * @fileoverview * A Target is an abstract "code-running" object for the Scratch VM. * Examples include sprites/clones or potentially physical-world devices. */ class Target extends EventEmitter { /** * @param {Runtime} runtime Reference to the runtime. * @param {?Blocks} blocks Blocks instance for the blocks owned by this target. * @constructor */ constructor(runtime, blocks) { super(); if (!blocks) { blocks = new Blocks(runtime); } /** * Reference to the runtime. * @type {Runtime} */ this.runtime = runtime; /** * A unique ID for this target. * @type {string} */ this.id = uid(); /** * Blocks run as code for this target. * @type {!Blocks} */ this.blocks = blocks; /** * Dictionary of variables and their values for this target. * Key is the variable id. * @type {Object.} */ this.variables = {}; /** * Dictionary of comments for this target. * Key is the comment id. * @type {Object.} */ this.comments = {}; /** * Dictionary of custom state for this target. * This can be used to store target-specific custom state for blocks which need it. * TODO: do we want to persist this in SB3 files? * @type {Object.} */ this._customState = {}; /** * Currently known values for edge-activated hats. * Keys are block ID for the hat; values are the currently known values. * @type {Object.} */ this._edgeActivatedHatValues = {}; } /** * Called when the project receives a "green flag." * @abstract */ onGreenFlag() {} /** * Return a human-readable name for this target. * Target implementations should override this. * @abstract * @returns {string} Human-readable name for the target. */ getName() { return this.id; } /** * Update an edge-activated hat block value. * @param {!string} blockId ID of hat to store value for. * @param {*} newValue Value to store for edge-activated hat. * @return {*} The old value for the edge-activated hat. */ updateEdgeActivatedValue(blockId, newValue) { const oldValue = this._edgeActivatedHatValues[blockId]; this._edgeActivatedHatValues[blockId] = newValue; return oldValue; } hasEdgeActivatedValue(blockId) { return this._edgeActivatedHatValues.hasOwnProperty(blockId); } /** * Clear all edge-activaed hat values. */ clearEdgeActivatedValues() { this._edgeActivatedHatValues = {}; } /** * Look up a variable object, first by id, and then by name if the id is not found. * Create a new variable if both lookups fail. * @param {string} id Id of the variable. * @param {string} name Name of the variable. * @return {!Variable} Variable object. */ lookupOrCreateVariable(id, name) { let variable = this.lookupVariableById(id); if (variable) return variable; variable = this.lookupVariableByNameAndType(name, Variable.SCALAR_TYPE); if (variable) return variable; // No variable with this name exists - create it locally. const newVariable = new Variable(id, name, Variable.SCALAR_TYPE, false); this.variables[id] = newVariable; return newVariable; } /** * Look up a broadcast message object with the given id and return it * if it exists. * @param {string} id Id of the variable. * @param {string} name Name of the variable. * @return {?Variable} Variable object. */ lookupBroadcastMsg(id, name) { let broadcastMsg; if (id) { broadcastMsg = this.lookupVariableById(id); } else if (name) { broadcastMsg = this.lookupBroadcastByInputValue(name); } else { log.error('Cannot find broadcast message if neither id nor name are provided.'); } if (broadcastMsg) { if (name && broadcastMsg.name.toLowerCase() !== name.toLowerCase()) { log.error("Found broadcast message with id: ".concat(id, ", but") + "its name, ".concat(broadcastMsg.name, " did not match expected name ").concat(name, ".")); } if (broadcastMsg.type !== Variable.BROADCAST_MESSAGE_TYPE) { log.error("Found variable with id: ".concat(id, ", but its type ").concat(broadcastMsg.type) + "did not match expected type ".concat(Variable.BROADCAST_MESSAGE_TYPE)); } return broadcastMsg; } } /** * Look up a broadcast message with the given name and return the variable * if it exists. Does not create a new broadcast message variable if * it doesn't exist. * @param {string} name Name of the variable. * @return {?Variable} Variable object. */ lookupBroadcastByInputValue(name) { const vars = this.variables; for (const propName in vars) { if (vars[propName].type === Variable.BROADCAST_MESSAGE_TYPE && vars[propName].name.toLowerCase() === name.toLowerCase()) { return vars[propName]; } } } /** * Look up a variable object. * Search begins for local variables; then look for globals. * @param {string} id Id of the variable. * @param {string} name Name of the variable. * @return {!Variable} Variable object. */ lookupVariableById(id) { // If we have a local copy, return it. if (this.variables.hasOwnProperty(id)) { return this.variables[id]; } // If the stage has a global copy, return it. if (this.runtime && !this.isStage) { const stage = this.runtime.getTargetForStage(); if (stage && stage.variables.hasOwnProperty(id)) { return stage.variables[id]; } } } /** * Look up a variable object by its name and variable type. * Search begins with local variables; then global variables if a local one * was not found. * @param {string} name Name of the variable. * @param {string} type Type of the variable. Defaults to Variable.SCALAR_TYPE. * @param {?bool} skipStage Optional flag to skip checking the stage * @return {?Variable} Variable object if found, or null if not. */ lookupVariableByNameAndType(name, type, skipStage) { if (typeof name !== 'string') return; if (typeof type !== 'string') type = Variable.SCALAR_TYPE; skipStage = skipStage || false; for (const varId in this.variables) { const currVar = this.variables[varId]; if (currVar.name === name && currVar.type === type) { return currVar; } } if (!skipStage && this.runtime && !this.isStage) { const stage = this.runtime.getTargetForStage(); if (stage) { for (const varId in stage.variables) { const currVar = stage.variables[varId]; if (currVar.name === name && currVar.type === type) { return currVar; } } } } return null; } /** * Look up a list object for this target, and create it if one doesn't exist. * Search begins for local lists; then look for globals. * @param {!string} id Id of the list. * @param {!string} name Name of the list. * @return {!Varible} Variable object representing the found/created list. */ lookupOrCreateList(id, name) { let list = this.lookupVariableById(id); if (list) return list; list = this.lookupVariableByNameAndType(name, Variable.LIST_TYPE); if (list) return list; // No variable with this name exists - create it locally. const newList = new Variable(id, name, Variable.LIST_TYPE, false); this.variables[id] = newList; return newList; } /** * Creates a variable with the given id and name and adds it to the * dictionary of variables. * @param {string} id Id of variable * @param {string} name Name of variable. * @param {string} type Type of variable, '', 'broadcast_msg', or 'list' * @param {boolean} isCloud Whether the variable to create has the isCloud flag set. * Additional checks are made that the variable can be created as a cloud variable. */ createVariable(id, name, type, isCloud) { if (!this.variables.hasOwnProperty(id)) { const newVariable = new Variable(id, name, type, false); if (isCloud && this.isStage && this.runtime.canAddCloudVariable()) { newVariable.isCloud = true; this.runtime.addCloudVariable(); this.runtime.ioDevices.cloud.requestCreateVariable(newVariable); } this.variables[id] = newVariable; } } /** * Creates a comment with the given properties. * @param {string} id Id of the comment. * @param {string} blockId Optional id of the block the comment is attached * to if it is a block comment. * @param {string} text The text the comment contains. * @param {number} x The x coordinate of the comment on the workspace. * @param {number} y The y coordinate of the comment on the workspace. * @param {number} width The width of the comment when it is full size * @param {number} height The height of the comment when it is full size * @param {boolean} minimized Whether the comment is minimized. */ createComment(id, blockId, text, x, y, width, height, minimized) { if (!this.comments.hasOwnProperty(id)) { const newComment = new Comment(id, text, x, y, width, height, minimized); if (blockId) { newComment.blockId = blockId; const blockWithComment = this.blocks.getBlock(blockId); if (blockWithComment) { blockWithComment.comment = id; } else { log.warn("Could not find block with id ".concat(blockId, " associated with commentId: ").concat(id)); } } this.comments[id] = newComment; } } /** * Renames the variable with the given id to newName. * @param {string} id Id of variable to rename. * @param {string} newName New name for the variable. */ renameVariable(id, newName) { if (this.variables.hasOwnProperty(id)) { const variable = this.variables[id]; if (variable.id === id) { const oldName = variable.name; variable.name = newName; if (this.runtime) { if (variable.isCloud && this.isStage) { this.runtime.ioDevices.cloud.requestRenameVariable(oldName, newName); } if (variable.type === Variable.SCALAR_TYPE) { // sensing__of may be referencing to this variable. // Change the reference. let blockUpdated = false; this.runtime.targets.forEach(t => { blockUpdated = t.blocks.updateSensingOfReference(oldName, newName, this.isStage ? '_stage_' : this.getName()) || blockUpdated; }); // Request workspace change only if sensing_of blocks were actually updated. if (blockUpdated) this.runtime.requestBlocksUpdate(); } const blocks = this.runtime.monitorBlocks; blocks.changeBlock({ id: id, element: 'field', name: variable.type === Variable.LIST_TYPE ? 'LIST' : 'VARIABLE', value: id }, this.runtime); const monitorBlock = blocks.getBlock(variable.id); if (monitorBlock) { this.runtime.requestUpdateMonitor(Map({ id: id, params: blocks._getBlockParams(monitorBlock) })); } } } } } /** * Removes the variable with the given id from the dictionary of variables. * @param {string} id Id of variable to delete. */ deleteVariable(id) { if (this.variables.hasOwnProperty(id)) { // Get info about the variable before deleting it const deletedVariableName = this.variables[id].name; const deletedVariableWasCloud = this.variables[id].isCloud; delete this.variables[id]; if (this.runtime) { if (deletedVariableWasCloud && this.isStage) { this.runtime.ioDevices.cloud.requestDeleteVariable(deletedVariableName); this.runtime.removeCloudVariable(); } this.runtime.monitorBlocks.deleteBlock(id); this.runtime.requestRemoveMonitor(id); } } } /** * Remove this target's monitors from the runtime state and remove the * target-specific monitored blocks (e.g. local variables, global variables for the stage, x-position). * NOTE: This does not delete any of the stage monitors like backdrop name. */ deleteMonitors() { this.runtime.requestRemoveMonitorByTargetId(this.id); let targetSpecificMonitorBlockIds; if (this.isStage) { // This only deletes global variables and not other stage monitors like backdrop number. targetSpecificMonitorBlockIds = Object.keys(this.variables); } else { targetSpecificMonitorBlockIds = Object.keys(this.runtime.monitorBlocks._blocks).filter(key => this.runtime.monitorBlocks._blocks[key].targetId === this.id); } for (const blockId of targetSpecificMonitorBlockIds) { this.runtime.monitorBlocks.deleteBlock(blockId); } } /** * Create a clone of the variable with the given id from the dictionary of * this target's variables. * @param {string} id Id of variable to duplicate. * @param {boolean=} optKeepOriginalId Optional flag to keep the original variable ID * for the duplicate variable. This is necessary when cloning a sprite, for example. * @return {?Variable} The duplicated variable, or null if * the original variable was not found. */ duplicateVariable(id, optKeepOriginalId) { if (this.variables.hasOwnProperty(id)) { const originalVariable = this.variables[id]; const newVariable = new Variable(optKeepOriginalId ? id : null, // conditionally keep original id or generate a new one originalVariable.name, originalVariable.type, originalVariable.isCloud); if (newVariable.type === Variable.LIST_TYPE) { newVariable.value = originalVariable.value.slice(0); } else { newVariable.value = originalVariable.value; } return newVariable; } return null; } /** * Duplicate the dictionary of this target's variables as part of duplicating. * this target or making a clone. * @param {object=} optBlocks Optional block container for the target being duplicated. * If provided, new variables will be generated with new UIDs and any variable references * in this blocks container will be updated to refer to the corresponding new IDs. * @return {object} The duplicated dictionary of variables */ duplicateVariables(optBlocks) { let allVarRefs; if (optBlocks) { allVarRefs = optBlocks.getAllVariableAndListReferences(); } return Object.keys(this.variables).reduce((accum, varId) => { const newVariable = this.duplicateVariable(varId, !optBlocks); accum[newVariable.id] = newVariable; if (optBlocks && allVarRefs) { const currVarRefs = allVarRefs[varId]; if (currVarRefs) { this.mergeVariables(varId, newVariable.id, currVarRefs); } } return accum; }, {}); } /** * Post/edit sprite info. * @param {object} data An object with sprite info data to set. * @abstract */ postSpriteInfo() {} /** * Retrieve custom state associated with this target and the provided state ID. * @param {string} stateId - specify which piece of state to retrieve. * @returns {*} the associated state, if any was found. */ getCustomState(stateId) { return this._customState[stateId]; } /** * Store custom state associated with this target and the provided state ID. * @param {string} stateId - specify which piece of state to store on this target. * @param {*} newValue - the state value to store. */ setCustomState(stateId, newValue) { this._customState[stateId] = newValue; } /** * Call to destroy a target. * @abstract */ dispose() { this._customState = {}; if (this.runtime) { this.runtime.removeExecutable(this); } } // Variable Conflict Resolution Helpers /** * Get the names of all the variables of the given type that are in scope for this target. * For targets that are not the stage, this includes any target-specific * variables as well as any stage variables unless the skipStage flag is true. * For the stage, this is all stage variables. * @param {string} type The variable type to search for; defaults to Variable.SCALAR_TYPE * @param {?bool} skipStage Optional flag to skip the stage. * @return {Array} A list of variable names */ getAllVariableNamesInScopeByType(type, skipStage) { if (typeof type !== 'string') type = Variable.SCALAR_TYPE; skipStage = skipStage || false; const targetVariables = Object.values(this.variables).filter(v => v.type === type).map(variable => variable.name); if (skipStage || this.isStage || !this.runtime) { return targetVariables; } const stage = this.runtime.getTargetForStage(); const stageVariables = stage.getAllVariableNamesInScopeByType(type); return targetVariables.concat(stageVariables); } /** * Merge variable references with another variable. * @param {string} idToBeMerged ID of the variable whose references need to be updated * @param {string} idToMergeWith ID of the variable that the old references should be replaced with * @param {?Array} optReferencesToUpdate Optional context of the change. * Defaults to all the blocks in this target. * @param {?string} optNewName New variable name to merge with. The old * variable name in the references being updated should be replaced with this new name. * If this parameter is not provided or is '', no name change occurs. */ mergeVariables(idToBeMerged, idToMergeWith, optReferencesToUpdate, optNewName) { const referencesToChange = optReferencesToUpdate || // TODO should there be a separate helper function that traverses the blocks // for all references for a given ID instead of doing the below..? this.blocks.getAllVariableAndListReferences()[idToBeMerged]; VariableUtil.updateVariableIdentifiers(referencesToChange, idToMergeWith, optNewName); } /** * Share a local variable (and given references for that variable) to the stage. * @param {string} varId The ID of the variable to share. * @param {Array} varRefs The list of variable references being shared, * that reference the given variable ID. The names and IDs of these variable * references will be updated to refer to the new (or pre-existing) global variable. */ shareLocalVariableToStage(varId, varRefs) { if (!this.runtime) return; const variable = this.variables[varId]; if (!variable) { log.warn("Cannot share a local variable to the stage if it's not local."); return; } const stage = this.runtime.getTargetForStage(); // If a local var is being shared with the stage, // sharing will make the variable global, resulting in a conflict // with the existing local variable. Preemptively Resolve this conflict // by renaming the new global variable. // First check if we've already done the local to global transition for this // variable. If we have, merge it with the global variable we've already created. const varIdForStage = "StageVarFromLocal_".concat(varId); let stageVar = stage.lookupVariableById(varIdForStage); // If a global var doesn't already exist, create a new one with a fresh name. // Use the ID we created above so that we can lookup this new variable in the // future if we decide to share this same variable again. if (!stageVar) { const varName = variable.name; const varType = variable.type; const newStageName = "Stage: ".concat(varName); stageVar = this.runtime.createNewGlobalVariable(newStageName, varIdForStage, varType); } // Update all variable references to use the new name and ID this.mergeVariables(varId, stageVar.id, varRefs, stageVar.name); } /** * Share a local variable with a sprite, merging with one of the same name and * type if it already exists on the sprite, or create a new one. * @param {string} varId Id of the variable to share * @param {Target} sprite The sprite to share the variable with * @param {Array} varRefs A list of all the variable references currently being shared. */ shareLocalVariableToSprite(varId, sprite, varRefs) { if (!this.runtime) return; if (this.isStage) return; const variable = this.variables[varId]; if (!variable) { log.warn("Tried to call 'shareLocalVariableToSprite' with a non-local variable."); return; } const varName = variable.name; const varType = variable.type; // Check if the receiving sprite already has a variable of the same name and type // and use the existing variable, otherwise create a new one. const existingLocalVar = sprite.lookupVariableByNameAndType(varName, varType); let newVarId; if (existingLocalVar) { newVarId = existingLocalVar.id; } else { const newVar = new Variable(null, varName, varType); newVarId = newVar.id; sprite.variables[newVarId] = newVar; } // Merge with the local variable on the new sprite. this.mergeVariables(varId, newVarId, varRefs); } /** * Given a list of variable referencing fields, shares those variables with * the target with the provided id, resolving any variable conflicts that arise * using the following rules: * * If this target is the stage, exit. There are no conflicts that arise * from sharing variables from the stage to another sprite. The variables * already exist globally, so no further action is needed. * * If a variable being referenced is a global variable, do nothing. The * global variable already exists so no further action is needed. * * If a variable being referenced is local, and * 1) The receiving target is a sprite: * create a new local variable or merge with an existing local variable * of the same name and type. Update all the referencing fields * for the original variable to reference the new variable. * 2) The receiving target is the stage: * Create a new global variable with a fresh name and update all the referencing * fields to reference the new variable. * * @param {Array} blocks The blocks containing * potential conflicting references to variables. * @param {Target} receivingTarget The target receiving the variables */ resolveVariableSharingConflictsWithTarget(blocks, receivingTarget) { if (this.isStage) return; // Get all the variable references in the given list of blocks const allVarListRefs = this.blocks.getAllVariableAndListReferences(blocks); // For all the variables being referenced, check for which ones are local // to this target, and resolve conflicts based on whether the receiving target // is a sprite (with a conflicting local variable) or whether it is // the stage (which cannot have local variables) for (const varId in allVarListRefs) { const currVar = this.variables[varId]; if (!currVar) continue; // The current variable is global, there shouldn't be any conflicts here, skip it. // Get the list of references for the current variable id const currVarListRefs = allVarListRefs[varId]; if (receivingTarget.isStage) { this.shareLocalVariableToStage(varId, currVarListRefs); } else { this.shareLocalVariableToSprite(varId, receivingTarget, currVarListRefs); } } } /** * Fixes up variable references in this target avoiding conflicts with * pre-existing variables in the same scope. * This is used when uploading this target as a new sprite into an existing * project, where the new sprite may contain references * to variable names that already exist as global variables in the project * (and thus are in scope for variable references in the given sprite). * * If this target has a block that references an existing global variable and that * variable *does not* exist in this target (e.g. it was a global variable in the * project the sprite was originally exported from), merge the variables. This entails * fixing the variable references in this sprite to reference the id of the pre-existing global variable. * * If this target has a block that references an existing global variable and that * variable does exist in the target itself (e.g. it's a local variable in the sprite being uploaded), * then the local variable is renamed to distinguish itself from the pre-existing variable. * All blocks that reference the local variable will be updated to use the new name. */ // TODO (#1360) This function is too long, add some helpers for the different chunks and cases... fixUpVariableReferences() { if (!this.runtime) return; // There's no runtime context to conflict with if (this.isStage) return; // Stage can't have variable conflicts with itself (and also can't be uploaded) const stage = this.runtime.getTargetForStage(); if (!stage || !stage.variables) return; const renameConflictingLocalVar = (id, name, type) => { const conflict = stage.lookupVariableByNameAndType(name, type); if (conflict) { const newName = StringUtil.unusedName("".concat(this.getName(), ": ").concat(name), this.getAllVariableNamesInScopeByType(type)); this.renameVariable(id, newName); return newName; } return null; }; const allReferences = this.blocks.getAllVariableAndListReferences(); const unreferencedLocalVarIds = []; if (Object.keys(this.variables).length > 0) { for (const localVarId in this.variables) { if (!this.variables.hasOwnProperty(localVarId)) continue; if (!allReferences[localVarId]) unreferencedLocalVarIds.push(localVarId); } } const conflictIdsToReplace = Object.create(null); const conflictNamesToReplace = Object.create(null); // Cache the list of all variable names by type so that we don't need to // re-calculate this in every iteration of the following loop. const varNamesByType = {}; const allVarNames = type => { const namesOfType = varNamesByType[type]; if (namesOfType) return namesOfType; varNamesByType[type] = this.runtime.getAllVarNamesOfType(type); return varNamesByType[type]; }; for (const varId in allReferences) { // We don't care about which var ref we get, they should all have the same var info const varRef = allReferences[varId][0]; const varName = varRef.referencingField.value; const varType = varRef.type; if (this.lookupVariableById(varId)) { // Found a variable with the id in either the target or the stage, // figure out which one. if (this.variables.hasOwnProperty(varId)) { // If the target has the variable, then check whether the stage // has one with the same name and type. If it does, then rename // this target specific variable so that there is a distinction. const newVarName = renameConflictingLocalVar(varId, varName, varType); if (newVarName) { // We are not calling this.blocks.updateBlocksAfterVarRename // here because it will search through all the blocks. We already // have access to all the references for this var id. allReferences[varId].map(ref => { ref.referencingField.value = newVarName; return ref; }); } } } else { // We didn't find the referenced variable id anywhere, // Treat it as a reference to a global variable (from the original // project this sprite was exported from). // Check for whether a global variable of the same name and type exists, // and if so, track it to merge with the existing global in a second pass of the blocks. const existingVar = stage.lookupVariableByNameAndType(varName, varType); if (existingVar) { if (!conflictIdsToReplace[varId]) { conflictIdsToReplace[varId] = existingVar.id; } } else { // A global variable with the same name did not already exist, // create a new one such that it does not conflict with any // names of local variables of the same type. const allNames = allVarNames(varType); const freshName = StringUtil.unusedName(varName, allNames); stage.createVariable(varId, freshName, varType); if (!conflictNamesToReplace[varId]) { conflictNamesToReplace[varId] = freshName; } } } } // Rename any local variables that were missed above because they aren't // referenced by any blocks for (const id in unreferencedLocalVarIds) { const varId = unreferencedLocalVarIds[id]; const name = this.variables[varId].name; const type = this.variables[varId].type; renameConflictingLocalVar(varId, name, type); } // Handle global var conflicts with existing global vars (e.g. a sprite is uploaded, and has // blocks referencing some variable that the sprite does not own, and this // variable conflicts with a global var) // In this case, we want to merge the new variable referenes with the // existing global variable for (const conflictId in conflictIdsToReplace) { const existingId = conflictIdsToReplace[conflictId]; const referencesToUpdate = allReferences[conflictId]; this.mergeVariables(conflictId, existingId, referencesToUpdate); } // Handle global var conflicts existing local vars (e.g a sprite is uploaded, // and has blocks referencing some variable that the sprite does not own, and this // variable conflcits with another sprite's local var). // In this case, we want to go through the variable references and update // the name of the variable in that reference. for (const conflictId in conflictNamesToReplace) { const newName = conflictNamesToReplace[conflictId]; const referencesToUpdate = allReferences[conflictId]; referencesToUpdate.map(ref => { ref.referencingField.value = newName; return ref; }); } } } module.exports = Target; /***/ }), /***/ "./node_modules/scratch-vm/src/engine/thread.js": /*!******************************************************!*\ !*** ./node_modules/scratch-vm/src/engine/thread.js ***! \******************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const log = __webpack_require__(/*! ../util/log */ "./node_modules/scratch-vm/src/util/log.js"); /** * Recycle bin for empty stackFrame objects * @type Array<_StackFrame> */ const _stackFrameFreeList = []; /** * A frame used for each level of the stack. A general purpose * place to store a bunch of execution context and parameters * @param {boolean} warpMode Whether this level of the stack is warping * @constructor * @private */ class _StackFrame { constructor(warpMode) { /** * Whether this level of the stack is a loop. * @type {boolean} */ this.isLoop = false; /** * Whether this level is in warp mode. Is set by some legacy blocks and * "turbo mode" * @type {boolean} */ this.warpMode = warpMode; /** * Reported value from just executed block. * @type {Any} */ this.justReported = null; /** * The active block that is waiting on a promise. * @type {string} */ this.reporting = ''; /** * Persists reported inputs during async block. * @type {Object} */ this.reported = null; /** * Name of waiting reporter. * @type {string} */ this.waitingReporter = null; /** * Procedure parameters. * @type {Object} */ this.params = null; /** * A context passed to block implementations. * @type {Object} */ this.executionContext = null; } /** * Reset all properties of the frame to pristine null and false states. * Used to recycle. * @return {_StackFrame} this */ reset() { this.isLoop = false; this.warpMode = false; this.justReported = null; this.reported = null; this.waitingReporter = null; this.params = null; this.executionContext = null; return this; } /** * Reuse an active stack frame in the stack. * @param {?boolean} warpMode defaults to current warpMode * @returns {_StackFrame} this */ reuse(warpMode = this.warpMode) { this.reset(); this.warpMode = Boolean(warpMode); return this; } /** * Create or recycle a stack frame object. * @param {boolean} warpMode Enable warpMode on this frame. * @returns {_StackFrame} The clean stack frame with correct warpMode setting. */ static create(warpMode) { const stackFrame = _stackFrameFreeList.pop(); if (typeof stackFrame !== 'undefined') { stackFrame.warpMode = Boolean(warpMode); return stackFrame; } return new _StackFrame(warpMode); } /** * Put a stack frame object into the recycle bin for reuse. * @param {_StackFrame} stackFrame The frame to reset and recycle. */ static release(stackFrame) { if (typeof stackFrame !== 'undefined') { _stackFrameFreeList.push(stackFrame.reset()); } } } /** * A thread is a running stack context and all the metadata needed. * @param {?string} firstBlock First block to execute in the thread. * @constructor */ class Thread { constructor(firstBlock) { /** * ID of top block of the thread * @type {!string} */ this.topBlock = firstBlock; /** * Stack for the thread. When the sequencer enters a control structure, * the block is pushed onto the stack so we know where to exit. * @type {Array.} */ this.stack = []; /** * Stack frames for the thread. Store metadata for the executing blocks. * @type {Array.<_StackFrame>} */ this.stackFrames = []; /** * Status of the thread, one of three states (below) * @type {number} */ this.status = 0; /* Thread.STATUS_RUNNING */ /** * Whether the thread is killed in the middle of execution. * @type {boolean} */ this.isKilled = false; /** * Target of this thread. * @type {?Target} */ this.target = null; /** * The Blocks this thread will execute. * @type {Blocks} */ this.blockContainer = null; /** * Whether the thread requests its script to glow during this frame. * @type {boolean} */ this.requestScriptGlowInFrame = false; /** * Which block ID should glow during this frame, if any. * @type {?string} */ this.blockGlowInFrame = null; /** * A timer for when the thread enters warp mode. * Substitutes the sequencer's count toward WORK_TIME on a per-thread basis. * @type {?Timer} */ this.warpTimer = null; this.justReported = null; this.triedToCompile = false; this.isCompiled = false; // compiler data // these values only make sense if isCompiled == true this.timer = null; /** * The thread's generator. * @type {Generator} */ this.generator = null; /** * @type {Object.} */ this.procedures = null; } /** * Thread status for initialized or running thread. * This is the default state for a thread - execution should run normally, * stepping from block to block. * @const */ static get STATUS_RUNNING() { return 0; // used by compiler } /** * Threads are in this state when a primitive is waiting on a promise; * execution is paused until the promise changes thread status. * @const */ static get STATUS_PROMISE_WAIT() { return 1; // used by compiler } /** * Thread status for yield. * @const */ static get STATUS_YIELD() { return 2; // used by compiler } /** * Thread status for a single-tick yield. This will be cleared when the * thread is resumed. * @const */ static get STATUS_YIELD_TICK() { return 3; // used by compiler } /** * Thread status for a finished/done thread. * Thread is in this state when there are no more blocks to execute. * @const */ static get STATUS_DONE() { return 4; // used by compiler } /** * @param {Target} target The target running the thread. * @param {string} topBlock ID of the thread's top block. * @returns {string} A unique ID for this target and thread. */ static getIdFromTargetAndBlock(target, topBlock) { // & should never appear in any IDs, so we can use it as a separator return "".concat(target.id, "&").concat(topBlock); } getId() { return Thread.getIdFromTargetAndBlock(this.target, this.topBlock); } /** * Push stack and update stack frames appropriately. * @param {string} blockId Block ID to push to stack. */ pushStack(blockId) { this.stack.push(blockId); // Push an empty stack frame, if we need one. // Might not, if we just popped the stack. if (this.stack.length > this.stackFrames.length) { const parent = this.stackFrames[this.stackFrames.length - 1]; this.stackFrames.push(_StackFrame.create(typeof parent !== 'undefined' && parent.warpMode)); } } /** * Reset the stack frame for use by the next block. * (avoids popping and re-pushing a new stack frame - keeps the warpmode the same * @param {string} blockId Block ID to push to stack. */ reuseStackForNextBlock(blockId) { this.stack[this.stack.length - 1] = blockId; this.stackFrames[this.stackFrames.length - 1].reuse(); } /** * Pop last block on the stack and its stack frame. * @return {string} Block ID popped from the stack. */ popStack() { _StackFrame.release(this.stackFrames.pop()); return this.stack.pop(); } /** * Pop back down the stack frame until we hit a procedure call or the stack frame is emptied */ stopThisScript() { let blockID = this.peekStack(); while (blockID !== null) { const block = this.target.blocks.getBlock(blockID); if (typeof block !== 'undefined' && block.opcode === 'procedures_call') { break; } this.popStack(); blockID = this.peekStack(); } if (this.stack.length === 0) { // Clean up! this.requestScriptGlowInFrame = false; this.status = Thread.STATUS_DONE; } } /** * Get top stack item. * @return {?string} Block ID on top of stack. */ peekStack() { return this.stack.length > 0 ? this.stack[this.stack.length - 1] : null; } /** * Get top stack frame. * @return {?object} Last stack frame stored on this thread. */ peekStackFrame() { return this.stackFrames.length > 0 ? this.stackFrames[this.stackFrames.length - 1] : null; } /** * Get stack frame above the current top. * @return {?object} Second to last stack frame stored on this thread. */ peekParentStackFrame() { return this.stackFrames.length > 1 ? this.stackFrames[this.stackFrames.length - 2] : null; } /** * Push a reported value to the parent of the current stack frame. * @param {*} value Reported value to push. */ pushReportedValue(value) { this.justReported = typeof value === 'undefined' ? null : value; } /** * Initialize procedure parameters on this stack frame. */ initParams() { const stackFrame = this.peekStackFrame(); if (stackFrame.params === null) { stackFrame.params = {}; } } /** * Add a parameter to the stack frame. * Use when calling a procedure with parameter values. * @param {!string} paramName Name of parameter. * @param {*} value Value to set for parameter. */ pushParam(paramName, value) { const stackFrame = this.peekStackFrame(); stackFrame.params[paramName] = value; } /** * Get a parameter at the lowest possible level of the stack. * @param {!string} paramName Name of parameter. * @return {*} value Value for parameter. */ getParam(paramName) { for (let i = this.stackFrames.length - 1; i >= 0; i--) { const frame = this.stackFrames[i]; if (frame.params === null) { continue; } if (frame.params.hasOwnProperty(paramName)) { return frame.params[paramName]; } return null; } return null; } getAllparams() { const stackFrame = this.peekStackFrame(); return stackFrame.params; } /** * Whether the current execution of a thread is at the top of the stack. * @return {boolean} True if execution is at top of the stack. */ atStackTop() { return this.peekStack() === this.topBlock; } /** * Switch the thread to the next block at the current level of the stack. * For example, this is used in a standard sequence of blocks, * where execution proceeds from one block to the next. */ goToNextBlock() { const nextBlockId = this.target.blocks.getNextBlock(this.peekStack()); this.reuseStackForNextBlock(nextBlockId); } /** * Attempt to determine whether a procedure call is recursive, * by examining the stack. * @param {!string} procedureCode Procedure code of procedure being called. * @return {boolean} True if the call appears recursive. */ isRecursiveCall(procedureCode) { let callCount = 5; // Max number of enclosing procedure calls to examine. const sp = this.stack.length - 1; for (let i = sp - 1; i >= 0; i--) { const block = this.target.blocks.getBlock(this.stack[i]); if (block.opcode === 'procedures_call' && block.mutation.proccode === procedureCode) { return true; } if (--callCount < 0) return false; } return false; } /** * Attempt to compile this thread. */ tryCompile() { if (!this.blockContainer) { return; } // importing the compiler here avoids circular dependency issues const compile = __webpack_require__(/*! ../compiler/compile */ "./node_modules/scratch-vm/src/compiler/compile.js"); this.triedToCompile = true; const topBlock = this.topBlock; // Flyout blocks are stored in a special block container. const blocks = this.blockContainer.getBlock(topBlock) ? this.blockContainer : this.target.runtime.flyoutBlocks; const cachedResult = blocks.getCachedCompileResult(topBlock); // If there is a cached error, do not attempt to recompile. if (cachedResult && !cachedResult.success) { return; } let result; if (cachedResult) { result = cachedResult.value; } else { try { result = compile(this); blocks.cacheCompileResult(topBlock, result); } catch (error) { log.error('cannot compile script', this.target.getName(), error); blocks.cacheCompileError(topBlock, error); this.target.runtime.emitCompileError(this.target, error); return; } } this.procedures = {}; for (const procedureCode of Object.keys(result.procedures)) { this.procedures[procedureCode] = result.procedures[procedureCode](this); } this.generator = result.startingFunction(this)(); if (!this.blockContainer.forceNoGlow) { this.blockGlowInFrame = this.topBlock; this.requestScriptGlowInFrame = true; } this.isCompiled = true; } } module.exports = Thread; /***/ }), /***/ "./node_modules/scratch-vm/src/engine/tw-frame-loop.js": /*!*************************************************************!*\ !*** ./node_modules/scratch-vm/src/engine/tw-frame-loop.js ***! \*************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { // Due to the existence of features such as interpolation and "0 FPS" being treated as "screen refresh rate", // The VM loop logic has become much more complex // Use setTimeout to polyfill requestAnimationFrame in Node.js environments const _requestAnimationFrame = typeof requestAnimationFrame === 'function' ? requestAnimationFrame : f => setTimeout(f, 1000 / 60); const _cancelAnimationFrame = typeof requestAnimationFrame === 'function' ? cancelAnimationFrame : clearTimeout; const animationFrameWrapper = callback => { let id; const handle = () => { id = _requestAnimationFrame(handle); callback(); }; const cancel = () => _cancelAnimationFrame(id); id = _requestAnimationFrame(handle); return { cancel }; }; class FrameLoop { constructor(runtime) { this.runtime = runtime; this.running = false; this.setFramerate(30); this.setInterpolation(false); this.stepCallback = this.stepCallback.bind(this); this.interpolationCallback = this.interpolationCallback.bind(this); this._stepInterval = null; this._interpolationAnimation = null; this._stepAnimation = null; } setFramerate(fps) { this.framerate = fps; this._restart(); } setInterpolation(interpolation) { this.interpolation = interpolation; this._restart(); } stepCallback() { this.runtime._step(); } interpolationCallback() { this.runtime._renderInterpolatedPositions(); } _restart() { if (this.running) { this.stop(); this.start(); } } start() { this.running = true; if (this.framerate === 0) { this._stepAnimation = animationFrameWrapper(this.stepCallback); this.runtime.currentStepTime = 1000 / 60; } else { // Interpolation should never be enabled when framerate === 0 as that's just redundant if (this.interpolation) { this._interpolationAnimation = animationFrameWrapper(this.interpolationCallback); } this._stepInterval = setInterval(this.stepCallback, 1000 / this.framerate); this.runtime.currentStepTime = 1000 / this.framerate; } } stop() { this.running = false; clearInterval(this._stepInterval); if (this._interpolationAnimation) { this._interpolationAnimation.cancel(); } if (this._stepAnimation) { this._stepAnimation.cancel(); } this._interpolationAnimation = null; this._stepAnimation = null; } } module.exports = FrameLoop; /***/ }), /***/ "./node_modules/scratch-vm/src/engine/tw-interpolate.js": /*!**************************************************************!*\ !*** ./node_modules/scratch-vm/src/engine/tw-interpolate.js ***! \**************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /** * Prepare the targets of a runtime for interpolation. * @param {Runtime} runtime The Runtime with targets to prepare for interpolation. */ const setupInitialState = runtime => { const renderer = runtime.renderer; for (const target of runtime.targets) { const directionAndScale = target._getRenderedDirectionAndScale(); // If sprite may have been interpolated in the previous frame, reset its renderer state. if (renderer && target.interpolationData) { const drawableID = target.drawableID; renderer.updateDrawablePosition(drawableID, [target.x, target.y]); renderer.updateDrawableDirectionScale(drawableID, directionAndScale.direction, directionAndScale.scale); renderer.updateDrawableEffect(drawableID, 'ghost', target.effects.ghost); } if (target.visible && !target.isStage) { target.interpolationData = { x: target.x, y: target.y, direction: directionAndScale.direction, scale: directionAndScale.scale, costume: target.currentCostume, ghost: target.effects.ghost }; } else { target.interpolationData = null; } } }; /** * Interpolate the position of targets. * @param {Runtime} runtime The Runtime with targets to interpolate. * @param {number} time Relative time in the frame in [0-1]. */ const interpolate = (runtime, time) => { const renderer = runtime.renderer; if (!renderer) { return; } for (const target of runtime.targets) { // interpolationData is the initial state at the start of the frame (time 0) // the state on the target itself is the state at the end of the frame (time 1) const interpolationData = target.interpolationData; if (!interpolationData) { continue; } // Don't waste time interpolating sprites that are hidden. if (!target.visible) { continue; } const drawableID = target.drawableID; // Position interpolation. const xDistance = target.x - interpolationData.x; const yDistance = target.y - interpolationData.y; const absoluteXDistance = Math.abs(xDistance); const absoluteYDistance = Math.abs(yDistance); if (absoluteXDistance > 0.1 || absoluteYDistance > 0.1) { const drawable = renderer._allDrawables[drawableID]; // Large movements are likely intended to be instantaneous. // getAABB is less accurate than getBounds, but it's much faster const bounds = drawable.getAABB(); const tolerance = Math.min(240, Math.max(50, 1.5 * (bounds.width + bounds.height))); const distance = Math.sqrt(absoluteXDistance ** 2 + absoluteYDistance ** 2); if (distance < tolerance) { const newX = interpolationData.x + xDistance * time; const newY = interpolationData.y + yDistance * time; renderer.updateDrawablePosition(drawableID, [newX, newY]); } } // Effect interpolation. const ghostChange = target.effects.ghost - interpolationData.ghost; const absoluteGhostChange = Math.abs(ghostChange); // Large changes are likely intended to be instantaneous. if (absoluteGhostChange > 0 && absoluteGhostChange < 25) { const newGhost = target.effects.ghost + ghostChange * time; renderer.updateDrawableEffect(drawableID, 'ghost', newGhost); } // Interpolate scale and direction. const costumeUnchanged = interpolationData.costume === target.currentCostume; if (costumeUnchanged) { let { direction, scale } = target._getRenderedDirectionAndScale(); let updateDrawableDirectionScale = false; // Interpolate direction. if (direction !== interpolationData.direction) { // Perfect 90 degree angles should not be interpolated. // eg. the foreground tile clones in https://scratch.mit.edu/projects/60917032/ if (direction % 90 !== 0 || interpolationData.direction % 90 !== 0) { const currentRadians = direction * Math.PI / 180; const startingRadians = interpolationData.direction * Math.PI / 180; direction = Math.atan2(Math.sin(currentRadians) * time + Math.sin(startingRadians) * (1 - time), Math.cos(currentRadians) * time + Math.cos(startingRadians) * (1 - time)) * 180 / Math.PI; updateDrawableDirectionScale = true; } } // Interpolate scale. const startingScale = interpolationData.scale; if (scale[0] !== startingScale[0] || scale[1] !== startingScale[1]) { // Do not interpolate size when the sign of either scale differs. if (Math.sign(scale[0]) === Math.sign(startingScale[0]) && Math.sign(scale[1]) === Math.sign(startingScale[1])) { const changeX = scale[0] - startingScale[0]; const changeY = scale[1] - startingScale[1]; const absoluteChangeX = Math.abs(changeX); const absoluteChangeY = Math.abs(changeY); // Large changes are likely intended to be instantaneous. if (absoluteChangeX < 100 && absoluteChangeY < 100) { scale[0] = startingScale[0] + changeX * time; scale[1] = startingScale[1] + changeY * time; updateDrawableDirectionScale = true; } } } if (updateDrawableDirectionScale) { renderer.updateDrawableDirectionScale(drawableID, direction, scale); } } } }; module.exports = { setupInitialState, interpolate }; /***/ }), /***/ "./node_modules/scratch-vm/src/engine/variable.js": /*!********************************************************!*\ !*** ./node_modules/scratch-vm/src/engine/variable.js ***! \********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /** * @fileoverview * Object representing a Scratch variable. */ const uid = __webpack_require__(/*! ../util/uid */ "./node_modules/scratch-vm/src/util/uid.js"); const xmlEscape = __webpack_require__(/*! ../util/xml-escape */ "./node_modules/scratch-vm/src/util/xml-escape.js"); class Variable { /** * @param {string} id Id of the variable. * @param {string} name Name of the variable. * @param {string} type Type of the variable, one of '' or 'list' * @param {boolean} isCloud Whether the variable is stored in the cloud. * @constructor */ constructor(id, name, type, isCloud) { this.id = id || uid(); this.name = name; this.type = type; this.isCloud = isCloud; switch (this.type) { case Variable.SCALAR_TYPE: this.value = 0; break; case Variable.LIST_TYPE: this.value = []; break; case Variable.BROADCAST_MESSAGE_TYPE: this.value = this.name; break; default: throw new Error("Invalid variable type: ".concat(this.type)); } } toXML(isLocal) { isLocal = isLocal === true; return "").concat(xmlEscape(this.name), ""); } /** * Type representation for scalar variables. * This is currently represented as '' * for compatibility with blockly. * @const {string} */ static get SCALAR_TYPE() { return ''; // used by compiler } /** * Type representation for list variables. * @const {string} */ static get LIST_TYPE() { return 'list'; // used by compiler } /** * Type representation for list variables. * @const {string} */ static get BROADCAST_MESSAGE_TYPE() { return 'broadcast_msg'; } } module.exports = Variable; /***/ }), /***/ "./node_modules/scratch-vm/src/extension-support/argument-type.js": /*!************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extension-support/argument-type.js ***! \************************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /** * Block argument types * @enum {string} */ const ArgumentType = { /** * Numeric value with angle picker */ ANGLE: 'angle', /** * Boolean value with hexagonal placeholder */ BOOLEAN: 'Boolean', /** * Numeric value with color picker */ COLOR: 'color', /** * Numeric value with text field */ NUMBER: 'number', /** * String value with text field */ STRING: 'string', /** * String value with matrix field */ MATRIX: 'matrix', /** * MIDI note number with note picker (piano) field */ NOTE: 'note', /** * Inline image on block (as part of the label) */ IMAGE: 'image' }; module.exports = ArgumentType; /***/ }), /***/ "./node_modules/scratch-vm/src/extension-support/block-type.js": /*!*********************************************************************!*\ !*** ./node_modules/scratch-vm/src/extension-support/block-type.js ***! \*********************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /** * Types of block * @enum {string} */ const BlockType = { /** * Boolean reporter with hexagonal shape */ BOOLEAN: 'Boolean', /** * A button (not an actual block) for some special action, like making a variable */ BUTTON: 'button', /** * Command block */ COMMAND: 'command', /** * Specialized command block which may or may not run a child branch * The thread continues with the next block whether or not a child branch ran. */ CONDITIONAL: 'conditional', /** * Specialized hat block with no implementation function * This stack only runs if the corresponding event is emitted by other code. */ EVENT: 'event', /** * Hat block which conditionally starts a block stack */ HAT: 'hat', /** * Specialized command block which may or may not run a child branch * If a child branch runs, the thread evaluates the loop block again. */ LOOP: 'loop', /** * General reporter with numeric or string value */ REPORTER: 'reporter' }; module.exports = BlockType; /***/ }), /***/ "./node_modules/scratch-vm/src/extension-support/extension-manager.js": /*!****************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extension-support/extension-manager.js ***! \****************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const dispatch = __webpack_require__(/*! ../dispatch/central-dispatch */ "./node_modules/scratch-vm/src/dispatch/central-dispatch.js"); const log = __webpack_require__(/*! ../util/log */ "./node_modules/scratch-vm/src/util/log.js"); const maybeFormatMessage = __webpack_require__(/*! ../util/maybe-format-message */ "./node_modules/scratch-vm/src/util/maybe-format-message.js"); const BlockType = __webpack_require__(/*! ./block-type */ "./node_modules/scratch-vm/src/extension-support/block-type.js"); const SecurityManager = __webpack_require__(/*! ./tw-security-manager */ "./node_modules/scratch-vm/src/extension-support/tw-security-manager.js"); // These extensions are currently built into the VM repository but should not be loaded at startup. // TODO: move these out into a separate repository? // TODO: change extension spec so that library info, including extension ID, can be collected through static methods const builtinExtensions = { // This is an example that isn't loaded with the other core blocks, // but serves as a reference for loading core blocks as extensions. coreExample: () => __webpack_require__(/*! ../blocks/scratch3_core_example */ "./node_modules/scratch-vm/src/blocks/scratch3_core_example.js"), // These are the non-core built-in extensions. pen: () => __webpack_require__(/*! ../extensions/scratch3_pen */ "./node_modules/scratch-vm/src/extensions/scratch3_pen/index.js"), wedo2: () => __webpack_require__(/*! ../extensions/scratch3_wedo2 */ "./node_modules/scratch-vm/src/extensions/scratch3_wedo2/index.js"), music: () => __webpack_require__(/*! ../extensions/scratch3_music */ "./node_modules/scratch-vm/src/extensions/scratch3_music/index.js"), microbit: () => __webpack_require__(/*! ../extensions/scratch3_microbit */ "./node_modules/scratch-vm/src/extensions/scratch3_microbit/index.js"), text2speech: () => __webpack_require__(/*! ../extensions/scratch3_text2speech */ "./node_modules/scratch-vm/src/extensions/scratch3_text2speech/index.js"), translate: () => __webpack_require__(/*! ../extensions/scratch3_translate */ "./node_modules/scratch-vm/src/extensions/scratch3_translate/index.js"), videoSensing: () => __webpack_require__(/*! ../extensions/scratch3_video_sensing */ "./node_modules/scratch-vm/src/extensions/scratch3_video_sensing/index.js"), ev3: () => __webpack_require__(/*! ../extensions/scratch3_ev3 */ "./node_modules/scratch-vm/src/extensions/scratch3_ev3/index.js"), makeymakey: () => __webpack_require__(/*! ../extensions/scratch3_makeymakey */ "./node_modules/scratch-vm/src/extensions/scratch3_makeymakey/index.js"), boost: () => __webpack_require__(/*! ../extensions/scratch3_boost */ "./node_modules/scratch-vm/src/extensions/scratch3_boost/index.js"), gdxfor: () => __webpack_require__(/*! ../extensions/scratch3_gdx_for */ "./node_modules/scratch-vm/src/extensions/scratch3_gdx_for/index.js"), // tw: core extension tw: () => __webpack_require__(/*! ../extensions/tw */ "./node_modules/scratch-vm/src/extensions/tw/index.js") }; /** * @typedef {object} ArgumentInfo - Information about an extension block argument * @property {ArgumentType} type - the type of value this argument can take * @property {*|undefined} default - the default value of this argument (default: blank) */ /** * @typedef {object} ConvertedBlockInfo - Raw extension block data paired with processed data ready for scratch-blocks * @property {ExtensionBlockMetadata} info - the raw block info * @property {object} json - the scratch-blocks JSON definition for this block * @property {string} xml - the scratch-blocks XML definition for this block */ /** * @typedef {object} CategoryInfo - Information about a block category * @property {string} id - the unique ID of this category * @property {string} name - the human-readable name of this category * @property {string|undefined} blockIconURI - optional URI for the block icon image * @property {string} color1 - the primary color for this category, in '#rrggbb' format * @property {string} color2 - the secondary color for this category, in '#rrggbb' format * @property {string} color3 - the tertiary color for this category, in '#rrggbb' format * @property {Array.} blocks - the blocks, separators, etc. in this category * @property {Array.} menus - the menus provided by this category */ /** * @typedef {object} PendingExtensionWorker - Information about an extension worker still initializing * @property {string} extensionURL - the URL of the extension to be loaded by this worker * @property {Function} resolve - function to call on successful worker startup * @property {Function} reject - function to call on failed worker startup */ const createExtensionService = extensionManager => { const service = {}; service.registerExtensionServiceSync = extensionManager.registerExtensionServiceSync.bind(extensionManager); service.allocateWorker = extensionManager.allocateWorker.bind(extensionManager); service.onWorkerInit = extensionManager.onWorkerInit.bind(extensionManager); service.registerExtensionService = extensionManager.registerExtensionService.bind(extensionManager); return service; }; class ExtensionManager { constructor(vm) { /** * The ID number to provide to the next extension worker. * @type {int} */ this.nextExtensionWorker = 0; /** * FIFO queue of extensions which have been requested but not yet loaded in a worker, * along with promise resolution functions to call once the worker is ready or failed. * * @type {Array.} */ this.pendingExtensions = []; /** * Map of worker ID to workers which have been allocated but have not yet finished initialization. * @type {Array.} */ this.pendingWorkers = []; /** * Map of worker ID to the URL where it was loaded from. * @type {Array} */ this.workerURLs = []; /** * Map of loaded extension URLs/IDs to service names. * @type {Map.} * @private */ this._loadedExtensions = new Map(); /** * Responsible for determining security policies related to custom extensions. */ this.securityManager = new SecurityManager(); /** * @type {VirtualMachine} */ this.vm = vm; /** * Keep a reference to the runtime so we can construct internal extension objects. * TODO: remove this in favor of extensions accessing the runtime as a service. * @type {Runtime} */ this.runtime = vm.runtime; this.loadingAsyncExtensions = 0; this.asyncExtensionsLoadedCallbacks = []; dispatch.setService('extensions', createExtensionService(this)).catch(e => { log.error("ExtensionManager was unable to register extension service: ".concat(JSON.stringify(e))); }); } /** * Check whether an extension is registered or is in the process of loading. This is intended to control loading or * adding extensions so it may return `true` before the extension is ready to be used. Use the promise returned by * `loadExtensionURL` if you need to wait until the extension is truly ready. * @param {string} extensionID - the ID of the extension. * @returns {boolean} - true if loaded, false otherwise. */ isExtensionLoaded(extensionID) { return this._loadedExtensions.has(extensionID); } /** * Determine whether an extension with a given ID is built in to the VM, such as pen. * Note that "core extensions" like motion will return false here. * @param {string} extensionId * @returns {boolean} */ isBuiltinExtension(extensionId) { return Object.prototype.hasOwnProperty.call(builtinExtensions, extensionId); } /** * Synchronously load an internal extension (core or non-core) by ID. This call will * fail if the provided id is not does not match an internal extension. * @param {string} extensionId - the ID of an internal extension */ loadExtensionIdSync(extensionId) { if (!this.isBuiltinExtension(extensionId)) { log.warn("Could not find extension ".concat(extensionId, " in the built in extensions.")); return; } /** @TODO dupe handling for non-builtin extensions. See commit 670e51d33580e8a2e852b3b038bb3afc282f81b9 */ if (this.isExtensionLoaded(extensionId)) { const message = "Rejecting attempt to load a second extension with ID ".concat(extensionId); log.warn(message); return; } const extension = builtinExtensions[extensionId](); const extensionInstance = new extension(this.runtime); const serviceName = this._registerInternalExtension(extensionInstance); this._loadedExtensions.set(extensionId, serviceName); this.runtime.compilerRegisterExtension(extensionId, extensionInstance); } _isValidExtensionURL(extensionURL) { try { const parsedURL = new URL(extensionURL); return parsedURL.protocol === 'https:' || parsedURL.protocol === 'http:' || parsedURL.protocol === 'data:' || parsedURL.protocol === 'file:'; } catch (e) { return false; } } /** * Load an extension by URL or internal extension ID * @param {string} extensionURL - the URL for the extension to load OR the ID of an internal extension * @returns {Promise} resolved once the extension is loaded and initialized or rejected on failure */ async loadExtensionURL(extensionURL) { if (this.isBuiltinExtension(extensionURL)) { this.loadExtensionIdSync(extensionURL); return; } if (!this._isValidExtensionURL(extensionURL)) { throw new Error("Invalid extension URL: ".concat(extensionURL)); } this.loadingAsyncExtensions++; const sandboxMode = await this.securityManager.getSandboxMode(extensionURL); if (sandboxMode === 'unsandboxed') { const { load } = __webpack_require__(/*! ./tw-unsandboxed-extension-runner */ "./node_modules/scratch-vm/src/extension-support/tw-unsandboxed-extension-runner.js"); const extensionObjects = await load(extensionURL, this.vm).catch(error => this._failedLoadingExtensionScript(error)); const fakeWorkerId = this.nextExtensionWorker++; this.workerURLs[fakeWorkerId] = extensionURL; for (const extensionObject of extensionObjects) { const extensionInfo = extensionObject.getInfo(); const serviceName = "unsandboxed.".concat(fakeWorkerId, ".").concat(extensionInfo.id); dispatch.setServiceSync(serviceName, extensionObject); dispatch.callSync('extensions', 'registerExtensionServiceSync', serviceName); this._loadedExtensions.set(extensionInfo.id, serviceName); } this._finishedLoadingExtensionScript(); return; } /* eslint-disable max-len */ let ExtensionWorker; if (sandboxMode === 'worker') { ExtensionWorker = __webpack_require__(/*! worker-loader?name=js/extension-worker/extension-worker.[hash].js!./extension-worker */ "./node_modules/scratch-vm/node_modules/worker-loader/dist/cjs.js?name=js/extension-worker/extension-worker.[hash].js!./node_modules/scratch-vm/src/extension-support/extension-worker.js"); } else if (sandboxMode === 'iframe') { ExtensionWorker = (await __webpack_require__.e(/*! import() | iframe-extension-worker */ "iframe-extension-worker").then(__webpack_require__.t.bind(null, /*! ./tw-iframe-extension-worker */ "./node_modules/scratch-vm/src/extension-support/tw-iframe-extension-worker.js", 7))).default; } else { throw new Error("Invalid sandbox mode: ".concat(sandboxMode)); } /* eslint-enable max-len */ return new Promise((resolve, reject) => { this.pendingExtensions.push({ extensionURL, resolve, reject }); dispatch.addWorker(new ExtensionWorker()); }).catch(error => this._failedLoadingExtensionScript(error)); } /** * Wait until all async extensions have loaded * @returns {Promise} resolved when all async extensions have loaded */ allAsyncExtensionsLoaded() { if (this.loadingAsyncExtensions === 0) { return; } return new Promise((resolve, reject) => { this.asyncExtensionsLoadedCallbacks.push({ resolve, reject }); }); } /** * Regenerate blockinfo for any loaded extensions * @returns {Promise} resolved once all the extensions have been reinitialized */ refreshBlocks() { const allPromises = Array.from(this._loadedExtensions.values()).map(serviceName => dispatch.call(serviceName, 'getInfo').then(info => { info = this._prepareExtensionInfo(serviceName, info); dispatch.call('runtime', '_refreshExtensionPrimitives', info); }).catch(e => { log.error("Failed to refresh built-in extension primitives: ".concat(JSON.stringify(e))); })); return Promise.all(allPromises); } allocateWorker() { const id = this.nextExtensionWorker++; const workerInfo = this.pendingExtensions.shift(); this.pendingWorkers[id] = workerInfo; this.workerURLs[id] = workerInfo.extensionURL; return [id, workerInfo.extensionURL]; } /** * Synchronously collect extension metadata from the specified service and begin the extension registration process. * @param {string} serviceName - the name of the service hosting the extension. */ registerExtensionServiceSync(serviceName) { const info = dispatch.callSync(serviceName, 'getInfo'); this._registerExtensionInfo(serviceName, info); } /** * Collect extension metadata from the specified service and begin the extension registration process. * @param {string} serviceName - the name of the service hosting the extension. */ registerExtensionService(serviceName) { dispatch.call(serviceName, 'getInfo').then(info => { this._loadedExtensions.set(info.id, serviceName); this._registerExtensionInfo(serviceName, info); this._finishedLoadingExtensionScript(); }); } _finishedLoadingExtensionScript() { this.loadingAsyncExtensions--; if (this.loadingAsyncExtensions === 0) { this.asyncExtensionsLoadedCallbacks.forEach(i => i.resolve()); this.asyncExtensionsLoadedCallbacks = []; } } _failedLoadingExtensionScript(error) { // Don't set the current extension counter to 0, otherwise it will go negative if another // extension finishes or fails to load. this.loadingAsyncExtensions--; this.asyncExtensionsLoadedCallbacks.forEach(i => i.reject(error)); this.asyncExtensionsLoadedCallbacks = []; // Re-throw error so the promise still rejects. throw error; } /** * Called by an extension worker to indicate that the worker has finished initialization. * @param {int} id - the worker ID. * @param {*?} e - the error encountered during initialization, if any. */ onWorkerInit(id, e) { const workerInfo = this.pendingWorkers[id]; delete this.pendingWorkers[id]; if (e) { workerInfo.reject(e); } else { workerInfo.resolve(id); } } /** * Register an internal (non-Worker) extension object * @param {object} extensionObject - the extension object to register * @returns {string} The name of the registered extension service */ _registerInternalExtension(extensionObject) { const extensionInfo = extensionObject.getInfo(); const fakeWorkerId = this.nextExtensionWorker++; const serviceName = "extension_".concat(fakeWorkerId, "_").concat(extensionInfo.id); dispatch.setServiceSync(serviceName, extensionObject); dispatch.callSync('extensions', 'registerExtensionServiceSync', serviceName); return serviceName; } /** * Sanitize extension info then register its primitives with the VM. * @param {string} serviceName - the name of the service hosting the extension * @param {ExtensionInfo} extensionInfo - the extension's metadata * @private */ _registerExtensionInfo(serviceName, extensionInfo) { extensionInfo = this._prepareExtensionInfo(serviceName, extensionInfo); dispatch.call('runtime', '_registerExtensionPrimitives', extensionInfo).catch(e => { log.error("Failed to register primitives for extension on service ".concat(serviceName, ":"), e); }); } /** * Modify the provided text as necessary to ensure that it may be used as an attribute value in valid XML. * @param {string} text - the text to be sanitized * @returns {string} - the sanitized text * @private */ _sanitizeID(text) { return text.toString().replace(/[<"&]/, '_'); } /** * Apply minor cleanup and defaults for optional extension fields. * TODO: make the ID unique in cases where two copies of the same extension are loaded. * @param {string} serviceName - the name of the service hosting this extension block * @param {ExtensionInfo} extensionInfo - the extension info to be sanitized * @returns {ExtensionInfo} - a new extension info object with cleaned-up values * @private */ _prepareExtensionInfo(serviceName, extensionInfo) { extensionInfo = Object.assign({}, extensionInfo); if (!/^[a-z0-9]+$/i.test(extensionInfo.id)) { throw new Error('Invalid extension id'); } extensionInfo.name = extensionInfo.name || extensionInfo.id; extensionInfo.blocks = extensionInfo.blocks || []; extensionInfo.targetTypes = extensionInfo.targetTypes || []; extensionInfo.blocks = extensionInfo.blocks.reduce((results, blockInfo) => { try { let result; switch (blockInfo) { case '---': // separator result = '---'; break; default: // an ExtensionBlockMetadata object result = this._prepareBlockInfo(serviceName, blockInfo); break; } results.push(result); } catch (e) { // TODO: more meaningful error reporting log.error("Error processing block: ".concat(e.message, ", Block:\n").concat(JSON.stringify(blockInfo))); } return results; }, []); extensionInfo.menus = extensionInfo.menus || {}; extensionInfo.menus = this._prepareMenuInfo(serviceName, extensionInfo.menus); return extensionInfo; } /** * Prepare extension menus. e.g. setup binding for dynamic menu functions. * @param {string} serviceName - the name of the service hosting this extension block * @param {Array.} menus - the menu defined by the extension. * @returns {Array.} - a menuInfo object with all preprocessing done. * @private */ _prepareMenuInfo(serviceName, menus) { const menuNames = Object.getOwnPropertyNames(menus); for (let i = 0; i < menuNames.length; i++) { const menuName = menuNames[i]; let menuInfo = menus[menuName]; // If the menu description is in short form (items only) then normalize it to general form: an object with // its items listed in an `items` property. if (!menuInfo.items) { menuInfo = { items: menuInfo }; menus[menuName] = menuInfo; } // If `items` is a string, it should be the name of a function in the extension object. Calling the // function should return an array of items to populate the menu when it is opened. if (typeof menuInfo.items === 'string') { const menuItemFunctionName = menuInfo.items; const serviceObject = dispatch.services[serviceName]; // Bind the function here so we can pass a simple item generation function to Scratch Blocks later. menuInfo.items = this._getExtensionMenuItems.bind(this, serviceObject, menuItemFunctionName); } } return menus; } /** * Fetch the items for a particular extension menu, providing the target ID for context. * @param {object} extensionObject - the extension object providing the menu. * @param {string} menuItemFunctionName - the name of the menu function to call. * @returns {Array} menu items ready for scratch-blocks. * @private */ _getExtensionMenuItems(extensionObject, menuItemFunctionName) { // Fetch the items appropriate for the target currently being edited. This assumes that menus only // collect items when opened by the user while editing a particular target. const editingTarget = this.runtime.getEditingTarget() || this.runtime.getTargetForStage(); const editingTargetID = editingTarget ? editingTarget.id : null; const extensionMessageContext = this.runtime.makeMessageContextForTarget(editingTarget); // TODO: Fix this to use dispatch.call when extensions are running in workers. const menuFunc = extensionObject[menuItemFunctionName]; const menuItems = menuFunc.call(extensionObject, editingTargetID).map(item => { item = maybeFormatMessage(item, extensionMessageContext); switch (typeof item) { case 'object': return [maybeFormatMessage(item.text, extensionMessageContext), item.value]; case 'string': return [item, item]; default: return item; } }); if (!menuItems || menuItems.length < 1) { throw new Error("Extension menu returned no items: ".concat(menuItemFunctionName)); } return menuItems; } /** * Apply defaults for optional block fields. * @param {string} serviceName - the name of the service hosting this extension block * @param {ExtensionBlockMetadata} blockInfo - the block info from the extension * @returns {ExtensionBlockMetadata} - a new block info object which has values for all relevant optional fields. * @private */ _prepareBlockInfo(serviceName, blockInfo) { blockInfo = Object.assign({}, { blockType: BlockType.COMMAND, terminal: false, blockAllThreads: false, arguments: {} }, blockInfo); blockInfo.opcode = blockInfo.opcode && this._sanitizeID(blockInfo.opcode); blockInfo.text = blockInfo.text || blockInfo.opcode; switch (blockInfo.blockType) { case BlockType.EVENT: if (blockInfo.func) { log.warn("Ignoring function \"".concat(blockInfo.func, "\" for event block ").concat(blockInfo.opcode)); } break; case BlockType.BUTTON: if (blockInfo.opcode) { log.warn("Ignoring opcode \"".concat(blockInfo.opcode, "\" for button with text: ").concat(blockInfo.text)); } break; default: { if (!blockInfo.opcode) { throw new Error('Missing opcode for block'); } const funcName = blockInfo.func ? this._sanitizeID(blockInfo.func) : blockInfo.opcode; const getBlockInfo = blockInfo.isDynamic ? args => args && args.mutation && args.mutation.blockInfo : () => blockInfo; const callBlockFunc = (() => { if (dispatch._isRemoteService(serviceName)) { return (args, util, realBlockInfo) => dispatch.call(serviceName, funcName, args, util, realBlockInfo).then(result => { // Scratch is only designed to handle these types. // If any other value comes in such as undefined, null, an object, etc. // we'll convert it to a string to avoid undefined behavior. if (typeof result === 'number' || typeof result === 'string' || typeof result === 'boolean') { return result; } return "".concat(result); }) // When an error happens, instead of returning undefined, we'll return a stringified // version of the error so that it can be debugged. .catch(err => { // We want the full error including stack to be printed but the log helper // messes with that. // eslint-disable-next-line no-console console.error('Custom extension block error', err); return "".concat(err); }); } // avoid promise latency if we can call direct const serviceObject = dispatch.services[serviceName]; if (!serviceObject[funcName]) { // The function might show up later as a dynamic property of the service object log.warn("Could not find extension block function called ".concat(funcName)); } return (args, util, realBlockInfo) => serviceObject[funcName](args, util, realBlockInfo); })(); blockInfo.func = (args, util) => { const realBlockInfo = getBlockInfo(args); // TODO: filter args using the keys of realBlockInfo.arguments? maybe only if sandboxed? return callBlockFunc(args, util, realBlockInfo); }; break; } } return blockInfo; } getExtensionURLs() { const extensionURLs = {}; for (const [extensionId, serviceName] of this._loadedExtensions.entries()) { if (builtinExtensions.hasOwnProperty(extensionId)) { continue; } // Service names for extension workers are in the format "extension.WORKER_ID.EXTENSION_ID" const workerId = +serviceName.split('.')[1]; const extensionURL = this.workerURLs[workerId]; if (typeof extensionURL === 'string') { extensionURLs[extensionId] = extensionURL; } } return extensionURLs; } } module.exports = ExtensionManager; /***/ }), /***/ "./node_modules/scratch-vm/src/extension-support/target-type.js": /*!**********************************************************************!*\ !*** ./node_modules/scratch-vm/src/extension-support/target-type.js ***! \**********************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /** * Default types of Target supported by the VM * @enum {string} */ const TargetType = { /** * Rendered target which can move, change costumes, etc. */ SPRITE: 'sprite', /** * Rendered target which cannot move but can change backdrops */ STAGE: 'stage' }; module.exports = TargetType; /***/ }), /***/ "./node_modules/scratch-vm/src/extension-support/tw-scratchx-compatibility-layer.js": /*!******************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extension-support/tw-scratchx-compatibility-layer.js ***! \******************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { // ScratchX API Documentation: https://github.com/LLK/scratchx/wiki/ // Global Scratch API from extension-worker.js /* globals Scratch */ const ArgumentType = __webpack_require__(/*! ./argument-type */ "./node_modules/scratch-vm/src/extension-support/argument-type.js"); const BlockType = __webpack_require__(/*! ./block-type */ "./node_modules/scratch-vm/src/extension-support/block-type.js"); const { argumentIndexToId, generateExtensionId } = __webpack_require__(/*! ./tw-scratchx-utilities */ "./node_modules/scratch-vm/src/extension-support/tw-scratchx-utilities.js"); /** * @typedef ScratchXDescriptor * @property {unknown[][]} blocks * @property {Record} [menus] * @property {string} [url] * @property {string} [displayName] */ /** * @typedef ScratchXStatus * @property {0|1|2} status 0 is red/error, 1 is yellow/not ready, 2 is green/ready * @property {string} msg */ const parseScratchXBlockType = type => { if (type === '' || type === ' ' || type === 'w') { return { type: BlockType.COMMAND, async: type === 'w' }; } if (type === 'r' || type === 'R') { return { type: BlockType.REPORTER, async: type === 'R' }; } if (type === 'b') { return { type: BlockType.BOOLEAN, // ScratchX docs don't seem to mention boolean reporters that wait async: false }; } if (type === 'h') { return { type: BlockType.HAT, async: false }; } throw new Error("Unknown ScratchX block type: ".concat(type)); }; const isScratchCompatibleValue = v => typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean'; /** * @param {string} argument ScratchX argument with leading % removed. * @param {unknown} defaultValue Default value, if any */ const parseScratchXArgument = (argument, defaultValue) => { const result = {}; const hasDefaultValue = isScratchCompatibleValue(defaultValue); if (hasDefaultValue) { result.defaultValue = defaultValue; } // TODO: ScratchX docs don't mention support for boolean arguments? if (argument === 's') { result.type = ArgumentType.STRING; if (!hasDefaultValue) { result.defaultValue = ''; } } else if (argument === 'n') { result.type = ArgumentType.NUMBER; if (!hasDefaultValue) { result.defaultValue = 0; } } else if (argument[0] === 'm') { result.type = ArgumentType.STRING; const split = argument.split(/\.|:/); const menuName = split[1]; result.menu = menuName; } else { throw new Error("Unknown ScratchX argument type: ".concat(argument)); } return result; }; const wrapScratchXFunction = (originalFunction, argumentCount, async) => args => { // Convert Scratch 3's argument object to an argument list expected by ScratchX const argumentList = []; for (let i = 0; i < argumentCount; i++) { argumentList.push(args[argumentIndexToId(i)]); } if (async) { return new Promise(resolve => { originalFunction(...argumentList, resolve); }); } return originalFunction(...argumentList); }; /** * @param {string} name * @param {ScratchXDescriptor} descriptor * @param {Record unknown>} functions */ const convert = (name, descriptor, functions) => { const extensionId = generateExtensionId(name); const info = { id: extensionId, name: descriptor.displayName || name, blocks: [], color1: '#4a4a5e', color2: '#31323f', color3: '#191a21' }; const scratch3Extension = { getInfo: () => info, _getStatus: functions._getStatus }; if (descriptor.url) { info.docsURI = descriptor.url; } for (const blockDescriptor of descriptor.blocks) { if (blockDescriptor.length === 1) { // Separator info.blocks.push('---'); continue; } const scratchXBlockType = blockDescriptor[0]; const blockText = blockDescriptor[1]; const functionName = blockDescriptor[2]; const defaultArgumentValues = blockDescriptor.slice(3); let scratchText = ''; const argumentInfo = []; const blockTextParts = blockText.split(/%([\w.:]+)/g); for (let i = 0; i < blockTextParts.length; i++) { const part = blockTextParts[i]; const isArgument = i % 2 === 1; if (isArgument) { parseScratchXArgument(part); const argumentIndex = Math.floor(i / 2).toString(); const argumentDefaultValue = defaultArgumentValues[argumentIndex]; const argumentId = argumentIndexToId(argumentIndex); argumentInfo[argumentId] = parseScratchXArgument(part, argumentDefaultValue); scratchText += "[".concat(argumentId, "]"); } else { scratchText += part; } } const scratch3BlockType = parseScratchXBlockType(scratchXBlockType); const blockInfo = { opcode: functionName, blockType: scratch3BlockType.type, text: scratchText, arguments: argumentInfo }; info.blocks.push(blockInfo); const originalFunction = functions[functionName]; const argumentCount = argumentInfo.length; scratch3Extension[functionName] = wrapScratchXFunction(originalFunction, argumentCount, scratch3BlockType.async); } const menus = descriptor.menus; if (menus) { const scratch3Menus = {}; for (const menuName of Object.keys(menus) || {}) { const menuItems = menus[menuName]; const menuInfo = { items: menuItems }; scratch3Menus[menuName] = menuInfo; } info.menus = scratch3Menus; } return scratch3Extension; }; const extensionNameToExtension = new Map(); const register = (name, descriptor, functions) => { const scratch3Extension = convert(name, descriptor, functions); extensionNameToExtension.set(name, scratch3Extension); Scratch.extensions.register(scratch3Extension); }; /** * @param {string} extensionName * @returns {ScratchXStatus} */ const getStatus = extensionName => { const extension = extensionNameToExtension.get(extensionName); if (extension) { return extension._getStatus(); } return { status: 0, msg: 'does not exist' }; }; module.exports = { register, getStatus, // For tests convert }; /***/ }), /***/ "./node_modules/scratch-vm/src/extension-support/tw-scratchx-utilities.js": /*!********************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extension-support/tw-scratchx-utilities.js ***! \********************************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /** * @fileoverview * General ScratchX-related utilities used in multiple places. * Changing these functions may break projects. */ /** * @param {string} scratchXName * @returns {string} */ const generateExtensionId = scratchXName => { const sanitizedName = scratchXName.replace(/[^a-z0-9]/gi, '').toLowerCase(); return "sbx".concat(sanitizedName); }; /** * @param {number} i 0-indexed index of argument in list * @returns {string} Scratch 3 argument name */ const argumentIndexToId = i => i.toString(); module.exports = { generateExtensionId, argumentIndexToId }; /***/ }), /***/ "./node_modules/scratch-vm/src/extension-support/tw-security-manager.js": /*!******************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extension-support/tw-security-manager.js ***! \******************************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /* eslint-disable no-unused-vars */ /** * Responsible for determining various policies related to custom extension security. * The default implementation attempts to retain compatibility with a vanilla scratch-vm * and ensure maximum security. You can manually opt-in to less security by overriding * methods. For example: * ```js * vm.securityManager.getSandboxMode = (url) => { * if (url.startsWith("https://example.com/")) { * return "unsandboxed"; * } * return "iframe"; * }; * vm.securityManager.canAutomaticallyLoadExtension = (url) => { * return confirm("Automatically load extension: " + url); * }; * ``` */ class SecurityManager { /** * Determine the typeof sandbox to use for a certain custom extension. * @param {string} extensionURL The URL of the custom extension. * @returns {Promise<'worker'|'iframe'|'unsandboxed'>} */ getSandboxMode(extensionURL) { // Default to worker for Scratch compatibility return Promise.resolve('worker'); } /** * Determine whether a custom extension that was stored inside a project may be * loaded. You could, for example, ask the user to confirm loading an extension * before resolving. * @param {string} extensionURL The URL of the custom extension. * @returns {Promise} */ canLoadExtensionFromProject(extensionURL) { // Default to false for security return Promise.resolve(false); } } module.exports = SecurityManager; /***/ }), /***/ "./node_modules/scratch-vm/src/extension-support/tw-unsandboxed-extension-runner.js": /*!******************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extension-support/tw-unsandboxed-extension-runner.js ***! \******************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(global) {const ArgumentType = __webpack_require__(/*! ../extension-support/argument-type */ "./node_modules/scratch-vm/src/extension-support/argument-type.js"); const BlockType = __webpack_require__(/*! ../extension-support/block-type */ "./node_modules/scratch-vm/src/extension-support/block-type.js"); const TargetType = __webpack_require__(/*! ../extension-support/target-type */ "./node_modules/scratch-vm/src/extension-support/target-type.js"); const AsyncLimiter = __webpack_require__(/*! ../util/async-limiter */ "./node_modules/scratch-vm/src/util/async-limiter.js"); /** * Sets up the global.Scratch API for an unsandboxed extension. * @param {VirtualMachine} vm * @returns {Promise} Resolves with a list of extension objects when Scratch.extensions.register is called. */ const createUnsandboxedExtensionAPI = vm => new Promise(resolve => { // Create a new copy of global.Scratch per-extension global.Scratch = Object.assign({}, global.Scratch || {}); global.Scratch.vm = vm; global.Scratch.renderer = vm.runtime.renderer; global.Scratch.ArgumentType = ArgumentType; global.Scratch.BlockType = BlockType; global.Scratch.TargetType = TargetType; const extensionObjects = []; const register = extensionObject => { extensionObjects.push(extensionObject); resolve(extensionObjects); }; global.Scratch.extensions = { unsandboxed: true, register }; global.ScratchExtensions = __webpack_require__(/*! ./tw-scratchx-compatibility-layer */ "./node_modules/scratch-vm/src/extension-support/tw-scratchx-compatibility-layer.js"); }); /** * Disable the existing global.Scratch unsandboxed extension APIs. * This helps debug poorly designed extensions. */ const teardownUnsandboxedExtensionAPI = () => { // We can assume global.Scratch already exists. global.Scratch.extensions.register = () => { throw new Error('Too late to register new extensions.'); }; }; /** * Load an unsandboxed extension from an arbitrary URL. This is dangerous. * @param {string} extensionURL * @param {Virtualmachine} vm * @returns {Promise} Resolves with a list of extension objects if the extension was loaded successfully. */ const loadUnsandboxedExtension = (extensionURL, vm) => new Promise((resolve, reject) => { createUnsandboxedExtensionAPI(vm).then(resolve); const script = document.createElement('script'); script.onerror = () => { reject(new Error("Error in unsandboxed script ".concat(extensionURL, ". Check the console for more information."))); }; script.src = extensionURL; document.body.appendChild(script); }).then(objects => { teardownUnsandboxedExtensionAPI(); return objects; }); // Because loading unsandboxed extensions requires messing with global state (global.Scratch), // only let one extension load at a time. const limiter = new AsyncLimiter(loadUnsandboxedExtension, 1); const load = (extensionURL, vm) => limiter.do(extensionURL, vm); module.exports = { createUnsandboxedExtensionAPI, load }; /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../../../webpack/buildin/global.js */ "./node_modules/webpack/buildin/global.js"))) /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_boost/index.js": /*!************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_boost/index.js ***! \************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const ArgumentType = __webpack_require__(/*! ../../extension-support/argument-type */ "./node_modules/scratch-vm/src/extension-support/argument-type.js"); const BlockType = __webpack_require__(/*! ../../extension-support/block-type */ "./node_modules/scratch-vm/src/extension-support/block-type.js"); const Cast = __webpack_require__(/*! ../../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); const formatMessage = __webpack_require__(/*! format-message */ "./node_modules/format-message/index.js"); const color = __webpack_require__(/*! ../../util/color */ "./node_modules/scratch-vm/src/util/color.js"); const BLE = __webpack_require__(/*! ../../io/ble */ "./node_modules/scratch-vm/src/io/ble.js"); const Base64Util = __webpack_require__(/*! ../../util/base64-util */ "./node_modules/scratch-vm/src/util/base64-util.js"); const MathUtil = __webpack_require__(/*! ../../util/math-util */ "./node_modules/scratch-vm/src/util/math-util.js"); const RateLimiter = __webpack_require__(/*! ../../util/rateLimiter.js */ "./node_modules/scratch-vm/src/util/rateLimiter.js"); const log = __webpack_require__(/*! ../../util/log */ "./node_modules/scratch-vm/src/util/log.js"); /** * The LEGO Wireless Protocol documentation used to create this extension can be found at: * https://lego.github.io/lego-ble-wireless-protocol-docs/index.html */ /** * Icon svg to be displayed at the left edge of each extension block, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len const iconURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACpQTFRF////fIel5ufolZ62/2YavsPS+YZOkJmy9/j53+Hk6+zs6N/b6dfO////tDhMHAAAAA50Uk5T/////////////////wBFwNzIAAAA6ElEQVR42uzX2w6DIBAEUGDVtlr//3dLaLwgiwUd2z7MJPJg5EQWiGhGcAxBggQJEiT436CIfqXJPTn3MKNYYMSDFpoAmp24OaYgvwKnFgL2zvVTCwHrMoMi+nUQLFthaNCCa0iwclLkDgYVsQp0mzxuqXgK1MRzoCLWgkPXNN2wI/q6Kvt7u/cX0HtejN8x2sXpnpb8J8D3b0Keuhh3X975M+i0xNVbg3s1TIasgK21bQyGO+s2PykaGMYbge8KrNrssvkOWDXkErB8UuBHETjoYLkKBA8ZfuDkbwVBggQJEiR4MC8BBgDTtMZLx2nFCQAAAABJRU5ErkJggg=='; /** * Boost BLE UUIDs. * @enum {string} */ const BoostBLE = { service: '00001623-1212-efde-1623-785feabcd123', characteristic: '00001624-1212-efde-1623-785feabcd123', sendInterval: 100, sendRateMax: 20 }; /** * Boost Motor Max Power Add. Defines how much more power than the target speed * the motors may supply to reach the target speed faster. * Lower number == softer, slower reached target speed. * Higher number == harder, faster reached target speed. * @constant {number} */ const BoostMotorMaxPowerAdd = 10; /** * A time interval to wait (in milliseconds) in between battery check calls. * @type {number} */ const BoostPingInterval = 5000; /** * The number of continuous samples the color-sensor will evaluate color from. * @type {number} */ const BoostColorSampleSize = 5; /** * Enum for Boost sensor and actuator types. * @readonly * @enum {number} */ const BoostIO = { MOTOR_WEDO: 0x01, MOTOR_SYSTEM: 0x02, BUTTON: 0x05, LIGHT: 0x08, VOLTAGE: 0x14, CURRENT: 0x15, PIEZO: 0x16, LED: 0x17, TILT_EXTERNAL: 0x22, MOTION_SENSOR: 0x23, COLOR: 0x25, MOTOREXT: 0x26, MOTORINT: 0x27, TILT: 0x28 }; /** * Enum for ids for various output command feedback types on the Boost. * @readonly * @enum {number} */ const BoostPortFeedback = { IN_PROGRESS: 0x01, COMPLETED: 0x02, DISCARDED: 0x04, IDLE: 0x08, BUSY_OR_FULL: 0x10 }; /** * Enum for physical Boost Ports * @readonly * @enum {number} */ const BoostPort10000223OrOlder = { A: 55, B: 56, C: 1, D: 2 }; const BoostPort10000224OrNewer = { A: 0, B: 1, C: 2, D: 3 }; // Set default port mapping to support the newer firmware let BoostPort = BoostPort10000224OrNewer; /** * Ids for each color sensor value used by the extension. * @readonly * @enum {string} */ const BoostColor = { ANY: 'any', NONE: 'none', RED: 'red', BLUE: 'blue', GREEN: 'green', YELLOW: 'yellow', WHITE: 'white', BLACK: 'black' }; /** * Enum for indices for each color sensed by the Boost vision sensor. * @readonly * @enum {number} */ const BoostColorIndex = { [BoostColor.NONE]: 255, [BoostColor.RED]: 9, [BoostColor.BLUE]: 3, [BoostColor.GREEN]: 5, [BoostColor.YELLOW]: 7, [BoostColor.WHITE]: 10, [BoostColor.BLACK]: 0 }; /** * Enum for Message Types * @readonly * @enum {number} */ const BoostMessage = { HUB_PROPERTIES: 0x01, HUB_ACTIONS: 0x02, HUB_ALERTS: 0x03, HUB_ATTACHED_IO: 0x04, ERROR: 0x05, PORT_INPUT_FORMAT_SETUP_SINGLE: 0x41, PORT_INPUT_FORMAT_SETUP_COMBINED: 0x42, PORT_INFORMATION: 0x43, PORT_MODEINFORMATION: 0x44, PORT_VALUE: 0x45, PORT_VALUE_COMBINED: 0x46, PORT_INPUT_FORMAT: 0x47, PORT_INPUT_FORMAT_COMBINED: 0x48, OUTPUT: 0x81, PORT_FEEDBACK: 0x82 }; /** * Enum for Hub Property Types * @readonly * @enum {number} */ const BoostHubProperty = { ADVERTISEMENT_NAME: 0x01, BUTTON: 0x02, FW_VERSION: 0x03, HW_VERSION: 0x04, RSSI: 0x05, BATTERY_VOLTAGE: 0x06, BATTERY_TYPE: 0x07, MANUFACTURER_NAME: 0x08, RADIO_FW_VERSION: 0x09, LEGO_WP_VERSION: 0x0A, SYSTEM_TYPE_ID: 0x0B, HW_NETWORK_ID: 0x0C, PRIMARY_MAC: 0x0D, SECONDARY_MAC: 0x0E, HW_NETWORK_FAMILY: 0x0F }; /** * Enum for Hub Property Operations * @readonly * @enum {number} */ const BoostHubPropertyOperation = { SET: 0x01, ENABLE_UPDATES: 0x02, DISABLE_UPDATES: 0x03, RESET: 0x04, REQUEST_UPDATE: 0x05, UPDATE: 0x06 }; /** * Enum for Motor Subcommands (for 0x81) * @readonly * @enum {number} */ const BoostOutputSubCommand = { START_POWER: 0x01, START_POWER_PAIR: 0x02, SET_ACC_TIME: 0x05, SET_DEC_TIME: 0x06, START_SPEED: 0x07, START_SPEED_PAIR: 0x08, START_SPEED_FOR_TIME: 0x09, START_SPEED_FOR_TIME_PAIR: 0x0A, START_SPEED_FOR_DEGREES: 0x0B, START_SPEED_FOR_DEGREES_PAIR: 0x0C, GO_TO_ABS_POSITION: 0x0D, GO_TO_ABS_POSITION_PAIR: 0x0E, PRESET_ENCODER: 0x14, WRITE_DIRECT_MODE_DATA: 0x51 }; /** * Enum for Startup/Completion information for an output command. * Startup and completion bytes must be OR'ed to be combined to a single byte. * @readonly * @enum {number} */ const BoostOutputExecution = { // Startup information BUFFER_IF_NECESSARY: 0x00, EXECUTE_IMMEDIATELY: 0x10, // Completion information NO_ACTION: 0x00, COMMAND_FEEDBACK: 0x01 }; /** * Enum for Boost Motor end states * @readonly * @enum {number} */ const BoostMotorEndState = { FLOAT: 0, HOLD: 126, BRAKE: 127 }; /** * Enum for Boost Motor acceleration/deceleration profiles * @readyonly * @enum {number} */ const BoostMotorProfile = { DO_NOT_USE: 0x00, ACCELERATION: 0x01, DECELERATION: 0x02 }; /** * Enum for when Boost IO's are attached/detached * @readonly * @enum {number} */ const BoostIOEvent = { ATTACHED: 0x01, DETACHED: 0x00, ATTACHED_VIRTUAL: 0x02 }; /** * Enum for selected sensor modes. * @enum {number} */ const BoostMode = { TILT: 0, // angle (pitch/yaw) LED: 1, // Set LED to accept RGB values COLOR: 0, // Read indexed colors from Vision Sensor MOTOR_SENSOR: 2, // Set motors to report their position UNKNOWN: 0 // Anything else will use the default mode (mode 0) }; /** * Enum for Boost motor states. * @param {number} */ const BoostMotorState = { OFF: 0, ON_FOREVER: 1, ON_FOR_TIME: 2, ON_FOR_ROTATION: 3 }; /** * Helper function for converting a JavaScript number to an INT32-number * @param {number} number - a number * @return {array} - a 4-byte array of Int8-values representing an INT32-number */ const numberToInt32Array = function numberToInt32Array(number) { const buffer = new ArrayBuffer(4); const dataview = new DataView(buffer); dataview.setInt32(0, number); return [dataview.getInt8(3), dataview.getInt8(2), dataview.getInt8(1), dataview.getInt8(0)]; }; /** * Helper function for converting a regular array to a Little Endian INT32-value * @param {Array} array - an array containing UInt8-values * @return {number} - a number */ const int32ArrayToNumber = function int32ArrayToNumber(array) { const i = Uint8Array.from(array); const d = new DataView(i.buffer); return d.getInt32(0, true); }; /** * Manage power, direction, position, and timers for one Boost motor. */ class BoostMotor { /** * Construct a Boost Motor instance. * @param {Boost} parent - the Boost peripheral which owns this motor. * @param {int} index - the zero-based index of this motor on its parent peripheral. */ constructor(parent, index) { /** * The Boost peripheral which owns this motor. * @type {Boost} * @private */ this._parent = parent; /** * The zero-based index of this motor on its parent peripheral. * @type {int} * @private */ this._index = index; /** * This motor's current direction: 1 for "this way" or -1 for "that way" * @type {number} * @private */ this._direction = 1; /** * This motor's current power level, in the range [0,100]. * @type {number} * @private */ this._power = 50; /** * This motor's current relative position * @type {number} * @private */ this._position = 0; /** * Is this motor currently moving? * @type {boolean} * @private */ this._status = BoostMotorState.OFF; /** * If the motor has been turned on or is actively braking for a specific duration, this is the timeout ID for * the end-of-action handler. Cancel this when changing plans. * @type {Object} * @private */ this._pendingDurationTimeoutId = null; /** * The starting time for the pending duration timeout. * @type {number} * @private */ this._pendingDurationTimeoutStartTime = null; /** * The delay/duration of the pending duration timeout. * @type {number} * @private */ this._pendingDurationTimeoutDelay = null; /** * The target position of a turn-based command. * @type {number} * @private */ this._pendingRotationDestination = null; /** * If the motor has been turned on run for a specific rotation, this is the function * that will be called once Scratch VM gets a notification from the Move Hub. * @type {Object} * @private */ this._pendingRotationPromise = null; this.turnOff = this.turnOff.bind(this); } /** * @return {int} - this motor's current direction: 1 for "this way" or -1 for "that way" */ get direction() { return this._direction; } /** * @param {int} value - this motor's new direction: 1 for "this way" or -1 for "that way" */ set direction(value) { if (value < 0) { this._direction = -1; } else { this._direction = 1; } } /** * @return {int} - this motor's current power level, in the range [0,100]. */ get power() { return this._power; } /** * @param {int} value - this motor's new power level, in the range [10,100]. */ set power(value) { /** * Scale the motor power to a range between 10 and 100, * to make sure the motors will run with something built onto them. */ if (value === 0) { this._power = 0; } else { this._power = MathUtil.scale(value, 1, 100, 10, 100); } } /** * @return {int} - this motor's current position, in the range of [-MIN_INT32,MAX_INT32] */ get position() { return this._position; } /** * @param {int} value - set this motor's current position. */ set position(value) { this._position = value; } /** * @return {BoostMotorState} - the motor's current state. */ get status() { return this._status; } /** * @param {BoostMotorState} value - set this motor's state. */ set status(value) { this._clearRotationState(); this._clearDurationTimeout(); this._status = value; } /** * @return {number} - time, in milliseconds, of when the pending duration timeout began. */ get pendingDurationTimeoutStartTime() { return this._pendingDurationTimeoutStartTime; } /** * @return {number} - delay, in milliseconds, of the pending duration timeout. */ get pendingDurationTimeoutDelay() { return this._pendingDurationTimeoutDelay; } /** * @return {number} - target position, in degrees, of the pending rotation. */ get pendingRotationDestination() { return this._pendingRotationDestination; } /** * @return {Promise} - the Promise function for the pending rotation. */ get pendingRotationPromise() { return this._pendingRotationPromise; } /** * @param {function} func - function to resolve pending rotation Promise */ set pendingRotationPromise(func) { this._pendingRotationPromise = func; } /** * Turn this motor on indefinitely * @private */ _turnOn() { const cmd = this._parent.generateOutputCommand(this._index, BoostOutputExecution.EXECUTE_IMMEDIATELY, BoostOutputSubCommand.START_SPEED, [this.power * this.direction, MathUtil.clamp(this.power + BoostMotorMaxPowerAdd, 0, 100), BoostMotorProfile.DO_NOT_USE]); this._parent.send(BoostBLE.characteristic, cmd); } /** * Turn this motor on indefinitely */ turnOnForever() { this.status = BoostMotorState.ON_FOREVER; this._turnOn(); } /** * Turn this motor on for a specific duration. * @param {number} milliseconds - run the motor for this long. */ turnOnFor(milliseconds) { milliseconds = Math.max(0, milliseconds); this.status = BoostMotorState.ON_FOR_TIME; this._turnOn(); this._setNewDurationTimeout(this.turnOff, milliseconds); } /** * Turn this motor on for a specific rotation in degrees. * @param {number} degrees - run the motor for this amount of degrees. * @param {number} direction - rotate in this direction */ turnOnForDegrees(degrees, direction) { degrees = Math.max(0, degrees); const cmd = this._parent.generateOutputCommand(this._index, BoostOutputExecution.EXECUTE_IMMEDIATELY ^ BoostOutputExecution.COMMAND_FEEDBACK, BoostOutputSubCommand.START_SPEED_FOR_DEGREES, [...numberToInt32Array(degrees), this.power * this.direction * direction, MathUtil.clamp(this.power + BoostMotorMaxPowerAdd, 0, 100), BoostMotorEndState.BRAKE, BoostMotorProfile.DO_NOT_USE]); this.status = BoostMotorState.ON_FOR_ROTATION; this._pendingRotationDestination = this.position + degrees * this.direction * direction; this._parent.send(BoostBLE.characteristic, cmd); } /** * Turn this motor off. * @param {boolean} [useLimiter=true] - if true, use the rate limiter */ turnOff(useLimiter = true) { const cmd = this._parent.generateOutputCommand(this._index, BoostOutputExecution.EXECUTE_IMMEDIATELY, BoostOutputSubCommand.START_POWER, [BoostMotorEndState.FLOAT]); this.status = BoostMotorState.OFF; this._parent.send(BoostBLE.characteristic, cmd, useLimiter); } /** * Clear the motor action timeout, if any. Safe to call even when there is no pending timeout. * @private */ _clearDurationTimeout() { if (this._pendingDurationTimeoutId !== null) { clearTimeout(this._pendingDurationTimeoutId); this._pendingDurationTimeoutId = null; this._pendingDurationTimeoutStartTime = null; this._pendingDurationTimeoutDelay = null; } } /** * Set a new motor action timeout, after clearing an existing one if necessary. * @param {Function} callback - to be called at the end of the timeout. * @param {int} delay - wait this many milliseconds before calling the callback. * @private */ _setNewDurationTimeout(callback, delay) { this._clearDurationTimeout(); const timeoutID = setTimeout(() => { if (this._pendingDurationTimeoutId === timeoutID) { this._pendingDurationTimeoutId = null; this._pendingDurationTimeoutStartTime = null; this._pendingDurationTimeoutDelay = null; } callback(); }, delay); this._pendingDurationTimeoutId = timeoutID; this._pendingDurationTimeoutStartTime = Date.now(); this._pendingDurationTimeoutDelay = delay; } /** * Clear the motor states related to rotation-based commands, if any. * Safe to call even when there is no pending promise function. * @private */ _clearRotationState() { if (this._pendingRotationPromise !== null) { this._pendingRotationPromise(); this._pendingRotationPromise = null; } this._pendingRotationDestination = null; } } /** * Manage communication with a Boost peripheral over a Bluetooth Low Energy client socket. */ class Boost { constructor(runtime, extensionId) { /** * The Scratch 3.0 runtime used to trigger the green flag button. * @type {Runtime} * @private */ this._runtime = runtime; this._runtime.on('PROJECT_STOP_ALL', this.stopAll.bind(this)); /** * The id of the extension this peripheral belongs to. */ this._extensionId = extensionId; /** * A list of the ids of the physical or virtual sensors. * @type {string[]} * @private */ this._ports = []; /** * A list of motors registered by the Boost hardware. * @type {BoostMotor[]} * @private */ this._motors = []; /** * The most recently received value for each sensor. * @type {Object.} * @private */ this._sensors = { tiltX: 0, tiltY: 0, color: BoostColor.NONE, previousColor: BoostColor.NONE }; /** * An array of values from the Boost Vision Sensor. * @type {Array} * @private */ this._colorSamples = []; /** * The Bluetooth connection socket for reading/writing peripheral data. * @type {BLE} * @private */ this._ble = null; this._runtime.registerPeripheralExtension(extensionId, this); /** * A rate limiter utility, to help limit the rate at which we send BLE messages * over the socket to Scratch Link to a maximum number of sends per second. * @type {RateLimiter} * @private */ this._rateLimiter = new RateLimiter(BoostBLE.sendRateMax); /** * An interval id for the battery check interval. * @type {number} * @private */ this._pingDeviceId = null; this.reset = this.reset.bind(this); this._onConnect = this._onConnect.bind(this); this._onMessage = this._onMessage.bind(this); this._pingDevice = this._pingDevice.bind(this); } /** * @return {number} - the latest value received for the tilt sensor's tilt about the X axis. */ get tiltX() { return this._sensors.tiltX; } /** * @return {number} - the latest value received for the tilt sensor's tilt about the Y axis. */ get tiltY() { return this._sensors.tiltY; } /** * @return {number} - the latest color value received from the vision sensor. */ get color() { return this._sensors.color; } /** * @return {number} - the previous color value received from the vision sensor. */ get previousColor() { return this._sensors.previousColor; } /** * Look up the color id for an index received from the vision sensor. * @param {number} index - the color index to look up. * @return {BoostColor} the color id for this index. */ boostColorForIndex(index) { const colorForIndex = Object.keys(BoostColorIndex).find(key => BoostColorIndex[key] === index); return colorForIndex || BoostColor.NONE; } /** * Access a particular motor on this peripheral. * @param {int} index - the index of the desired motor. * @return {BoostMotor} - the BoostMotor instance, if any, at that index. */ motor(index) { return this._motors[index]; } /** * Stop all the motors that are currently running. */ stopAllMotors() { this._motors.forEach(motor => { if (motor) { // Send the motor off command without using the rate limiter. // This allows the stop button to stop motors even if we are // otherwise flooded with commands. motor.turnOff(false); } }); } /** * Set the Boost peripheral's LED to a specific color. * @param {int} inputRGB - a 24-bit RGB color in 0xRRGGBB format. * @return {Promise} - a promise of the completion of the set led send operation. */ setLED(inputRGB) { const rgb = [inputRGB >> 16 & 0x000000FF, inputRGB >> 8 & 0x000000FF, inputRGB & 0x000000FF]; const cmd = this.generateOutputCommand(this._ports.indexOf(BoostIO.LED), BoostOutputExecution.EXECUTE_IMMEDIATELY ^ BoostOutputExecution.COMMAND_FEEDBACK, BoostOutputSubCommand.WRITE_DIRECT_MODE_DATA, [BoostMode.LED, ...rgb]); return this.send(BoostBLE.characteristic, cmd); } /** * Sets the input mode of the LED to RGB. * @return {Promise} - a promise returned by the send operation. */ setLEDMode() { const cmd = this.generateInputCommand(this._ports.indexOf(BoostIO.LED), BoostMode.LED, 0, false); return this.send(BoostBLE.characteristic, cmd); } /** * Stop the motors on the Boost peripheral. */ stopAll() { if (!this.isConnected()) return; this.stopAllMotors(); } /** * Called by the runtime when user wants to scan for a Boost peripheral. */ scan() { if (this._ble) { this._ble.disconnect(); } this._ble = new BLE(this._runtime, this._extensionId, { filters: [{ services: [BoostBLE.service], manufacturerData: { 0x0397: { dataPrefix: [0x00, 0x40], mask: [0x00, 0xFF] } } }], optionalServices: [] }, this._onConnect, this.reset); } /** * Called by the runtime when user wants to connect to a certain Boost peripheral. * @param {number} id - the id of the peripheral to connect to. */ connect(id) { if (this._ble) { this._ble.connectPeripheral(id); } } /** * Disconnects from the current BLE socket and resets state. */ disconnect() { if (this._ble) { this._ble.disconnect(); } this.reset(); } /** * Reset all the state and timeout/interval ids. */ reset() { this._ports = []; this._motors = []; this._sensors = { tiltX: 0, tiltY: 0, color: BoostColor.NONE, previousColor: BoostColor.NONE }; if (this._pingDeviceId) { window.clearInterval(this._pingDeviceId); this._pingDeviceId = null; } } /** * Called by the runtime to detect whether the Boost peripheral is connected. * @return {boolean} - the connected state. */ isConnected() { let connected = false; if (this._ble) { connected = this._ble.isConnected(); } return connected; } /** * Write a message to the Boost peripheral BLE socket. * @param {number} uuid - the UUID of the characteristic to write to * @param {Array} message - the message to write. * @param {boolean} [useLimiter=true] - if true, use the rate limiter * @return {Promise} - a promise result of the write operation */ send(uuid, message, useLimiter = true) { if (!this.isConnected()) return Promise.resolve(); if (useLimiter) { if (!this._rateLimiter.okayToSend()) return Promise.resolve(); } return this._ble.write(BoostBLE.service, uuid, Base64Util.uint8ArrayToBase64(message), 'base64'); } /** * Generate a Boost 'Output Command' in the byte array format * (COMMON HEADER, PORT ID, EXECUTION BYTE, SUBCOMMAND ID, PAYLOAD). * * Payload is accepted as an array since these vary across different subcommands. * * @param {number} portID - the port (Connect ID) to send a command to. * @param {number} execution - Byte containing startup/completion information * @param {number} subCommand - the id of the subcommand byte. * @param {array} payload - the list of bytes to send as subcommand payload * @return {array} - a generated output command. */ generateOutputCommand(portID, execution, subCommand, payload) { const hubID = 0x00; const command = [hubID, BoostMessage.OUTPUT, portID, execution, subCommand, ...payload]; command.unshift(command.length + 1); // Prepend payload with length byte; return command; } /** * Generate a Boost 'Input Command' in the byte array format * (COMMAND ID, COMMAND TYPE, CONNECT ID, TYPE ID, MODE, DELTA INTERVAL (4 BYTES), * UNIT, NOTIFICATIONS ENABLED). * * This sends a command to the Boost that sets that input format * of the specified inputs and sets value change notifications. * * @param {number} portID - the port (Connect ID) to send a command to. * @param {number} mode - the mode of the input sensor. * @param {number} delta - the delta change needed to trigger notification. * @param {boolean} enableNotifications - whether to enable notifications. * @return {array} - a generated input command. */ generateInputCommand(portID, mode, delta, enableNotifications) { const command = [0x00, // Hub ID BoostMessage.PORT_INPUT_FORMAT_SETUP_SINGLE, portID, mode].concat(numberToInt32Array(delta)).concat([enableNotifications]); command.unshift(command.length + 1); // Prepend payload with length byte; return command; } /** * Starts reading data from peripheral after BLE has connected. * @private */ _onConnect() { this._ble.startNotifications(BoostBLE.service, BoostBLE.characteristic, this._onMessage); this._pingDeviceId = window.setInterval(this._pingDevice, BoostPingInterval); // Send a request for firmware version. setTimeout(() => { const command = [0x00, // Hub ID BoostMessage.HUB_PROPERTIES, BoostHubProperty.FW_VERSION, BoostHubPropertyOperation.REQUEST_UPDATE]; command.unshift(command.length + 1); this.send(BoostBLE.characteristic, command, false); }, 500); } /** * Process the sensor data from the incoming BLE characteristic. * @param {object} base64 - the incoming BLE data. * @private */ _onMessage(base64) { const data = Base64Util.base64ToUint8Array(base64); /** * First three bytes are the common header: * 0: Length of message * 1: Hub ID (always 0x00 at the moment, unused) * 2: Message Type * 3: Port ID * We base our switch-case on Message Type */ const messageType = data[2]; const portID = data[3]; switch (messageType) { case BoostMessage.HUB_PROPERTIES: { const property = data[3]; switch (property) { case BoostHubProperty.FW_VERSION: { // Establish firmware version 1.0.00.0224 as a 32-bit signed integer (little endian) const fwVersion10000224 = int32ArrayToNumber([0x24, 0x02, 0x00, 0x10]); const fwHub = int32ArrayToNumber(data.slice(5, data.length)); if (fwHub < fwVersion10000224) { BoostPort = BoostPort10000223OrOlder; log.info('Move Hub firmware older than version 1.0.00.0224 detected. Using old port mapping.'); } else { BoostPort = BoostPort10000224OrNewer; } break; } } break; } case BoostMessage.HUB_ATTACHED_IO: { // IO Attach/Detach events const event = data[4]; const typeId = data[5]; switch (event) { case BoostIOEvent.ATTACHED: this._registerSensorOrMotor(portID, typeId); break; case BoostIOEvent.DETACHED: this._clearPort(portID); break; case BoostIOEvent.ATTACHED_VIRTUAL: default: } break; } case BoostMessage.PORT_VALUE: { const type = this._ports[portID]; switch (type) { case BoostIO.TILT: this._sensors.tiltX = data[4]; this._sensors.tiltY = data[5]; break; case BoostIO.COLOR: this._colorSamples.unshift(data[4]); if (this._colorSamples.length > BoostColorSampleSize) { this._colorSamples.pop(); if (this._colorSamples.every((v, i, arr) => v === arr[0])) { this._sensors.previousColor = this._sensors.color; this._sensors.color = this.boostColorForIndex(this._colorSamples[0]); } else { this._sensors.color = BoostColor.NONE; } } else { this._sensors.color = BoostColor.NONE; } break; case BoostIO.MOTOREXT: case BoostIO.MOTORINT: this.motor(portID).position = int32ArrayToNumber(data.slice(4, 8)); break; case BoostIO.CURRENT: case BoostIO.VOLTAGE: case BoostIO.LED: break; default: log.warn("Unknown sensor value! Type: ".concat(type)); } break; } case BoostMessage.PORT_FEEDBACK: { const feedback = data[4]; const motor = this.motor(portID); if (motor) { // Makes sure that commands resolve both when they actually complete and when they fail const isBusy = feedback & BoostPortFeedback.IN_PROGRESS; const commandCompleted = feedback & (BoostPortFeedback.COMPLETED ^ BoostPortFeedback.DISCARDED); if (!isBusy && commandCompleted) { if (motor.status === BoostMotorState.ON_FOR_ROTATION) { motor.status = BoostMotorState.OFF; } } } break; } case BoostMessage.ERROR: log.warn("Error reported by hub: ".concat(data)); break; } } /** * Ping the Boost hub. If the Boost hub has disconnected * for some reason, the BLE socket will get an error back and automatically * close the socket. * @private */ _pingDevice() { this._ble.read(BoostBLE.service, BoostBLE.characteristic, false); } /** * Register a new sensor or motor connected at a port. Store the type of * sensor or motor internally, and then register for notifications on input * values if it is a sensor. * @param {number} portID - the port to register a sensor or motor on. * @param {number} type - the type ID of the sensor or motor * @private */ _registerSensorOrMotor(portID, type) { // Record which port is connected to what type of device this._ports[portID] = type; // Record motor port if (type === BoostIO.MOTORINT || type === BoostIO.MOTOREXT) { this._motors[portID] = new BoostMotor(this, portID); } // Set input format for tilt or distance sensor let mode = null; let delta = 1; switch (type) { case BoostIO.MOTORINT: case BoostIO.MOTOREXT: mode = BoostMode.MOTOR_SENSOR; break; case BoostIO.COLOR: mode = BoostMode.COLOR; delta = 0; break; case BoostIO.LED: mode = BoostMode.LED; /** * Sets the LED to blue to give an indication on the hub * that it has connected successfully. */ this.setLEDMode(); this.setLED(0x0000FF); break; case BoostIO.TILT: mode = BoostMode.TILT; break; default: mode = BoostMode.UNKNOWN; } const cmd = this.generateInputCommand(portID, mode, delta, true // Receive feedback ); this.send(BoostBLE.characteristic, cmd); } /** * Clear the sensors or motors present on the ports. * @param {number} portID - the port to clear. * @private */ _clearPort(portID) { const type = this._ports[portID]; if (type === BoostIO.TILT) { this._sensors.tiltX = this._sensors.tiltY = 0; } if (type === BoostIO.COLOR) { this._sensors.color = BoostColor.NONE; } this._ports[portID] = 'none'; this._motors[portID] = null; } } /** * Enum for motor specification. * @readonly * @enum {string} */ const BoostMotorLabel = { A: 'A', B: 'B', C: 'C', D: 'D', AB: 'AB', ALL: 'ABCD' }; /** * Enum for motor direction specification. * @readonly * @enum {string} */ const BoostMotorDirection = { FORWARD: 'this way', BACKWARD: 'that way', REVERSE: 'reverse' }; /** * Enum for tilt sensor direction. * @readonly * @enum {string} */ const BoostTiltDirection = { UP: 'up', DOWN: 'down', LEFT: 'left', RIGHT: 'right', ANY: 'any' }; /** * Scratch 3.0 blocks to interact with a LEGO Boost peripheral. */ class Scratch3BoostBlocks { /** * @return {string} - the ID of this extension. */ static get EXTENSION_ID() { return 'boost'; } /** * @return {number} - the tilt sensor counts as "tilted" if its tilt angle meets or exceeds this threshold. */ static get TILT_THRESHOLD() { return 15; } /** * Construct a set of Boost blocks. * @param {Runtime} runtime - the Scratch 3.0 runtime. */ constructor(runtime) { /** * The Scratch 3.0 runtime. * @type {Runtime} */ this.runtime = runtime; // Create a new Boost peripheral instance this._peripheral = new Boost(this.runtime, Scratch3BoostBlocks.EXTENSION_ID); } /** * @returns {object} metadata for this extension and its blocks. */ getInfo() { return { id: Scratch3BoostBlocks.EXTENSION_ID, name: 'BOOST', blockIconURI: iconURI, showStatusButton: true, blocks: [{ opcode: 'motorOnFor', text: formatMessage({ id: 'boost.motorOnFor', default: 'turn motor [MOTOR_ID] for [DURATION] seconds', description: 'turn a motor on for some time' }), blockType: BlockType.COMMAND, arguments: { MOTOR_ID: { type: ArgumentType.STRING, menu: 'MOTOR_ID', defaultValue: BoostMotorLabel.A }, DURATION: { type: ArgumentType.NUMBER, defaultValue: 1 } } }, { opcode: 'motorOnForRotation', text: formatMessage({ id: 'boost.motorOnForRotation', default: 'turn motor [MOTOR_ID] for [ROTATION] rotations', description: 'turn a motor on for rotation' }), blockType: BlockType.COMMAND, arguments: { MOTOR_ID: { type: ArgumentType.STRING, menu: 'MOTOR_ID', defaultValue: BoostMotorLabel.A }, ROTATION: { type: ArgumentType.NUMBER, defaultValue: 1 } } }, { opcode: 'motorOn', text: formatMessage({ id: 'boost.motorOn', default: 'turn motor [MOTOR_ID] on', description: 'turn a motor on indefinitely' }), blockType: BlockType.COMMAND, arguments: { MOTOR_ID: { type: ArgumentType.STRING, menu: 'MOTOR_ID', defaultValue: BoostMotorLabel.A } } }, { opcode: 'motorOff', text: formatMessage({ id: 'boost.motorOff', default: 'turn motor [MOTOR_ID] off', description: 'turn a motor off' }), blockType: BlockType.COMMAND, arguments: { MOTOR_ID: { type: ArgumentType.STRING, menu: 'MOTOR_ID', defaultValue: BoostMotorLabel.A } } }, { opcode: 'setMotorPower', text: formatMessage({ id: 'boost.setMotorPower', default: 'set motor [MOTOR_ID] speed to [POWER] %', description: 'set the motor\'s speed without turning it on' }), blockType: BlockType.COMMAND, arguments: { MOTOR_ID: { type: ArgumentType.STRING, menu: 'MOTOR_ID', defaultValue: BoostMotorLabel.ALL }, POWER: { type: ArgumentType.NUMBER, defaultValue: 100 } } }, { opcode: 'setMotorDirection', text: formatMessage({ id: 'boost.setMotorDirection', default: 'set motor [MOTOR_ID] direction [MOTOR_DIRECTION]', description: 'set the motor\'s turn direction without turning it on' }), blockType: BlockType.COMMAND, arguments: { MOTOR_ID: { type: ArgumentType.STRING, menu: 'MOTOR_ID', defaultValue: BoostMotorLabel.A }, MOTOR_DIRECTION: { type: ArgumentType.STRING, menu: 'MOTOR_DIRECTION', defaultValue: BoostMotorDirection.FORWARD } } }, { opcode: 'getMotorPosition', text: formatMessage({ id: 'boost.getMotorPosition', default: 'motor [MOTOR_REPORTER_ID] position', description: 'the position returned by the motor' }), blockType: BlockType.REPORTER, arguments: { MOTOR_REPORTER_ID: { type: ArgumentType.STRING, menu: 'MOTOR_REPORTER_ID', defaultValue: BoostMotorLabel.A } } }, { opcode: 'whenColor', text: formatMessage({ id: 'boost.whenColor', default: 'when [COLOR] brick seen', description: 'check for when color' }), blockType: BlockType.HAT, arguments: { COLOR: { type: ArgumentType.STRING, menu: 'COLOR', defaultValue: BoostColor.ANY } } }, { opcode: 'seeingColor', text: formatMessage({ id: 'boost.seeingColor', default: 'seeing [COLOR] brick?', description: 'is the color sensor seeing a certain color?' }), blockType: BlockType.BOOLEAN, arguments: { COLOR: { type: ArgumentType.STRING, menu: 'COLOR', defaultValue: BoostColor.ANY } } }, { opcode: 'whenTilted', text: formatMessage({ id: 'boost.whenTilted', default: 'when tilted [TILT_DIRECTION_ANY]', description: 'check when tilted in a certain direction' }), func: 'isTilted', blockType: BlockType.HAT, arguments: { TILT_DIRECTION_ANY: { type: ArgumentType.STRING, menu: 'TILT_DIRECTION_ANY', defaultValue: BoostTiltDirection.ANY } } }, { opcode: 'getTiltAngle', text: formatMessage({ id: 'boost.getTiltAngle', default: 'tilt angle [TILT_DIRECTION]', description: 'the angle returned by the tilt sensor' }), blockType: BlockType.REPORTER, arguments: { TILT_DIRECTION: { type: ArgumentType.STRING, menu: 'TILT_DIRECTION', defaultValue: BoostTiltDirection.UP } } }, { opcode: 'setLightHue', text: formatMessage({ id: 'boost.setLightHue', default: 'set light color to [HUE]', description: 'set the LED color' }), blockType: BlockType.COMMAND, arguments: { HUE: { type: ArgumentType.NUMBER, defaultValue: 50 } } }], menus: { MOTOR_ID: { acceptReporters: true, items: [{ text: 'A', value: BoostMotorLabel.A }, { text: 'B', value: BoostMotorLabel.B }, { text: 'C', value: BoostMotorLabel.C }, { text: 'D', value: BoostMotorLabel.D }, { text: 'AB', value: BoostMotorLabel.AB }, { text: 'ABCD', value: BoostMotorLabel.ALL }] }, MOTOR_REPORTER_ID: { acceptReporters: true, items: [{ text: 'A', value: BoostMotorLabel.A }, { text: 'B', value: BoostMotorLabel.B }, { text: 'C', value: BoostMotorLabel.C }, { text: 'D', value: BoostMotorLabel.D }] }, MOTOR_DIRECTION: { acceptReporters: true, items: [{ text: formatMessage({ id: 'boost.motorDirection.forward', default: 'this way', description: 'label for forward element in motor direction menu for LEGO Boost extension' }), value: BoostMotorDirection.FORWARD }, { text: formatMessage({ id: 'boost.motorDirection.backward', default: 'that way', description: 'label for backward element in motor direction menu for LEGO Boost extension' }), value: BoostMotorDirection.BACKWARD }, { text: formatMessage({ id: 'boost.motorDirection.reverse', default: 'reverse', description: 'label for reverse element in motor direction menu for LEGO Boost extension' }), value: BoostMotorDirection.REVERSE }] }, TILT_DIRECTION: { acceptReporters: true, items: [{ text: formatMessage({ id: 'boost.tiltDirection.up', default: 'up', description: 'label for up element in tilt direction menu for LEGO Boost extension' }), value: BoostTiltDirection.UP }, { text: formatMessage({ id: 'boost.tiltDirection.down', default: 'down', description: 'label for down element in tilt direction menu for LEGO Boost extension' }), value: BoostTiltDirection.DOWN }, { text: formatMessage({ id: 'boost.tiltDirection.left', default: 'left', description: 'label for left element in tilt direction menu for LEGO Boost extension' }), value: BoostTiltDirection.LEFT }, { text: formatMessage({ id: 'boost.tiltDirection.right', default: 'right', description: 'label for right element in tilt direction menu for LEGO Boost extension' }), value: BoostTiltDirection.RIGHT }] }, TILT_DIRECTION_ANY: { acceptReporters: true, items: [{ text: formatMessage({ id: 'boost.tiltDirection.up', default: 'up' }), value: BoostTiltDirection.UP }, { text: formatMessage({ id: 'boost.tiltDirection.down', default: 'down' }), value: BoostTiltDirection.DOWN }, { text: formatMessage({ id: 'boost.tiltDirection.left', default: 'left' }), value: BoostTiltDirection.LEFT }, { text: formatMessage({ id: 'boost.tiltDirection.right', default: 'right' }), value: BoostTiltDirection.RIGHT }, { text: formatMessage({ id: 'boost.tiltDirection.any', default: 'any', description: 'label for any element in tilt direction menu for LEGO Boost extension' }), value: BoostTiltDirection.ANY }] }, COLOR: { acceptReporters: true, items: [{ text: formatMessage({ id: 'boost.color.red', default: 'red', description: 'the color red' }), value: BoostColor.RED }, { text: formatMessage({ id: 'boost.color.blue', default: 'blue', description: 'the color blue' }), value: BoostColor.BLUE }, { text: formatMessage({ id: 'boost.color.green', default: 'green', description: 'the color green' }), value: BoostColor.GREEN }, { text: formatMessage({ id: 'boost.color.yellow', default: 'yellow', description: 'the color yellow' }), value: BoostColor.YELLOW }, { text: formatMessage({ id: 'boost.color.white', default: 'white', desription: 'the color white' }), value: BoostColor.WHITE }, { text: formatMessage({ id: 'boost.color.black', default: 'black', description: 'the color black' }), value: BoostColor.BLACK }, { text: formatMessage({ id: 'boost.color.any', default: 'any color', description: 'any color' }), value: BoostColor.ANY }] } } }; } /** * Turn specified motor(s) on for a specified duration. * @param {object} args - the block's arguments. * @property {MotorID} MOTOR_ID - the motor(s) to activate. * @property {int} DURATION - the amount of time to run the motors. * @return {Promise} - a promise which will resolve at the end of the duration. */ motorOnFor(args) { // TODO: cast args.MOTOR_ID? let durationMS = Cast.toNumber(args.DURATION) * 1000; durationMS = MathUtil.clamp(durationMS, 0, 15000); return new Promise(resolve => { this._forEachMotor(args.MOTOR_ID, motorIndex => { const motor = this._peripheral.motor(motorIndex); if (motor) motor.turnOnFor(durationMS); }); // Run for some time even when no motor is connected setTimeout(resolve, durationMS); }); } /** * Turn specified motor(s) on for a specified rotation in full rotations. * @param {object} args - the block's arguments. * @property {MotorID} MOTOR_ID - the motor(s) to activate. * @property {int} ROTATION - the amount of full rotations to turn the motors. * @return {Promise} - a promise which will resolve at the end of the duration. */ motorOnForRotation(args) { // TODO: cast args.MOTOR_ID? let degrees = Cast.toNumber(args.ROTATION) * 360; // TODO: Clamps to 100 rotations. Consider changing. const sign = Math.sign(degrees); degrees = Math.abs(MathUtil.clamp(degrees, -360000, 360000)); const motors = []; this._forEachMotor(args.MOTOR_ID, motorIndex => { motors.push(motorIndex); }); /** * Checks that the motors given in args.MOTOR_ID exist, * and maps a promise for each of the motor-commands to an array. */ const promises = motors.map(portID => { const motor = this._peripheral.motor(portID); if (motor) { // to avoid a hanging block if power is 0, return an immediately resolving promise. if (motor.power === 0) return Promise.resolve(); return new Promise(resolve => { motor.turnOnForDegrees(degrees, sign); motor.pendingRotationPromise = resolve; }); } return null; }); /** * Make sure all promises are resolved, i.e. all motor-commands have completed. * To prevent the block from returning a value, an empty function is added to the .then */ return Promise.all(promises).then(() => {}); } /** * Turn specified motor(s) on indefinitely. * @param {object} args - the block's arguments. * @property {MotorID} MOTOR_ID - the motor(s) to activate. * @return {Promise} - a Promise that resolves after some delay. */ motorOn(args) { // TODO: cast args.MOTOR_ID? this._forEachMotor(args.MOTOR_ID, motorIndex => { const motor = this._peripheral.motor(motorIndex); if (motor) motor.turnOnForever(); }); return new Promise(resolve => { window.setTimeout(() => { resolve(); }, BoostBLE.sendInterval); }); } /** * Turn specified motor(s) off. * @param {object} args - the block's arguments. * @property {MotorID} MOTOR_ID - the motor(s) to deactivate. * @return {Promise} - a Promise that resolves after some delay. */ motorOff(args) { // TODO: cast args.MOTOR_ID? this._forEachMotor(args.MOTOR_ID, motorIndex => { const motor = this._peripheral.motor(motorIndex); if (motor) motor.turnOff(); }); return new Promise(resolve => { window.setTimeout(() => { resolve(); }, BoostBLE.sendInterval); }); } /** * Set the power level of the specified motor(s). * @param {object} args - the block's arguments. * @property {MotorID} MOTOR_ID - the motor(s) to be affected. * @property {int} POWER - the new power level for the motor(s). * @return {Promise} - returns a promise to make sure the block yields. */ setMotorPower(args) { // TODO: cast args.MOTOR_ID? this._forEachMotor(args.MOTOR_ID, motorIndex => { const motor = this._peripheral.motor(motorIndex); if (motor) { motor.power = MathUtil.clamp(Cast.toNumber(args.POWER), 0, 100); switch (motor.status) { case BoostMotorState.ON_FOREVER: motor.turnOnForever(); break; case BoostMotorState.ON_FOR_TIME: motor.turnOnFor(motor.pendingDurationTimeoutStartTime + motor.pendingDurationTimeoutDelay - Date.now()); break; } } }); return new Promise(resolve => { window.setTimeout(() => { resolve(); }, BoostBLE.sendInterval); }); } /** * Set the direction of rotation for specified motor(s). * If the direction is 'reverse' the motor(s) will be reversed individually. * @param {object} args - the block's arguments. * @property {MotorID} MOTOR_ID - the motor(s) to be affected. * @property {MotorDirection} MOTOR_DIRECTION - the new direction for the motor(s). * @return {Promise} - returns a promise to make sure the block yields. */ setMotorDirection(args) { // TODO: cast args.MOTOR_ID? this._forEachMotor(args.MOTOR_ID, motorIndex => { const motor = this._peripheral.motor(motorIndex); if (motor) { switch (args.MOTOR_DIRECTION) { case BoostMotorDirection.FORWARD: motor.direction = 1; break; case BoostMotorDirection.BACKWARD: motor.direction = -1; break; case BoostMotorDirection.REVERSE: motor.direction = -motor.direction; break; default: log.warn("Unknown motor direction in setMotorDirection: ".concat(args.DIRECTION)); break; } // keep the motor on if it's running, and update the pending timeout if needed if (motor) { switch (motor.status) { case BoostMotorState.ON_FOREVER: motor.turnOnForever(); break; case BoostMotorState.ON_FOR_TIME: motor.turnOnFor(motor.pendingDurationTimeoutStartTime + motor.pendingDurationTimeoutDelay - Date.now()); break; } } } }); return new Promise(resolve => { window.setTimeout(() => { resolve(); }, BoostBLE.sendInterval); }); } /** * @param {object} args - the block's arguments. * @return {number} - returns the motor's position. */ getMotorPosition(args) { let portID = null; switch (args.MOTOR_REPORTER_ID) { case BoostMotorLabel.A: portID = BoostPort.A; break; case BoostMotorLabel.B: portID = BoostPort.B; break; case BoostMotorLabel.C: portID = BoostPort.C; break; case BoostMotorLabel.D: portID = BoostPort.D; break; default: log.warn('Asked for a motor position that doesnt exist!'); return false; } if (portID !== null && this._peripheral.motor(portID)) { let val = this._peripheral.motor(portID).position; // Boost motor A position direction is reversed by design // so we have to reverse the position here if (portID === BoostPort.A) { val *= -1; } return MathUtil.wrapClamp(val, 0, 360); } return 0; } /** * Call a callback for each motor indexed by the provided motor ID. * @param {MotorID} motorID - the ID specifier. * @param {Function} callback - the function to call with the numeric motor index for each motor. * @private */ _forEachMotor(motorID, callback) { let motors; switch (motorID) { case BoostMotorLabel.A: motors = [BoostPort.A]; break; case BoostMotorLabel.B: motors = [BoostPort.B]; break; case BoostMotorLabel.C: motors = [BoostPort.C]; break; case BoostMotorLabel.D: motors = [BoostPort.D]; break; case BoostMotorLabel.AB: motors = [BoostPort.A, BoostPort.B]; break; case BoostMotorLabel.ALL: motors = [BoostPort.A, BoostPort.B, BoostPort.C, BoostPort.D]; break; default: log.warn("Invalid motor ID: ".concat(motorID)); motors = []; break; } for (const index of motors) { callback(index); } } /** * Test whether the tilt sensor is currently tilted. * @param {object} args - the block's arguments. * @property {TiltDirection} TILT_DIRECTION_ANY - the tilt direction to test (up, down, left, right, or any). * @return {boolean} - true if the tilt sensor is tilted past a threshold in the specified direction. */ whenTilted(args) { return this._isTilted(args.TILT_DIRECTION_ANY); } /** * Test whether the tilt sensor is currently tilted. * @param {object} args - the block's arguments. * @property {TiltDirection} TILT_DIRECTION_ANY - the tilt direction to test (up, down, left, right, or any). * @return {boolean} - true if the tilt sensor is tilted past a threshold in the specified direction. */ isTilted(args) { return this._isTilted(args.TILT_DIRECTION_ANY); } /** * @param {object} args - the block's arguments. * @property {TiltDirection} TILT_DIRECTION - the direction (up, down, left, right) to check. * @return {number} - the tilt sensor's angle in the specified direction. * Note that getTiltAngle(up) = -getTiltAngle(down) and getTiltAngle(left) = -getTiltAngle(right). */ getTiltAngle(args) { return this._getTiltAngle(args.TILT_DIRECTION); } /** * Test whether the tilt sensor is currently tilted. * @param {TiltDirection} direction - the tilt direction to test (up, down, left, right, or any). * @return {boolean} - true if the tilt sensor is tilted past a threshold in the specified direction. * @private */ _isTilted(direction) { switch (direction) { case BoostTiltDirection.ANY: return Math.abs(this._peripheral.tiltX) >= Scratch3BoostBlocks.TILT_THRESHOLD || Math.abs(this._peripheral.tiltY) >= Scratch3BoostBlocks.TILT_THRESHOLD; default: return this._getTiltAngle(direction) >= Scratch3BoostBlocks.TILT_THRESHOLD; } } /** * @param {TiltDirection} direction - the direction (up, down, left, right) to check. * @return {number} - the tilt sensor's angle in the specified direction. * Note that getTiltAngle(up) = -getTiltAngle(down) and getTiltAngle(left) = -getTiltAngle(right). * @private */ _getTiltAngle(direction) { switch (direction) { case BoostTiltDirection.UP: return this._peripheral.tiltY > 90 ? 256 - this._peripheral.tiltY : -this._peripheral.tiltY; case BoostTiltDirection.DOWN: return this._peripheral.tiltY > 90 ? this._peripheral.tiltY - 256 : this._peripheral.tiltY; case BoostTiltDirection.LEFT: return this._peripheral.tiltX > 90 ? this._peripheral.tiltX - 256 : this._peripheral.tiltX; case BoostTiltDirection.RIGHT: return this._peripheral.tiltX > 90 ? 256 - this._peripheral.tiltX : -this._peripheral.tiltX; default: log.warn("Unknown tilt direction in _getTiltAngle: ".concat(direction)); } } /** * Edge-triggering hat function, for when the vision sensor is detecting * a certain color. * @param {object} args - the block's arguments. * @return {boolean} - true when the color sensor senses the specified color. */ whenColor(args) { if (args.COLOR === BoostColor.ANY) { // For "any" color, return true if the color is not "none", and // the color is different from the previous color detected. This // allows the hat to trigger when the color changes from one color // to another. return this._peripheral.color !== BoostColor.NONE && this._peripheral.color !== this._peripheral.previousColor; } return args.COLOR === this._peripheral.color; } /** * A boolean reporter function, for whether the vision sensor is detecting * a certain color. * @param {object} args - the block's arguments. * @return {boolean} - true when the color sensor senses the specified color. */ seeingColor(args) { if (args.COLOR === BoostColor.ANY) { return this._peripheral.color !== BoostColor.NONE; } return args.COLOR === this._peripheral.color; } /** * Set the LED's hue. * @param {object} args - the block's arguments. * @property {number} HUE - the hue to set, in the range [0,100]. * @return {Promise} - a Promise that resolves after some delay. */ setLightHue(args) { // Convert from [0,100] to [0,360] let inputHue = Cast.toNumber(args.HUE); inputHue = MathUtil.wrapClamp(inputHue, 0, 100); const hue = inputHue * 360 / 100; const rgbObject = color.hsvToRgb({ h: hue, s: 1, v: 1 }); const rgbDecimal = color.rgbToDecimal(rgbObject); this._peripheral._led = inputHue; this._peripheral.setLED(rgbDecimal); return new Promise(resolve => { window.setTimeout(() => { resolve(); }, BoostBLE.sendInterval); }); } } module.exports = Scratch3BoostBlocks; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_ev3/index.js": /*!**********************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_ev3/index.js ***! \**********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const ArgumentType = __webpack_require__(/*! ../../extension-support/argument-type */ "./node_modules/scratch-vm/src/extension-support/argument-type.js"); const BlockType = __webpack_require__(/*! ../../extension-support/block-type */ "./node_modules/scratch-vm/src/extension-support/block-type.js"); const Cast = __webpack_require__(/*! ../../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); const formatMessage = __webpack_require__(/*! format-message */ "./node_modules/format-message/index.js"); const uid = __webpack_require__(/*! ../../util/uid */ "./node_modules/scratch-vm/src/util/uid.js"); const BT = __webpack_require__(/*! ../../io/bt */ "./node_modules/scratch-vm/src/io/bt.js"); const Base64Util = __webpack_require__(/*! ../../util/base64-util */ "./node_modules/scratch-vm/src/util/base64-util.js"); const MathUtil = __webpack_require__(/*! ../../util/math-util */ "./node_modules/scratch-vm/src/util/math-util.js"); const RateLimiter = __webpack_require__(/*! ../../util/rateLimiter.js */ "./node_modules/scratch-vm/src/util/rateLimiter.js"); const log = __webpack_require__(/*! ../../util/log */ "./node_modules/scratch-vm/src/util/log.js"); /** * Icon svg to be displayed at the left edge of each extension block, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len const blockIconURI = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNDBweCIgaGVpZ2h0PSI0MHB4IiB2aWV3Qm94PSIwIDAgNDAgNDAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUwLjIgKDU1MDQ3KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5ldjMtYmxvY2staWNvbjwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxkZWZzPjwvZGVmcz4KICAgIDxnIGlkPSJldjMtYmxvY2staWNvbiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9ImV2MyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNS41MDAwMDAsIDMuNTAwMDAwKSIgZmlsbC1ydWxlPSJub256ZXJvIj4KICAgICAgICAgICAgPHJlY3QgaWQ9IlJlY3RhbmdsZS1wYXRoIiBzdHJva2U9IiM3Qzg3QTUiIGZpbGw9IiNGRkZGRkYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgeD0iMC41IiB5PSIzLjU5IiB3aWR0aD0iMjgiIGhlaWdodD0iMjUuODEiIHJ4PSIxIj48L3JlY3Q+CiAgICAgICAgICAgIDxyZWN0IGlkPSJSZWN0YW5nbGUtcGF0aCIgc3Ryb2tlPSIjN0M4N0E1IiBmaWxsPSIjRTZFN0U4IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHg9IjIuNSIgeT0iMC41IiB3aWR0aD0iMjQiIGhlaWdodD0iMzIiIHJ4PSIxIj48L3JlY3Q+CiAgICAgICAgICAgIDxyZWN0IGlkPSJSZWN0YW5nbGUtcGF0aCIgc3Ryb2tlPSIjN0M4N0E1IiBmaWxsPSIjRkZGRkZGIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHg9IjIuNSIgeT0iMTQuNSIgd2lkdGg9IjI0IiBoZWlnaHQ9IjEzIj48L3JlY3Q+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNC41LDEwLjUgTDE0LjUsMTQuNSIgaWQ9IlNoYXBlIiBzdHJva2U9IiM3Qzg3QTUiIGZpbGw9IiNFNkU3RTgiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PC9wYXRoPgogICAgICAgICAgICA8cmVjdCBpZD0iUmVjdGFuZ2xlLXBhdGgiIGZpbGw9IiM0MTQ3NTciIHg9IjQuNSIgeT0iMi41IiB3aWR0aD0iMjAiIGhlaWdodD0iMTAiIHJ4PSIxIj48L3JlY3Q+CiAgICAgICAgICAgIDxyZWN0IGlkPSJSZWN0YW5nbGUtcGF0aCIgZmlsbD0iIzdDODdBNSIgb3BhY2l0eT0iMC41IiB4PSIxMy41IiB5PSIyMC4xMyIgd2lkdGg9IjIiIGhlaWdodD0iMiIgcng9IjAuNSI+PC9yZWN0PgogICAgICAgICAgICA8cGF0aCBkPSJNOS4wNiwyMC4xMyBMMTAuNTYsMjAuMTMgQzEwLjgzNjE0MjQsMjAuMTMgMTEuMDYsMjAuMzUzODU3NiAxMS4wNiwyMC42MyBMMTEuMDYsMjEuNjMgQzExLjA2LDIxLjkwNjE0MjQgMTAuODM2MTQyNCwyMi4xMyAxMC41NiwyMi4xMyBMOS4wNiwyMi4xMyBDOC41MDc3MTUyNSwyMi4xMyA4LjA2LDIxLjY4MjI4NDcgOC4wNiwyMS4xMyBDOC4wNiwyMC41Nzc3MTUzIDguNTA3NzE1MjUsMjAuMTMgOS4wNiwyMC4xMyBaIiBpZD0iU2hhcGUiIGZpbGw9IiM3Qzg3QTUiIG9wYWNpdHk9IjAuNSI+PC9wYXRoPgogICAgICAgICAgICA8cGF0aCBkPSJNMTguOTEsMjAuMTMgTDIwLjQyLDIwLjEzIEMyMC42OTYxNDI0LDIwLjEzIDIwLjkyLDIwLjM1Mzg1NzYgMjAuOTIsMjAuNjMgTDIwLjkyLDIxLjYzIEMyMC45MiwyMS45MDYxNDI0IDIwLjY5NjE0MjQsMjIuMTMgMjAuNDIsMjIuMTMgTDE4LjkyLDIyLjEzIEMxOC4zNjc3MTUzLDIyLjEzIDE3LjkyLDIxLjY4MjI4NDcgMTcuOTIsMjEuMTMgQzE3LjkxOTk3MjYsMjAuNTgxNTk3IDE4LjM2MTYyNDUsMjAuMTM1NDg0IDE4LjkxLDIwLjEzIFoiIGlkPSJTaGFwZSIgZmlsbD0iIzdDODdBNSIgb3BhY2l0eT0iMC41IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxOS40MjAwMDAsIDIxLjEzMDAwMCkgcm90YXRlKC0xODAuMDAwMDAwKSB0cmFuc2xhdGUoLTE5LjQyMDAwMCwgLTIxLjEzMDAwMCkgIj48L3BhdGg+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik04LjIzLDE3LjUgTDUsMTcuNSBDNC43MjM4NTc2MywxNy41IDQuNSwxNy4yNzYxNDI0IDQuNSwxNyBMNC41LDE0LjUgTDEwLjUsMTQuNSBMOC42NSwxNy4yOCBDOC41NTQ2Njk2MSwxNy40MTc5MDgyIDguMzk3NjUwMDYsMTcuNTAwMTU2NiA4LjIzLDE3LjUgWiIgaWQ9IlNoYXBlIiBmaWxsPSIjN0M4N0E1IiBvcGFjaXR5PSIwLjUiPjwvcGF0aD4KICAgICAgICAgICAgPHBhdGggZD0iTTE4LjE1LDE4Ljg1IEwxNy42NSwxOS4zNSBDMTcuNTUyMzQxNiwxOS40NDQwNzU2IDE3LjQ5ODAzMzksMTkuNTc0NDE0MiAxNy41LDE5LjcxIEwxNy41LDIwIEMxNy41LDIwLjI3NjE0MjQgMTcuMjc2MTQyNCwyMC41IDE3LDIwLjUgTDE2LjUsMjAuNSBDMTYuMjIzODU3NiwyMC41IDE2LDIwLjI3NjE0MjQgMTYsMjAgQzE2LDE5LjcyMzg1NzYgMTUuNzc2MTQyNCwxOS41IDE1LjUsMTkuNSBMMTMuNSwxOS41IEMxMy4yMjM4NTc2LDE5LjUgMTMsMTkuNzIzODU3NiAxMywyMCBDMTMsMjAuMjc2MTQyNCAxMi43NzYxNDI0LDIwLjUgMTIuNSwyMC41IEwxMiwyMC41IEMxMS43MjM4NTc2LDIwLjUgMTEuNSwyMC4yNzYxNDI0IDExLjUsMjAgTDExLjUsMTkuNzEgQzExLjUwMTk2NjEsMTkuNTc0NDE0MiAxMS40NDc2NTg0LDE5LjQ0NDA3NTYgMTEuMzUsMTkuMzUgTDEwLjg1LDE4Ljg1IEMxMC42NTgyMTY3LDE4LjY1MjE4NjMgMTAuNjU4MjE2NywxOC4zMzc4MTM3IDEwLjg1LDE4LjE0IEwxMi4zNiwxNi42NSBDMTIuNDUwMjgwMywxNi41NTI4NjE3IDEyLjU3NzM5NjEsMTYuNDk4MzgzNSAxMi43MSwxNi41IEwxNi4yOSwxNi41IEMxNi40MjI2MDM5LDE2LjQ5ODM4MzUgMTYuNTQ5NzE5NywxNi41NTI4NjE3IDE2LjY0LDE2LjY1IEwxOC4xNSwxOC4xNCBDMTguMzQxNzgzMywxOC4zMzc4MTM3IDE4LjM0MTc4MzMsMTguNjUyMTg2MyAxOC4xNSwxOC44NSBaIiBpZD0iU2hhcGUiIGZpbGw9IiM3Qzg3QTUiIG9wYWNpdHk9IjAuNSI+PC9wYXRoPgogICAgICAgICAgICA8cGF0aCBkPSJNMTAuODUsMjMuNDUgTDExLjM1LDIyLjk1IEMxMS40NDc2NTg0LDIyLjg1NTkyNDQgMTEuNTAxOTY2MSwyMi43MjU1ODU4IDExLjUsMjIuNTkgTDExLjUsMjIuMyBDMTEuNSwyMi4wMjM4NTc2IDExLjcyMzg1NzYsMjEuOCAxMiwyMS44IEwxMi41LDIxLjggQzEyLjc3NjE0MjQsMjEuOCAxMywyMi4wMjM4NTc2IDEzLDIyLjMgQzEzLDIyLjU3NjE0MjQgMTMuMjIzODU3NiwyMi44IDEzLjUsMjIuOCBMMTUuNSwyMi44IEMxNS43NzYxNDI0LDIyLjggMTYsMjIuNTc2MTQyNCAxNiwyMi4zIEMxNiwyMi4wMjM4NTc2IDE2LjIyMzg1NzYsMjEuOCAxNi41LDIxLjggTDE3LDIxLjggQzE3LjI3NjE0MjQsMjEuOCAxNy41LDIyLjAyMzg1NzYgMTcuNSwyMi4zIEwxNy41LDIyLjU5IEMxNy40OTgwMzM5LDIyLjcyNTU4NTggMTcuNTUyMzQxNiwyMi44NTU5MjQ0IDE3LjY1LDIyLjk1IEwxOC4xNSwyMy40NSBDMTguMzQwNTcxNCwyMy42NDQ0MjE4IDE4LjM0MDU3MTQsMjMuOTU1NTc4MiAxOC4xNSwyNC4xNSBMMTYuNjQsMjUuNjUgQzE2LjU0OTcxOTcsMjUuNzQ3MTM4MyAxNi40MjI2MDM5LDI1LjgwMTYxNjUgMTYuMjksMjUuOCBMMTIuNzEsMjUuOCBDMTIuNTc3Mzk2MSwyNS44MDE2MTY1IDEyLjQ1MDI4MDMsMjUuNzQ3MTM4MyAxMi4zNiwyNS42NSBMMTAuODUsMjQuMTUgQzEwLjY1OTQyODYsMjMuOTU1NTc4MiAxMC42NTk0Mjg2LDIzLjY0NDQyMTggMTAuODUsMjMuNDUgWiIgaWQ9IlNoYXBlIiBmaWxsPSIjN0M4N0E1IiBvcGFjaXR5PSIwLjUiPjwvcGF0aD4KICAgICAgICAgICAgPHBhdGggZD0iTTIxLjUsMjcuNSBMMjYuNSwyNy41IEwyNi41LDMxLjUgQzI2LjUsMzIuMDUyMjg0NyAyNi4wNTIyODQ3LDMyLjUgMjUuNSwzMi41IEwyMS41LDMyLjUgTDIxLjUsMjcuNSBaIiBpZD0iU2hhcGUiIHN0cm9rZT0iI0NDNEMyMyIgZmlsbD0iI0YxNUEyOSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48L3BhdGg+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4='; /** * String with Ev3 expected pairing pin. * @readonly */ const Ev3PairingPin = '1234'; /** * A maximum number of BT message sends per second, to be enforced by the rate limiter. * @type {number} */ const BTSendRateMax = 40; /** * Enum for Ev3 parameter encodings of various argument and return values. * Found in the 'EV3 Firmware Developer Kit', section4, page 9, at * https://education.lego.com/en-us/support/mindstorms-ev3/developer-kits. * * The format for these values is: * 0xxxxxxx for Short Format * 1ttt-bbb for Long Format * * @readonly * @enum {number} */ const Ev3Encoding = { ONE_BYTE: 0x81, // = 0b1000-001, "1 byte to follow" TWO_BYTES: 0x82, // = 0b1000-010, "2 bytes to follow" FOUR_BYTES: 0x83, // = 0b1000-011, "4 bytes to follow" GLOBAL_VARIABLE_ONE_BYTE: 0xE1, // = 0b1110-001, "1 byte to follow" GLOBAL_CONSTANT_INDEX_0: 0x20, // = 0b00100000 GLOBAL_VARIABLE_INDEX_0: 0x60 // = 0b01100000 }; /** * Enum for Ev3 direct command types. * Found in the 'EV3 Communication Developer Kit', section 4, page 24, at * https://education.lego.com/en-us/support/mindstorms-ev3/developer-kits. * @readonly * @enum {number} */ const Ev3Command = { DIRECT_COMMAND_REPLY: 0x00, DIRECT_COMMAND_NO_REPLY: 0x80, DIRECT_REPLY: 0x02 }; /** * Enum for Ev3 commands opcodes. * Found in the 'EV3 Firmware Developer Kit', section 4, page 10, at * https://education.lego.com/en-us/support/mindstorms-ev3/developer-kits. * @readonly * @enum {number} */ const Ev3Opcode = { OPOUTPUT_STEP_SPEED: 0xAE, OPOUTPUT_TIME_SPEED: 0xAF, OPOUTPUT_STOP: 0xA3, OPOUTPUT_RESET: 0xA2, OPOUTPUT_STEP_SYNC: 0xB0, OPOUTPUT_TIME_SYNC: 0xB1, OPOUTPUT_GET_COUNT: 0xB3, OPSOUND: 0x94, OPSOUND_CMD_TONE: 1, OPSOUND_CMD_STOP: 0, OPINPUT_DEVICE_LIST: 0x98, OPINPUT_READSI: 0x9D }; /** * Enum for Ev3 values used as arguments to various opcodes. * Found in the 'EV3 Firmware Developer Kit', section4, page 10-onwards, at * https://education.lego.com/en-us/support/mindstorms-ev3/developer-kits. * @readonly * @enum {number} */ const Ev3Args = { LAYER: 0, // always 0, chained EV3s not supported COAST: 0, BRAKE: 1, RAMP: 50, // time in milliseconds DO_NOT_CHANGE_TYPE: 0, MAX_DEVICES: 32 // 'Normally 32' from pg. 46 }; /** * Enum for Ev3 device type numbers. * Found in the 'EV3 Firmware Developer Kit', section 5, page 100, at * https://education.lego.com/en-us/support/mindstorms-ev3/developer-kits. * @readonly * @enum {string} */ const Ev3Device = { 29: 'color', 30: 'ultrasonic', 32: 'gyro', 16: 'touch', 8: 'mediumMotor', 7: 'largeMotor', 126: 'none', 125: 'none' }; /** * Enum for Ev3 device modes. * Found in the 'EV3 Firmware Developer Kit', section 5, page 100, at * https://education.lego.com/en-us/support/mindstorms-ev3/developer-kits. * @readonly * @enum {number} */ const Ev3Mode = { touch: 0, // touch color: 1, // ambient ultrasonic: 1, // inch none: 0 }; /** * Enum for Ev3 device labels used in the Scratch blocks/UI. * @readonly * @enum {string} */ const Ev3Label = { touch: 'button', color: 'brightness', ultrasonic: 'distance' }; /** * Manage power, direction, and timers for one EV3 motor. */ class EV3Motor { /** * Construct a EV3 Motor instance, which could be of type 'largeMotor' or * 'mediumMotor'. * * @param {EV3} parent - the EV3 peripheral which owns this motor. * @param {int} index - the zero-based index of this motor on its parent peripheral. * @param {string} type - the type of motor (i.e. 'largeMotor' or 'mediumMotor'). */ constructor(parent, index, type) { /** * The EV3 peripheral which owns this motor. * @type {EV3} * @private */ this._parent = parent; /** * The zero-based index of this motor on its parent peripheral. * @type {int} * @private */ this._index = index; /** * The type of EV3 motor this could be: 'largeMotor' or 'mediumMotor'. * @type {string} * @private */ this._type = type; /** * This motor's current direction: 1 for "clockwise" or -1 for "counterclockwise" * @type {number} * @private */ this._direction = 1; /** * This motor's current power level, in the range [0,100]. * @type {number} * @private */ this._power = 50; /** * This motor's current position, in the range [0,360]. * @type {number} * @private */ this._position = 0; /** * An ID for the current coast command, to help override multiple coast * commands sent in succession. * @type {number} * @private */ this._commandID = null; /** * A delay, in milliseconds, to add to coasting, to make sure that a brake * first takes effect if one was sent. * @type {number} * @private */ this._coastDelay = 1000; } /** * @return {string} - this motor's type: 'largeMotor' or 'mediumMotor' */ get type() { return this._type; } /** * @param {string} value - this motor's new type: 'largeMotor' or 'mediumMotor' */ set type(value) { this._type = value; } /** * @return {int} - this motor's current direction: 1 for "clockwise" or -1 for "counterclockwise" */ get direction() { return this._direction; } /** * @param {int} value - this motor's new direction: 1 for "clockwise" or -1 for "counterclockwise" */ set direction(value) { if (value < 0) { this._direction = -1; } else { this._direction = 1; } } /** * @return {int} - this motor's current power level, in the range [0,100]. */ get power() { return this._power; } /** * @param {int} value - this motor's new power level, in the range [0,100]. */ set power(value) { this._power = value; } /** * @return {int} - this motor's current position, in the range [-inf,inf]. */ get position() { return this._position; } /** * @param {int} array - this motor's new position, in the range [0,360]. */ set position(array) { // tachoValue from Paula let value = array[0] + array[1] * 256 + array[2] * 256 * 256 + array[3] * 256 * 256 * 256; if (value > 0x7fffffff) { value = value - 0x100000000; } this._position = value; } /** * Turn this motor on for a specific duration. * Found in the 'EV3 Firmware Developer Kit', page 56, at * https://education.lego.com/en-us/support/mindstorms-ev3/developer-kits. * * Opcode arguments: * (Data8) LAYER – Specify chain layer number [0 - 3] * (Data8) NOS – Output bit field [0x00 – 0x0F] * (Data8) SPEED – Power level, [-100 – 100] * (Data32) STEP1 – Time in milliseconds for ramp up * (Data32) STEP2 – Time in milliseconds for continues run * (Data32) STEP3 – Time in milliseconds for ramp down * (Data8) BRAKE - Specify break level [0: Float, 1: Break] * * @param {number} milliseconds - run the motor for this long. */ turnOnFor(milliseconds) { if (this._power === 0) return; const port = this._portMask(this._index); let n = milliseconds; let speed = this._power * this._direction; const ramp = Ev3Args.RAMP; let byteCommand = []; byteCommand[0] = Ev3Opcode.OPOUTPUT_TIME_SPEED; // If speed is less than zero, make it positive and multiply the input // value by -1 if (speed < 0) { speed = -1 * speed; n = -1 * n; } // If the input value is less than 0 const dir = n < 0 ? 0x100 - speed : speed; // step negative or positive n = Math.abs(n); // Setup motor run duration and ramping behavior let rampup = ramp; let rampdown = ramp; let run = n - ramp * 2; if (run < 0) { rampup = Math.floor(n / 2); run = 0; rampdown = n - rampup; } // Generate motor command values const runcmd = this._runValues(run); byteCommand = byteCommand.concat([Ev3Args.LAYER, port, Ev3Encoding.ONE_BYTE, dir & 0xff, Ev3Encoding.ONE_BYTE, rampup]).concat(runcmd.concat([Ev3Encoding.ONE_BYTE, rampdown, Ev3Args.BRAKE])); const cmd = this._parent.generateCommand(Ev3Command.DIRECT_COMMAND_NO_REPLY, byteCommand); this._parent.send(cmd); this.coastAfter(milliseconds); } /** * Set the motor to coast after a specified amount of time. * @param {number} time - the time in milliseconds. */ coastAfter(time) { if (this._power === 0) return; // Set the motor command id to check before starting coast const commandId = uid(); this._commandID = commandId; // Send coast message setTimeout(() => { // Do not send coast if another motor command changed the command id. if (this._commandID === commandId) { this.coast(); this._commandID = null; } }, time + this._coastDelay); // add a delay so the brake takes effect } /** * Set the motor to coast. */ coast() { if (this._power === 0) return; const cmd = this._parent.generateCommand(Ev3Command.DIRECT_COMMAND_NO_REPLY, [Ev3Opcode.OPOUTPUT_STOP, Ev3Args.LAYER, this._portMask(this._index), // port output bit field Ev3Args.COAST]); this._parent.send(cmd, false); // don't use rate limiter to ensure motor stops } /** * Generate motor run values for a given input. * @param {number} run - run input. * @return {array} - run values as a byte array. */ _runValues(run) { // If run duration is less than max 16-bit integer if (run < 0x7fff) { return [Ev3Encoding.TWO_BYTES, run & 0xff, run >> 8 & 0xff]; } // Run forever return [Ev3Encoding.FOUR_BYTES, run & 0xff, run >> 8 & 0xff, run >> 16 & 0xff, run >> 24 & 0xff]; } /** * Return a port value for the EV3 that is in the format for 'output bit field' * as 1/2/4/8, generally needed for motor ports, instead of the typical 0/1/2/3. * The documentation in the 'EV3 Firmware Developer Kit' for motor port arguments * is sometimes mistaken, but we believe motor ports are mostly addressed this way. * @param {number} port - the port number to convert to an 'output bit field'. * @return {number} - the converted port number. */ _portMask(port) { return Math.pow(2, port); } } class EV3 { constructor(runtime, extensionId) { /** * The Scratch 3.0 runtime used to trigger the green flag button. * @type {Runtime} * @private */ this._runtime = runtime; this._runtime.on('PROJECT_STOP_ALL', this.stopAll.bind(this)); /** * The id of the extension this peripheral belongs to. */ this._extensionId = extensionId; /** * A list of the names of the sensors connected in ports 1,2,3,4. * @type {string[]} * @private */ this._sensorPorts = []; /** * A list of the names of the motors connected in ports A,B,C,D. * @type {string[]} * @private */ this._motorPorts = []; /** * The state of all sensor values. * @type {string[]} * @private */ this._sensors = { distance: 0, brightness: 0, buttons: [0, 0, 0, 0] }; /** * The motors which this EV3 could possibly have connected. * @type {string[]} * @private */ this._motors = [null, null, null, null]; /** * The polling interval, in milliseconds. * @type {number} * @private */ this._pollingInterval = 150; /** * The polling interval ID. * @type {number} * @private */ this._pollingIntervalID = null; /** * The counter keeping track of polling cycles. * @type {string[]} * @private */ this._pollingCounter = 0; /** * The Bluetooth socket connection for reading/writing peripheral data. * @type {BT} * @private */ this._bt = null; this._runtime.registerPeripheralExtension(extensionId, this); /** * A rate limiter utility, to help limit the rate at which we send BT messages * over the socket to Scratch Link to a maximum number of sends per second. * @type {RateLimiter} * @private */ this._rateLimiter = new RateLimiter(BTSendRateMax); this.reset = this.reset.bind(this); this._onConnect = this._onConnect.bind(this); this._onMessage = this._onMessage.bind(this); this._pollValues = this._pollValues.bind(this); } get distance() { let value = this._sensors.distance > 100 ? 100 : this._sensors.distance; value = value < 0 ? 0 : value; value = Math.round(100 * value) / 100; return value; } get brightness() { return this._sensors.brightness; } /** * Access a particular motor on this peripheral. * @param {int} index - the zero-based index of the desired motor. * @return {EV3Motor} - the EV3Motor instance, if any, at that index. */ motor(index) { return this._motors[index]; } isButtonPressed(port) { return this._sensors.buttons[port] === 1; } beep(freq, time) { const cmd = this.generateCommand(Ev3Command.DIRECT_COMMAND_NO_REPLY, [Ev3Opcode.OPSOUND, Ev3Opcode.OPSOUND_CMD_TONE, Ev3Encoding.ONE_BYTE, 2, Ev3Encoding.TWO_BYTES, freq, freq >> 8, Ev3Encoding.TWO_BYTES, time, time >> 8]); this.send(cmd); } stopAll() { this.stopAllMotors(); this.stopSound(); } stopSound() { const cmd = this.generateCommand(Ev3Command.DIRECT_COMMAND_NO_REPLY, [Ev3Opcode.OPSOUND, Ev3Opcode.OPSOUND_CMD_STOP]); this.send(cmd, false); // don't use rate limiter to ensure sound stops } stopAllMotors() { this._motors.forEach(motor => { if (motor) { motor.coast(); } }); } /** * Called by the runtime when user wants to scan for an EV3 peripheral. */ scan() { if (this._bt) { this._bt.disconnect(); } this._bt = new BT(this._runtime, this._extensionId, { majorDeviceClass: 8, minorDeviceClass: 1 }, this._onConnect, this.reset, this._onMessage); } /** * Called by the runtime when user wants to connect to a certain EV3 peripheral. * @param {number} id - the id of the peripheral to connect to. */ connect(id) { if (this._bt) { this._bt.connectPeripheral(id, Ev3PairingPin); } } /** * Called by the runtime when user wants to disconnect from the EV3 peripheral. */ disconnect() { if (this._bt) { this._bt.disconnect(); } this.reset(); } /** * Reset all the state and timeout/interval ids. */ reset() { this._sensorPorts = []; this._motorPorts = []; this._sensors = { distance: 0, brightness: 0, buttons: [0, 0, 0, 0] }; this._motors = [null, null, null, null]; if (this._pollingIntervalID) { window.clearInterval(this._pollingIntervalID); this._pollingIntervalID = null; } } /** * Called by the runtime to detect whether the EV3 peripheral is connected. * @return {boolean} - the connected state. */ isConnected() { let connected = false; if (this._bt) { connected = this._bt.isConnected(); } return connected; } /** * Send a message to the peripheral BT socket. * @param {Uint8Array} message - the message to send. * @param {boolean} [useLimiter=true] - if true, use the rate limiter * @return {Promise} - a promise result of the send operation. */ send(message, useLimiter = true) { if (!this.isConnected()) return Promise.resolve(); if (useLimiter) { if (!this._rateLimiter.okayToSend()) return Promise.resolve(); } return this._bt.sendMessage({ message: Base64Util.uint8ArrayToBase64(message), encoding: 'base64' }); } /** * Genrates direct commands that are sent to the EV3 as a single or compounded byte arrays. * See 'EV3 Communication Developer Kit', section 4, page 24 at * https://education.lego.com/en-us/support/mindstorms-ev3/developer-kits. * * Direct commands are one of two types: * DIRECT_COMMAND_NO_REPLY = a direct command where no reply is expected * DIRECT_COMMAND_REPLY = a direct command where a reply is expected, and the * number and length of returned values needs to be specified. * * The direct command byte array sent takes the following format: * Byte 0 - 1: Command size, Little Endian. Command size not including these 2 bytes * Byte 2 - 3: Message counter, Little Endian. Forth running counter * Byte 4: Command type. Either DIRECT_COMMAND_REPLY or DIRECT_COMMAND_NO_REPLY * Byte 5 - 6: Reservation (allocation) of global and local variables using a compressed format * (globals reserved in byte 5 and the 2 lsb of byte 6, locals reserved in the upper * 6 bits of byte 6) – see documentation for more details. * Byte 7 - n: Byte codes as a single command or compound commands (I.e. more commands composed * as a small program) * * @param {number} type - the direct command type. * @param {string} byteCommands - a compound array of EV3 Opcode + arguments. * @param {number} allocation - the allocation of global and local vars needed for replies. * @return {array} - generated complete command byte array, with header and compounded commands. */ generateCommand(type, byteCommands, allocation = 0) { // Header (Bytes 0 - 6) let command = []; command[2] = 0; // Message counter unused for now command[3] = 0; // Message counter unused for now command[4] = type; command[5] = allocation & 0xFF; command[6] = allocation >> 8 && 0xFF; // Bytecodes (Bytes 7 - n) command = command.concat(byteCommands); // Calculate command length minus first two header bytes const len = command.length - 2; command[0] = len & 0xFF; command[1] = len >> 8 && 0xFF; return command; } /** * When the EV3 peripheral connects, start polling for sensor and motor values. * @private */ _onConnect() { this._pollingIntervalID = window.setInterval(this._pollValues, this._pollingInterval); } /** * Poll the EV3 for sensor and motor input values, based on the list of * known connected sensors and motors. This is sent as many compound commands * in a direct command, with a reply expected. * * See 'EV3 Firmware Developer Kit', section 4.8, page 46, at * https://education.lego.com/en-us/support/mindstorms-ev3/developer-kits * for a list of polling/input device commands and their arguments. * * @private */ _pollValues() { if (!this.isConnected()) { window.clearInterval(this._pollingIntervalID); return; } const cmds = []; // compound command let allocation = 0; let sensorCount = 0; // Reset the list of devices every 20 counts if (this._pollingCounter % 20 === 0) { // GET DEVICE LIST cmds[0] = Ev3Opcode.OPINPUT_DEVICE_LIST; cmds[1] = Ev3Encoding.ONE_BYTE; cmds[2] = Ev3Args.MAX_DEVICES; cmds[3] = Ev3Encoding.GLOBAL_VARIABLE_INDEX_0; cmds[4] = Ev3Encoding.GLOBAL_VARIABLE_ONE_BYTE; cmds[5] = Ev3Encoding.GLOBAL_CONSTANT_INDEX_0; // Command and payload lengths allocation = 33; this._updateDevices = true; } else { // GET SENSOR VALUES FOR CONNECTED SENSORS let index = 0; for (let i = 0; i < 4; i++) { if (this._sensorPorts[i] !== 'none') { cmds[index + 0] = Ev3Opcode.OPINPUT_READSI; cmds[index + 1] = Ev3Args.LAYER; cmds[index + 2] = i; // PORT cmds[index + 3] = Ev3Args.DO_NOT_CHANGE_TYPE; cmds[index + 4] = Ev3Mode[this._sensorPorts[i]]; cmds[index + 5] = Ev3Encoding.GLOBAL_VARIABLE_ONE_BYTE; cmds[index + 6] = sensorCount * 4; // GLOBAL INDEX index += 7; } sensorCount++; } // GET MOTOR POSITION VALUES, EVEN IF NO MOTOR PRESENT for (let i = 0; i < 4; i++) { cmds[index + 0] = Ev3Opcode.OPOUTPUT_GET_COUNT; cmds[index + 1] = Ev3Args.LAYER; cmds[index + 2] = i; // PORT (incorrectly specified as 'Output bit field' in LEGO docs) cmds[index + 3] = Ev3Encoding.GLOBAL_VARIABLE_ONE_BYTE; cmds[index + 4] = sensorCount * 4; // GLOBAL INDEX index += 5; sensorCount++; } // Command and payload lengths allocation = sensorCount * 4; } const cmd = this.generateCommand(Ev3Command.DIRECT_COMMAND_REPLY, cmds, allocation); this.send(cmd); this._pollingCounter++; } /** * Message handler for incoming EV3 reply messages, either a list of connected * devices (sensors and motors) or the values of the connected sensors and motors. * * See 'EV3 Communication Developer Kit', section 4.1, page 24 at * https://education.lego.com/en-us/support/mindstorms-ev3/developer-kits * for more details on direct reply formats. * * The direct reply byte array sent takes the following format: * Byte 0 – 1: Reply size, Little Endian. Reply size not including these 2 bytes * Byte 2 – 3: Message counter, Little Endian. Equals the Direct Command * Byte 4: Reply type. Either DIRECT_REPLY or DIRECT_REPLY_ERROR * Byte 5 - n: Resonse buffer. I.e. the content of the by the Command reserved global variables. * I.e. if the command reserved 64 bytes, these bytes will be placed in the reply * packet as the bytes 5 to 68. * * See 'EV3 Firmware Developer Kit', section 4.8, page 56 at * https://education.lego.com/en-us/support/mindstorms-ev3/developer-kits * for direct response buffer formats for various commands. * * @param {object} params - incoming message parameters * @private */ _onMessage(params) { const message = params.message; const data = Base64Util.base64ToUint8Array(message); if (data[4] !== Ev3Command.DIRECT_REPLY) { return; } if (this._updateDevices) { // PARSE DEVICE LIST for (let i = 0; i < 4; i++) { const deviceType = Ev3Device[data[i + 5]]; // if returned device type is null, use 'none' this._sensorPorts[i] = deviceType ? deviceType : 'none'; } for (let i = 0; i < 4; i++) { const deviceType = Ev3Device[data[i + 21]]; // if returned device type is null, use 'none' this._motorPorts[i] = deviceType ? deviceType : 'none'; } for (let m = 0; m < 4; m++) { const type = this._motorPorts[m]; if (type !== 'none' && !this._motors[m]) { // add new motor if don't already have one this._motors[m] = new EV3Motor(this, m, type); } if (type === 'none' && this._motors[m]) { // clear old motor this._motors[m] = null; } } this._updateDevices = false; // eslint-disable-next-line no-undefined } else if (!this._sensorPorts.includes(undefined) && !this._motorPorts.includes(undefined)) { // PARSE SENSOR VALUES let offset = 5; // start reading sensor values at byte 5 for (let i = 0; i < 4; i++) { // array 2 float const buffer = new Uint8Array([data[offset], data[offset + 1], data[offset + 2], data[offset + 3]]).buffer; const view = new DataView(buffer); const value = view.getFloat32(0, true); if (Ev3Label[this._sensorPorts[i]] === 'button') { // Read a button value per port this._sensors.buttons[i] = value ? value : 0; } else if (Ev3Label[this._sensorPorts[i]]) { // if valid // Read brightness / distance values and set to 0 if null this._sensors[Ev3Label[this._sensorPorts[i]]] = value ? value : 0; } offset += 4; } // PARSE MOTOR POSITION VALUES, EVEN IF NO MOTOR PRESENT for (let i = 0; i < 4; i++) { const positionArray = [data[offset], data[offset + 1], data[offset + 2], data[offset + 3]]; if (this._motors[i]) { this._motors[i].position = positionArray; } offset += 4; } } } } /** * Enum for motor port names. * Note: if changed, will break compatibility with previously saved projects. * @readonly * @enum {string} */ const Ev3MotorMenu = ['A', 'B', 'C', 'D']; /** * Enum for sensor port names. * Note: if changed, will break compatibility with previously saved projects. * @readonly * @enum {string} */ const Ev3SensorMenu = ['1', '2', '3', '4']; class Scratch3Ev3Blocks { /** * The ID of the extension. * @return {string} the id */ static get EXTENSION_ID() { return 'ev3'; } /** * Creates a new instance of the EV3 extension. * @param {object} runtime VM runtime * @constructor */ constructor(runtime) { /** * The Scratch 3.0 runtime. * @type {Runtime} */ this.runtime = runtime; // Create a new EV3 peripheral instance this._peripheral = new EV3(this.runtime, Scratch3Ev3Blocks.EXTENSION_ID); this._playNoteForPicker = this._playNoteForPicker.bind(this); this.runtime.on('PLAY_NOTE', this._playNoteForPicker); } /** * Define the EV3 extension. * @return {object} Extension description. */ getInfo() { return { id: Scratch3Ev3Blocks.EXTENSION_ID, name: 'LEGO EV3', blockIconURI: blockIconURI, showStatusButton: true, blocks: [{ opcode: 'motorTurnClockwise', text: formatMessage({ id: 'ev3.motorTurnClockwise', default: 'motor [PORT] turn this way for [TIME] seconds', description: 'turn a motor clockwise for some time' }), blockType: BlockType.COMMAND, arguments: { PORT: { type: ArgumentType.STRING, menu: 'motorPorts', defaultValue: 0 }, TIME: { type: ArgumentType.NUMBER, defaultValue: 1 } } }, { opcode: 'motorTurnCounterClockwise', text: formatMessage({ id: 'ev3.motorTurnCounterClockwise', default: 'motor [PORT] turn that way for [TIME] seconds', description: 'turn a motor counter-clockwise for some time' }), blockType: BlockType.COMMAND, arguments: { PORT: { type: ArgumentType.STRING, menu: 'motorPorts', defaultValue: 0 }, TIME: { type: ArgumentType.NUMBER, defaultValue: 1 } } }, { opcode: 'motorSetPower', text: formatMessage({ id: 'ev3.motorSetPower', default: 'motor [PORT] set power [POWER] %', description: 'set a motor\'s power to some value' }), blockType: BlockType.COMMAND, arguments: { PORT: { type: ArgumentType.STRING, menu: 'motorPorts', defaultValue: 0 }, POWER: { type: ArgumentType.NUMBER, defaultValue: 100 } } }, { opcode: 'getMotorPosition', text: formatMessage({ id: 'ev3.getMotorPosition', default: 'motor [PORT] position', description: 'get the measured degrees a motor has turned' }), blockType: BlockType.REPORTER, arguments: { PORT: { type: ArgumentType.STRING, menu: 'motorPorts', defaultValue: 0 } } }, { opcode: 'whenButtonPressed', text: formatMessage({ id: 'ev3.whenButtonPressed', default: 'when button [PORT] pressed', description: 'when a button connected to a port is pressed' }), blockType: BlockType.HAT, arguments: { PORT: { type: ArgumentType.STRING, menu: 'sensorPorts', defaultValue: 0 } } }, { opcode: 'whenDistanceLessThan', text: formatMessage({ id: 'ev3.whenDistanceLessThan', default: 'when distance < [DISTANCE]', description: 'when the value measured by the distance sensor is less than some value' }), blockType: BlockType.HAT, arguments: { DISTANCE: { type: ArgumentType.NUMBER, defaultValue: 5 } } }, { opcode: 'whenBrightnessLessThan', text: formatMessage({ id: 'ev3.whenBrightnessLessThan', default: 'when brightness < [DISTANCE]', description: 'when value measured by brightness sensor is less than some value' }), blockType: BlockType.HAT, arguments: { DISTANCE: { type: ArgumentType.NUMBER, defaultValue: 50 } } }, { opcode: 'buttonPressed', text: formatMessage({ id: 'ev3.buttonPressed', default: 'button [PORT] pressed?', description: 'is a button on some port pressed?' }), blockType: BlockType.BOOLEAN, arguments: { PORT: { type: ArgumentType.STRING, menu: 'sensorPorts', defaultValue: 0 } } }, { opcode: 'getDistance', text: formatMessage({ id: 'ev3.getDistance', default: 'distance', description: 'gets measured distance' }), blockType: BlockType.REPORTER }, { opcode: 'getBrightness', text: formatMessage({ id: 'ev3.getBrightness', default: 'brightness', description: 'gets measured brightness' }), blockType: BlockType.REPORTER }, { opcode: 'beep', text: formatMessage({ id: 'ev3.beepNote', default: 'beep note [NOTE] for [TIME] secs', description: 'play some note on EV3 for some time' }), blockType: BlockType.COMMAND, arguments: { NOTE: { type: ArgumentType.NOTE, defaultValue: 60 }, TIME: { type: ArgumentType.NUMBER, defaultValue: 0.5 } } }], menus: { motorPorts: { acceptReporters: true, items: this._formatMenu(Ev3MotorMenu) }, sensorPorts: { acceptReporters: true, items: this._formatMenu(Ev3SensorMenu) } } }; } motorTurnClockwise(args) { const port = Cast.toNumber(args.PORT); let time = Cast.toNumber(args.TIME) * 1000; time = MathUtil.clamp(time, 0, 15000); return new Promise(resolve => { this._forEachMotor(port, motorIndex => { const motor = this._peripheral.motor(motorIndex); if (motor) { motor.direction = 1; motor.turnOnFor(time); } }); // Run for some time even when no motor is connected setTimeout(resolve, time); }); } motorTurnCounterClockwise(args) { const port = Cast.toNumber(args.PORT); let time = Cast.toNumber(args.TIME) * 1000; time = MathUtil.clamp(time, 0, 15000); return new Promise(resolve => { this._forEachMotor(port, motorIndex => { const motor = this._peripheral.motor(motorIndex); if (motor) { motor.direction = -1; motor.turnOnFor(time); } }); // Run for some time even when no motor is connected setTimeout(resolve, time); }); } motorSetPower(args) { const port = Cast.toNumber(args.PORT); const power = MathUtil.clamp(Cast.toNumber(args.POWER), 0, 100); this._forEachMotor(port, motorIndex => { const motor = this._peripheral.motor(motorIndex); if (motor) { motor.power = power; } }); } getMotorPosition(args) { const port = Cast.toNumber(args.PORT); if (![0, 1, 2, 3].includes(port)) { return; } const motor = this._peripheral.motor(port); let position = 0; if (motor) { position = MathUtil.wrapClamp(motor.position, 0, 360); } return position; } whenButtonPressed(args) { const port = Cast.toNumber(args.PORT); if (![0, 1, 2, 3].includes(port)) { return; } return this._peripheral.isButtonPressed(port); } whenDistanceLessThan(args) { const distance = MathUtil.clamp(Cast.toNumber(args.DISTANCE), 0, 100); return this._peripheral.distance < distance; } whenBrightnessLessThan(args) { const brightness = MathUtil.clamp(Cast.toNumber(args.DISTANCE), 0, 100); return this._peripheral.brightness < brightness; } buttonPressed(args) { const port = Cast.toNumber(args.PORT); if (![0, 1, 2, 3].includes(port)) { return; } return this._peripheral.isButtonPressed(port); } getDistance() { return this._peripheral.distance; } getBrightness() { return this._peripheral.brightness; } _playNoteForPicker(note, category) { if (category !== this.getInfo().name) return; this.beep({ NOTE: note, TIME: 0.25 }); } beep(args) { const note = MathUtil.clamp(Cast.toNumber(args.NOTE), 47, 99); // valid EV3 sounds let time = Cast.toNumber(args.TIME) * 1000; time = MathUtil.clamp(time, 0, 3000); if (time === 0) { return; // don't send a beep time of 0 } return new Promise(resolve => { // https://en.wikipedia.org/wiki/MIDI_tuning_standard#Frequency_values const freq = Math.pow(2, (note - 69 + 12) / 12) * 440; this._peripheral.beep(freq, time); // Run for some time even when no piezo is connected. setTimeout(resolve, time); }); } /** * Call a callback for each motor indexed by the provided motor ID. * * Note: This way of looping through motors is currently unnecessary, but could be * useful if an 'all motors' option is added in the future (see WeDo2 extension). * * @param {MotorID} motorID - the ID specifier. * @param {Function} callback - the function to call with the numeric motor index for each motor. * @private */ _forEachMotor(motorID, callback) { let motors; switch (motorID) { case 0: motors = [0]; break; case 1: motors = [1]; break; case 2: motors = [2]; break; case 3: motors = [3]; break; default: log.warn("Invalid motor ID: ".concat(motorID)); motors = []; break; } for (const index of motors) { callback(index); } } /** * Formats menus into a format suitable for block menus, and loading previously * saved projects: * [ * { * text: label, * value: index * }, * { * text: label, * value: index * }, * etc... * ] * * @param {array} menu - a menu to format. * @return {object} - a formatted menu as an object. * @private */ _formatMenu(menu) { const m = []; for (let i = 0; i < menu.length; i++) { const obj = {}; obj.text = menu[i]; obj.value = i.toString(); m.push(obj); } return m; } } module.exports = Scratch3Ev3Blocks; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_gdx_for/index.js": /*!**************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_gdx_for/index.js ***! \**************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const ArgumentType = __webpack_require__(/*! ../../extension-support/argument-type */ "./node_modules/scratch-vm/src/extension-support/argument-type.js"); const BlockType = __webpack_require__(/*! ../../extension-support/block-type */ "./node_modules/scratch-vm/src/extension-support/block-type.js"); const log = __webpack_require__(/*! ../../util/log */ "./node_modules/scratch-vm/src/util/log.js"); const formatMessage = __webpack_require__(/*! format-message */ "./node_modules/format-message/index.js"); const MathUtil = __webpack_require__(/*! ../../util/math-util */ "./node_modules/scratch-vm/src/util/math-util.js"); const BLE = __webpack_require__(/*! ../../io/ble */ "./node_modules/scratch-vm/src/io/ble.js"); const godirect = __webpack_require__(/*! @vernier/godirect/dist/godirect.min.umd.js */ "./node_modules/@vernier/godirect/dist/godirect.min.umd.js"); const ScratchLinkDeviceAdapter = __webpack_require__(/*! ./scratch-link-device-adapter */ "./node_modules/scratch-vm/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js"); /** * Icon png to be displayed at the left edge of each extension block, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len const blockIconURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAABGdBTUEAALGPC/xhBQAACCNJREFUeAHtnGtsFFUUgM+dfXbbbbcWaKHSFgrlkWgkJCb6A4kmJfiHIBYBpcFfRg1GEkmEVAvhFYw/TExMxGoICAECiZEIIUQCiiT4gh+KILRQCi2ENIV2t/ue6zl3u2Upu4XuzO4csCe587iPmXO/OWfunTszV4ABWfflQU+0p+9bTcLzEmS5gUPlvagAcVMXcMpnK1u+evW8QLYKaNkWpHKxnt6dQsqFjxo80p10Jt1vx7t30n62Ys+2IJUTUpDlqUNomgYutwsjhZFD5r6slBAOhUHX9YTe6D1GTmrIAhFeBZ2c4JFCpBiggmwlBR7pTGLUewxZYBIUWV7yqgb7g8lotuukt5ihqyELHCSEbusk931ExMxbjSkWSNxEyr3vysxZLFHWnDuT0CtFV6OKmmOBRrV4hMubZoGmMZA6lHTfgsLeHnBEIiCxUY86XRDw+sBfOgZ0m820U5lxIFYAncF+GNvVDo5QaLBu1ClyYTyF4tvd8lZltQgXFA6mW73BxoVt0ShUXG2VCp4QQdDEFqez4Bm7p7gaO0of422r3x4Ji/KrbdIexu4SE2FjgWO6OkCLx6gt6gxOiNV92tiY+ni1Ye1nu7dpQfk35ikru9EBN6unsEDIwgLJPQv8dwCfT3WPt+iFIfAUqM3vL7vpjmuz0KX1gkAfOMN33dxKkjwA9vsTDIS8uubdBZcyAWlqWtohQbRSuru/L1O2vMazAGiLxRKVFqDgDEdAaHCN0kU8Ply2vKWxABhzJZ5ipC6qHlRzfJxVz99S49GdYQEw7PYkuAmokZJ6fumlQUqiNpVSQ56i9JnyHMsCYMRdADGHk0ZyHM1b976XicH0rXtWYR57FPNSGQ7CAiCBCJQ8oXhI0FdmBiPfVnl9ZZmz5DmFDcA+HwIUOEYMcjL2+e57PbBp04HxONI4ifIEKC8TYQMwhs+7IU+hwBFOYQvB5qF8grbwJnRfQXnIhbkIG4AExF+ScE00w0X3AZLwisrDyH1JH1YAA8UlIG029FRZsu6TPfVJiIltWYIjMTLgLUlGs1izeRYmGtS383t9wnu7G2J6fH/Tln2LNUdExGLxvZSOQ1qCS/+P9CFhBZAUuj12PHgCvRJHZ7w4EnhYjya6hXGHQ2Jaxj4ilbVC2AFEUNBVXSdKb3WC29+rmISKiqFn7ARBadyEHUACFHM64VZlDTdWafVh1Yik1ZB5JEsLJGaVtosw37ld4TscWQHX4+oRWO1zWrAEWCR6oMnTCEXijmI1234MVvsPgV+WcmKndGHpwlNtZwbhkZYEkuI4CkuAXfpk0HGAPym0TXEchaUL39Br4JvQeljk+lwxOxBeCRQ3UrFHI+AMBsEV6gcnhlwIS4BU0RORV1V42EqnwnLgSyo3AsM3eA9bPOt8bAEOV6NUWGRZ9FYvHSx6R0pfYgkMmk2DCH1+Z7KwB5gKazjLGgpLgUOAuRZWALnDSncxLAOYCmskbqjhe02h5d6y0sFKF5cXgI8LrLwB9PTeGew6POwNnptlpYOVLi4nFjjuWts957rnBk8tomoZ+bjhPcqOcCcnAG34EaTqOjxmsNKxzQnAkX5wronsOry6zIn66ThljLNcg+W1a2Gi55+MCg6XcKl3NuxrbxouS87TLAcY1V0QV5+8jLyuEekeeSGTS1gOcM/lZpOrlN/DsRzOyi8CY2fLuwUum/wR1BT+ZUzrDKUv9D4LB9rXZEjNTfRjZYFS5r86ebfA3W0bcmMKFh01/5fMoorm6rSjAA2SNc2F8dvmQVWCgdy8fxg8gcEN0pWez80QUyyQFAqn/N9mhmK5PAYN7adecCPnMsUCCZ7U8ari4IGb87wJeKFDA/MlmHXBDVkgTR1CV4/gaThKzBoeKYpuSzqSrqSzEiFuJDayWxqyQJp3RUhYSKfWUSEz5iDIrhrZl8I5b37JvrTBT3wdpd43cOqT/WiJhq6ikQpkW5a8BxuS/X219uXZHoPKmdMUGdEgpWzTll3Kr95Z8VJK7N3NL7b/qHY2rnmdjd6G7oF3q/b/3RoFaPDajwIcBWiQgMHioxZoEKChfqDBc2csnmxtM2ZglMDKArFvduhBbLDv9sOD8oymA0xBCHVtl6+c7ey6Ibdt+3ox7WOoxMCmD4i68PrZkBQaEDUe1tnVqSyyfl79+vr6evz1C2jKogkYWEEc0JnViiZRqKuoqJiZtEJcn0GIsykewzhW2jJVZjzBamxsfK79ase/5MoXL106TnEDwfq36qgIF6HGjKyqFsNkDGMwUNxEDEmIHQTxyNGjH1AchvumBcC4vAuXVpiA+TDYMFDXiiZFoN+SrmMI7tixo/v3337diNtQUzNpPq1RChIra5ccAFKDUEwYLra2fnXu3PmtA0gojqbaVUNl23ft+pPiPW73U7RGYdGH5QCQYCg93C73075S34I5c+ZQa0s/B1Njou51tVVVatJAXcrED3Q4EI5plgsHgAQiSiRCoRD9ECeam9fPo32UJzFQYwJLlix9mdZ9fb1naY2iyiQ2rVtyAEi199Pi5M8/tdB62vRpzceOH3+toaHBh61w2clTp96sqq5ehUnxw0eO7KA8KKpMYtO6JZcOKTUeNRhsp0+ffmtilYI1VLf4+Qvn1784d+5ezEfW144hMR05blglpDgHSbqxt6Wl5Y8ZM6afKq8oL7LZHd54PH7H7w+cOPj9dx8uXbLk+ICynbhm4cJDr7LVMKmhoP5dphaWoFGrHMTAQrgBJCjkFdQHpPntqCUmiWCge14PBsvdFnUYlP8AMAKfKIKmYukAAAAASUVORK5CYII='; /** * Icon png to be displayed in the blocks category menu, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len const menuIconURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABGdBTUEAALGPC/xhBQAAA9dJREFUWAnNmE2IFEcUgF/9dE/v7LoaM9kkK4JBRA0EFBIPRm85hBAvEXHXwyo5eFE87GFcReMkObgJiQnkkJzEg9n8HIJixKNe1IMKihgiCbviwV11V3d0d3pmuqsqr5ppcEnb3TNVggVFVVe9eu+r97qqq4tASqp8/fsboQgmU0TMugi571K29bPy9ovPU8Sf16HbpQj3EkYFBcJcr5Am2nZfs94AIWVfqMQeHNwhICUBZ4ypUIA/X2sbIm2AW8AJK0lkEP6TJpfqwXgg4QxmF/fB7Gtvxk1G5ZKHU1CqTgPJoSUXYJYeohSUJu+qrqdVUGh2/pVX4VFffx77WaqBZkrkEFj271+qWH0sXcU3FBzyQe/Mg7B//LbKMTRTxNiDbsMHHjTJlyM7HEJIBHXs2KXFj+oTNSdoQOCYLS5jD9IwBMm5H8NplwwPb/QV4yEIcycaAza9IuA76B38fuz1OF5RXUkmHCdu6rg0BpSMgV/sAe7DdzGFrvvdi0D3mSZjQA0wt7REQsY+iWF0XbfFzyal8SLRxuteD+Du4h4Z/flbqaBHibAQtZmQtcZaAZSMwtTylaR/4vaw1ju5YhWG10pwwAqghmp2FeHO2+t11WqyM80W0m7vAOhsM1kD7CGz8L57Jsq6bitZC/GcWgLf1H6KuHT92cTDAFy/BgXMXm0OCpgV50Bo9kK3BqiBboabQMMU/WoL5im4jToeq/AIgXsiRx5KKCjcwPEsiAv/BQMu9EwyDHXd/3kqCOSzDk6t5/YglQKKeJwq+PNRmJI8kwSTaj1HZy5AhSHqnXkIvU9mMUwEw4Q5wTM57LUtkg8QPw/cdcBJ+PhvKJ0Gj80nGq6JXrg6/XFiX97GXIBpyqTieKpKViOl+WEhWXMaUavvvdIZ8Giy5+Lh3bwKm/t+Be3JazMfxc1tldY26rastiHcsQevTG9pw0znovkAcRWHzSDKnZtaOJLSfMFLB5RqtRBS4LbCurqLCy0YPkU3C0IIPEimMqR2ei7ZX2+KQdRi/WahNT/GmfOD4Vyzhx/66pcjp85dUvcmp6J8+txldXh07PPskdkS+V6EbD0vTOKlB0x9B/O6BS8ULly9PgE6x4kDPR/XX5pyYKj8xcCucsUmkNUQE0JvKKm2VioVK5HRE7UKOHbi6B94RzP+93jtpC0vWgXUF0hr3ipuw8uadwd3jXxoA9IK4Pah8t6BneV9GgjD28Svw1mlxFobgFbeFTz13cKbth93fDryp2CEq0a4hTA+aAPQ/ESJFDdvXLzzzrqNjlTqOP6uDeFf0uhvJ0ZP2QD8D6ZzU6u8YIbBAAAAAElFTkSuQmCC'; /** * Enum for Vernier godirect protocol. * @readonly * @enum {string} */ const BLEUUID = { service: 'd91714ef-28b9-4f91-ba16-f0d9a604f112', commandChar: 'f4bf14a6-c7d5-4b6d-8aa8-df1a7c83adcb', responseChar: 'b41e6675-a329-40e0-aa01-44d2f444babe' }; /** * A time interval to wait (in milliseconds) before reporting to the BLE socket * that data has stopped coming from the peripheral. */ const BLETimeout = 4500; /** * A string to report to the BLE socket when the GdxFor has stopped receiving data. * @type {string} */ const BLEDataStoppedError = 'Force and Acceleration extension stopped receiving data'; /** * Sensor ID numbers for the GDX-FOR. */ const GDXFOR_SENSOR = { FORCE: 1, ACCELERATION_X: 2, ACCELERATION_Y: 3, ACCELERATION_Z: 4, SPIN_SPEED_X: 5, SPIN_SPEED_Y: 6, SPIN_SPEED_Z: 7 }; /** * The update rate, in milliseconds, for sensor data input from the peripheral. */ const GDXFOR_UPDATE_RATE = 80; /** * Threshold for pushing and pulling force, for the whenForcePushedOrPulled hat block. * @type {number} */ const FORCE_THRESHOLD = 5; /** * Threshold for acceleration magnitude, for the "shaken" gesture. * @type {number} */ const SHAKEN_THRESHOLD = 30; /** * Threshold for acceleration magnitude, to check if we are facing up. * @type {number} */ const FACING_THRESHOLD = 9; /** * An offset for the facing threshold, used to check that we are no longer facing up. * @type {number} */ const FACING_THRESHOLD_OFFSET = 5; /** * Threshold for acceleration magnitude, below which we are in freefall. * @type {number} */ const FREEFALL_THRESHOLD = 0.5; /** * Factor used to account for influence of rotation during freefall. * @type {number} */ const FREEFALL_ROTATION_FACTOR = 0.3; /** * Threshold in degrees for reporting that the sensor is tilted. * @type {number} */ const TILT_THRESHOLD = 15; /** * Acceleration due to gravity, in m/s^2. * @type {number} */ const GRAVITY = 9.8; /** * Manage communication with a GDX-FOR peripheral over a Scratch Link client socket. */ class GdxFor { /** * Construct a GDX-FOR communication object. * @param {Runtime} runtime - the Scratch 3.0 runtime * @param {string} extensionId - the id of the extension */ constructor(runtime, extensionId) { /** * The Scratch 3.0 runtime used to trigger the green flag button. * @type {Runtime} * @private */ this._runtime = runtime; /** * The BluetoothLowEnergy connection socket for reading/writing peripheral data. * @type {BLE} * @private */ this._ble = null; /** * An @vernier/godirect Device * @type {Device} * @private */ this._device = null; this._runtime.registerPeripheralExtension(extensionId, this); /** * The id of the extension this peripheral belongs to. */ this._extensionId = extensionId; /** * The most recently received value for each sensor. * @type {Object.} * @private */ this._sensors = { force: 0, accelerationX: 0, accelerationY: 0, accelerationZ: 0, spinSpeedX: 0, spinSpeedY: 0, spinSpeedZ: 0 }; /** * Interval ID for data reading timeout. * @type {number} * @private */ this._timeoutID = null; this.reset = this.reset.bind(this); this._onConnect = this._onConnect.bind(this); } /** * Called by the runtime when user wants to scan for a peripheral. */ scan() { if (this._ble) { this._ble.disconnect(); } this._ble = new BLE(this._runtime, this._extensionId, { filters: [{ namePrefix: 'GDX-FOR' }], optionalServices: [BLEUUID.service] }, this._onConnect, this.reset); } /** * Called by the runtime when user wants to connect to a certain peripheral. * @param {number} id - the id of the peripheral to connect to. */ connect(id) { if (this._ble) { this._ble.connectPeripheral(id); } } /** * Called by the runtime when a user exits the connection popup. * Disconnect from the GDX FOR. */ disconnect() { if (this._ble) { this._ble.disconnect(); } this.reset(); } /** * Reset all the state and timeout/interval ids. */ reset() { this._sensors = { force: 0, accelerationX: 0, accelerationY: 0, accelerationZ: 0, spinSpeedX: 0, spinSpeedY: 0, spinSpeedZ: 0 }; if (this._timeoutID) { window.clearInterval(this._timeoutID); this._timeoutID = null; } } /** * Return true if connected to the goforce device. * @return {boolean} - whether the goforce is connected. */ isConnected() { let connected = false; if (this._ble) { connected = this._ble.isConnected(); } return connected; } /** * Starts reading data from peripheral after BLE has connected to it. * @private */ _onConnect() { const adapter = new ScratchLinkDeviceAdapter(this._ble, BLEUUID); godirect.createDevice(adapter, { open: true, startMeasurements: false }).then(device => { // Setup device this._device = device; this._device.keepValues = false; // todo: possibly remove after updating Vernier godirect module // Enable sensors this._device.sensors.forEach(sensor => { sensor.setEnabled(true); }); // Set sensor value-update behavior this._device.on('measurements-started', () => { const enabledSensors = this._device.sensors.filter(s => s.enabled); enabledSensors.forEach(sensor => { sensor.on('value-changed', s => { this._onSensorValueChanged(s); }); }); this._timeoutID = window.setInterval(() => this._ble.handleDisconnectError(BLEDataStoppedError), BLETimeout); }); // Start device this._device.start(GDXFOR_UPDATE_RATE); }); } /** * Handler for sensor value changes from the goforce device. * @param {object} sensor - goforce device sensor whose value has changed * @private */ _onSensorValueChanged(sensor) { switch (sensor.number) { case GDXFOR_SENSOR.FORCE: // Normalize the force, which can be measured between -50 and 50 N, // to be a value between -100 and 100. this._sensors.force = MathUtil.clamp(sensor.value * 2, -100, 100); break; case GDXFOR_SENSOR.ACCELERATION_X: this._sensors.accelerationX = sensor.value; break; case GDXFOR_SENSOR.ACCELERATION_Y: this._sensors.accelerationY = sensor.value; break; case GDXFOR_SENSOR.ACCELERATION_Z: this._sensors.accelerationZ = sensor.value; break; case GDXFOR_SENSOR.SPIN_SPEED_X: this._sensors.spinSpeedX = this._spinSpeedFromGyro(sensor.value); break; case GDXFOR_SENSOR.SPIN_SPEED_Y: this._sensors.spinSpeedY = this._spinSpeedFromGyro(sensor.value); break; case GDXFOR_SENSOR.SPIN_SPEED_Z: this._sensors.spinSpeedZ = this._spinSpeedFromGyro(sensor.value); break; } // cancel disconnect timeout and start a new one window.clearInterval(this._timeoutID); this._timeoutID = window.setInterval(() => this._ble.handleDisconnectError(BLEDataStoppedError), BLETimeout); } _spinSpeedFromGyro(val) { const framesPerSec = 1000 / this._runtime.currentStepTime; val = MathUtil.radToDeg(val); val = val / framesPerSec; // convert to from degrees per sec to degrees per frame val = val * -1; return val; } getForce() { return this._sensors.force; } getTiltFrontBack(back = false) { const x = this.getAccelerationX(); const y = this.getAccelerationY(); const z = this.getAccelerationZ(); // Compute the yz unit vector const y2 = y * y; const z2 = z * z; let value = y2 + z2; value = Math.sqrt(value); // For sufficiently small zy vector values we are essentially at 90 degrees. // The following snaps to 90 and avoids divide-by-zero errors. // The snap factor was derived through observation -- just enough to // still allow single degree steps up to 90 (..., 87, 88, 89, 90). if (value < 0.35) { value = x < 0 ? 90 : -90; } else { value = x / value; value = Math.atan(value); value = MathUtil.radToDeg(value) * -1; } // Back is the inverse of front if (back) value *= -1; return value; } getTiltLeftRight(right = false) { const x = this.getAccelerationX(); const y = this.getAccelerationY(); const z = this.getAccelerationZ(); // Compute the yz unit vector const x2 = x * x; const z2 = z * z; let value = x2 + z2; value = Math.sqrt(value); // For sufficiently small zy vector values we are essentially at 90 degrees. // The following snaps to 90 and avoids divide-by-zero errors. // The snap factor was derived through observation -- just enough to // still allow single degree steps up to 90 (..., 87, 88, 89, 90). if (value < 0.35) { value = y < 0 ? 90 : -90; } else { value = y / value; value = Math.atan(value); value = MathUtil.radToDeg(value) * -1; } // Right is the inverse of left if (right) value *= -1; return value; } getAccelerationX() { return this._sensors.accelerationX; } getAccelerationY() { return this._sensors.accelerationY; } getAccelerationZ() { return this._sensors.accelerationZ; } getSpinSpeedX() { return this._sensors.spinSpeedX; } getSpinSpeedY() { return this._sensors.spinSpeedY; } getSpinSpeedZ() { return this._sensors.spinSpeedZ; } } /** * Enum for pushed and pulled menu options. * @readonly * @enum {string} */ const PushPullValues = { PUSHED: 'pushed', PULLED: 'pulled' }; /** * Enum for motion gesture menu options. * @readonly * @enum {string} */ const GestureValues = { SHAKEN: 'shaken', STARTED_FALLING: 'started falling', TURNED_FACE_UP: 'turned face up', TURNED_FACE_DOWN: 'turned face down' }; /** * Enum for tilt axis menu options. * @readonly * @enum {string} */ const TiltAxisValues = { FRONT: 'front', BACK: 'back', LEFT: 'left', RIGHT: 'right', ANY: 'any' }; /** * Enum for axis menu options. * @readonly * @enum {string} */ const AxisValues = { X: 'x', Y: 'y', Z: 'z' }; /** * Scratch 3.0 blocks to interact with a GDX-FOR peripheral. */ class Scratch3GdxForBlocks { /** * @return {string} - the name of this extension. */ static get EXTENSION_NAME() { return 'Force and Acceleration'; } /** * @return {string} - the ID of this extension. */ static get EXTENSION_ID() { return 'gdxfor'; } get AXIS_MENU() { return [{ text: 'x', value: AxisValues.X }, { text: 'y', value: AxisValues.Y }, { text: 'z', value: AxisValues.Z }]; } get TILT_MENU() { return [{ text: formatMessage({ id: 'gdxfor.tiltDirectionMenu.front', default: 'front', description: 'label for front element in tilt direction picker for gdxfor extension' }), value: TiltAxisValues.FRONT }, { text: formatMessage({ id: 'gdxfor.tiltDirectionMenu.back', default: 'back', description: 'label for back element in tilt direction picker for gdxfor extension' }), value: TiltAxisValues.BACK }, { text: formatMessage({ id: 'gdxfor.tiltDirectionMenu.left', default: 'left', description: 'label for left element in tilt direction picker for gdxfor extension' }), value: TiltAxisValues.LEFT }, { text: formatMessage({ id: 'gdxfor.tiltDirectionMenu.right', default: 'right', description: 'label for right element in tilt direction picker for gdxfor extension' }), value: TiltAxisValues.RIGHT }]; } get TILT_MENU_ANY() { return [...this.TILT_MENU, { text: formatMessage({ id: 'gdxfor.tiltDirectionMenu.any', default: 'any', description: 'label for any direction element in tilt direction picker for gdxfor extension' }), value: TiltAxisValues.ANY }]; } get PUSH_PULL_MENU() { return [{ text: formatMessage({ id: 'gdxfor.pushed', default: 'pushed', description: 'the force sensor was pushed inward' }), value: PushPullValues.PUSHED }, { text: formatMessage({ id: 'gdxfor.pulled', default: 'pulled', description: 'the force sensor was pulled outward' }), value: PushPullValues.PULLED }]; } get GESTURE_MENU() { return [{ text: formatMessage({ id: 'gdxfor.shaken', default: 'shaken', description: 'the sensor was shaken' }), value: GestureValues.SHAKEN }, { text: formatMessage({ id: 'gdxfor.startedFalling', default: 'started falling', description: 'the sensor started free falling' }), value: GestureValues.STARTED_FALLING }, { text: formatMessage({ id: 'gdxfor.turnedFaceUp', default: 'turned face up', description: 'the sensor was turned to face up' }), value: GestureValues.TURNED_FACE_UP }, { text: formatMessage({ id: 'gdxfor.turnedFaceDown', default: 'turned face down', description: 'the sensor was turned to face down' }), value: GestureValues.TURNED_FACE_DOWN }]; } /** * Construct a set of GDX-FOR blocks. * @param {Runtime} runtime - the Scratch 3.0 runtime. */ constructor(runtime) { /** * The Scratch 3.0 runtime. * @type {Runtime} */ this.runtime = runtime; // Create a new GdxFor peripheral instance this._peripheral = new GdxFor(this.runtime, Scratch3GdxForBlocks.EXTENSION_ID); } /** * @returns {object} metadata for this extension and its blocks. */ getInfo() { return { id: Scratch3GdxForBlocks.EXTENSION_ID, name: Scratch3GdxForBlocks.EXTENSION_NAME, blockIconURI: blockIconURI, menuIconURI: menuIconURI, showStatusButton: true, blocks: [{ opcode: 'whenGesture', text: formatMessage({ id: 'gdxfor.whenGesture', default: 'when [GESTURE]', description: 'when the sensor detects a gesture' }), blockType: BlockType.HAT, arguments: { GESTURE: { type: ArgumentType.STRING, menu: 'gestureOptions', defaultValue: GestureValues.SHAKEN } } }, { opcode: 'whenForcePushedOrPulled', text: formatMessage({ id: 'gdxfor.whenForcePushedOrPulled', default: 'when force sensor [PUSH_PULL]', description: 'when the force sensor is pushed or pulled' }), blockType: BlockType.HAT, arguments: { PUSH_PULL: { type: ArgumentType.STRING, menu: 'pushPullOptions', defaultValue: PushPullValues.PUSHED } } }, { opcode: 'getForce', text: formatMessage({ id: 'gdxfor.getForce', default: 'force', description: 'gets force' }), blockType: BlockType.REPORTER }, '---', { opcode: 'whenTilted', text: formatMessage({ id: 'gdxfor.whenTilted', default: 'when tilted [TILT]', description: 'when the sensor detects tilt' }), blockType: BlockType.HAT, arguments: { TILT: { type: ArgumentType.STRING, menu: 'tiltAnyOptions', defaultValue: TiltAxisValues.ANY } } }, { opcode: 'isTilted', text: formatMessage({ id: 'gdxfor.isTilted', default: 'tilted [TILT]?', description: 'is the device tilted?' }), blockType: BlockType.BOOLEAN, arguments: { TILT: { type: ArgumentType.STRING, menu: 'tiltAnyOptions', defaultValue: TiltAxisValues.ANY } } }, { opcode: 'getTilt', text: formatMessage({ id: 'gdxfor.getTilt', default: 'tilt angle [TILT]', description: 'gets tilt' }), blockType: BlockType.REPORTER, arguments: { TILT: { type: ArgumentType.STRING, menu: 'tiltOptions', defaultValue: TiltAxisValues.FRONT } } }, '---', { opcode: 'isFreeFalling', text: formatMessage({ id: 'gdxfor.isFreeFalling', default: 'falling?', description: 'is the device in free fall?' }), blockType: BlockType.BOOLEAN }, { opcode: 'getSpinSpeed', text: formatMessage({ id: 'gdxfor.getSpin', default: 'spin speed [DIRECTION]', description: 'gets spin speed' }), blockType: BlockType.REPORTER, arguments: { DIRECTION: { type: ArgumentType.STRING, menu: 'axisOptions', defaultValue: AxisValues.Z } } }, { opcode: 'getAcceleration', text: formatMessage({ id: 'gdxfor.getAcceleration', default: 'acceleration [DIRECTION]', description: 'gets acceleration' }), blockType: BlockType.REPORTER, arguments: { DIRECTION: { type: ArgumentType.STRING, menu: 'axisOptions', defaultValue: AxisValues.X } } }], menus: { pushPullOptions: { acceptReporters: true, items: this.PUSH_PULL_MENU }, gestureOptions: { acceptReporters: true, items: this.GESTURE_MENU }, axisOptions: { acceptReporters: true, items: this.AXIS_MENU }, tiltOptions: { acceptReporters: true, items: this.TILT_MENU }, tiltAnyOptions: { acceptReporters: true, items: this.TILT_MENU_ANY } } }; } whenForcePushedOrPulled(args) { switch (args.PUSH_PULL) { case PushPullValues.PUSHED: return this._peripheral.getForce() < FORCE_THRESHOLD * -1; case PushPullValues.PULLED: return this._peripheral.getForce() > FORCE_THRESHOLD; default: log.warn("unknown push/pull value in whenForcePushedOrPulled: ".concat(args.PUSH_PULL)); return false; } } getForce() { return Math.round(this._peripheral.getForce()); } whenGesture(args) { switch (args.GESTURE) { case GestureValues.SHAKEN: return this.gestureMagnitude() > SHAKEN_THRESHOLD; case GestureValues.STARTED_FALLING: return this.isFreeFalling(); case GestureValues.TURNED_FACE_UP: return this._isFacing(GestureValues.TURNED_FACE_UP); case GestureValues.TURNED_FACE_DOWN: return this._isFacing(GestureValues.TURNED_FACE_DOWN); default: log.warn("unknown gesture value in whenGesture: ".concat(args.GESTURE)); return false; } } _isFacing(direction) { if (typeof this._facingUp === 'undefined') { this._facingUp = false; } if (typeof this._facingDown === 'undefined') { this._facingDown = false; } // If the sensor is already facing up or down, reduce the threshold. // This prevents small fluctations in acceleration while it is being // turned from causing the hat block to trigger multiple times. let threshold = FACING_THRESHOLD; if (this._facingUp || this._facingDown) { threshold -= FACING_THRESHOLD_OFFSET; } this._facingUp = this._peripheral.getAccelerationZ() > threshold; this._facingDown = this._peripheral.getAccelerationZ() < threshold * -1; switch (direction) { case GestureValues.TURNED_FACE_UP: return this._facingUp; case GestureValues.TURNED_FACE_DOWN: return this._facingDown; default: return false; } } whenTilted(args) { return this._isTilted(args.TILT); } isTilted(args) { return this._isTilted(args.TILT); } getTilt(args) { return this._getTiltAngle(args.TILT); } _isTilted(direction) { switch (direction) { case TiltAxisValues.ANY: return this._getTiltAngle(TiltAxisValues.FRONT) > TILT_THRESHOLD || this._getTiltAngle(TiltAxisValues.BACK) > TILT_THRESHOLD || this._getTiltAngle(TiltAxisValues.LEFT) > TILT_THRESHOLD || this._getTiltAngle(TiltAxisValues.RIGHT) > TILT_THRESHOLD; default: return this._getTiltAngle(direction) > TILT_THRESHOLD; } } _getTiltAngle(direction) { // Tilt values are calculated using acceleration due to gravity, // so we need to return 0 when the peripheral is not connected. if (!this._peripheral.isConnected()) { return 0; } switch (direction) { case TiltAxisValues.FRONT: return Math.round(this._peripheral.getTiltFrontBack(true)); case TiltAxisValues.BACK: return Math.round(this._peripheral.getTiltFrontBack(false)); case TiltAxisValues.LEFT: return Math.round(this._peripheral.getTiltLeftRight(true)); case TiltAxisValues.RIGHT: return Math.round(this._peripheral.getTiltLeftRight(false)); default: log.warn("Unknown direction in getTilt: ".concat(direction)); } } getSpinSpeed(args) { switch (args.DIRECTION) { case AxisValues.X: return Math.round(this._peripheral.getSpinSpeedX()); case AxisValues.Y: return Math.round(this._peripheral.getSpinSpeedY()); case AxisValues.Z: return Math.round(this._peripheral.getSpinSpeedZ()); default: log.warn("Unknown direction in getSpinSpeed: ".concat(args.DIRECTION)); } } getAcceleration(args) { switch (args.DIRECTION) { case AxisValues.X: return Math.round(this._peripheral.getAccelerationX()); case AxisValues.Y: return Math.round(this._peripheral.getAccelerationY()); case AxisValues.Z: return Math.round(this._peripheral.getAccelerationZ()); default: log.warn("Unknown direction in getAcceleration: ".concat(args.DIRECTION)); } } /** * @param {number} x - x axis vector * @param {number} y - y axis vector * @param {number} z - z axis vector * @return {number} - the magnitude of a three dimension vector. */ magnitude(x, y, z) { return Math.sqrt(x * x + y * y + z * z); } accelMagnitude() { return this.magnitude(this._peripheral.getAccelerationX(), this._peripheral.getAccelerationY(), this._peripheral.getAccelerationZ()); } gestureMagnitude() { return this.accelMagnitude() - GRAVITY; } spinMagnitude() { return this.magnitude(this._peripheral.getSpinSpeedX(), this._peripheral.getSpinSpeedY(), this._peripheral.getSpinSpeedZ()); } isFreeFalling() { // When the peripheral is not connected, the acceleration magnitude // is 0 instead of ~9.8, which ends up calculating as a positive // free fall; so we need to return 'false' here to prevent returning 'true'. if (!this._peripheral.isConnected()) { return false; } const accelMag = this.accelMagnitude(); const spinMag = this.spinMagnitude(); // We want to account for rotation during freefall, // so we tack on a an estimated "rotational effect" // The FREEFALL_ROTATION_FACTOR const is used to both scale the // gyro measurements and convert them to radians/second. // So, we compare our accel magnitude against: // FREEFALL_THRESHOLD + (some_scaled_magnitude_of_rotation). const ffThresh = FREEFALL_THRESHOLD + FREEFALL_ROTATION_FACTOR * spinMag; return accelMag < ffThresh; } } module.exports = Scratch3GdxForBlocks; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js": /*!************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js ***! \************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const Base64Util = __webpack_require__(/*! ../../util/base64-util */ "./node_modules/scratch-vm/src/util/base64-util.js"); /** * Adapter class */ class ScratchLinkDeviceAdapter { constructor(socket, { service, commandChar, responseChar }) { this.socket = socket; this._service = service; this._commandChar = commandChar; this._responseChar = responseChar; this._onResponse = this._onResponse.bind(this); this._deviceOnResponse = null; } get godirectAdapter() { return true; } writeCommand(commandBuffer) { const data = Base64Util.uint8ArrayToBase64(commandBuffer); return this.socket.write(this._service, this._commandChar, data, 'base64'); } setup({ onResponse }) { this._deviceOnResponse = onResponse; return this.socket.startNotifications(this._service, this._responseChar, this._onResponse); // TODO: // How do we find out from scratch link if communication closes? } _onResponse(base64) { const array = Base64Util.base64ToUint8Array(base64); const response = new DataView(array.buffer); return this._deviceOnResponse(response); } } module.exports = ScratchLinkDeviceAdapter; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_makeymakey/index.js": /*!*****************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_makeymakey/index.js ***! \*****************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const formatMessage = __webpack_require__(/*! format-message */ "./node_modules/format-message/index.js"); const ArgumentType = __webpack_require__(/*! ../../extension-support/argument-type */ "./node_modules/scratch-vm/src/extension-support/argument-type.js"); const BlockType = __webpack_require__(/*! ../../extension-support/block-type */ "./node_modules/scratch-vm/src/extension-support/block-type.js"); const Cast = __webpack_require__(/*! ../../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); /** * Icon svg to be displayed at the left edge of each extension block, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len const blockIconURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHN0eWxlPi5zdDJ7ZmlsbDpyZWR9LnN0M3tmaWxsOiNlMGUwZTB9LnN0NHtmaWxsOm5vbmU7c3Ryb2tlOiM2NjY7c3Ryb2tlLXdpZHRoOi41O3N0cm9rZS1taXRlcmxpbWl0OjEwfTwvc3R5bGU+PHBhdGggZD0iTTM1IDI4SDVhMSAxIDAgMCAxLTEtMVYxMmMwLS42LjQtMSAxLTFoMzBjLjUgMCAxIC40IDEgMXYxNWMwIC41LS41IDEtMSAxeiIgZmlsbD0iI2ZmZiIgaWQ9IkxheWVyXzYiLz48ZyBpZD0iTGF5ZXJfNCI+PHBhdGggY2xhc3M9InN0MiIgZD0iTTQgMjVoMzJ2Mi43SDR6TTEzIDI0aC0yLjJhMSAxIDAgMCAxLTEtMXYtOS43YzAtLjYuNC0xIDEtMUgxM2MuNiAwIDEgLjQgMSAxVjIzYzAgLjYtLjUgMS0xIDF6Ii8+PHBhdGggY2xhc3M9InN0MiIgZD0iTTYuMSAxOS4zdi0yLjJjMC0uNS40LTEgMS0xaDkuN2MuNSAwIDEgLjUgMSAxdjIuMmMwIC41LS41IDEtMSAxSDcuMWExIDEgMCAwIDEtMS0xeiIvPjxjaXJjbGUgY2xhc3M9InN0MiIgY3g9IjIyLjgiIGN5PSIxOC4yIiByPSIzLjQiLz48Y2lyY2xlIGNsYXNzPSJzdDIiIGN4PSIzMC42IiBjeT0iMTguMiIgcj0iMy40Ii8+PHBhdGggY2xhc3M9InN0MiIgZD0iTTQuMiAyN2gzMS45di43SDQuMnoiLz48L2c+PGcgaWQ9IkxheWVyXzUiPjxjaXJjbGUgY2xhc3M9InN0MyIgY3g9IjIyLjgiIGN5PSIxOC4yIiByPSIyLjMiLz48Y2lyY2xlIGNsYXNzPSJzdDMiIGN4PSIzMC42IiBjeT0iMTguMiIgcj0iMi4zIi8+PHBhdGggY2xhc3M9InN0MyIgZD0iTTEyLjUgMjIuOWgtMS4yYy0uMyAwLS41LS4yLS41LS41VjE0YzAtLjMuMi0uNS41LS41aDEuMmMuMyAwIC41LjIuNS41djguNGMwIC4zLS4yLjUtLjUuNXoiLz48cGF0aCBjbGFzcz0ic3QzIiBkPSJNNy4yIDE4Ljd2LTEuMmMwLS4zLjItLjUuNS0uNWg4LjRjLjMgMCAuNS4yLjUuNXYxLjJjMCAuMy0uMi41LS41LjVINy43Yy0uMyAwLS41LS4yLS41LS41ek00IDI2aDMydjJINHoiLz48L2c+PGcgaWQ9IkxheWVyXzMiPjxwYXRoIGNsYXNzPSJzdDQiIGQ9Ik0zNS4yIDI3LjlINC44YTEgMSAwIDAgMS0xLTFWMTIuMWMwLS42LjUtMSAxLTFoMzAuNWMuNSAwIDEgLjQgMSAxVjI3YTEgMSAwIDAgMS0xLjEuOXoiLz48cGF0aCBjbGFzcz0ic3Q0IiBkPSJNMzUuMiAyNy45SDQuOGExIDEgMCAwIDEtMS0xVjEyLjFjMC0uNi41LTEgMS0xaDMwLjVjLjUgMCAxIC40IDEgMVYyN2ExIDEgMCAwIDEtMS4xLjl6Ii8+PC9nPjwvc3ZnPg=='; /** * Length of the buffer to store key presses for the "when keys pressed in order" hat * @type {number} */ const KEY_BUFFER_LENGTH = 100; /** * Timeout in milliseconds to reset the completed flag for a sequence. * @type {number} */ const SEQUENCE_HAT_TIMEOUT = 100; /** * An id for the space key on a keyboard. */ const KEY_ID_SPACE = 'SPACE'; /** * An id for the left arrow key on a keyboard. */ const KEY_ID_LEFT = 'LEFT'; /** * An id for the right arrow key on a keyboard. */ const KEY_ID_RIGHT = 'RIGHT'; /** * An id for the up arrow key on a keyboard. */ const KEY_ID_UP = 'UP'; /** * An id for the down arrow key on a keyboard. */ const KEY_ID_DOWN = 'DOWN'; /** * Names used by keyboard io for keys used in scratch. * @enum {string} */ const SCRATCH_KEY_NAME = { [KEY_ID_SPACE]: 'space', [KEY_ID_LEFT]: 'left arrow', [KEY_ID_UP]: 'up arrow', [KEY_ID_RIGHT]: 'right arrow', [KEY_ID_DOWN]: 'down arrow' }; /** * Class for the makey makey blocks in Scratch 3.0 * @constructor */ class Scratch3MakeyMakeyBlocks { constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; /** * A toggle that alternates true and false each frame, so that an * edge-triggered hat can trigger on every other frame. * @type {boolean} */ this.frameToggle = false; // Set an interval that toggles the frameToggle every frame. setInterval(() => { this.frameToggle = !this.frameToggle; }, this.runtime.currentStepTime); this.keyPressed = this.keyPressed.bind(this); this.runtime.on('KEY_PRESSED', this.keyPressed); this._clearkeyPressBuffer = this._clearkeyPressBuffer.bind(this); this.runtime.on('PROJECT_STOP_ALL', this._clearkeyPressBuffer); /* * An object containing a set of sequence objects. * These are the key sequences currently being detected by the "when * keys pressed in order" hat block. Each sequence is keyed by its * string representation (the sequence's value in the menu, which is a * string of KEY_IDs separated by spaces). Each sequence object * has an array property (an array of KEY_IDs) and a boolean * completed property that is true when the sequence has just been * pressed. * @type {object} */ this.sequences = {}; /* * An array of the key codes of recently pressed keys. * @type {array} */ this.keyPressBuffer = []; } /* * Localized short-form names of the space bar and arrow keys, for use in the * displayed menu items of the "when keys pressed in order" block. * @type {object} */ get KEY_TEXT_SHORT() { return { [KEY_ID_SPACE]: formatMessage({ id: 'makeymakey.spaceKey', default: 'space', description: 'The space key on a computer keyboard.' }), [KEY_ID_LEFT]: formatMessage({ id: 'makeymakey.leftArrowShort', default: 'left', description: 'Short name for the left arrow key on a computer keyboard.' }), [KEY_ID_UP]: formatMessage({ id: 'makeymakey.upArrowShort', default: 'up', description: 'Short name for the up arrow key on a computer keyboard.' }), [KEY_ID_RIGHT]: formatMessage({ id: 'makeymakey.rightArrowShort', default: 'right', description: 'Short name for the right arrow key on a computer keyboard.' }), [KEY_ID_DOWN]: formatMessage({ id: 'makeymakey.downArrowShort', default: 'down', description: 'Short name for the down arrow key on a computer keyboard.' }) }; } /* * An array of strings of KEY_IDs representing the default set of * key sequences for use by the "when keys pressed in order" block. * @type {array} */ get DEFAULT_SEQUENCES() { return ["".concat(KEY_ID_LEFT, " ").concat(KEY_ID_UP, " ").concat(KEY_ID_RIGHT), "".concat(KEY_ID_RIGHT, " ").concat(KEY_ID_UP, " ").concat(KEY_ID_LEFT), "".concat(KEY_ID_LEFT, " ").concat(KEY_ID_RIGHT), "".concat(KEY_ID_RIGHT, " ").concat(KEY_ID_LEFT), "".concat(KEY_ID_UP, " ").concat(KEY_ID_DOWN), "".concat(KEY_ID_DOWN, " ").concat(KEY_ID_UP), "".concat(KEY_ID_UP, " ").concat(KEY_ID_RIGHT, " ").concat(KEY_ID_DOWN, " ").concat(KEY_ID_LEFT), "".concat(KEY_ID_UP, " ").concat(KEY_ID_LEFT, " ").concat(KEY_ID_DOWN, " ").concat(KEY_ID_RIGHT), "".concat(KEY_ID_UP, " ").concat(KEY_ID_UP, " ").concat(KEY_ID_DOWN, " ").concat(KEY_ID_DOWN, " ") + "".concat(KEY_ID_LEFT, " ").concat(KEY_ID_RIGHT, " ").concat(KEY_ID_LEFT, " ").concat(KEY_ID_RIGHT)]; } /** * @returns {object} metadata for this extension and its blocks. */ getInfo() { return { id: 'makeymakey', name: 'Makey Makey', blockIconURI: blockIconURI, blocks: [{ opcode: 'whenMakeyKeyPressed', text: formatMessage({ id: 'makeymakey.whenKeyPressed', default: 'when [KEY] key pressed', description: 'when a keyboard key is pressed' }), blockType: BlockType.HAT, arguments: { KEY: { type: ArgumentType.STRING, menu: 'KEY', defaultValue: KEY_ID_SPACE } } }, { opcode: 'whenCodePressed', text: formatMessage({ id: 'makeymakey.whenKeysPressedInOrder', default: 'when [SEQUENCE] pressed in order', description: 'when a sequence of keyboard keys is pressed in a specific order' }), blockType: BlockType.HAT, arguments: { SEQUENCE: { type: ArgumentType.STRING, menu: 'SEQUENCE', defaultValue: this.DEFAULT_SEQUENCES[0] } } }], menus: { KEY: { acceptReporters: true, items: [{ text: formatMessage({ id: 'makeymakey.spaceKey', default: 'space', description: 'The space key on a computer keyboard.' }), value: KEY_ID_SPACE }, { text: formatMessage({ id: 'makeymakey.upArrow', default: 'up arrow', description: 'The up arrow key on a computer keyboard.' }), value: KEY_ID_UP }, { text: formatMessage({ id: 'makeymakey.downArrow', default: 'down arrow', description: 'The down arrow key on a computer keyboard.' }), value: KEY_ID_DOWN }, { text: formatMessage({ id: 'makeymakey.rightArrow', default: 'right arrow', description: 'The right arrow key on a computer keyboard.' }), value: KEY_ID_RIGHT }, { text: formatMessage({ id: 'makeymakey.leftArrow', default: 'left arrow', description: 'The left arrow key on a computer keyboard.' }), value: KEY_ID_LEFT }, { text: 'w', value: 'w' }, { text: 'a', value: 'a' }, { text: 's', value: 's' }, { text: 'd', value: 'd' }, { text: 'f', value: 'f' }, { text: 'g', value: 'g' }] }, SEQUENCE: { acceptReporters: true, items: this.buildSequenceMenu(this.DEFAULT_SEQUENCES) } } }; } /* * Build the menu of key sequences. * @param {array} sequencesArray an array of strings of KEY_IDs. * @returns {array} an array of objects with text and value properties. */ buildSequenceMenu(sequencesArray) { return sequencesArray.map(str => this.getMenuItemForSequenceString(str)); } /* * Create a menu item for a sequence string. * @param {string} sequenceString a string of KEY_IDs. * @return {object} an object with text and value properties. */ getMenuItemForSequenceString(sequenceString) { let sequenceArray = sequenceString.split(' '); sequenceArray = sequenceArray.map(str => this.KEY_TEXT_SHORT[str]); return { text: sequenceArray.join(' '), value: sequenceString }; } /* * Check whether a keyboard key is currently pressed. * Also, toggle the results of the test on alternate frames, so that the * hat block fires repeatedly. * @param {object} args - the block arguments. * @property {number} KEY - a key code. * @param {object} util - utility object provided by the runtime. */ whenMakeyKeyPressed(args, util) { let key = args.KEY; // Convert the key arg, if it is a KEY_ID, to the key name used by // the Keyboard io module. if (SCRATCH_KEY_NAME[args.KEY]) { key = SCRATCH_KEY_NAME[args.KEY]; } const isDown = util.ioQuery('keyboard', 'getKeyIsDown', [key]); return isDown && this.frameToggle; } /* * A function called on the KEY_PRESSED event, to update the key press * buffer and check if any of the key sequences have been completed. * @param {string} key A scratch key name. */ keyPressed(key) { // Store only the first word of the Scratch key name, so that e.g. when // "left arrow" is pressed, we store "LEFT", which matches KEY_ID_LEFT key = key.split(' ')[0]; key = key.toUpperCase(); this.keyPressBuffer.push(key); // Keep the buffer under the length limit if (this.keyPressBuffer.length > KEY_BUFFER_LENGTH) { this.keyPressBuffer.shift(); } // Check the buffer for each sequence in use for (const str in this.sequences) { const arr = this.sequences[str].array; // Bail out if we don't have enough presses for this sequence if (this.keyPressBuffer.length < arr.length) { continue; } let missFlag = false; // Slice the buffer to the length of the sequence we're checking const bufferSegment = this.keyPressBuffer.slice(-1 * arr.length); for (let i = 0; i < arr.length; i++) { if (arr[i] !== bufferSegment[i]) { missFlag = true; } } // If the miss flag is false, the sequence matched the buffer if (!missFlag) { this.sequences[str].completed = true; // Clear the completed flag after a timeout. This is necessary because // the hat is edge-triggered (not event triggered). Multiple hats // may be checking the same sequence, so this timeout gives them enough // time to all trigger before resetting the flag. setTimeout(() => { this.sequences[str].completed = false; }, SEQUENCE_HAT_TIMEOUT); } } } /** * Clear the key press buffer. */ _clearkeyPressBuffer() { this.keyPressBuffer = []; } /* * Add a key sequence to the set currently being checked on each key press. * @param {string} sequenceString a string of space-separated KEY_IDs. * @param {array} sequenceArray an array of KEY_IDs. */ addSequence(sequenceString, sequenceArray) { // If we already have this sequence string, return. if (this.sequences.hasOwnProperty(sequenceString)) { return; } this.sequences[sequenceString] = { array: sequenceArray, completed: false }; } /* * Check whether a key sequence was recently completed. * @param {object} args The block arguments. * @property {number} SEQUENCE A string of KEY_IDs. */ whenCodePressed(args) { const sequenceString = Cast.toString(args.SEQUENCE).toUpperCase(); const sequenceArray = sequenceString.split(' '); if (sequenceArray.length < 2) { return; } this.addSequence(sequenceString, sequenceArray); return this.sequences[sequenceString].completed; } } module.exports = Scratch3MakeyMakeyBlocks; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_microbit/index.js": /*!***************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_microbit/index.js ***! \***************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const ArgumentType = __webpack_require__(/*! ../../extension-support/argument-type */ "./node_modules/scratch-vm/src/extension-support/argument-type.js"); const BlockType = __webpack_require__(/*! ../../extension-support/block-type */ "./node_modules/scratch-vm/src/extension-support/block-type.js"); const log = __webpack_require__(/*! ../../util/log */ "./node_modules/scratch-vm/src/util/log.js"); const cast = __webpack_require__(/*! ../../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); const formatMessage = __webpack_require__(/*! format-message */ "./node_modules/format-message/index.js"); const BLE = __webpack_require__(/*! ../../io/ble */ "./node_modules/scratch-vm/src/io/ble.js"); const Base64Util = __webpack_require__(/*! ../../util/base64-util */ "./node_modules/scratch-vm/src/util/base64-util.js"); /** * Icon png to be displayed at the left edge of each extension block, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len const blockIconURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAACXBIWXMAABYlAAAWJQFJUiTwAAAKcElEQVR42u2cfXAU9RnHv7u3L3d7l9yR5PIGXO7MkQKaYiCUWqJhFGvRMk4JZXSc8aXVaSmiYlthVHQEW99FxiIdrVY6teiMdoa+ICqhIqgQAsjwMgYDOQKXl7uY17u9293b3f5x5JKYe8+FJGSfvzbP/n77e/azz+95nt9v90KoqgpN0hdSQ6AB1ABqADWAmmgANYAaQA2gJhpADeBEE2q8GPLaWzu/CslyiY4k9dOn5uijtXGd7+jWkaReVpT3Hrhv6d0awEFC07rgD+ZeYYnXprhwigUAvjj0zbjxQCLebozT7iDzK1ZUWCru2K7L//6MVC8ue45Blz8n6rlQ815QtuohOlXiEdy/AUqPa6y59Mkh6Q1345GNja6m7pHEQKNl3t0704EXat4L6fSOmOeEI1vHKzwAyNJR9MPFpRUPOu0ONm2A0xatWaTLm5WfDrzvAppA8AbiG03fC8CQNkDKZK2YrPAuRrhpifJERsuYywveJc7CqcIDMAyeLm82dEXzw39I/qjXkpr3QuW9lxfAdOABGAKPslWDnbsy7Jl8BxTeM3SqmO0gaA5U6c3jymup0YSn9JyLee67wpTfBQAQjmyF3HFqiJcRtDECjy5dAmbmcgQPvjjxl3Lx4IVjnD/5cE1zkWtyP34VBGcdKLJnLgc9cznk1kMXFdzEn8KJ4KUqqsSHvcxWDf7j1UM8UPr6/YgHhhX8xAaYaXgAIB7fBnbuSrBzV8aNgarEQ/z6/YkLcDTg9V9XlXjQtuqoU1TpcUHlvZDOfDiuyh5qPMCLrJ1bDw3EuUtx81N/BH3pjQBJQ2HMF5V6iKfeRchVm9kkMtrwxmSdobeA9daBde8GwVlBcFYofS1Jw0vaAy9HeJHQwBUPzIBvGxDc92Rmp/BowJs10wkAONfsBs8HAAAltqngOAO8HZ3o6OiMqcvLy4E1Lwc8H8C5ZndMXdLJa/qNacNLCDBw/O8nFUNWxp/64+tWAwBefe1tHKg7CgC4/9d3ori4EHv3HcDrb26PqVt2602ovvaHaGlpw+8ffSamLqXYmya8jG8mpFy6iGLkWLh4HAwG4+r6j4VBfaPpLgU8IMGO9MLqW2pYQ9aQokuR5dgXIwCC1CUcNMj3hpdvLAdSF54EYpCHooRA0Swomo2pC0kCQpIAkqTA6LmYupgxL0X7m78+aG10NXVkpIwxsAwWXncDCESHLkohfPbpbiT6ZFPPZQ9fC0e58Wi6wTDj6UbT/rQAyiERS2pW4Kc3LQDLRO8miCEAKj7d83FcTxyLJJJJ+9MCqKoq9HomMrgkSThxsgEcZ8AMpwMkSYJlKDA0DVUFiHGWRDJp/4jXwqIo4uFHnkZXdw8AYGbZFXhs3WqQJDkhkkim7E8KoMlkxKbnn8DBunrwUli3e8/+yOAA0HjmHDq7upGXm5PUoDUr7hmWRB5Zt3FYwoime+vtd/H6G9uGJIxouniSyP6H7v8FystnY80jGzIA0MihsMAKu20aTp3JzFb6WCWRuDUvHwByw8cOhw2FBVaYjNzIAba1e3Hfb9aiq7MTNStuBwAsvr4KO3d9GnmKztIS5EyxTJiVSDT7p04tipx/9MnnYc7ORlu7NzMxsK3di5AkDHgGw2DTC+uHBeGJshJJZL/fxyMQEDKbRAiCQDAoQhBDYBkKNE2j4uqrhpUBoiSBIMZfEhkN+1NeiWSqEB2rlUg69md0JRIQRHy86z8jXsqNVRLJlP0jqgNJXXgAgjbCcONmCHUvQ+44NWG2s/rtH5Mt/ciToo0wLH4JBGO6LLazRiJk2vBYy4gHHw/bWSN+LZBKEhkMjzn/CaSiKgQOvJDyFB7L7axUJWNJZDA8IhQA1boPin7KZbMSGfUYyFx9b3hXg/cCsoBA2Z0AoYOaxlcC4+mdyCUDKBzanLFBJ3USyaRMuiSSKZmUSSSTMimTCABUlblRU9kAZ0E39p+eii21c+EL0jHbOwu6sfaWgyjND//U4oP6MmzZnfi79XT7mfQSNi7bh0JzOLG19XBY/89r49pYVebGqhuOosDsh1+gsWV3BXYdd2Q+BlaVuXFv9bHgkSbzk+vfcVRyjHhi47J9cftsXLYf7T36Ix8cLHlo6ydlv6qpPI2qssRZcuOy/Wjp4k5s+2zG+offKqtcUt6kJtNv7S0H0RtkvEufXTB/6bML5je2Wy7UVDbEbF9o9mPDsv2oP5v75vbPS26rP5u3fdXiozDppcwDrKlswOlWy9E//DX09Mt/azh8zzNM1RybF86C7pheVGD240CDeX3NWtfml94Rt+0+Mf3Lm8qbEnpfgdmPs+3G9+564vTT//pM/GrHYduWRP0AYOEMN/5S61xT92Vtfd2XtfWb/vu91fHALyxzw9tnkB/cTD5w+2Ou9375HHtfa7exM5mxRpKFaafdQQKgAcDERs98/foLHrXdaXfoABi8vczhWO2/28/TRR5z2h00gKymNl1ton79oigq6bQ7dE67Q+ew9mb1h4FYYwVESgLAXLSRa+3mWpIdK+UYuPiq89f8+XfT/+ftZQ4vLm9ZmUyfdcsv1M2fWfRaUCK8i8vdK1u6ktuAWPWTsztm24o/cnnYHUsrWzd1+fVJ9XtqxbG3XzFdNcPTawjcueibpxK1t+X26f/9R8a953jub4typOvm2b1XnvUmv8JKWMZcaZffX3XDERRP8cGaFRjWxtPLoZvXY4oxgPBNEsgxBhCUKEzL6Ru+JydS8Ak0giKFgESDJFQoKmCgQzAwIfQEWETzmoBIwd2VNaStu8uEHGO4Buz06zHHFv0dRkefAZ1+PQx0KNK2eIoPLCUj2zDc275qzgcBFWv+cf3IyxgTK2KOzQufEM5kfpGF12eGPSf8DXN+No/87HDWiwYYALw+M6ym8AscAxO++X7xCTRM7EDQzht0Da8v/NWo1dQDAxNCocUXs+303IGHdaptOmYXnh/SLlZbV+fwnwJm6UXEm/ojqgM/PFmJQ81OPHfrtqT7bN23BE8seTflYLvz5DwYGQHLKz5Puo/XZ8aLtT+D1dSDuxbsGQIymmz48DbwIguOESJOcce8XaO3oVpZ8k3Em5KVVAAMFnuOB9as1MbimCBunn04vBmR40ls29Wfgxf1KMn1gBdY+MXUCvK4ANvPndpLzrLzALjBN2VPwrDBksgLYkn1jBMp90nVY2++8vAw3RlPeLNYVZSPAEgjKWP6ZCn4lF+gMdnE08spQb73RQB9aXtgo6tJcNodf8rWz3L//Br340UW3sExEkXrFFKSSUVHqkRfkJZ8QSZk5gS6hw9H+GyDQAclSs41BVmSUIn+toAKIUTJskKoQUknCxKlkISKb/sM0NMyyVAhXW+AlYosfgOgQlUJVadTSUWBKoQoudvPioPbenq5oIUTaRUqenhWKi3oyVIUqKpKREoLggDhF6hQb4CV9LRM9rctMPN6glChp2SdTqeSskwoAECSKnG61fzFR/XsGu+FhmONriYl7TImsjoYKJyZSeB8CoBQo6spqU8TCO1fgE7gDVUNoCYaQA2gBlADqAHURAOoAdQAagA10QCOgfwfNp/hXbfBMCAAAAAASUVORK5CYII='; /** * Enum for micro:bit BLE command protocol. * https://github.com/LLK/scratch-microbit-firmware/blob/master/protocol.md * @readonly * @enum {number} */ const BLECommand = { CMD_PIN_CONFIG: 0x80, CMD_DISPLAY_TEXT: 0x81, CMD_DISPLAY_LED: 0x82 }; /** * A time interval to wait (in milliseconds) before reporting to the BLE socket * that data has stopped coming from the peripheral. */ const BLETimeout = 4500; /** * A time interval to wait (in milliseconds) while a block that sends a BLE message is running. * @type {number} */ const BLESendInterval = 100; /** * A string to report to the BLE socket when the micro:bit has stopped receiving data. * @type {string} */ const BLEDataStoppedError = 'micro:bit extension stopped receiving data'; /** * Enum for micro:bit protocol. * https://github.com/LLK/scratch-microbit-firmware/blob/master/protocol.md * @readonly * @enum {string} */ const BLEUUID = { service: 0xf005, rxChar: '5261da01-fa7e-42ab-850b-7c80220097cc', txChar: '5261da02-fa7e-42ab-850b-7c80220097cc' }; /** * Manage communication with a MicroBit peripheral over a Scrath Link client socket. */ class MicroBit { /** * Construct a MicroBit communication object. * @param {Runtime} runtime - the Scratch 3.0 runtime * @param {string} extensionId - the id of the extension */ constructor(runtime, extensionId) { /** * The Scratch 3.0 runtime used to trigger the green flag button. * @type {Runtime} * @private */ this._runtime = runtime; /** * The BluetoothLowEnergy connection socket for reading/writing peripheral data. * @type {BLE} * @private */ this._ble = null; this._runtime.registerPeripheralExtension(extensionId, this); /** * The id of the extension this peripheral belongs to. */ this._extensionId = extensionId; /** * The most recently received value for each sensor. * @type {Object.} * @private */ this._sensors = { tiltX: 0, tiltY: 0, buttonA: 0, buttonB: 0, touchPins: [0, 0, 0], gestureState: 0, ledMatrixState: new Uint8Array(5) }; /** * The most recently received value for each gesture. * @type {Object.} * @private */ this._gestures = { moving: false, move: { active: false, timeout: false }, shake: { active: false, timeout: false }, jump: { active: false, timeout: false } }; /** * Interval ID for data reading timeout. * @type {number} * @private */ this._timeoutID = null; /** * A flag that is true while we are busy sending data to the BLE socket. * @type {boolean} * @private */ this._busy = false; /** * ID for a timeout which is used to clear the busy flag if it has been * true for a long time. */ this._busyTimeoutID = null; this.reset = this.reset.bind(this); this._onConnect = this._onConnect.bind(this); this._onMessage = this._onMessage.bind(this); } /** * @param {string} text - the text to display. * @return {Promise} - a Promise that resolves when writing to peripheral. */ displayText(text) { const output = new Uint8Array(text.length); for (let i = 0; i < text.length; i++) { output[i] = text.charCodeAt(i); } return this.send(BLECommand.CMD_DISPLAY_TEXT, output); } /** * @param {Uint8Array} matrix - the matrix to display. * @return {Promise} - a Promise that resolves when writing to peripheral. */ displayMatrix(matrix) { return this.send(BLECommand.CMD_DISPLAY_LED, matrix); } /** * @return {number} - the latest value received for the tilt sensor's tilt about the X axis. */ get tiltX() { return this._sensors.tiltX; } /** * @return {number} - the latest value received for the tilt sensor's tilt about the Y axis. */ get tiltY() { return this._sensors.tiltY; } /** * @return {boolean} - the latest value received for the A button. */ get buttonA() { return this._sensors.buttonA; } /** * @return {boolean} - the latest value received for the B button. */ get buttonB() { return this._sensors.buttonB; } /** * @return {number} - the latest value received for the motion gesture states. */ get gestureState() { return this._sensors.gestureState; } /** * @return {Uint8Array} - the current state of the 5x5 LED matrix. */ get ledMatrixState() { return this._sensors.ledMatrixState; } /** * Called by the runtime when user wants to scan for a peripheral. */ scan() { if (this._ble) { this._ble.disconnect(); } this._ble = new BLE(this._runtime, this._extensionId, { filters: [{ services: [BLEUUID.service] }] }, this._onConnect, this.reset); } /** * Called by the runtime when user wants to connect to a certain peripheral. * @param {number} id - the id of the peripheral to connect to. */ connect(id) { if (this._ble) { this._ble.connectPeripheral(id); } } /** * Disconnect from the micro:bit. */ disconnect() { if (this._ble) { this._ble.disconnect(); } this.reset(); } /** * Reset all the state and timeout/interval ids. */ reset() { if (this._timeoutID) { window.clearTimeout(this._timeoutID); this._timeoutID = null; } } /** * Return true if connected to the micro:bit. * @return {boolean} - whether the micro:bit is connected. */ isConnected() { let connected = false; if (this._ble) { connected = this._ble.isConnected(); } return connected; } /** * Send a message to the peripheral BLE socket. * @param {number} command - the BLE command hex. * @param {Uint8Array} message - the message to write */ send(command, message) { if (!this.isConnected()) return; if (this._busy) return; // Set a busy flag so that while we are sending a message and waiting for // the response, additional messages are ignored. this._busy = true; // Set a timeout after which to reset the busy flag. This is used in case // a BLE message was sent for which we never received a response, because // e.g. the peripheral was turned off after the message was sent. We reset // the busy flag after a while so that it is possible to try again later. this._busyTimeoutID = window.setTimeout(() => { this._busy = false; }, 5000); const output = new Uint8Array(message.length + 1); output[0] = command; // attach command to beginning of message for (let i = 0; i < message.length; i++) { output[i + 1] = message[i]; } const data = Base64Util.uint8ArrayToBase64(output); this._ble.write(BLEUUID.service, BLEUUID.txChar, data, 'base64', true).then(() => { this._busy = false; window.clearTimeout(this._busyTimeoutID); }); } /** * Starts reading data from peripheral after BLE has connected to it. * @private */ _onConnect() { this._ble.read(BLEUUID.service, BLEUUID.rxChar, true, this._onMessage); this._timeoutID = window.setTimeout(() => this._ble.handleDisconnectError(BLEDataStoppedError), BLETimeout); } /** * Process the sensor data from the incoming BLE characteristic. * @param {object} base64 - the incoming BLE data. * @private */ _onMessage(base64) { // parse data const data = Base64Util.base64ToUint8Array(base64); this._sensors.tiltX = data[1] | data[0] << 8; if (this._sensors.tiltX > 1 << 15) this._sensors.tiltX -= 1 << 16; this._sensors.tiltY = data[3] | data[2] << 8; if (this._sensors.tiltY > 1 << 15) this._sensors.tiltY -= 1 << 16; this._sensors.buttonA = data[4]; this._sensors.buttonB = data[5]; this._sensors.touchPins[0] = data[6]; this._sensors.touchPins[1] = data[7]; this._sensors.touchPins[2] = data[8]; this._sensors.gestureState = data[9]; // cancel disconnect timeout and start a new one window.clearTimeout(this._timeoutID); this._timeoutID = window.setTimeout(() => this._ble.handleDisconnectError(BLEDataStoppedError), BLETimeout); } /** * @param {number} pin - the pin to check touch state. * @return {number} - the latest value received for the touch pin states. * @private */ _checkPinState(pin) { return this._sensors.touchPins[pin]; } } /** * Enum for tilt sensor direction. * @readonly * @enum {string} */ const MicroBitTiltDirection = { FRONT: 'front', BACK: 'back', LEFT: 'left', RIGHT: 'right', ANY: 'any' }; /** * Enum for micro:bit gestures. * @readonly * @enum {string} */ const MicroBitGestures = { MOVED: 'moved', SHAKEN: 'shaken', JUMPED: 'jumped' }; /** * Enum for micro:bit buttons. * @readonly * @enum {string} */ const MicroBitButtons = { A: 'A', B: 'B', ANY: 'any' }; /** * Enum for micro:bit pin states. * @readonly * @enum {string} */ const MicroBitPinState = { ON: 'on', OFF: 'off' }; /** * Scratch 3.0 blocks to interact with a MicroBit peripheral. */ class Scratch3MicroBitBlocks { /** * @return {string} - the name of this extension. */ static get EXTENSION_NAME() { return 'micro:bit'; } /** * @return {string} - the ID of this extension. */ static get EXTENSION_ID() { return 'microbit'; } /** * @return {number} - the tilt sensor counts as "tilted" if its tilt angle meets or exceeds this threshold. */ static get TILT_THRESHOLD() { return 15; } /** * @return {array} - text and values for each buttons menu element */ get BUTTONS_MENU() { return [{ text: 'A', value: MicroBitButtons.A }, { text: 'B', value: MicroBitButtons.B }, { text: formatMessage({ id: 'microbit.buttonsMenu.any', default: 'any', description: 'label for "any" element in button picker for micro:bit extension' }), value: MicroBitButtons.ANY }]; } /** * @return {array} - text and values for each gestures menu element */ get GESTURES_MENU() { return [{ text: formatMessage({ id: 'microbit.gesturesMenu.moved', default: 'moved', description: 'label for moved gesture in gesture picker for micro:bit extension' }), value: MicroBitGestures.MOVED }, { text: formatMessage({ id: 'microbit.gesturesMenu.shaken', default: 'shaken', description: 'label for shaken gesture in gesture picker for micro:bit extension' }), value: MicroBitGestures.SHAKEN }, { text: formatMessage({ id: 'microbit.gesturesMenu.jumped', default: 'jumped', description: 'label for jumped gesture in gesture picker for micro:bit extension' }), value: MicroBitGestures.JUMPED }]; } /** * @return {array} - text and values for each pin state menu element */ get PIN_STATE_MENU() { return [{ text: formatMessage({ id: 'microbit.pinStateMenu.on', default: 'on', description: 'label for on element in pin state picker for micro:bit extension' }), value: MicroBitPinState.ON }, { text: formatMessage({ id: 'microbit.pinStateMenu.off', default: 'off', description: 'label for off element in pin state picker for micro:bit extension' }), value: MicroBitPinState.OFF }]; } /** * @return {array} - text and values for each tilt direction menu element */ get TILT_DIRECTION_MENU() { return [{ text: formatMessage({ id: 'microbit.tiltDirectionMenu.front', default: 'front', description: 'label for front element in tilt direction picker for micro:bit extension' }), value: MicroBitTiltDirection.FRONT }, { text: formatMessage({ id: 'microbit.tiltDirectionMenu.back', default: 'back', description: 'label for back element in tilt direction picker for micro:bit extension' }), value: MicroBitTiltDirection.BACK }, { text: formatMessage({ id: 'microbit.tiltDirectionMenu.left', default: 'left', description: 'label for left element in tilt direction picker for micro:bit extension' }), value: MicroBitTiltDirection.LEFT }, { text: formatMessage({ id: 'microbit.tiltDirectionMenu.right', default: 'right', description: 'label for right element in tilt direction picker for micro:bit extension' }), value: MicroBitTiltDirection.RIGHT }]; } /** * @return {array} - text and values for each tilt direction (plus "any") menu element */ get TILT_DIRECTION_ANY_MENU() { return [...this.TILT_DIRECTION_MENU, { text: formatMessage({ id: 'microbit.tiltDirectionMenu.any', default: 'any', description: 'label for any direction element in tilt direction picker for micro:bit extension' }), value: MicroBitTiltDirection.ANY }]; } /** * Construct a set of MicroBit blocks. * @param {Runtime} runtime - the Scratch 3.0 runtime. */ constructor(runtime) { /** * The Scratch 3.0 runtime. * @type {Runtime} */ this.runtime = runtime; // Create a new MicroBit peripheral instance this._peripheral = new MicroBit(this.runtime, Scratch3MicroBitBlocks.EXTENSION_ID); } /** * @returns {object} metadata for this extension and its blocks. */ getInfo() { return { id: Scratch3MicroBitBlocks.EXTENSION_ID, name: Scratch3MicroBitBlocks.EXTENSION_NAME, blockIconURI: blockIconURI, showStatusButton: true, blocks: [{ opcode: 'whenButtonPressed', text: formatMessage({ id: 'microbit.whenButtonPressed', default: 'when [BTN] button pressed', description: 'when the selected button on the micro:bit is pressed' }), blockType: BlockType.HAT, arguments: { BTN: { type: ArgumentType.STRING, menu: 'buttons', defaultValue: MicroBitButtons.A } } }, { opcode: 'isButtonPressed', text: formatMessage({ id: 'microbit.isButtonPressed', default: '[BTN] button pressed?', description: 'is the selected button on the micro:bit pressed?' }), blockType: BlockType.BOOLEAN, arguments: { BTN: { type: ArgumentType.STRING, menu: 'buttons', defaultValue: MicroBitButtons.A } } }, '---', { opcode: 'whenGesture', text: formatMessage({ id: 'microbit.whenGesture', default: 'when [GESTURE]', description: 'when the selected gesture is detected by the micro:bit' }), blockType: BlockType.HAT, arguments: { GESTURE: { type: ArgumentType.STRING, menu: 'gestures', defaultValue: MicroBitGestures.MOVED } } }, '---', { opcode: 'displaySymbol', text: formatMessage({ id: 'microbit.displaySymbol', default: 'display [MATRIX]', description: 'display a pattern on the micro:bit display' }), blockType: BlockType.COMMAND, arguments: { MATRIX: { type: ArgumentType.MATRIX, defaultValue: '0101010101100010101000100' } } }, { opcode: 'displayText', text: formatMessage({ id: 'microbit.displayText', default: 'display text [TEXT]', description: 'display text on the micro:bit display' }), blockType: BlockType.COMMAND, arguments: { TEXT: { type: ArgumentType.STRING, defaultValue: formatMessage({ id: 'microbit.defaultTextToDisplay', default: 'Hello!', description: "default text to display.\n IMPORTANT - the micro:bit only supports letters a-z, A-Z.\n Please substitute a default word in your language\n that can be written with those characters,\n substitute non-accented characters or leave it as \"Hello!\".\n Check the micro:bit site documentation for details" }) } } }, { opcode: 'displayClear', text: formatMessage({ id: 'microbit.clearDisplay', default: 'clear display', description: 'display nothing on the micro:bit display' }), blockType: BlockType.COMMAND }, '---', { opcode: 'whenTilted', text: formatMessage({ id: 'microbit.whenTilted', default: 'when tilted [DIRECTION]', description: 'when the micro:bit is tilted in a direction' }), blockType: BlockType.HAT, arguments: { DIRECTION: { type: ArgumentType.STRING, menu: 'tiltDirectionAny', defaultValue: MicroBitTiltDirection.ANY } } }, { opcode: 'isTilted', text: formatMessage({ id: 'microbit.isTilted', default: 'tilted [DIRECTION]?', description: 'is the micro:bit is tilted in a direction?' }), blockType: BlockType.BOOLEAN, arguments: { DIRECTION: { type: ArgumentType.STRING, menu: 'tiltDirectionAny', defaultValue: MicroBitTiltDirection.ANY } } }, { opcode: 'getTiltAngle', text: formatMessage({ id: 'microbit.tiltAngle', default: 'tilt angle [DIRECTION]', description: 'how much the micro:bit is tilted in a direction' }), blockType: BlockType.REPORTER, arguments: { DIRECTION: { type: ArgumentType.STRING, menu: 'tiltDirection', defaultValue: MicroBitTiltDirection.FRONT } } }, '---', { opcode: 'whenPinConnected', text: formatMessage({ id: 'microbit.whenPinConnected', default: 'when pin [PIN] connected', description: 'when the pin detects a connection to Earth/Ground' }), blockType: BlockType.HAT, arguments: { PIN: { type: ArgumentType.STRING, menu: 'touchPins', defaultValue: '0' } } }], menus: { buttons: { acceptReporters: true, items: this.BUTTONS_MENU }, gestures: { acceptReporters: true, items: this.GESTURES_MENU }, pinState: { acceptReporters: true, items: this.PIN_STATE_MENU }, tiltDirection: { acceptReporters: true, items: this.TILT_DIRECTION_MENU }, tiltDirectionAny: { acceptReporters: true, items: this.TILT_DIRECTION_ANY_MENU }, touchPins: { acceptReporters: true, items: ['0', '1', '2'] } } }; } /** * Test whether the A or B button is pressed * @param {object} args - the block's arguments. * @return {boolean} - true if the button is pressed. */ whenButtonPressed(args) { if (args.BTN === 'any') { return this._peripheral.buttonA | this._peripheral.buttonB; } else if (args.BTN === 'A') { return this._peripheral.buttonA; } else if (args.BTN === 'B') { return this._peripheral.buttonB; } return false; } /** * Test whether the A or B button is pressed * @param {object} args - the block's arguments. * @return {boolean} - true if the button is pressed. */ isButtonPressed(args) { if (args.BTN === 'any') { return (this._peripheral.buttonA | this._peripheral.buttonB) !== 0; } else if (args.BTN === 'A') { return this._peripheral.buttonA !== 0; } else if (args.BTN === 'B') { return this._peripheral.buttonB !== 0; } return false; } /** * Test whether the micro:bit is moving * @param {object} args - the block's arguments. * @return {boolean} - true if the micro:bit is moving. */ whenGesture(args) { const gesture = cast.toString(args.GESTURE); if (gesture === 'moved') { return this._peripheral.gestureState >> 2 & 1; } else if (gesture === 'shaken') { return this._peripheral.gestureState & 1; } else if (gesture === 'jumped') { return this._peripheral.gestureState >> 1 & 1; } return false; } /** * Display a predefined symbol on the 5x5 LED matrix. * @param {object} args - the block's arguments. * @return {Promise} - a Promise that resolves after a tick. */ displaySymbol(args) { const symbol = cast.toString(args.MATRIX).replace(/\s/g, ''); const reducer = (accumulator, c, index) => { const value = c === '0' ? accumulator : accumulator + Math.pow(2, index); return value; }; const hex = symbol.split('').reduce(reducer, 0); if (hex !== null) { this._peripheral.ledMatrixState[0] = hex & 0x1F; this._peripheral.ledMatrixState[1] = hex >> 5 & 0x1F; this._peripheral.ledMatrixState[2] = hex >> 10 & 0x1F; this._peripheral.ledMatrixState[3] = hex >> 15 & 0x1F; this._peripheral.ledMatrixState[4] = hex >> 20 & 0x1F; this._peripheral.displayMatrix(this._peripheral.ledMatrixState); } return new Promise(resolve => { setTimeout(() => { resolve(); }, BLESendInterval); }); } /** * Display text on the 5x5 LED matrix. * @param {object} args - the block's arguments. * @return {Promise} - a Promise that resolves after the text is done printing. * Note the limit is 19 characters * The print time is calculated by multiplying the number of horizontal pixels * by the default scroll delay of 120ms. * The number of horizontal pixels = 6px for each character in the string, * 1px before the string, and 5px after the string. */ displayText(args) { const text = String(args.TEXT).substring(0, 19); if (text.length > 0) this._peripheral.displayText(text); const yieldDelay = 120 * (6 * text.length + 6); return new Promise(resolve => { setTimeout(() => { resolve(); }, yieldDelay); }); } /** * Turn all 5x5 matrix LEDs off. * @return {Promise} - a Promise that resolves after a tick. */ displayClear() { for (let i = 0; i < 5; i++) { this._peripheral.ledMatrixState[i] = 0; } this._peripheral.displayMatrix(this._peripheral.ledMatrixState); return new Promise(resolve => { setTimeout(() => { resolve(); }, BLESendInterval); }); } /** * Test whether the tilt sensor is currently tilted. * @param {object} args - the block's arguments. * @property {TiltDirection} DIRECTION - the tilt direction to test (front, back, left, right, or any). * @return {boolean} - true if the tilt sensor is tilted past a threshold in the specified direction. */ whenTilted(args) { return this._isTilted(args.DIRECTION); } /** * Test whether the tilt sensor is currently tilted. * @param {object} args - the block's arguments. * @property {TiltDirection} DIRECTION - the tilt direction to test (front, back, left, right, or any). * @return {boolean} - true if the tilt sensor is tilted past a threshold in the specified direction. */ isTilted(args) { return this._isTilted(args.DIRECTION); } /** * @param {object} args - the block's arguments. * @property {TiltDirection} DIRECTION - the direction (front, back, left, right) to check. * @return {number} - the tilt sensor's angle in the specified direction. * Note that getTiltAngle(front) = -getTiltAngle(back) and getTiltAngle(left) = -getTiltAngle(right). */ getTiltAngle(args) { return this._getTiltAngle(args.DIRECTION); } /** * Test whether the tilt sensor is currently tilted. * @param {TiltDirection} direction - the tilt direction to test (front, back, left, right, or any). * @return {boolean} - true if the tilt sensor is tilted past a threshold in the specified direction. * @private */ _isTilted(direction) { switch (direction) { case MicroBitTiltDirection.ANY: return Math.abs(this._peripheral.tiltX / 10) >= Scratch3MicroBitBlocks.TILT_THRESHOLD || Math.abs(this._peripheral.tiltY / 10) >= Scratch3MicroBitBlocks.TILT_THRESHOLD; default: return this._getTiltAngle(direction) >= Scratch3MicroBitBlocks.TILT_THRESHOLD; } } /** * @param {TiltDirection} direction - the direction (front, back, left, right) to check. * @return {number} - the tilt sensor's angle in the specified direction. * Note that getTiltAngle(front) = -getTiltAngle(back) and getTiltAngle(left) = -getTiltAngle(right). * @private */ _getTiltAngle(direction) { switch (direction) { case MicroBitTiltDirection.FRONT: return Math.round(this._peripheral.tiltY / -10); case MicroBitTiltDirection.BACK: return Math.round(this._peripheral.tiltY / 10); case MicroBitTiltDirection.LEFT: return Math.round(this._peripheral.tiltX / -10); case MicroBitTiltDirection.RIGHT: return Math.round(this._peripheral.tiltX / 10); default: log.warn("Unknown tilt direction in _getTiltAngle: ".concat(direction)); } } /** * @param {object} args - the block's arguments. * @return {boolean} - the touch pin state. * @private */ whenPinConnected(args) { const pin = parseInt(args.PIN, 10); if (isNaN(pin)) return; if (pin < 0 || pin > 2) return false; return this._peripheral._checkPinState(pin); } } module.exports = Scratch3MicroBitBlocks; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/1-snare.mp3": /*!****************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/1-snare.mp3 ***! \****************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/90eaf6469dbf3a808a3d9739cc77358d.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/10-wood-block.mp3": /*!**********************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/10-wood-block.mp3 ***! \**********************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/4240a79d13ecf2792f825457194c96d9.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/11-cowbell.mp3": /*!*******************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/11-cowbell.mp3 ***! \*******************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/9ad12a9de73f49fb645902987027eb2b.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/12-triangle.mp3": /*!********************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/12-triangle.mp3 ***! \********************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/2b7b80de8884cc3cf584aa0deb86a59b.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/13-bongo.mp3": /*!*****************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/13-bongo.mp3 ***! \*****************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/5c6533a34175f61a9cab627f671111e1.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/14-conga.mp3": /*!*****************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/14-conga.mp3 ***! \*****************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/5888c4ba6b8a0767f8be5bbc81994397.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/15-cabasa.mp3": /*!******************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/15-cabasa.mp3 ***! \******************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/fad59dd220562492e6722aa8a97f9369.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/16-guiro.mp3": /*!*****************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/16-guiro.mp3 ***! \*****************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/51a75dd50afd0bc6022dfc86455be19c.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/17-vibraslap.mp3": /*!*********************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/17-vibraslap.mp3 ***! \*********************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/9f8e3a1db63c7a8fd976beca7e3546c3.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/18-cuica.mp3": /*!*****************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/18-cuica.mp3 ***! \*****************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/b6a8e4a96ffcd83154ad2c5cbcb52751.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/2-bass-drum.mp3": /*!********************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/2-bass-drum.mp3 ***! \********************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/1c9630b745711a0b829841e8555d76e4.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/3-side-stick.mp3": /*!*********************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/3-side-stick.mp3 ***! \*********************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/f8d8b9d9f1aa45900b786980418219b1.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/4-crash-cymbal.mp3": /*!***********************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/4-crash-cymbal.mp3 ***! \***********************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/83f2d48d0c7d1e6be8a509d4d2c6d0e5.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/5-open-hi-hat.mp3": /*!**********************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/5-open-hi-hat.mp3 ***! \**********************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/b700cf6f9c368ce49851d287ddd3b63c.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/6-closed-hi-hat.mp3": /*!************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/6-closed-hi-hat.mp3 ***! \************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/3fbd690bdae84637e34b8b933a164e3d.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/7-tambourine.mp3": /*!*********************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/7-tambourine.mp3 ***! \*********************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/a7c08a472cc8b1c4e0c45ae9b030b414.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/8-hand-clap.mp3": /*!********************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/8-hand-clap.mp3 ***! \********************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/f28b1ecd6fccd6218a837c14b1109da7.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/9-claves.mp3": /*!*****************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/9-claves.mp3 ***! \*****************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/f9868658d8483a6dbcd600e0226dfeef.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/108.mp3": /*!**************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/108.mp3 ***! \**************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/10af80546707afae5507edb828dd35a0.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/24.mp3": /*!*************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/24.mp3 ***! \*************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/7a7fdb40997804d4778e2a12bd7599f7.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/36.mp3": /*!*************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/36.mp3 ***! \*************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/a61fc8393abec3c0d1e813fc01f252ee.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/48.mp3": /*!*************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/48.mp3 ***! \*************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/a0b130dbafdc7958b73d162239053173.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/60.mp3": /*!*************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/60.mp3 ***! \*************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/d72b98474fc83d6268886779339e242e.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/72.mp3": /*!*************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/72.mp3 ***! \*************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/d4b3ce804680eb7d58f6accc7436e807.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/84.mp3": /*!*************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/84.mp3 ***! \*************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/129b99ac19024c35228d855f42fb852b.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/96.mp3": /*!*************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/96.mp3 ***! \*************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/8c0c02f16572b730d422f96a3ce53e7f.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/10-clarinet/48.mp3": /*!*****************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/10-clarinet/48.mp3 ***! \*****************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/00d2dff9d5ece15a67074374b2027590.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/10-clarinet/60.mp3": /*!*****************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/10-clarinet/60.mp3 ***! \*****************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/09995475180591a6c64c8744fbfdf4d8.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/11-saxophone/36.mp3": /*!******************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/11-saxophone/36.mp3 ***! \******************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/961bfad11616b6f5c951c58499cf267a.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/11-saxophone/60.mp3": /*!******************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/11-saxophone/60.mp3 ***! \******************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/2b0cfb89b2c8d1badb03136fcf911c3b.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/11-saxophone/84.mp3": /*!******************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/11-saxophone/84.mp3 ***! \******************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/c44ce3bfa465281e765f197d6c3ee7ea.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/12-flute/60.mp3": /*!**************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/12-flute/60.mp3 ***! \**************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/e6180253665b8248f685c6d96881f75b.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/12-flute/72.mp3": /*!**************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/12-flute/72.mp3 ***! \**************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/b52b83f63e8482255d46f40ea454fa01.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/13-wooden-flute/60.mp3": /*!*********************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/13-wooden-flute/60.mp3 ***! \*********************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/1e7ed7b14b056ebd80f434143846fb4e.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/13-wooden-flute/72.mp3": /*!*********************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/13-wooden-flute/72.mp3 ***! \*********************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/c36dd943607003a3229aca77b49d32de.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/14-bassoon/36.mp3": /*!****************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/14-bassoon/36.mp3 ***! \****************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/f382f43d667b784d1bcd8cfe7aa6fff0.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/14-bassoon/48.mp3": /*!****************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/14-bassoon/48.mp3 ***! \****************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/5e0704b815761d38242f1b961ce9ef69.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/14-bassoon/60.mp3": /*!****************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/14-bassoon/60.mp3 ***! \****************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/1a87a73db1ba0193283680e37b35754e.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/15-choir/48.mp3": /*!**************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/15-choir/48.mp3 ***! \**************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/fc383956e315b7ee2bd8dd09de311701.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/15-choir/60.mp3": /*!**************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/15-choir/60.mp3 ***! \**************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/0b18f02669375ad2ee80bef8d07ea7ec.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/15-choir/72.mp3": /*!**************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/15-choir/72.mp3 ***! \**************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/1980303ffc6f5c17c601a9e5992aea77.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/16-vibraphone/60.mp3": /*!*******************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/16-vibraphone/60.mp3 ***! \*******************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/57f0f65052d9dac78ee66b11cc696b6a.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/16-vibraphone/72.mp3": /*!*******************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/16-vibraphone/72.mp3 ***! \*******************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/da1a6ebcd442e9d867b31fb21ce6a289.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/17-music-box/60.mp3": /*!******************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/17-music-box/60.mp3 ***! \******************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/bacc13779ca01580b89f39dd2118c22a.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/18-steel-drum/60.mp3": /*!*******************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/18-steel-drum/60.mp3 ***! \*******************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/0dcd27b60c185811b19f59d56eaa12f6.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/19-marimba/60.mp3": /*!****************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/19-marimba/60.mp3 ***! \****************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/1a064f9a752824e781ccf79ab66850ed.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/2-electric-piano/60.mp3": /*!**********************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/2-electric-piano/60.mp3 ***! \**********************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/a05bbf6359407ad7950e115edab178d9.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/20-synth-lead/60.mp3": /*!*******************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/20-synth-lead/60.mp3 ***! \*******************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/da3126c6a70c4ef84192c33f99996354.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/21-synth-pad/60.mp3": /*!******************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/21-synth-pad/60.mp3 ***! \******************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/103fe904046c35630c600cb122492d78.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/3-organ/60.mp3": /*!*************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/3-organ/60.mp3 ***! \*************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/8ca9997e9ed7534a8d0f349a6125bd24.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/4-guitar/60.mp3": /*!**************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/4-guitar/60.mp3 ***! \**************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/83857346b7c2e6a351c69377e82a3606.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/5-electric-guitar/60.mp3": /*!***********************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/5-electric-guitar/60.mp3 ***! \***********************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/ecb1cbda3b9c4f29ab971734d97e3faf.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/6-bass/36.mp3": /*!************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/6-bass/36.mp3 ***! \************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/0043f23189fb3cbf2021a88959961ece.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/6-bass/48.mp3": /*!************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/6-bass/48.mp3 ***! \************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/78a74345ee778afbd6abe637b4f69efc.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/7-pizzicato/60.mp3": /*!*****************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/7-pizzicato/60.mp3 ***! \*****************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/d434438e5d193118e4aad3a846e1c7ba.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/8-cello/36.mp3": /*!*************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/8-cello/36.mp3 ***! \*************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/39563f3b38b1fdb805323b1f69dace54.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/8-cello/48.mp3": /*!*************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/8-cello/48.mp3 ***! \*************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/0e8ed599d9875c77d52db36de2b2b33f.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/8-cello/60.mp3": /*!*************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/8-cello/60.mp3 ***! \*************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/7337f194b0a727f4be98902487dfb615.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/9-trombone/36.mp3": /*!****************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/9-trombone/36.mp3 ***! \****************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/ed2a96fbdb476efe419246982e357121.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/9-trombone/48.mp3": /*!****************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/9-trombone/48.mp3 ***! \****************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/7c5a16e0627c64fd62ec597bb72b879d.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/9-trombone/60.mp3": /*!****************************************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/9-trombone/60.mp3 ***! \****************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__.p + "static/assets/e27f7cdf42df8b768345ae83fecffe4b.mp3"; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/index.js": /*!************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/index.js ***! \************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const ArgumentType = __webpack_require__(/*! ../../extension-support/argument-type */ "./node_modules/scratch-vm/src/extension-support/argument-type.js"); const BlockType = __webpack_require__(/*! ../../extension-support/block-type */ "./node_modules/scratch-vm/src/extension-support/block-type.js"); const Clone = __webpack_require__(/*! ../../util/clone */ "./node_modules/scratch-vm/src/util/clone.js"); const Cast = __webpack_require__(/*! ../../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); const formatMessage = __webpack_require__(/*! format-message */ "./node_modules/format-message/index.js"); const MathUtil = __webpack_require__(/*! ../../util/math-util */ "./node_modules/scratch-vm/src/util/math-util.js"); const Timer = __webpack_require__(/*! ../../util/timer */ "./node_modules/scratch-vm/src/util/timer.js"); /** * The instrument and drum sounds, loaded as static assets. * @type {object} */ let assetData = {}; try { assetData = __webpack_require__(/*! ./manifest */ "./node_modules/scratch-vm/src/extensions/scratch3_music/manifest.js"); } catch (e) {// Non-webpack environment, don't worry about assets. } /** * Icon svg to be displayed at the left edge of each extension block, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len const blockIconURI = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHZpZXdCb3g9IjAgMCA0MCA0MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PHRpdGxlPm11c2ljLWJsb2NrLWljb248L3RpdGxlPjxkZWZzPjxwYXRoIGQ9Ik0zMi4xOCAyNS44NzRDMzIuNjM2IDI4LjE1NyAzMC41MTIgMzAgMjcuNDMzIDMwYy0zLjA3IDAtNS45MjMtMS44NDMtNi4zNzItNC4xMjYtLjQ1OC0yLjI4NSAxLjY2NS00LjEzNiA0Ljc0My00LjEzNi42NDcgMCAxLjI4My4wODQgMS44OS4yMzQuMzM4LjA4Ni42MzcuMTguOTM4LjMwMi44Ny0uMDItLjEwNC0yLjI5NC0xLjgzNS0xMi4yMy0yLjEzNC0xMi4zMDIgMy4wNi0xLjg3IDguNzY4LTIuNzUyIDUuNzA4LS44ODUuMDc2IDQuODItMy42NSAzLjg0NC0zLjcyNC0uOTg3LTQuNjUtNy4xNTMuMjYzIDE0LjczOHptLTE2Ljk5OCA1Ljk5QzE1LjYzIDM0LjE0OCAxMy41MDcgMzYgMTAuNDQgMzZjLTMuMDcgMC01LjkyMi0xLjg1Mi02LjM4LTQuMTM2LS40NDgtMi4yODQgMS42NzQtNC4xMzUgNC43NS00LjEzNSAxLjAwMyAwIDEuOTc1LjE5NiAyLjg1NS41NDMuODIyLS4wNTUtLjE1LTIuMzc3LTEuODYyLTEyLjIyOC0yLjEzMy0xMi4zMDMgMy4wNi0xLjg3IDguNzY0LTIuNzUzIDUuNzA2LS44OTQuMDc2IDQuODItMy42NDggMy44MzQtMy43MjQtLjk4Ny00LjY1LTcuMTUyLjI2MiAxNC43Mzh6IiBpZD0iYSIvPjwvZGVmcz48ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjx1c2UgZmlsbD0iI0ZGRiIgeGxpbms6aHJlZj0iI2EiLz48cGF0aCBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZT0iIzAwMCIgZD0iTTI4LjQ1NiAyMS42NzVjLS4wMS0uMzEyLS4wODctLjgyNS0uMjU2LTEuNzAyLS4wOTYtLjQ5NS0uNjEyLTMuMDIyLS43NTMtMy43My0uMzk1LTEuOTgtLjc2LTMuOTItMS4xNDItNi4xMTMtLjczMi00LjIyMy0uNjkzLTYuMDUuMzQ0LTYuNTI3LjUtLjIzIDEuMDYtLjA4IDEuODQuMzUuNDE0LjIyNyAyLjE4MiAxLjM2NSAyLjA3IDEuMjk2IDEuOTk0IDEuMjQyIDMuNDY0IDEuNzc0IDQuOTMgMS41NDggMS41MjYtLjIzNyAyLjUwNC0uMDYgMi44NzYuNjE4LjM0OC42MzUuMDE1IDEuNDE2LS43MyAyLjE4LTEuNDcyIDEuNTE2LTMuOTc1IDIuNTE0LTUuODQ4IDIuMDIzLS44MjItLjIyLTEuMjM4LS40NjUtMi4zOC0xLjI2N2wtLjA5NS0uMDY2Yy4wNDcuNTkzLjI2NCAxLjc0LjcxNyAzLjgwMy4yOTQgMS4zMzYgMi4wOCA5LjE4NyAyLjYzNyAxMS42NzRsLjAwMi4wMTJjLjUyOCAyLjYzNy0xLjg3MyA0LjcyNC01LjIzNiA0LjcyNC0zLjI5IDAtNi4zNjMtMS45ODgtNi44NjItNC41MjgtLjUzLTIuNjQgMS44NzMtNC43MzQgNS4yMzMtNC43MzQuNjcyIDAgMS4zNDcuMDg1IDIuMDE0LjI1LjIyNy4wNTcuNDM2LjExOC42MzYuMTg3em0tMTYuOTk2IDUuOTljLS4wMS0uMzE4LS4wOS0uODM4LS4yNjYtMS43MzctLjA5LS40Ni0uNTk1LTIuOTM3LS43NTMtMy43MjctLjM5LTEuOTYtLjc1LTMuODktMS4xMy02LjA3LS43MzItNC4yMjMtLjY5Mi02LjA1LjM0NC02LjUyNi41MDItLjIzIDEuMDYtLjA4MiAxLjg0LjM1LjQxNS4yMjcgMi4xODIgMS4zNjQgMi4wNyAxLjI5NSAxLjk5MyAxLjI0MiAzLjQ2MiAxLjc3NCA0LjkyNiAxLjU0OCAxLjUyNS0uMjQgMi41MDQtLjA2NCAyLjg3Ni42MTQuMzQ4LjYzNS4wMTUgMS40MTUtLjcyOCAyLjE4LTEuNDc0IDEuNTE3LTMuOTc3IDIuNTEzLTUuODQ3IDIuMDE3LS44Mi0uMjItMS4yMzYtLjQ2NC0yLjM3OC0xLjI2N2wtLjA5NS0uMDY1Yy4wNDcuNTkzLjI2NCAxLjc0LjcxNyAzLjgwMi4yOTQgMS4zMzcgMi4wNzggOS4xOSAyLjYzNiAxMS42NzVsLjAwMy4wMTNjLjUxNyAyLjYzOC0xLjg4NCA0LjczMi01LjIzNCA0LjczMi0zLjI4NyAwLTYuMzYtMS45OTMtNi44Ny00LjU0LS41Mi0yLjY0IDEuODg0LTQuNzMgNS4yNC00LjczLjkwNSAwIDEuODAzLjE1IDIuNjUuNDM2eiIvPjwvZz48L3N2Zz4='; /** * Icon svg to be displayed in the category menu, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len const menuIconURI = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTE2LjA5IDEyLjkzN2MuMjI4IDEuMTQxLS44MzMgMi4wNjMtMi4zNzMgMi4wNjMtMS41MzUgMC0yLjk2Mi0uOTIyLTMuMTg2LTIuMDYzLS4yMy0xLjE0Mi44MzMtMi4wNjggMi4zNzItMi4wNjguMzIzIDAgLjY0MS4wNDIuOTQ1LjExN2EzLjUgMy41IDAgMCAxIC40NjguMTUxYy40MzUtLjAxLS4wNTItMS4xNDctLjkxNy02LjExNC0xLjA2Ny02LjE1MiAxLjUzLS45MzUgNC4zODQtMS4zNzcgMi44NTQtLjQ0Mi4wMzggMi40MS0xLjgyNSAxLjkyMi0xLjg2Mi0uNDkzLTIuMzI1LTMuNTc3LjEzMiA3LjM3ek03LjQ2IDguNTYzYy0xLjg2Mi0uNDkzLTIuMzI1LTMuNTc2LjEzIDcuMzdDNy44MTYgMTcuMDczIDYuNzU0IDE4IDUuMjIgMThjLTEuNTM1IDAtMi45NjEtLjkyNi0zLjE5LTIuMDY4LS4yMjQtMS4xNDIuODM3LTIuMDY3IDIuMzc1LTIuMDY3LjUwMSAwIC45ODcuMDk4IDEuNDI3LjI3Mi40MTItLjAyOC0uMDc0LTEuMTg5LS45My02LjExNEMzLjgzNCAxLjg3IDYuNDMgNy4wODcgOS4yODIgNi42NDZjMi44NTQtLjQ0Ny4wMzggMi40MS0xLjgyMyAxLjkxN3oiIGZpbGw9IiM1NzVFNzUiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg=='; /** * Class for the music-related blocks in Scratch 3.0 * @param {Runtime} runtime - the runtime instantiating this block package. * @constructor */ class Scratch3MusicBlocks { constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; /** * The number of drum and instrument sounds currently being played simultaneously. * @type {number} * @private */ this._concurrencyCounter = 0; /** * An array of sound players, one for each drum sound. * @type {Array} * @private */ this._drumPlayers = []; /** * An array of arrays of sound players. Each instrument has one or more audio players. * @type {Array[]} * @private */ this._instrumentPlayerArrays = []; /** * An array of arrays of sound players. Each instrument mya have an audio player for each playable note. * @type {Array[]} * @private */ this._instrumentPlayerNoteArrays = []; /** * An array of audio bufferSourceNodes. Each time you play an instrument or drum sound, * a bufferSourceNode is created. We keep references to them to make sure their onended * events can fire. * @type {Array} * @private */ this._bufferSources = []; this._loadAllSounds(); this._onTargetCreated = this._onTargetCreated.bind(this); this.runtime.on('targetWasCreated', this._onTargetCreated); this._playNoteForPicker = this._playNoteForPicker.bind(this); this.runtime.on('PLAY_NOTE', this._playNoteForPicker); } /** * Decode the full set of drum and instrument sounds, and store the audio buffers in arrays. */ _loadAllSounds() { const loadingPromises = []; this.DRUM_INFO.forEach((drumInfo, index) => { const filePath = "drums/".concat(drumInfo.fileName); const promise = this._storeSound(filePath, index, this._drumPlayers); loadingPromises.push(promise); }); this.INSTRUMENT_INFO.forEach((instrumentInfo, instrumentIndex) => { this._instrumentPlayerArrays[instrumentIndex] = []; this._instrumentPlayerNoteArrays[instrumentIndex] = []; instrumentInfo.samples.forEach((sample, noteIndex) => { const filePath = "instruments/".concat(instrumentInfo.dirName, "/").concat(sample); const promise = this._storeSound(filePath, noteIndex, this._instrumentPlayerArrays[instrumentIndex]); loadingPromises.push(promise); }); }); Promise.all(loadingPromises).then(() => {// @TODO: Update the extension status indicator. }); } /** * Decode a sound and store the player in an array. * @param {string} filePath - the audio file name. * @param {number} index - the index at which to store the audio player. * @param {array} playerArray - the array of players in which to store it. * @return {Promise} - a promise which will resolve once the sound has been stored. */ _storeSound(filePath, index, playerArray) { const fullPath = "".concat(filePath, ".mp3"); if (!assetData[fullPath]) return; const soundFile = assetData[fullPath]; return fetch(soundFile).then(r => r.arrayBuffer()).then(soundBuffer => this._decodeSound(soundBuffer)).then(player => { playerArray[index] = player; }); } /** * Decode a sound and return a promise with the audio buffer. * @param {ArrayBuffer} soundBuffer - a buffer containing the encoded audio. * @return {Promise} - a promise which will resolve once the sound has decoded. */ _decodeSound(soundBuffer) { const engine = this.runtime.audioEngine; if (!engine) { return Promise.reject(new Error('No Audio Context Detected')); } // Check for newer promise-based API return engine.decodeSoundPlayer({ data: { buffer: soundBuffer } }); } /** * Create data for a menu in scratch-blocks format, consisting of an array of objects with text and * value properties. The text is a translated string, and the value is one-indexed. * @param {object[]} info - An array of info objects each having a name property. * @return {array} - An array of objects with text and value properties. * @private */ _buildMenu(info) { return info.map((entry, index) => { const obj = {}; obj.text = entry.name; obj.value = String(index + 1); return obj; }); } /** * An array of info about each drum. * @type {object[]} * @param {string} name - the translatable name to display in the drums menu. * @param {string} fileName - the name of the audio file containing the drum sound. */ get DRUM_INFO() { return [{ name: formatMessage({ id: 'music.drumSnare', default: '(1) Snare Drum', description: 'Sound of snare drum as used in a standard drum kit' }), fileName: '1-snare' }, { name: formatMessage({ id: 'music.drumBass', default: '(2) Bass Drum', description: 'Sound of bass drum as used in a standard drum kit' }), fileName: '2-bass-drum' }, { name: formatMessage({ id: 'music.drumSideStick', default: '(3) Side Stick', description: 'Sound of a drum stick hitting the side of a drum (usually the snare)' }), fileName: '3-side-stick' }, { name: formatMessage({ id: 'music.drumCrashCymbal', default: '(4) Crash Cymbal', description: 'Sound of a drum stick hitting a crash cymbal' }), fileName: '4-crash-cymbal' }, { name: formatMessage({ id: 'music.drumOpenHiHat', default: '(5) Open Hi-Hat', description: 'Sound of a drum stick hitting a hi-hat while open' }), fileName: '5-open-hi-hat' }, { name: formatMessage({ id: 'music.drumClosedHiHat', default: '(6) Closed Hi-Hat', description: 'Sound of a drum stick hitting a hi-hat while closed' }), fileName: '6-closed-hi-hat' }, { name: formatMessage({ id: 'music.drumTambourine', default: '(7) Tambourine', description: 'Sound of a tambourine being struck' }), fileName: '7-tambourine' }, { name: formatMessage({ id: 'music.drumHandClap', default: '(8) Hand Clap', description: 'Sound of two hands clapping together' }), fileName: '8-hand-clap' }, { name: formatMessage({ id: 'music.drumClaves', default: '(9) Claves', description: 'Sound of claves being struck together' }), fileName: '9-claves' }, { name: formatMessage({ id: 'music.drumWoodBlock', default: '(10) Wood Block', description: 'Sound of a wood block being struck' }), fileName: '10-wood-block' }, { name: formatMessage({ id: 'music.drumCowbell', default: '(11) Cowbell', description: 'Sound of a cowbell being struck' }), fileName: '11-cowbell' }, { name: formatMessage({ id: 'music.drumTriangle', default: '(12) Triangle', description: 'Sound of a triangle (instrument) being struck' }), fileName: '12-triangle' }, { name: formatMessage({ id: 'music.drumBongo', default: '(13) Bongo', description: 'Sound of a bongo being struck' }), fileName: '13-bongo' }, { name: formatMessage({ id: 'music.drumConga', default: '(14) Conga', description: 'Sound of a conga being struck' }), fileName: '14-conga' }, { name: formatMessage({ id: 'music.drumCabasa', default: '(15) Cabasa', description: 'Sound of a cabasa being shaken' }), fileName: '15-cabasa' }, { name: formatMessage({ id: 'music.drumGuiro', default: '(16) Guiro', description: 'Sound of a guiro being played' }), fileName: '16-guiro' }, { name: formatMessage({ id: 'music.drumVibraslap', default: '(17) Vibraslap', description: 'Sound of a Vibraslap being played' }), fileName: '17-vibraslap' }, { name: formatMessage({ id: 'music.drumCuica', default: '(18) Cuica', description: 'Sound of a cuica being played' }), fileName: '18-cuica' }]; } /** * An array of info about each instrument. * @type {object[]} * @param {string} name - the translatable name to display in the instruments menu. * @param {string} dirName - the name of the directory containing audio samples for this instrument. * @param {number} [releaseTime] - an optional duration for the release portion of each note. * @param {number[]} samples - an array of numbers representing the MIDI note number for each * sampled sound used to play this instrument. */ get INSTRUMENT_INFO() { return [{ name: formatMessage({ id: 'music.instrumentPiano', default: '(1) Piano', description: 'Sound of a piano' }), dirName: '1-piano', releaseTime: 0.5, samples: [24, 36, 48, 60, 72, 84, 96, 108] }, { name: formatMessage({ id: 'music.instrumentElectricPiano', default: '(2) Electric Piano', description: 'Sound of an electric piano' }), dirName: '2-electric-piano', releaseTime: 0.5, samples: [60] }, { name: formatMessage({ id: 'music.instrumentOrgan', default: '(3) Organ', description: 'Sound of an organ' }), dirName: '3-organ', releaseTime: 0.5, samples: [60] }, { name: formatMessage({ id: 'music.instrumentGuitar', default: '(4) Guitar', description: 'Sound of an accoustic guitar' }), dirName: '4-guitar', releaseTime: 0.5, samples: [60] }, { name: formatMessage({ id: 'music.instrumentElectricGuitar', default: '(5) Electric Guitar', description: 'Sound of an electric guitar' }), dirName: '5-electric-guitar', releaseTime: 0.5, samples: [60] }, { name: formatMessage({ id: 'music.instrumentBass', default: '(6) Bass', description: 'Sound of an accoustic upright bass' }), dirName: '6-bass', releaseTime: 0.25, samples: [36, 48] }, { name: formatMessage({ id: 'music.instrumentPizzicato', default: '(7) Pizzicato', description: 'Sound of a string instrument (e.g. violin) being plucked' }), dirName: '7-pizzicato', releaseTime: 0.25, samples: [60] }, { name: formatMessage({ id: 'music.instrumentCello', default: '(8) Cello', description: 'Sound of a cello being played with a bow' }), dirName: '8-cello', releaseTime: 0.1, samples: [36, 48, 60] }, { name: formatMessage({ id: 'music.instrumentTrombone', default: '(9) Trombone', description: 'Sound of a trombone being played' }), dirName: '9-trombone', samples: [36, 48, 60] }, { name: formatMessage({ id: 'music.instrumentClarinet', default: '(10) Clarinet', description: 'Sound of a clarinet being played' }), dirName: '10-clarinet', samples: [48, 60] }, { name: formatMessage({ id: 'music.instrumentSaxophone', default: '(11) Saxophone', description: 'Sound of a saxophone being played' }), dirName: '11-saxophone', samples: [36, 60, 84] }, { name: formatMessage({ id: 'music.instrumentFlute', default: '(12) Flute', description: 'Sound of a flute being played' }), dirName: '12-flute', samples: [60, 72] }, { name: formatMessage({ id: 'music.instrumentWoodenFlute', default: '(13) Wooden Flute', description: 'Sound of a wooden flute being played' }), dirName: '13-wooden-flute', samples: [60, 72] }, { name: formatMessage({ id: 'music.instrumentBassoon', default: '(14) Bassoon', description: 'Sound of a bassoon being played' }), dirName: '14-bassoon', samples: [36, 48, 60] }, { name: formatMessage({ id: 'music.instrumentChoir', default: '(15) Choir', description: 'Sound of a choir singing' }), dirName: '15-choir', releaseTime: 0.25, samples: [48, 60, 72] }, { name: formatMessage({ id: 'music.instrumentVibraphone', default: '(16) Vibraphone', description: 'Sound of a vibraphone being struck' }), dirName: '16-vibraphone', releaseTime: 0.5, samples: [60, 72] }, { name: formatMessage({ id: 'music.instrumentMusicBox', default: '(17) Music Box', description: 'Sound of a music box playing' }), dirName: '17-music-box', releaseTime: 0.25, samples: [60] }, { name: formatMessage({ id: 'music.instrumentSteelDrum', default: '(18) Steel Drum', description: 'Sound of a steel drum being struck' }), dirName: '18-steel-drum', releaseTime: 0.5, samples: [60] }, { name: formatMessage({ id: 'music.instrumentMarimba', default: '(19) Marimba', description: 'Sound of a marimba being struck' }), dirName: '19-marimba', samples: [60] }, { name: formatMessage({ id: 'music.instrumentSynthLead', default: '(20) Synth Lead', description: 'Sound of a "lead" synthesizer being played' }), dirName: '20-synth-lead', releaseTime: 0.1, samples: [60] }, { name: formatMessage({ id: 'music.instrumentSynthPad', default: '(21) Synth Pad', description: 'Sound of a "pad" synthesizer being played' }), dirName: '21-synth-pad', releaseTime: 0.25, samples: [60] }]; } /** * An array that is a mapping from MIDI instrument numbers to Scratch instrument numbers. * @type {number[]} */ get MIDI_INSTRUMENTS() { return [// Acoustic Grand, Bright Acoustic, Electric Grand, Honky-Tonk 1, 1, 1, 1, // Electric Piano 1, Electric Piano 2, Harpsichord, Clavinet 2, 2, 4, 4, // Celesta, Glockenspiel, Music Box, Vibraphone 17, 17, 17, 16, // Marimba, Xylophone, Tubular Bells, Dulcimer 19, 16, 17, 17, // Drawbar Organ, Percussive Organ, Rock Organ, Church Organ 3, 3, 3, 3, // Reed Organ, Accordion, Harmonica, Tango Accordion 3, 3, 3, 3, // Nylon String Guitar, Steel String Guitar, Electric Jazz Guitar, Electric Clean Guitar 4, 4, 5, 5, // Electric Muted Guitar, Overdriven Guitar,Distortion Guitar, Guitar Harmonics 5, 5, 5, 5, // Acoustic Bass, Electric Bass (finger), Electric Bass (pick), Fretless Bass 6, 6, 6, 6, // Slap Bass 1, Slap Bass 2, Synth Bass 1, Synth Bass 2 6, 6, 6, 6, // Violin, Viola, Cello, Contrabass 8, 8, 8, 8, // Tremolo Strings, Pizzicato Strings, Orchestral Strings, Timpani 8, 7, 8, 19, // String Ensemble 1, String Ensemble 2, SynthStrings 1, SynthStrings 2 8, 8, 8, 8, // Choir Aahs, Voice Oohs, Synth Voice, Orchestra Hit 15, 15, 15, 19, // Trumpet, Trombone, Tuba, Muted Trumpet 9, 9, 9, 9, // French Horn, Brass Section, SynthBrass 1, SynthBrass 2 9, 9, 9, 9, // Soprano Sax, Alto Sax, Tenor Sax, Baritone Sax 11, 11, 11, 11, // Oboe, English Horn, Bassoon, Clarinet 14, 14, 14, 10, // Piccolo, Flute, Recorder, Pan Flute 12, 12, 13, 13, // Blown Bottle, Shakuhachi, Whistle, Ocarina 13, 13, 12, 12, // Lead 1 (square), Lead 2 (sawtooth), Lead 3 (calliope), Lead 4 (chiff) 20, 20, 20, 20, // Lead 5 (charang), Lead 6 (voice), Lead 7 (fifths), Lead 8 (bass+lead) 20, 20, 20, 20, // Pad 1 (new age), Pad 2 (warm), Pad 3 (polysynth), Pad 4 (choir) 21, 21, 21, 21, // Pad 5 (bowed), Pad 6 (metallic), Pad 7 (halo), Pad 8 (sweep) 21, 21, 21, 21, // FX 1 (rain), FX 2 (soundtrack), FX 3 (crystal), FX 4 (atmosphere) 21, 21, 21, 21, // FX 5 (brightness), FX 6 (goblins), FX 7 (echoes), FX 8 (sci-fi) 21, 21, 21, 21, // Sitar, Banjo, Shamisen, Koto 4, 4, 4, 4, // Kalimba, Bagpipe, Fiddle, Shanai 17, 14, 8, 10, // Tinkle Bell, Agogo, Steel Drums, Woodblock 17, 17, 18, 19, // Taiko Drum, Melodic Tom, Synth Drum, Reverse Cymbal 1, 1, 1, 1, // Guitar Fret Noise, Breath Noise, Seashore, Bird Tweet 21, 21, 21, 21, // Telephone Ring, Helicopter, Applause, Gunshot 21, 21, 21, 21]; } /** * An array that is a mapping from MIDI drum numbers in range (35..81) to Scratch drum numbers. * It's in the format [drumNum, pitch, decay]. * The pitch and decay properties are not currently being used. * @type {Array[]} */ get MIDI_DRUMS() { return [[1, -4], // "BassDrum" in 2.0, "Bass Drum" in 3.0 (which was "Tom" in 2.0) [1, 0], // Same as just above [2, 0], [0, 0], [7, 0], [0, 2], [1, -6, 4], [5, 0], [1, -3, 3.2], [5, 0], // "HiHatPedal" in 2.0, "Closed Hi-Hat" in 3.0 [1, 0, 3], [4, -8], [1, 4, 3], [1, 7, 2.7], [3, -8], [1, 10, 2.7], [4, -2], [3, -11], [4, 2], [6, 0], [3, 0, 3.5], [10, 0], [3, -8, 3.5], [16, -6], [4, 2], [12, 2], [12, 0], [13, 0, 0.2], [13, 0, 2], [13, -5, 2], [12, 12], [12, 5], [10, 19], [10, 12], [14, 0], [14, 0], // "Maracas" in 2.0, "Cabasa" in 3.0 (TODO: pitch up?) [17, 12], [17, 5], [15, 0], // "GuiroShort" in 2.0, "Guiro" in 3.0 (which was "GuiroLong" in 2.0) (TODO: decay?) [15, 0], [8, 0], [9, 0], [9, -4], [17, -5], [17, 0], [11, -6, 1], [11, -6, 3]]; } /** * The key to load & store a target's music-related state. * @type {string} */ static get STATE_KEY() { return 'Scratch.music'; } /** * The default music-related state, to be used when a target has no existing music state. * @type {MusicState} */ static get DEFAULT_MUSIC_STATE() { return { currentInstrument: 0 }; } /** * The minimum and maximum MIDI note numbers, for clamping the input to play note. * @type {{min: number, max: number}} */ static get MIDI_NOTE_RANGE() { return { min: 0, max: 130 }; } /** * The minimum and maximum beat values, for clamping the duration of play note, play drum and rest. * 100 beats at the default tempo of 60bpm is 100 seconds. * @type {{min: number, max: number}} */ static get BEAT_RANGE() { return { min: 0, max: 100 }; } /** The minimum and maximum tempo values, in bpm. * @type {{min: number, max: number}} */ static get TEMPO_RANGE() { return { min: 20, max: 500 }; } /** * The maximum number of sounds to allow to play simultaneously. * @type {number} */ static get CONCURRENCY_LIMIT() { return 30; } /** * @param {Target} target - collect music state for this target. * @returns {MusicState} the mutable music state associated with that target. This will be created if necessary. * @private */ _getMusicState(target) { let musicState = target.getCustomState(Scratch3MusicBlocks.STATE_KEY); if (!musicState) { musicState = Clone.simple(Scratch3MusicBlocks.DEFAULT_MUSIC_STATE); target.setCustomState(Scratch3MusicBlocks.STATE_KEY, musicState); } return musicState; } /** * When a music-playing Target is cloned, clone the music state. * @param {Target} newTarget - the newly created target. * @param {Target} [sourceTarget] - the target used as a source for the new clone, if any. * @listens Runtime#event:targetWasCreated * @private */ _onTargetCreated(newTarget, sourceTarget) { if (sourceTarget) { const musicState = sourceTarget.getCustomState(Scratch3MusicBlocks.STATE_KEY); if (musicState) { newTarget.setCustomState(Scratch3MusicBlocks.STATE_KEY, Clone.simple(musicState)); } } } /** * @returns {object} metadata for this extension and its blocks. */ getInfo() { return { id: 'music', name: formatMessage({ id: 'music.categoryName', default: 'Music', description: 'Label for the Music extension category' }), menuIconURI: menuIconURI, blockIconURI: blockIconURI, blocks: [{ opcode: 'playDrumForBeats', blockType: BlockType.COMMAND, text: formatMessage({ id: 'music.playDrumForBeats', default: 'play drum [DRUM] for [BEATS] beats', description: 'play drum sample for a number of beats' }), arguments: { DRUM: { type: ArgumentType.NUMBER, menu: 'DRUM', defaultValue: 1 }, BEATS: { type: ArgumentType.NUMBER, defaultValue: 0.25 } } }, { opcode: 'midiPlayDrumForBeats', blockType: BlockType.COMMAND, text: formatMessage({ id: 'music.midiPlayDrumForBeats', default: 'play drum [DRUM] for [BEATS] beats', description: 'play drum sample for a number of beats according to a mapping of MIDI codes' }), arguments: { DRUM: { type: ArgumentType.NUMBER, menu: 'DRUM', defaultValue: 1 }, BEATS: { type: ArgumentType.NUMBER, defaultValue: 0.25 } }, hideFromPalette: true }, { opcode: 'restForBeats', blockType: BlockType.COMMAND, text: formatMessage({ id: 'music.restForBeats', default: 'rest for [BEATS] beats', description: 'rest (play no sound) for a number of beats' }), arguments: { BEATS: { type: ArgumentType.NUMBER, defaultValue: 0.25 } } }, { opcode: 'playNoteForBeats', blockType: BlockType.COMMAND, text: formatMessage({ id: 'music.playNoteForBeats', default: 'play note [NOTE] for [BEATS] beats', description: 'play a note for a number of beats' }), arguments: { NOTE: { type: ArgumentType.NOTE, defaultValue: 60 }, BEATS: { type: ArgumentType.NUMBER, defaultValue: 0.25 } } }, { opcode: 'setInstrument', blockType: BlockType.COMMAND, text: formatMessage({ id: 'music.setInstrument', default: 'set instrument to [INSTRUMENT]', description: 'set the instrument (e.g. piano, guitar, trombone) for notes played' }), arguments: { INSTRUMENT: { type: ArgumentType.NUMBER, menu: 'INSTRUMENT', defaultValue: 1 } } }, { opcode: 'midiSetInstrument', blockType: BlockType.COMMAND, text: formatMessage({ id: 'music.midiSetInstrument', default: 'set instrument to [INSTRUMENT]', description: 'set the instrument for notes played according to a mapping of MIDI codes' }), arguments: { INSTRUMENT: { type: ArgumentType.NUMBER, defaultValue: 1 } }, hideFromPalette: true }, { opcode: 'setTempo', blockType: BlockType.COMMAND, text: formatMessage({ id: 'music.setTempo', default: 'set tempo to [TEMPO]', description: 'set tempo (speed) for notes, drums, and rests played' }), arguments: { TEMPO: { type: ArgumentType.NUMBER, defaultValue: 60 } } }, { opcode: 'changeTempo', blockType: BlockType.COMMAND, text: formatMessage({ id: 'music.changeTempo', default: 'change tempo by [TEMPO]', description: 'change tempo (speed) for notes, drums, and rests played' }), arguments: { TEMPO: { type: ArgumentType.NUMBER, defaultValue: 20 } } }, { opcode: 'getTempo', text: formatMessage({ id: 'music.getTempo', default: 'tempo', description: 'get the current tempo (speed) for notes, drums, and rests played' }), blockType: BlockType.REPORTER }], menus: { DRUM: { acceptReporters: true, items: this._buildMenu(this.DRUM_INFO) }, INSTRUMENT: { acceptReporters: true, items: this._buildMenu(this.INSTRUMENT_INFO) } } }; } /** * Play a drum sound for some number of beats. * @param {object} args - the block arguments. * @param {object} util - utility object provided by the runtime. * @property {int} DRUM - the number of the drum to play. * @property {number} BEATS - the duration in beats of the drum sound. */ playDrumForBeats(args, util) { this._playDrumForBeats(args.DRUM, args.BEATS, util); } /** * Play a drum sound for some number of beats according to the range of "MIDI" drum codes supported. * This block is implemented for compatibility with old Scratch projects that use the * 'drum:duration:elapsed:from:' block. * @param {object} args - the block arguments. * @param {object} util - utility object provided by the runtime. */ midiPlayDrumForBeats(args, util) { let drumNum = Cast.toNumber(args.DRUM); drumNum = Math.round(drumNum); const midiDescription = this.MIDI_DRUMS[drumNum - 35]; if (midiDescription) { drumNum = midiDescription[0]; } else { drumNum = 2; // Default instrument used in Scratch 2.0 } drumNum += 1; // drumNum input to _playDrumForBeats is one-indexed this._playDrumForBeats(drumNum, args.BEATS, util); } /** * Internal code to play a drum sound for some number of beats. * @param {number} drumNum - the drum number. * @param {beats} beats - the duration in beats to pause after playing the sound. * @param {object} util - utility object provided by the runtime. */ _playDrumForBeats(drumNum, beats, util) { if (this._stackTimerNeedsInit(util)) { drumNum = Cast.toNumber(drumNum); drumNum = Math.round(drumNum); drumNum -= 1; // drums are one-indexed drumNum = MathUtil.wrapClamp(drumNum, 0, this.DRUM_INFO.length - 1); beats = Cast.toNumber(beats); beats = this._clampBeats(beats); this._playDrumNum(util, drumNum); this._startStackTimer(util, this._beatsToSec(beats)); } else { this._checkStackTimer(util); } } /** * Play a drum sound using its 0-indexed number. * @param {object} util - utility object provided by the runtime. * @param {number} drumNum - the number of the drum to play. * @private */ _playDrumNum(util, drumNum) { if (util.runtime.audioEngine === null) return; if (util.target.sprite.soundBank === null) return; // If we're playing too many sounds, do not play the drum sound. if (this._concurrencyCounter > Scratch3MusicBlocks.CONCURRENCY_LIMIT) { return; } const player = this._drumPlayers[drumNum]; if (typeof player === 'undefined') return; if (player.isPlaying && !player.isStarting) { // Take the internal player state and create a new player with it. // `.play` does this internally but then instructs the sound to // stop. player.take(); } const engine = util.runtime.audioEngine; const context = engine.audioContext; const volumeGain = context.createGain(); volumeGain.gain.setValueAtTime(util.target.volume / 100, engine.currentTime); volumeGain.connect(engine.getInputNode()); this._concurrencyCounter++; player.once('stop', () => { this._concurrencyCounter--; }); player.play(); // Connect the player to the gain node. player.connect({ getInputNode() { return volumeGain; } }); } /** * Rest for some number of beats. * @param {object} args - the block arguments. * @param {object} util - utility object provided by the runtime. * @property {number} BEATS - the duration in beats of the rest. */ restForBeats(args, util) { if (this._stackTimerNeedsInit(util)) { let beats = Cast.toNumber(args.BEATS); beats = this._clampBeats(beats); this._startStackTimer(util, this._beatsToSec(beats)); } else { this._checkStackTimer(util); } } /** * Play a note using the current musical instrument for some number of beats. * This function processes the arguments, and handles the timing of the block's execution. * @param {object} args - the block arguments. * @param {object} util - utility object provided by the runtime. * @property {number} NOTE - the pitch of the note to play, interpreted as a MIDI note number. * @property {number} BEATS - the duration in beats of the note. */ playNoteForBeats(args, util) { if (this._stackTimerNeedsInit(util)) { let note = Cast.toNumber(args.NOTE); note = MathUtil.clamp(note, Scratch3MusicBlocks.MIDI_NOTE_RANGE.min, Scratch3MusicBlocks.MIDI_NOTE_RANGE.max); let beats = Cast.toNumber(args.BEATS); beats = this._clampBeats(beats); // If the duration is 0, do not play the note. In Scratch 2.0, "play drum for 0 beats" plays the drum, // but "play note for 0 beats" is silent. if (beats === 0) return; const durationSec = this._beatsToSec(beats); this._playNote(util, note, durationSec); this._startStackTimer(util, durationSec); } else { this._checkStackTimer(util); } } _playNoteForPicker(noteNum, category) { if (category !== this.getInfo().name) return; const util = { runtime: this.runtime, target: this.runtime.getEditingTarget() }; this._playNote(util, noteNum, 0.25); } /** * Play a note using the current instrument for a duration in seconds. * This function actually plays the sound, and handles the timing of the sound, including the * "release" portion of the sound, which continues briefly after the block execution has finished. * @param {object} util - utility object provided by the runtime. * @param {number} note - the pitch of the note to play, interpreted as a MIDI note number. * @param {number} durationSec - the duration in seconds to play the note. * @private */ _playNote(util, note, durationSec) { if (util.runtime.audioEngine === null) return; if (util.target.sprite.soundBank === null) return; // If we're playing too many sounds, do not play the note. if (this._concurrencyCounter > Scratch3MusicBlocks.CONCURRENCY_LIMIT) { return; } // Determine which of the audio samples for this instrument to play const musicState = this._getMusicState(util.target); const inst = musicState.currentInstrument; const instrumentInfo = this.INSTRUMENT_INFO[inst]; const sampleArray = instrumentInfo.samples; const sampleIndex = this._selectSampleIndexForNote(note, sampleArray); // If the audio sample has not loaded yet, bail out if (typeof this._instrumentPlayerArrays[inst] === 'undefined') return; if (typeof this._instrumentPlayerArrays[inst][sampleIndex] === 'undefined') return; // Fetch the sound player to play the note. const engine = util.runtime.audioEngine; if (!this._instrumentPlayerNoteArrays[inst][note]) { this._instrumentPlayerNoteArrays[inst][note] = this._instrumentPlayerArrays[inst][sampleIndex].take(); } const player = this._instrumentPlayerNoteArrays[inst][note]; if (player.isPlaying && !player.isStarting) { // Take the internal player state and create a new player with it. // `.play` does this internally but then instructs the sound to // stop. player.take(); } // Set its pitch. const sampleNote = sampleArray[sampleIndex]; const notePitchInterval = this._ratioForPitchInterval(note - sampleNote); // Create gain nodes for this note's volume and release, and chain them // to the output. const context = engine.audioContext; const volumeGain = context.createGain(); volumeGain.gain.setValueAtTime(util.target.volume / 100, engine.currentTime); const releaseGain = context.createGain(); volumeGain.connect(releaseGain); releaseGain.connect(engine.getInputNode()); // Schedule the release of the note, ramping its gain down to zero, // and then stopping the sound. let releaseDuration = this.INSTRUMENT_INFO[inst].releaseTime; if (typeof releaseDuration === 'undefined') { releaseDuration = 0.01; } const releaseStart = context.currentTime + durationSec; const releaseEnd = releaseStart + releaseDuration; releaseGain.gain.setValueAtTime(1, releaseStart); releaseGain.gain.linearRampToValueAtTime(0.0001, releaseEnd); this._concurrencyCounter++; player.once('stop', () => { this._concurrencyCounter--; }); // Start playing the note player.play(); // Connect the player to the gain node. player.connect({ getInputNode() { return volumeGain; } }); // Set playback now after play creates the outputNode. player.outputNode.playbackRate.value = notePitchInterval; // Schedule playback to stop. player.outputNode.stop(releaseEnd); } /** * The samples array for each instrument is the set of pitches of the available audio samples. * This function selects the best one to use to play a given input note, and returns its index * in the samples array. * @param {number} note - the input note to select a sample for. * @param {number[]} samples - an array of the pitches of the available samples. * @return {index} the index of the selected sample in the samples array. * @private */ _selectSampleIndexForNote(note, samples) { // Step backwards through the array of samples, i.e. in descending pitch, in order to find // the sample that is the closest one below (or matching) the pitch of the input note. for (let i = samples.length - 1; i >= 0; i--) { if (note >= samples[i]) { return i; } } return 0; } /** * Calcuate the frequency ratio for a given musical interval. * @param {number} interval - the pitch interval to convert. * @return {number} a ratio corresponding to the input interval. * @private */ _ratioForPitchInterval(interval) { return Math.pow(2, interval / 12); } /** * Clamp a duration in beats to the allowed min and max duration. * @param {number} beats - a duration in beats. * @return {number} - the clamped duration. * @private */ _clampBeats(beats) { return MathUtil.clamp(beats, Scratch3MusicBlocks.BEAT_RANGE.min, Scratch3MusicBlocks.BEAT_RANGE.max); } /** * Convert a number of beats to a number of seconds, using the current tempo. * @param {number} beats - number of beats to convert to secs. * @return {number} seconds - number of seconds `beats` will last. * @private */ _beatsToSec(beats) { return 60 / this.getTempo() * beats; } /** * Check if the stack timer needs initialization. * @param {object} util - utility object provided by the runtime. * @return {boolean} - true if the stack timer needs to be initialized. * @private */ _stackTimerNeedsInit(util) { return !util.stackFrame.timer; } /** * Start the stack timer and the yield the thread if necessary. * @param {object} util - utility object provided by the runtime. * @param {number} duration - a duration in seconds to set the timer for. * @private */ _startStackTimer(util, duration) { util.stackFrame.timer = new Timer(); util.stackFrame.timer.start(); util.stackFrame.duration = duration; util.yield(); } /** * Check the stack timer, and if its time is not up yet, yield the thread. * @param {object} util - utility object provided by the runtime. * @private */ _checkStackTimer(util) { const timeElapsed = util.stackFrame.timer.timeElapsed(); if (timeElapsed < util.stackFrame.duration * 1000) { util.yield(); } } /** * Select an instrument for playing notes. * @param {object} args - the block arguments. * @param {object} util - utility object provided by the runtime. * @property {int} INSTRUMENT - the number of the instrument to select. */ setInstrument(args, util) { this._setInstrument(args.INSTRUMENT, util, false); } /** * Select an instrument for playing notes according to a mapping of MIDI codes to Scratch instrument numbers. * This block is implemented for compatibility with old Scratch projects that use the 'midiInstrument:' block. * @param {object} args - the block arguments. * @param {object} util - utility object provided by the runtime. * @property {int} INSTRUMENT - the MIDI number of the instrument to select. */ midiSetInstrument(args, util) { this._setInstrument(args.INSTRUMENT, util, true); } /** * Internal code to select an instrument for playing notes. If mapMidi is true, set the instrument according to * the MIDI to Scratch instrument mapping. * @param {number} instNum - the instrument number. * @param {object} util - utility object provided by the runtime. * @param {boolean} mapMidi - whether or not instNum is a MIDI instrument number. */ _setInstrument(instNum, util, mapMidi) { const musicState = this._getMusicState(util.target); instNum = Cast.toNumber(instNum); instNum = Math.round(instNum); instNum -= 1; // instruments are one-indexed if (mapMidi) { instNum = (this.MIDI_INSTRUMENTS[instNum] || 0) - 1; } instNum = MathUtil.wrapClamp(instNum, 0, this.INSTRUMENT_INFO.length - 1); musicState.currentInstrument = instNum; } /** * Set the current tempo to a new value. * @param {object} args - the block arguments. * @property {number} TEMPO - the tempo, in beats per minute. */ setTempo(args) { const tempo = Cast.toNumber(args.TEMPO); this._updateTempo(tempo); } /** * Change the current tempo by some amount. * @param {object} args - the block arguments. * @property {number} TEMPO - the amount to change the tempo, in beats per minute. */ changeTempo(args) { const change = Cast.toNumber(args.TEMPO); const tempo = change + this.getTempo(); this._updateTempo(tempo); } /** * Update the current tempo, clamping it to the min and max allowable range. * @param {number} tempo - the tempo to set, in beats per minute. * @private */ _updateTempo(tempo) { tempo = MathUtil.clamp(tempo, Scratch3MusicBlocks.TEMPO_RANGE.min, Scratch3MusicBlocks.TEMPO_RANGE.max); const stage = this.runtime.getTargetForStage(); if (stage) { stage.tempo = tempo; } } /** * Get the current tempo. * @return {number} - the current tempo, in beats per minute. */ getTempo() { const stage = this.runtime.getTargetForStage(); if (stage) { return stage.tempo; } return 60; } } module.exports = Scratch3MusicBlocks; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_music/manifest.js": /*!***************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_music/manifest.js ***! \***************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { module.exports = { 'drums/1-snare.mp3': __webpack_require__(/*! ./assets/drums/1-snare.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/1-snare.mp3"), 'drums/2-bass-drum.mp3': __webpack_require__(/*! ./assets/drums/2-bass-drum.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/2-bass-drum.mp3"), 'drums/3-side-stick.mp3': __webpack_require__(/*! ./assets/drums/3-side-stick.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/3-side-stick.mp3"), 'drums/4-crash-cymbal.mp3': __webpack_require__(/*! ./assets/drums/4-crash-cymbal.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/4-crash-cymbal.mp3"), 'drums/5-open-hi-hat.mp3': __webpack_require__(/*! ./assets/drums/5-open-hi-hat.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/5-open-hi-hat.mp3"), 'drums/6-closed-hi-hat.mp3': __webpack_require__(/*! ./assets/drums/6-closed-hi-hat.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/6-closed-hi-hat.mp3"), 'drums/7-tambourine.mp3': __webpack_require__(/*! ./assets/drums/7-tambourine.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/7-tambourine.mp3"), 'drums/8-hand-clap.mp3': __webpack_require__(/*! ./assets/drums/8-hand-clap.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/8-hand-clap.mp3"), 'drums/9-claves.mp3': __webpack_require__(/*! ./assets/drums/9-claves.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/9-claves.mp3"), 'drums/10-wood-block.mp3': __webpack_require__(/*! ./assets/drums/10-wood-block.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/10-wood-block.mp3"), 'drums/11-cowbell.mp3': __webpack_require__(/*! ./assets/drums/11-cowbell.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/11-cowbell.mp3"), 'drums/12-triangle.mp3': __webpack_require__(/*! ./assets/drums/12-triangle.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/12-triangle.mp3"), 'drums/13-bongo.mp3': __webpack_require__(/*! ./assets/drums/13-bongo.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/13-bongo.mp3"), 'drums/14-conga.mp3': __webpack_require__(/*! ./assets/drums/14-conga.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/14-conga.mp3"), 'drums/15-cabasa.mp3': __webpack_require__(/*! ./assets/drums/15-cabasa.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/15-cabasa.mp3"), 'drums/16-guiro.mp3': __webpack_require__(/*! ./assets/drums/16-guiro.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/16-guiro.mp3"), 'drums/17-vibraslap.mp3': __webpack_require__(/*! ./assets/drums/17-vibraslap.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/17-vibraslap.mp3"), 'drums/18-cuica.mp3': __webpack_require__(/*! ./assets/drums/18-cuica.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/drums/18-cuica.mp3"), 'instruments/1-piano/24.mp3': __webpack_require__(/*! ./assets/instruments/1-piano/24.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/24.mp3"), 'instruments/1-piano/36.mp3': __webpack_require__(/*! ./assets/instruments/1-piano/36.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/36.mp3"), 'instruments/1-piano/48.mp3': __webpack_require__(/*! ./assets/instruments/1-piano/48.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/48.mp3"), 'instruments/1-piano/60.mp3': __webpack_require__(/*! ./assets/instruments/1-piano/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/60.mp3"), 'instruments/1-piano/72.mp3': __webpack_require__(/*! ./assets/instruments/1-piano/72.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/72.mp3"), 'instruments/1-piano/84.mp3': __webpack_require__(/*! ./assets/instruments/1-piano/84.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/84.mp3"), 'instruments/1-piano/96.mp3': __webpack_require__(/*! ./assets/instruments/1-piano/96.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/96.mp3"), 'instruments/1-piano/108.mp3': __webpack_require__(/*! ./assets/instruments/1-piano/108.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/1-piano/108.mp3"), 'instruments/2-electric-piano/60.mp3': __webpack_require__(/*! ./assets/instruments/2-electric-piano/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/2-electric-piano/60.mp3"), 'instruments/3-organ/60.mp3': __webpack_require__(/*! ./assets/instruments/3-organ/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/3-organ/60.mp3"), 'instruments/4-guitar/60.mp3': __webpack_require__(/*! ./assets/instruments/4-guitar/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/4-guitar/60.mp3"), 'instruments/5-electric-guitar/60.mp3': __webpack_require__(/*! ./assets/instruments/5-electric-guitar/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/5-electric-guitar/60.mp3"), 'instruments/6-bass/36.mp3': __webpack_require__(/*! ./assets/instruments/6-bass/36.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/6-bass/36.mp3"), 'instruments/6-bass/48.mp3': __webpack_require__(/*! ./assets/instruments/6-bass/48.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/6-bass/48.mp3"), 'instruments/7-pizzicato/60.mp3': __webpack_require__(/*! ./assets/instruments/7-pizzicato/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/7-pizzicato/60.mp3"), 'instruments/8-cello/36.mp3': __webpack_require__(/*! ./assets/instruments/8-cello/36.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/8-cello/36.mp3"), 'instruments/8-cello/48.mp3': __webpack_require__(/*! ./assets/instruments/8-cello/48.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/8-cello/48.mp3"), 'instruments/8-cello/60.mp3': __webpack_require__(/*! ./assets/instruments/8-cello/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/8-cello/60.mp3"), 'instruments/9-trombone/36.mp3': __webpack_require__(/*! ./assets/instruments/9-trombone/36.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/9-trombone/36.mp3"), 'instruments/9-trombone/48.mp3': __webpack_require__(/*! ./assets/instruments/9-trombone/48.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/9-trombone/48.mp3"), 'instruments/9-trombone/60.mp3': __webpack_require__(/*! ./assets/instruments/9-trombone/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/9-trombone/60.mp3"), 'instruments/10-clarinet/48.mp3': __webpack_require__(/*! ./assets/instruments/10-clarinet/48.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/10-clarinet/48.mp3"), 'instruments/10-clarinet/60.mp3': __webpack_require__(/*! ./assets/instruments/10-clarinet/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/10-clarinet/60.mp3"), 'instruments/11-saxophone/36.mp3': __webpack_require__(/*! ./assets/instruments/11-saxophone/36.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/11-saxophone/36.mp3"), 'instruments/11-saxophone/60.mp3': __webpack_require__(/*! ./assets/instruments/11-saxophone/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/11-saxophone/60.mp3"), 'instruments/11-saxophone/84.mp3': __webpack_require__(/*! ./assets/instruments/11-saxophone/84.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/11-saxophone/84.mp3"), 'instruments/12-flute/60.mp3': __webpack_require__(/*! ./assets/instruments/12-flute/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/12-flute/60.mp3"), 'instruments/12-flute/72.mp3': __webpack_require__(/*! ./assets/instruments/12-flute/72.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/12-flute/72.mp3"), 'instruments/13-wooden-flute/60.mp3': __webpack_require__(/*! ./assets/instruments/13-wooden-flute/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/13-wooden-flute/60.mp3"), 'instruments/13-wooden-flute/72.mp3': __webpack_require__(/*! ./assets/instruments/13-wooden-flute/72.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/13-wooden-flute/72.mp3"), 'instruments/14-bassoon/36.mp3': __webpack_require__(/*! ./assets/instruments/14-bassoon/36.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/14-bassoon/36.mp3"), 'instruments/14-bassoon/48.mp3': __webpack_require__(/*! ./assets/instruments/14-bassoon/48.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/14-bassoon/48.mp3"), 'instruments/14-bassoon/60.mp3': __webpack_require__(/*! ./assets/instruments/14-bassoon/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/14-bassoon/60.mp3"), 'instruments/15-choir/48.mp3': __webpack_require__(/*! ./assets/instruments/15-choir/48.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/15-choir/48.mp3"), 'instruments/15-choir/60.mp3': __webpack_require__(/*! ./assets/instruments/15-choir/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/15-choir/60.mp3"), 'instruments/15-choir/72.mp3': __webpack_require__(/*! ./assets/instruments/15-choir/72.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/15-choir/72.mp3"), 'instruments/16-vibraphone/60.mp3': __webpack_require__(/*! ./assets/instruments/16-vibraphone/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/16-vibraphone/60.mp3"), 'instruments/16-vibraphone/72.mp3': __webpack_require__(/*! ./assets/instruments/16-vibraphone/72.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/16-vibraphone/72.mp3"), 'instruments/17-music-box/60.mp3': __webpack_require__(/*! ./assets/instruments/17-music-box/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/17-music-box/60.mp3"), 'instruments/18-steel-drum/60.mp3': __webpack_require__(/*! ./assets/instruments/18-steel-drum/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/18-steel-drum/60.mp3"), 'instruments/19-marimba/60.mp3': __webpack_require__(/*! ./assets/instruments/19-marimba/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/19-marimba/60.mp3"), 'instruments/20-synth-lead/60.mp3': __webpack_require__(/*! ./assets/instruments/20-synth-lead/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/20-synth-lead/60.mp3"), 'instruments/21-synth-pad/60.mp3': __webpack_require__(/*! ./assets/instruments/21-synth-pad/60.mp3 */ "./node_modules/scratch-vm/src/extensions/scratch3_music/assets/instruments/21-synth-pad/60.mp3") }; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_pen/index.js": /*!**********************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_pen/index.js ***! \**********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const ArgumentType = __webpack_require__(/*! ../../extension-support/argument-type */ "./node_modules/scratch-vm/src/extension-support/argument-type.js"); const BlockType = __webpack_require__(/*! ../../extension-support/block-type */ "./node_modules/scratch-vm/src/extension-support/block-type.js"); const TargetType = __webpack_require__(/*! ../../extension-support/target-type */ "./node_modules/scratch-vm/src/extension-support/target-type.js"); const Cast = __webpack_require__(/*! ../../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); const Clone = __webpack_require__(/*! ../../util/clone */ "./node_modules/scratch-vm/src/util/clone.js"); const Color = __webpack_require__(/*! ../../util/color */ "./node_modules/scratch-vm/src/util/color.js"); const formatMessage = __webpack_require__(/*! format-message */ "./node_modules/format-message/index.js"); const MathUtil = __webpack_require__(/*! ../../util/math-util */ "./node_modules/scratch-vm/src/util/math-util.js"); const RenderedTarget = __webpack_require__(/*! ../../sprites/rendered-target */ "./node_modules/scratch-vm/src/sprites/rendered-target.js"); const log = __webpack_require__(/*! ../../util/log */ "./node_modules/scratch-vm/src/util/log.js"); const StageLayering = __webpack_require__(/*! ../../engine/stage-layering */ "./node_modules/scratch-vm/src/engine/stage-layering.js"); /** * Icon svg to be displayed at the left edge of each extension block, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len const blockIconURI = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHZpZXdCb3g9IjAgMCA0MCA0MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+cGVuLWljb248L3RpdGxlPjxnIHN0cm9rZT0iIzU3NUU3NSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik04Ljc1MyAzNC42MDJsLTQuMjUgMS43OCAxLjc4My00LjIzN2MxLjIxOC0yLjg5MiAyLjkwNy01LjQyMyA1LjAzLTcuNTM4TDMxLjA2NiA0LjkzYy44NDYtLjg0MiAyLjY1LS40MSA0LjAzMi45NjcgMS4zOCAxLjM3NSAxLjgxNiAzLjE3My45NyA0LjAxNUwxNi4zMTggMjkuNTljLTIuMTIzIDIuMTE2LTQuNjY0IDMuOC03LjU2NSA1LjAxMiIgZmlsbD0iI0ZGRiIvPjxwYXRoIGQ9Ik0yOS40MSA2LjExcy00LjQ1LTIuMzc4LTguMjAyIDUuNzcyYy0xLjczNCAzLjc2Ni00LjM1IDEuNTQ2LTQuMzUgMS41NDYiLz48cGF0aCBkPSJNMzYuNDIgOC44MjVjMCAuNDYzLS4xNC44NzMtLjQzMiAxLjE2NGwtOS4zMzUgOS4zYy4yODItLjI5LjQxLS42NjguNDEtMS4xMiAwLS44NzQtLjUwNy0xLjk2My0xLjQwNi0yLjg2OC0xLjM2Mi0xLjM1OC0zLjE0Ny0xLjgtNC4wMDItLjk5TDMwLjk5IDUuMDFjLjg0NC0uODQgMi42NS0uNDEgNC4wMzUuOTYuODk4LjkwNCAxLjM5NiAxLjk4MiAxLjM5NiAyLjg1NU0xMC41MTUgMzMuNzc0Yy0uNTczLjMwMi0xLjE1Ny41Ny0xLjc2NC44M0w0LjUgMzYuMzgybDEuNzg2LTQuMjM1Yy4yNTgtLjYwNC41My0xLjE4Ni44MzMtMS43NTcuNjkuMTgzIDEuNDQ4LjYyNSAyLjEwOCAxLjI4Mi42Ni42NTggMS4xMDIgMS40MTIgMS4yODcgMi4xMDIiIGZpbGw9IiM0Qzk3RkYiLz48cGF0aCBkPSJNMzYuNDk4IDguNzQ4YzAgLjQ2NC0uMTQuODc0LS40MzMgMS4xNjVsLTE5Ljc0MiAxOS42OGMtMi4xMyAyLjExLTQuNjczIDMuNzkzLTcuNTcyIDUuMDFMNC41IDM2LjM4bC45NzQtMi4zMTYgMS45MjUtLjgwOGMyLjg5OC0xLjIxOCA1LjQ0LTIuOSA3LjU3LTUuMDFsMTkuNzQzLTE5LjY4Yy4yOTItLjI5Mi40MzItLjcwMi40MzItMS4xNjUgMC0uNjQ2LS4yNy0xLjQtLjc4LTIuMTIyLjI1LjE3Mi41LjM3Ny43MzcuNjE0Ljg5OC45MDUgMS4zOTYgMS45ODMgMS4zOTYgMi44NTYiIGZpbGw9IiM1NzVFNzUiIG9wYWNpdHk9Ii4xNSIvPjxwYXRoIGQ9Ik0xOC40NSAxMi44M2MwIC41LS40MDQuOTA1LS45MDQuOTA1cy0uOTA1LS40MDUtLjkwNS0uOTA0YzAtLjUuNDA3LS45MDMuOTA2LS45MDMuNSAwIC45MDQuNDA0LjkwNC45MDR6IiBmaWxsPSIjNTc1RTc1Ii8+PC9nPjwvc3ZnPg=='; /** * Enum for pen color parameter values. * @readonly * @enum {string} */ const ColorParam = { COLOR: 'color', SATURATION: 'saturation', BRIGHTNESS: 'brightness', TRANSPARENCY: 'transparency' }; /** * @typedef {object} PenState - the pen state associated with a particular target. * @property {Boolean} penDown - tracks whether the pen should draw for this target. * @property {number} color - the current color (hue) of the pen. * @property {PenAttributes} penAttributes - cached pen attributes for the renderer. This is the authoritative value for * diameter but not for pen color. */ /** * Host for the Pen-related blocks in Scratch 3.0 * @param {Runtime} runtime - the runtime instantiating this block package. * @constructor */ class Scratch3PenBlocks { constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; /** * The ID of the renderer Drawable corresponding to the pen layer. * @type {int} * @private */ this._penDrawableId = -1; /** * The ID of the renderer Skin corresponding to the pen layer. * @type {int} * @private */ this._penSkinId = -1; this._onTargetCreated = this._onTargetCreated.bind(this); this._onTargetMoved = this._onTargetMoved.bind(this); runtime.on('targetWasCreated', this._onTargetCreated); runtime.on('RUNTIME_DISPOSED', this.clear.bind(this)); } /** * The default pen state, to be used when a target has no existing pen state. * @type {PenState} */ static get DEFAULT_PEN_STATE() { return { penDown: false, color: 66.66, saturation: 100, brightness: 100, transparency: 0, _shade: 50, // Used only for legacy `change shade by` blocks penAttributes: { color4f: [0, 0, 1, 1], diameter: 1 } }; } /** * The minimum and maximum allowed pen size. * The maximum is twice the diagonal of the stage, so that even an * off-stage sprite can fill it. * @type {{min: number, max: number}} */ static get PEN_SIZE_RANGE() { return { min: 1, max: 1200 }; } /** * The key to load & store a target's pen-related state. * @type {string} */ static get STATE_KEY() { // tw: We've hardcoded this value in various places for slight performance gains // Make sure to update those if this changes. return 'Scratch.pen'; } /** * Clamp a pen size value to the range allowed by the pen. * @param {number} requestedSize - the requested pen size. * @returns {number} the clamped size. * @private */ _clampPenSize(requestedSize) { if (this.runtime.renderer && this.runtime.renderer.useHighQualityRender || !this.runtime.runtimeOptions.miscLimits) { return Math.max(0, requestedSize); } return MathUtil.clamp(requestedSize, Scratch3PenBlocks.PEN_SIZE_RANGE.min, Scratch3PenBlocks.PEN_SIZE_RANGE.max); } /** * Retrieve the ID of the renderer "Skin" corresponding to the pen layer. If * the pen Skin doesn't yet exist, create it. * @returns {int} the Skin ID of the pen layer, or -1 on failure. * @private */ _getPenLayerID() { if (this._penSkinId < 0 && this.runtime.renderer) { this._penSkinId = this.runtime.renderer.createPenSkin(); this._penDrawableId = this.runtime.renderer.createDrawable(StageLayering.PEN_LAYER); this.runtime.renderer.updateDrawableSkinId(this._penDrawableId, this._penSkinId); } return this._penSkinId; } /** * @param {Target} target - collect pen state for this target. Probably, but not necessarily, a RenderedTarget. * @returns {PenState} the mutable pen state associated with that target. This will be created if necessary. * @private */ _getPenState(target) { let penState = target._customState['Scratch.pen']; if (!penState) { penState = Clone.simple(Scratch3PenBlocks.DEFAULT_PEN_STATE); target.setCustomState(Scratch3PenBlocks.STATE_KEY, penState); } return penState; } /** * When a pen-using Target is cloned, clone the pen state. * @param {Target} newTarget - the newly created target. * @param {Target} [sourceTarget] - the target used as a source for the new clone, if any. * @listens Runtime#event:targetWasCreated * @private */ _onTargetCreated(newTarget, sourceTarget) { if (sourceTarget) { const penState = sourceTarget.getCustomState(Scratch3PenBlocks.STATE_KEY); if (penState) { newTarget.setCustomState(Scratch3PenBlocks.STATE_KEY, Clone.simple(penState)); if (penState.penDown) { newTarget.onTargetMoved = this._onTargetMoved; } } } } /** * Handle a target which has moved. This only fires when the pen is down. * @param {RenderedTarget} target - the target which has moved. * @param {number} oldX - the previous X position. * @param {number} oldY - the previous Y position. * @param {boolean} isForce - whether the movement was forced. * @private */ _onTargetMoved(target, oldX, oldY, isForce) { // Only move the pen if the movement isn't forced (ie. dragged). if (!isForce) { const penSkinId = this._getPenLayerID(); if (penSkinId >= 0) { const penState = this._getPenState(target); this.runtime.renderer.penLine(penSkinId, penState.penAttributes, oldX, oldY, target.x, target.y); this.runtime.requestRedraw(); } } } /** * Wrap a color input into the range (0,100). * @param {number} value - the value to be wrapped. * @returns {number} the wrapped value. * @private */ _wrapColor(value) { return MathUtil.wrapClamp(value, 0, 100); } /** * Initialize color parameters menu with localized strings * @returns {array} of the localized text and values for each menu element * @private */ _initColorParam() { return [{ text: formatMessage({ id: 'pen.colorMenu.color', default: 'color', description: 'label for color element in color picker for pen extension' }), value: ColorParam.COLOR }, { text: formatMessage({ id: 'pen.colorMenu.saturation', default: 'saturation', description: 'label for saturation element in color picker for pen extension' }), value: ColorParam.SATURATION }, { text: formatMessage({ id: 'pen.colorMenu.brightness', default: 'brightness', description: 'label for brightness element in color picker for pen extension' }), value: ColorParam.BRIGHTNESS }, { text: formatMessage({ id: 'pen.colorMenu.transparency', default: 'transparency', description: 'label for transparency element in color picker for pen extension' }), value: ColorParam.TRANSPARENCY }]; } /** * Clamp a pen color parameter to the range (0,100). * @param {number} value - the value to be clamped. * @returns {number} the clamped value. * @private */ _clampColorParam(value) { return MathUtil.clamp(value, 0, 100); } /** * Convert an alpha value to a pen transparency value. * Alpha ranges from 0 to 1, where 0 is transparent and 1 is opaque. * Transparency ranges from 0 to 100, where 0 is opaque and 100 is transparent. * @param {number} alpha - the input alpha value. * @returns {number} the transparency value. * @private */ _alphaToTransparency(alpha) { return (1.0 - alpha) * 100.0; } /** * Convert a pen transparency value to an alpha value. * Alpha ranges from 0 to 1, where 0 is transparent and 1 is opaque. * Transparency ranges from 0 to 100, where 0 is opaque and 100 is transparent. * @param {number} transparency - the input transparency value. * @returns {number} the alpha value. * @private */ _transparencyToAlpha(transparency) { return 1.0 - transparency / 100.0; } /** * @returns {object} metadata for this extension and its blocks. */ getInfo() { return { id: 'pen', name: formatMessage({ id: 'pen.categoryName', default: 'Pen', description: 'Label for the pen extension category' }), blockIconURI: blockIconURI, blocks: [{ opcode: 'clear', blockType: BlockType.COMMAND, text: formatMessage({ id: 'pen.clear', default: 'erase all', description: 'erase all pen trails and stamps' }) }, { opcode: 'stamp', blockType: BlockType.COMMAND, text: formatMessage({ id: 'pen.stamp', default: 'stamp', description: 'render current costume on the background' }), filter: [TargetType.SPRITE] }, { opcode: 'penDown', blockType: BlockType.COMMAND, text: formatMessage({ id: 'pen.penDown', default: 'pen down', description: 'start leaving a trail when the sprite moves' }), filter: [TargetType.SPRITE] }, { opcode: 'penUp', blockType: BlockType.COMMAND, text: formatMessage({ id: 'pen.penUp', default: 'pen up', description: 'stop leaving a trail behind the sprite' }), filter: [TargetType.SPRITE] }, { opcode: 'setPenColorToColor', blockType: BlockType.COMMAND, text: formatMessage({ id: 'pen.setColor', default: 'set pen color to [COLOR]', description: 'set the pen color to a particular (RGB) value' }), arguments: { COLOR: { type: ArgumentType.COLOR } }, filter: [TargetType.SPRITE] }, { opcode: 'changePenColorParamBy', blockType: BlockType.COMMAND, text: formatMessage({ id: 'pen.changeColorParam', default: 'change pen [COLOR_PARAM] by [VALUE]', description: 'change the state of a pen color parameter' }), arguments: { COLOR_PARAM: { type: ArgumentType.STRING, menu: 'colorParam', defaultValue: ColorParam.COLOR }, VALUE: { type: ArgumentType.NUMBER, defaultValue: 10 } }, filter: [TargetType.SPRITE] }, { opcode: 'setPenColorParamTo', blockType: BlockType.COMMAND, text: formatMessage({ id: 'pen.setColorParam', default: 'set pen [COLOR_PARAM] to [VALUE]', description: 'set the state for a pen color parameter e.g. saturation' }), arguments: { COLOR_PARAM: { type: ArgumentType.STRING, menu: 'colorParam', defaultValue: ColorParam.COLOR }, VALUE: { type: ArgumentType.NUMBER, defaultValue: 50 } }, filter: [TargetType.SPRITE] }, { opcode: 'changePenSizeBy', blockType: BlockType.COMMAND, text: formatMessage({ id: 'pen.changeSize', default: 'change pen size by [SIZE]', description: 'change the diameter of the trail left by a sprite' }), arguments: { SIZE: { type: ArgumentType.NUMBER, defaultValue: 1 } }, filter: [TargetType.SPRITE] }, { opcode: 'setPenSizeTo', blockType: BlockType.COMMAND, text: formatMessage({ id: 'pen.setSize', default: 'set pen size to [SIZE]', description: 'set the diameter of a trail left by a sprite' }), arguments: { SIZE: { type: ArgumentType.NUMBER, defaultValue: 1 } }, filter: [TargetType.SPRITE] }, /* Legacy blocks, should not be shown in flyout */ { opcode: 'setPenShadeToNumber', blockType: BlockType.COMMAND, text: formatMessage({ id: 'pen.setShade', default: 'set pen shade to [SHADE]', description: 'legacy pen blocks - set pen shade' }), arguments: { SHADE: { type: ArgumentType.NUMBER, defaultValue: 1 } }, hideFromPalette: true }, { opcode: 'changePenShadeBy', blockType: BlockType.COMMAND, text: formatMessage({ id: 'pen.changeShade', default: 'change pen shade by [SHADE]', description: 'legacy pen blocks - change pen shade' }), arguments: { SHADE: { type: ArgumentType.NUMBER, defaultValue: 1 } }, hideFromPalette: true }, { opcode: 'setPenHueToNumber', blockType: BlockType.COMMAND, text: formatMessage({ id: 'pen.setHue', default: 'set pen color to [HUE]', description: 'legacy pen blocks - set pen color to number' }), arguments: { HUE: { type: ArgumentType.NUMBER, defaultValue: 1 } }, hideFromPalette: true }, { opcode: 'changePenHueBy', blockType: BlockType.COMMAND, text: formatMessage({ id: 'pen.changeHue', default: 'change pen color by [HUE]', description: 'legacy pen blocks - change pen color' }), arguments: { HUE: { type: ArgumentType.NUMBER, defaultValue: 1 } }, hideFromPalette: true }], menus: { colorParam: { acceptReporters: true, items: this._initColorParam() } } }; } /** * The pen "clear" block clears the pen layer's contents. */ clear() { // used by compiler const penSkinId = this._getPenLayerID(); if (penSkinId >= 0) { this.runtime.renderer.penClear(penSkinId); this.runtime.requestRedraw(); } } /** * The pen "stamp" block stamps the current drawable's image onto the pen layer. * @param {object} args - the block arguments. * @param {object} util - utility object provided by the runtime. */ stamp(args, util) { this._stamp(util.target); } _stamp(target) { // used by compiler const penSkinId = this._getPenLayerID(); if (penSkinId >= 0) { this.runtime.renderer.penStamp(penSkinId, target.drawableID); this.runtime.requestRedraw(); } } /** * The pen "pen down" block causes the target to leave pen trails on future motion. * @param {object} args - the block arguments. * @param {object} util - utility object provided by the runtime. */ penDown(args, util) { this._penDown(util.target); } _penDown(target) { // used by compiler const penState = this._getPenState(target); if (!penState.penDown) { penState.penDown = true; target.onTargetMoved = this._onTargetMoved; } const penSkinId = this._getPenLayerID(); if (penSkinId >= 0) { this.runtime.renderer.penPoint(penSkinId, penState.penAttributes, target.x, target.y); this.runtime.requestRedraw(); } } /** * The pen "pen up" block stops the target from leaving pen trails. * @param {object} args - the block arguments. * @param {object} util - utility object provided by the runtime. */ penUp(args, util) { this._penUp(util.target); } _penUp(target) { // used by compiler const penState = this._getPenState(target); if (penState.penDown) { penState.penDown = false; target.onTargetMoved = null; } } /** * The pen "set pen color to {color}" block sets the pen to a particular RGB color. * The transparency is reset to 0. * @param {object} args - the block arguments. * @property {int} COLOR - the color to set, expressed as a 24-bit RGB value (0xRRGGBB). * @param {object} util - utility object provided by the runtime. */ setPenColorToColor(args, util) { this._setPenColorToColor(args.COLOR, util.target); } _setPenColorToColor(color, target) { // used by compiler const penState = this._getPenState(target); const rgb = Cast.toRgbColorObject(color); const hsv = Color.rgbToHsv(rgb); penState.color = hsv.h / 360 * 100; penState.saturation = hsv.s * 100; penState.brightness = hsv.v * 100; if (rgb.hasOwnProperty('a')) { penState.transparency = 100 * (1 - rgb.a / 255.0); } else { penState.transparency = 0; } // Set the legacy "shade" value the same way scratch 2 did. penState._shade = penState.brightness / 2; this._updatePenColor(penState); } /** * Update the cached color from the color, saturation, brightness and transparency values * in the provided PenState object. * @param {PenState} penState - the pen state to update. * @private */ _updatePenColor(penState) { const rgb = Color.hsvToRgb({ h: penState.color * 360 / 100, s: penState.saturation / 100, v: penState.brightness / 100 }); penState.penAttributes.color4f[0] = rgb.r / 255.0; penState.penAttributes.color4f[1] = rgb.g / 255.0; penState.penAttributes.color4f[2] = rgb.b / 255.0; penState.penAttributes.color4f[3] = this._transparencyToAlpha(penState.transparency); } /** * Set or change a single color parameter on the pen state, and update the pen color. * @param {ColorParam} param - the name of the color parameter to set or change. * @param {number} value - the value to set or change the param by. * @param {PenState} penState - the pen state to update. * @param {boolean} change - if true change param by value, if false set param to value. * @private */ _setOrChangeColorParam(param, value, penState, change) { // used by compiler switch (param) { case ColorParam.COLOR: penState.color = this._wrapColor(value + (change ? penState.color : 0)); break; case ColorParam.SATURATION: penState.saturation = this._clampColorParam(value + (change ? penState.saturation : 0)); break; case ColorParam.BRIGHTNESS: penState.brightness = this._clampColorParam(value + (change ? penState.brightness : 0)); break; case ColorParam.TRANSPARENCY: penState.transparency = this._clampColorParam(value + (change ? penState.transparency : 0)); break; default: log.warn("Tried to set or change unknown color parameter: ".concat(param)); } this._updatePenColor(penState); } /** * The "change pen {ColorParam} by {number}" block changes one of the pen's color parameters * by a given amound. * @param {object} args - the block arguments. * @property {ColorParam} COLOR_PARAM - the name of the selected color parameter. * @property {number} VALUE - the amount to change the selected parameter by. * @param {object} util - utility object provided by the runtime. */ changePenColorParamBy(args, util) { const penState = this._getPenState(util.target); this._setOrChangeColorParam(args.COLOR_PARAM, Cast.toNumber(args.VALUE), penState, true); } /** * The "set pen {ColorParam} to {number}" block sets one of the pen's color parameters * to a given amound. * @param {object} args - the block arguments. * @property {ColorParam} COLOR_PARAM - the name of the selected color parameter. * @property {number} VALUE - the amount to set the selected parameter to. * @param {object} util - utility object provided by the runtime. */ setPenColorParamTo(args, util) { const penState = this._getPenState(util.target); this._setOrChangeColorParam(args.COLOR_PARAM, Cast.toNumber(args.VALUE), penState, false); } /** * The pen "change pen size by {number}" block changes the pen size by the given amount. * @param {object} args - the block arguments. * @property {number} SIZE - the amount of desired size change. * @param {object} util - utility object provided by the runtime. */ changePenSizeBy(args, util) { this._changePenSizeBy(Cast.toNumber(args.SIZE), util.target); } _changePenSizeBy(size, target) { // used by compiler const penAttributes = this._getPenState(target).penAttributes; penAttributes.diameter = this._clampPenSize(penAttributes.diameter + size); } /** * The pen "set pen size to {number}" block sets the pen size to the given amount. * @param {object} args - the block arguments. * @property {number} SIZE - the amount of desired size change. * @param {object} util - utility object provided by the runtime. */ setPenSizeTo(args, util) { this._setPenSizeTo(Cast.toNumber(args.SIZE), util.target); } _setPenSizeTo(size, target) { // used by compiler const penAttributes = this._getPenState(target).penAttributes; penAttributes.diameter = this._clampPenSize(size); } /* LEGACY OPCODES */ /** * Scratch 2 "hue" param is equivelant to twice the new "color" param. * @param {object} args - the block arguments. * @property {number} HUE - the amount to set the hue to. * @param {object} util - utility object provided by the runtime. */ setPenHueToNumber(args, util) { this._setPenHueToNumber(Cast.toNumber(args.HUE), util.target); } _setPenHueToNumber(hueValue, target) { const penState = this._getPenState(target); const colorValue = hueValue / 2; this._setOrChangeColorParam(ColorParam.COLOR, colorValue, penState, false); this._setOrChangeColorParam(ColorParam.TRANSPARENCY, 0, penState, false); this._legacyUpdatePenColor(penState); } /** * Scratch 2 "hue" param is equivelant to twice the new "color" param. * @param {object} args - the block arguments. * @property {number} HUE - the amount of desired hue change. * @param {object} util - utility object provided by the runtime. */ changePenHueBy(args, util) { this._changePenHueBy(Cast.toNumber(args.HUE), util.target); } _changePenHueBy(hueChange, target) { // used by compiler const penState = this._getPenState(target); const colorChange = hueChange / 2; this._setOrChangeColorParam(ColorParam.COLOR, colorChange, penState, true); this._legacyUpdatePenColor(penState); } /** * Use legacy "set shade" code to calculate RGB value for shade, * then convert back to HSV and store those components. * It is important to also track the given shade in penState._shade * because it cannot be accurately backed out of the new HSV later. * @param {object} args - the block arguments. * @property {number} SHADE - the amount to set the shade to. * @param {object} util - utility object provided by the runtime. */ setPenShadeToNumber(args, util) { this._setPenShadeToNumber(Cast.toNumber(args.SHADE), util.target); } _setPenShadeToNumber(shade, target) { const penState = this._getPenState(target); let newShade = Cast.toNumber(shade); // Wrap clamp the new shade value the way scratch 2 did. newShade = newShade % 200; if (newShade < 0) newShade += 200; // And store the shade that was used to compute this new color for later use. penState._shade = newShade; this._legacyUpdatePenColor(penState); } /** * Because "shade" cannot be backed out of hsv consistently, use the previously * stored penState._shade to make the shade change. * @param {object} args - the block arguments. * @property {number} SHADE - the amount of desired shade change. * @param {object} util - utility object provided by the runtime. */ changePenShadeBy(args, util) { this._changePenShadeBy(args.SHADE, util.target); } _changePenShadeBy(shade, target) { const penState = this._getPenState(target); const shadeChange = Cast.toNumber(shade); this._setPenShadeToNumber(penState._shade + shadeChange, target); } /** * Update the pen state's color from its hue & shade values, Scratch 2.0 style. * @param {object} penState - update the HSV & RGB values in this pen state from its hue & shade values. * @private */ _legacyUpdatePenColor(penState) { // Create the new color in RGB using the scratch 2 "shade" model let rgb = Color.hsvToRgb({ h: penState.color * 360 / 100, s: 1, v: 1 }); const shade = penState._shade > 100 ? 200 - penState._shade : penState._shade; if (shade < 50) { rgb = Color.mixRgb(Color.RGB_BLACK, rgb, (10 + shade) / 60); } else { rgb = Color.mixRgb(rgb, Color.RGB_WHITE, (shade - 50) / 60); } // Update the pen state according to new color const hsv = Color.rgbToHsv(rgb); penState.color = 100 * hsv.h / 360; penState.saturation = 100 * hsv.s; penState.brightness = 100 * hsv.v; this._updatePenColor(penState); } } module.exports = Scratch3PenBlocks; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_text2speech/index.js": /*!******************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_text2speech/index.js ***! \******************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const formatMessage = __webpack_require__(/*! format-message */ "./node_modules/format-message/index.js"); const languageNames = __webpack_require__(/*! scratch-translate-extension-languages */ "./node_modules/scratch-translate-extension-languages/languages.json"); const ArgumentType = __webpack_require__(/*! ../../extension-support/argument-type */ "./node_modules/scratch-vm/src/extension-support/argument-type.js"); const BlockType = __webpack_require__(/*! ../../extension-support/block-type */ "./node_modules/scratch-vm/src/extension-support/block-type.js"); const Cast = __webpack_require__(/*! ../../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); const MathUtil = __webpack_require__(/*! ../../util/math-util */ "./node_modules/scratch-vm/src/util/math-util.js"); const Clone = __webpack_require__(/*! ../../util/clone */ "./node_modules/scratch-vm/src/util/clone.js"); const log = __webpack_require__(/*! ../../util/log */ "./node_modules/scratch-vm/src/util/log.js"); const fetchWithTimeout = __webpack_require__(/*! ../../util/fetch-with-timeout */ "./node_modules/scratch-vm/src/util/fetch-with-timeout.js"); /** * Icon svg to be displayed in the blocks category menu, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len const menuIconURI = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjBweCIgaGVpZ2h0PSIyMHB4IiB2aWV3Qm94PSIwIDAgMjAgMjAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjIgKDY3MTQ1KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5FeHRlbnNpb25zL1NvZnR3YXJlL1RleHQtdG8tU3BlZWNoLU1lbnU8L3RpdGxlPgogICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+CiAgICA8ZyBpZD0iRXh0ZW5zaW9ucy9Tb2Z0d2FyZS9UZXh0LXRvLVNwZWVjaC1NZW51IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgICAgICA8ZyBpZD0idGV4dDJzcGVlY2giIHRyYW5zZm9ybT0idHJhbnNsYXRlKDIuMDAwMDAwLCAyLjAwMDAwMCkiIGZpbGwtcnVsZT0ibm9uemVybyI+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik01Ljc1LDguODM0NjcxNzMgQzUuNzUsOC4zMjY5NjM0NCA1LjAwMzAwNzI3LDguMDQyMjEzNzEgNC41NTYyODAxMiw4LjQ0NDE0OTk5IEwzLjIwNjI4MDEyLDkuNTI1MzU3MDIgQzIuNjk2NzMzNzgsOS45MzM0NDk2OCAyLjAzNzQ4Njc1LDEwLjE2NTg3ODggMS4zNSwxMC4xNjU4Nzg4IEwxLjE1LDEwLjE2NTg3ODggQzAuNjMyNTk2MTY1LDEwLjE2NTg3ODggMC4yNSwxMC41MTA2MDAyIDAuMjUsMTAuOTUyMDM1NSBMMC4yNSwxMy4wNjkzOTkzIEMwLjI1LDEzLjUxMDgzNDYgMC42MzI1OTYxNjUsMTMuODU1NTU2IDEuMTUsMTMuODU1NTU2IEwxLjM1LDEzLjg1NTU1NiBDMi4wNzg3Nzg0MSwxMy44NTU1NTYgMi43MjY4NjE2MSwxNC4wNjY3NjM2IDMuMjU5ODYwNDksMTQuNDk5IEw0LjU1OTIwMTQ3LDE1LjU3OTY2MDggQzUuMDEzMDkyNzYsMTUuOTU0NTM5NiA1Ljc1LDE1LjY3MzYzNDQgNS43NSwxNS4xNDE3MTI4IEw1Ljc1LDguODM0NjcxNzMgWiIgaWQ9InNwZWFrZXIiIHN0cm9rZS1vcGFjaXR5PSIwLjE1IiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS13aWR0aD0iMC41IiBmaWxsPSIjNEQ0RDREIj48L3BhdGg+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMC43MDQ4MzEzLDggQzkuNzkwNjc0NjgsOS4xMzExNDg0NyA4LjMwNjYxODQsOS43MTQyODU3MSA3LjgzMzMzMzMzLDkuNzE0Mjg1NzEgQzcuODMzMzMzMzMsOS43MTQyODU3MSA3LjUsOS43MTQyODU3MSA3LjUsOS4zODA5NTIzOCBDNy41LDkuMDg1MjI2ODQgOC4wNjIyMDE2OCw4LjkwMTk0MTY0IDguMTg5MDYwNjcsNy41Njc1NDA1OCBDNi44ODk5Njk5MSw2LjkwNjc5MDA1IDYsNS41NTczMjY4MyA2LDQgQzYsMS43OTA4NjEgNy43OTA4NjEsNC4wNTgxMjI1MWUtMTYgMTAsMCBMMTIsMCBDMTQuMjA5MTM5LC00LjA1ODEyMjUxZS0xNiAxNiwxLjc5MDg2MSAxNiw0IEMxNiw2LjIwOTEzOSAxNC4yMDkxMzksOCAxMiw4IEwxMC43MDQ4MzEzLDggWiIgaWQ9InNwZWVjaCIgZmlsbD0iIzBFQkQ4QyI+PC9wYXRoPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+'; /** * Icon svg to be displayed at the left edge of each extension block, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len const blockIconURI = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNDBweCIgaGVpZ2h0PSI0MHB4IiB2aWV3Qm94PSIwIDAgNDAgNDAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjIgKDY3MTQ1KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5FeHRlbnNpb25zL1NvZnR3YXJlL1RleHQtdG8tU3BlZWNoLUJsb2NrPC90aXRsZT4KICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPgogICAgPGcgaWQ9IkV4dGVuc2lvbnMvU29mdHdhcmUvVGV4dC10by1TcGVlY2gtQmxvY2siIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZS1vcGFjaXR5PSIwLjE1Ij4KICAgICAgICA8ZyBpZD0idGV4dDJzcGVlY2giIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQuMDAwMDAwLCA0LjAwMDAwMCkiIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlPSIjMDAwMDAwIj4KICAgICAgICAgICAgPHBhdGggZD0iTTExLjUsMTcuNjY5MzQzNSBDMTEuNSwxNi42NTM5MjY5IDEwLjAwNjAxNDUsMTYuMDg0NDI3NCA5LjExMjU2MDI0LDE2Ljg4ODMgTDYuNDEyNTYwMjQsMTkuMDUwNzE0IEM1LjM5MzQ2NzU1LDE5Ljg2Njg5OTQgNC4wNzQ5NzM1MSwyMC4zMzE3NTc1IDIuNywyMC4zMzE3NTc1IEwyLjMsMjAuMzMxNzU3NSBDMS4yNjUxOTIzMywyMC4zMzE3NTc1IDAuNSwyMS4wMjEyMDAzIDAuNSwyMS45MDQwNzEgTDAuNSwyNi4xMzg3OTg2IEMwLjUsMjcuMDIxNjY5MyAxLjI2NTE5MjMzLDI3LjcxMTExMiAyLjMsMjcuNzExMTEyIEwyLjcsMjcuNzExMTEyIEM0LjE1NzU1NjgyLDI3LjcxMTExMiA1LjQ1MzcyMzIyLDI4LjEzMzUyNzEgNi41MTk3MjA5OCwyOC45OTggTDkuMTE4NDAyOTMsMzEuMTU5MzIxNiBDMTAuMDI2MTg1NSwzMS45MDkwNzkzIDExLjUsMzEuMzQ3MjY4OSAxMS41LDMwLjI4MzQyNTUgTDExLjUsMTcuNjY5MzQzNSBaIiBpZD0ic3BlYWtlciIgZmlsbD0iIzRENEQ0RCI+PC9wYXRoPgogICAgICAgICAgICA8cGF0aCBkPSJNMjEuNjQzNjA2NiwxNi41IEMxOS45NzcwMDk5LDE4LjQzNzAyMzQgMTcuMTA1MDI3NSwxOS45Mjg1NzE0IDE1LjY2NjY2NjcsMTkuOTI4NTcxNCBDMTUuNTEyNjM5NywxOS45Mjg1NzE0IDE1LjMxNjYyOTIsMTkuODk1OTAzIDE1LjEwOTcyNjUsMTkuNzkyNDUxNyBDMTQuNzM3NjAzOSwxOS42MDYzOTA0IDE0LjUsMTkuMjQ5OTg0NiAxNC41LDE4Ljc2MTkwNDggQzE0LjUsMTguNjU2ODA0MSAxNC41MTcwNTU1LDE4LjU1NDUwNzYgMTQuNTQ5NDQ2NywxOC40NTQwODQ0IEMxNC42MjU3NTQ1LDE4LjIxNzUwNjMgMTUuMTczNTcyMSwxNy40Njc1MzEgMTUuMjc3MjA3MSwxNy4yODA5ODgxIEMxNS41NDYzNTI2LDE2Ljc5NjUyNjEgMTUuNzM5MDI1LDE2LjIwNjM1NjEgMTUuODQzMjg5MSwxNS40MTYwMDM0IEMxMy4xODk3MDA1LDEzLjkyNjgzNjkgMTEuNSwxMS4xMTM5NjY4IDExLjUsOCBDMTEuNSwzLjMwNTU3OTYzIDE1LjMwNTU3OTYsLTAuNSAyMCwtMC41IEwyNCwtMC41IEMyOC42OTQ0MjA0LC0wLjUgMzIuNSwzLjMwNTU3OTYzIDMyLjUsOCBDMzIuNSwxMi42OTQ0MjA0IDI4LjY5NDQyMDQsMTYuNSAyNCwxNi41IEwyMS42NDM2MDY2LDE2LjUgWiIgaWQ9InNwZWVjaCIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+'; /** * The url of the synthesis server. * @type {string} */ const SERVER_HOST = 'https://synthesis-service.scratch.mit.edu'; /** * How long to wait in ms before timing out requests to synthesis server. * @type {int} */ const SERVER_TIMEOUT = 10000; // 10 seconds /** * Volume for playback of speech sounds, as a percentage. * @type {number} */ const SPEECH_VOLUME = 250; /** * An id for one of the voices. */ const ALTO_ID = 'ALTO'; /** * An id for one of the voices. */ const TENOR_ID = 'TENOR'; /** * An id for one of the voices. */ const SQUEAK_ID = 'SQUEAK'; /** * An id for one of the voices. */ const GIANT_ID = 'GIANT'; /** * An id for one of the voices. */ const KITTEN_ID = 'KITTEN'; /** * Playback rate for the tenor voice, for cases where we have only a female gender voice. */ const FEMALE_TENOR_RATE = 0.89; // -2 semitones /** * Playback rate for the giant voice, for cases where we have only a female gender voice. */ const FEMALE_GIANT_RATE = 0.79; // -4 semitones /** * Language ids. The value for each language id is a valid Scratch locale. */ const ARABIC_ID = 'ar'; const CHINESE_ID = 'zh-cn'; const DANISH_ID = 'da'; const DUTCH_ID = 'nl'; const ENGLISH_ID = 'en'; const FRENCH_ID = 'fr'; const GERMAN_ID = 'de'; const HINDI_ID = 'hi'; const ICELANDIC_ID = 'is'; const ITALIAN_ID = 'it'; const JAPANESE_ID = 'ja'; const KOREAN_ID = 'ko'; const NORWEGIAN_ID = 'nb'; const POLISH_ID = 'pl'; const PORTUGUESE_BR_ID = 'pt-br'; const PORTUGUESE_ID = 'pt'; const ROMANIAN_ID = 'ro'; const RUSSIAN_ID = 'ru'; const SPANISH_ID = 'es'; const SPANISH_419_ID = 'es-419'; const SWEDISH_ID = 'sv'; const TURKISH_ID = 'tr'; const WELSH_ID = 'cy'; /** * Class for the text2speech blocks. * @constructor */ class Scratch3Text2SpeechBlocks { constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; /** * Map of soundPlayers by sound id. * @type {Map} */ this._soundPlayers = new Map(); this._stopAllSpeech = this._stopAllSpeech.bind(this); if (this.runtime) { this.runtime.on('PROJECT_STOP_ALL', this._stopAllSpeech); } this._onTargetCreated = this._onTargetCreated.bind(this); if (this.runtime) { runtime.on('targetWasCreated', this._onTargetCreated); } /** * A list of all Scratch locales that are supported by the extension. * @type {Array} */ this._supportedLocales = this._getSupportedLocales(); } /** * An object with info for each voice. */ get VOICE_INFO() { return { [ALTO_ID]: { name: formatMessage({ id: 'text2speech.alto', default: 'alto', description: 'Name for a voice with ambiguous gender.' }), gender: 'female', playbackRate: 1 }, [TENOR_ID]: { name: formatMessage({ id: 'text2speech.tenor', default: 'tenor', description: 'Name for a voice with ambiguous gender.' }), gender: 'male', playbackRate: 1 }, [SQUEAK_ID]: { name: formatMessage({ id: 'text2speech.squeak', default: 'squeak', description: 'Name for a funny voice with a high pitch.' }), gender: 'female', playbackRate: 1.19 // +3 semitones }, [GIANT_ID]: { name: formatMessage({ id: 'text2speech.giant', default: 'giant', description: 'Name for a funny voice with a low pitch.' }), gender: 'male', playbackRate: 0.84 // -3 semitones }, [KITTEN_ID]: { name: formatMessage({ id: 'text2speech.kitten', default: 'kitten', description: 'A baby cat.' }), gender: 'female', playbackRate: 1.41 // +6 semitones } }; } /** * An object with information for each language. * * A note on the different sets of locales referred to in this extension: * * SCRATCH LOCALE * Set by the editor, and used to store the language state in the project. * Listed in l10n: https://github.com/LLK/scratch-l10n/blob/master/src/supported-locales.js * SUPPORTED LOCALE * A Scratch locale that has a corresponding extension locale. * EXTENSION LOCALE * A locale corresponding to one of the available spoken languages * in the extension. There can be multiple supported locales for a single * extension locale. For example, for both written versions of chinese, * zh-cn and zh-tw, we use a single spoken language (Mandarin). So there * are two supported locales, with a single extension locale. * SPEECH SYNTH LOCALE * A different locale code system, used by our speech synthesis service. * Each extension locale has a speech synth locale. */ get LANGUAGE_INFO() { return { [ARABIC_ID]: { name: 'Arabic', locales: ['ar'], speechSynthLocale: 'arb', singleGender: true }, [CHINESE_ID]: { name: 'Chinese (Mandarin)', locales: ['zh-cn', 'zh-tw'], speechSynthLocale: 'cmn-CN', singleGender: true }, [DANISH_ID]: { name: 'Danish', locales: ['da'], speechSynthLocale: 'da-DK' }, [DUTCH_ID]: { name: 'Dutch', locales: ['nl'], speechSynthLocale: 'nl-NL' }, [ENGLISH_ID]: { name: 'English', locales: ['en'], speechSynthLocale: 'en-US' }, [FRENCH_ID]: { name: 'French', locales: ['fr'], speechSynthLocale: 'fr-FR' }, [GERMAN_ID]: { name: 'German', locales: ['de'], speechSynthLocale: 'de-DE' }, [HINDI_ID]: { name: 'Hindi', locales: ['hi'], speechSynthLocale: 'hi-IN', singleGender: true }, [ICELANDIC_ID]: { name: 'Icelandic', locales: ['is'], speechSynthLocale: 'is-IS' }, [ITALIAN_ID]: { name: 'Italian', locales: ['it'], speechSynthLocale: 'it-IT' }, [JAPANESE_ID]: { name: 'Japanese', locales: ['ja', 'ja-hira'], speechSynthLocale: 'ja-JP' }, [KOREAN_ID]: { name: 'Korean', locales: ['ko'], speechSynthLocale: 'ko-KR', singleGender: true }, [NORWEGIAN_ID]: { name: 'Norwegian', locales: ['nb', 'nn'], speechSynthLocale: 'nb-NO', singleGender: true }, [POLISH_ID]: { name: 'Polish', locales: ['pl'], speechSynthLocale: 'pl-PL' }, [PORTUGUESE_BR_ID]: { name: 'Portuguese (Brazilian)', locales: ['pt-br'], speechSynthLocale: 'pt-BR' }, [PORTUGUESE_ID]: { name: 'Portuguese (European)', locales: ['pt'], speechSynthLocale: 'pt-PT' }, [ROMANIAN_ID]: { name: 'Romanian', locales: ['ro'], speechSynthLocale: 'ro-RO', singleGender: true }, [RUSSIAN_ID]: { name: 'Russian', locales: ['ru'], speechSynthLocale: 'ru-RU' }, [SPANISH_ID]: { name: 'Spanish (European)', locales: ['es'], speechSynthLocale: 'es-ES' }, [SPANISH_419_ID]: { name: 'Spanish (Latin American)', locales: ['es-419'], speechSynthLocale: 'es-US' }, [SWEDISH_ID]: { name: 'Swedish', locales: ['sv'], speechSynthLocale: 'sv-SE', singleGender: true }, [TURKISH_ID]: { name: 'Turkish', locales: ['tr'], speechSynthLocale: 'tr-TR', singleGender: true }, [WELSH_ID]: { name: 'Welsh', locales: ['cy'], speechSynthLocale: 'cy-GB', singleGender: true } }; } /** * The key to load & store a target's text2speech state. * @return {string} The key. */ static get STATE_KEY() { return 'Scratch.text2speech'; } /** * The default state, to be used when a target has no existing state. * @type {Text2SpeechState} */ static get DEFAULT_TEXT2SPEECH_STATE() { return { voiceId: ALTO_ID }; } /** * A default language to use for speech synthesis. * @type {string} */ get DEFAULT_LANGUAGE() { return ENGLISH_ID; } /** * @param {Target} target - collect state for this target. * @returns {Text2SpeechState} the mutable state associated with that target. This will be created if necessary. * @private */ _getState(target) { let state = target.getCustomState(Scratch3Text2SpeechBlocks.STATE_KEY); if (!state) { state = Clone.simple(Scratch3Text2SpeechBlocks.DEFAULT_TEXT2SPEECH_STATE); target.setCustomState(Scratch3Text2SpeechBlocks.STATE_KEY, state); } return state; } /** * When a Target is cloned, clone the state. * @param {Target} newTarget - the newly created target. * @param {Target} [sourceTarget] - the target used as a source for the new clone, if any. * @listens Runtime#event:targetWasCreated * @private */ _onTargetCreated(newTarget, sourceTarget) { if (sourceTarget) { const state = sourceTarget.getCustomState(Scratch3Text2SpeechBlocks.STATE_KEY); if (state) { newTarget.setCustomState(Scratch3Text2SpeechBlocks.STATE_KEY, Clone.simple(state)); } } } /** * @returns {object} metadata for this extension and its blocks. */ getInfo() { // Only localize the default input to the "speak" block if we are in a // supported language. let defaultTextToSpeak = 'hello'; if (this.isSupportedLanguage(this.getEditorLanguage())) { defaultTextToSpeak = formatMessage({ id: 'text2speech.defaultTextToSpeak', default: 'hello', description: 'hello: the default text to speak' }); } return { id: 'text2speech', name: formatMessage({ id: 'text2speech.categoryName', default: 'Text to Speech', description: 'Name of the Text to Speech extension.' }), blockIconURI: blockIconURI, menuIconURI: menuIconURI, blocks: [{ opcode: 'speakAndWait', text: formatMessage({ id: 'text2speech.speakAndWaitBlock', default: 'speak [WORDS]', description: 'Speak some words.' }), blockType: BlockType.COMMAND, arguments: { WORDS: { type: ArgumentType.STRING, defaultValue: defaultTextToSpeak } } }, { opcode: 'setVoice', text: formatMessage({ id: 'text2speech.setVoiceBlock', default: 'set voice to [VOICE]', description: 'Set the voice for speech synthesis.' }), blockType: BlockType.COMMAND, arguments: { VOICE: { type: ArgumentType.STRING, menu: 'voices', defaultValue: ALTO_ID } } }, { opcode: 'setLanguage', text: formatMessage({ id: 'text2speech.setLanguageBlock', default: 'set language to [LANGUAGE]', description: 'Set the language for speech synthesis.' }), blockType: BlockType.COMMAND, arguments: { LANGUAGE: { type: ArgumentType.STRING, menu: 'languages', defaultValue: this.getCurrentLanguage() } } }], menus: { voices: { acceptReporters: true, items: this.getVoiceMenu() }, languages: { acceptReporters: true, items: this.getLanguageMenu() } } }; } /** * Get the language code currently set in the editor, or fall back to the * browser locale. * @return {string} a Scratch locale code. */ getEditorLanguage() { const locale = formatMessage.setup().locale || navigator.language || navigator.userLanguage || this.DEFAULT_LANGUAGE; return locale.toLowerCase(); } /** * Get the language code currently set for the extension. * @returns {string} a Scratch locale code. */ getCurrentLanguage() { const stage = this.runtime.getTargetForStage(); if (!stage) return this.DEFAULT_LANGUAGE; // If no language has been set, set it to the editor locale (or default). if (!stage.textToSpeechLanguage) { this.setCurrentLanguage(this.getEditorLanguage()); } return stage.textToSpeechLanguage; } /** * Set the language code for the extension. * It is stored in the stage so it can be saved and loaded with the project. * @param {string} locale a locale code. */ setCurrentLanguage(locale) { const stage = this.runtime.getTargetForStage(); if (!stage) return; if (this.isSupportedLanguage(locale)) { stage.textToSpeechLanguage = this._getExtensionLocaleForSupportedLocale(locale); } // Support language names dropped onto the menu via reporter block // such as a variable containing a language name (in any language), // or the translate extension's language reporter. const localeForDroppedName = languageNames.nameMap[locale.toLowerCase()]; if (localeForDroppedName && this.isSupportedLanguage(localeForDroppedName)) { stage.textToSpeechLanguage = this._getExtensionLocaleForSupportedLocale(localeForDroppedName); } // If the language is null, set it to the default language. // This can occur e.g. if the extension was loaded with the editor // set to a language that is not in the list. if (!stage.textToSpeechLanguage) { stage.textToSpeechLanguage = this.DEFAULT_LANGUAGE; } } /** * Get the extension locale for a supported locale, or null. * @param {string} locale a locale code. * @returns {?string} a locale supported by the extension. */ _getExtensionLocaleForSupportedLocale(locale) { for (const lang in this.LANGUAGE_INFO) { if (this.LANGUAGE_INFO[lang].locales.includes(locale)) { return lang; } } log.error("cannot find extension locale for locale ".concat(locale)); } /** * Get the locale code used by the speech synthesis server corresponding to * the current language code set for the extension. * @returns {string} a speech synthesis locale. */ _getSpeechSynthLocale() { let speechSynthLocale = this.LANGUAGE_INFO[this.DEFAULT_LANGUAGE].speechSynthLocale; if (this.LANGUAGE_INFO[this.getCurrentLanguage()]) { speechSynthLocale = this.LANGUAGE_INFO[this.getCurrentLanguage()].speechSynthLocale; } return speechSynthLocale; } /** * Get an array of the locales supported by this extension. * @returns {Array} An array of locale strings. */ _getSupportedLocales() { return Object.keys(this.LANGUAGE_INFO).reduce((acc, lang) => acc.concat(this.LANGUAGE_INFO[lang].locales), []); } /** * Check if a Scratch language code is in the list of supported languages for the * speech synthesis service. * @param {string} languageCode the language code to check. * @returns {boolean} true if the language code is supported. */ isSupportedLanguage(languageCode) { return this._supportedLocales.includes(languageCode); } /** * Get the menu of voices for the "set voice" block. * @return {array} the text and value for each menu item. */ getVoiceMenu() { return Object.keys(this.VOICE_INFO).map(voiceId => ({ text: this.VOICE_INFO[voiceId].name, value: voiceId })); } /** * Get the localized menu of languages for the "set language" block. * For each language: * if there is a custom translated spoken language name, use that; * otherwise use the translation in the languageNames menuMap; * otherwise fall back to the untranslated name in LANGUAGE_INFO. * @return {array} the text and value for each menu item. */ getLanguageMenu() { const editorLanguage = this.getEditorLanguage(); // Get the array of localized language names const localizedNameMap = {}; let nameArray = languageNames.menuMap[editorLanguage]; if (nameArray) { // Also get any localized names of spoken languages let spokenNameArray = []; if (languageNames.spokenLanguages) { spokenNameArray = languageNames.spokenLanguages[editorLanguage]; nameArray = nameArray.concat(spokenNameArray); } // Create a map of language code to localized name // The localized spoken language names have been concatenated onto // the end of the name array, so the result of the forEach below is // when there is both a written language name (e.g. 'Chinese // (simplified)') and a spoken language name (e.g. 'Chinese // (Mandarin)', we always use the spoken version. nameArray.forEach(lang => { localizedNameMap[lang.code] = lang.name; }); } return Object.keys(this.LANGUAGE_INFO).map(key => { let name = this.LANGUAGE_INFO[key].name; const localizedName = localizedNameMap[key]; if (localizedName) { name = localizedName; } // Uppercase the first character of the name name = name.charAt(0).toUpperCase() + name.slice(1); return { text: name, value: key }; }); } /** * Set the voice for speech synthesis for this sprite. * @param {object} args Block arguments * @param {object} util Utility object provided by the runtime. */ setVoice(args, util) { const state = this._getState(util.target); let voice = args.VOICE; // If the arg is a dropped number, treat it as a voice index let voiceNum = parseInt(voice, 10); if (!isNaN(voiceNum)) { voiceNum -= 1; // Treat dropped args as one-indexed voiceNum = MathUtil.wrapClamp(voiceNum, 0, Object.keys(this.VOICE_INFO).length - 1); voice = Object.keys(this.VOICE_INFO)[voiceNum]; } // Only set the voice if the arg is a valid voice id. if (Object.keys(this.VOICE_INFO).includes(voice)) { state.voiceId = voice; } } /** * Set the language for speech synthesis. * @param {object} args Block arguments */ setLanguage(args) { this.setCurrentLanguage(args.LANGUAGE); } /** * Stop all currently playing speech sounds. */ _stopAllSpeech() { this._soundPlayers.forEach(player => { player.stop(); }); } /** * Convert the provided text into a sound file and then play the file. * @param {object} args Block arguments * @param {object} util Utility object provided by the runtime. * @return {Promise} A promise that resolves after playing the sound */ speakAndWait(args, util) { // Cast input to string let words = Cast.toString(args.WORDS); let locale = this._getSpeechSynthLocale(); const state = this._getState(util.target); let gender = this.VOICE_INFO[state.voiceId].gender; let playbackRate = this.VOICE_INFO[state.voiceId].playbackRate; // Special case for voices where the synthesis service only provides a // single gender voice. In that case, always request the female voice, // and set special playback rates for the tenor and giant voices. if (this.LANGUAGE_INFO[this.getCurrentLanguage()].singleGender) { gender = 'female'; if (state.voiceId === TENOR_ID) { playbackRate = FEMALE_TENOR_RATE; } if (state.voiceId === GIANT_ID) { playbackRate = FEMALE_GIANT_RATE; } } if (state.voiceId === KITTEN_ID) { words = words.replace(/\S+/g, 'meow'); locale = this.LANGUAGE_INFO[this.DEFAULT_LANGUAGE].speechSynthLocale; } // Build up URL let path = "".concat(SERVER_HOST, "/synth"); path += "?locale=".concat(locale); path += "&gender=".concat(gender); path += "&text=".concat(encodeURIComponent(words.substring(0, 128))); // Perform HTTP request to get audio file return fetchWithTimeout(path, {}, SERVER_TIMEOUT).then(res => { if (res.status !== 200) { throw new Error("HTTP ".concat(res.status, " error reaching translation service")); } return res.arrayBuffer(); }).then(buffer => { // Play the sound const sound = { data: { buffer } }; return this.runtime.audioEngine.decodeSoundPlayer(sound); }).then(soundPlayer => { this._soundPlayers.set(soundPlayer.id, soundPlayer); soundPlayer.setPlaybackRate(playbackRate); // Increase the volume const engine = this.runtime.audioEngine; const chain = engine.createEffectChain(); chain.set('volume', SPEECH_VOLUME); soundPlayer.connect(chain); soundPlayer.play(); return new Promise(resolve => { soundPlayer.on('stop', () => { this._soundPlayers.delete(soundPlayer.id); resolve(); }); }); }).catch(err => { log.warn(err); }); } } module.exports = Scratch3Text2SpeechBlocks; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_translate/index.js": /*!****************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_translate/index.js ***! \****************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const ArgumentType = __webpack_require__(/*! ../../extension-support/argument-type */ "./node_modules/scratch-vm/src/extension-support/argument-type.js"); const BlockType = __webpack_require__(/*! ../../extension-support/block-type */ "./node_modules/scratch-vm/src/extension-support/block-type.js"); const Cast = __webpack_require__(/*! ../../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); const log = __webpack_require__(/*! ../../util/log */ "./node_modules/scratch-vm/src/util/log.js"); const fetchWithTimeout = __webpack_require__(/*! ../../util/fetch-with-timeout */ "./node_modules/scratch-vm/src/util/fetch-with-timeout.js"); const languageNames = __webpack_require__(/*! scratch-translate-extension-languages */ "./node_modules/scratch-translate-extension-languages/languages.json"); const formatMessage = __webpack_require__(/*! format-message */ "./node_modules/format-message/index.js"); /** * Icon svg to be displayed in the blocks category menu, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len const menuIconURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAACXBIWXMAABYlAAAWJQFJUiTwAAAGAklEQVRYhe1YbUxTVxh+rh02o0KtkOEgKA4U4yeRWCdgxDoxCnH6h22iqSz76aasZlnijzkTBlvS4TJ/LGaJsmiyESe4hAVJvMJGxwQhLKECcRWkpWNZERs6Ctb2Lm97C/fe3n6Jyfzhk5y09z3nPPe57znnPe85DMdxeJ6x6LlW90LgM8BLchR1dXUZeXl5b3Ect+ppXsEwzHBfX98PVVVVY0GbmjW2AdgpaFYP4JxTZ+iLyCVdJFeuXNmdn59fn56enrFkyRIsWhSfk30+H1wuF+x2+1hPT4++oqLiJi/wEoA8AJslXSqdOsOlmARWV1dnlpeXd2ZnZ2fEK0xOqMViGWtoaNh++vRpa9CuZo1ZAJokQlc5dYYROR6RCq1WW56WlhZV3H0H8O9sZIHEQVzEKbTzQooBPBCYz4TlET4oFIosGtZoOHUN+Ph61GYgLuIU2tSscSmAYwAeCcx6NWs8o2aNxVKOkEUi9R55qv428Ng7b3viA/6eAs7dmrctVgD6bYBKGZ6LB4mrk7F/whcmokApfh8BWu6G2mc8ADsktuWmAbtzozGiLUJdu9QQVSC98JUkYNgBfPsboH4Z+GhPoK62FZiaAU7sCrTZmB5VHM3BPjVrrARwUVL1B4CD0vYxLVV68YFNQIICcLrn7SROtTjwEbGIE4iksFIpEVfs1BkeSdvGFUsObAz8Gm8CNTcC/49q42EIEbkLwKfhxCGWIRZC/zrQ/ifgcAWMK5YB+zc8nUBeZFuUORmfQIp/PsHGM/04YMta5oPT6cTs7Cw8Ho+oj9vtzmloaCgPZQtApVI96ejo6K2trR3lOM4nrRftJCzLfq3T6Y7LCfvuNtDL7wepfKgkTz6ZdeHdzePYlq30xz2lUintHhH0UbQ12my2+oKCguMcx7mE7aOHmWHgsxvzzzQP3ysMxMfzt2bxKmNHyZblSE5OjktYEImJidBoNFCr1frOzs5khmHe4Thubp8SCVQoFBwNUUJCwpyNwsfyZGBDOvB2fuCZQAH56KYJKJUpTy1OCOJYvXr1ocbGxjIAPwarRKvYZrNdn5iYEHV8LRW4cBj4oHheXBDT09PPRFwQxKXRaIQpmVjgkSNHfrFardcmJydjIqSMRehtOfzjmMTZmm/8hf5HAnF5vV7RVicSyHGcR6vVHh4YGPjKYrFMkTelq5JAH0B1MzMzUT+iu6cfdwfv+wv9jxchgZomaEFBwcmcnJxVY2NjXQqFQlQ/Pj6O/v7+s2az+U2Hw9Ec7X3tHXfm/v/c2hG3wLCruLm5+VBGRoY2mJGQJ0nc4ODgqZKSkjqKWSzL7olEPjJqx4PRv5CaqvE/OxyTflvWitj3xbBbnUql2kRxjYTRcA4MDHR1d3frguJiIW//NeC9/SVF2LplvcgWK8J6sKWl5UuVSrXO4/HYHj58+FNZWVkLx3HT8Rz0u3vN/t8Ho3aRaH3FgYULrKmpodT8jeBzvDcQ3T1m/5D6RXX0zNmn3TP+uq356xcmkE/NTwLoc+oMTXGpA3CnN7Bi99Hw5s8PL4mlulgFys5BXlwbn4I3qlnjsXgFBr22f+8OrFub7S/79u4Q1cWCEA8KxAmPhRfVrBFy51cK1nJnj+/rvwix0eqVswu5pJDzoPTMKhSZJzQolUoLZSLPCsRFnEI6OYE7I7xPdGYoKiq6YLVaByllWiiIg7iIM5rAYBouBB2yq5w6g+iATWGnqampZGhoqItiJSUP4YrcR9CQUh31JQ7iIk5hm7AXmPxdip5/dNIUCnduYBgm8fLly9tzc3NLwzlSqVTuW7NmzVphQkubwL179+xdXV3HKisrTVJxiJKwnuGHVM2XNjVrPCh3h8IT3+SLLKqrq+tKS0uvrly5UksJKvjsJSkpKd3r9TrkxCGSBxHwIoWXc7zAIOiIOOLUGULOsNHAMIzSZDJ9npmZeSIlJcWfTdPQm0ym8zqd7n257hGPnXxYyePv8py8mVb40ji1+UGZUmFh4Yetra1bzGbzteHh4SlKQNxu961wff7XS3Sau/w0c4VLQF7c8i8IAP4DcHKth/4Ur7MAAAAASUVORK5CYII='; /** * Icon svg to be displayed at the left edge of each extension block, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len const blockIconURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAACXBIWXMAABYlAAAWJQFJUiTwAAAN+UlEQVR4Ae1ce2xT1xn/Tkhq4hqHJKRLDAlQGI+GUfFc14HaLmxuGd0ab93GgK6Vmm01y9BUsaU0RfyRFTakaRHq3So6jVapWEUxa9dRuU8x6IAGCoO6wa1KXiSQOE9jkjivO/2u7yWOuff6XvvekFb5SUdx7ON7v/vz9zrnO+cwnudpAokjZYK75DBBYJKYIDBJTBCYJCYITBJfOgIZYzbGWA5jLJ8xNm/z5s334a/4P1omYyzNsPt9WdIYxhiUId/j8azPz89fY7VaF6ampjqi+4TD4Qvd3d0f7t+/fx/HcTVE1M7z/EBS99VDoCikTWzWMdTgYSLqIaIQGs/zwzKyOaqrq1+aOnVqUUZGBqWnp5PFYqG0tDQaHh6mvr4+GhwcpFAoJLSenp4P9+7dW8Zx3Fme5zsTFSxVa0eovtPpnL1ly5YfzJgxw2WxWBYketNEAO25dOmSp7Ky8iBjrFbmoW12u70oOzubMjMzR32QkpJCVqtVeG2322lgYIACgcDK0tLS1+6+++4yxpiH5/krCQkGDYzXiCi3qqrKXVNTE7x48SLf0dHB9/X18WMF3Av3xL0hA2SBTNFyE9E8v9/PX758WbNUuCa+4/F4ymKvp7XF1UDGWK7H43m0sLBwZ05Ozg2/7lgApoiGe3d2dk5ZsWLFcx6Px84Y2xelOcHW1taXiOiRcDgsaJ2gljab0GDKscD1Jk2ahHd3ejwePOtenufb9TySKoEw26qqKhfIy83NFdT/ZiP6oauqqoKMsf2iObeuXr26vKKiwpOVlTXFbrfb8/LyFubk5KyBu1H68aVnGh4e3uZ2u08yxo7pCixKqgrX4XQ6l8JkoOrjDZAJskFGyBolt0UMcGhgJ19yP2rm3dDQwJ85c+akXlNWI9B++PDh38PvjFdANsgIWVUfksheUVHxfZDY3d0t+zT9/f2CP3S73feJWYZFC4FqJmxDtJ06daphRnuiluhrDqJbLcZcD7JBRiJ6Dj5Qrg9jDHfLhlm3tbUdslgsj8i5IvhI+MpNmzaVLlq0yCN+9wMiCvA8H1KSQY1AK3yHFP6ThfcTouePEaVNItrzI6LbpiR/TcgmplOyQmLE4XQ6C3fv3v0y+iEQIbggjZELKiB2+vTpxXl5ecUIRD6fr/nQoUNuxtjbPM/3yN1DLREWPsNNjUBNC9HgMFEKI2q5asglo2VTeo7sioqKP6anpwtBZObMmZSfny9LHokRG5+jn8PhoFtuucVRXFzMQdmVZPiyTyakIblGBqE3/QKZIBLDQafTmavUT/NIRA3XwkSlB4jaFD3FCPqHiJ5+Xb3PNBvRnoeN85UYyiUCmDHg9XoVn8wQDTxRR9RxjQjxLl4DgfH64Fq4pgEY6OjoONTe3q6bRPTH9zBmFsfgsjBEA4vmE/kuE30eiPzfN0B0WYyJGelEWQpx6FJXhNC0FKIcG9Fk0TUVZEWuaQBad+zYUbF79+6FjY2NC+DfpBGKGkBeY2MjBYPBC2VlZU9g1sZUAoFf3zvyGia9/u8RbRrmiSofvrG/1IeEaEn0/E+NkmQEmLVhjPmIaAMisRYSo8nbunXrBq/X6+N5PqzU35QgAt8177bI655+ovPNN/Z50xeJyIyIlswwQ4oI8PAgAWSAFJCjZM56ySMzo/DP7iJKTSEaGibi/jP6M2jfwbNEQzzRpBSin68yS4oItJCYCHlkJoEYcWSKvu9KkOjwxyOf7T9F1DsQ0b6CTGOS6niQIxEJNSVBHhnpA+Xwm28RPfOvSAL9t+NEy2cShcJEr5+P+EcQ+PT9ZkowGiBF8olIsMPhcBFmrnt7e4Voi4Chhzwym0BoYWFexAcODBGVvUbU3RshbxIjWrdobLQvGhKJXq+3xO12z1q3bt2aN9544x2O45A4Neshj8wmENjmJHr8ZaJQ/0iizcRk+fFvmn13eYgk1TLGWjiOwxQWKY1148H0oRwiMohiUYky8Oz3zL5zfIA0qSV6DdM18NWPiF4+FXnNogh84h9EW9cQ3TV7pC+ceVTVTNPooa5OGLLMYkgmE0fcqp8STCPwYhvRn94jauqKBBHJbOED4Q8xAtn1FtH8rxA9WUSUNthJiQy5Zs2aRX6/35usvBqqfrJQrAujmu/3+/3z5s3TJQgCxsEzRP9riuSAUsBYXhCJysCWVyP+EHkgiA0Hr9D9Xw3S/QuJJlvShIlSca4vASr0A5MG0Piuri68vnr69OmyjRs3aip1GqaByPNePRuZCMDwTSIuPY1oy32jTfWFDUQvniB67RzRta4rtDwvSN8tJBrnVT9ZGEIgpupf+C/RgGh90CpMEKwtJFq/XH5aCiOVb0zvpH+fipD3Baj6yUKNQIEOqLcWU4IPx9ANGue6k+iBQvX5PPi6lHD7dc0bD+RJgCxDQ0O0bNmyXU6n8wRjrFsxsKhUshznzp2r0VrSbAny/OcB7eU7VMdQBfuiV/3U8sAQohIcqxZgRHH7NO2/MlIVEitr4xVRVT+bkoiqBCKkIyp1dia8eEkRiHokVtbGK+JV/VQJhM17vd5ahPRAIICZCkMfU8r3xipVSQQaqn7qURjRB0u/ENIRleBYb0aaEQ+Btk4qfXLnqF7bn/oF3bFgjun3jjsWRh7kcrn2VVdXb25pablaW1uLXOl6xWo84LD36A1SHDl6akwk05QHgkTkQwjpsQsstSa/V65cGeUGMIbFMMwIyJFVfdpHj2zopVut6YbcQwmaZ2Ngzl6v9+zatWv/sHjx4u9UVlYKAzMUoOMB5HV1dV09cODAQ/NFOJ1OpxEPAKJ6evtueB/vnTrtM+IWqtA1nYXAwvM81GgAi3CUFi5KQKBobm4WyDt48OCm8vLy93me/xQNSmjEAxw5NqJ91vTJQpNQ/dE4I5AikwxWjuPWZGVlFWM9shLgI+vr6zHDcoHjuAdF8gwN5dd6eulUFEkrlhUKTQI+Q4AxE4lMqOasWrXqafg9uRREquiDvKamppe2bdv2kz179pwwmjyS8X3Lly4SWjSqT38s/2WDkMhkggUBJHbsCuIQndH6+/ubjxw58ju32/0eXKCeCUo9iDbfadMyr2sfzFjyi4ffOkZrnatNoi8xAoX1JjabrRhDnehZZBDn9/v3uFyuV+ItTEwWdQ3NVN9w+fpVViwdMV0QeeTYaeF1W1un0HdWgcNoEQQkYsJd27dvfxa+7dKlS9TQ0NBcV1d36OTJk5sLCwtXuVwujuf5WjPJIxnzvWf18uuvY834TZk80Sjo1kBxdPLp4sWLizBnKr4NewnqLQkmg1gCy575s+LVkOo8UWKOHAlV5cSAgGmadnG/WWCsyZPL/ZSAvmaNTHRroLho2xFdlGaMXRSDxZiQGJvf3bHgdtl+n1y4OOo70WZuFHQRCPKwaHvXrl1/sVqtK7EsYs6cOdsee+yxd8vLy3+Lir/ZJCKvi879Zhbk0fanfinb91dP7hSCCEXlhDnTjJ0M0WzCEnlYZ5eZmbly7ty5woLs2bNnYzxchPfxuaihpiE2r7tnlbJWRUdmMikn1ERgNHl2u33UIkUM5fA/3h8LEpHXRWPFskWKfWNNNva7RkDLZkNF8iTgf7yPFaDoh9VPZpnzvVEaZ7VOVjVJ5H4/fOjbRoswGnG2SIG8pSgu1dXV8UNDQ6pFGHyOfugv7mFT3C5FRHNRVBrLbbN6AdkgI2RNZK+cLvIkyJCYonB9XVW/mwHIBhkhayJVuWxEWyWzVYJkzjabbcGOHTvKUbBT6Kqr6nczANkgo9o2BzVWbEhVMGWllbzrF01JIXwPU16IMwrdTK36JQuxbHEVMiZEoNPpFKaaE62axSPd7KpfMoAskAmyQUa12STFKOz1egODg4PN9fX1Dqxb0TJ1LwG/HuYEg8Hgu5i9Ueo3Hqt+kB3k+Xy+p8QVWqrmoZbGtGOrJ3YrNjc3O6StonhAOTKx4h21D0xvYTYa6+0wOlHb5UMjBat9WMiDtShdXV1TvkjL21TPjcEpQJiB5jhOWM28ZMkSV0FBQTG2gsoBJU/MQp8/f/5tt9v9gZ5F20Yeq4LJXlhNPEjaRjELLEWz1eaYNR57AlWwYTs88iJsj5cDFgxhWz2218fbhq90ToN4zgF+obk4ykRvk7b2azn+JGabf754b9m0S3ceqPCAuTiYAQc0KAGCR53tIgklHQKh6RyCZFr0+QhNTU1x81f0OX78uMe0c2Ni0I7jknDiTzAYxNEiN3SA6VgsFmGV57lz50oDgcA7fr9f2ErQ0dFxlTH2ERE1mVUnwVwlY+z9lpaWB0tKSv4aDocXwOUo+VOkW6FQqJjjOI94gpG+FfsJmFk2TvqB6iudgCGZBzJ5aCsaRif4ztGjR19M9NfWKadl3bp1d+J+uG9bW5uiNra2tkojjpm675OgcLkSiXqGYjBvcWw5z2wC+RGf6uA4bqPP52v67LPPZImMGvPqliuhNdKxqUdvb+8UrJFRW6VAN2Epm+gmmhlj/ySiDzwez4/nz59f2tnZ6ZCOhEJqhvQFlUa1nFUJCS8ylxYcud3umpKSkl2hUGilJFRqaipNnjz5+hEjyLOwoa+7u1tKrk2t2MnIKmygYYzhBI5XqqqqHpgzZ84au93+dRwqgRQGlUaxzqMLSR/AKJ4Gme12uxeuX7/+0YyMjJWxORxGND09PTWNjY3vuFyu/UTUaFYQ0SizRcwOpIU0Q2JVUf8Pa6C/AZGZYuqSL+VkYh6H/3OQS46F7xvLNnGSeZKYOMU3SUwQmCQmCEwSEwQmiQkCkwER/R+aET3lwEIlXgAAAABJRU5ErkJggg=='; /** * The url of the translate server. * @type {string} */ const serverURL = 'https://trampoline.turbowarp.org/translate/'; /** * How long to wait in ms before timing out requests to translate server. * @type {int} */ const serverTimeoutMs = 10000; // 10 seconds (chosen arbitrarily). /** * Class for the translate block in Scratch 3.0. * @constructor */ class Scratch3TranslateBlocks { constructor() { /** * Language code of the viewer, based on their locale. * @type {string} * @private */ this._viewerLanguageCode = this.getViewerLanguageCode(); /** * List of supported language name and language code pairs, for use in the block menu. * Filled in by getInfo so it is updated when the interface language changes. * @type {Array.>} * @private */ this._supportedLanguages = []; /** * A randomly selected language code, for use as the default value in the language menu. * Properly filled in getInfo so it is updated when the interface languages changes. * @type {string} * @private */ this._randomLanguageCode = 'en'; /** * The result from the most recent translation. * @type {string} * @private */ this._translateResult = ''; /** * The language of the text most recently translated. * @type {string} * @private */ this._lastLangTranslated = ''; /** * The text most recently translated. * @type {string} * @private */ this._lastTextTranslated = ''; } /** * The key to load & store a target's translate state. * @return {string} The key. */ static get STATE_KEY() { return 'Scratch.translate'; } /** * @returns {object} metadata for this extension and its blocks. */ getInfo() { this._supportedLanguages = this._getSupportedLanguages(this.getViewerLanguageCode()); this._randomLanguageCode = this._supportedLanguages[Math.floor(Math.random() * this._supportedLanguages.length)].value; return { id: 'translate', name: formatMessage({ id: 'translate.categoryName', default: 'Translate', description: 'Name of extension that adds translate blocks' }), blockIconURI: blockIconURI, menuIconURI: menuIconURI, blocks: [{ opcode: 'getTranslate', text: formatMessage({ id: 'translate.translateBlock', default: 'translate [WORDS] to [LANGUAGE]', description: 'translate some text to a different language' }), blockType: BlockType.REPORTER, arguments: { WORDS: { type: ArgumentType.STRING, defaultValue: formatMessage({ id: 'translate.defaultTextToTranslate', default: 'hello', description: 'hello: the default text to translate' }) }, LANGUAGE: { type: ArgumentType.STRING, menu: 'languages', defaultValue: this._randomLanguageCode } } }, { opcode: 'getViewerLanguage', text: formatMessage({ id: 'translate.viewerLanguage', default: 'language', description: 'the languge of the project viewer' }), blockType: BlockType.REPORTER, arguments: {} }], menus: { languages: { acceptReporters: true, items: this._supportedLanguages } } }; } /** * Computes a list of language code and name pairs for the given language. * @param {string} code The language code to get the list of language pairs * @return {Array.>} An array of languge name and * language code pairs. * @private */ _getSupportedLanguages(code) { return languageNames.menuMap[code].map(entry => { const obj = { text: entry.name, value: entry.code }; return obj; }); } /** * Get the human readable language value for the reporter block. * @return {string} the language name of the project viewer. */ getViewerLanguage() { this._viewerLanguageCode = this.getViewerLanguageCode(); const names = languageNames.menuMap[this._viewerLanguageCode]; let langNameObj = names.find(obj => obj.code === this._viewerLanguageCode); // If we don't have a name entry yet, try looking it up via the Google langauge // code instead of Scratch's (e.g. for es-419 we look up es to get espanol) if (!langNameObj && languageNames.scratchToGoogleMap[this._viewerLanguageCode]) { const lookupCode = languageNames.scratchToGoogleMap[this._viewerLanguageCode]; langNameObj = names.find(obj => obj.code === lookupCode); } let langName = this._viewerLanguageCode; if (langNameObj) { langName = langNameObj.name; } return langName; } /** * Get the viewer's language code. * @return {string} the language code. */ getViewerLanguageCode() { const locale = formatMessage.setup().locale; const viewerLanguages = [locale].concat(navigator.languages); const languageKeys = Object.keys(languageNames.menuMap); // Return the first entry in viewerLanguages that matches // one of the available language keys. const languageCode = viewerLanguages.reduce((acc, lang) => { if (acc) { return acc; } if (languageKeys.indexOf(lang.toLowerCase()) > -1) { return lang; } return acc; }, '') || 'en'; return languageCode.toLowerCase(); } /** * Get a language code from a block argument. The arg can be a language code * or a language name, written in any language. * @param {object} arg A block argument. * @return {string} A language code. */ getLanguageCodeFromArg(arg) { const languageArg = Cast.toString(arg).toLowerCase(); // Check if the arg matches a language code in the menu. if (languageNames.menuMap.hasOwnProperty(languageArg)) { return languageArg; } // Check for a dropped-in language name, and convert to a language code. if (languageNames.nameMap.hasOwnProperty(languageArg)) { return languageNames.nameMap[languageArg]; } // There are some languages we launched in the language menu that Scratch did not // end up launching in. In order to keep projects that may have had that menu item // working, check for those language codes and let them through. // Examples: 'ab', 'hi'. if (languageNames.previouslySupported.indexOf(languageArg) !== -1) { return languageArg; } // Default to English. return 'en'; } /** * Translates the text in the translate block to the language specified in the menu. * @param {object} args - the block arguments. * @return {Promise} - a promise that resolves after the response from the translate server. */ getTranslate(args) { // If the text contains only digits 0-9 and nothing else, return it without // making a request. if (/^\d+$/.test(args.WORDS)) return Promise.resolve(args.WORDS); // Don't remake the request if we already have the value. if (this._lastTextTranslated === args.WORDS && this._lastLangTranslated === args.LANGUAGE) { return this._translateResult; } const lang = this.getLanguageCodeFromArg(args.LANGUAGE); let urlBase = "".concat(serverURL, "translate?language="); urlBase += lang; urlBase += '&text='; urlBase += encodeURIComponent(args.WORDS); const tempThis = this; const translatePromise = fetchWithTimeout(urlBase, {}, serverTimeoutMs).then(response => response.text()).then(responseText => { const translated = JSON.parse(responseText).result; tempThis._translateResult = translated; // Cache what we just translated so we don't keep making the // same call over and over. tempThis._lastTextTranslated = args.WORDS; tempThis._lastLangTranslated = args.LANGUAGE; return translated; }).catch(err => { log.warn("error fetching translate result! ".concat(err)); return ''; }); return translatePromise; } } module.exports = Scratch3TranslateBlocks; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_video_sensing/index.js": /*!********************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_video_sensing/index.js ***! \********************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const Runtime = __webpack_require__(/*! ../../engine/runtime */ "./node_modules/scratch-vm/src/engine/runtime.js"); const ArgumentType = __webpack_require__(/*! ../../extension-support/argument-type */ "./node_modules/scratch-vm/src/extension-support/argument-type.js"); const BlockType = __webpack_require__(/*! ../../extension-support/block-type */ "./node_modules/scratch-vm/src/extension-support/block-type.js"); const Clone = __webpack_require__(/*! ../../util/clone */ "./node_modules/scratch-vm/src/util/clone.js"); const Cast = __webpack_require__(/*! ../../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); const formatMessage = __webpack_require__(/*! format-message */ "./node_modules/format-message/index.js"); const Video = __webpack_require__(/*! ../../io/video */ "./node_modules/scratch-vm/src/io/video.js"); const VideoMotion = __webpack_require__(/*! ./library */ "./node_modules/scratch-vm/src/extensions/scratch3_video_sensing/library.js"); /** * Icon svg to be displayed in the blocks category menu, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len const menuIconURI = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjBweCIgaGVpZ2h0PSIyMHB4IiB2aWV3Qm94PSIwIDAgMjAgMjAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjIgKDY3MTQ1KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5FeHRlbnNpb25zL1NvZnR3YXJlL1ZpZGVvLVNlbnNpbmctTWVudTwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxnIGlkPSJFeHRlbnNpb25zL1NvZnR3YXJlL1ZpZGVvLVNlbnNpbmctTWVudSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9InZpZGVvLW1vdGlvbiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC4wMDAwMDAsIDUuMDAwMDAwKSIgZmlsbC1ydWxlPSJub256ZXJvIj4KICAgICAgICAgICAgPGNpcmNsZSBpZD0iT3ZhbC1Db3B5IiBmaWxsPSIjMEVCRDhDIiBvcGFjaXR5PSIwLjI1IiBjeD0iMTYiIGN5PSI4IiByPSIyIj48L2NpcmNsZT4KICAgICAgICAgICAgPGNpcmNsZSBpZD0iT3ZhbC1Db3B5IiBmaWxsPSIjMEVCRDhDIiBvcGFjaXR5PSIwLjUiIGN4PSIxNiIgY3k9IjYiIHI9IjIiPjwvY2lyY2xlPgogICAgICAgICAgICA8Y2lyY2xlIGlkPSJPdmFsLUNvcHkiIGZpbGw9IiMwRUJEOEMiIG9wYWNpdHk9IjAuNzUiIGN4PSIxNiIgY3k9IjQiIHI9IjIiPjwvY2lyY2xlPgogICAgICAgICAgICA8Y2lyY2xlIGlkPSJPdmFsIiBmaWxsPSIjMEVCRDhDIiBjeD0iMTYiIGN5PSIyIiByPSIyIj48L2NpcmNsZT4KICAgICAgICAgICAgPHBhdGggZD0iTTExLjMzNTk3MzksMi4yMDk3ODgyNSBMOC4yNSw0LjIwOTk1NjQ5IEw4LjI1LDMuMDUgQzguMjUsMi4wNDQ4ODIyNyA3LjQ2ODU5MDMxLDEuMjUgNi41LDEuMjUgTDIuMDUsMS4yNSBDMS4wMzgwNzExOSwxLjI1IDAuMjUsMi4wMzgwNzExOSAwLjI1LDMuMDUgTDAuMjUsNyBDMC4yNSw3Ljk2MzY5OTM3IDEuMDQyMjQ5MTksOC43NTU5NDg1NiAyLjA1LDguOCBMNi41LDguOCBDNy40NTA4MzAwOSw4LjggOC4yNSw3Ljk3MzI3MjUgOC4yNSw3IEw4LjI1LDUuODU4NDUyNDEgTDguNjI4NjIzOTQsNi4wODU2MjY3NyBMMTEuNDI2Nzc2Nyw3Ljc3MzIyMzMgQzExLjQzNjg5NDMsNy43ODMzNDA5MSAxMS40NzU3NjU1LDcuOCAxMS41LDcuOCBDMTEuNjMzNDkzMiw3LjggMTEuNzUsNy42OTEyNjAzNCAxMS43NSw3LjU1IEwxMS43NSwyLjQgQzExLjc1LDIuNDE4MzgyNjkgMTEuNzIxOTAyOSwyLjM1MjgyMjgyIDExLjY4NTYyNjgsMi4yNzg2MjM5NCBDMTEuNjEyOTUyOCwyLjE1NzUwMDY5IDExLjQ3MDc5NjgsMi4xMjkwNjk1IDExLjMzNTk3MzksMi4yMDk3ODgyNSBaIiBpZD0idmlkZW9fMzdfIiBzdHJva2Utb3BhY2l0eT0iMC4xNSIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjAuNSIgZmlsbD0iIzRENEQ0RCI+PC9wYXRoPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+'; /** * Icon svg to be displayed at the left edge of each extension block, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len const blockIconURI = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNDBweCIgaGVpZ2h0PSI0MHB4IiB2aWV3Qm94PSIwIDAgNDAgNDAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjIgKDY3MTQ1KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5FeHRlbnNpb25zL1NvZnR3YXJlL1ZpZGVvLVNlbnNpbmctQmxvY2s8L3RpdGxlPgogICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+CiAgICA8ZyBpZD0iRXh0ZW5zaW9ucy9Tb2Z0d2FyZS9WaWRlby1TZW5zaW5nLUJsb2NrIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2Utb3BhY2l0eT0iMC4xNSI+CiAgICAgICAgPGcgaWQ9InZpZGVvLW1vdGlvbiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC4wMDAwMDAsIDEwLjAwMDAwMCkiIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlPSIjMDAwMDAwIj4KICAgICAgICAgICAgPGNpcmNsZSBpZD0iT3ZhbC1Db3B5IiBmaWxsPSIjRkZGRkZGIiBvcGFjaXR5PSIwLjI1IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGN4PSIzMiIgY3k9IjE2IiByPSI0LjUiPjwvY2lyY2xlPgogICAgICAgICAgICA8Y2lyY2xlIGlkPSJPdmFsLUNvcHkiIGZpbGw9IiNGRkZGRkYiIG9wYWNpdHk9IjAuNSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBjeD0iMzIiIGN5PSIxMiIgcj0iNC41Ij48L2NpcmNsZT4KICAgICAgICAgICAgPGNpcmNsZSBpZD0iT3ZhbC1Db3B5IiBmaWxsPSIjRkZGRkZGIiBvcGFjaXR5PSIwLjc1IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGN4PSIzMiIgY3k9IjgiIHI9IjQuNSI+PC9jaXJjbGU+CiAgICAgICAgICAgIDxjaXJjbGUgaWQ9Ik92YWwiIGZpbGw9IiNGRkZGRkYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgY3g9IjMyIiBjeT0iNCIgcj0iNC41Ij48L2NpcmNsZT4KICAgICAgICAgICAgPHBhdGggZD0iTTIyLjY3MTk0NzcsNC40MTk1NzY0OSBMMTYuNSw4LjQxOTkxMjk4IEwxNi41LDYuMSBDMTYuNSw0LjA4OTc2NDU0IDE0LjkzNzE4MDYsMi41IDEzLDIuNSBMNC4xLDIuNSBDMi4wNzYxNDIzNywyLjUgMC41LDQuMDc2MTQyMzcgMC41LDYuMSBMMC41LDE0IEMwLjUsMTUuOTI3Mzk4NyAyLjA4NDQ5ODM5LDE3LjUxMTg5NzEgNC4xLDE3LjYgTDEzLDE3LjYgQzE0LjkwMTY2MDIsMTcuNiAxNi41LDE1Ljk0NjU0NSAxNi41LDE0IEwxNi41LDExLjcxNjkwNDggTDIyLjc1NzI0NzksMTUuNDcxMjUzNSBMMjIuODUzNTUzNCwxNS41NDY0NDY2IEMyMi44NzM3ODg2LDE1LjU2NjY4MTggMjIuOTUxNTMxLDE1LjYgMjMsMTUuNiBDMjMuMjY2OTg2NSwxNS42IDIzLjUsMTUuMzgyNTIwNyAyMy41LDE1LjEgTDIzLjUsNC44IEMyMy41LDQuODM2NzY1MzggMjMuNDQzODA1OCw0LjcwNTY0NTYzIDIzLjM3MTI1MzUsNC41NTcyNDc4OCBDMjMuMjI1OTA1Niw0LjMxNTAwMTM5IDIyLjk0MTU5MzcsNC4yNTgxMzg5OSAyMi42NzE5NDc3LDQuNDE5NTc2NDkgWiIgaWQ9InZpZGVvXzM3XyIgZmlsbD0iIzRENEQ0RCI+PC9wYXRoPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+'; /** * Sensor attribute video sensor block should report. * @readonly * @enum {string} */ const SensingAttribute = { /** The amount of motion. */ MOTION: 'motion', /** The direction of the motion. */ DIRECTION: 'direction' }; /** * Subject video sensor block should report for. * @readonly * @enum {string} */ const SensingSubject = { /** The sensor traits of the whole stage. */ STAGE: 'Stage', /** The senosr traits of the area overlapped by this sprite. */ SPRITE: 'this sprite' }; /** * States the video sensing activity can be set to. * @readonly * @enum {string} */ const VideoState = { /** Video turned off. */ OFF: 'off', /** Video turned on with default y axis mirroring. */ ON: 'on', /** Video turned on without default y axis mirroring. */ ON_FLIPPED: 'on-flipped' }; /** * Class for the motion-related blocks in Scratch 3.0 * @param {Runtime} runtime - the runtime instantiating this block package. * @constructor */ class Scratch3VideoSensingBlocks { constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; /** * The motion detection algoritm used to power the motion amount and * direction values. * @type {VideoMotion} */ this.detect = new VideoMotion(); /** * The last millisecond epoch timestamp that the video stream was * analyzed. * @type {number} */ this._lastUpdate = null; /** * A flag to determine if this extension has been installed in a project. * It is set to false the first time getInfo is run. * @type {boolean} */ this.firstInstall = true; if (this.runtime.ioDevices) { // Configure the video device with values from globally stored locations. this.runtime.on(Runtime.PROJECT_LOADED, this.updateVideoDisplay.bind(this)); // Clear target motion state values when the project starts. this.runtime.on(Runtime.PROJECT_RUN_START, this.reset.bind(this)); // Kick off looping the analysis logic. this._loop(); } } /** * After analyzing a frame the amount of milliseconds until another frame * is analyzed. * @type {number} */ static get INTERVAL() { return 33; } /** * Dimensions the video stream is analyzed at after its rendered to the * sample canvas. * @type {Array.} */ static get DIMENSIONS() { return [480, 360]; } /** * The key to load & store a target's motion-related state. * @type {string} */ static get STATE_KEY() { return 'Scratch.videoSensing'; } /** * The default motion-related state, to be used when a target has no existing motion state. * @type {MotionState} */ static get DEFAULT_MOTION_STATE() { return { motionFrameNumber: 0, motionAmount: 0, motionDirection: 0 }; } /** * The transparency setting of the video preview stored in a value * accessible by any object connected to the virtual machine. * @type {number} */ get globalVideoTransparency() { const stage = this.runtime.getTargetForStage(); if (stage) { return stage.videoTransparency; } return 50; } set globalVideoTransparency(transparency) { const stage = this.runtime.getTargetForStage(); if (stage) { stage.videoTransparency = transparency; } return transparency; } /** * The video state of the video preview stored in a value accessible by any * object connected to the virtual machine. * @type {number} */ get globalVideoState() { const stage = this.runtime.getTargetForStage(); if (stage) { return stage.videoState; } // Though the default value for the stage is normally 'on', we need to default // to 'off' here to prevent the video device from briefly activating // while waiting for stage targets to be installed that say it should be off return VideoState.OFF; } set globalVideoState(state) { const stage = this.runtime.getTargetForStage(); if (stage) { stage.videoState = state; } return state; } /** * Get the latest values for video transparency and state, * and set the video device to use them. */ updateVideoDisplay() { this.setVideoTransparency({ TRANSPARENCY: this.globalVideoTransparency }); this.videoToggle({ VIDEO_STATE: this.globalVideoState }); } /** * Reset the extension's data motion detection data. This will clear out * for example old frames, so the first analyzed frame will not be compared * against a frame from before reset was called. */ reset() { this.detect.reset(); const targets = this.runtime.targets; for (let i = 0; i < targets.length; i++) { const state = targets[i].getCustomState(Scratch3VideoSensingBlocks.STATE_KEY); if (state) { state.motionAmount = 0; state.motionDirection = 0; } } } /** * Occasionally step a loop to sample the video, stamp it to the preview * skin, and add a TypedArray copy of the canvas's pixel data. * @private */ _loop() { setTimeout(this._loop.bind(this), Math.max(this.runtime.currentStepTime, Scratch3VideoSensingBlocks.INTERVAL)); // Add frame to detector const time = Date.now(); if (this._lastUpdate === null) { this._lastUpdate = time; } const offset = time - this._lastUpdate; if (offset > Scratch3VideoSensingBlocks.INTERVAL) { const frame = this.runtime.ioDevices.video.getFrame({ format: Video.FORMAT_IMAGE_DATA, dimensions: Scratch3VideoSensingBlocks.DIMENSIONS }); if (frame) { this._lastUpdate = time; this.detect.addFrame(frame.data); } } } /** * Create data for a menu in scratch-blocks format, consisting of an array * of objects with text and value properties. The text is a translated * string, and the value is one-indexed. * @param {object[]} info - An array of info objects each having a name * property. * @return {array} - An array of objects with text and value properties. * @private */ _buildMenu(info) { return info.map((entry, index) => { const obj = {}; obj.text = entry.name; obj.value = entry.value || String(index + 1); return obj; }); } /** * @param {Target} target - collect motion state for this target. * @returns {MotionState} the mutable motion state associated with that * target. This will be created if necessary. * @private */ _getMotionState(target) { let motionState = target.getCustomState(Scratch3VideoSensingBlocks.STATE_KEY); if (!motionState) { motionState = Clone.simple(Scratch3VideoSensingBlocks.DEFAULT_MOTION_STATE); target.setCustomState(Scratch3VideoSensingBlocks.STATE_KEY, motionState); } return motionState; } static get SensingAttribute() { return SensingAttribute; } /** * An array of choices of whether a reporter should return the frame's * motion amount or direction. * @type {object[]} * @param {string} name - the translatable name to display in sensor * attribute menu * @param {string} value - the serializable value of the attribute */ get ATTRIBUTE_INFO() { return [{ name: formatMessage({ id: 'videoSensing.motion', default: 'motion', description: 'Attribute for the "video [ATTRIBUTE] on [SUBJECT]" block' }), value: SensingAttribute.MOTION }, { name: formatMessage({ id: 'videoSensing.direction', default: 'direction', description: 'Attribute for the "video [ATTRIBUTE] on [SUBJECT]" block' }), value: SensingAttribute.DIRECTION }]; } static get SensingSubject() { return SensingSubject; } /** * An array of info about the subject choices. * @type {object[]} * @param {string} name - the translatable name to display in the subject menu * @param {string} value - the serializable value of the subject */ get SUBJECT_INFO() { return [{ name: formatMessage({ id: 'videoSensing.sprite', default: 'sprite', description: 'Subject for the "video [ATTRIBUTE] on [SUBJECT]" block' }), value: SensingSubject.SPRITE }, { name: formatMessage({ id: 'videoSensing.stage', default: 'stage', description: 'Subject for the "video [ATTRIBUTE] on [SUBJECT]" block' }), value: SensingSubject.STAGE }]; } /** * States the video sensing activity can be set to. * @readonly * @enum {string} */ static get VideoState() { return VideoState; } /** * An array of info on video state options for the "turn video [STATE]" block. * @type {object[]} * @param {string} name - the translatable name to display in the video state menu * @param {string} value - the serializable value stored in the block */ get VIDEO_STATE_INFO() { return [{ name: formatMessage({ id: 'videoSensing.off', default: 'off', description: 'Option for the "turn video [STATE]" block' }), value: VideoState.OFF }, { name: formatMessage({ id: 'videoSensing.on', default: 'on', description: 'Option for the "turn video [STATE]" block' }), value: VideoState.ON }, { name: formatMessage({ id: 'videoSensing.onFlipped', default: 'on flipped', description: 'Option for the "turn video [STATE]" block that causes the video to be flipped' + ' horizontally (reversed as in a mirror)' }), value: VideoState.ON_FLIPPED }]; } /** * @returns {object} metadata for this extension and its blocks. */ getInfo() { // Set the video display properties to defaults the first time // getInfo is run. This turns on the video device when it is // first added to a project, and is overwritten by a PROJECT_LOADED // event listener that later calls updateVideoDisplay if (this.firstInstall) { this.globalVideoState = VideoState.ON; this.globalVideoTransparency = 50; this.updateVideoDisplay(); this.firstInstall = false; } // Return extension definition return { id: 'videoSensing', name: formatMessage({ id: 'videoSensing.categoryName', default: 'Video Sensing', description: 'Label for the video sensing extension category' }), blockIconURI: blockIconURI, menuIconURI: menuIconURI, blocks: [{ // @todo this hat needs to be set itself to restart existing // threads like Scratch 2's behaviour. opcode: 'whenMotionGreaterThan', text: formatMessage({ id: 'videoSensing.whenMotionGreaterThan', default: 'when video motion > [REFERENCE]', description: 'Event that triggers when the amount of motion is greater than [REFERENCE]' }), blockType: BlockType.HAT, arguments: { REFERENCE: { type: ArgumentType.NUMBER, defaultValue: 10 } } }, { opcode: 'videoOn', blockType: BlockType.REPORTER, text: formatMessage({ id: 'videoSensing.videoOn', default: 'video [ATTRIBUTE] on [SUBJECT]', description: 'Reporter that returns the amount of [ATTRIBUTE] for the selected [SUBJECT]' }), arguments: { ATTRIBUTE: { type: ArgumentType.NUMBER, menu: 'ATTRIBUTE', defaultValue: SensingAttribute.MOTION }, SUBJECT: { type: ArgumentType.NUMBER, menu: 'SUBJECT', defaultValue: SensingSubject.SPRITE } } }, { opcode: 'videoToggle', text: formatMessage({ id: 'videoSensing.videoToggle', default: 'turn video [VIDEO_STATE]', description: 'Controls display of the video preview layer' }), arguments: { VIDEO_STATE: { type: ArgumentType.NUMBER, menu: 'VIDEO_STATE', defaultValue: VideoState.ON } } }, { opcode: 'setVideoTransparency', text: formatMessage({ id: 'videoSensing.setVideoTransparency', default: 'set video transparency to [TRANSPARENCY]', description: 'Controls transparency of the video preview layer' }), arguments: { TRANSPARENCY: { type: ArgumentType.NUMBER, defaultValue: 50 } } }], menus: { ATTRIBUTE: { acceptReporters: true, items: this._buildMenu(this.ATTRIBUTE_INFO) }, SUBJECT: { acceptReporters: true, items: this._buildMenu(this.SUBJECT_INFO) }, VIDEO_STATE: { acceptReporters: true, items: this._buildMenu(this.VIDEO_STATE_INFO) } } }; } /** * Analyze a part of the frame that a target overlaps. * @param {Target} target - a target to determine where to analyze * @returns {MotionState} the motion state for the given target */ _analyzeLocalMotion(target) { const drawable = this.runtime.renderer._allDrawables[target.drawableID]; const state = this._getMotionState(target); this.detect.getLocalMotion(drawable, state); return state; } /** * A scratch reporter block handle that analyzes the last two frames and * depending on the arguments, returns the motion or direction for the * whole stage or just the target sprite. * @param {object} args - the block arguments * @param {BlockUtility} util - the block utility * @returns {number} the motion amount or direction of the stage or sprite */ videoOn(args, util) { this.detect.analyzeFrame(); let state = this.detect; if (args.SUBJECT === SensingSubject.SPRITE) { state = this._analyzeLocalMotion(util.target); } if (args.ATTRIBUTE === SensingAttribute.MOTION) { return state.motionAmount; } return state.motionDirection; } /** * A scratch hat block edge handle that analyzes the last two frames where * the target sprite overlaps and if it has more motion than the given * reference value. * @param {object} args - the block arguments * @param {BlockUtility} util - the block utility * @returns {boolean} true if the sprite overlaps more motion than the * reference */ whenMotionGreaterThan(args, util) { this.detect.analyzeFrame(); const state = this._analyzeLocalMotion(util.target); return state.motionAmount > Number(args.REFERENCE); } /** * A scratch command block handle that configures the video state from * passed arguments. * @param {object} args - the block arguments * @param {VideoState} args.VIDEO_STATE - the video state to set the device to */ videoToggle(args) { const state = args.VIDEO_STATE; this.globalVideoState = state; if (state === VideoState.OFF) { this.runtime.ioDevices.video.disableVideo(); } else { this.runtime.ioDevices.video.enableVideo(); // Mirror if state is ON. Do not mirror if state is ON_FLIPPED. this.runtime.ioDevices.video.mirror = state === VideoState.ON; } } /** * A scratch command block handle that configures the video preview's * transparency from passed arguments. * @param {object} args - the block arguments * @param {number} args.TRANSPARENCY - the transparency to set the video * preview to */ setVideoTransparency(args) { const transparency = Cast.toNumber(args.TRANSPARENCY); this.globalVideoTransparency = transparency; this.runtime.ioDevices.video.setPreviewGhost(transparency); } } module.exports = Scratch3VideoSensingBlocks; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_video_sensing/library.js": /*!**********************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_video_sensing/library.js ***! \**********************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /** * @file library.js * * Tony Hwang and John Maloney, January 2011 * Michael "Z" Goddard, March 2018 * * Video motion sensing primitives. */ const { motionVector, scratchAtan2 } = __webpack_require__(/*! ./math */ "./node_modules/scratch-vm/src/extensions/scratch3_video_sensing/math.js"); /** * The width of the intended resolution to analyze for motion. * @type {number} */ const WIDTH = 480; /** * The height of the intended resolution to analyze for motion. * @type {number} */ const HEIGHT = 360; /** * A constant value to scale the magnitude of the x and y components called u * and v. This creates the motionAmount value. * * Old note: chosen empirically to give a range of roughly 0-100 * * @type {number} */ const AMOUNT_SCALE = 100; /** * A constant value to scale the magnitude of the x and y components called u * and v in the local motion derivative. This creates the motionAmount value on * a target's motion state. * * Old note: note 2e-4 * activePixelNum is an experimentally tuned threshold * for my logitech Pro 9000 webcam - TTH * * @type {number} */ const LOCAL_AMOUNT_SCALE = AMOUNT_SCALE * 2e-4; /** * The motion amount must be higher than the THRESHOLD to calculate a new * direction value. * @type {number} */ const THRESHOLD = 10; /** * The size of the radius of the window of summarized values when considering * the motion inside the full resolution of the sample. * @type {number} */ const WINSIZE = 8; /** * A ceiling for the motionAmount stored to a local target's motion state. The * motionAmount is not allowed to be larger than LOCAL_MAX_AMOUNT. * @type {number} */ const LOCAL_MAX_AMOUNT = 100; /** * The motion amount for a target's local motion must be higher than the * LOCAL_THRESHOLD to calculate a new direction value. * @type {number} */ const LOCAL_THRESHOLD = THRESHOLD / 3; /** * Store the necessary image pixel data to compares frames of a video and * detect an amount and direction of motion in the full sample or in a * specified area. * @constructor */ class VideoMotion { constructor() { /** * The number of frames that have been added from a source. * @type {number} */ this.frameNumber = 0; /** * The frameNumber last analyzed. * @type {number} */ this.lastAnalyzedFrame = 0; /** * The amount of motion detected in the current frame. * @type {number} */ this.motionAmount = 0; /** * The direction the motion detected in the frame is general moving in. * @type {number} */ this.motionDirection = 0; /** * A copy of the current frame's pixel values. A index of the array is * represented in RGBA. The lowest byte is red. The next is green. The * next is blue. And the last is the alpha value of that pixel. * @type {Uint32Array} */ this.curr = null; /** * A copy of the last frame's pixel values. * @type {Uint32Array} */ this.prev = null; /** * A buffer for holding one component of a pixel's full value twice. * One for the current value. And one for the last value. * @type {number} */ this._arrays = new ArrayBuffer(WIDTH * HEIGHT * 2 * 1); /** * A clamped uint8 view of _arrays. One component of each index of the * curr member is copied into this array. * @type {number} */ this._curr = new Uint8ClampedArray(this._arrays, WIDTH * HEIGHT * 0 * 1, WIDTH * HEIGHT); /** * A clamped uint8 view of _arrays. One component of each index of the * prev member is copied into this array. * @type {number} */ this._prev = new Uint8ClampedArray(this._arrays, WIDTH * HEIGHT * 1 * 1, WIDTH * HEIGHT); } /** * Reset internal state so future frame analysis does not consider values * from before this method was called. */ reset() { this.frameNumber = 0; this.lastAnalyzedFrame = 0; this.motionAmount = this.motionDirection = 0; this.prev = this.curr = null; } /** * Add a frame to be next analyzed. The passed array represent a pixel with * each index in the RGBA format. * @param {Uint32Array} source - a source frame of pixels to copy */ addFrame(source) { this.frameNumber++; // Swap curr to prev. this.prev = this.curr; // Create a clone of the array so any modifications made to the source // array do not affect the work done in here. this.curr = new Uint32Array(source.buffer.slice(0)); // Swap _prev and _curr. Copy one of the color components of the new // array into _curr overwriting what was the old _prev data. const _tmp = this._prev; this._prev = this._curr; this._curr = _tmp; for (let i = 0; i < this.curr.length; i++) { this._curr[i] = this.curr[i] & 0xff; } } /** * Analyze the current frame against the previous frame determining the * amount of motion and direction of the motion. */ analyzeFrame() { if (!this.curr || !this.prev) { this.motionAmount = this.motionDirection = -1; // Don't have two frames to analyze yet return; } // Return early if new data has not been received. if (this.lastAnalyzedFrame === this.frameNumber) { return; } this.lastAnalyzedFrame = this.frameNumber; const { _curr: curr, _prev: prev } = this; const winStep = WINSIZE * 2 + 1; const wmax = WIDTH - WINSIZE - 1; const hmax = HEIGHT - WINSIZE - 1; // Accumulate 2d motion vectors from groups of pixels and average it // later. let uu = 0; let vv = 0; let n = 0; // Iterate over groups of cells building up the components to determine // a motion vector for each cell instead of the whole frame to avoid // integer overflows. for (let i = WINSIZE + 1; i < hmax; i += winStep) { for (let j = WINSIZE + 1; j < wmax; j += winStep) { let A2 = 0; let A1B2 = 0; let B1 = 0; let C1 = 0; let C2 = 0; // This is a performance critical math region. let address = (i - WINSIZE) * WIDTH + j - WINSIZE; let nextAddress = address + winStep; const maxAddress = (i + WINSIZE) * WIDTH + j + WINSIZE; for (; address <= maxAddress; address += WIDTH - winStep, nextAddress += WIDTH) { for (; address <= nextAddress; address += 1) { // The difference in color between the last frame and // the current frame. const gradT = prev[address] - curr[address]; // The difference between the pixel to the left and the // pixel to the right. const gradX = curr[address - 1] - curr[address + 1]; // The difference between the pixel above and the pixel // below. const gradY = curr[address - WIDTH] - curr[address + WIDTH]; // Add the combined values of this pixel to previously // considered pixels. A2 += gradX * gradX; A1B2 += gradX * gradY; B1 += gradY * gradY; C2 += gradX * gradT; C1 += gradY * gradT; } } // Use the accumalated values from the for loop to determine a // motion direction. const { u, v } = motionVector(A2, A1B2, B1, C2, C1); // If u and v are within negative winStep to positive winStep, // add them to a sum that will later be averaged. if (-winStep < u && u < winStep && -winStep < v && v < winStep) { uu += u; vv += v; n++; } } } // Average the summed vector values of all of the motion groups. uu /= n; vv /= n; // Scale the magnitude of the averaged UV vector. this.motionAmount = Math.round(AMOUNT_SCALE * Math.hypot(uu, vv)); if (this.motionAmount > THRESHOLD) { // Scratch direction this.motionDirection = scratchAtan2(vv, uu); } } /** * Build motion amount and direction values based on stored current and * previous frame that overlaps a given drawable. * @param {Drawable} drawable - touchable and bounded drawable to build motion for * @param {MotionState} state - state to store built values to */ getLocalMotion(drawable, state) { if (!this.curr || !this.prev) { state.motionAmount = state.motionDirection = -1; // Don't have two frames to analyze yet return; } // Skip if the current frame has already been considered for this state. if (state.motionFrameNumber !== this.frameNumber) { const { _prev: prev, _curr: curr } = this; // The public APIs for Renderer#isTouching manage keeping the matrix and // silhouette up-to-date, which is needed for drawable#isTouching to work (used below) drawable.updateCPURenderAttributes(); // Restrict the region the amount and direction are built from to // the area of the current frame overlapped by the given drawable's // bounding box. const boundingRect = drawable.getFastBounds(); // Transform the bounding box from scratch space to a space from 0, // 0 to WIDTH, HEIGHT. const xmin = Math.max(Math.floor(boundingRect.left + WIDTH / 2), 1); const xmax = Math.min(Math.floor(boundingRect.right + WIDTH / 2), WIDTH - 1); const ymin = Math.max(Math.floor(HEIGHT / 2 - boundingRect.top), 1); const ymax = Math.min(Math.floor(HEIGHT / 2 - boundingRect.bottom), HEIGHT - 1); let A2 = 0; let A1B2 = 0; let B1 = 0; let C1 = 0; let C2 = 0; let scaleFactor = 0; const position = [0, 0, 0]; // This is a performance critical math region. for (let i = ymin; i < ymax; i++) { for (let j = xmin; j < xmax; j++) { // i and j are in a coordinate planning ranging from 0 to // HEIGHT and 0 to WIDTH. Transform that into Scratch's // range of HEIGHT / 2 to -HEIGHT / 2 and -WIDTH / 2 to // WIDTH / 2; position[0] = j - WIDTH / 2; position[1] = HEIGHT / 2 - i; // Consider only pixels in the drawable that can touch the // edge or other drawables. Empty space in the current skin // is skipped. if (drawable.isTouching(position)) { const address = i * WIDTH + j; // The difference in color between the last frame and // the current frame. const gradT = prev[address] - curr[address]; // The difference between the pixel to the left and the // pixel to the right. const gradX = curr[address - 1] - curr[address + 1]; // The difference between the pixel above and the pixel // below. const gradY = curr[address - WIDTH] - curr[address + WIDTH]; // Add the combined values of this pixel to previously // considered pixels. A2 += gradX * gradX; A1B2 += gradX * gradY; B1 += gradY * gradY; C2 += gradX * gradT; C1 += gradY * gradT; scaleFactor++; } } } // Use the accumalated values from the for loop to determine a // motion direction. let { u, v } = motionVector(A2, A1B2, B1, C2, C1); let activePixelNum = 0; if (scaleFactor) { // Store the area of the sprite in pixels activePixelNum = scaleFactor; scaleFactor /= 2 * WINSIZE * 2 * WINSIZE; u = u / scaleFactor; v = v / scaleFactor; } // Scale the magnitude of the averaged UV vector and the number of // overlapping drawable pixels. state.motionAmount = Math.round(LOCAL_AMOUNT_SCALE * activePixelNum * Math.hypot(u, v)); if (state.motionAmount > LOCAL_MAX_AMOUNT) { // Clip all magnitudes greater than 100. state.motionAmount = LOCAL_MAX_AMOUNT; } if (state.motionAmount > LOCAL_THRESHOLD) { // Scratch direction. state.motionDirection = scratchAtan2(v, u); } // Skip future calls on this state until a new frame is added. state.motionFrameNumber = this.frameNumber; } } } module.exports = VideoMotion; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_video_sensing/math.js": /*!*******************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_video_sensing/math.js ***! \*******************************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { /** * A constant value helping to transform a value in radians to degrees. * @type {number} */ const TO_DEGREE = 180 / Math.PI; /** * A object reused to save on memory allocation returning u and v vector from * motionVector. * @type {UV} */ const _motionVectorOut = { u: 0, v: 0 }; /** * Determine a motion vector combinations of the color component difference on * the x axis, y axis, and temporal axis. * @param {number} A2 - a sum of x axis squared * @param {number} A1B2 - a sum of x axis times y axis * @param {number} B1 - a sum of y axis squared * @param {number} C2 - a sum of x axis times temporal axis * @param {number} C1 - a sum of y axis times temporal axis * @param {UV} out - optional object to store return UV info in * @returns {UV} a uv vector representing the motion for the given input */ const motionVector = function motionVector(A2, A1B2, B1, C2, C1, out = _motionVectorOut) { // Compare sums of X * Y and sums of X squared and Y squared. const delta = A1B2 * A1B2 - A2 * B1; if (delta) { // System is not singular - solving by Kramer method. const deltaX = -(C1 * A1B2 - C2 * B1); const deltaY = -(A1B2 * C2 - A2 * C1); const Idelta = 8 / delta; out.u = deltaX * Idelta; out.v = deltaY * Idelta; } else { // Singular system - find optical flow in gradient direction. const Norm = (A1B2 + A2) * (A1B2 + A2) + (B1 + A1B2) * (B1 + A1B2); if (Norm) { const IGradNorm = 8 / Norm; const temp = -(C1 + C2) * IGradNorm; out.u = (A1B2 + A2) * temp; out.v = (B1 + A1B2) * temp; } else { out.u = 0; out.v = 0; } } return out; }; /** * Translate an angle in degrees with the range -180 to 180 rotated to * Scratch's reference angle. * @param {number} degrees - angle in range -180 to 180 * @returns {number} angle from Scratch's reference angle */ const scratchDegrees = function scratchDegrees(degrees) { return (degrees + 270) % 360 - 180; }; /** * Get the angle of the y and x component of a 2d vector in degrees in * Scratch's coordinate plane. * @param {number} y - the y component of a 2d vector * @param {number} x - the x component of a 2d vector * @returns {number} angle in degrees in Scratch's coordinate plane */ const scratchAtan2 = function scratchAtan2(y, x) { return scratchDegrees(Math.atan2(y, x) * TO_DEGREE); }; module.exports = { motionVector, scratchDegrees, scratchAtan2 }; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/scratch3_wedo2/index.js": /*!************************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/scratch3_wedo2/index.js ***! \************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const ArgumentType = __webpack_require__(/*! ../../extension-support/argument-type */ "./node_modules/scratch-vm/src/extension-support/argument-type.js"); const BlockType = __webpack_require__(/*! ../../extension-support/block-type */ "./node_modules/scratch-vm/src/extension-support/block-type.js"); const Cast = __webpack_require__(/*! ../../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); const formatMessage = __webpack_require__(/*! format-message */ "./node_modules/format-message/index.js"); const color = __webpack_require__(/*! ../../util/color */ "./node_modules/scratch-vm/src/util/color.js"); const BLE = __webpack_require__(/*! ../../io/ble */ "./node_modules/scratch-vm/src/io/ble.js"); const Base64Util = __webpack_require__(/*! ../../util/base64-util */ "./node_modules/scratch-vm/src/util/base64-util.js"); const MathUtil = __webpack_require__(/*! ../../util/math-util */ "./node_modules/scratch-vm/src/util/math-util.js"); const RateLimiter = __webpack_require__(/*! ../../util/rateLimiter.js */ "./node_modules/scratch-vm/src/util/rateLimiter.js"); const log = __webpack_require__(/*! ../../util/log */ "./node_modules/scratch-vm/src/util/log.js"); /** * Icon svg to be displayed at the left edge of each extension block, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len const iconURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAACXBIWXMAABYlAAAWJQFJUiTwAAAF8klEQVR4Ae2cbWxTVRjH/7ctbVc2tyEMNpWBk0VIkLcEjSAQgglTE5HEaKqJi1E/mbCP/dJA0kQbvzgTQ0Ki2T7V6AeYGoEPLJmGKPiyzZDwEpYJCHSbQIcbdLvres1zOa13Xbvdu2eTDp9fst329Lnn5XfPPfece7tphmFAmDkuccdDBDIRgUxEIBMRyEQEMhGBTEQgExHIRAQyEYFMRCATEchEBDIRgUxEIBMRyEQEMhGBTEQgExHIxMPNIByNVQBoBUDb7kgo2KTS9wBoUmFNkVCwW6U3A1gP4JJKHwxHY/S+WcW2RkLBVhV7AMAOAIMAGlWstbyOSCh4QMU2Uoy1PBVL+a7IqZu1vOZIKNg20/azBarGvKxebw9HY22RULADwBFLTBcATQnZl4lVEimN4ssteXQrQfstebQpmW1q30xshyqvxRLbofYnYW9ZYgeV8C5LLOWlzbTxM3ouHI7GPgSwWx3Z0syBSBku6IYnlTbM+uQenJQaMnKHDaqAFnDrcCFbl3G1defEjas0a4N/Vz10OybyvapfrSX1sjpo+WIz0ME7QL3djgtHPTAcjb2mepw/b2ZaGh5NL5RnofR8R99dIC5fHusK5JsrCUpm7TSx21XvbcwTNwnbAsPR2GcA3qaG+H0LsHlDPZ7fca/ujZ+cRW9/Em5vCXzlNVhQUjFpf/3OTSRvXkKJz43Xt1bh1S1LUeq/5+njQ9/iVmLIfL1ieRU2b1iFtavztXNu6TrTi8PfnYI67WdPoOp5przV9Y8iuHdb9rOW9uumPI+vDIElddBckztPOqVn5X36Xj1WVQeynx1sOWbK83jc2PviM/dFXIYNax9H55leXLoyYHsfWwI14JCRRx7x5ckBU1oheYQ+1G9u39lVM0Hej7+cR7w/Yb7e9+5LqChfaLvixcK088BwNNZkAOV02ubK6+odwt3RcfOULSSPGEveG48bNj08If3kqXPmdtO6unkpDzYn0u/TLxrzcumJJ80Ut79sygzoFF6/siw75mUYupOEpmnY0/A0pw33FTsCa+hX5oJhZXgkZb5zub2O20CnL7EwkPeCPm+wI7CEBvi5wuOZ36tJW7X3uGXJXAgxk8P4eNpRPEvgskqfuR0Z/BNGejxvDM3/5gs0pboWv+motqybCc+tqUCzz43kaBJ/X+2eMjZ3ClNsjIzo5ioknXZ2b4AlkKYltLJoaY9jOJm/B0KJbtg4c4F/XOmH3+dF9dLKbBo1OD6QQGV56YQ55ODtO0jcHkZ1VSX8/n9nB9S7RkZ1rFy+NG8ZR9s70TeQQKDEh7vJUdt1Y9/OopXFB2/WcbMpyOexE9mlFS21aLlHMmKHfzBl0QT/hV2bzM9oLXv0xG8YGR0zpdLEn6RT2k+/XjDzoLX2G3u3TZBLUyral/Z5qCyAK1f/sl2/or+IWNel1Eji3MWrpjyCZHWqdNrSe6ieSHFERl4mP+q5GehgHGvvRGal5XI5uzU47f3A/R99YTgdF2wXrmkolr9ToZ5NvTjT4yOhoC2T057CJM/r9WDxoqmXa07R9THcuDVcMO8bt4ag6ynULKvkFjWBTLl0ugZKvNlyqLeSQKfYGgOpgXt2b5zVhlzrS+Dr451YvKg0b95txztxvS8xZ+VuXFuLJ5+oNgV+9c3PuHDxGs6cu+w4v//9RJo6x5bN9UgbBo4cPY1U6j+cSD8orFvzGFYuX4KxsRQGbth6FCICc9m5dY05HtN46AQRqPB5PWjY+ZT5RnMwkxGBFh5ZVmle9Z3MrGbjwfqccrC1vajrV7QCaVCfS6qrJj96nQlFK5CujPRT7MgYyEQEMhGBTGwJpAW4kJ9pBbo0zbx70X7y7AOv8HxP3LyB4YTpb2cZBt2iqL3QEwf9zDbX+waLca439QMeC7a+YBmOxugLiM/OTt2yaOoMoO+H6LOcNwf6xusrthsh/7mIh1yFmYhAJiKQiQhkIgKZiEAmIpCJCGQiApmIQCYikIkIZCICmYhAJiKQiQhkIgKZiEAmIpCJCGQiAjkA+AeOwQKMcWZqHgAAAABJRU5ErkJggg=='; /** * A list of WeDo 2.0 BLE service UUIDs. * @enum */ const BLEService = { DEVICE_SERVICE: '00001523-1212-efde-1523-785feabcd123', IO_SERVICE: '00004f0e-1212-efde-1523-785feabcd123' }; /** * A list of WeDo 2.0 BLE characteristic UUIDs. * * Characteristics on DEVICE_SERVICE: * - ATTACHED_IO * * Characteristics on IO_SERVICE: * - INPUT_VALUES * - INPUT_COMMAND * - OUTPUT_COMMAND * * @enum */ const BLECharacteristic = { ATTACHED_IO: '00001527-1212-efde-1523-785feabcd123', LOW_VOLTAGE_ALERT: '00001528-1212-efde-1523-785feabcd123', INPUT_VALUES: '00001560-1212-efde-1523-785feabcd123', INPUT_COMMAND: '00001563-1212-efde-1523-785feabcd123', OUTPUT_COMMAND: '00001565-1212-efde-1523-785feabcd123' }; /** * A time interval to wait (in milliseconds) in between battery check calls. * @type {number} */ const BLEBatteryCheckInterval = 5000; /** * A time interval to wait (in milliseconds) while a block that sends a BLE message is running. * @type {number} */ const BLESendInterval = 100; /** * A maximum number of BLE message sends per second, to be enforced by the rate limiter. * @type {number} */ const BLESendRateMax = 20; /** * Enum for WeDo 2.0 sensor and output types. * @readonly * @enum {number} */ const WeDo2Device = { MOTOR: 1, PIEZO: 22, LED: 23, TILT: 34, DISTANCE: 35 }; /** * Enum for connection/port ids assigned to internal WeDo 2.0 output devices. * @readonly * @enum {number} */ // TODO: Check for these more accurately at startup? const WeDo2ConnectID = { LED: 6, PIEZO: 5 }; /** * Enum for ids for various output commands on the WeDo 2.0. * @readonly * @enum {number} */ const WeDo2Command = { MOTOR_POWER: 1, PLAY_TONE: 2, STOP_TONE: 3, WRITE_RGB: 4, SET_VOLUME: 255 }; /** * Enum for modes for input sensors on the WeDo 2.0. * @enum {number} */ const WeDo2Mode = { TILT: 0, // angle DISTANCE: 0, // detect LED: 1 // RGB }; /** * Enum for units for input sensors on the WeDo 2.0. * * 0 = raw * 1 = percent * * @enum {number} */ const WeDo2Unit = { TILT: 0, DISTANCE: 1, LED: 0 }; /** * Manage power, direction, and timers for one WeDo 2.0 motor. */ class WeDo2Motor { /** * Construct a WeDo 2.0 Motor instance. * @param {WeDo2} parent - the WeDo 2.0 peripheral which owns this motor. * @param {int} index - the zero-based index of this motor on its parent peripheral. */ constructor(parent, index) { /** * The WeDo 2.0 peripheral which owns this motor. * @type {WeDo2} * @private */ this._parent = parent; /** * The zero-based index of this motor on its parent peripheral. * @type {int} * @private */ this._index = index; /** * This motor's current direction: 1 for "this way" or -1 for "that way" * @type {number} * @private */ this._direction = 1; /** * This motor's current power level, in the range [0,100]. * @type {number} * @private */ this._power = 100; /** * Is this motor currently moving? * @type {boolean} * @private */ this._isOn = false; /** * If the motor has been turned on or is actively braking for a specific duration, this is the timeout ID for * the end-of-action handler. Cancel this when changing plans. * @type {Object} * @private */ this._pendingTimeoutId = null; /** * The starting time for the pending timeout. * @type {Object} * @private */ this._pendingTimeoutStartTime = null; /** * The delay/duration of the pending timeout. * @type {Object} * @private */ this._pendingTimeoutDelay = null; this.startBraking = this.startBraking.bind(this); this.turnOff = this.turnOff.bind(this); } /** * @return {number} - the duration of active braking after a call to startBraking(). Afterward, turn the motor off. * @constructor */ static get BRAKE_TIME_MS() { return 1000; } /** * @return {int} - this motor's current direction: 1 for "this way" or -1 for "that way" */ get direction() { return this._direction; } /** * @param {int} value - this motor's new direction: 1 for "this way" or -1 for "that way" */ set direction(value) { if (value < 0) { this._direction = -1; } else { this._direction = 1; } } /** * @return {int} - this motor's current power level, in the range [0,100]. */ get power() { return this._power; } /** * @param {int} value - this motor's new power level, in the range [0,100]. */ set power(value) { const p = Math.max(0, Math.min(value, 100)); // Lego Wedo 2.0 hub only turns motors at power range [30 - 100], so // map value from [0 - 100] to [30 - 100]. if (p === 0) { this._power = 0; } else { const delta = 100 / p; this._power = 30 + 70 / delta; } } /** * @return {boolean} - true if this motor is currently moving, false if this motor is off or braking. */ get isOn() { return this._isOn; } /** * @return {boolean} - time, in milliseconds, of when the pending timeout began. */ get pendingTimeoutStartTime() { return this._pendingTimeoutStartTime; } /** * @return {boolean} - delay, in milliseconds, of the pending timeout. */ get pendingTimeoutDelay() { return this._pendingTimeoutDelay; } /** * Turn this motor on indefinitely. */ turnOn() { if (this._power === 0) return; const cmd = this._parent.generateOutputCommand(this._index + 1, WeDo2Command.MOTOR_POWER, [this._power * this._direction] // power in range 0-100 ); this._parent.send(BLECharacteristic.OUTPUT_COMMAND, cmd); this._isOn = true; this._clearTimeout(); } /** * Turn this motor on for a specific duration. * @param {number} milliseconds - run the motor for this long. */ turnOnFor(milliseconds) { if (this._power === 0) return; milliseconds = Math.max(0, milliseconds); this.turnOn(); this._setNewTimeout(this.startBraking, milliseconds); } /** * Start active braking on this motor. After a short time, the motor will turn off. */ startBraking() { if (this._power === 0) return; const cmd = this._parent.generateOutputCommand(this._index + 1, WeDo2Command.MOTOR_POWER, [127] // 127 = break ); this._parent.send(BLECharacteristic.OUTPUT_COMMAND, cmd); this._isOn = false; this._setNewTimeout(this.turnOff, WeDo2Motor.BRAKE_TIME_MS); } /** * Turn this motor off. * @param {boolean} [useLimiter=true] - if true, use the rate limiter */ turnOff(useLimiter = true) { if (this._power === 0) return; const cmd = this._parent.generateOutputCommand(this._index + 1, WeDo2Command.MOTOR_POWER, [0] // 0 = stop ); this._parent.send(BLECharacteristic.OUTPUT_COMMAND, cmd, useLimiter); this._isOn = false; } /** * Clear the motor action timeout, if any. Safe to call even when there is no pending timeout. * @private */ _clearTimeout() { if (this._pendingTimeoutId !== null) { clearTimeout(this._pendingTimeoutId); this._pendingTimeoutId = null; this._pendingTimeoutStartTime = null; this._pendingTimeoutDelay = null; } } /** * Set a new motor action timeout, after clearing an existing one if necessary. * @param {Function} callback - to be called at the end of the timeout. * @param {int} delay - wait this many milliseconds before calling the callback. * @private */ _setNewTimeout(callback, delay) { this._clearTimeout(); const timeoutID = setTimeout(() => { if (this._pendingTimeoutId === timeoutID) { this._pendingTimeoutId = null; this._pendingTimeoutStartTime = null; this._pendingTimeoutDelay = null; } callback(); }, delay); this._pendingTimeoutId = timeoutID; this._pendingTimeoutStartTime = Date.now(); this._pendingTimeoutDelay = delay; } } /** * Manage communication with a WeDo 2.0 peripheral over a Bluetooth Low Energy client socket. */ class WeDo2 { constructor(runtime, extensionId) { /** * The Scratch 3.0 runtime used to trigger the green flag button. * @type {Runtime} * @private */ this._runtime = runtime; this._runtime.on('PROJECT_STOP_ALL', this.stopAll.bind(this)); /** * The id of the extension this peripheral belongs to. */ this._extensionId = extensionId; /** * A list of the ids of the motors or sensors in ports 1 and 2. * @type {string[]} * @private */ this._ports = ['none', 'none']; /** * The motors which this WeDo 2.0 could possibly have. * @type {WeDo2Motor[]} * @private */ this._motors = [null, null]; /** * The most recently received value for each sensor. * @type {Object.} * @private */ this._sensors = { tiltX: 0, tiltY: 0, distance: 0 }; /** * The Bluetooth connection socket for reading/writing peripheral data. * @type {BLE} * @private */ this._ble = null; this._runtime.registerPeripheralExtension(extensionId, this); /** * A rate limiter utility, to help limit the rate at which we send BLE messages * over the socket to Scratch Link to a maximum number of sends per second. * @type {RateLimiter} * @private */ this._rateLimiter = new RateLimiter(BLESendRateMax); /** * An interval id for the battery check interval. * @type {number} * @private */ this._batteryLevelIntervalId = null; this.reset = this.reset.bind(this); this._onConnect = this._onConnect.bind(this); this._onMessage = this._onMessage.bind(this); this._checkBatteryLevel = this._checkBatteryLevel.bind(this); } /** * @return {number} - the latest value received for the tilt sensor's tilt about the X axis. */ get tiltX() { return this._sensors.tiltX; } /** * @return {number} - the latest value received for the tilt sensor's tilt about the Y axis. */ get tiltY() { return this._sensors.tiltY; } /** * @return {number} - the latest value received from the distance sensor. */ get distance() { return this._sensors.distance; } /** * Access a particular motor on this peripheral. * @param {int} index - the zero-based index of the desired motor. * @return {WeDo2Motor} - the WeDo2Motor instance, if any, at that index. */ motor(index) { return this._motors[index]; } /** * Stop all the motors that are currently running. */ stopAllMotors() { this._motors.forEach(motor => { if (motor) { // Send the motor off command without using the rate limiter. // This allows the stop button to stop motors even if we are // otherwise flooded with commands. motor.turnOff(false); } }); } /** * Set the WeDo 2.0 peripheral's LED to a specific color. * @param {int} inputRGB - a 24-bit RGB color in 0xRRGGBB format. * @return {Promise} - a promise of the completion of the set led send operation. */ setLED(inputRGB) { const rgb = [inputRGB >> 16 & 0x000000FF, inputRGB >> 8 & 0x000000FF, inputRGB & 0x000000FF]; const cmd = this.generateOutputCommand(WeDo2ConnectID.LED, WeDo2Command.WRITE_RGB, rgb); return this.send(BLECharacteristic.OUTPUT_COMMAND, cmd); } /** * Sets the input mode of the LED to RGB. * @return {Promise} - a promise returned by the send operation. */ setLEDMode() { const cmd = this.generateInputCommand(WeDo2ConnectID.LED, WeDo2Device.LED, WeDo2Mode.LED, 0, WeDo2Unit.LED, false); return this.send(BLECharacteristic.INPUT_COMMAND, cmd); } /** * Switch off the LED on the WeDo 2.0. * @return {Promise} - a promise of the completion of the stop led send operation. */ stopLED() { const cmd = this.generateOutputCommand(WeDo2ConnectID.LED, WeDo2Command.WRITE_RGB, [0, 0, 0]); return this.send(BLECharacteristic.OUTPUT_COMMAND, cmd); } /** * Play a tone from the WeDo 2.0 peripheral for a specific amount of time. * @param {int} tone - the pitch of the tone, in Hz. * @param {int} milliseconds - the duration of the note, in milliseconds. * @return {Promise} - a promise of the completion of the play tone send operation. */ playTone(tone, milliseconds) { const cmd = this.generateOutputCommand(WeDo2ConnectID.PIEZO, WeDo2Command.PLAY_TONE, [tone, tone >> 8, milliseconds, milliseconds >> 8]); return this.send(BLECharacteristic.OUTPUT_COMMAND, cmd); } /** * Stop the tone playing from the WeDo 2.0 peripheral, if any. * @return {Promise} - a promise that the command sent. */ stopTone() { const cmd = this.generateOutputCommand(WeDo2ConnectID.PIEZO, WeDo2Command.STOP_TONE); // Send this command without using the rate limiter, because it is // only triggered by the stop button. return this.send(BLECharacteristic.OUTPUT_COMMAND, cmd, false); } /** * Stop the tone playing and motors on the WeDo 2.0 peripheral. */ stopAll() { if (!this.isConnected()) return; this.stopTone(); this.stopAllMotors(); } /** * Called by the runtime when user wants to scan for a WeDo 2.0 peripheral. */ scan() { if (this._ble) { this._ble.disconnect(); } this._ble = new BLE(this._runtime, this._extensionId, { filters: [{ services: [BLEService.DEVICE_SERVICE] }], optionalServices: [BLEService.IO_SERVICE] }, this._onConnect, this.reset); } /** * Called by the runtime when user wants to connect to a certain WeDo 2.0 peripheral. * @param {number} id - the id of the peripheral to connect to. */ connect(id) { if (this._ble) { this._ble.connectPeripheral(id); } } /** * Disconnects from the current BLE socket. */ disconnect() { if (this._ble) { this._ble.disconnect(); } this.reset(); } /** * Reset all the state and timeout/interval ids. */ reset() { this._ports = ['none', 'none']; this._motors = [null, null]; this._sensors = { tiltX: 0, tiltY: 0, distance: 0 }; if (this._batteryLevelIntervalId) { window.clearInterval(this._batteryLevelIntervalId); this._batteryLevelIntervalId = null; } } /** * Called by the runtime to detect whether the WeDo 2.0 peripheral is connected. * @return {boolean} - the connected state. */ isConnected() { let connected = false; if (this._ble) { connected = this._ble.isConnected(); } return connected; } /** * Write a message to the WeDo 2.0 peripheral BLE socket. * @param {number} uuid - the UUID of the characteristic to write to * @param {Array} message - the message to write. * @param {boolean} [useLimiter=true] - if true, use the rate limiter * @return {Promise} - a promise result of the write operation */ send(uuid, message, useLimiter = true) { if (!this.isConnected()) return Promise.resolve(); if (useLimiter) { if (!this._rateLimiter.okayToSend()) return Promise.resolve(); } return this._ble.write(BLEService.IO_SERVICE, uuid, Base64Util.uint8ArrayToBase64(message), 'base64'); } /** * Generate a WeDo 2.0 'Output Command' in the byte array format * (CONNECT ID, COMMAND ID, NUMBER OF BYTES, VALUES ...). * * This sends a command to the WeDo 2.0 to actuate the specified outputs. * * @param {number} connectID - the port (Connect ID) to send a command to. * @param {number} commandID - the id of the byte command. * @param {array} values - the list of values to write to the command. * @return {array} - a generated output command. */ generateOutputCommand(connectID, commandID, values = null) { let command = [connectID, commandID]; if (values) { command = command.concat(values.length).concat(values); } return command; } /** * Generate a WeDo 2.0 'Input Command' in the byte array format * (COMMAND ID, COMMAND TYPE, CONNECT ID, TYPE ID, MODE, DELTA INTERVAL (4 BYTES), * UNIT, NOTIFICATIONS ENABLED). * * This sends a command to the WeDo 2.0 that sets that input format * of the specified inputs and sets value change notifications. * * @param {number} connectID - the port (Connect ID) to send a command to. * @param {number} type - the type of input sensor. * @param {number} mode - the mode of the input sensor. * @param {number} delta - the delta change needed to trigger notification. * @param {array} units - the unit of the input sensor value. * @param {boolean} enableNotifications - whether to enable notifications. * @return {array} - a generated input command. */ generateInputCommand(connectID, type, mode, delta, units, enableNotifications) { const command = [1, // Command ID = 1 = "Sensor Format" 2, // Command Type = 2 = "Write" connectID, type, mode, delta, 0, // Delta Interval Byte 2 0, // Delta Interval Byte 3 0, // Delta Interval Byte 4 units, enableNotifications ? 1 : 0]; return command; } /** * Sets LED mode and initial color and starts reading data from peripheral after BLE has connected. * @private */ _onConnect() { this.setLEDMode(); this.setLED(0x0000FF); this._ble.startNotifications(BLEService.DEVICE_SERVICE, BLECharacteristic.ATTACHED_IO, this._onMessage); this._batteryLevelIntervalId = window.setInterval(this._checkBatteryLevel, BLEBatteryCheckInterval); } /** * Process the sensor data from the incoming BLE characteristic. * @param {object} base64 - the incoming BLE data. * @private */ _onMessage(base64) { const data = Base64Util.base64ToUint8Array(base64); // log.info(data); /** * If first byte of data is '1' or '2', then either clear the * sensor present in ports 1 or 2 or set their format. * * If first byte of data is anything else, read incoming sensor value. */ switch (data[0]) { case 1: case 2: { const connectID = data[0]; if (data[1] === 0) { // clear sensor or motor this._clearPort(connectID); } else { // register sensor or motor this._registerSensorOrMotor(connectID, data[3]); } break; } default: { // read incoming sensor value const connectID = data[1]; const type = this._ports[connectID - 1]; if (type === WeDo2Device.DISTANCE) { this._sensors.distance = data[2]; } if (type === WeDo2Device.TILT) { this._sensors.tiltX = data[2]; this._sensors.tiltY = data[3]; } break; } } } /** * Check the battery level on the WeDo 2.0. If the WeDo 2.0 has disconnected * for some reason, the BLE socket will get an error back and automatically * close the socket. */ _checkBatteryLevel() { this._ble.read(BLEService.DEVICE_SERVICE, BLECharacteristic.LOW_VOLTAGE_ALERT, false); } /** * Register a new sensor or motor connected at a port. Store the type of * sensor or motor internally, and then register for notifications on input * values if it is a sensor. * @param {number} connectID - the port to register a sensor or motor on. * @param {number} type - the type ID of the sensor or motor * @private */ _registerSensorOrMotor(connectID, type) { // Record which port is connected to what type of device this._ports[connectID - 1] = type; // Record motor port if (type === WeDo2Device.MOTOR) { this._motors[connectID - 1] = new WeDo2Motor(this, connectID - 1); } else { // Set input format for tilt or distance sensor const typeString = type === WeDo2Device.DISTANCE ? 'DISTANCE' : 'TILT'; const cmd = this.generateInputCommand(connectID, type, WeDo2Mode[typeString], 1, WeDo2Unit[typeString], true); this.send(BLECharacteristic.INPUT_COMMAND, cmd); this._ble.startNotifications(BLEService.IO_SERVICE, BLECharacteristic.INPUT_VALUES, this._onMessage); } } /** * Clear the sensor or motor present at port 1 or 2. * @param {number} connectID - the port to clear. * @private */ _clearPort(connectID) { const type = this._ports[connectID - 1]; if (type === WeDo2Device.TILT) { this._sensors.tiltX = this._sensors.tiltY = 0; } if (type === WeDo2Device.DISTANCE) { this._sensors.distance = 0; } this._ports[connectID - 1] = 'none'; this._motors[connectID - 1] = null; } } /** * Enum for motor specification. * @readonly * @enum {string} */ const WeDo2MotorLabel = { DEFAULT: 'motor', A: 'motor A', B: 'motor B', ALL: 'all motors' }; /** * Enum for motor direction specification. * @readonly * @enum {string} */ const WeDo2MotorDirection = { FORWARD: 'this way', BACKWARD: 'that way', REVERSE: 'reverse' }; /** * Enum for tilt sensor direction. * @readonly * @enum {string} */ const WeDo2TiltDirection = { UP: 'up', DOWN: 'down', LEFT: 'left', RIGHT: 'right', ANY: 'any' }; /** * Scratch 3.0 blocks to interact with a LEGO WeDo 2.0 peripheral. */ class Scratch3WeDo2Blocks { /** * @return {string} - the ID of this extension. */ static get EXTENSION_ID() { return 'wedo2'; } /** * @return {number} - the tilt sensor counts as "tilted" if its tilt angle meets or exceeds this threshold. */ static get TILT_THRESHOLD() { return 15; } /** * Construct a set of WeDo 2.0 blocks. * @param {Runtime} runtime - the Scratch 3.0 runtime. */ constructor(runtime) { /** * The Scratch 3.0 runtime. * @type {Runtime} */ this.runtime = runtime; // Create a new WeDo 2.0 peripheral instance this._peripheral = new WeDo2(this.runtime, Scratch3WeDo2Blocks.EXTENSION_ID); } /** * @returns {object} metadata for this extension and its blocks. */ getInfo() { return { id: Scratch3WeDo2Blocks.EXTENSION_ID, name: 'WeDo 2.0', blockIconURI: iconURI, showStatusButton: true, blocks: [{ opcode: 'motorOnFor', text: formatMessage({ id: 'wedo2.motorOnFor', default: 'turn [MOTOR_ID] on for [DURATION] seconds', description: 'turn a motor on for some time' }), blockType: BlockType.COMMAND, arguments: { MOTOR_ID: { type: ArgumentType.STRING, menu: 'MOTOR_ID', defaultValue: WeDo2MotorLabel.DEFAULT }, DURATION: { type: ArgumentType.NUMBER, defaultValue: 1 } } }, { opcode: 'motorOn', text: formatMessage({ id: 'wedo2.motorOn', default: 'turn [MOTOR_ID] on', description: 'turn a motor on indefinitely' }), blockType: BlockType.COMMAND, arguments: { MOTOR_ID: { type: ArgumentType.STRING, menu: 'MOTOR_ID', defaultValue: WeDo2MotorLabel.DEFAULT } } }, { opcode: 'motorOff', text: formatMessage({ id: 'wedo2.motorOff', default: 'turn [MOTOR_ID] off', description: 'turn a motor off' }), blockType: BlockType.COMMAND, arguments: { MOTOR_ID: { type: ArgumentType.STRING, menu: 'MOTOR_ID', defaultValue: WeDo2MotorLabel.DEFAULT } } }, { opcode: 'startMotorPower', text: formatMessage({ id: 'wedo2.startMotorPower', default: 'set [MOTOR_ID] power to [POWER]', description: 'set the motor\'s power and turn it on' }), blockType: BlockType.COMMAND, arguments: { MOTOR_ID: { type: ArgumentType.STRING, menu: 'MOTOR_ID', defaultValue: WeDo2MotorLabel.DEFAULT }, POWER: { type: ArgumentType.NUMBER, defaultValue: 100 } } }, { opcode: 'setMotorDirection', text: formatMessage({ id: 'wedo2.setMotorDirection', default: 'set [MOTOR_ID] direction to [MOTOR_DIRECTION]', description: 'set the motor\'s turn direction' }), blockType: BlockType.COMMAND, arguments: { MOTOR_ID: { type: ArgumentType.STRING, menu: 'MOTOR_ID', defaultValue: WeDo2MotorLabel.DEFAULT }, MOTOR_DIRECTION: { type: ArgumentType.STRING, menu: 'MOTOR_DIRECTION', defaultValue: WeDo2MotorDirection.FORWARD } } }, { opcode: 'setLightHue', text: formatMessage({ id: 'wedo2.setLightHue', default: 'set light color to [HUE]', description: 'set the LED color' }), blockType: BlockType.COMMAND, arguments: { HUE: { type: ArgumentType.NUMBER, defaultValue: 50 } } }, { opcode: 'playNoteFor', text: formatMessage({ id: 'wedo2.playNoteFor', default: 'play note [NOTE] for [DURATION] seconds', description: 'play a certain note for some time' }), blockType: BlockType.COMMAND, arguments: { NOTE: { type: ArgumentType.NUMBER, // TODO: ArgumentType.MIDI_NOTE? defaultValue: 60 }, DURATION: { type: ArgumentType.NUMBER, defaultValue: 0.5 } }, hideFromPalette: true }, { opcode: 'whenDistance', text: formatMessage({ id: 'wedo2.whenDistance', default: 'when distance [OP] [REFERENCE]', description: 'check for when distance is < or > than reference' }), blockType: BlockType.HAT, arguments: { OP: { type: ArgumentType.STRING, menu: 'OP', defaultValue: '<' }, REFERENCE: { type: ArgumentType.NUMBER, defaultValue: 50 } } }, { opcode: 'whenTilted', text: formatMessage({ id: 'wedo2.whenTilted', default: 'when tilted [TILT_DIRECTION_ANY]', description: 'check when tilted in a certain direction' }), func: 'isTilted', blockType: BlockType.HAT, arguments: { TILT_DIRECTION_ANY: { type: ArgumentType.STRING, menu: 'TILT_DIRECTION_ANY', defaultValue: WeDo2TiltDirection.ANY } } }, { opcode: 'getDistance', text: formatMessage({ id: 'wedo2.getDistance', default: 'distance', description: 'the value returned by the distance sensor' }), blockType: BlockType.REPORTER }, { opcode: 'isTilted', text: formatMessage({ id: 'wedo2.isTilted', default: 'tilted [TILT_DIRECTION_ANY]?', description: 'whether the tilt sensor is tilted' }), blockType: BlockType.BOOLEAN, arguments: { TILT_DIRECTION_ANY: { type: ArgumentType.STRING, menu: 'TILT_DIRECTION_ANY', defaultValue: WeDo2TiltDirection.ANY } } }, { opcode: 'getTiltAngle', text: formatMessage({ id: 'wedo2.getTiltAngle', default: 'tilt angle [TILT_DIRECTION]', description: 'the angle returned by the tilt sensor' }), blockType: BlockType.REPORTER, arguments: { TILT_DIRECTION: { type: ArgumentType.STRING, menu: 'TILT_DIRECTION', defaultValue: WeDo2TiltDirection.UP } } }], menus: { MOTOR_ID: { acceptReporters: true, items: [{ text: formatMessage({ id: 'wedo2.motorId.default', default: 'motor', description: 'label for motor element in motor menu for LEGO WeDo 2 extension' }), value: WeDo2MotorLabel.DEFAULT }, { text: formatMessage({ id: 'wedo2.motorId.a', default: 'motor A', description: 'label for motor A element in motor menu for LEGO WeDo 2 extension' }), value: WeDo2MotorLabel.A }, { text: formatMessage({ id: 'wedo2.motorId.b', default: 'motor B', description: 'label for motor B element in motor menu for LEGO WeDo 2 extension' }), value: WeDo2MotorLabel.B }, { text: formatMessage({ id: 'wedo2.motorId.all', default: 'all motors', description: 'label for all motors element in motor menu for LEGO WeDo 2 extension' }), value: WeDo2MotorLabel.ALL }] }, MOTOR_DIRECTION: { acceptReporters: true, items: [{ text: formatMessage({ id: 'wedo2.motorDirection.forward', default: 'this way', description: 'label for forward element in motor direction menu for LEGO WeDo 2 extension' }), value: WeDo2MotorDirection.FORWARD }, { text: formatMessage({ id: 'wedo2.motorDirection.backward', default: 'that way', description: 'label for backward element in motor direction menu for LEGO WeDo 2 extension' }), value: WeDo2MotorDirection.BACKWARD }, { text: formatMessage({ id: 'wedo2.motorDirection.reverse', default: 'reverse', description: 'label for reverse element in motor direction menu for LEGO WeDo 2 extension' }), value: WeDo2MotorDirection.REVERSE }] }, TILT_DIRECTION: { acceptReporters: true, items: [{ text: formatMessage({ id: 'wedo2.tiltDirection.up', default: 'up', description: 'label for up element in tilt direction menu for LEGO WeDo 2 extension' }), value: WeDo2TiltDirection.UP }, { text: formatMessage({ id: 'wedo2.tiltDirection.down', default: 'down', description: 'label for down element in tilt direction menu for LEGO WeDo 2 extension' }), value: WeDo2TiltDirection.DOWN }, { text: formatMessage({ id: 'wedo2.tiltDirection.left', default: 'left', description: 'label for left element in tilt direction menu for LEGO WeDo 2 extension' }), value: WeDo2TiltDirection.LEFT }, { text: formatMessage({ id: 'wedo2.tiltDirection.right', default: 'right', description: 'label for right element in tilt direction menu for LEGO WeDo 2 extension' }), value: WeDo2TiltDirection.RIGHT }] }, TILT_DIRECTION_ANY: { acceptReporters: true, items: [{ text: formatMessage({ id: 'wedo2.tiltDirection.up', default: 'up' }), value: WeDo2TiltDirection.UP }, { text: formatMessage({ id: 'wedo2.tiltDirection.down', default: 'down' }), value: WeDo2TiltDirection.DOWN }, { text: formatMessage({ id: 'wedo2.tiltDirection.left', default: 'left' }), value: WeDo2TiltDirection.LEFT }, { text: formatMessage({ id: 'wedo2.tiltDirection.right', default: 'right' }), value: WeDo2TiltDirection.RIGHT }, { text: formatMessage({ id: 'wedo2.tiltDirection.any', default: 'any', description: 'label for any element in tilt direction menu for LEGO WeDo 2 extension' }), value: WeDo2TiltDirection.ANY }] }, OP: { acceptReporters: true, items: ['<', '>'] } } }; } /** * Turn specified motor(s) on for a specified duration. * @param {object} args - the block's arguments. * @property {MotorID} MOTOR_ID - the motor(s) to activate. * @property {int} DURATION - the amount of time to run the motors. * @return {Promise} - a promise which will resolve at the end of the duration. */ motorOnFor(args) { // TODO: cast args.MOTOR_ID? let durationMS = Cast.toNumber(args.DURATION) * 1000; durationMS = MathUtil.clamp(durationMS, 0, 15000); return new Promise(resolve => { this._forEachMotor(args.MOTOR_ID, motorIndex => { const motor = this._peripheral.motor(motorIndex); if (motor) { motor.turnOnFor(durationMS); } }); // Run for some time even when no motor is connected setTimeout(resolve, durationMS); }); } /** * Turn specified motor(s) on indefinitely. * @param {object} args - the block's arguments. * @property {MotorID} MOTOR_ID - the motor(s) to activate. * @return {Promise} - a Promise that resolves after some delay. */ motorOn(args) { // TODO: cast args.MOTOR_ID? this._forEachMotor(args.MOTOR_ID, motorIndex => { const motor = this._peripheral.motor(motorIndex); if (motor) { motor.turnOn(); } }); return new Promise(resolve => { window.setTimeout(() => { resolve(); }, BLESendInterval); }); } /** * Turn specified motor(s) off. * @param {object} args - the block's arguments. * @property {MotorID} MOTOR_ID - the motor(s) to deactivate. * @return {Promise} - a Promise that resolves after some delay. */ motorOff(args) { // TODO: cast args.MOTOR_ID? this._forEachMotor(args.MOTOR_ID, motorIndex => { const motor = this._peripheral.motor(motorIndex); if (motor) { motor.turnOff(); } }); return new Promise(resolve => { window.setTimeout(() => { resolve(); }, BLESendInterval); }); } /** * Turn specified motor(s) off. * @param {object} args - the block's arguments. * @property {MotorID} MOTOR_ID - the motor(s) to be affected. * @property {int} POWER - the new power level for the motor(s). * @return {Promise} - a Promise that resolves after some delay. */ startMotorPower(args) { // TODO: cast args.MOTOR_ID? this._forEachMotor(args.MOTOR_ID, motorIndex => { const motor = this._peripheral.motor(motorIndex); if (motor) { motor.power = MathUtil.clamp(Cast.toNumber(args.POWER), 0, 100); motor.turnOn(); } }); return new Promise(resolve => { window.setTimeout(() => { resolve(); }, BLESendInterval); }); } /** * Set the direction of rotation for specified motor(s). * If the direction is 'reverse' the motor(s) will be reversed individually. * @param {object} args - the block's arguments. * @property {MotorID} MOTOR_ID - the motor(s) to be affected. * @property {MotorDirection} MOTOR_DIRECTION - the new direction for the motor(s). * @return {Promise} - a Promise that resolves after some delay. */ setMotorDirection(args) { // TODO: cast args.MOTOR_ID? this._forEachMotor(args.MOTOR_ID, motorIndex => { const motor = this._peripheral.motor(motorIndex); if (motor) { switch (args.MOTOR_DIRECTION) { case WeDo2MotorDirection.FORWARD: motor.direction = 1; break; case WeDo2MotorDirection.BACKWARD: motor.direction = -1; break; case WeDo2MotorDirection.REVERSE: motor.direction = -motor.direction; break; default: log.warn("Unknown motor direction in setMotorDirection: ".concat(args.DIRECTION)); break; } // keep the motor on if it's running, and update the pending timeout if needed if (motor.isOn) { if (motor.pendingTimeoutDelay) { motor.turnOnFor(motor.pendingTimeoutStartTime + motor.pendingTimeoutDelay - Date.now()); } else { motor.turnOn(); } } } }); return new Promise(resolve => { window.setTimeout(() => { resolve(); }, BLESendInterval); }); } /** * Set the LED's hue. * @param {object} args - the block's arguments. * @property {number} HUE - the hue to set, in the range [0,100]. * @return {Promise} - a Promise that resolves after some delay. */ setLightHue(args) { // Convert from [0,100] to [0,360] let inputHue = Cast.toNumber(args.HUE); inputHue = MathUtil.wrapClamp(inputHue, 0, 100); const hue = inputHue * 360 / 100; const rgbObject = color.hsvToRgb({ h: hue, s: 1, v: 1 }); const rgbDecimal = color.rgbToDecimal(rgbObject); this._peripheral.setLED(rgbDecimal); return new Promise(resolve => { window.setTimeout(() => { resolve(); }, BLESendInterval); }); } /** * Make the WeDo 2.0 peripheral play a MIDI note for the specified duration. * @param {object} args - the block's arguments. * @property {number} NOTE - the MIDI note to play. * @property {number} DURATION - the duration of the note, in seconds. * @return {Promise} - a promise which will resolve at the end of the duration. */ playNoteFor(args) { let durationMS = Cast.toNumber(args.DURATION) * 1000; durationMS = MathUtil.clamp(durationMS, 0, 3000); const note = MathUtil.clamp(Cast.toNumber(args.NOTE), 25, 125); // valid WeDo 2.0 sounds if (durationMS === 0) return; // WeDo 2.0 plays duration '0' forever return new Promise(resolve => { const tone = this._noteToTone(note); this._peripheral.playTone(tone, durationMS); // Run for some time even when no piezo is connected setTimeout(resolve, durationMS); }); } /** * Compare the distance sensor's value to a reference. * @param {object} args - the block's arguments. * @property {string} OP - the comparison operation: '<' or '>'. * @property {number} REFERENCE - the value to compare against. * @return {boolean} - the result of the comparison, or false on error. */ whenDistance(args) { switch (args.OP) { case '<': return this._peripheral.distance < Cast.toNumber(args.REFERENCE); case '>': return this._peripheral.distance > Cast.toNumber(args.REFERENCE); default: log.warn("Unknown comparison operator in whenDistance: ".concat(args.OP)); return false; } } /** * Test whether the tilt sensor is currently tilted. * @param {object} args - the block's arguments. * @property {TiltDirection} TILT_DIRECTION_ANY - the tilt direction to test (up, down, left, right, or any). * @return {boolean} - true if the tilt sensor is tilted past a threshold in the specified direction. */ whenTilted(args) { return this._isTilted(args.TILT_DIRECTION_ANY); } /** * @return {number} - the distance sensor's value, scaled to the [0,100] range. */ getDistance() { return this._peripheral.distance; } /** * Test whether the tilt sensor is currently tilted. * @param {object} args - the block's arguments. * @property {TiltDirection} TILT_DIRECTION_ANY - the tilt direction to test (up, down, left, right, or any). * @return {boolean} - true if the tilt sensor is tilted past a threshold in the specified direction. */ isTilted(args) { return this._isTilted(args.TILT_DIRECTION_ANY); } /** * @param {object} args - the block's arguments. * @property {TiltDirection} TILT_DIRECTION - the direction (up, down, left, right) to check. * @return {number} - the tilt sensor's angle in the specified direction. * Note that getTiltAngle(up) = -getTiltAngle(down) and getTiltAngle(left) = -getTiltAngle(right). */ getTiltAngle(args) { return this._getTiltAngle(args.TILT_DIRECTION); } /** * Test whether the tilt sensor is currently tilted. * @param {TiltDirection} direction - the tilt direction to test (up, down, left, right, or any). * @return {boolean} - true if the tilt sensor is tilted past a threshold in the specified direction. * @private */ _isTilted(direction) { switch (direction) { case WeDo2TiltDirection.ANY: return this._getTiltAngle(WeDo2TiltDirection.UP) >= Scratch3WeDo2Blocks.TILT_THRESHOLD || this._getTiltAngle(WeDo2TiltDirection.DOWN) >= Scratch3WeDo2Blocks.TILT_THRESHOLD || this._getTiltAngle(WeDo2TiltDirection.LEFT) >= Scratch3WeDo2Blocks.TILT_THRESHOLD || this._getTiltAngle(WeDo2TiltDirection.RIGHT) >= Scratch3WeDo2Blocks.TILT_THRESHOLD; default: return this._getTiltAngle(direction) >= Scratch3WeDo2Blocks.TILT_THRESHOLD; } } /** * @param {TiltDirection} direction - the direction (up, down, left, right) to check. * @return {number} - the tilt sensor's angle in the specified direction. * Note that getTiltAngle(up) = -getTiltAngle(down) and getTiltAngle(left) = -getTiltAngle(right). * @private */ _getTiltAngle(direction) { switch (direction) { case WeDo2TiltDirection.UP: return this._peripheral.tiltY > 45 ? 256 - this._peripheral.tiltY : -this._peripheral.tiltY; case WeDo2TiltDirection.DOWN: return this._peripheral.tiltY > 45 ? this._peripheral.tiltY - 256 : this._peripheral.tiltY; case WeDo2TiltDirection.LEFT: return this._peripheral.tiltX > 45 ? 256 - this._peripheral.tiltX : -this._peripheral.tiltX; case WeDo2TiltDirection.RIGHT: return this._peripheral.tiltX > 45 ? this._peripheral.tiltX - 256 : this._peripheral.tiltX; default: log.warn("Unknown tilt direction in _getTiltAngle: ".concat(direction)); } } /** * Call a callback for each motor indexed by the provided motor ID. * @param {MotorID} motorID - the ID specifier. * @param {Function} callback - the function to call with the numeric motor index for each motor. * @private */ _forEachMotor(motorID, callback) { let motors; switch (motorID) { case WeDo2MotorLabel.A: motors = [0]; break; case WeDo2MotorLabel.B: motors = [1]; break; case WeDo2MotorLabel.ALL: case WeDo2MotorLabel.DEFAULT: motors = [0, 1]; break; default: log.warn("Invalid motor ID: ".concat(motorID)); motors = []; break; } for (const index of motors) { callback(index); } } /** * @param {number} midiNote - the MIDI note value to convert. * @return {number} - the frequency, in Hz, corresponding to that MIDI note value. * @private */ _noteToTone(midiNote) { // Note that MIDI note 69 is A4, 440 Hz return 440 * Math.pow(2, (midiNote - 69) / 12); } } module.exports = Scratch3WeDo2Blocks; /***/ }), /***/ "./node_modules/scratch-vm/src/extensions/tw/index.js": /*!************************************************************!*\ !*** ./node_modules/scratch-vm/src/extensions/tw/index.js ***! \************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const formatMessage = __webpack_require__(/*! format-message */ "./node_modules/format-message/index.js"); const BlockType = __webpack_require__(/*! ../../extension-support/block-type */ "./node_modules/scratch-vm/src/extension-support/block-type.js"); const ArgumentType = __webpack_require__(/*! ../../extension-support/argument-type */ "./node_modules/scratch-vm/src/extension-support/argument-type.js"); const Cast = __webpack_require__(/*! ../../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); /** * Class for TurboWarp blocks * @constructor */ class TurboWarpBlocks { constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; } /** * @returns {object} metadata for this extension and its blocks. */ getInfo() { return { id: 'tw', name: 'TurboWarp', color1: '#ff4c4c', color2: '#e64444', docsURI: 'https://docs.turbowarp.org/blocks', blocks: [{ opcode: 'getLastKeyPressed', text: formatMessage({ id: 'tw.blocks.lastKeyPressed', default: 'last key pressed', description: 'Block that returns the last key that was pressed' }), blockType: BlockType.REPORTER }, { opcode: 'getButtonIsDown', text: formatMessage({ id: 'tw.blocks.buttonIsDown', default: '[MOUSE_BUTTON] mouse button down?', description: 'Block that returns whether a specific mouse button is down' }), blockType: BlockType.BOOLEAN, arguments: { MOUSE_BUTTON: { type: ArgumentType.NUMBER, menu: 'mouseButton', defaultValue: '0' } } }], menus: { mouseButton: { items: [{ text: formatMessage({ id: 'tw.blocks.mouseButton.primary', default: '(0) primary', description: 'Dropdown item to select primary (usually left) mouse button' }), value: '0' }, { text: formatMessage({ id: 'tw.blocks.mouseButton.middle', default: '(1) middle', description: 'Dropdown item to select middle mouse button' }), value: '1' }, { text: formatMessage({ id: 'tw.blocks.mouseButton.secondary', default: '(2) secondary', description: 'Dropdown item to select secondary (usually right) mouse button' }), value: '2' }], acceptReporters: true } } }; } getLastKeyPressed(args, util) { return util.ioQuery('keyboard', 'getLastKeyPressed'); } getButtonIsDown(args, util) { const button = Cast.toNumber(args.MOUSE_BUTTON); return util.ioQuery('mouse', 'getButtonIsDown', [button]); } } module.exports = TurboWarpBlocks; /***/ }), /***/ "./node_modules/scratch-vm/src/import/load-costume.js": /*!************************************************************!*\ !*** ./node_modules/scratch-vm/src/import/load-costume.js ***! \************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const StringUtil = __webpack_require__(/*! ../util/string-util */ "./node_modules/scratch-vm/src/util/string-util.js"); const log = __webpack_require__(/*! ../util/log */ "./node_modules/scratch-vm/src/util/log.js"); const AsyncLimiter = __webpack_require__(/*! ../util/async-limiter */ "./node_modules/scratch-vm/src/util/async-limiter.js"); const { loadSvgString, serializeSvgToString } = __webpack_require__(/*! scratch-svg-renderer */ "./node_modules/scratch-svg-renderer/src/index.js"); const { parseVectorMetadata } = __webpack_require__(/*! ../serialization/tw-costume-import-export */ "./node_modules/scratch-vm/src/serialization/tw-costume-import-export.js"); const loadVector_ = function loadVector_(costume, runtime, rotationCenter, optVersion) { return new Promise(resolve => { let svgString = costume.asset.decodeText(); // TW: We allow SVGs to specify their rotation center using a special comment. if (typeof rotationCenter === 'undefined') { const parsedRotationCenter = parseVectorMetadata(svgString); if (parsedRotationCenter) { rotationCenter = parsedRotationCenter; costume.rotationCenterX = rotationCenter[0]; costume.rotationCenterY = rotationCenter[1]; } } // SVG Renderer load fixes "quirks" associated with Scratch 2 projects if (optVersion && optVersion === 2) { // scratch-svg-renderer fixes syntax that causes loading issues, // and if optVersion is 2, fixes "quirks" associated with Scratch 2 SVGs, const fixedSvgString = serializeSvgToString(loadSvgString(svgString, true /* fromVersion2 */ )); // If the string changed, put back into storage if (svgString !== fixedSvgString) { svgString = fixedSvgString; const storage = runtime.storage; costume.asset.encodeTextData(fixedSvgString, storage.DataFormat.SVG, true); costume.assetId = costume.asset.assetId; costume.md5 = "".concat(costume.assetId, ".").concat(costume.dataFormat); } } // createSVGSkin does the right thing if rotationCenter isn't provided, so it's okay if it's // undefined here costume.skinId = runtime.renderer.createSVGSkin(svgString, rotationCenter); costume.size = runtime.renderer.getSkinSize(costume.skinId); // Now we should have a rotationCenter even if we didn't before if (!rotationCenter) { rotationCenter = runtime.renderer.getSkinRotationCenter(costume.skinId); costume.rotationCenterX = rotationCenter[0]; costume.rotationCenterY = rotationCenter[1]; costume.bitmapResolution = 1; } if (runtime.isPackaged) { costume.asset = null; } resolve(costume); }); }; const canvasPool = function () { /** * A pool of canvas objects that can be reused to reduce memory * allocations. And time spent in those allocations and the later garbage * collection. */ class CanvasPool { constructor() { this.pool = []; this.clearSoon = null; } /** * After a short wait period clear the pool to let the VM collect * garbage. */ clear() { if (!this.clearSoon) { this.clearSoon = new Promise(resolve => setTimeout(resolve, 1000)).then(() => { this.pool.length = 0; this.clearSoon = null; }); } } /** * Return a canvas. Create the canvas if the pool is empty. * @returns {HTMLCanvasElement} A canvas element. */ create() { return this.pool.pop() || document.createElement('canvas'); } /** * Release the canvas to be reused. * @param {HTMLCanvasElement} canvas A canvas element. */ release(canvas) { this.clear(); this.pool.push(canvas); } } return new CanvasPool(); }(); /** * @param {string} src URL of image * @returns {Promise} */ const readAsImageElement = src => new Promise((resolve, reject) => { const image = new Image(); image.onload = function () { resolve(image); image.onload = null; image.onerror = null; }; image.onerror = function () { reject(new Error('Costume load failed. Asset could not be read.')); image.onload = null; image.onerror = null; }; image.src = src; }); /** * @param {Asset} asset scratch-storage asset * @returns {Promise} */ const _persistentReadImage = async asset => { // Sometimes, when a lot of images are loaded at once, especially in Chrome, reading an image // can throw an error even on valid images. To mitigate this, we'll retry image reading a few // time with delays. let firstError; for (let i = 0; i < 3; i++) { try { if (typeof createImageBitmap === 'function') { const imageBitmap = await createImageBitmap(new Blob([asset.data.buffer], { type: asset.assetType.contentType })); // If we do too many createImageBitmap at the same time, some browsers (Chrome) will // sometimes resolve with undefined. We limit concurrency so this shouldn't ever // happen, but if it somehow does, throw an error so it can be retried or so that it // falls back to scratch's broken costume handling. if (!imageBitmap) { throw new Error("createImageBitmap resolved with ".concat(imageBitmap)); } return imageBitmap; } return await readAsImageElement(asset.encodeDataURI()); } catch (e) { if (!firstError) { firstError = e; } log.warn(e); await new Promise(resolve => setTimeout(resolve, Math.random() * 2000)); } } throw firstError; }; // Browsers break when we do too many createImageBitmap at the same time. const readImage = new AsyncLimiter(_persistentReadImage, 25); /** * Return a promise to fetch a bitmap from storage and return it as a canvas * If the costume has bitmapResolution 1, it will be converted to bitmapResolution 2 here (the standard for Scratch 3) * If the costume has a text layer asset, which is a text part from Scratch 1.4, then this function * will merge the two image assets. See the issue LLK/scratch-vm#672 for more information. * @param {!object} costume - the Scratch costume object. * @param {!Runtime} runtime - Scratch runtime, used to access the v2BitmapAdapter * @param {?object} rotationCenter - optionally passed in coordinates for the center of rotation for the image. If * none is given, the rotation center of the costume will be set to the middle of the costume later on. * @property {number} costume.bitmapResolution - the resolution scale for a bitmap costume. * @returns {?Promise} - a promise which will resolve to an object {canvas, rotationCenter, assetMatchesBase}, * or reject on error. * assetMatchesBase is true if the asset matches the base layer; false if it required adjustment */ const fetchBitmapCanvas_ = function fetchBitmapCanvas_(costume, runtime, rotationCenter) { if (!costume || !costume.asset) { // TODO: We can probably remove this check... return Promise.reject('Costume load failed. Assets were missing.'); } if (!runtime.v2BitmapAdapter) { return Promise.reject('No V2 Bitmap adapter present.'); } return Promise.all([costume.asset, costume.textLayerAsset].map(asset => { if (!asset) { return null; } return readImage.do(asset); })).then(([baseImageElement, textImageElement]) => { if (!baseImageElement) { throw new Error('Loading bitmap costume base failed.'); } const scale = costume.bitmapResolution === 1 ? 2 : 1; let imageOrCanvas; let canvas; if (textImageElement) { canvas = canvasPool.create(); canvas.width = baseImageElement.width; canvas.height = baseImageElement.height; const ctx = canvas.getContext('2d'); ctx.drawImage(baseImageElement, 0, 0); ctx.drawImage(textImageElement, 0, 0); imageOrCanvas = canvas; } else { imageOrCanvas = baseImageElement; } if (scale !== 1) { // resize() returns a new canvas. imageOrCanvas = runtime.v2BitmapAdapter.resize(imageOrCanvas, imageOrCanvas.width * scale, imageOrCanvas.height * scale); // Old canvas is no longer used. if (canvas) { canvasPool.release(canvas); } } // This informs TurboWarp/scratch-render that this canvas won't be reused by the canvas pool, // which helps it optimize memory use. imageOrCanvas.reusable = false; // By scaling, we've converted it to bitmap resolution 2 if (rotationCenter) { rotationCenter[0] = rotationCenter[0] * scale; rotationCenter[1] = rotationCenter[1] * scale; costume.rotationCenterX = rotationCenter[0]; costume.rotationCenterY = rotationCenter[1]; } costume.bitmapResolution = 2; // Clean up the costume object delete costume.textLayerMD5; delete costume.textLayerAsset; return { image: imageOrCanvas, rotationCenter, // True if the asset matches the base layer; false if it required adjustment assetMatchesBase: scale === 1 && !textImageElement }; }).finally(() => { // Clean up the text layer properties if it fails to load delete costume.textLayerMD5; delete costume.textLayerAsset; }); }; const toDataURL = imageOrCanvas => { if (imageOrCanvas instanceof HTMLCanvasElement) { return imageOrCanvas.toDataURL(); } const canvas = canvasPool.create(); canvas.width = imageOrCanvas.width; canvas.height = imageOrCanvas.height; const ctx = canvas.getContext('2d'); ctx.drawImage(imageOrCanvas, 0, 0); const url = canvas.toDataURL(); canvasPool.release(canvas); return url; }; const loadBitmap_ = function loadBitmap_(costume, runtime, _rotationCenter) { return fetchBitmapCanvas_(costume, runtime, _rotationCenter).then(fetched => { const updateCostumeAsset = function updateCostumeAsset(dataURI) { if (!runtime.v2BitmapAdapter) { // TODO: This might be a bad practice since the returned // promise isn't acted on. If this is something we should be // creating a rejected promise for we should also catch it // somewhere and act on that error (like logging). // // Return a rejection to stop executing updateCostumeAsset. return Promise.reject('No V2 Bitmap adapter present.'); } const storage = runtime.storage; costume.asset = storage.createAsset(storage.AssetType.ImageBitmap, storage.DataFormat.PNG, runtime.v2BitmapAdapter.convertDataURIToBinary(dataURI), null, true // generate md5 ); costume.dataFormat = storage.DataFormat.PNG; costume.assetId = costume.asset.assetId; costume.md5 = "".concat(costume.assetId, ".").concat(costume.dataFormat); }; if (!fetched.assetMatchesBase) { updateCostumeAsset(toDataURL(fetched.image)); } return fetched; }).then(({ image, rotationCenter }) => { // createBitmapSkin does the right thing if costume.rotationCenter is undefined. // That will be the case if you upload a bitmap asset or create one by taking a photo. let center; if (rotationCenter) { // fetchBitmapCanvas will ensure that the costume's bitmap resolution is 2 and its rotation center is // scaled to match, so it's okay to always divide by 2. center = [rotationCenter[0] / 2, rotationCenter[1] / 2]; } // TODO: costume.bitmapResolution will always be 2 at this point because of fetchBitmapCanvas_, so we don't // need to pass it in here. costume.skinId = runtime.renderer.createBitmapSkin(image, costume.bitmapResolution, center); const renderSize = runtime.renderer.getSkinSize(costume.skinId); costume.size = [renderSize[0] * 2, renderSize[1] * 2]; // Actual size, since all bitmaps are resolution 2 if (!rotationCenter) { rotationCenter = runtime.renderer.getSkinRotationCenter(costume.skinId); // Actual rotation center, since all bitmaps are resolution 2 costume.rotationCenterX = rotationCenter[0] * 2; costume.rotationCenterY = rotationCenter[1] * 2; costume.bitmapResolution = 2; } if (runtime.isPackaged) { costume.asset = null; } return costume; }); }; // Handle all manner of costume errors with a Gray Question Mark (default costume) // and preserve as much of the original costume data as possible // Returns a promise of a costume const handleCostumeLoadError = function handleCostumeLoadError(costume, runtime) { // Keep track of the old asset information until we're done loading the default costume const oldAsset = costume.asset; // could be null const oldAssetId = costume.assetId; const oldRotationX = costume.rotationCenterX; const oldRotationY = costume.rotationCenterY; const oldBitmapResolution = costume.bitmapResolution; const oldDataFormat = costume.dataFormat; const AssetType = runtime.storage.AssetType; const isVector = costume.dataFormat === AssetType.ImageVector.runtimeFormat; // Use default asset if original fails to load costume.assetId = isVector ? runtime.storage.defaultAssetId.ImageVector : runtime.storage.defaultAssetId.ImageBitmap; costume.asset = runtime.storage.get(costume.assetId); costume.md5 = "".concat(costume.assetId, ".").concat(costume.asset.dataFormat); const defaultCostumePromise = isVector ? loadVector_(costume, runtime) : loadBitmap_(costume, runtime); return defaultCostumePromise.then(loadedCostume => { loadedCostume.broken = {}; loadedCostume.broken.assetId = oldAssetId; loadedCostume.broken.md5 = "".concat(oldAssetId, ".").concat(oldDataFormat); // Should be null if we got here because the costume was missing loadedCostume.broken.asset = oldAsset; loadedCostume.broken.dataFormat = oldDataFormat; loadedCostume.broken.rotationCenterX = oldRotationX; loadedCostume.broken.rotationCenterY = oldRotationY; loadedCostume.broken.bitmapResolution = oldBitmapResolution; return loadedCostume; }); }; /** * Initialize a costume from an asset asynchronously. * Do not call this unless there is a renderer attached. * @param {!object} costume - the Scratch costume object. * @property {int} skinId - the ID of the costume's render skin, once installed. * @property {number} rotationCenterX - the X component of the costume's origin. * @property {number} rotationCenterY - the Y component of the costume's origin. * @property {number} [bitmapResolution] - the resolution scale for a bitmap costume. * @property {!Asset} costume.asset - the asset of the costume loaded from storage. * @param {!Runtime} runtime - Scratch runtime, used to access the storage module. * @param {?int} optVersion - Version of Scratch that the costume comes from. If this is set * to 2, scratch 3 will perform an upgrade step to handle quirks in SVGs from Scratch 2.0. * @returns {?Promise} - a promise which will resolve after skinId is set, or null on error. */ const loadCostumeFromAsset = function loadCostumeFromAsset(costume, runtime, optVersion) { costume.assetId = costume.asset.assetId; const renderer = runtime.renderer; if (!renderer) { log.warn('No rendering module present; cannot load costume: ', costume.name); return Promise.resolve(costume); } const AssetType = runtime.storage.AssetType; let rotationCenter; // Use provided rotation center and resolution if they are defined. Bitmap resolution // should only ever be 1 or 2. if (typeof costume.rotationCenterX === 'number' && !isNaN(costume.rotationCenterX) && typeof costume.rotationCenterY === 'number' && !isNaN(costume.rotationCenterY)) { rotationCenter = [costume.rotationCenterX, costume.rotationCenterY]; } if (costume.asset.assetType.runtimeFormat === AssetType.ImageVector.runtimeFormat) { return loadVector_(costume, runtime, rotationCenter, optVersion).catch(error => { log.warn("Error loading vector image: ".concat(error)); return handleCostumeLoadError(costume, runtime); }); } return loadBitmap_(costume, runtime, rotationCenter, optVersion).catch(error => { log.warn("Error loading bitmap image: ".concat(error)); return handleCostumeLoadError(costume, runtime); }); }; /** * Load a costume's asset into memory asynchronously. * Do not call this unless there is a renderer attached. * @param {!string} md5ext - the MD5 and extension of the costume to be loaded. * @param {!object} costume - the Scratch costume object. * @property {int} skinId - the ID of the costume's render skin, once installed. * @property {number} rotationCenterX - the X component of the costume's origin. * @property {number} rotationCenterY - the Y component of the costume's origin. * @property {number} [bitmapResolution] - the resolution scale for a bitmap costume. * @param {!Runtime} runtime - Scratch runtime, used to access the storage module. * @param {?int} optVersion - Version of Scratch that the costume comes from. If this is set * to 2, scratch 3 will perform an upgrade step to handle quirks in SVGs from Scratch 2.0. * @returns {?Promise} - a promise which will resolve after skinId is set, or null on error. */ const loadCostume = function loadCostume(md5ext, costume, runtime, optVersion) { const idParts = StringUtil.splitFirst(md5ext, '.'); const md5 = idParts[0]; const ext = idParts[1].toLowerCase(); costume.dataFormat = ext; if (costume.asset) { // Costume comes with asset. It could be coming from image upload, drag and drop, or file return loadCostumeFromAsset(costume, runtime, optVersion); } // Need to load the costume from storage. The server should have a reference to this md5. if (!runtime.storage) { log.warn('No storage module present; cannot load costume asset: ', md5ext); return Promise.resolve(costume); } if (!runtime.storage.defaultAssetId) { log.warn("No default assets found"); return Promise.resolve(costume); } const AssetType = runtime.storage.AssetType; const assetType = ext === 'svg' ? AssetType.ImageVector : AssetType.ImageBitmap; const costumePromise = runtime.storage.load(assetType, md5, ext); let textLayerPromise; if (costume.textLayerMD5) { textLayerPromise = runtime.storage.load(AssetType.ImageBitmap, costume.textLayerMD5, 'png'); } else { textLayerPromise = Promise.resolve(null); } return Promise.all([costumePromise, textLayerPromise]).then(assetArray => { if (assetArray[0]) { costume.asset = assetArray[0]; } else { return handleCostumeLoadError(costume, runtime); } if (assetArray[1]) { costume.textLayerAsset = assetArray[1]; } return loadCostumeFromAsset(costume, runtime, optVersion); }).catch(error => { // Handle case where storage.load rejects with errors // instead of resolving null log.warn('Error loading costume: ', error); return handleCostumeLoadError(costume, runtime); }); }; module.exports = { loadCostume, loadCostumeFromAsset }; /***/ }), /***/ "./node_modules/scratch-vm/src/import/load-sound.js": /*!**********************************************************!*\ !*** ./node_modules/scratch-vm/src/import/load-sound.js ***! \**********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const StringUtil = __webpack_require__(/*! ../util/string-util */ "./node_modules/scratch-vm/src/util/string-util.js"); const log = __webpack_require__(/*! ../util/log */ "./node_modules/scratch-vm/src/util/log.js"); /** * Initialize a sound from an asset asynchronously. * @param {!object} sound - the Scratch sound object. * @property {string} md5 - the MD5 and extension of the sound to be loaded. * @property {Buffer} data - sound data will be written here once loaded. * @param {!Asset} soundAsset - the asset loaded from storage. * @param {!Runtime} runtime - Scratch runtime, used to access the storage module. * @param {SoundBank} soundBank - Scratch Audio SoundBank to add sounds to. * @returns {!Promise} - a promise which will resolve to the sound when ready. */ const loadSoundFromAsset = function loadSoundFromAsset(sound, soundAsset, runtime, soundBank) { sound.assetId = soundAsset.assetId; if (!runtime.audioEngine) { log.warn('No audio engine present; cannot load sound asset: ', sound.md5); return Promise.resolve(sound); } return runtime.audioEngine.decodeSoundPlayer(Object.assign({}, sound, { data: soundAsset.data })).then(soundPlayer => { sound.soundId = soundPlayer.id; // Set the sound sample rate and sample count based on the // the audio buffer from the audio engine since the sound // gets resampled by the audio engine const soundBuffer = soundPlayer.buffer; sound.rate = soundBuffer.sampleRate; sound.sampleCount = soundBuffer.length; if (soundBank !== null) { soundBank.addSoundPlayer(soundPlayer); } if (runtime.isPackaged) { sound.asset = null; } return sound; }); }; // Handle sound loading errors by replacing the runtime sound with the // default sound from storage, but keeping track of the original sound metadata // in a `broken` field const handleSoundLoadError = function handleSoundLoadError(sound, runtime, soundBank) { // Keep track of the old asset information until we're done loading the default sound const oldAsset = sound.asset; // could be null const oldAssetId = sound.assetId; const oldSample = sound.sampleCount; const oldRate = sound.rate; const oldFormat = sound.format; const oldDataFormat = sound.dataFormat; // Use default asset if original fails to load sound.assetId = runtime.storage.defaultAssetId.Sound; sound.asset = runtime.storage.get(sound.assetId); sound.md5 = "".concat(sound.assetId, ".").concat(sound.asset.dataFormat); return loadSoundFromAsset(sound, sound.asset, runtime, soundBank).then(loadedSound => { loadedSound.broken = {}; loadedSound.broken.assetId = oldAssetId; loadedSound.broken.md5 = "".concat(oldAssetId, ".").concat(oldDataFormat); // Should be null if we got here because the sound was missing loadedSound.broken.asset = oldAsset; loadedSound.broken.sampleCount = oldSample; loadedSound.broken.rate = oldRate; loadedSound.broken.format = oldFormat; loadedSound.broken.dataFormat = oldDataFormat; return loadedSound; }); }; /** * Load a sound's asset into memory asynchronously. * @param {!object} sound - the Scratch sound object. * @property {string} md5 - the MD5 and extension of the sound to be loaded. * @property {Buffer} data - sound data will be written here once loaded. * @param {!Runtime} runtime - Scratch runtime, used to access the storage module. * @param {SoundBank} soundBank - Scratch Audio SoundBank to add sounds to. * @returns {!Promise} - a promise which will resolve to the sound when ready. */ const loadSound = function loadSound(sound, runtime, soundBank) { if (!runtime.storage) { log.warn('No storage module present; cannot load sound asset: ', sound.md5); return Promise.resolve(sound); } const idParts = StringUtil.splitFirst(sound.md5, '.'); const md5 = idParts[0]; const ext = idParts[1].toLowerCase(); sound.dataFormat = ext; return (sound.asset && Promise.resolve(sound.asset) || runtime.storage.load(runtime.storage.AssetType.Sound, md5, ext)).then(soundAsset => { sound.asset = soundAsset; if (!soundAsset) { log.warn('Failed to find sound data: ', sound.md5); return handleSoundLoadError(sound, runtime, soundBank); } return loadSoundFromAsset(sound, soundAsset, runtime, soundBank); }).catch(e => { log.warn("Failed to load sound: ".concat(sound.md5, " with error: ").concat(e)); return handleSoundLoadError(sound, runtime, soundBank); }); }; module.exports = { loadSound, loadSoundFromAsset }; /***/ }), /***/ "./node_modules/scratch-vm/src/index.js": /*!**********************************************!*\ !*** ./node_modules/scratch-vm/src/index.js ***! \**********************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const VirtualMachine = __webpack_require__(/*! ./virtual-machine */ "./node_modules/scratch-vm/src/virtual-machine.js"); module.exports = VirtualMachine; /***/ }), /***/ "./node_modules/scratch-vm/src/io/ble.js": /*!***********************************************!*\ !*** ./node_modules/scratch-vm/src/io/ble.js ***! \***********************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const JSONRPC = __webpack_require__(/*! ../util/jsonrpc */ "./node_modules/scratch-vm/src/util/jsonrpc.js"); class BLE extends JSONRPC { /** * A BLE peripheral socket object. It handles connecting, over web sockets, to * BLE peripherals, and reading and writing data to them. * @param {Runtime} runtime - the Runtime for sending/receiving GUI update events. * @param {string} extensionId - the id of the extension using this socket. * @param {object} peripheralOptions - the list of options for peripheral discovery. * @param {object} connectCallback - a callback for connection. * @param {object} resetCallback - a callback for resetting extension state. */ constructor(runtime, extensionId, peripheralOptions, connectCallback, resetCallback = null) { super(); this._socket = runtime.getScratchLinkSocket('BLE'); this._socket.setOnOpen(this.requestPeripheral.bind(this)); this._socket.setOnClose(this.handleDisconnectError.bind(this)); this._socket.setOnError(this._handleRequestError.bind(this)); this._socket.setHandleMessage(this._handleMessage.bind(this)); this._sendMessage = this._socket.sendMessage.bind(this._socket); this._availablePeripherals = {}; this._connectCallback = connectCallback; this._connected = false; this._characteristicDidChangeCallback = null; this._resetCallback = resetCallback; this._discoverTimeoutID = null; this._extensionId = extensionId; this._peripheralOptions = peripheralOptions; this._runtime = runtime; this._socket.open(); } /** * Request connection to the peripheral. * If the web socket is not yet open, request when the socket promise resolves. */ requestPeripheral() { this._availablePeripherals = {}; if (this._discoverTimeoutID) { window.clearTimeout(this._discoverTimeoutID); } this._discoverTimeoutID = window.setTimeout(this._handleDiscoverTimeout.bind(this), 15000); this.sendRemoteRequest('discover', this._peripheralOptions).catch(e => { this._handleRequestError(e); }); } /** * Try connecting to the input peripheral id, and then call the connect * callback if connection is successful. * @param {number} id - the id of the peripheral to connect to */ connectPeripheral(id) { this.sendRemoteRequest('connect', { peripheralId: id }).then(() => { this._connected = true; this._runtime.emit(this._runtime.constructor.PERIPHERAL_CONNECTED); this._connectCallback(); }).catch(e => { this._handleRequestError(e); }); } /** * Close the websocket. */ disconnect() { if (this._connected) { this._connected = false; } if (this._socket.isOpen()) { this._socket.close(); } if (this._discoverTimeoutID) { window.clearTimeout(this._discoverTimeoutID); } // Sets connection status icon to orange this._runtime.emit(this._runtime.constructor.PERIPHERAL_DISCONNECTED); } /** * @return {bool} whether the peripheral is connected. */ isConnected() { return this._connected; } /** * Start receiving notifications from the specified ble service. * @param {number} serviceId - the ble service to read. * @param {number} characteristicId - the ble characteristic to get notifications from. * @param {object} onCharacteristicChanged - callback for characteristic change notifications. * @return {Promise} - a promise from the remote startNotifications request. */ startNotifications(serviceId, characteristicId, onCharacteristicChanged = null) { const params = { serviceId, characteristicId }; this._characteristicDidChangeCallback = onCharacteristicChanged; return this.sendRemoteRequest('startNotifications', params).catch(e => { this.handleDisconnectError(e); }); } /** * Read from the specified ble service. * @param {number} serviceId - the ble service to read. * @param {number} characteristicId - the ble characteristic to read. * @param {boolean} optStartNotifications - whether to start receiving characteristic change notifications. * @param {object} onCharacteristicChanged - callback for characteristic change notifications. * @return {Promise} - a promise from the remote read request. */ read(serviceId, characteristicId, optStartNotifications = false, onCharacteristicChanged = null) { const params = { serviceId, characteristicId }; if (optStartNotifications) { params.startNotifications = true; } if (onCharacteristicChanged) { this._characteristicDidChangeCallback = onCharacteristicChanged; } return this.sendRemoteRequest('read', params).catch(e => { this.handleDisconnectError(e); }); } /** * Write data to the specified ble service. * @param {number} serviceId - the ble service to write. * @param {number} characteristicId - the ble characteristic to write. * @param {string} message - the message to send. * @param {string} encoding - the message encoding type. * @param {boolean} withResponse - if true, resolve after peripheral's response. * @return {Promise} - a promise from the remote send request. */ write(serviceId, characteristicId, message, encoding = null, withResponse = null) { const params = { serviceId, characteristicId, message }; if (encoding) { params.encoding = encoding; } if (withResponse !== null) { params.withResponse = withResponse; } return this.sendRemoteRequest('write', params).catch(e => { this.handleDisconnectError(e); }); } /** * Handle a received call from the socket. * @param {string} method - a received method label. * @param {object} params - a received list of parameters. * @return {object} - optional return value. */ didReceiveCall(method, params) { switch (method) { case 'didDiscoverPeripheral': this._availablePeripherals[params.peripheralId] = params; this._runtime.emit(this._runtime.constructor.PERIPHERAL_LIST_UPDATE, this._availablePeripherals); if (this._discoverTimeoutID) { window.clearTimeout(this._discoverTimeoutID); } break; case 'userDidPickPeripheral': this._availablePeripherals[params.peripheralId] = params; this._runtime.emit(this._runtime.constructor.USER_PICKED_PERIPHERAL, this._availablePeripherals); if (this._discoverTimeoutID) { window.clearTimeout(this._discoverTimeoutID); } break; case 'userDidNotPickPeripheral': this._runtime.emit(this._runtime.constructor.PERIPHERAL_SCAN_TIMEOUT); if (this._discoverTimeoutID) { window.clearTimeout(this._discoverTimeoutID); } break; case 'characteristicDidChange': if (this._characteristicDidChangeCallback) { this._characteristicDidChangeCallback(params.message); } break; case 'ping': return 42; } } /** * Handle an error resulting from losing connection to a peripheral. * * This could be due to: * - battery depletion * - going out of bluetooth range * - being powered down * * Disconnect the socket, and if the extension using this socket has a * reset callback, call it. Finally, emit an error to the runtime. */ handleDisconnectError() { // log.error(`BLE error: ${JSON.stringify(e)}`); if (!this._connected) return; this.disconnect(); if (this._resetCallback) { this._resetCallback(); } this._runtime.emit(this._runtime.constructor.PERIPHERAL_CONNECTION_LOST_ERROR, { message: "Scratch lost connection to", extensionId: this._extensionId }); } _handleRequestError() { // log.error(`BLE error: ${JSON.stringify(e)}`); this._runtime.emit(this._runtime.constructor.PERIPHERAL_REQUEST_ERROR, { message: "Scratch lost connection to", extensionId: this._extensionId }); } _handleDiscoverTimeout() { if (this._discoverTimeoutID) { window.clearTimeout(this._discoverTimeoutID); } this._runtime.emit(this._runtime.constructor.PERIPHERAL_SCAN_TIMEOUT); } } module.exports = BLE; /***/ }), /***/ "./node_modules/scratch-vm/src/io/bt.js": /*!**********************************************!*\ !*** ./node_modules/scratch-vm/src/io/bt.js ***! \**********************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const JSONRPC = __webpack_require__(/*! ../util/jsonrpc */ "./node_modules/scratch-vm/src/util/jsonrpc.js"); class BT extends JSONRPC { /** * A BT peripheral socket object. It handles connecting, over web sockets, to * BT peripherals, and reading and writing data to them. * @param {Runtime} runtime - the Runtime for sending/receiving GUI update events. * @param {string} extensionId - the id of the extension using this socket. * @param {object} peripheralOptions - the list of options for peripheral discovery. * @param {object} connectCallback - a callback for connection. * @param {object} resetCallback - a callback for resetting extension state. * @param {object} messageCallback - a callback for message sending. */ constructor(runtime, extensionId, peripheralOptions, connectCallback, resetCallback = null, messageCallback) { super(); this._socket = runtime.getScratchLinkSocket('BT'); this._socket.setOnOpen(this.requestPeripheral.bind(this)); this._socket.setOnError(this._handleRequestError.bind(this)); this._socket.setOnClose(this.handleDisconnectError.bind(this)); this._socket.setHandleMessage(this._handleMessage.bind(this)); this._sendMessage = this._socket.sendMessage.bind(this._socket); this._availablePeripherals = {}; this._connectCallback = connectCallback; this._connected = false; this._characteristicDidChangeCallback = null; this._resetCallback = resetCallback; this._discoverTimeoutID = null; this._extensionId = extensionId; this._peripheralOptions = peripheralOptions; this._messageCallback = messageCallback; this._runtime = runtime; this._socket.open(); } /** * Request connection to the peripheral. * If the web socket is not yet open, request when the socket promise resolves. */ requestPeripheral() { this._availablePeripherals = {}; if (this._discoverTimeoutID) { window.clearTimeout(this._discoverTimeoutID); } this._discoverTimeoutID = window.setTimeout(this._handleDiscoverTimeout.bind(this), 15000); this.sendRemoteRequest('discover', this._peripheralOptions).catch(e => this._handleRequestError(e)); } /** * Try connecting to the input peripheral id, and then call the connect * callback if connection is successful. * @param {number} id - the id of the peripheral to connect to * @param {string} pin - an optional pin for pairing */ connectPeripheral(id, pin = null) { const params = { peripheralId: id }; if (pin) { params.pin = pin; } this.sendRemoteRequest('connect', params).then(() => { this._connected = true; this._runtime.emit(this._runtime.constructor.PERIPHERAL_CONNECTED); this._connectCallback(); }).catch(e => { this._handleRequestError(e); }); } /** * Close the websocket. */ disconnect() { if (this._connected) { this._connected = false; } if (this._socket.isOpen()) { this._socket.close(); } if (this._discoverTimeoutID) { window.clearTimeout(this._discoverTimeoutID); } // Sets connection status icon to orange this._runtime.emit(this._runtime.constructor.PERIPHERAL_DISCONNECTED); } /** * @return {bool} whether the peripheral is connected. */ isConnected() { return this._connected; } sendMessage(options) { return this.sendRemoteRequest('send', options).catch(e => { this.handleDisconnectError(e); }); } /** * Handle a received call from the socket. * @param {string} method - a received method label. * @param {object} params - a received list of parameters. * @return {object} - optional return value. */ didReceiveCall(method, params) { // TODO: Add peripheral 'undiscover' handling switch (method) { case 'didDiscoverPeripheral': this._availablePeripherals[params.peripheralId] = params; this._runtime.emit(this._runtime.constructor.PERIPHERAL_LIST_UPDATE, this._availablePeripherals); if (this._discoverTimeoutID) { window.clearTimeout(this._discoverTimeoutID); } break; case 'userDidPickPeripheral': this._availablePeripherals[params.peripheralId] = params; this._runtime.emit(this._runtime.constructor.USER_PICKED_PERIPHERAL, this._availablePeripherals); if (this._discoverTimeoutID) { window.clearTimeout(this._discoverTimeoutID); } break; case 'userDidNotPickPeripheral': this._runtime.emit(this._runtime.constructor.PERIPHERAL_SCAN_TIMEOUT); if (this._discoverTimeoutID) { window.clearTimeout(this._discoverTimeoutID); } break; case 'didReceiveMessage': this._messageCallback(params); // TODO: refine? break; default: return 'nah'; } } /** * Handle an error resulting from losing connection to a peripheral. * * This could be due to: * - battery depletion * - going out of bluetooth range * - being powered down * * Disconnect the socket, and if the extension using this socket has a * reset callback, call it. Finally, emit an error to the runtime. */ handleDisconnectError() { // log.error(`BT error: ${JSON.stringify(e)}`); if (!this._connected) return; this.disconnect(); if (this._resetCallback) { this._resetCallback(); } this._runtime.emit(this._runtime.constructor.PERIPHERAL_CONNECTION_LOST_ERROR, { message: "Scratch lost connection to", extensionId: this._extensionId }); } _handleRequestError() { // log.error(`BT error: ${JSON.stringify(e)}`); this._runtime.emit(this._runtime.constructor.PERIPHERAL_REQUEST_ERROR, { message: "Scratch lost connection to", extensionId: this._extensionId }); } _handleDiscoverTimeout() { if (this._discoverTimeoutID) { window.clearTimeout(this._discoverTimeoutID); } this._runtime.emit(this._runtime.constructor.PERIPHERAL_SCAN_TIMEOUT); } } module.exports = BT; /***/ }), /***/ "./node_modules/scratch-vm/src/io/clock.js": /*!*************************************************!*\ !*** ./node_modules/scratch-vm/src/io/clock.js ***! \*************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const Timer = __webpack_require__(/*! ../util/timer */ "./node_modules/scratch-vm/src/util/timer.js"); class Clock { constructor(runtime) { this._projectTimer = new Timer({ now: () => runtime.currentMSecs }); this._projectTimer.start(); this._pausedTime = null; this._paused = false; /** * Reference to the owning Runtime. * @type{!Runtime} */ this.runtime = runtime; } projectTimer() { if (this._paused) { return this._pausedTime / 1000; } return this._projectTimer.timeElapsed() / 1000; } pause() { this._paused = true; this._pausedTime = this._projectTimer.timeElapsed(); } resume() { this._paused = false; const dt = this._projectTimer.timeElapsed() - this._pausedTime; this._projectTimer.startTime += dt; } resetProjectTimer() { this._projectTimer.start(); } } module.exports = Clock; /***/ }), /***/ "./node_modules/scratch-vm/src/io/cloud.js": /*!*************************************************!*\ !*** ./node_modules/scratch-vm/src/io/cloud.js ***! \*************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const Variable = __webpack_require__(/*! ../engine/variable */ "./node_modules/scratch-vm/src/engine/variable.js"); const log = __webpack_require__(/*! ../util/log */ "./node_modules/scratch-vm/src/util/log.js"); class Cloud { /** * @typedef updateVariable * @param {string} name The name of the cloud variable to update on the server * @param {(string | number)} value The value to update the cloud variable with. */ /** * A cloud data provider, responsible for managing the connection to the * cloud data server and for posting data about cloud data activity to * this IO device. * @typedef {object} CloudProvider * @property {updateVariable} updateVariable A function which sends a cloud variable * update to the cloud data server. * @property {Function} requestCloseConnection A function which closes * the connection to the cloud data server. */ /** * Part of a cloud io data post indicating a cloud variable update. * @typedef {object} VarUpdateData * @property {string} name The name of the variable to update * @property {(number | string)} value The scalar value to update the variable with */ /** * A cloud io data post message. * @typedef {object} CloudIOData * @property {VarUpdateData} varUpdate A {@link VarUpdateData} message indicating * a cloud variable update */ /** * Cloud IO Device responsible for sending and receiving messages from * cloud provider (mananging the cloud server connection) and interacting * with cloud variables in the current project. * @param {Runtime} runtime The runtime context for this cloud io device. */ constructor(runtime) { /** * Reference to the cloud data provider, responsible for mananging * the web socket connection to the cloud data server. * @type {?CloudProvider} */ this.provider = null; /** * Reference to the runtime that owns this cloud io device. * @type {!Runtime} */ this.runtime = runtime; /** * Reference to the stage target which owns the cloud variables * in the project. * @type {?Target} */ this.stage = null; } /** * Set a reference to the cloud data provider. * @param {CloudProvider} provider The cloud data provider */ setProvider(provider) { this.provider = provider; } /** * Set a reference to the stage target which owns the * cloud variables in the project. * @param {Target} stage The stage target */ setStage(stage) { this.stage = stage; } /** * Handle incoming data to this io device. * @param {CloudIOData} data The {@link CloudIOData} object to process */ postData(data) { if (data.varUpdate) { this.updateCloudVariable(data.varUpdate); } } requestCreateVariable(variable) { if (this.runtime.canAddCloudVariable()) { if (this.provider) { this.provider.createVariable(variable.name, variable.value); // We'll set the cloud flag and update the // cloud variable limit when we actually // get a confirmation from the cloud data server } } // TODO else track creation for later } /** * Request the cloud data provider to update the given variable with * the given value. Does nothing if this io device does not have a provider set. * @param {string} name The name of the variable to update * @param {string | number} value The value to update the variable with */ requestUpdateVariable(name, value) { if (this.provider) { this.provider.updateVariable(name, value); } } /** * Request the cloud data provider to rename the variable with the given name * to the given new name. Does nothing if this io device does not have a provider set. * @param {string} oldName The name of the variable to rename * @param {string | number} newName The new name for the variable */ requestRenameVariable(oldName, newName) { if (this.provider) { this.provider.renameVariable(oldName, newName); } } /** * Request the cloud data provider to delete the variable with the given name * Does nothing if this io device does not have a provider set. * @param {string} name The name of the variable to delete */ requestDeleteVariable(name) { if (this.provider) { this.provider.deleteVariable(name); } } /** * Update a cloud variable in the runtime based on the message received * from the cloud provider. * @param {VarData} varUpdate A {@link VarData} object describing * a cloud variable update received from the cloud data provider. */ updateCloudVariable(varUpdate) { const varName = varUpdate.name; const variable = this.stage.lookupVariableByNameAndType(varName, Variable.SCALAR_TYPE); if (!variable || !variable.isCloud) { log.warn("Received an update for a cloud variable that does not exist: ".concat(varName)); return; } variable.value = varUpdate.value; } /** * Request the cloud data provider to close the web socket connection and * clear this io device of references to the cloud data provider and the * stage. */ clear() { if (!this.provider) return; this.provider.requestCloseConnection(); this.provider = null; this.stage = null; } } module.exports = Cloud; /***/ }), /***/ "./node_modules/scratch-vm/src/io/keyboard.js": /*!****************************************************!*\ !*** ./node_modules/scratch-vm/src/io/keyboard.js ***! \****************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const Cast = __webpack_require__(/*! ../util/cast */ "./node_modules/scratch-vm/src/util/cast.js"); /** * Names used internally for keys used in scratch, also known as "scratch keys". * @enum {string} */ const KEY_NAME = { SPACE: 'space', LEFT: 'left arrow', UP: 'up arrow', RIGHT: 'right arrow', DOWN: 'down arrow', ENTER: 'enter', // tw: extra keys BACKSPACE: 'backspace', DELETE: 'delete', SHIFT: 'shift', CAPS_LOCK: 'caps lock', SCROLL_LOCK: 'scroll lock', CONTROL: 'control', ESCAPE: 'escape', INSERT: 'insert', HOME: 'home', END: 'end', PAGE_UP: 'page up', PAGE_DOWN: 'page down' }; /** * An array of the names of scratch keys. * @type {Array} */ const KEY_NAME_LIST = Object.keys(KEY_NAME).map(name => KEY_NAME[name]); class Keyboard { constructor(runtime) { /** * List of currently pressed scratch keys. * A scratch key is: * A key you can press on a keyboard, excluding modifier keys. * An uppercase string of length one; * except for special key names for arrow keys and space (e.g. 'left arrow'). * Can be a non-english unicode letter like: æ ø ש נ 手 廿. * @type{Array.} */ this._keysPressed = []; /** * Reference to the owning Runtime. * Can be used, for example, to activate hats. * @type{!Runtime} */ this.runtime = runtime; // tw: track last pressed key this.lastKeyPressed = ''; this._numeralKeyCodesToStringKey = new Map(); } /** * Convert from a keyboard event key name to a Scratch key name. * @param {string} keyString the input key string. * @return {string} the corresponding Scratch key, or an empty string. */ _keyStringToScratchKey(keyString) { keyString = Cast.toString(keyString); // Convert space and arrow keys to their Scratch key names. switch (keyString) { case ' ': return KEY_NAME.SPACE; case 'ArrowLeft': case 'Left': return KEY_NAME.LEFT; case 'ArrowUp': case 'Up': return KEY_NAME.UP; case 'Right': case 'ArrowRight': return KEY_NAME.RIGHT; case 'Down': case 'ArrowDown': return KEY_NAME.DOWN; case 'Enter': return KEY_NAME.ENTER; // tw: extra keys case 'Backspace': return KEY_NAME.BACKSPACE; case 'Delete': return KEY_NAME.DELETE; case 'Shift': return KEY_NAME.SHIFT; case 'CapsLock': return KEY_NAME.CAPS_LOCK; case 'ScrollLock': return KEY_NAME.SCROLL_LOCK; case 'Control': return KEY_NAME.CONTROL; case 'Escape': return KEY_NAME.ESCAPE; case 'Insert': return KEY_NAME.INSERT; case 'Home': return KEY_NAME.HOME; case 'End': return KEY_NAME.END; case 'PageUp': return KEY_NAME.PAGE_UP; case 'PageDown': return KEY_NAME.PAGE_DOWN; } // Ignore modifier keys if (keyString.length > 1) { return ''; } // tw: toUpperCase() happens later. We need to track key case. return keyString; } /** * Convert from a block argument to a Scratch key name. * @param {string} keyArg the input arg. * @return {string} the corresponding Scratch key. */ _keyArgToScratchKey(keyArg) { // If a number was dropped in, try to convert from ASCII to Scratch key. if (typeof keyArg === 'number') { // Check for the ASCII range containing numbers, some punctuation, // and uppercase letters. if (keyArg >= 48 && keyArg <= 90) { return String.fromCharCode(keyArg); } switch (keyArg) { case 32: return KEY_NAME.SPACE; case 37: return KEY_NAME.LEFT; case 38: return KEY_NAME.UP; case 39: return KEY_NAME.RIGHT; case 40: return KEY_NAME.DOWN; } } keyArg = Cast.toString(keyArg); // If the arg matches a special key name, return it. if (KEY_NAME_LIST.includes(keyArg)) { return keyArg; } // Use only the first character. if (keyArg.length > 1) { keyArg = keyArg[0]; } // Check for the space character. if (keyArg === ' ') { return KEY_NAME.SPACE; } // tw: support Scratch 2 hacked blocks // There are more hacked blocks but most of them get mangled by Scratch 2 -> Scratch 3 conversion if (keyArg === '\r') { // this probably belongs upstream return KEY_NAME.ENTER; } if (keyArg === '\u001b') { return KEY_NAME.ESCAPE; } return keyArg.toUpperCase(); } /** * Keyboard DOM event handler. * @param {object} data Data from DOM event. */ postData(data) { if (!data.key) return; // tw: convert single letter keys to uppercase because of changes in _keyStringToScratchKey const scratchKeyCased = this._keyStringToScratchKey(data.key); const scratchKey = scratchKeyCased.length === 1 ? scratchKeyCased.toUpperCase() : scratchKeyCased; if (scratchKey === '') return; const index = this._keysPressed.indexOf(scratchKey); if (data.isDown) { // tw: track last pressed key this.lastKeyPressed = scratchKeyCased; this.runtime.emit('KEY_PRESSED', scratchKey); // If not already present, add to the list. if (index < 0) { this._keysPressed.push(scratchKey); } } else if (index > -1) { // If already present, remove from the list. this._keysPressed.splice(index, 1); } // Fix for https://github.com/LLK/scratch-vm/issues/2271 if (data.hasOwnProperty('keyCode')) { const keyCode = data.keyCode; if (this._numeralKeyCodesToStringKey.has(keyCode)) { const lastKeyOfSameCode = this._numeralKeyCodesToStringKey.get(keyCode); if (lastKeyOfSameCode !== scratchKey) { const indexToUnpress = this._keysPressed.indexOf(lastKeyOfSameCode); if (indexToUnpress !== -1) { this._keysPressed.splice(indexToUnpress, 1); } } } this._numeralKeyCodesToStringKey.set(keyCode, scratchKey); } } /** * Get key down state for a specified key. * @param {Any} keyArg key argument. * @return {boolean} Is the specified key down? */ getKeyIsDown(keyArg) { if (keyArg === 'any') { return this._keysPressed.length > 0; } const scratchKey = this._keyArgToScratchKey(keyArg); return this._keysPressed.indexOf(scratchKey) > -1; } // tw: expose last pressed key getLastKeyPressed() { return this.lastKeyPressed; } } module.exports = Keyboard; /***/ }), /***/ "./node_modules/scratch-vm/src/io/mouse.js": /*!*************************************************!*\ !*** ./node_modules/scratch-vm/src/io/mouse.js ***! \*************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const MathUtil = __webpack_require__(/*! ../util/math-util */ "./node_modules/scratch-vm/src/util/math-util.js"); const roundToThreeDecimals = number => Math.round(number * 1000) / 1000; class Mouse { constructor(runtime) { this._clientX = 0; this._clientY = 0; this._scratchX = 0; this._scratchY = 0; this._buttons = new Set(); this.usesRightClickDown = false; this._isDown = false; /** * Reference to the owning Runtime. * Can be used, for example, to activate hats. * @type{!Runtime} */ this.runtime = runtime; } /** * Activate "event_whenthisspriteclicked" hats. * @param {Target} target to trigger hats on. * @private */ _activateClickHats(target) { // Activate both "this sprite clicked" and "stage clicked" // They were separated into two opcodes for labeling, // but should act the same way. // Intentionally not checking isStage to make it work when sharing blocks. // @todo the blocks should be converted from one to another when shared this.runtime.startHats('event_whenthisspriteclicked', null, target); this.runtime.startHats('event_whenstageclicked', null, target); } /** * Find a target by XY location * @param {number} x X position to be sent to the renderer. * @param {number} y Y position to be sent to the renderer. * @return {Target} the target at that location * @private */ _pickTarget(x, y) { if (this.runtime.renderer) { const drawableID = this.runtime.renderer.pick(x, y); for (let i = 0; i < this.runtime.targets.length; i++) { const target = this.runtime.targets[i]; if (target.hasOwnProperty('drawableID') && target.drawableID === drawableID) { return target; } } } // Return the stage if no target was found return this.runtime.getTargetForStage(); } /** * Mouse DOM event handler. * @param {object} data Data from DOM event. */ postData(data) { if (typeof data.x === 'number') { this._clientX = data.x; this._scratchX = MathUtil.clamp(this.runtime.stageWidth * (data.x / data.canvasWidth - 0.5), -(this.runtime.stageWidth / 2), this.runtime.stageWidth / 2); } if (typeof data.y === 'number') { this._clientY = data.y; this._scratchY = MathUtil.clamp(-this.runtime.stageHeight * (data.y / data.canvasHeight - 0.5), -(this.runtime.stageHeight / 2), this.runtime.stageHeight / 2); } if (typeof data.isDown !== 'undefined') { // If no button specified, default to left button for compatibility const button = typeof data.button === 'undefined' ? 0 : data.button; if (data.isDown) { this._buttons.add(button); } else { this._buttons.delete(button); } const previousDownState = this._isDown; this._isDown = data.isDown; // Do not trigger if down state has not changed if (previousDownState === this._isDown) return; // Never trigger click hats at the end of a drag if (data.wasDragged) return; // Do not activate click hats for clicks outside canvas bounds if (!(data.x > 0 && data.x < data.canvasWidth && data.y > 0 && data.y < data.canvasHeight)) return; const target = this._pickTarget(data.x, data.y); const isNewMouseDown = !previousDownState && this._isDown; const isNewMouseUp = previousDownState && !this._isDown; // Draggable targets start click hats on mouse up. // Non-draggable targets start click hats on mouse down. if (target.draggable && isNewMouseUp) { this._activateClickHats(target); } else if (!target.draggable && isNewMouseDown) { this._activateClickHats(target); } } } /** * Get the X position of the mouse in client coordinates. * @return {number} Non-clamped X position of the mouse cursor. */ getClientX() { return this._clientX; } /** * Get the Y position of the mouse in client coordinates. * @return {number} Non-clamped Y position of the mouse cursor. */ getClientY() { return this._clientY; } /** * Get the X position of the mouse in scratch coordinates. * @return {number} Clamped and integer rounded X position of the mouse cursor. */ getScratchX() { if (this.runtime.runtimeOptions.miscLimits) { return Math.round(this._scratchX); } return roundToThreeDecimals(this._scratchX); } /** * Get the Y position of the mouse in scratch coordinates. * @return {number} Clamped and integer rounded Y position of the mouse cursor. */ getScratchY() { if (this.runtime.runtimeOptions.miscLimits) { return Math.round(this._scratchY); } return roundToThreeDecimals(this._scratchY); } /** * Get the down state of the mouse. * @return {boolean} Is the mouse down? */ getIsDown() { return this._isDown; } /** * tw: Get the down state of a specific button of the mouse. * @param {number} button The ID of the button. 0 = left, 1 = middle, 2 = right * @return {boolean} Is the mouse button down? */ getButtonIsDown(button) { if (button === 2) { this.usesRightClickDown = true; } return this._buttons.has(button); } } module.exports = Mouse; /***/ }), /***/ "./node_modules/scratch-vm/src/io/mouseWheel.js": /*!******************************************************!*\ !*** ./node_modules/scratch-vm/src/io/mouseWheel.js ***! \******************************************************/ /*! no static exports found */ /***/ (function(module, exports) { class MouseWheel { constructor(runtime) { /** * Reference to the owning Runtime. * @type{!Runtime} */ this.runtime = runtime; } /** * Mouse wheel DOM event handler. * @param {object} data Data from DOM event. */ postData(data) { const matchFields = {}; if (data.deltaY < 0) { matchFields.KEY_OPTION = 'up arrow'; } else if (data.deltaY > 0) { matchFields.KEY_OPTION = 'down arrow'; } else { return; } this.runtime.startHats('event_whenkeypressed', matchFields); } } module.exports = MouseWheel; /***/ }), /***/ "./node_modules/scratch-vm/src/io/userData.js": /*!****************************************************!*\ !*** ./node_modules/scratch-vm/src/io/userData.js ***! \****************************************************/ /*! no static exports found */ /***/ (function(module, exports) { class UserData { constructor() { this._username = ''; } /** * Handler for updating the username * @param {object} data Data posted to this ioDevice. * @property {!string} username The new username. */ postData(data) { this._username = data.username; } /** * Getter for username. Initially empty string, until set via postData. * @returns {!string} The current username */ getUsername() { return this._username; } } module.exports = UserData; /***/ }), /***/ "./node_modules/scratch-vm/src/io/video.js": /*!*************************************************!*\ !*** ./node_modules/scratch-vm/src/io/video.js ***! \*************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { const StageLayering = __webpack_require__(/*! ../engine/stage-layering */ "./node_modules/scratch-vm/src/engine/stage-layering.js"); class Video { constructor(runtime) { this.runtime = runtime; /** * @typedef VideoProvider * @property {Function} enableVideo - Requests camera access from the user, and upon success, * enables the video feed * @property {Function} disableVideo - Turns off the video feed * @property {Function} getFrame - Return frame data from the video feed in * specified dimensions, format, and mirroring. */ this.provider = null; /** * Id representing a Scratch Renderer skin the video is rendered to for * previewing. * @type {number} */ this._skinId = -1; /** * Id for a drawable using the video's skin that will render as a video * preview. * @type {Drawable} */ this._drawable = -1; /** * Store the last state of the video transparency ghost effect * @type {number} */ this._ghost = 0; /** * Store a flag that allows the preview to be forced transparent. * @type {number} */ this._forceTransparentPreview = false; } static get FORMAT_IMAGE_DATA() { return 'image-data'; } static get FORMAT_CANVAS() { return 'canvas'; } /** * Dimensions the video stream is analyzed at after its rendered to the * sample canvas. * @type {Array.} */ static get DIMENSIONS() { return [480, 360]; } /** * Order preview drawable is inserted at in the renderer. * @type {number} */ static get ORDER() { return 1; } /** * Set a video provider for this device. A default implementation of * a video provider can be found in scratch-gui/src/lib/video/video-provider * @param {VideoProvider} provider - Video provider to use */ setProvider(provider) { this.provider = provider; } /** * Request video be enabled. Sets up video, creates video skin and enables preview. * * ioDevices.video.requestVideo() * * @return {Promise.