blocklypy
Version:
BlocklyPy: SPIKE to Pybricks - word-block converter to Pybricks python code
1,535 lines • 593 kB
JavaScript
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.