UNPKG

blocklypy

Version:

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

1,535 lines 727 kB
class qn { constructor(e, n) { this.id = qn.idToString(e), this.payload = n; } static idToString(e) { return typeof e == "string" ? e : JSON.stringify(e); } } function km(r) { return !!r && typeof r.use == "function"; } function Vm(r) { return !!r; } function Gm(r) { return !!r; } class hi { constructor(e, n) { this.context = e, this.factory = n, this.registry = /* @__PURE__ */ new Map(); } get(e) { return this.registry.get(qn.idToString(e))?.payload; } has(e) { return this.registry.has(qn.idToString(e)); } use(e, ...n) { let o = this.registry.get(qn.idToString(e)); if (!o) { const a = typeof this.factory == "function" ? this.factory(...n) : n[0]; Vm(a) && (a.id = e), Gm(a) && (a.parent = this), o = new qn(e, a), this.registry.set(qn.idToString(e), o); } return o.payload && km(o.payload) && o.payload.use(...n), o.payload; } entries() { return [...this.registry.entries()]; } values() { return [...this.registry.values()]; } payloads() { return [...this.registry.values()].map((e) => e.payload); } clear() { this.registry.clear(); } } const fs = " ", hs = "cm", ps = "inches", Pn = "rotations", Rs = "degrees", pi = "seconds", pn = "AUTO"; var ti = /* @__PURE__ */ ((r) => (r[r.DEBUG = 0] = "DEBUG", r[r.INFO = 1] = "INFO", r[r.WARNING = 2] = "WARNING", r[r.ERROR = 3] = "ERROR", r[r.CRITICAL = 4] = "CRITICAL", r))(ti || {}); let wc = 0, qo; function $m(r) { wc = r; } function ec(r) { qo = r; } function ta(r, e, n = "-", o = 80) { const a = o - r.length - 6 - e?.length; return `#${e} ${n.repeat( Math.floor(a / 2) )} ${r} ${n.repeat(Math.ceil(a / 2))} #`; } function Wm(r, ...e) { if (wc <= r) if (qo) qo(r, ...e); else switch (r) { case 4: case 3: console.error(`::${ti[r]}::`, ...e); break; case 2: console.warn(`::${ti[r]}::`, ...e); break; case 1: console.info(`::${ti[r]}::`, ...e); break; case 0: default: console.debug(`::${ti[r]}::`, ...e); break; } } const fe = (...r) => Wm(2, ...r); function ae(r, e = 1) { let n = []; return r === void 0 ? n = [] : Array.isArray(r) ? n = r.reduce( (o, a) => [...o, ...ae(a, e)], [] ) : r.includes(` `) ? n = ae(r.split(/\r?\n/), e) : n = [fs.repeat(e) + r], n; } function Ar(r, e = !0) { if (!r.filter((n) => !n.match(/^\s*$|^\s*#.*$/)).length) { r.push("pass"); //!! } return r; } function Gn(r) { return r?.trim().toLowerCase().replaceAll(/[ .-]/gi, "_").replace(/^(\d)/im, "_$1").replaceAll( /[áéíóöőúüű]/g, (e) => ({ á: "a", é: "e", í: "i", ó: "o", ö: "o", ő: "o", ú: "u", ü: "u", ű: "u" })[e] ?? e ).replace(/[^a-zA-Z0-9_]/g, ""); } function tr(r) { return r?.replace(/\.[^/.]+$/, "").replaceAll(" ", "_"); } function Qe(r, e = !0) { return r = r?.replaceAll(/\\(.)/g, "$1").replaceAll(" ", "_").replaceAll(/[\/,.]/g, ""), e && (r = r?.toUpperCase()), r; } function Ym(r) { return typeof r == "number"; } function $n(r) { const e = r?.lastIndexOf("."); return r === void 0 || e === -1 || e === void 0 ? "" : r.substring(e); } function Je(r) { return r?.replace(/^.*[\\/]/, ""); } function _s(r) { return r?.split(".").slice(0, -1).join("."); } function ca(r) { const e = r?.trim().toLowerCase(); return e === "true" || e === "1"; } function Se(r) { return parseInt(r ?? "0"); } function fa(r) { return `"""\r ` + r.map(([e, n]) => `${(e + ":").padEnd(12, " ")}${n}`).join(`\r `) + `\r """\r `; } function ha(r, e) { return e.extra || (e.extra = {}), e.extra[r] || (e.extra[r] = {}), e.extra[r]; } class pa { constructor(e) { this.name = e; } // Generates the code for the broadcast registry payload get_code(e) { const n = e.map((o) => Gn(o)); return `${this.get_pyname()} = Message([${n.join(", ")}])`; } // Returns the sanitized Python name for the message get_pyname() { return `message_${Gn(this.name)}`; } // Creates a new registry manager for the broadcast registry payload static createRegistry(e) { return new hi( e, (...n) => new pa(n[0]) ); } } var Gt = /* @__PURE__ */ ((r) => (r[r.NONE = 0] = "NONE", r[r.SPIKE = 1] = "SPIKE", r[r.ROBOTINVENTOR = 2] = "ROBOTINVENTOR", r[r._GEN_EV5 = 3] = "_GEN_EV5", r[r.EV3CLASSROOM = 4] = "EV3CLASSROOM", r[r._SB3_FORMAT = 7] = "_SB3_FORMAT", r[r.EV3G = 8] = "EV3G", r[r.EV3B = 16] = "EV3B", r[r._GEN_EV3 = 28] = "_GEN_EV3", r[r._EV3Lab_FORMAT = 24] = "_EV3Lab_FORMAT", r[r.PYTHON = 32] = "PYTHON", r[r.WEDO2 = 64] = "WEDO2", r))(Gt || {}), Ht = /* @__PURE__ */ ((r) => (r[r.SIMPLE = 0] = "SIMPLE", r[r.PARENTHESIS = 1] = "PARENTHESIS", r[r.REFERENCE = 2] = "REFERENCE", r[r.EXPONENTIATION = 3] = "EXPONENTIATION", r[r.UNARY = 4] = "UNARY", r[r.BINARYOP_MUL = 5] = "BINARYOP_MUL", r[r.BINARY_ADD = 6] = "BINARY_ADD", r[r.BINARY_SHIFT = 7] = "BINARY_SHIFT", r[r.BINARY_AND = 8] = "BINARY_AND", r[r.BINARY_XOR = 9] = "BINARY_XOR", r[r.BINARY_OR = 10] = "BINARY_OR", r[r.BINARY_COMPARISON = 11] = "BINARY_COMPARISON", r[r.BOOLEAN_NOT = 12] = "BOOLEAN_NOT", r[r.BOOLEAN_AND = 13] = "BOOLEAN_AND", r[r.BOOLEAN_OR = 14] = "BOOLEAN_OR", r[r.WEAKEST = 99] = "WEAKEST", r))(Ht || {}), q = /* @__PURE__ */ ((r) => (r[r.UNKNOWN = 0] = "UNKNOWN", r[r.NUMBER = 10] = "NUMBER", r[r.STRING = 11] = "STRING", r[r.BOOLEAN = 12] = "BOOLEAN", r[r.ENUM = 13] = "ENUM", r[r.NUMBERARRAY = 20] = "NUMBERARRAY", r[r.BOOLEANARRAY = 21] = "BOOLEANARRAY", r[r.ENUMARRAY = 23] = "ENUMARRAY", r))(q || {}); class K { constructor(e, n) { this.options = n, e && K.is(e) ? this.value = e.value : this.value = e; } get is_string() { return this.options?.type === q.STRING; } get is_numeric() { return this.options?.type === q.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 K.toString(this); } toInt() { return K.toInt(this); } toFloat() { return K.toFloat(this); } toBool() { return K.toBool(this); } ensureString(e) { return ea(e, this, q.STRING); } ensureNumber(e, n = !1) { if (this.is_numeric) { if (this.options?.is_dynamic) return this; { const o = n ? this.toInt() : this.toFloat(); return new K(o, { type: q.NUMBER }); } } else return ea(e, this, q.NUMBER, n); } static is(e) { return e instanceof K; } static is_dynamic(e) { return K.is(e) && !!e.options?.is_dynamic; } static raw(e) { return K.is(e) ? e.raw : e; } static value(e) { return K.is(e) ? e.value : e; } static toString(e) { return K.value(e)?.toString() ?? ""; } static toInt(e) { const n = K.is(e) ? e.value : e; return parseInt(n?.toString() ?? ""); } static toFloat(e) { const n = K.is(e) ? e.value : e; return parseFloat(n?.toString() ?? ""); } static toBool(e) { const n = K.is(e) ? e.value : e; return ca(n?.toString()); } static ensureNumber(e, n, o = !1) { return K.is(n) ? n.ensureNumber(e) : e.helpers.use(o ? "int_safe" : "float_safe").call(n); } static isEqual(e, n) { return K.is(e) && K.is(n) ? e.value === n.value && JSON.stringify(e.options) === JSON.stringify(n.options) : e === n; } } function ie(r, e, n = !1) { const [o, a, l] = Array.isArray(e) ? e : [e, void 0, void 0]; if (a === void 0) { if (Array.isArray(o)) return ie(r, o, n); if (!K.is_dynamic(o)) { const f = Math.round(parseFloat(o?.toString() ?? "") * 1e3) / 1e3; return new K(f, { type: q.NUMBER }); } return !K.is(o) || o.options?.type !== q.NUMBER ? K.ensureNumber(r, o, n) : new K(o, { type: q.NUMBER, is_dynamic: o.options.is_dynamic, precedence: o.options.precedence }); } else if (l === void 0) { const f = ie(r, a, n), c = !K.is_dynamic(f); if (o === "-" || o === "+") if (c) { const _ = (o === "-" ? -1 : 1) * K.toFloat(f); return new K(_, { type: q.NUMBER }); } else { const h = `${o}${K.raw(f)}`; return new K(h, { is_dynamic: !0, type: q.NUMBER, precedence: Ht.UNARY }); } else if (o === "abs") return c ? new K(Math.abs(K.toFloat(f)), { type: q.NUMBER }) : (r.imports.use("umath", null), new K(`umath.fabs(${K.raw(f)})`, { is_dynamic: !0, type: q.NUMBER, precedence: Ht.SIMPLE })); } else { const f = ie(r, o, n), c = ie(r, l, n); let h = K.raw(f), _ = K.raw(c); if (!K.is_dynamic(f) && !K.is_dynamic(c)) { const C = (g, R, O) => { switch (R) { case "+": return g + O; case "-": return g - O; case "*": return g * O; case "/": return g / O; case "%": return g % O; } }; if (h === void 0 || a === void 0 || _ === void 0) return; const N = ie( r, C(K.toFloat(h), a?.toString(), K.toFloat(_)) ); return new K(N, { type: q.NUMBER, precedence: Ht.SIMPLE }); } else { const C = ie(r, o, n), N = ie(r, l, n), g = a?.toString(), R = (S) => S?.toString() === "0", O = (S) => S?.toString() === "1", v = (S) => S?.toString() === "-1"; if (g === "*") { if (R(C) || O(N)) return C; if (R(N) || O(C)) return N; if (v(C)) return ie(r, ["-", N]); if (v(N)) return ie(r, ["-", C]); } else if (g === "/") { if (R(C) || O(N)) return C; if (v(N)) return ie(r, ["-", C]); } else if (g === "+") { if (R(C)) return N; if (R(N)) return C; } else if (g === "-") { if (R(C)) return ie(r, ["-", N]); if (R(N)) return C; } const P = (() => { switch (a.toString()) { case "-": case "+": return Ht.BINARY_ADD; case "*": case "/": case "%": return Ht.BINARYOP_MUL; default: return Ht.WEAKEST; } })(); return P < (C?.options?.precedence ?? 0) && (h = `(${h})`), P < (N?.options?.precedence ?? 0) && (_ = `(${_})`), new K(`${h} ${a} ${_}`, { is_dynamic: !0, type: q.NUMBER, precedence: P }); } } } function ea(r, e, n, o = !1) { const a = e?.options?.type; if (n !== a) switch (n) { case q.NUMBER: e = o ? r.helpers.use("int_safe").call(e) : r.helpers.use("float_safe").call(e); break; case q.STRING: e = r.helpers.use("str").call(e); break; case q.NUMBERARRAY: switch (a) { case q.NUMBER: e = new K(`[${e?.raw}]`, { is_dynamic: !0, is_variable: !0, type: q.NUMBERARRAY }); break; } break; case q.BOOLEANARRAY: switch (a) { case q.BOOLEAN: e = new K(`[${e?.raw}]`, { is_dynamic: !0, is_variable: !0, type: q.BOOLEANARRAY }); break; } break; } return e; } const nc = /* @__PURE__ */ new Map([ [0, "Stop.COAST"], [1, "Stop.BRAKE"], [2, "Stop.HOLD"] ]), Sc = /* @__PURE__ */ new Map([ [0, "Stop.COAST"], [1, "Stop.HOLD"] ]), zm = /* @__PURE__ */ new Map([ [1, "Side.TOP"], [2, "Side.LEFT"], [3, "Side.RIGHT"], [4, "Side.BOTTOM"] ]), zo = /* @__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"] ]), da = /* @__PURE__ */ new Map([ [0, "Button.NONE"], [1, "Button.LEFT"], [2, "Button.CENTER"], [3, "Button.RIGHT"], [4, "Button.UP"], [5, "Button.DOWN"] ]), Hm = /* @__PURE__ */ new Map([ [0, "RELEASED"], [1, "PRESSED"] ]); var Lc = /* @__PURE__ */ ((r) => (r[r.OFF = 0] = "OFF", r[r.GREEN = 1] = "GREEN", r[r.RED = 2] = "RED", r[r.ORANGE = 3] = "ORANGE", r[r.GREEN_PULSE = 4] = "GREEN_PULSE", r[r.RED_PULSE = 5] = "RED_PULSE", r[r.ORANGE_PULSE = 6] = "ORANGE_PULSE", r))(Lc || {}); const Km = /* @__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"] ]), Qm = /* @__PURE__ */ new Map([ [0, "Color.GREEN"], [1, "Color.RED"], [2, "Color.ORANGE"] ]), _a = /* @__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 Mc(r, e = -1) { if (r.imports.use("pybricks.parameters", "Stop"), nc.has(e)) return nc.get(e); } function rs(r, e = 0) { const n = 10 ** e; return Math.round(r * n) / n; } function xc(r) { return r?.value === "=" ? "==" : r?.value?.toString(); } function li(r) { return ["==", "!=", ">", ">=", "<", "<="][r?.toInt() ?? -1]; } class As { constructor() { this.isPyFnEnabled = !1; } call(...e) { const n = this.parent.helperFunctionsMap.get(this.id); if (n) { if (n.imports?.forEach( ([o, a]) => this.parent.context.imports.use(o, a) ), n.local_fn) { if (e.every((a) => !K.is_dynamic(a)) && (!n.local_fn_condition || n.local_fn_condition( e.map((a) => K.value(a)) ))) { const a = n.local_fn( ...e.map((l) => K.value(l)) //? .raw ); return K.is(a) ? a : new K(a, { precedence: Ht.SIMPLE, type: n.type ?? (typeof a == "string" ? q.STRING : q.NUMBER) }); //!! } else if (n.local_dynamic_fn) { const a = n.local_fn(...e); return K.is(a) ? a : new K(a, { is_dynamic: !0, type: n.type ?? (typeof a == "string" ? q.STRING : q.NUMBER) }); } } n.py_fn && (this.isPyFnEnabled = !0, n.py_dependencies?.forEach( (o) => this.parent.use(o).isPyFnEnabled = !0 )); } else fe(`missing helper function called "${this.id}"`); return new K( `${this.id}(${e.map((o) => K.raw(o)).join(", ")})`, { is_dynamic: !0, type: n?.type, precedence: Ht.SIMPLE } ); } static to_global_code(e) { return Array.from(e.entries()).filter(([, o]) => o.payload.isPyFnEnabled).map(([o]) => { const a = e.helperFunctionsMap.get(o); return a?.py_fn ? a.py_fn()?.trim().split(`\r `) : []; }).flat(); } static createRegistry(e) { return new Ea( e, () => new As() ); } } class Ea extends hi { constructor(e, n) { super(e, n), this.helperFunctionsMap = Ea.createHelperFunctionsMap(e); } static createHelperFunctionsMap(e) { 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) => K.toFloat(n) * 1e3, type: q.NUMBER } ], [ "convert_time_back", { py_fn: () => ` def convert_time_back(msec): return float_safe(msec) / 1000`, py_dependencies: ["float_safe"], local_fn: (n) => K.toFloat(n) / 1e3, type: q.NUMBER } ], [ "convert_speed", { py_fn: () => ` def convert_speed(pct): return float_safe(pct) * 10`, local_fn: (n) => K.toFloat(n) * 10, py_dependencies: ["float_safe"], // 100 % = 1080 deg/s for the medium motor // 100 % = 970 deg/s for the large motor. type: q.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) => K.toFloat(n) / 10, type: q.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: () => ` ${e.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)) ${e.awaitPrefix}hub.speaker.beep(freq, duration)` } ], [ "hub_speaker_iconblocks_play", { // 12 bmp with /4 note is 0.5 sec py_fn: () => ` ${e.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] ${e.awaitPrefix}hub.speaker.beep(freq, 500)` } ], [ "round", { // py_fn: //none needed local_fn: (n) => rs(K.toFloat(n)), type: q.NUMBER } ], [ "float_safe", { py_fn: () => ` def float_safe(value, default=0): try: return float(value) except: return default `, local_fn_condition: (n) => n.every( (o) => typeof o == "number" || typeof o == "string" && String(parseFloat(o)) === o ), local_fn: (n) => K.toFloat(n), type: q.NUMBER } ], [ "str", { // py_fn: //none needed local_fn: (n) => String(n), type: q.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( (o) => typeof o == "number" || typeof o == "string" && String(parseFloat(o)) === o ), local_fn: (n, o = 0, a = 10) => parseInt( K.toString(n), K.toInt(a) ), type: q.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, o) => { switch (o) { case hs: return rs(K?.toFloat(n) * 10, 2); // cm->mm case ps: return rs(K?.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: q.NUMBER } ], [ "convert_color", { local_fn: (n) => { const o = Array.from(zo.values()), a = K.toInt(n); return a in o ? o[a] : "Color.NONE"; }, py_fn: () => ` def convert_color(value): color_list = [${Array.from(zo.values()).map((n, o) => `${n}`).join(", ")}] return color_list[int_safe(value)]`, py_dependencies: ["int_safe"], type: q.ENUM, imports: [["pybricks.parameters", "Color"]] } ], [ "convert_color_back", { py_fn: () => ` def convert_color_back(value): color_list = [${Array.from(zo.values()).map((n, o) => `${n}`).join(", ")}] return color_list.index(value) if value in color_list else None`, type: q.NUMBER } ], [ "convert_ev3gcolor_back", { py_fn: () => ` def convert_ev3gcolor_back(value): color_list = [${Array.from(_a.values()).map((n, o) => `${n}`).join(", ")}] return color_list.index(value) if value in color_list else None`, type: q.NUMBER } ], [ "convert_color_matrix", { local_fn: (n) => { const o = n?.toString().split("").map( (a) => e.helpers.use("convert_color").call(parseInt(a, 16)) ); return o?.every( (a) => K.isEqual(a, o[0]) ) ? o[0] : `[${o?.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: q.ENUMARRAY } ], [ "convert_brightness", { local_fn: (n) => rs( Math.min(9, Math.max(0, K.toFloat(n))) / 9 * 100, 3 ), py_fn: () => ` def convert_brightness(value): return round(min(9, max(0, value)) / 9 * 100)`, type: q.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: q.NUMBERARRAY } ], [ "convert_ussensor_distance", { local_fn: (n, o) => { switch (K.raw(o)) { case hs: return K.toFloat(n) * 10; // cm->mm case ps: return K.toFloat(n) * 25.4; // in->mm case "%": return 2e3 * K.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: q.NUMBER } ], [ "convert_ussensor_distance_back", { local_fn: (n, o) => { switch (K.raw(o)) { case hs: return K.toFloat(n) / 10; // cm->mm case ps: return K.toFloat(n) / 25.4; // in->mm case "%": return K.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: q.NUMBER } ], [ "convert_hub_orientation", { local_fn: (n) => "Side." + K.value(n)?.toString().replace("side", "").toUpperCase(), py_fn: () => ` def convert_hub_orientation(value: str): return 'Side.' + value.replace('side', '').upper()`, type: q.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: q.STRING } ], [ "convert_display_orientation", { // value is 1..4 local_fn: (n) => { const o = Array.from( zm.entries() ).find(([l, f]) => l === K.toInt(n)); return o ? o[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: () => ` ${e.asyncPrefix}def play_animation(anim): while True: for frame in anim["frames"]: hub.display.icon(frame) ${e.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: q.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(da.values()).map((n, o) => `${n}`).join(", ")}] return value_list.index(value) if value in value_list else None`, type: q.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 ui { constructor(e, n, o, a) { this.id = e, this.blockid = o, this.name = n, this.args = a; } getPyName(e) { return `${e ?? ""}${this.name}`; } getPyDefinition(e) { const n = [...this.args.values()].map( (o) => `${o.name}: ${o.type}` ); return `${this.getPyName(e)}(${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(e) { return Gn( /^(.*?)(?= %[sb])|^.*/.exec(e ?? "")?.[0] ?? "" ); } static create(e, n = !1) { const o = e.getBlock("custom_block"), a = o._block.mutation?.proccode ?? ""; if (n) return e.converter.context.procedures.get(a); const l = this.getProcName(a); if (!l) return; const f = [], c = [], h = []; Object.entries(o._block.inputs).forEach(([m, C]) => { const N = C[1]; if (typeof N != "string") return; const g = o.getPeerById(N); if (!g) return; const R = g.opcode.replace("argument_reporter_", ""), O = Gn(g.get("VALUE")?.toString()); O && (h.indexOf(O) >= 0 && fe(`duplicate argname at ${a} - ${O}/${m}`), h.push(O), c.push(m), f.push(R === "string_number" ? "string" : "boolean")); }); const _ = h.reduce((m, C, N) => (m.set(C, { name: C, id: c[N], type: f[N] }), m), /* @__PURE__ */ new Map()); return new ui( a, // will act as id l, e._id, _ ); } static createRegistry(e) { return new Jm(e); } } class Jm extends hi { getByBlockId(e) { return Array.from(this.registry.values()).find( (n) => n.payload.blockid === e )?.payload; } // getByBlockName(name: string): ProcedureRegistryPayload[] { // return Array.from(this.registry.values()) // .filter((proc) => proc.payload.name === name) // .map((elem) => elem.payload); // } } class ga { constructor(e) { this.context = e; } get devicename() { } setupCode() { return []; } get dependencies() { return []; } ensureDependencies() { } static createRegistry(e) { return /* @__PURE__ */ new Map(); } } class Te extends ga { constructor(e, n, o) { super(e), this.port = n, this.devicePyClass = o; } get portString() { return Te.portToString(this.port); } get devicename() { return Te.devicenameTemplate(this.port, this.devicePyClass); } static portToString(e) { return `Port.${e}`; } setupCode() { return this._setupCode_internal([]); } _setupCode_internal(e = []) { 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 o = this.port !== pn ? `${this.devicePyClass}(${[this.portString].concat(e).join(", ")})` : this.context.helpers.use("get_pupdevices").call([this.devicePyClass].concat(e).join(", ")).raw; return n.push(`${this.devicename} = ${o}`), n; } getDeviceClass() { return this.devicePyClass ?? ""; } static devicenameTemplate(e, n) { return `${n?.toLowerCase() ?? "device"}_${e?.toLowerCase()}`; } static devicenameFromPort(e, n, o) { return n ? [...e.devicesRegistry.entries()].find( (l) => l[1].port === n )?.[0] ?? this.devicenameTemplate(n, o) : ""; } static instance(e, n, o) { const a = this.devicenameFromPort(e, n, o); if (!a) throw new Error(`Device on port ${n} not found`); let l = e.devicesRegistry.get(a); return l ? l.devicePyClass !== o && fe( `Device on port ${n} is already assigned (${a}) and new deviceClass "${o}" is not matching "${l.devicePyClass}"` ) : (l = this.factory(e, n, o), e.devicesRegistry.set(a, l)), l; } static factory(e, n, o) { return new Te(e, n, o); } } class Ae extends Te { constructor(e, n, o = !0) { super(e, n, "Motor"), this.direction_cw = o, this._default_then = void 0; } static factory(e, n, o) { return new Ae(e, n); } static instance(e, n) { return super.instance(e, n, "Motor"); } get_then() { return this._default_then; } get default_speed_variable() { return `default_speeds[${this.devicename}]`; } set default_then(e) { this._default_then = e; } get devicename() { return Ae.devicenameFromPort(this.context, this.port); } setupCode() { const e = this.direction_cw ? [] : ["Direction.COUNTERCLOCKWISE"]; this.context.imports.use("pybricks.parameters", "Direction"); const n = super._setupCode_internal(e); return this.context.deviceDefaultSpeeds.set( this.devicename, this.context.helpers.use("convert_speed")?.call(50).toString() ), n; } } const Xm = 175, jm = 55.7, Zm = 117; class Ge extends ga { constructor(e, n, o, a, l = !0) { super(e), this._ports = n, this._wheel_diameter = o, this._axle_track = a, this.isExplicitlyUsed = l; } static { this.DEVICENAME = "drivebase"; } static instance(e, n, o, a, l = !0) { let f = e.devicesRegistry.get( Ge.DEVICENAME ); return f ? (f.ports = n ?? f._ports, f.wheel_diameter = o ?? f._wheel_diameter, f.axle_track = a ?? f._axle_track, !f.isExplicitlyUsed && l && (f.isExplicitlyUsed = !0, f.ensureDependencies())) : (f = new Ge( e, n, o, a, l ), e.devicesRegistry.set(Ge.DEVICENAME, f)), f; } 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(e) { this._default_then = e; } get wheel_diameter() { return this._wheel_diameter ?? jm; } set wheel_diameter(e) { this._wheel_diameter = e; } get rotation_distance() { return this._rotation_distance ?? Xm; } set rotation_distance(e) { this._rotation_distance = e; } get rotation_distance_variable() { return `${this.devicename}_rotation_distance`; } get axle_track() { return this._axle_track ?? Zm; } set axle_track(e) { this._axle_track = e; } get devicename() { return Ge.DEVICENAME; } get dependencies() { return this.ensureDependencies(), [this.motor_left, this.motor_right].filter( (e) => !!e ); } get ports() { return this._ports || ["A", "B"]; } set ports(e) { this._ports = e; } setupCode() { if (!this.isExplicitlyUsed) return []; const e = super.setupCode(); return e.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() ), e; } ensureDependencies() { if (!this.isExplicitlyUsed) return; const e = (n, o) => { const a = Ae.instance(this.context, n); return a && o !== void 0 && (a.direction_cw = o, a.ensureDependencies()), a; }; if (this.context.imports.use("pybricks.robotics", "DriveBase"), !this.ports || !Array.isArray(this.ports)) throw new Error("Invalid ports"); this.motor_left = e(this.ports[0], !1), this.motor_right = e(this.ports[1], !0); } } class Ns { constructor() { this.importedItems = /* @__PURE__ */ new Set(); } // constructor(...importedItems: string[]) { // this.use(...importedItems); // } use(...e) { e.forEach((n) => { n != null && !this.importedItems.has(n) && this.importedItems.add(n); }); } static to_global_code(e) { return Array.from( e.entries().sort( ([n, o], [a, l]) => n.localeCompare(a) ) ).map( ([n, o]) => o?.payload?.importedItems.size > 0 ? `from ${n} import ` + Array.from(o?.payload?.importedItems.keys()).join(", ") : `import ${n}` ); } static createRegistry(e) { return new hi(e, () => new Ns()); } } class vs { get py() { return this._py_name_unique; } py_setValue(e, n) { return e.variablesForWriteAccess.add(this), `${this.py} = ${n}`; } constructor(e, n) { this._value = e, this._is_list = n; } use(...e) { this.generateUniqueName(); } generateUniqueName() { const e = typeof this.id == "string" ? this.id : this.id[0]; this._py_name_base = `g_${Gn(e)}`, this._py_name_unique = this.createUniqueName(this._py_name_base); } createUniqueName(e) { const n = [...this.parent.values()].filter( (o) => o.payload._py_name_base === e || o.payload._py_name_unique === e ).length; return n <= 1 ? e : `${e}_${n}`; } static to_global_code(e) { return Array.from(e.entries()).map( ([n, o]) => `${o.payload._py_name_unique} = ${o.payload._value || (o.payload._is_list ? "[]" : "None")}` ); } static createRegistry(e) { return new hi( e, (...n) => new vs( n[0], n[1] ) ); } } class vr { //TODO: later add and track lineid constructor() { this.isAsyncNeeded = !1, this.filetype = Gt.NONE, this.imports = Ns.createRegistry(this), this.broadcasts = pa.createRegistry(this), this.variables = vs.createRegistry(this), this.procedures = ui.createRegistry(this), this.helpers = As.createRegistry(this), this.devicesRegistry = ga.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 = Gt.NONE; } get filetypeIsSB3() { return this.filetype !== void 0 && (this.filetype & Gt._SB3_FORMAT) !== 0; } get filetypeIsSPIKERI() { return this.filetype !== void 0 && (this.filetype & Gt._GEN_EV5) !== 0; } get filetypeIsEV3Lab() { return this.filetype !== void 0 && (this.filetype & Gt._EV3Lab_FORMAT) !== 0; } } const qm = "_MultiStartBlockParent", t1 = "StartBlock", e1 = "Interrupt", n1 = "StartLoop", Es = "_ForkParent", gs = "_ForkItem", r1 = "Case", i1 = "ConfigurableWaitFor", ys = "ConfigurableWhileLoop", s1 = "MYBLOCK", o1 = "GlobalGet", a1 = "GlobalSet", l1 = "String", u1 = "Boolean", c1 = "Single", rc = "Array", f1 = "CaseSelector.String", h1 = "_ForkMergeItem", ic = "Dummy_StartLoop", p1 = "InterruptName", d1 = "InterruptId", sc = "Pattern", _1 = "MathEquation", E1 = "DEFAULT*", g1 = "MotorPort", m1 = "Ports", O1 = "Port", T1 = "Port_Number"; var Ut = /* @__PURE__ */ ((r) => (r[r.None = 0] = "None", r[r.WhileLoop = 1] = "WhileLoop", r[r.WaitFor = 2] = "WaitFor", r[r.Switch = 3] = "Switch", r[r.SwitchCase = 4] = "SwitchCase", r[r.ForkParent = 5] = "ForkParent", r[r.ForkItem = 6] = "ForkItem", r[r.MyBlockNode = 7] = "MyBlockNode", r[r.TopLevel = 8] = "TopLevel", r))(Ut || {}); const C1 = /* @__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.