UNPKG

blocklypy

Version:

BlocklyPy: SPIKE to Pybricks - word-block converter to Pybricks python code

1,535 lines 593 kB
class qt { constructor(t, n) { this.id = qt.idToString(t), this.payload = n; } static idToString(t) { return typeof t == "string" ? t : JSON.stringify(t); } } function es(e) { return !!e && typeof e.use == "function"; } function rs(e) { return !!e; } function ns(e) { return !!e; } class xe { constructor(t, n) { this.context = t, this.factory = n, this.registry = /* @__PURE__ */ new Map(); } get(t) { return this.registry.get(qt.idToString(t))?.payload; } has(t) { return this.registry.has(qt.idToString(t)); } use(t, ...n) { let s = this.registry.get(qt.idToString(t)); if (!s) { const i = typeof this.factory == "function" ? this.factory(...n) : n[0]; rs(i) && (i.id = t), ns(i) && (i.parent = this), s = new qt(t, i), this.registry.set(qt.idToString(t), s); } return s.payload && es(s.payload) && s.payload.use(...n), s.payload; } entries() { return [...this.registry.entries()]; } values() { return [...this.registry.values()]; } payloads() { return [...this.registry.values()].map((t) => t.payload); } clear() { this.registry.clear(); } } const je = " ", Qe = "cm", Ke = "inches", Kt = "rotations", rr = "degrees", Ue = "seconds", Ht = "AUTO"; var Ae = /* @__PURE__ */ ((e) => (e[e.DEBUG = 0] = "DEBUG", e[e.INFO = 1] = "INFO", e[e.WARNING = 2] = "WARNING", e[e.ERROR = 3] = "ERROR", e[e.CRITICAL = 4] = "CRITICAL", e))(Ae || {}); let Tn = 0, mr; function ss(e) { Tn = e; } function Hr(e) { mr = e; } function gr(e, t, n = "-", s = 80) { const i = s - e.length - 6 - t?.length; return `#${t} ${n.repeat( Math.floor(i / 2) )} ${e} ${n.repeat(Math.ceil(i / 2))} #`; } function is(e, ...t) { if (Tn <= e) if (mr) mr(e, ...t); else switch (e) { case 4: case 3: console.error(`::${Ae[e]}::`, ...t); break; case 2: console.warn(`::${Ae[e]}::`, ...t); break; case 1: console.info(`::${Ae[e]}::`, ...t); break; case 0: default: console.debug(`::${Ae[e]}::`, ...t); break; } } const Pt = (...e) => is(2, ...e); function At(e, t = 1) { let n = []; return e === void 0 ? n = [] : Array.isArray(e) ? n = e.reduce( (s, i) => [...s, ...At(i, t)], [] ) : e.includes(` `) ? n = At(e.split(/\r?\n/), t) : n = [je.repeat(t) + e], n; } function oe(e, t = !0) { if (!e.filter((n) => !n.match(/^\s*$|^\s*#.*$/)).length) { e.push("pass"); //!! } return e; } function Jt(e) { return e?.trim().toLowerCase().replaceAll(/[ .-]/gi, "_").replace(/^(\d)/im, "_$1").replaceAll( /[áéíóöőúüű]/g, (t) => ({ á: "a", é: "e", í: "i", ó: "o", ö: "o", ő: "o", ú: "u", ü: "u", ű: "u" })[t] ?? t ).replace(/[^a-zA-Z0-9_]/g, ""); } function te(e) { return e?.replace(/\.[^/.]+$/, "").replaceAll(" ", "_"); } function Gt(e, t = !0) { return e = e?.replaceAll(/\\(.)/g, "$1").replaceAll(" ", "_").replaceAll(/[\/,.]/g, ""), t && (e = e?.toUpperCase()), e; } function os(e) { return typeof e == "number"; } function Xt(e) { const t = e?.lastIndexOf("."); return e === void 0 || t === -1 || t === void 0 ? "" : e.substring(t); } function $t(e) { return e?.replace(/^.*[\\/]/, ""); } function Je(e) { return e?.split(".").slice(0, -1).join("."); } function vr(e) { const t = e?.trim().toLowerCase(); return t === "true" || t === "1"; } function Ut(e) { return parseInt(e ?? "0"); } function Sr(e) { return `"""\r ` + e.map(([t, n]) => `${(t + ":").padEnd(12, " ")}${n}`).join(`\r `) + `\r """\r `; } function wr(e, t) { return t.extra || (t.extra = {}), t.extra[e] || (t.extra[e] = {}), t.extra[e]; } class Lr { constructor(t) { this.name = t; } // Generates the code for the broadcast registry payload get_code(t) { const n = t.map((s) => Jt(s)); return `${this.get_pyname()} = Message([${n.join(", ")}])`; } // Returns the sanitized Python name for the message get_pyname() { return `message_${Jt(this.name)}`; } // Creates a new registry manager for the broadcast registry payload static createRegistry(t) { return new xe( t, (...n) => new Lr(n[0]) ); } } var dt = /* @__PURE__ */ ((e) => (e[e.NONE = 0] = "NONE", e[e.SPIKE = 1] = "SPIKE", e[e.ROBOTINVENTOR = 2] = "ROBOTINVENTOR", e[e._GEN_EV5 = 3] = "_GEN_EV5", e[e.EV3CLASSROOM = 4] = "EV3CLASSROOM", e[e._SB3_FORMAT = 7] = "_SB3_FORMAT", e[e.EV3G = 8] = "EV3G", e[e.EV3B = 16] = "EV3B", e[e._GEN_EV3 = 28] = "_GEN_EV3", e[e._EV3Lab_FORMAT = 24] = "_EV3Lab_FORMAT", e[e.PYTHON = 32] = "PYTHON", e[e.WEDO2 = 64] = "WEDO2", e))(dt || {}), _t = /* @__PURE__ */ ((e) => (e[e.SIMPLE = 0] = "SIMPLE", e[e.PARENTHESIS = 1] = "PARENTHESIS", e[e.REFERENCE = 2] = "REFERENCE", e[e.EXPONENTIATION = 3] = "EXPONENTIATION", e[e.UNARY = 4] = "UNARY", e[e.BINARYOP_MUL = 5] = "BINARYOP_MUL", e[e.BINARY_ADD = 6] = "BINARY_ADD", e[e.BINARY_SHIFT = 7] = "BINARY_SHIFT", e[e.BINARY_AND = 8] = "BINARY_AND", e[e.BINARY_XOR = 9] = "BINARY_XOR", e[e.BINARY_OR = 10] = "BINARY_OR", e[e.BINARY_COMPARISON = 11] = "BINARY_COMPARISON", e[e.BOOLEAN_NOT = 12] = "BOOLEAN_NOT", e[e.BOOLEAN_AND = 13] = "BOOLEAN_AND", e[e.BOOLEAN_OR = 14] = "BOOLEAN_OR", e[e.WEAKEST = 99] = "WEAKEST", e))(_t || {}), G = /* @__PURE__ */ ((e) => (e[e.UNKNOWN = 0] = "UNKNOWN", e[e.NUMBER = 10] = "NUMBER", e[e.STRING = 11] = "STRING", e[e.BOOLEAN = 12] = "BOOLEAN", e[e.ENUM = 13] = "ENUM", e[e.NUMBERARRAY = 20] = "NUMBERARRAY", e[e.BOOLEANARRAY = 21] = "BOOLEANARRAY", e[e.ENUMARRAY = 23] = "ENUMARRAY", e))(G || {}); class U { constructor(t, n) { this.options = n, t && U.is(t) ? this.value = t.value : this.value = t; } get is_string() { return this.options?.type === G.STRING; } get is_numeric() { return this.options?.type === G.NUMBER || !this.options?.is_dynamic && !this.is_string && typeof this.value == "number"; } get raw() { return !this.is_string || this.options?.is_dynamic ? this.value : `"${this.value}"`; } toString() { return U.toString(this); } toInt() { return U.toInt(this); } toFloat() { return U.toFloat(this); } toBool() { return U.toBool(this); } ensureString(t) { return Or(t, this, G.STRING); } ensureNumber(t, n = !1) { if (this.is_numeric) { if (this.options?.is_dynamic) return this; { const s = n ? this.toInt() : this.toFloat(); return new U(s, { type: G.NUMBER }); } } else return Or(t, this, G.NUMBER, n); } static is(t) { return t instanceof U; } static is_dynamic(t) { return U.is(t) && !!t.options?.is_dynamic; } static raw(t) { return U.is(t) ? t.raw : t; } static value(t) { return U.is(t) ? t.value : t; } static toString(t) { return U.value(t)?.toString() ?? ""; } static toInt(t) { const n = U.is(t) ? t.value : t; return parseInt(n?.toString() ?? ""); } static toFloat(t) { const n = U.is(t) ? t.value : t; return parseFloat(n?.toString() ?? ""); } static toBool(t) { const n = U.is(t) ? t.value : t; return vr(n?.toString()); } static ensureNumber(t, n, s = !1) { return U.is(n) ? n.ensureNumber(t) : t.helpers.use(s ? "int_safe" : "float_safe").call(n); } static isEqual(t, n) { return U.is(t) && U.is(n) ? t.value === n.value && JSON.stringify(t.options) === JSON.stringify(n.options) : t === n; } } function Tt(e, t, n = !1) { const [s, i, o] = Array.isArray(t) ? t : [t, void 0, void 0]; if (i === void 0) { if (Array.isArray(s)) return Tt(e, s, n); if (!U.is_dynamic(s)) { const l = Math.round(parseFloat(s?.toString() ?? "") * 1e3) / 1e3; return new U(l, { type: G.NUMBER }); } return !U.is(s) || s.options?.type !== G.NUMBER ? U.ensureNumber(e, s, n) : new U(s, { type: G.NUMBER, is_dynamic: s.options.is_dynamic, precedence: s.options.precedence }); } else if (o === void 0) { const l = Tt(e, i, n), a = !U.is_dynamic(l); if (s === "-" || s === "+") if (a) { const h = (s === "-" ? -1 : 1) * U.toFloat(l); return new U(h, { type: G.NUMBER }); } else { const c = `${s}${U.raw(l)}`; return new U(c, { is_dynamic: !0, type: G.NUMBER, precedence: _t.UNARY }); } else if (s === "abs") return a ? new U(Math.abs(U.toFloat(l)), { type: G.NUMBER }) : (e.imports.use("umath", null), new U(`umath.fabs(${U.raw(l)})`, { is_dynamic: !0, type: G.NUMBER, precedence: _t.SIMPLE })); } else { const l = Tt(e, s, n), a = Tt(e, o, n); let c = U.raw(l), h = U.raw(a); if (!U.is_dynamic(l) && !U.is_dynamic(a)) { const m = (p, g, _) => { switch (g) { case "+": return p + _; case "-": return p - _; case "*": return p * _; case "/": return p / _; case "%": return p % _; } }; if (c === void 0 || i === void 0 || h === void 0) return; const O = Tt( e, m(U.toFloat(c), i?.toString(), U.toFloat(h)) ); return new U(O, { type: G.NUMBER, precedence: _t.SIMPLE }); } else { const m = Tt(e, s, n), O = Tt(e, o, n), p = i?.toString(), g = (N) => N?.toString() === "0", _ = (N) => N?.toString() === "1", C = (N) => N?.toString() === "-1"; if (p === "*") { if (g(m) || _(O)) return m; if (g(O) || _(m)) return O; if (C(m)) return Tt(e, ["-", O]); if (C(O)) return Tt(e, ["-", m]); } else if (p === "/") { if (g(m) || _(O)) return m; if (C(O)) return Tt(e, ["-", m]); } else if (p === "+") { if (g(m)) return O; if (g(O)) return m; } else if (p === "-") { if (g(m)) return Tt(e, ["-", O]); if (g(O)) return m; } const A = (() => { switch (i.toString()) { case "-": case "+": return _t.BINARY_ADD; case "*": case "/": case "%": return _t.BINARYOP_MUL; default: return _t.WEAKEST; } })(); return A < (m?.options?.precedence ?? 0) && (c = `(${c})`), A < (O?.options?.precedence ?? 0) && (h = `(${h})`), new U(`${c} ${i} ${h}`, { is_dynamic: !0, type: G.NUMBER, precedence: A }); } } } function Or(e, t, n, s = !1) { const i = t?.options?.type; if (n !== i) switch (n) { case G.NUMBER: t = s ? e.helpers.use("int_safe").call(t) : e.helpers.use("float_safe").call(t); break; case G.STRING: t = e.helpers.use("str").call(t); break; case G.NUMBERARRAY: switch (i) { case G.NUMBER: t = new U(`[${t?.raw}]`, { is_dynamic: !0, is_variable: !0, type: G.NUMBERARRAY }); break; } break; case G.BOOLEANARRAY: switch (i) { case G.BOOLEAN: t = new U(`[${t?.raw}]`, { is_dynamic: !0, is_variable: !0, type: G.BOOLEANARRAY }); break; } break; } return t; } const jr = /* @__PURE__ */ new Map([ [0, "Stop.COAST"], [1, "Stop.BRAKE"], [2, "Stop.HOLD"] ]), Cn = /* @__PURE__ */ new Map([ [0, "Stop.COAST"], [1, "Stop.HOLD"] ]), as = /* @__PURE__ */ new Map([ [1, "Side.TOP"], [2, "Side.LEFT"], [3, "Side.RIGHT"], [4, "Side.BOTTOM"] ]), ur = /* @__PURE__ */ new Map([ [0, "Color.BLACK"], [1, "Color.MAGENTA"], [2, "Color.VIOLET"], [3, "Color.BLUE"], [4, "Color.CYAN"], [5, "Color.GREEN"], [6, "Color.GREEN"], [7, "Color.YELLOW"], [8, "Color.ORANGE"], [9, "Color.RED"], [10, "Color.WHITE"] ]), Mr = /* @__PURE__ */ new Map([ [0, "Button.NONE"], [1, "Button.LEFT"], [2, "Button.CENTER"], [3, "Button.RIGHT"], [4, "Button.UP"], [5, "Button.DOWN"] ]), ls = /* @__PURE__ */ new Map([ [0, "RELEASED"], [1, "PRESSED"] ]); var Rn = /* @__PURE__ */ ((e) => (e[e.OFF = 0] = "OFF", e[e.GREEN = 1] = "GREEN", e[e.RED = 2] = "RED", e[e.ORANGE = 3] = "ORANGE", e[e.GREEN_PULSE = 4] = "GREEN_PULSE", e[e.RED_PULSE = 5] = "RED_PULSE", e[e.ORANGE_PULSE = 6] = "ORANGE_PULSE", e))(Rn || {}); const cs = /* @__PURE__ */ new Map([ [0, "Color.NONE"], [1, "Color.GREEN"], [2, "Color.RED"], [3, "Color.ORANGE"], [4, "Color.GREEN_PULSE"], [5, "Color.RED_PULSE"], [6, "Color.ORANGE_PULSE"] ]), us = /* @__PURE__ */ new Map([ [0, "Color.GREEN"], [1, "Color.RED"], [2, "Color.ORANGE"] ]), Br = /* @__PURE__ */ new Map([ [0, "Color.NONE"], [1, "Color.BLACK"], [2, "Color.BLUE"], [3, "Color.GREEN"], [4, "Color.YELLOW"], [5, "Color.RED"], [6, "Color.WHITE"], [7, "Color.BROWN"] ]); function An(e, t = -1) { if (e.imports.use("pybricks.parameters", "Stop"), jr.has(t)) return jr.get(t); } function be(e, t = 0) { const n = 10 ** t; return Math.round(e * n) / n; } function Nn(e) { return e?.value === "=" ? "==" : e?.value?.toString(); } function we(e) { return ["==", "!=", ">", ">=", "<", "<="][e?.toInt() ?? -1]; } class nr { constructor() { this.isPyFnEnabled = !1; } call(...t) { const n = this.parent.helperFunctionsMap.get(this.id); if (n) { if (n.imports?.forEach( ([s, i]) => this.parent.context.imports.use(s, i) ), n.local_fn) { if (t.every((i) => !U.is_dynamic(i)) && (!n.local_fn_condition || n.local_fn_condition( t.map((i) => U.value(i)) ))) { const i = n.local_fn( ...t.map((o) => U.value(o)) //? .raw ); return U.is(i) ? i : new U(i, { precedence: _t.SIMPLE, type: n.type ?? (typeof i == "string" ? G.STRING : G.NUMBER) }); //!! } else if (n.local_dynamic_fn) { const i = n.local_fn(...t); return U.is(i) ? i : new U(i, { is_dynamic: !0, type: n.type ?? (typeof i == "string" ? G.STRING : G.NUMBER) }); } } n.py_fn && (this.isPyFnEnabled = !0, n.py_dependencies?.forEach( (s) => this.parent.use(s).isPyFnEnabled = !0 )); } else Pt(`missing helper function called "${this.id}"`); return new U( `${this.id}(${t.map((s) => U.raw(s)).join(", ")})`, { is_dynamic: !0, type: n?.type, precedence: _t.SIMPLE } ); } static to_global_code(t) { return Array.from(t.entries()).filter(([, s]) => s.payload.isPyFnEnabled).map(([s]) => { const i = t.helperFunctionsMap.get(s); return i?.py_fn ? i.py_fn()?.trim().split(`\r `) : []; }).flat(); } static createRegistry(t) { return new xr( t, () => new nr() ); } } class xr extends xe { constructor(t, n) { super(t, n), this.helperFunctionsMap = xr.createHelperFunctionsMap(t); } static createHelperFunctionsMap(t) { return /* @__PURE__ */ new Map( [ // const [ "convert_time", { py_fn: () => ` def convert_time(sec): return float_safe(sec) * 1000`, py_dependencies: ["float_safe"], local_fn: (n) => U.toFloat(n) * 1e3, type: G.NUMBER } ], [ "convert_time_back", { py_fn: () => ` def convert_time_back(msec): return float_safe(msec) / 1000`, py_dependencies: ["float_safe"], local_fn: (n) => U.toFloat(n) / 1e3, type: G.NUMBER } ], [ "convert_speed", { py_fn: () => ` def convert_speed(pct): return float_safe(pct) * 10`, local_fn: (n) => U.toFloat(n) * 10, py_dependencies: ["float_safe"], // 100 % = 1080 deg/s for the medium motor // 100 % = 970 deg/s for the large motor. type: G.NUMBER } ], [ "convert_speed_back", { py_fn: () => ` def convert_speed_back(deg_s): return float_safe(deg_s) / 10`, py_dependencies: ["float_safe"], local_fn: (n) => U.toFloat(n) / 10, type: G.NUMBER } ], [ "hub_speaker_flipper_play", { // py_fn: () => ` // ${context.asyncPrefix}def hub_speaker_flipper_play(note, duration): // NOTES = ["C","C#","D","Eb","E","F","F#","G","G#","A","Bb","B"] // note_abc = NOTES[note%12] // octave = str(int(note/12)) // bpm = int(60000 / duration * 4) // ${context.awaitPrefix}hub.speaker.play_notes([f"{note_abc}{octave}/1"], bpm)`, py_fn: () => ` ${t.asyncPrefix}def hub_speaker_flipper_play(note, duration): NOTE_FREQS = [16.35, 17.32, 18.35, 19.45, 20.60, 21.83, 23.12, 24.50, 25.96, 27.50, 29.14, 30.87] freq = NOTE_FREQS[note%12] * (2 ** (note//12)) ${t.awaitPrefix}hub.speaker.beep(freq, duration)` } ], [ "hub_speaker_iconblocks_play", { // 12 bmp with /4 note is 0.5 sec py_fn: () => ` ${t.asyncPrefix}def hub_speaker_iconblocks_play(note): NOTES = [261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25] freq = NOTES[((int(note) if note != "?" else randint(1, 8))%8)-1] ${t.awaitPrefix}hub.speaker.beep(freq, 500)` } ], [ "round", { // py_fn: //none needed local_fn: (n) => be(U.toFloat(n)), type: G.NUMBER } ], [ "float_safe", { py_fn: () => ` def float_safe(value, default=0): try: return float(value) except: return default `, local_fn_condition: (n) => n.every( (s) => typeof s == "number" || typeof s == "string" && String(parseFloat(s)) === s ), local_fn: (n) => U.toFloat(n), type: G.NUMBER } ], [ "str", { // py_fn: //none needed local_fn: (n) => String(n), type: G.STRING } ], [ "int_safe", { py_fn: () => ` def int_safe(value, default=0, base=10): try: return int(value, base) except: return default `, local_fn_condition: (n) => n.every( (s) => typeof s == "number" || typeof s == "string" && String(parseFloat(s)) === s ), local_fn: (n, s = 0, i = 10) => parseInt( U.toString(n), U.toInt(i) ), type: G.NUMBER //TODO add int and float differentiation } ], [ "event_task", { py_fn: () => ` async def event_task(condition_fn, stack_fn): while True: while not await condition_fn(): yield await stack_fn() while await condition_fn(): yield` } ], [ "class_Message", { py_fn: () => ` class Message: def __init__(self, stack_fns): self.running = False self.signalled = False self.cancelling = False self.stack_fns = stack_fns async def main_fn(self): while True: while not self.signalled: yield self.signalled = False await self.action_fn() async def action_fn(self): await self.guard_single() if self.running: self.cancelling = True while self.running: yield self.cancelling = False try: self.running = True await multitask(self.guard_fn(), multitask(*[stack_fn() for stack_fn in self.stack_fns]), race=True) finally: self.running = False def guard_single(self): if self.running: self.cancelling = True while self.running: yield self.cancelling = False def guard_fn(self): while self.running and not self.cancelling: yield async def broadcast_exec(self, wait): if wait: await self.action_fn() else: await self.guard_single() self.signalled = True` } ], [ "convert_distance", { local_fn: (n, s) => { switch (s) { case Qe: return be(U?.toFloat(n) * 10, 2); // cm->mm case Ke: return be(U?.toFloat(n) * 25.4, 2); // in->mm default: return n; } }, py_fn: () => ` def convert_distance(value, unit): if unit == "cm": return value * 10 elif unit == "inches": return value * 25.4 else: return value`, type: G.NUMBER } ], [ "convert_color", { local_fn: (n) => { const s = Array.from(ur.values()), i = U.toInt(n); return i in s ? s[i] : "Color.NONE"; }, py_fn: () => ` def convert_color(value): color_list = [${Array.from(ur.values()).map((n, s) => `${n}`).join(", ")}] return color_list[int_safe(value)]`, py_dependencies: ["int_safe"], type: G.ENUM, imports: [["pybricks.parameters", "Color"]] } ], [ "convert_color_back", { py_fn: () => ` def convert_color_back(value): color_list = [${Array.from(ur.values()).map((n, s) => `${n}`).join(", ")}] return color_list.index(value) if value in color_list else None`, type: G.NUMBER } ], [ "convert_ev3gcolor_back", { py_fn: () => ` def convert_ev3gcolor_back(value): color_list = [${Array.from(Br.values()).map((n, s) => `${n}`).join(", ")}] return color_list.index(value) if value in color_list else None`, type: G.NUMBER } ], [ "convert_color_matrix", { local_fn: (n) => { const s = n?.toString().split("").map( (i) => t.helpers.use("convert_color").call(parseInt(i, 16)) ); return s?.every( (i) => U.isEqual(i, s[0]) ) ? s[0] : `[${s?.join(", ")}]`; }, py_fn: () => ` def convert_color_matrix(colors: Color[]): return [convert_color(int_safe(color,0,16) if color!='?' else randint(0, 10)) for color in colors]`, py_dependencies: ["convert_color", "int_safe"], type: G.ENUMARRAY } ], [ "convert_brightness", { local_fn: (n) => be( Math.min(9, Math.max(0, U.toFloat(n))) / 9 * 100, 3 ), py_fn: () => ` def convert_brightness(value): return round(min(9, max(0, value)) / 9 * 100)`, type: G.NUMBER } ], [ "convert_icon_matrix", { py_fn: () => ` def convert_icon_matrix(value, pixel_brightness=100): return [[round((int(char) if '0' <= char <= '9' else 9 if char == 'x' else randint(1, 9)) / 9 * pixel_brightness) for char in value[i:i+5]] for i in range(0, len(value), 5)]`, // return [[(round((int(char) if '0' <= char <= '9' else 9 if char=='x' else randint(1, 9))/9*brightness)) for char in value[i:i+5]] for i in range(0, len(value), 5)]`, type: G.NUMBERARRAY } ], [ "convert_ussensor_distance", { local_fn: (n, s) => { switch (U.raw(s)) { case Qe: return U.toFloat(n) * 10; // cm->mm case Ke: return U.toFloat(n) * 25.4; // in->mm case "%": return 2e3 * U.toFloat(n) / 100; // 100% = 2000mm default: return n; } }, py_fn: () => ` def convert_ussensor_distance(value, unit): if unit == "cm": return value * 10 elif unit == "inches": return value * 25.4 elif unit == "%": return 2000 * value / 100 else: return value`, type: G.NUMBER } ], [ "convert_ussensor_distance_back", { local_fn: (n, s) => { switch (U.raw(s)) { case Qe: return U.toFloat(n) / 10; // cm->mm case Ke: return U.toFloat(n) / 25.4; // in->mm case "%": return U.toFloat(n) * 100 / 2e3; // 100% = 2000mm default: return n; } }, py_fn: () => ` def convert_ussensor_distance_back(value, unit): if unit == "cm": return value / 10 elif unit == "inches": return value / 25.4 elif unit == "%": return value * 100 / 2000 else: return value`, type: G.NUMBER } ], [ "convert_hub_orientation", { local_fn: (n) => "Side." + U.value(n)?.toString().replace("side", "").toUpperCase(), py_fn: () => ` def convert_hub_orientation(value: str): return 'Side.' + value.replace('side', '').upper()`, type: G.ENUM } ], [ "convert_hub_orientation_back", { // NOOP - local_fn: py_fn: () => ` def convert_hub_orientation_back(value: Side): value = str(value).replace('Side.', '').lower() return value + 'side' if value in ['left','right'] else value`, type: G.STRING } ], [ "convert_display_orientation", { // value is 1..4 local_fn: (n) => { const s = Array.from( as.entries() ).find(([o, l]) => o === U.toInt(n)); return s ? s[1] : "Side.ERROR"; }, py_fn: () => ` def convert_display_orientation(value): return [Side.TOP, Side.LEFT, Side.RIGHT, Side.BOTTOM][value-1]`, imports: [["pybricks.parameters", "Side"]] } ], [ "get_pupdevices", { py_fn: () => ` def get_pupdevices(class_type, *args): for port in [Port.A,Port.B,Port.C,Port.D,Port.E,Port.F]: try: return class_type(port, *args) except: pass` } //TODO: wip, this returns the first device - program should use ALL ], [ "pupdevice_type", { py_fn: () => ` def pupdevice_type(port): try: return PUPDevice(port).info()['id'] except: return None` } ], [ "play_animation", { py_fn: () => ` ${t.asyncPrefix}def play_animation(anim): while True: for frame in anim["frames"]: hub.display.icon(frame) ${t.awaitPrefix}wait(1000/anim["fps"]) if not anim["loop"]: break ` } ], [ "relative_position", { py_fn: () => ` def relative_position(motor): angle_mod = motor.angle() % 360 return angle_mod if angle_mod <= 180 else angle_mod - 360`, type: G.NUMBER } ], [ "motorpair_move", { py_fn: () => ` def motorpair_move(motor_left, motor_right, steer, value): secondary_value = (50 - abs(steer)) * 2 / 100 * value motor_left.run(value if steer>=0 else secondary_value) motor_right.run(value if steer<=0 else secondary_value) ` } ], [ "motorpair_move_dc", { py_fn: () => ` def motorpair_move_dc(motor_left, motor_right, steer, value): secondary_value = (50 - abs(steer)) * 2 / 100 * value motor_left.dc(value if steer>=0 else secondary_value) motor_right.dc(value if steer<=0 else secondary_value) ` } ], [ "convert_ev3button_back", { py_fn: () => ` def convert_ev3button_back(value): value_list = [${Array.from(Mr.values()).map((n, s) => `${n}`).join(", ")}] return value_list.index(value) if value in value_list else None`, type: G.NUMBER } ], [ "check_interrupt_flag", { py_fn: () => ` def check_interrupt_flag(*loop_ids): for index, loop_id in enumerate(loop_ids): if loop_id in g_interrupt_vector: if index == 0: g_interrupt_vector.remove(loop_id) return True return False` } ], [ "set_interrupt_flag", { py_fn: () => ` def set_interrupt_flag(loop_id): g_interrupt_vector.add(loop_id)` } ] ] // num_eval: { // local_fn: num_eval, // local_dynamic_fn: num_eval, // }, ); } } class Le { constructor(t, n, s, i) { this.id = t, this.blockid = s, this.name = n, this.args = i; } getPyName(t) { return `${t ?? ""}${this.name}`; } getPyDefinition(t) { const n = [...this.args.values()].map( (s) => `${s.name}: ${s.type}` ); return `${this.getPyName(t)}(${n.join(", ")})`; } // static getArgDefByArgBlockId(id: string) { // for (const proc of proceduresRegistry.values()) { // for (const arg of proc.payload.args.values()) { // if (arg.id === id) return arg; // } // } // } static getProcName(t) { return Jt( /^(.*?)(?= %[sb])|^.*/.exec(t ?? "")?.[0] ?? "" ); } static create(t, n = !1) { const s = t.getBlock("custom_block"), i = s._block.mutation?.proccode ?? ""; if (n) return t.converter.context.procedures.get(i); const o = this.getProcName(i); if (!o) return; const l = [], a = [], c = []; Object.entries(s._block.inputs).forEach(([d, m]) => { const O = m[1]; if (typeof O != "string") return; const p = s.getPeerById(O); if (!p) return; const g = p.opcode.replace("argument_reporter_", ""), _ = Jt(p.get("VALUE")?.toString()); _ && (c.indexOf(_) >= 0 && Pt(`duplicate argname at ${i} - ${_}/${d}`), c.push(_), a.push(d), l.push(g === "string_number" ? "string" : "boolean")); }); const h = c.reduce((d, m, O) => (d.set(m, { name: m, id: a[O], type: l[O] }), d), /* @__PURE__ */ new Map()); return new Le( i, // will act as id o, t._id, h ); } static createRegistry(t) { return new hs(t); } } class hs extends xe { getByBlockId(t) { return Array.from(this.registry.values()).find( (n) => n.payload.blockid === t )?.payload; } // getByBlockName(name: string): ProcedureRegistryPayload[] { // return Array.from(this.registry.values()) // .filter((proc) => proc.payload.name === name) // .map((elem) => elem.payload); // } } class Ur { constructor(t) { this.context = t; } get devicename() { } setupCode() { return []; } get dependencies() { return []; } ensureDependencies() { } static createRegistry(t) { return /* @__PURE__ */ new Map(); } } class wt extends Ur { constructor(t, n, s) { super(t), this.port = n, this.devicePyClass = s; } get portString() { return wt.portToString(this.port); } get devicename() { return wt.devicenameTemplate(this.port, this.devicePyClass); } static portToString(t) { return `Port.${t}`; } setupCode() { return this._setupCode_internal([]); } _setupCode_internal(t = []) { const n = super.setupCode(); this.context.imports.use("pybricks.parameters", "Port"), this.context.imports.use( this.devicePyClass === "PUPDevice" ? "pybricks.iodevices" : "pybricks.pupdevices", this.devicePyClass ); const s = this.port !== Ht ? `${this.devicePyClass}(${[this.portString].concat(t).join(", ")})` : this.context.helpers.use("get_pupdevices").call([this.devicePyClass].concat(t).join(", ")).raw; return n.push(`${this.devicename} = ${s}`), n; } getDeviceClass() { return this.devicePyClass ?? ""; } static devicenameTemplate(t, n) { return `${n?.toLowerCase() ?? "device"}_${t?.toLowerCase()}`; } static devicenameFromPort(t, n, s) { return n ? [...t.devicesRegistry.entries()].find( (o) => o[1].port === n )?.[0] ?? this.devicenameTemplate(n, s) : ""; } static instance(t, n, s) { const i = this.devicenameFromPort(t, n, s); if (!i) throw new Error(`Device on port ${n} not found`); let o = t.devicesRegistry.get(i); return o ? o.devicePyClass !== s && Pt( `Device on port ${n} is already assigned (${i}) and new deviceClass "${s}" is not matching "${o.devicePyClass}"` ) : (o = this.factory(t, n, s), t.devicesRegistry.set(i, o)), o; } static factory(t, n, s) { return new wt(t, n, s); } } class Mt extends wt { constructor(t, n, s = !0) { super(t, n, "Motor"), this.direction_cw = s, this._default_then = void 0; } static factory(t, n, s) { return new Mt(t, n); } static instance(t, n) { return super.instance(t, n, "Motor"); } get_then() { return this._default_then; } get default_speed_variable() { return `default_speeds[${this.devicename}]`; } set default_then(t) { this._default_then = t; } get devicename() { return Mt.devicenameFromPort(this.context, this.port); } setupCode() { const t = this.direction_cw ? [] : ["Direction.COUNTERCLOCKWISE"]; this.context.imports.use("pybricks.parameters", "Direction"); const n = super._setupCode_internal(t); return this.context.deviceDefaultSpeeds.set( this.devicename, this.context.helpers.use("convert_speed")?.call(50).toString() ), n; } } const fs = 175, ps = 55.7, ds = 117; class kt extends Ur { constructor(t, n, s, i, o = !0) { super(t), this._ports = n, this._wheel_diameter = s, this._axle_track = i, this.isExplicitlyUsed = o; } static { this.DEVICENAME = "drivebase"; } static instance(t, n, s, i, o = !0) { let l = t.devicesRegistry.get( kt.DEVICENAME ); return l ? (l.ports = n ?? l._ports, l.wheel_diameter = s ?? l._wheel_diameter, l.axle_track = i ?? l._axle_track, !l.isExplicitlyUsed && o && (l.isExplicitlyUsed = !0, l.ensureDependencies())) : (l = new kt( t, n, s, i, o ), t.devicesRegistry.set(kt.DEVICENAME, l)), l; } get_then() { return this._default_then && this.context.imports.use("pybricks.parameters", "Stop"), this._default_then; } get default_speed_variable() { return `default_speeds[${this.devicename}]`; } set default_then(t) { this._default_then = t; } get wheel_diameter() { return this._wheel_diameter ?? ps; } set wheel_diameter(t) { this._wheel_diameter = t; } get rotation_distance() { return this._rotation_distance ?? fs; } set rotation_distance(t) { this._rotation_distance = t; } get rotation_distance_variable() { return `${this.devicename}_rotation_distance`; } get axle_track() { return this._axle_track ?? ds; } set axle_track(t) { this._axle_track = t; } get devicename() { return kt.DEVICENAME; } get dependencies() { return this.ensureDependencies(), [this.motor_left, this.motor_right].filter( (t) => !!t ); } get ports() { return this._ports || ["A", "B"]; } set ports(t) { this._ports = t; } setupCode() { if (!this.isExplicitlyUsed) return []; const t = super.setupCode(); return t.push( `${this.devicename} = DriveBase(${this.motor_left?.devicename}, ${this.motor_right?.devicename}, ${this.wheel_diameter}, ${this.axle_track})` ), this.context.deviceDefaultSpeeds.set( this.devicename, this.context.helpers.use("convert_speed")?.call(50).toString() ), t; } ensureDependencies() { if (!this.isExplicitlyUsed) return; const t = (n, s) => { const i = Mt.instance(this.context, n); return i && s !== void 0 && (i.direction_cw = s, i.ensureDependencies()), i; }; if (this.context.imports.use("pybricks.robotics", "DriveBase"), !this.ports || !Array.isArray(this.ports)) throw new Error("Invalid ports"); this.motor_left = t(this.ports[0], !1), this.motor_right = t(this.ports[1], !0); } } class sr { constructor() { this.importedItems = /* @__PURE__ */ new Set(); } // constructor(...importedItems: string[]) { // this.use(...importedItems); // } use(...t) { t.forEach((n) => { n != null && !this.importedItems.has(n) && this.importedItems.add(n); }); } static to_global_code(t) { return Array.from( t.entries().sort( ([n, s], [i, o]) => n.localeCompare(i) ) ).map( ([n, s]) => s?.payload?.importedItems.size > 0 ? `from ${n} import ` + Array.from(s?.payload?.importedItems.keys()).join(", ") : `import ${n}` ); } static createRegistry(t) { return new xe(t, () => new sr()); } } class ir { get py() { return this._py_name_unique; } py_setValue(t, n) { return t.variablesForWriteAccess.add(this), `${this.py} = ${n}`; } constructor(t, n) { this._value = t, this._is_list = n; } use(...t) { this.generateUniqueName(); } generateUniqueName() { const t = typeof this.id == "string" ? this.id : this.id[0]; this._py_name_base = `g_${Jt(t)}`, this._py_name_unique = this.createUniqueName(this._py_name_base); } createUniqueName(t) { const n = [...this.parent.values()].filter( (s) => s.payload._py_name_base === t || s.payload._py_name_unique === t ).length; return n <= 1 ? t : `${t}_${n}`; } static to_global_code(t) { return Array.from(t.entries()).map( ([n, s]) => `${s.payload._py_name_unique} = ${s.payload._value || (s.payload._is_list ? "[]" : "None")}` ); } static createRegistry(t) { return new xe( t, (...n) => new ir( n[0], n[1] ) ); } } class le { //TODO: later add and track lineid constructor() { this.isAsyncNeeded = !1, this.filetype = dt.NONE, this.imports = sr.createRegistry(this), this.broadcasts = Lr.createRegistry(this), this.variables = ir.createRegistry(this), this.procedures = Le.createRegistry(this), this.helpers = nr.createRegistry(this), this.devicesRegistry = Ur.createRegistry(this), this.deviceDefaultSpeeds = /* @__PURE__ */ new Map(), this.pycodeByBlocks = {}; } get awaitPrefix() { return this.isAsyncNeeded ? "await " : ""; } get asyncPrefix() { return this.isAsyncNeeded ? "async " : ""; } clear() { this.imports.clear(), this.broadcasts.clear(), this.variables.clear(), this.procedures.clear(), this.helpers.clear(), this.devicesRegistry.clear(), this.deviceDefaultSpeeds.clear(), this.isAsyncNeeded = !1, this.filetype = dt.NONE; } get filetypeIsSB3() { return this.filetype !== void 0 && (this.filetype & dt._SB3_FORMAT) !== 0; } get filetypeIsSPIKERI() { return this.filetype !== void 0 && (this.filetype & dt._GEN_EV5) !== 0; } get filetypeIsEV3Lab() { return this.filetype !== void 0 && (this.filetype & dt._EV3Lab_FORMAT) !== 0; } } const _s = "_MultiStartBlockParent", Es = "StartBlock", ms = "Interrupt", gs = "StartLoop", Xe = "_ForkParent", Ze = "_ForkItem", Os = "Case", Ts = "ConfigurableWaitFor", or = "ConfigurableWhileLoop", Cs = "MYBLOCK", Rs = "GlobalGet", As = "GlobalSet", Ns = "String", ys = "Boolean", Ps = "Single", Qr = "Array", Is = "CaseSelector.String", vs = "_ForkMergeItem", Kr = "Dummy_StartLoop", Ss = "InterruptName", ws = "InterruptId", Jr = "Pattern", Ls = "MathEquation", Ms = "DEFAULT*", Bs = "MotorPort", xs = "Ports", Us = "Port", Fs = "Port_Number"; var ut = /* @__PURE__ */ ((e) => (e[e.None = 0] = "None", e[e.WhileLoop = 1] = "WhileLoop", e[e.WaitFor = 2] = "WaitFor", e[e.Switch = 3] = "Switch", e[e.SwitchCase = 4] = "SwitchCase", e[e.ForkParent = 5] = "ForkParent", e[e.ForkItem = 6] = "ForkItem", e[e.MyBlockNode = 7] = "MyBlockNode", e[e.TopLevel = 8] = "TopLevel", e))(ut || {}); const Ds = /* @__PURE__ */ new Map([ ["ArrayBuildBoolean", "ArrayOperations.Append_Boolean"], ["ArrayBuild", "ArrayOperations.Append_Numeric"], ["ArrayGetSizeBoolean", "ArrayOperations.Length_Boolean"], ["ArrayGetSize", "ArrayOperations.Length_Numeric"], ["ArrayReadAtIndexBoolean", "ArrayOperations.ReadAtIndex_Boolean"], ["ArrayReadAtIndex", "ArrayOperations.ReadAtIndex_Numeric"], ["ArrayWriteAtIndexBoolean", "ArrayOperations.WriteAtIndex_Boolean"], ["ArrayWriteAtIndex", "ArrayOperations.WriteAtIndex_Numeric"], ["BluetoothMessagingClose", "Bluetooth.Clear"], ["BluetoothMessagingInitiate", "Bluetooth.Initiate"], ["BluetoothMessagingOff", "Bluetooth.Off"], ["BluetoothMessagingOn", "Bluetooth.On"], ["Boolean_And", "BooleanOperations.And"], ["Boolean_Not", "BooleanOperations.Not"], ["Boolean_Or", "BooleanOperations.Or"], ["Boolean_XOr", "BooleanOperations.XOR"], ["ButtonChange", "BrickButton.ChangeBrickButton"], ["ButtonCompare", "BrickButton.Compare"], ["ButtonValue", "BrickButton.Measure"], ["CaseSelector_Boolean", "CaseSelector.Boolean"], ["CaseSelector_Numeric", "CaseSelector.Numeric"], ["CaseSelector_String", "CaseSelector.String"], ["ColorCalibrateMax", "ColorSensor.CalibrateMaxColor"], ["ColorCalibrateMin", "ColorSensor.CalibrateMinColor"], ["ColorCalibrateDefault", "ColorSensor.CalibrateResetColor"], ["ColorAmbientIntensityChange", "ColorSensor.ChangeAmbientLight"], ["ColorChange", "ColorSensor.ChangeColor"], ["ColorReflectedIntensityChange", "ColorSensor.ChangeReflectedLight"], ["ColorAmbientIntensityCompare", "ColorSensor.CompareAmbientLight"], ["ColorCompare", "ColorSensor.CompareColor"], ["ColorReflectedIntensityCompare", "ColorSensor.CompareReflectedLight"], ["ColorAmbientIntensity", "ColorSensor.MeasureAmbientLight"], ["ColorValue", "ColorSensor.MeasureColor"], ["ColorReflectedIntensity", "ColorSensor.MeasureReflectedLight"], ["CommentBlock", "CommentBlock"], ["Comparison_Equal", "Compare.Equal"], ["Comparison_GreaterEqual", "Compare.GreaterOrEqual"], ["Comparison_Greater", "Compare.GreaterThan"], ["Comparison_LessEqual", "Compare.LessOrEqual"], ["Comparison_Less", "Compare.LessThan"], ["Comparison_NotEqual", "Compare.NotEqual"], ["GlobalConstBoolean", "Constant.Boolean"], ["GlobalConstBooleanArray", "Constant.BooleanArray"], ["GlobalConstSingle", "Constant.Numeric"], ["GlobalConstNumericArray", "Constant.NumericArray"], ["GlobalConstString", "Constant.Text"], // ['X3.Lib:GlobalConstBoolean', 'Constant.Boolean'], // ['X3.Lib:GlobalConstBooleanArray', 'Constant.BooleanArray'], // ['X3.Lib:GlobalConstSingle', 'Constant.Numeric'], // ['X3.Lib:GlobalConstNumericArray', 'Constant.NumericArray'], // ['X3.Lib:GlobalConstString', 'Constant.Text'], ["DataLogMasterOn", "Datalogging.On"], ["DataLogMasterMinutes", "Datalogging.OnForTimeMinute"], ["DataLogMaster", "Datalogging.OnForTimeSeconds"], ["DataLogMasterSingle", "Datalogging.SingleMeasurement"], ["DataLogStop", "Datalogging.Stop"], // [ // 'X3Placeholder_2A058539-ED76-4476-93FE-CCE8AA559C5A_DataLogMasterOn', // 'Datalogging.On', // ], // [ // 'X3Placeholder_2A058539-ED76-4476-93FE-CCE8AA559C5A_DataLogMasterMinutes', // 'Datalogging.OnForTimeMinute', // ], // [ // 'X3Placeholder_2A058539-ED76-4476-93FE-CCE8AA559C5A_DataLogMaster', // 'Datalogging.OnForTimeSeconds', // ], // [ // 'X3Placeholder_2A058539-ED76-4476-93FE-CCE8AA559C5A_DataLogMasterSingle', // 'Datalogging.SingleMeasurement', // ], // [ // 'X3Placeholder_2A058539-ED76-4476-93FE-CCE8AA559C5A_DataLogStop', // 'Datalogging.Stop', // ], ["DisplayCircle", "Display.Circle"], ["DisplayClear", "Display.Clear"], ["DisplayFile", "Display.File"], ["DisplayLine", "Display.Line"], ["DisplayPoint", "Display.Point"], ["DisplayRect", "Display.Rectangle"], ["DisplayString", "Display.String"], ["DisplayStringGrid", "Display.StringGrid"], ["EnergyMeterChangeInCurrent", "EnergyMeter.ChangeInCurrent"], ["EnergyMeterChangeInVoltage", "EnergyMeter.ChangeInVoltage"], ["EnergyMeterChangeInWatt", "EnergyMeter.ChangeInWatt"], ["EnergyMeterChangeJoule", "EnergyMeter.ChangeJoule"], ["EnergyMeterChangeOutCurrent", "EnergyMeter.ChangeOutCurrent"], ["EnergyMeterChangeOutVoltage", "EnergyMeter.ChangeOutVoltage"], ["EnergyMeterChangeOutWatt", "EnergyMeter.ChangeOutWatt"], ["EnergyMeterCompareInCurrent", "EnergyMeter.CompareInCurrent"], ["EnergyMeterCompareInVoltage", "EnergyMeter.CompareInVoltage"], ["EnergyMeterCompareInWatt", "EnergyMeter.CompareInWatt"], ["EnergyMeterCompareOutCurrent", "EnergyMeter.CompareOutCurrent"], ["EnergyMeterCompareJoule", "EnergyMeter.CompareOutJoule"], ["EnergyMeterCompareOutVoltage", "EnergyMeter.CompareOutVoltage"], ["EnergyMeterCompareOutWatt", "EnergyMeter.CompareOutWatt"], ["EnergyMeterInCurrent", "EnergyMeter.MeasureInCurrent"], ["EnergyMeterInVoltage", "EnergyMeter.MeasureInVoltage"], ["EnergyMeterInWattage", "EnergyMeter.MeasureInWatts"], ["EnergyMeterJoule", "EnergyMeter.MeasureJoule"], ["EnergyMeterOutCurrent", "EnergyMeter.MeasureOutCurrent"], ["EnergyMeterOutVoltage", "EnergyMeter.MeasureOutVoltage"], ["EnergyMeterOutWattage", "EnergyMeter.MeasureOutWatts"], ["FileClose", "FileAccess.Close"], ["FileDelete", "FileAccess.Delete"], ["FileReadNumeric", "FileAccess.Numeric"], ["FileReadText", "FileAccess.Text"], ["FileWriteText", "FileAccess.Write"], ["DeltaWaitGyroAngle", "Gyro.ChangeAngle"], ["DeltaWaitGyroRate", "Gyro.ChangeRate"], ["GyroAngleCompare", "Gyro.CompareAngle"], ["GyroRateCompare", "Gyro.CompareRate"], ["GyroDegrees", "Gyro.MeasureAngle"], ["GyroAngleAndRate", "Gyro.MeasureAngleAndRate"], ["GyroRate", "Gyro.MeasureRate"], ["GyroReset", "Gyro.Reset"], ["neverUsed_D04426AB-522F-477F-86FA-4A1EEEC45449", "HWPageManualInput"], ["neverUsed_24800E4C-0E91-4B6C-A3B7-2C75465F04B8", "HWPageManualOutput"], ["IRTrackerChangeProximity", "InfraredSensor.ChangeBeaconProximity"], ["IRTrackerChangeHeading", "InfraredSensor.ChangeHeading"], ["IRProximityChange", "InfraredSensor.ChangeProximity"], ["IRRemoteChange", "InfraredSensor.ChangeRemote"], ["IRTrackerCompareHeading", "InfraredSensor.CompareBeaconSeekerHeading"], ["IRTrackerCompareProximity", "InfraredSensor.CompareBeaconSeekerProximity"], ["IRProximityCompare", "InfraredSensor.CompareProximity"], ["IRRemoteCompare", "InfraredSensor.CompareRemote"], ["IRRemote", "InfraredSensor.MeasureBeaconRemote"], ["IRSeeker", "InfraredSensor.MeasureBeaconSeeker"], [ "IRSeekerDataloggingHeading", "InfraredSensor.MeasureBeaconSeekerDataloggingHeading" ], [ "IRSeekerDataloggingProximity", "InfraredSensor.MeasureBeaconSeekerDataloggingProximity" ], ["IRProximity", "InfraredSensor.MeasureProximity"], ["ToggleInterrupt", "Interrupt"], ["InvertMotor", "InvertMotor"], ["KeepAlive", "KeepAlive"], ["LedOff", "LED.Off"], ["LedOn", "LED.On"], ["LedReset", "LED.Reset"], ["StopIfTrue", "LoopCondition.Boolean"], ["StopAfterNumberIterations", "LoopCondition.Count"], ["TimeCompareLoop", "LoopCondition.Time"], ["StopNever", "LoopCondition.Unlimited"], ["LoopIndex", "LoopIndex"], ["Arithmetic_AbsoluteValue", "Math.AbsoluteValue"], ["Arithmetic_Add", "Math.Add"], ["MathEquation", "Math.Advanced"], // [ // 'X3Placeholder_2A058539-ED76-4476-93FE-CCE8AA559C5A_MathEquation', // 'Math.Advanced', // ], ["Arithmetic_Divide", "Math.Divide"], ["Arithmetic_Power", "Math.Exponent"], ["Arithmetic_Multiply", "Math.Multiply"], ["Arithmetic_SquareRoot", "Math.SquareRoot"], ["Arithmetic_Subtract", "Math.Subtract"], ["MediumMotorDistance", "MediumMotor.Degrees"], ["MediumMotorDistanceRotations", "MediumMotor.Rotations"], ["MediumMotorStop", "MediumMotor.Stop"], ["MediumMotorTime", "MediumMotor.Time"], ["MediumMotorUnlimited", "MediumMotor.Unlimited"], ["MessageUpdateBoolean", "Messaging.ChangeBooleanUpdate"], ["MessageChangeValueBoolean", "Messaging.ChangeBooleanValue"], ["MessageUpdateNumeric", "Messaging.ChangeNumericUpdate"], ["MessageChangeValueNumeric", "Messaging.ChangeNumericValue"], ["MessageUpdateText", "Messaging.ChangeTextUpdate"], ["MessageChangeValueText", "Messaging.ChangeTextValue"], ["MessageCompareBoolean", "Messaging.CompareBoolean"], ["MessageCompareNumeric", "Messaging.CompareNumeric"], ["MessageCompareText", "Messaging.CompareText"], ["ReceiveMessageBoolean", "Messaging.ReceiveBoolean"], ["ReceiveMessageNumeric", "Messaging.ReceiveNumeric"], ["ReceiveMessage", "Messaging.ReceiveText"], ["SendMessageBoolean", "Messaging.SendBoolean"], ["SendMessageNumeric", "Messaging.SendNumeric"], ["SendMessage", "Messaging.SendText"], ["MotorDistance", "Motor.Degrees"], ["MotorDistanceRotations", "Motor.Rotations"], ["MotorStop", "Motor.Stop"], ["MotorTime", "Motor.Time"], ["MotorUnlimited", "Motor.Unlimited"], ["MoveDistance", "Move.Degrees"], ["MoveDistanceRotations", "Move.Rotations"], ["MoveStop", "Move.Stop"], ["MoveTime", "Move.