pxt-core 8.2.6 → 8.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/built/cli.js +1 -0
  2. package/built/pxt-common.json +1 -1
  3. package/built/pxt.js +69 -26
  4. package/built/pxtblockly.js +37 -9
  5. package/built/pxtblocks.d.ts +1 -0
  6. package/built/pxtblocks.js +37 -9
  7. package/built/pxtcompiler.js +3 -3
  8. package/built/pxteditor.js +5 -0
  9. package/built/pxtlib.js +26 -7
  10. package/built/pxtpy.d.ts +1 -0
  11. package/built/pxtpy.js +39 -16
  12. package/built/pxtrunner.js +13 -0
  13. package/built/target.js +1 -1
  14. package/built/web/blockly.css +1 -1
  15. package/built/web/main.js +1 -1
  16. package/built/web/pxtapp.js +1 -1
  17. package/built/web/pxtblockly.js +1 -1
  18. package/built/web/pxtblocks.js +1 -1
  19. package/built/web/pxtcompiler.js +1 -1
  20. package/built/web/pxteditor.js +1 -1
  21. package/built/web/pxtembed.js +2 -2
  22. package/built/web/pxtlib.js +1 -1
  23. package/built/web/pxtpy.js +1 -1
  24. package/built/web/pxtrunner.js +1 -1
  25. package/built/web/pxtworker.js +1 -1
  26. package/built/web/react-common-authcode.css +98 -0
  27. package/built/web/react-common-skillmap.css +1 -1
  28. package/built/web/rtlblockly.css +1 -1
  29. package/built/web/rtlreact-common-skillmap.css +1 -1
  30. package/built/web/rtlsemantic.css +1 -1
  31. package/built/web/semantic.css +1 -1
  32. package/built/web/skillmap/css/main.3684f34d.chunk.css +1 -0
  33. package/built/web/skillmap/js/2.26325281.chunk.js +2 -0
  34. package/built/web/skillmap/js/main.d94a2bd9.chunk.js +1 -0
  35. package/localtypings/pxtarget.d.ts +16 -0
  36. package/localtypings/react.d.ts +5 -0
  37. package/package.json +1 -1
  38. package/react-common/components/controls/Checkbox.tsx +1 -1
  39. package/react-common/components/palette/ColorPickerField.tsx +65 -0
  40. package/react-common/components/palette/PaletteEditor.tsx +66 -0
  41. package/react-common/components/palette/PalettePicker.tsx +52 -0
  42. package/react-common/components/palette/PaletteSwatch.tsx +27 -0
  43. package/react-common/components/palette/Palettes.ts +289 -0
  44. package/react-common/components/profile/SignInModal.tsx +100 -0
  45. package/react-common/components/profile/UserPane.tsx +17 -9
  46. package/react-common/styles/palette/ColorPickerField.less +21 -0
  47. package/react-common/styles/palette/PalettePicker.less +10 -0
  48. package/react-common/styles/palette/PaletteSwatch.less +27 -0
  49. package/react-common/styles/palette/palette.less +3 -0
  50. package/react-common/styles/profile/profile.less +64 -1
  51. package/react-common/styles/react-common.less +1 -0
  52. package/theme/blockly-core.less +1 -1
  53. package/theme/common.less +13 -2
  54. package/theme/image-editor/bottomBar.less +1 -1
  55. package/theme/tutorial-sidebar.less +2 -2
  56. package/webapp/public/skillmap.html +2 -2
  57. package/built/web/skillmap/css/main.c5811548.chunk.css +0 -1
  58. package/built/web/skillmap/js/2.26b9a6f6.chunk.js +0 -2
  59. package/built/web/skillmap/js/main.98eed582.chunk.js +0 -1
@@ -3185,6 +3185,22 @@ var pxt;
3185
3185
  }
3186
3186
  });
3187
3187
  }
3188
+ function validateAllReferencedBlocksExist(xml) {
3189
+ pxt.U.assert(!!(Blockly === null || Blockly === void 0 ? void 0 : Blockly.Blocks), "Called validateAllReferencedBlocksExist before initializing Blockly");
3190
+ const dom = Blockly.Xml.textToDom(xml);
3191
+ const blocks = dom.querySelectorAll("block");
3192
+ for (let i = 0; i < blocks.length; i++) {
3193
+ if (!Blockly.Blocks[blocks.item(i).getAttribute("type")])
3194
+ return false;
3195
+ }
3196
+ const shadows = dom.querySelectorAll("shadow");
3197
+ for (let i = 0; i < shadows.length; i++) {
3198
+ if (!Blockly.Blocks[shadows.item(i).getAttribute("type")])
3199
+ return false;
3200
+ }
3201
+ return true;
3202
+ }
3203
+ blocks_2.validateAllReferencedBlocksExist = validateAllReferencedBlocksExist;
3188
3204
  })(blocks = pxt.blocks || (pxt.blocks = {}));
3189
3205
  })(pxt || (pxt = {}));
3190
3206
  var pxt;
@@ -3206,6 +3222,7 @@ var pxt;
3206
3222
  const newDom = Blockly.Xml.workspaceToDom(newWs, true);
3207
3223
  pxt.Util.toArray(oldDom.childNodes)
3208
3224
  .filter((n) => n.nodeType == Node.ELEMENT_NODE && n.localName == "block" && n.getAttribute("disabled") == "true")
3225
+ .filter((n) => !!Blockly.Blocks[n.getAttribute("type")])
3209
3226
  .forEach(n => newDom.appendChild(newDom.ownerDocument.importNode(n, true)));
3210
3227
  const updatedXml = Blockly.Xml.domToText(newDom);
3211
3228
  return updatedXml;
@@ -4151,6 +4168,14 @@ var pxt;
4151
4168
  blocksXml: `<xml xmlns="http://www.w3.org/1999/xhtml">${cleanOuterHTML(blockXml)}</xml>`,
4152
4169
  };
4153
4170
  }
4171
+ function attachCardInfo(blockInfo, qName) {
4172
+ const toModify = blockInfo.apis.byQName[qName];
4173
+ if (toModify) {
4174
+ const comp = blocks_4.compileInfo(toModify);
4175
+ const xml = createToolboxBlock(blockInfo, toModify, comp);
4176
+ return mkCard(toModify, xml);
4177
+ }
4178
+ }
4154
4179
  function isSubtype(apis, specific, general) {
4155
4180
  if (specific == general)
4156
4181
  return true;
@@ -4498,7 +4523,7 @@ var pxt;
4498
4523
  * Used by pxtrunner to initialize blocks in the docs
4499
4524
  */
4500
4525
  function initializeAndInject(blockInfo) {
4501
- init();
4526
+ init(blockInfo);
4502
4527
  injectBlocks(blockInfo);
4503
4528
  }
4504
4529
  blocks_4.initializeAndInject = initializeAndInject;
@@ -4507,12 +4532,12 @@ var pxt;
4507
4532
  * Blocks are injected separately by called injectBlocks
4508
4533
  */
4509
4534
  function initialize(blockInfo) {
4510
- init();
4535
+ init(blockInfo);
4511
4536
  initJresIcons(blockInfo);
4512
4537
  }
4513
4538
  blocks_4.initialize = initialize;
4514
4539
  let blocklyInitialized = false;
4515
- function init() {
4540
+ function init(blockInfo) {
4516
4541
  if (blocklyInitialized)
4517
4542
  return;
4518
4543
  blocklyInitialized = true;
@@ -4523,7 +4548,7 @@ var pxt;
4523
4548
  blocks_4.initFieldEditors();
4524
4549
  initContextMenu();
4525
4550
  initOnStart();
4526
- initMath();
4551
+ initMath(blockInfo);
4527
4552
  initVariables();
4528
4553
  initFunctions();
4529
4554
  initLists();
@@ -5383,9 +5408,10 @@ var pxt;
5383
5408
  }
5384
5409
  };
5385
5410
  }
5386
- function initMath() {
5411
+ function initMath(blockInfo) {
5387
5412
  // math_op2
5388
5413
  const mathOp2Id = "math_op2";
5414
+ const mathOp2qName = "Math.min"; // TODO: implement logic so that this changes based on which is used (min or max)
5389
5415
  const mathOp2Def = pxt.blocks.getBlockDefinition(mathOp2Id);
5390
5416
  const mathOp2Tooltips = mathOp2Def.tooltip;
5391
5417
  Blockly.Blocks[mathOp2Id] = {
@@ -5421,11 +5447,13 @@ var pxt;
5421
5447
  setHelpResources(this, mathOp2Id, mathOp2Def.name, function (block) {
5422
5448
  return mathOp2Tooltips[block.getFieldValue('op')];
5423
5449
  }, mathOp2Def.url, pxt.toolbox.getNamespaceColor(mathOp2Def.category));
5424
- }
5450
+ },
5451
+ codeCard: attachCardInfo(blockInfo, mathOp2qName)
5425
5452
  };
5426
5453
  // math_op3
5427
5454
  const mathOp3Id = "math_op3";
5428
5455
  const mathOp3Def = pxt.blocks.getBlockDefinition(mathOp3Id);
5456
+ const mathOp3qName = "Math.abs";
5429
5457
  Blockly.Blocks[mathOp3Id] = {
5430
5458
  init: function () {
5431
5459
  this.jsonInit({
@@ -5443,7 +5471,8 @@ var pxt;
5443
5471
  "colour": pxt.toolbox.getNamespaceColor('math')
5444
5472
  });
5445
5473
  setBuiltinHelpInfo(this, mathOp3Id);
5446
- }
5474
+ },
5475
+ codeCard: attachCardInfo(blockInfo, mathOp3qName)
5447
5476
  };
5448
5477
  // builtin math_number, math_integer, math_whole_number, math_number_minmax
5449
5478
  //XXX Integer validation needed.
@@ -8389,7 +8418,6 @@ var pxtblockly;
8389
8418
  this.fieldGroup_.appendChild(bg.el);
8390
8419
  const icon = new svg.Text("\uf008")
8391
8420
  .at(X_PADDING, 5 + (TOTAL_HEIGHT >> 1))
8392
- .fill(this.sourceBlock_.getColourSecondary())
8393
8421
  .setClass("semanticIcon");
8394
8422
  this.fieldGroup_.appendChild(icon.el);
8395
8423
  if (this.asset) {
@@ -9907,7 +9935,7 @@ var pxtblockly;
9907
9935
  return function () {
9908
9936
  const res = [];
9909
9937
  const that = this;
9910
- if (that.sourceBlock_ && that.sourceBlock_.workspace) {
9938
+ if (that.sourceBlock_ && that.sourceBlock_.workspace && !that.sourceBlock_.isInFlyout) {
9911
9939
  const options = that.sourceBlock_.workspace.getVariablesOfType(kindType(opts.name));
9912
9940
  options.forEach(model => {
9913
9941
  res.push([model.name, model.name]);
@@ -6258,7 +6258,7 @@ ${output}</xml>`;
6258
6258
  if (alias) {
6259
6259
  info.decompilerBlockAlias = env.aliasBlocks[info.qName];
6260
6260
  }
6261
- else {
6261
+ else if (!env.opts.snippetMode) {
6262
6262
  return pxtc.Util.lf("No output expressions as statements");
6263
6263
  }
6264
6264
  }
@@ -13817,7 +13817,7 @@ var ts;
13817
13817
  snippetMode: opts.snippetMode || false,
13818
13818
  alwaysEmitOnStart: opts.alwaysDecompileOnStart,
13819
13819
  includeGreyBlockMessages,
13820
- generateSourceMap: !!opts.ast,
13820
+ generateSourceMap: opts.generateSourceMap !== undefined ? opts.generateSourceMap : !!opts.ast,
13821
13821
  allowedArgumentTypes: opts.allowedArgumentTypes || ["number", "boolean", "string"],
13822
13822
  errorOnGreyBlocks: !!opts.errorOnGreyBlocks
13823
13823
  };
@@ -13835,7 +13835,7 @@ var ts;
13835
13835
  snippetMode: opts.snippetMode || false,
13836
13836
  alwaysEmitOnStart: opts.alwaysDecompileOnStart,
13837
13837
  includeGreyBlockMessages,
13838
- generateSourceMap: !!opts.ast,
13838
+ generateSourceMap: opts.generateSourceMap !== undefined ? opts.generateSourceMap : !!opts.ast,
13839
13839
  allowedArgumentTypes: opts.allowedArgumentTypes || ["number", "boolean", "string"],
13840
13840
  errorOnGreyBlocks: !!opts.errorOnGreyBlocks
13841
13841
  };
@@ -558,6 +558,11 @@ var pxt;
558
558
  name: lf("Blocks Error List"),
559
559
  description: lf("Show an error list panel for Blocks")
560
560
  },
561
+ {
562
+ id: "palettePicker",
563
+ name: lf("Change Color Palette"),
564
+ description: lf("Change the game palette in project settings")
565
+ },
561
566
  ].filter(experiment => ids.indexOf(experiment.id) > -1 && !(pxt.BrowserUtils.isPxtElectron() && experiment.enableOnline));
562
567
  }
563
568
  experiments_1.all = all;
package/built/pxtlib.js CHANGED
@@ -4110,7 +4110,7 @@ var pxt;
4110
4110
  MATH_ADDITION_SYMBOL: pxt.Util.lf("{id:op}+"),
4111
4111
  MATH_SUBTRACTION_SYMBOL: pxt.Util.lf("{id:op}-"),
4112
4112
  MATH_MULTIPLICATION_SYMBOL: pxt.Util.lf("{id:op}×"),
4113
- MATH_DIVISION_SYMBOL: pxt.Util.lf("{id:op}÷"),
4113
+ MATH_DIVISION_SYMBOL: pxt.Util.lf("{id:op}/"),
4114
4114
  MATH_POWER_SYMBOL: pxt.Util.lf("{id:op}**")
4115
4115
  }
4116
4116
  },
@@ -4120,7 +4120,7 @@ var pxt;
4120
4120
  url: '/blocks/math',
4121
4121
  category: 'math',
4122
4122
  block: {
4123
- MATH_MODULO_TITLE: pxt.Util.lf("remainder of %1 ÷ %2")
4123
+ MATH_MODULO_TITLE: pxt.Util.lf("remainder of %1 / %2")
4124
4124
  }
4125
4125
  },
4126
4126
  'math_js_op': {
@@ -4149,7 +4149,7 @@ var pxt;
4149
4149
  "acos": pxt.Util.lf("{id:op}acos"),
4150
4150
  "tan": pxt.Util.lf("{id:op}tan"),
4151
4151
  "atan2": pxt.Util.lf("{id:op}atan2"),
4152
- "idiv": pxt.Util.lf("{id:op}integer ÷"),
4152
+ "idiv": pxt.Util.lf("{id:op}integer /"),
4153
4153
  "imul": pxt.Util.lf("{id:op}integer ×"),
4154
4154
  }
4155
4155
  },
@@ -19318,6 +19318,7 @@ var pxt;
19318
19318
  diffify(steps, activities);
19319
19319
  }
19320
19320
  const assetFiles = parseAssetJson(assetJson);
19321
+ const globalBlockConfig = parseTutorialBlockConfig("global", tutorialmd);
19321
19322
  // strip hidden snippets
19322
19323
  steps.forEach(step => {
19323
19324
  step.contentMd = stripHiddenSnippets(step.contentMd);
@@ -19337,7 +19338,8 @@ var pxt;
19337
19338
  jres,
19338
19339
  assetFiles,
19339
19340
  customTs,
19340
- tutorialValidationRules
19341
+ tutorialValidationRules,
19342
+ globalBlockConfig
19341
19343
  };
19342
19344
  }
19343
19345
  tutorial.parseTutorial = parseTutorial;
@@ -19364,6 +19366,8 @@ var pxt;
19364
19366
  switch (m1) {
19365
19367
  case "block":
19366
19368
  case "blocks":
19369
+ case "blockconfig.local":
19370
+ case "blockconfig.global":
19367
19371
  case "requiredTutorialBlock":
19368
19372
  case "filterblocks":
19369
19373
  if (!checkTutorialEditor(pxt.BLOCKS_PROJECT_NAME))
@@ -19516,6 +19520,7 @@ ${code}
19516
19520
  markdown.replace(stepRegex, function (match, flags, step) {
19517
19521
  step = step.trim();
19518
19522
  let { header, hint, requiredBlocks } = parseTutorialHint(step, metadata && metadata.explicitHints, metadata.tutorialCodeValidation);
19523
+ const blockConfig = parseTutorialBlockConfig("local", step);
19519
19524
  // if title is not hidden ("{TITLE HERE}"), strip flags
19520
19525
  const title = !flags.match(/^\{.*\}$/)
19521
19526
  ? flags.replace(/@(fullscreen|unplugged|showdialog|showhint|tutorialCompleted|resetDiff)/gi, "").trim()
@@ -19523,7 +19528,8 @@ ${code}
19523
19528
  let info = {
19524
19529
  title,
19525
19530
  contentMd: step,
19526
- headerContentMd: header
19531
+ headerContentMd: header,
19532
+ localBlockConfig: blockConfig
19527
19533
  };
19528
19534
  if (/@(fullscreen|unplugged|showdialog|showhint)/i.test(flags))
19529
19535
  info.showHint = true;
@@ -19578,6 +19584,18 @@ ${code}
19578
19584
  }
19579
19585
  return { header, hint, requiredBlocks };
19580
19586
  }
19587
+ function parseTutorialBlockConfig(scope, content) {
19588
+ let blockConfig = {
19589
+ md: "",
19590
+ blocks: [],
19591
+ };
19592
+ const regex = new RegExp(`\`\`\`\\s*blockconfig\\.${scope}\\s*\\n([\\s\\S]*?)\\n\`\`\``, "gmi");
19593
+ content.replace(regex, (m0, m1) => {
19594
+ blockConfig.md += `${m1}\n`;
19595
+ return "";
19596
+ });
19597
+ return blockConfig;
19598
+ }
19581
19599
  function categorizingValidationRules(listOfRules, title) {
19582
19600
  const ruleNames = Object.keys(listOfRules);
19583
19601
  for (let i = 0; i < ruleNames.length; i++) {
@@ -19593,7 +19611,7 @@ ${code}
19593
19611
  function stripHiddenSnippets(str) {
19594
19612
  if (!str)
19595
19613
  return str;
19596
- const hiddenSnippetRegex = /```(filterblocks|package|ghost|config|template|jres|assetjson|customts)\s*\n([\s\S]*?)\n```/gmi;
19614
+ const hiddenSnippetRegex = /```(filterblocks|package|ghost|config|template|jres|assetjson|customts|blockconfig\.local|blockconfig\.global)\s*\n([\s\S]*?)\n```/gmi;
19597
19615
  return str.replace(hiddenSnippetRegex, '').trim();
19598
19616
  }
19599
19617
  /*
@@ -19675,7 +19693,8 @@ ${code}
19675
19693
  jres: tutorialInfo.jres,
19676
19694
  assetFiles: tutorialInfo.assetFiles,
19677
19695
  customTs: tutorialInfo.customTs,
19678
- tutorialValidationRules: tutorialInfo.tutorialValidationRules
19696
+ tutorialValidationRules: tutorialInfo.tutorialValidationRules,
19697
+ globalBlockConfig: tutorialInfo.globalBlockConfig
19679
19698
  };
19680
19699
  return { options: tutorialOptions, editor: tutorialInfo.editor };
19681
19700
  }
package/built/pxtpy.d.ts CHANGED
@@ -145,6 +145,7 @@ declare namespace pxt.py {
145
145
  vars: Map<ScopeSymbolInfo>;
146
146
  parent?: ScopeDef;
147
147
  blockDepth?: number;
148
+ nextHelperVariableId?: number;
148
149
  }
149
150
  interface FunctionDef extends Symbol, ScopeDef {
150
151
  kind: "FunctionDef";
package/built/pxtpy.js CHANGED
@@ -342,6 +342,13 @@ var pxt;
342
342
  error(a, 9503, pxt.U.lf("No module named '{0}'", name));
343
343
  return sym;
344
344
  }
345
+ function getHelperVariableName() {
346
+ const scope = currentScope();
347
+ if (scope.nextHelperVariableId === undefined) {
348
+ scope.nextHelperVariableId = 0;
349
+ }
350
+ return "___tempvar" + scope.nextHelperVariableId++;
351
+ }
345
352
  function defvar(name, opts, modifier, scope) {
346
353
  if (!scope)
347
354
  scope = currentScope();
@@ -1648,20 +1655,7 @@ var pxt;
1648
1655
  return B.mkStmt(B.mkText(pref), B.mkInfix(expr(target), "=", expr(value)));
1649
1656
  }
1650
1657
  if (!pref && target.kind == "Tuple") {
1651
- let tup = target;
1652
- let targs = [B.mkText("let "), B.mkText("[")];
1653
- let nonNames = tup.elts.filter(e => e.kind !== "Name");
1654
- if (nonNames.length) {
1655
- error(n, 9556, pxt.U.lf("non-trivial tuple assignment unsupported"));
1656
- return stmtTODO(n);
1657
- }
1658
- let tupNames = tup.elts
1659
- .map(e => e)
1660
- .map(convertName);
1661
- targs.push(B.mkCommaSep(tupNames));
1662
- targs.push(B.mkText("]"));
1663
- let res = B.mkStmt(B.mkInfix(B.mkGroup(targs), "=", expr(value)));
1664
- return res;
1658
+ return convertDestructuring(n, target, value);
1665
1659
  }
1666
1660
  if (target.kind === "Name") {
1667
1661
  const scopeSym = currentScope().vars[nm];
@@ -1689,12 +1683,41 @@ var pxt;
1689
1683
  if (!lExp)
1690
1684
  lExp = expr(target);
1691
1685
  return B.mkStmt(B.mkText(pref), B.mkInfix(lExp, "=", expr(value)));
1692
- function convertName(n) {
1686
+ }
1687
+ function convertDestructuring(parent, targets, value) {
1688
+ let nonNames = targets.elts.filter(e => e.kind !== "Name");
1689
+ if (nonNames.length) {
1690
+ error(parent, 9556, pxt.U.lf("non-trivial tuple assignment unsupported"));
1691
+ return stmtTODO(parent);
1692
+ }
1693
+ const names = targets.elts.map(tryGetName);
1694
+ const symbols = names
1695
+ .map(nm => nm ? currentScope().vars[nm] : undefined);
1696
+ if (symbols.some(s => (s === null || s === void 0 ? void 0 : s.modifier) !== undefined)) {
1697
+ const helperVar = getHelperVariableName();
1698
+ const valueAssign = B.mkStmt(B.mkInfix(B.mkGroup([B.mkText("let "), B.mkText(helperVar)]), "=", expr(value)));
1699
+ const assignStatements = [valueAssign];
1700
+ for (let i = 0; i < symbols.length; i++) {
1701
+ const name = convertName(targets.elts[i]);
1702
+ assignStatements.push(B.mkStmt(B.mkInfix(name, "=", B.mkGroup([B.mkText(helperVar), B.mkText(`[${i}]`)]))));
1703
+ }
1704
+ return B.mkGroup(assignStatements);
1705
+ }
1706
+ else {
1707
+ let targs = [B.mkText("let "), B.mkText("[")];
1708
+ let tupNames = targets.elts
1709
+ .map(e => e)
1710
+ .map(e => convertName(e, true));
1711
+ targs.push(B.mkCommaSep(tupNames));
1712
+ targs.push(B.mkText("]"));
1713
+ return B.mkStmt(B.mkInfix(B.mkGroup(targs), "=", expr(value)));
1714
+ }
1715
+ function convertName(n, excludeLet = false) {
1693
1716
  // TODO resuse with Name expr
1694
1717
  markInfoNode(n, "identifierCompletion");
1695
1718
  typeOf(n);
1696
1719
  let v = lookupName(n);
1697
- return possibleDef(n, /*excludeLet*/ true);
1720
+ return possibleDef(n, excludeLet);
1698
1721
  }
1699
1722
  }
1700
1723
  function possibleDef(n, excludeLet = false) {
@@ -1319,6 +1319,18 @@ var pxt;
1319
1319
  c = c.parent();
1320
1320
  c.remove();
1321
1321
  }
1322
+ function renderBlockConfig(options) {
1323
+ function render(scope) {
1324
+ $(`code.lang-blockconfig.${scope}`).each((i, c) => {
1325
+ let $c = $(c);
1326
+ if (options.snippetReplaceParent)
1327
+ $c = $c.parent();
1328
+ $c.remove();
1329
+ });
1330
+ }
1331
+ render("local");
1332
+ render("global");
1333
+ }
1322
1334
  function renderSims(options) {
1323
1335
  if (!options.simulatorClass)
1324
1336
  return;
@@ -1359,6 +1371,7 @@ var pxt;
1359
1371
  readAssetJson(options);
1360
1372
  renderQueue = [];
1361
1373
  renderGhost(options);
1374
+ renderBlockConfig(options);
1362
1375
  renderSims(options);
1363
1376
  renderTypeScript(options);
1364
1377
  renderDirectPython(options);