diff --git a/Blockly/html/agc/blocks/logic.js b/Blockly/html/agc/blocks/logic.js
index c604429..06d4d58 100644
--- a/Blockly/html/agc/blocks/logic.js
+++ b/Blockly/html/agc/blocks/logic.js
@@ -5,7 +5,7 @@
Blockly.defineBlocksWithJsonArray([
{
- 'type': 'agc_controls_if',
+ 'type': 'controls_if',
'message0': '%{BKY_CONTROLS_IF_MSG_IF} %1',
'args0': [
{
@@ -28,7 +28,7 @@ Blockly.defineBlocksWithJsonArray([
'helpUrl': '%{BKY_CONTROLS_IF_HELPURL}',
},
{
- 'type': 'agc_controls_ifelse',
+ 'type': 'controls_ifelse',
'message0': '%{BKY_CONTROLS_IF_MSG_IF} %1',
'args0': [
{
@@ -59,7 +59,7 @@ Blockly.defineBlocksWithJsonArray([
},
// Block for boolean data type: true and false.
{
- 'type': 'agc_logic_boolean',
+ 'type': 'logic_boolean',
'message0': '%1',
'args0': [
{
@@ -78,7 +78,7 @@ Blockly.defineBlocksWithJsonArray([
},
// Block for comparison operator.
{
- 'type': 'agc_logic_compare',
+ 'type': 'logic_compare',
'message0': '%1 %2 %3',
'args0': [
{
@@ -110,7 +110,7 @@ Blockly.defineBlocksWithJsonArray([
},
// Block for logical operations: 'and', 'or'.
{
- 'type': 'agc_logic_operation',
+ 'type': 'logic_operation',
'message0': '%1 %2 %3',
'args0': [
{
@@ -140,7 +140,7 @@ Blockly.defineBlocksWithJsonArray([
},
// Block for negation.
{
- 'type': 'agc_logic_negate',
+ 'type': 'logic_negate',
'message0': '%{BKY_LOGIC_NEGATE_TITLE}',
'args0': [
{
@@ -156,7 +156,7 @@ Blockly.defineBlocksWithJsonArray([
},
// Block for ternary operator.
{
- 'type': 'agc_logic_ternary',
+ 'type': 'logic_ternary',
'message0': '%{BKY_LOGIC_TERNARY_CONDITION} %1',
'args0': [
{
@@ -186,3 +186,144 @@ Blockly.defineBlocksWithJsonArray([
'extensions': ['logic_ternary'],
},
]);
+
+(function() {
+ /**
+ * Adds dynamic type validation for the left and right sides of a logic_compare
+ * block.
+ * @mixin
+ * @augments Blockly.Block
+ * @package
+ * @readonly
+ */
+ const LOGIC_COMPARE_ONCHANGE_MIXIN = {
+ /**
+ * Called whenever anything on the workspace changes.
+ * Prevent mismatched types from being compared.
+ * @param {!Blockly.Events.Abstract} e Change event.
+ * @this {Blockly.Block}
+ */
+ onchange: function(e) {
+ if (!this.prevBlocks_) {
+ this.prevBlocks_ = [null, null];
+ }
+
+ const blockA = this.getInputTargetBlock('A');
+ const blockB = this.getInputTargetBlock('B');
+ // Disconnect blocks that existed prior to this change if they don't match.
+ if (blockA && blockB &&
+ !this.workspace.connectionChecker.doTypeChecks(
+ blockA.outputConnection, blockB.outputConnection)) {
+ // Mismatch between two inputs. Revert the block connections,
+ // bumping away the newly connected block(s).
+ Blockly.Events.setGroup(e.group);
+ const prevA = this.prevBlocks_[0];
+ if (prevA !== blockA) {
+ blockA.unplug();
+ if (prevA && !prevA.isDisposed() && !prevA.isShadow()) {
+ // The shadow block is automatically replaced during unplug().
+ this.getInput('A').connection.connect(prevA.outputConnection);
+ }
+ }
+ const prevB = this.prevBlocks_[1];
+ if (prevB !== blockB) {
+ blockB.unplug();
+ if (prevB && !prevB.isDisposed() && !prevB.isShadow()) {
+ // The shadow block is automatically replaced during unplug().
+ this.getInput('B').connection.connect(prevB.outputConnection);
+ }
+ }
+ this.bumpNeighbours();
+ Blockly.Events.setGroup(false);
+ }
+ this.prevBlocks_[0] = this.getInputTargetBlock('A');
+ this.prevBlocks_[1] = this.getInputTargetBlock('B');
+ },
+ };
+
+ /**
+ * "logic_compare" extension function. Adds type left and right side type
+ * checking to "logic_compare" blocks.
+ * @this {Blockly.Block}
+ * @package
+ * @readonly
+ */
+ const LOGIC_COMPARE_EXTENSION = function() {
+ // Add onchange handler to ensure types are compatible.
+ this.mixin(LOGIC_COMPARE_ONCHANGE_MIXIN);
+ };
+
+ Blockly.Extensions.register('logic_compare', LOGIC_COMPARE_EXTENSION);
+
+ /**
+ * Tooltip text, keyed by block OP value. Used by logic_compare and
+ * logic_operation blocks.
+ * @see {Blockly.Extensions#buildTooltipForDropdown}
+ * @package
+ * @readonly
+ */
+ const TOOLTIPS_BY_OP = {
+ // logic_compare
+ 'EQ': '%{BKY_LOGIC_COMPARE_TOOLTIP_EQ}',
+ 'NEQ': '%{BKY_LOGIC_COMPARE_TOOLTIP_NEQ}',
+ 'LT': '%{BKY_LOGIC_COMPARE_TOOLTIP_LT}',
+ 'LTE': '%{BKY_LOGIC_COMPARE_TOOLTIP_LTE}',
+ 'GT': '%{BKY_LOGIC_COMPARE_TOOLTIP_GT}',
+ 'GTE': '%{BKY_LOGIC_COMPARE_TOOLTIP_GTE}',
+
+ // logic_operation
+ 'AND': '%{BKY_LOGIC_OPERATION_TOOLTIP_AND}',
+ 'OR': '%{BKY_LOGIC_OPERATION_TOOLTIP_OR}',
+ };
+
+ Blockly.Extensions.register('logic_op_tooltip',
+ Blockly.Extensions.buildTooltipForDropdown('OP', TOOLTIPS_BY_OP));
+
+ /**
+ * Adds type coordination between inputs and output.
+ * @mixin
+ * @augments Blockly.Block
+ * @package
+ * @readonly
+ */
+ const LOGIC_TERNARY_ONCHANGE_MIXIN = {
+ prevParentConnection_: null,
+
+ /**
+ * Called whenever anything on the workspace changes.
+ * Prevent mismatched types.
+ * @param {!Blockly.Events.Abstract} e Change event.
+ * @this {Blockly.Block}
+ */
+ onchange: function(e) {
+ const blockA = this.getInputTargetBlock('THEN');
+ const blockB = this.getInputTargetBlock('ELSE');
+ const parentConnection = this.outputConnection.targetConnection;
+ // Disconnect blocks that existed prior to this change if they don't match.
+ if ((blockA || blockB) && parentConnection) {
+ for (let i = 0; i < 2; i++) {
+ const block = (i === 1) ? blockA : blockB;
+ if (block &&
+ !block.workspace.connectionChecker.doTypeChecks(
+ block.outputConnection, parentConnection)) {
+ // Ensure that any disconnections are grouped with the causing event.
+ Blockly.Events.setGroup(e.group);
+ if (parentConnection === this.prevParentConnection_) {
+ this.unplug();
+ parentConnection.getSourceBlock().bumpNeighbours();
+ } else {
+ block.unplug();
+ block.bumpNeighbours();
+ }
+ Blockly.Events.setGroup(false);
+ }
+ }
+ }
+ this.prevParentConnection_ = parentConnection;
+ },
+ };
+
+ Blockly.Extensions.registerMixin('logic_ternary',
+ LOGIC_TERNARY_ONCHANGE_MIXIN);
+
+})();
diff --git a/Blockly/html/agc/blocks/loops.js b/Blockly/html/agc/blocks/loops.js
index a0104a6..7da5ba2 100644
--- a/Blockly/html/agc/blocks/loops.js
+++ b/Blockly/html/agc/blocks/loops.js
@@ -6,7 +6,7 @@
Blockly.defineBlocksWithJsonArray([
// Block for 'do while/until' loop.
{
- 'type': 'agc_controls_whileUntil',
+ 'type': 'controls_whileUntil',
'message0': '%1 %2',
'args0': [
{
@@ -37,3 +37,11 @@ Blockly.defineBlocksWithJsonArray([
'extensions': ['controls_whileUntil_tooltip'],
},
]);
+
+
+Blockly.Extensions.register('controls_whileUntil_tooltip',
+ Blockly.Extensions.buildTooltipForDropdown(
+ 'MODE', {
+ 'WHILE': '%{BKY_CONTROLS_WHILEUNTIL_TOOLTIP_WHILE}',
+ 'UNTIL': '%{BKY_CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL}',
+}));
diff --git a/Blockly/html/agc/blocks/math.js b/Blockly/html/agc/blocks/math.js
index 5edf836..a53eaf5 100644
--- a/Blockly/html/agc/blocks/math.js
+++ b/Blockly/html/agc/blocks/math.js
@@ -6,7 +6,7 @@
Blockly.defineBlocksWithJsonArray([
// Block for numeric value.
{
- 'type': 'agc_math_number',
+ 'type': 'math_number',
'message0': '%1',
'args0': [{
'type': 'field_number',
@@ -25,7 +25,7 @@ Blockly.defineBlocksWithJsonArray([
// Block for basic arithmetic operator.
{
- 'type': 'agc_math_arithmetic',
+ 'type': 'math_arithmetic',
'message0': '%1 %2 %3',
'args0': [
{
@@ -57,7 +57,7 @@ Blockly.defineBlocksWithJsonArray([
// Block for random integer between 0 and [X-1].
{
- "type": "agc_math_random_int_0",
+ "type": "math_random_int_0",
"message0": "random integer to %1",
"args0": [
{
@@ -75,7 +75,7 @@ Blockly.defineBlocksWithJsonArray([
// Block for random integer between [X] and [Y].
{
- "type": "agc_math_random_int",
+ "type": "math_random_int",
"message0": "%{BKY_MATH_RANDOM_INT_TITLE}",
"args0": [
{
@@ -95,4 +95,81 @@ Blockly.defineBlocksWithJsonArray([
"tooltip": "%{BKY_MATH_RANDOM_INT_TOOLTIP}",
"helpUrl": "%{BKY_MATH_RANDOM_INT_HELPURL}",
},
+ // Block for adding to a variable in place.
+ {
+ "type": "math_change",
+ "message0": "%{BKY_MATH_CHANGE_TITLE}",
+ "args0": [
+ {
+ "type": "field_variable",
+ "name": "VAR",
+ "variable": "%{BKY_MATH_CHANGE_TITLE_ITEM}",
+ },
+ {
+ "type": "input_value",
+ "name": "DELTA",
+ "check": "Number",
+ },
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "style": "variable_blocks",
+ "helpUrl": "%{BKY_MATH_CHANGE_HELPURL}",
+ "extensions": ["math_change_tooltip"],
+ },
]);
+
+// Update the tooltip of 'math_change' block to reference the variable.
+Blockly.Extensions.register('math_change_tooltip',
+ Blockly.Extensions.buildTooltipWithFieldText(
+ '%{BKY_MATH_CHANGE_TOOLTIP}', 'VAR'));
+
+
+(function() {
+ /**
+ * Mapping of math block OP value to tooltip message for blocks
+ * math_arithmetic, math_simple, math_trig, and math_on_lists.
+ * @see {Blockly.Extensions#buildTooltipForDropdown}
+ * @package
+ * @readonly
+ */
+ const TOOLTIPS_BY_OP = {
+ // math_arithmetic
+ 'ADD': '%{BKY_MATH_ARITHMETIC_TOOLTIP_ADD}',
+ 'MINUS': '%{BKY_MATH_ARITHMETIC_TOOLTIP_MINUS}',
+ 'MULTIPLY': '%{BKY_MATH_ARITHMETIC_TOOLTIP_MULTIPLY}',
+ 'DIVIDE': '%{BKY_MATH_ARITHMETIC_TOOLTIP_DIVIDE}',
+ 'POWER': '%{BKY_MATH_ARITHMETIC_TOOLTIP_POWER}',
+
+ // math_simple
+ 'ROOT': '%{BKY_MATH_SINGLE_TOOLTIP_ROOT}',
+ 'ABS': '%{BKY_MATH_SINGLE_TOOLTIP_ABS}',
+ 'NEG': '%{BKY_MATH_SINGLE_TOOLTIP_NEG}',
+ 'LN': '%{BKY_MATH_SINGLE_TOOLTIP_LN}',
+ 'LOG10': '%{BKY_MATH_SINGLE_TOOLTIP_LOG10}',
+ 'EXP': '%{BKY_MATH_SINGLE_TOOLTIP_EXP}',
+ 'POW10': '%{BKY_MATH_SINGLE_TOOLTIP_POW10}',
+
+ // math_trig
+ 'SIN': '%{BKY_MATH_TRIG_TOOLTIP_SIN}',
+ 'COS': '%{BKY_MATH_TRIG_TOOLTIP_COS}',
+ 'TAN': '%{BKY_MATH_TRIG_TOOLTIP_TAN}',
+ 'ASIN': '%{BKY_MATH_TRIG_TOOLTIP_ASIN}',
+ 'ACOS': '%{BKY_MATH_TRIG_TOOLTIP_ACOS}',
+ 'ATAN': '%{BKY_MATH_TRIG_TOOLTIP_ATAN}',
+
+ // math_on_lists
+ 'SUM': '%{BKY_MATH_ONLIST_TOOLTIP_SUM}',
+ 'MIN': '%{BKY_MATH_ONLIST_TOOLTIP_MIN}',
+ 'MAX': '%{BKY_MATH_ONLIST_TOOLTIP_MAX}',
+ 'AVERAGE': '%{BKY_MATH_ONLIST_TOOLTIP_AVERAGE}',
+ 'MEDIAN': '%{BKY_MATH_ONLIST_TOOLTIP_MEDIAN}',
+ 'MODE': '%{BKY_MATH_ONLIST_TOOLTIP_MODE}',
+ 'STD_DEV': '%{BKY_MATH_ONLIST_TOOLTIP_STD_DEV}',
+ 'RANDOM': '%{BKY_MATH_ONLIST_TOOLTIP_RANDOM}',
+ };
+
+ Blockly.Extensions.register('math_op_tooltip',
+ Blockly.Extensions.buildTooltipForDropdown(
+ 'OP', TOOLTIPS_BY_OP));
+})();
diff --git a/Blockly/html/agc/blocks/procedures.js b/Blockly/html/agc/blocks/procedures.js
new file mode 100644
index 0000000..98e486a
--- /dev/null
+++ b/Blockly/html/agc/blocks/procedures.js
@@ -0,0 +1,460 @@
+/**
+ * @fileoverview AGC procedure blocks for Blockly.
+ */
+'use strict';
+
+
+Blockly.Blocks['procedures_defnoreturn'] = {
+ /**
+ * Block for defining a procedure with no return value.
+ * @this {Blockly.Block}
+ */
+ init: function() {
+ const initName = Blockly.Procedures.findLegalName('', this);
+ const nameField = new Blockly.FieldTextInput(initName,
+ Blockly.Procedures.rename);
+ nameField.setSpellcheck(false);
+ this.appendDummyInput()
+ .appendField(Blockly.Msg['PROCEDURES_DEFNORETURN_TITLE'])
+ .appendField(nameField, 'NAME');
+ this.appendStatementInput('STACK')
+ .appendField(Blockly.Msg['PROCEDURES_DEFNORETURN_DO']);
+ if ((this.workspace.options.comments ||
+ (this.workspace.options.parentWorkspace &&
+ this.workspace.options.parentWorkspace.options.comments)) &&
+ Blockly.Msg['PROCEDURES_DEFNORETURN_COMMENT']) {
+ this.setCommentText(Blockly.Msg['PROCEDURES_DEFNORETURN_COMMENT']);
+ }
+ this.setStyle('procedure_blocks');
+ this.setTooltip(Blockly.Msg['PROCEDURES_DEFNORETURN_TOOLTIP']);
+ this.setHelpUrl(Blockly.Msg['PROCEDURES_DEFNORETURN_HELPURL']);
+ },
+ /**
+ * Create XML to represent the argument inputs.
+ * Backwards compatible serialization implementation.
+ * @param {boolean=} opt_paramIds If true include the IDs of the parameter
+ * quarks. Used by Blockly.Procedures.mutateCallers for reconnection.
+ * @return {!Element} XML storage element.
+ * @this {Blockly.Block}
+ */
+ mutationToDom: function(opt_paramIds) {
+ const container = Blockly.utils.xml.createElement('mutation');
+ if (opt_paramIds) {
+ container.setAttribute('name', this.getFieldValue('NAME'));
+ }
+ return container;
+ },
+ /**
+ * Parse XML to restore the argument inputs.
+ * Backwards compatible serialization implementation.
+ * @param {!Element} xmlElement XML storage element.
+ * @this {Blockly.Block}
+ */
+ domToMutation: function(xmlElement) {
+ Blockly.Procedures.mutateCallers(this);
+ },
+ /**
+ * Return the signature of this procedure definition.
+ * @return {!Array} Tuple containing three elements:
+ * - the name of the defined procedure,
+ * - a list of all its arguments,
+ * - that it DOES NOT have a return value.
+ * @this {Blockly.Block}
+ */
+ getProcedureDef: function() {
+ return [this.getFieldValue('NAME'), [], false];
+ },
+ /**
+ * Return all variables referenced by this block.
+ * @return {!Array} List of variable models.
+ * @this {Blockly.Block}
+ */
+ getVarModels: function() {
+ return [];
+ },
+ /**
+ * Add custom menu options to this block's context menu.
+ * @param {!Array} options List of menu options to add to.
+ * @this {Blockly.Block}
+ */
+ customContextMenu: function(options) {
+ if (this.isInFlyout) {
+ return;
+ }
+ // Add option to create caller.
+ const option = {enabled: true};
+ const name = this.getFieldValue('NAME');
+ option.text = Blockly.Msg['PROCEDURES_CREATE_DO'].replace('%1', name);
+ const xmlMutation = Blockly.utils.xml.createElement('mutation');
+ xmlMutation.setAttribute('name', name);
+ const xmlBlock = Blockly.utils.xml.createElement('block');
+ xmlBlock.setAttribute('type', this.callType_);
+ xmlBlock.appendChild(xmlMutation);
+ option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock);
+ options.push(option);
+ },
+ callType_: 'procedures_callnoreturn',
+};
+
+Blockly.Blocks['procedures_defreturn'] = {
+ /**
+ * Block for defining a procedure with a return value.
+ * @this {Blockly.Block}
+ */
+ init: function() {
+ const initName = Blockly.Procedures.findLegalName('', this);
+ const nameField = new Blockly.FieldTextInput(initName,
+ Blockly.Procedures.rename);
+ nameField.setSpellcheck(false);
+ this.appendDummyInput()
+ .appendField(Blockly.Msg['PROCEDURES_DEFRETURN_TITLE'])
+ .appendField(nameField, 'NAME');
+ this.appendStatementInput('STACK')
+ .appendField(Blockly.Msg['PROCEDURES_DEFNORETURN_DO']);
+ this.appendValueInput('RETURN')
+ .setAlign(Blockly.ALIGN_RIGHT)
+ .appendField(Blockly.Msg['PROCEDURES_DEFRETURN_RETURN']);
+ if ((this.workspace.options.comments ||
+ (this.workspace.options.parentWorkspace &&
+ this.workspace.options.parentWorkspace.options.comments)) &&
+ Blockly.Msg['PROCEDURES_DEFRETURN_COMMENT']) {
+ this.setCommentText(Blockly.Msg['PROCEDURES_DEFRETURN_COMMENT']);
+ }
+ this.setStyle('procedure_blocks');
+ this.setTooltip(Blockly.Msg['PROCEDURES_DEFRETURN_TOOLTIP']);
+ this.setHelpUrl(Blockly.Msg['PROCEDURES_DEFRETURN_HELPURL']);
+ },
+ mutationToDom: Blockly.Blocks['procedures_defnoreturn'].mutationToDom,
+ domToMutation: Blockly.Blocks['procedures_defnoreturn'].domToMutation,
+ /**
+ * Return the signature of this procedure definition.
+ * @return {!Array} Tuple containing three elements:
+ * - the name of the defined procedure,
+ * - a list of all its arguments,
+ * - that it DOES have a return value.
+ * @this {Blockly.Block}
+ */
+ getProcedureDef: function() {
+ return [this.getFieldValue('NAME'), [], true];
+ },
+ getVarModels: Blockly.Blocks['procedures_defnoreturn'].getVarModels,
+ customContextMenu: Blockly.Blocks['procedures_defnoreturn'].customContextMenu,
+ callType_: 'procedures_callreturn',
+};
+
+
+Blockly.Blocks['procedures_callnoreturn'] = {
+ /**
+ * Block for calling a procedure with no return value.
+ * @this {Blockly.Block}
+ */
+ init: function() {
+ this.appendDummyInput('TOPROW')
+ .appendField('', 'NAME');
+ this.setPreviousStatement(true);
+ this.setNextStatement(true);
+ this.setStyle('procedure_blocks');
+ // Tooltip is set in renameProcedure.
+ this.setHelpUrl(Blockly.Msg['PROCEDURES_CALLNORETURN_HELPURL']);
+ this.previousEnabledState_ = true;
+ },
+
+ /**
+ * Returns the name of the procedure this block calls.
+ * @return {string} Procedure name.
+ * @this {Blockly.Block}
+ */
+ getProcedureCall: function() {
+ // The NAME field is guaranteed to exist, null will never be returned.
+ return /** @type {string} */ (this.getFieldValue('NAME'));
+ },
+ /**
+ * Notification that a procedure is renaming.
+ * If the name matches this block's procedure, rename it.
+ * @param {string} oldName Previous name of procedure.
+ * @param {string} newName Renamed procedure.
+ * @this {Blockly.Block}
+ */
+ renameProcedure: function(oldName, newName) {
+ if (Blockly.Names.equals(oldName, this.getProcedureCall())) {
+ this.setFieldValue(newName, 'NAME');
+ const baseMsg = this.outputConnection ?
+ Blockly.Msg['PROCEDURES_CALLRETURN_TOOLTIP'] :
+ Blockly.Msg['PROCEDURES_CALLNORETURN_TOOLTIP'];
+ this.setTooltip(baseMsg.replace('%1', newName));
+ }
+ },
+ /**
+ * Create XML to represent the (non-editable) name and arguments.
+ * Backwards compatible serialization implementation.
+ * @return {!Element} XML storage element.
+ * @this {Blockly.Block}
+ */
+ mutationToDom: function() {
+ const container = Blockly.utils.xml.createElement('mutation');
+ container.setAttribute('name', this.getProcedureCall());
+ return container;
+ },
+ /**
+ * Parse XML to restore the (non-editable) name and parameters.
+ * Backwards compatible serialization implementation.
+ * @param {!Element} xmlElement XML storage element.
+ * @this {Blockly.Block}
+ */
+ domToMutation: function(xmlElement) {
+ const name = xmlElement.getAttribute('name');
+ this.renameProcedure(this.getProcedureCall(), name);
+ },
+ /**
+ * Return all variables referenced by this block.
+ * @return {!Array} List of variable models.
+ * @this {Blockly.Block}
+ */
+ getVarModels: function() {
+ return [];
+ },
+ /**
+ * Procedure calls cannot exist without the corresponding procedure
+ * definition. Enforce this link whenever an event is fired.
+ * @param {!Blockly.Events.Abstract} event Change event.
+ * @this {Blockly.Block}
+ */
+ onchange: function(event) {
+ if (!this.workspace || this.workspace.isFlyout) {
+ // Block is deleted or is in a flyout.
+ return;
+ }
+ if (!event.recordUndo) {
+ // Events not generated by user. Skip handling.
+ return;
+ }
+ if (event.type === Blockly.Events.BLOCK_CREATE &&
+ event.ids.indexOf(this.id) !== -1) {
+ // Look for the case where a procedure call was created (usually through
+ // paste) and there is no matching definition. In this case, create
+ // an empty definition block with the correct signature.
+ const name = this.getProcedureCall();
+ let def = Blockly.Procedures.getDefinition(name, this.workspace);
+ if (def && (def.type !== this.defType_)) {
+ // The signatures don't match.
+ def = null;
+ }
+ if (!def) {
+ Blockly.Events.setGroup(event.group);
+ /**
+ * Create matching definition block.
+ *
+ *
+ *
+ * test
+ *
+ *
+ */
+ const xml = Blockly.utils.xml.createElement('xml');
+ const block = Blockly.utils.xml.createElement('block');
+ block.setAttribute('type', this.defType_);
+ const xy = this.getRelativeToSurfaceXY();
+ const x = xy.x + Blockly.SNAP_RADIUS * (this.RTL ? -1 : 1);
+ const y = xy.y + Blockly.SNAP_RADIUS * 2;
+ block.setAttribute('x', x);
+ block.setAttribute('y', y);
+ const mutation = this.mutationToDom();
+ block.appendChild(mutation);
+ const field = Blockly.utils.xml.createElement('field');
+ field.setAttribute('name', 'NAME');
+ let callName = this.getProcedureCall();
+ if (!callName) {
+ // Rename if name is empty string.
+ callName = Blockly.Procedures.findLegalName('', this);
+ this.renameProcedure('', callName);
+ }
+ field.appendChild(Blockly.utils.xml.createTextNode(callName));
+ block.appendChild(field);
+ xml.appendChild(block);
+ Blockly.Xml.domToWorkspace(xml, this.workspace);
+ Blockly.Events.setGroup(false);
+ }
+ } else if (event.type === Blockly.Events.BLOCK_DELETE) {
+ // Look for the case where a procedure definition has been deleted,
+ // leaving this block (a procedure call) orphaned. In this case, delete
+ // the orphan.
+ const name = this.getProcedureCall();
+ const def = Blockly.Procedures.getDefinition(name, this.workspace);
+ if (!def) {
+ Blockly.Events.setGroup(event.group);
+ this.dispose(true);
+ Blockly.Events.setGroup(false);
+ }
+ } else if (event.type === Blockly.Events.CHANGE && event.element === 'disabled') {
+ const name = this.getProcedureCall();
+ const def = Blockly.Procedures.getDefinition(name, this.workspace);
+ if (def && def.id === event.blockId) {
+ // in most cases the old group should be ''
+ const oldGroup = Blockly.Events.getGroup();
+ if (oldGroup) {
+ // This should only be possible programmatically and may indicate a problem
+ // with event grouping. If you see this message please investigate. If the
+ // use ends up being valid we may need to reorder events in the undo stack.
+ console.log('Saw an existing group while responding to a definition change');
+ }
+ Blockly.Events.setGroup(event.group);
+ if (event.newValue) {
+ this.previousEnabledState_ = this.isEnabled();
+ this.setEnabled(false);
+ } else {
+ this.setEnabled(this.previousEnabledState_);
+ }
+ Blockly.Events.setGroup(oldGroup);
+ }
+ }
+ },
+ /**
+ * Add menu option to find the definition block for this call.
+ * @param {!Array} options List of menu options to add to.
+ * @this {Blockly.Block}
+ */
+ customContextMenu: function(options) {
+ if (!this.workspace.isMovable()) {
+ // If we center on the block and the workspace isn't movable we could
+ // loose blocks at the edges of the workspace.
+ return;
+ }
+
+ const option = {enabled: true};
+ option.text = Blockly.Msg['PROCEDURES_HIGHLIGHT_DEF'];
+ const name = this.getProcedureCall();
+ const workspace = this.workspace;
+ option.callback = function() {
+ const def = Blockly.Procedures.getDefinition(name, workspace);
+ if (def) {
+ workspace.centerOnBlock(def.id);
+ def.select();
+ }
+ };
+ options.push(option);
+ },
+ defType_: 'procedures_defnoreturn',
+};
+
+Blockly.Blocks['procedures_callreturn'] = {
+ /**
+ * Block for calling a procedure with a return value.
+ * @this {Blockly.Block}
+ */
+ init: function() {
+ this.appendDummyInput('TOPROW')
+ .appendField('', 'NAME');
+ this.setOutput(true);
+ this.setStyle('procedure_blocks');
+ // Tooltip is set in domToMutation.
+ this.setHelpUrl(Blockly.Msg['PROCEDURES_CALLRETURN_HELPURL']);
+ this.previousEnabledState_ = true;
+ },
+
+ getProcedureCall: Blockly.Blocks['procedures_callnoreturn'].getProcedureCall,
+ renameProcedure: Blockly.Blocks['procedures_callnoreturn'].renameProcedure,
+ mutationToDom: Blockly.Blocks['procedures_callnoreturn'].mutationToDom,
+ domToMutation: Blockly.Blocks['procedures_callnoreturn'].domToMutation,
+ getVarModels: Blockly.Blocks['procedures_callnoreturn'].getVarModels,
+ onchange: Blockly.Blocks['procedures_callnoreturn'].onchange,
+ customContextMenu:
+ Blockly.Blocks['procedures_callnoreturn'].customContextMenu,
+ defType_: 'procedures_defreturn',
+};
+
+Blockly.Blocks['procedures_ifreturn'] = {
+ /**
+ * Block for conditionally returning a value from a procedure.
+ * @this {Blockly.Block}
+ */
+ init: function() {
+ this.appendValueInput('CONDITION')
+ .setCheck('Boolean')
+ .appendField(Blockly.Msg['CONTROLS_IF_MSG_IF']);
+ this.appendValueInput('VALUE')
+ .appendField(Blockly.Msg['PROCEDURES_DEFRETURN_RETURN']);
+ this.setInputsInline(true);
+ this.setPreviousStatement(true);
+ this.setNextStatement(true);
+ this.setStyle('procedure_blocks');
+ this.setTooltip(Blockly.Msg['PROCEDURES_IFRETURN_TOOLTIP']);
+ this.setHelpUrl(Blockly.Msg['PROCEDURES_IFRETURN_HELPURL']);
+ this.hasReturnValue_ = true;
+ },
+ /**
+ * Create XML to represent whether this block has a return value.
+ * @return {!Element} XML storage element.
+ * @this {Blockly.Block}
+ */
+ mutationToDom: function() {
+ const container = Blockly.utils.xml.createElement('mutation');
+ container.setAttribute('value', Number(this.hasReturnValue_));
+ return container;
+ },
+ /**
+ * Parse XML to restore whether this block has a return value.
+ * @param {!Element} xmlElement XML storage element.
+ * @this {Blockly.Block}
+ */
+ domToMutation: function(xmlElement) {
+ const value = xmlElement.getAttribute('value');
+ this.hasReturnValue_ = (value === '1');
+ if (!this.hasReturnValue_) {
+ this.removeInput('VALUE');
+ this.appendDummyInput('VALUE')
+ .appendField(Blockly.Msg['PROCEDURES_DEFRETURN_RETURN']);
+ }
+ },
+
+ /**
+ * Called whenever anything on the workspace changes.
+ * Add warning if this flow block is not nested inside a loop.
+ * @param {!Blockly.Events.Abstract} _e Change event.
+ * @this {Blockly.Block}
+ */
+ onchange: function(_e) {
+ if (this.workspace.isDragging && this.workspace.isDragging()) {
+ return; // Don't change state at the start of a drag.
+ }
+ let legal = false;
+ // Is the block nested in a procedure?
+ let block = this;
+ do {
+ if (this.FUNCTION_TYPES.indexOf(block.type) !== -1) {
+ legal = true;
+ break;
+ }
+ block = block.getSurroundParent();
+ } while (block);
+ if (legal) {
+ // If needed, toggle whether this block has a return value.
+ if (block.type === 'procedures_defnoreturn' && this.hasReturnValue_) {
+ this.removeInput('VALUE');
+ this.appendDummyInput('VALUE')
+ .appendField(Blockly.Msg['PROCEDURES_DEFRETURN_RETURN']);
+ this.hasReturnValue_ = false;
+ } else if (block.type === 'procedures_defreturn' &&
+ !this.hasReturnValue_) {
+ this.removeInput('VALUE');
+ this.appendValueInput('VALUE')
+ .appendField(Blockly.Msg['PROCEDURES_DEFRETURN_RETURN']);
+ this.hasReturnValue_ = true;
+ }
+ this.setWarningText(null);
+ if (!this.isInFlyout) {
+ this.setEnabled(true);
+ }
+ } else {
+ this.setWarningText(Blockly.Msg['PROCEDURES_IFRETURN_WARNING']);
+ if (!this.isInFlyout && !this.getInheritedDisabled()) {
+ this.setEnabled(false);
+ }
+ }
+ },
+ /**
+ * List of block types that are functions and thus do not need warnings.
+ * To add a new function type add this to your code:
+ * Blockly.Blocks['procedures_ifreturn'].FUNCTION_TYPES.push('custom_func');
+ */
+ FUNCTION_TYPES: ['procedures_defnoreturn', 'procedures_defreturn'],
+};
diff --git a/Blockly/html/agc/blocks/variables.js b/Blockly/html/agc/blocks/variables.js
index e321566..ca1b380 100644
--- a/Blockly/html/agc/blocks/variables.js
+++ b/Blockly/html/agc/blocks/variables.js
@@ -54,7 +54,7 @@ Blockly.defineBlocksWithJsonArray([
* @package
* @readonly
*/
-Blockly.Constants.Variables.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN = {
+Blockly.Variables.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN = {
/**
* Add menu option to create getter/setter block for this setter/getter.
* @param {!Array} options List of menu options to add to.
@@ -111,7 +111,7 @@ Blockly.Constants.Variables.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN = {
* @param {!Blockly.Block} block The block with the variable to rename.
* @return {!function()} A function that renames the variable.
*/
-Blockly.Constants.Variables.RENAME_OPTION_CALLBACK_FACTORY = function(block) {
+Blockly.Variables.RENAME_OPTION_CALLBACK_FACTORY = function(block) {
return function() {
const workspace = block.workspace;
const variable = block.getField('VAR').getVariable();
@@ -125,7 +125,7 @@ Blockly.Constants.Variables.RENAME_OPTION_CALLBACK_FACTORY = function(block) {
* @param {!Blockly.Block} block The block with the variable to delete.
* @return {!function()} A function that deletes the variable.
*/
-Blockly.Constants.Variables.DELETE_OPTION_CALLBACK_FACTORY = function(block) {
+Blockly.Variables.DELETE_OPTION_CALLBACK_FACTORY = function(block) {
return function() {
const workspace = block.workspace;
const variable = block.getField('VAR').getVariable();
@@ -135,4 +135,4 @@ Blockly.Constants.Variables.DELETE_OPTION_CALLBACK_FACTORY = function(block) {
};
Blockly.Extensions.registerMixin('contextMenu_variableSetterGetter',
- Blockly.Constants.Variables.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN);
+ Blockly.Variables.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN);
diff --git a/Blockly/html/agc/generator/generator.js b/Blockly/html/agc/generator/generator.js
index ade78b7..665a811 100644
--- a/Blockly/html/agc/generator/generator.js
+++ b/Blockly/html/agc/generator/generator.js
@@ -134,7 +134,7 @@ AgcGenerator.scrub_ = function(block, code, opt_thisOnly) {
let comment = block.getCommentText();
if (comment) {
comment = Blockly.utils.string.wrap(comment, this.COMMENT_WRAP - 3);
- commentCode += this.prefixLines(comment + '\n', '// ');
+ commentCode += this.prefixLines(comment + '\n', '# ');
}
// Collect comments for all value arguments.
// Don't collect comments for nested statements.
@@ -144,7 +144,7 @@ AgcGenerator.scrub_ = function(block, code, opt_thisOnly) {
if (childBlock) {
comment = this.allNestedComments(childBlock);
if (comment) {
- commentCode += this.prefixLines(comment, '// ');
+ commentCode += this.prefixLines(comment, '# ');
}
}
}
diff --git a/Blockly/html/agc/generator/logic.js b/Blockly/html/agc/generator/logic.js
index 0d7f4be..ee8e70c 100644
--- a/Blockly/html/agc/generator/logic.js
+++ b/Blockly/html/agc/generator/logic.js
@@ -4,7 +4,7 @@
*/
'use strict';
-AgcGenerator['agc_controls_if'] = function(block) {
+AgcGenerator['controls_if'] = function(block) {
// If condition.
const labelIf = 'IF' + AgcGenerator.getUniqueLabel();
const conditionCode =
@@ -21,7 +21,7 @@ ${labelIf}-X
return code;
};
-AgcGenerator['agc_controls_ifelse'] = function(block) {
+AgcGenerator['controls_ifelse'] = function(block) {
// If/else condition.
const labelIf = 'IF' + AgcGenerator.getUniqueLabel();
const conditionCode =
@@ -42,14 +42,14 @@ ${labelIf}-X
return code;
};
-AgcGenerator['agc_logic_boolean'] = function(block) {
+AgcGenerator['logic_boolean'] = function(block) {
// Boolean values true and false.
const boolean = block.getFieldValue('BOOL');
const code = `\tCA\tNUM${boolean}\n`;
return code;
};
-AgcGenerator['agc_logic_compare'] = function(block) {
+AgcGenerator['logic_compare'] = function(block) {
// Comparison operator.
const OPERATORS = {
'EQ': '\tTCR\tBL-NOT',
@@ -73,7 +73,7 @@ AgcGenerator['agc_logic_compare'] = function(block) {
return code;
};
-AgcGenerator['agc_logic_operation'] = function(block) {
+AgcGenerator['logic_operation'] = function(block) {
// Operations 'and', 'or'.
const operator = block.getFieldValue('OP'); // AND or OR
let argument0 = AgcGenerator.valueToCode(block, 'A');
@@ -98,11 +98,11 @@ AgcGenerator['agc_logic_operation'] = function(block) {
${argument1}
\tTCR\tPUSH
\tTCR\tBL-${operator}
- `;
+`;
return code;
};
-AgcGenerator['agc_logic_negate'] = function(block) {
+AgcGenerator['logic_negate'] = function(block) {
// Negation.
const argument0 = AgcGenerator.valueToCode(block, 'BOOL') || AgcGenerator.default1;
const code = `
@@ -112,7 +112,7 @@ ${argument0}
return code;
};
-AgcGenerator['agc_logic_ternary'] = function(block) {
+AgcGenerator['logic_ternary'] = function(block) {
// Ternary operator.
const argument0 = AgcGenerator.valueToCode(block, 'ELSE') || AgcGenerator.default0;
const argument1 = AgcGenerator.valueToCode(block, 'THEN') || AgcGenerator.default0;
diff --git a/Blockly/html/agc/generator/loops.js b/Blockly/html/agc/generator/loops.js
index 22bcacf..8efaf52 100644
--- a/Blockly/html/agc/generator/loops.js
+++ b/Blockly/html/agc/generator/loops.js
@@ -4,7 +4,7 @@
*/
'use strict';
-AgcGenerator['agc_controls_whileUntil'] = function(block) {
+AgcGenerator['controls_whileUntil'] = function(block) {
// Generator for 'do while/until' loop.
const labelLoop = 'LOOP' + AgcGenerator.getUniqueLabel();
const conditionCode =
diff --git a/Blockly/html/agc/generator/math.js b/Blockly/html/agc/generator/math.js
index e4e2d93..58ca0b6 100644
--- a/Blockly/html/agc/generator/math.js
+++ b/Blockly/html/agc/generator/math.js
@@ -4,7 +4,7 @@
*/
'use strict';
-AgcGenerator['agc_math_number'] = function(block) {
+AgcGenerator['math_number'] = function(block) {
// Numeric value.
const number = Number(block.getFieldValue('NUM'));
AgcGenerator.provideFunction_('NUM' + number, [`NUM${number}\tDEC\t${number}`]);
@@ -12,7 +12,7 @@ AgcGenerator['agc_math_number'] = function(block) {
return code;
};
-AgcGenerator['agc_math_arithmetic'] = function(block) {
+AgcGenerator['math_arithmetic'] = function(block) {
// Basic arithmetic operators.
const OPERATORS = {
'ADD': 'MA-AD',
@@ -32,7 +32,7 @@ ${argument0}
return code;
};
-AgcGenerator['agc_math_random_int_0'] = function(block) {
+AgcGenerator['math_random_int_0'] = function(block) {
const to = AgcGenerator.valueToCode(block, 'TO') || AgcGenerator.default1;
const code = `
${to}
@@ -41,3 +41,16 @@ ${to}
`;
return code;
};
+
+AgcGenerator['math_change'] = function(block) {
+ // Add to a variable in place.
+ const argument0 = AgcGenerator.valueToCode(block, 'DELTA') || AgcGenerator.default0;
+ const varName = AgcGenerator.nameDB_.getName(block.getFieldValue('VAR'),
+ Blockly.VARIABLE_CATEGORY_NAME);
+
+ const code = `
+${argument0}
+\tADS\t${varName}
+`;
+ return code;
+};
diff --git a/Blockly/html/agc/generator/procedures.js b/Blockly/html/agc/generator/procedures.js
new file mode 100644
index 0000000..8f7a088
--- /dev/null
+++ b/Blockly/html/agc/generator/procedures.js
@@ -0,0 +1,83 @@
+/**
+ * @fileoverview Generating AGC assembly for procedure blocks.
+ */
+'use strict';
+
+AgcGenerator['procedures_defreturn'] = function(block) {
+ // Procedure definition.
+ const funcName = AgcGenerator.nameDB_.getName(block.getFieldValue('NAME'),
+ Blockly.PROCEDURE_CATEGORY_NAME);
+ // Create the function definition.
+ // 1. Push the return pointer onto the stack.
+ // 2. Execute the body of the function.
+ const branch = AgcGenerator.statementToCode(block, 'STACK');
+ let code = `
+${funcName}\tCA\tQ
+\t\tTCR\tPUSH
+${branch}`;
+ if (block.getInput('RETURN')) {
+ // 3. Execute the return value.
+ // 4. Preserve the A register (return value) into L.
+ // 5. Pop the return pointer from the stack into Q.
+ // 6. Restore the return value from L back into the A register.
+ // 7. Return from the function.
+ const returnValue = AgcGenerator.valueToCode(block, 'RETURN') || AgcGenerator.default0;
+ code += `
+${returnValue}
+\t\tTS\tL
+\t\tTCR\tPOP
+\t\tTS\tQ
+\t\tCA\tL
+\t\tRETURN
+`;
+ } else {
+ // 3. Pop the return pointer from the stack into Q.
+ // 4. Return from the function.
+ code += `
+\t\tTCR\tPOP
+\t\tTS\tQ
+\t\tRETURN
+`;
+ }
+ code = AgcGenerator.scrub_(block, code);
+ // Add % so as not to collide with helper functions in definitions list.
+ AgcGenerator.definitions_['%' + funcName] = code;
+ return null;
+};
+
+// Defining a procedure without a return value uses the same generator as
+// defining a procedure with a return value.
+AgcGenerator['procedures_defnoreturn'] = AgcGenerator['procedures_defreturn'];
+
+AgcGenerator['procedures_callreturn'] = function(block) {
+ // Call a procedure with a return value.
+ const funcName = AgcGenerator.nameDB_.getName(block.getFieldValue('NAME'),
+ Blockly.PROCEDURE_CATEGORY_NAME);
+ const code = `\t\tTCR\t${funcName}\n`;
+ return code;
+};
+
+// Calling a procedure without a return value uses the same generator as
+// a calling procedure with a return value.
+AgcGenerator['procedures_callnoreturn'] = AgcGenerator['procedures_callreturn'];
+
+
+AgcGenerator['procedures_ifreturn'] = function(block) {
+ // Conditionally return value from a procedure.
+ const labelIf = 'IF' + AgcGenerator.getUniqueLabel();
+ const condition = AgcGenerator.valueToCode(block, 'CONDITION') ||
+ AgcGenerator.defaultFalse;
+ const returnValue = block.hasReturnValue_ ?
+ AgcGenerator.valueToCode(block, 'VALUE') || AgcGenerator.default0 : '';
+ let code = `
+${condition}
+\tEXTEND
+\tBZF\t${labelIf}
+\t\tTCR\tPOP
+\t\tTS\tQ
+${returnValue}
+\tRETURN
+${labelIf}
+`;
+ return code;
+};
diff --git a/Blockly/html/agc/generator/variables.js b/Blockly/html/agc/generator/variables.js
index 529ecd3..66afcff 100644
--- a/Blockly/html/agc/generator/variables.js
+++ b/Blockly/html/agc/generator/variables.js
@@ -15,8 +15,7 @@ AgcGenerator['variables_get'] = function(block) {
AgcGenerator['variables_set'] = function(block) {
// Variable setter.
- const argument0 = AgcGenerator.valueToCode(
- block, 'VALUE') ||
+ const argument0 = AgcGenerator.valueToCode(block, 'VALUE') ||
AgcGenerator.default0;
const varName = AgcGenerator.nameDB_.getName(
block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME);
diff --git a/Blockly/html/agc/index.html b/Blockly/html/agc/index.html
index 19f1fc3..383ddc0 100644
--- a/Blockly/html/agc/index.html
+++ b/Blockly/html/agc/index.html
@@ -6,7 +6,6 @@
Blockly AGC
-
@@ -18,12 +17,14 @@
+
+
@@ -71,209 +72,55 @@ Blockly AGC
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
- 10
-
-
-
-
-
-
-
- 1
-
-
-
-
- 10
-
-
-
-
- 1
-
-
-
-
-
+
-
+
123
-
+
-
+
1
-
+
1
-
+
-
+
6
-
-
-
- 1
-
-
-
-
- 100
-
-
-
-
-
-
- 9
-
-
-
-
-
-
- 45
-
-
-
-
-
-
-
- 0
-
-
-
-
-
-
- 3.1
-
-
-
-
-
-
-
- 64
-
-
-
-
- 10
-
-
-
-
-
-
- 50
-
-
-
-
- 1
-
-
-
-
- 100
-
-
-
-
-
-
-
- 1
-
-
-
-
- 1
-
-
-
-
-
-
-
-
-
-
-
-
- 5
-
-
-
-
-
-
-
-
- list
-
-
-
-
-
-
- list
-
-
-
-
-
-
- list
-
-
-
-
-
-
- list
-
-
-
-
-
+
0
-
+
0
-
+
0
@@ -281,7 +128,7 @@ Blockly AGC
-
+
100
diff --git a/Blockly/html/third-party/blockly/blocks_compressed.js b/Blockly/html/third-party/blockly/blocks_compressed.js
deleted file mode 100644
index 8333c05..0000000
--- a/Blockly/html/third-party/blockly/blocks_compressed.js
+++ /dev/null
@@ -1,193 +0,0 @@
-// Do not edit this file; automatically generated by gulp.
-
-/* eslint-disable */
-;(function(root, factory) {
- if (typeof define === 'function' && define.amd) { // AMD
- define(['./blockly_compressed.js'], factory);
- } else if (typeof exports === 'object') { // Node.js
- module.exports = factory(require('./blockly_compressed.js'));
- } else { // Browser
- root.Blockly.Blocks = factory(root.Blockly);
- }
-}(this, function(Blockly) {
- 'use strict';var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.SIMPLE_FROUND_POLYFILL=!1;$jscomp.ISOLATE_POLYFILLS=!1;$jscomp.FORCE_POLYFILL_PROMISE=!1;$jscomp.FORCE_POLYFILL_PROMISE_WHEN_NO_UNHANDLED_REJECTION=!1;$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){if(a==Array.prototype||a==Object.prototype)return a;a[b]=c.value;return a};
-$jscomp.getGlobal=function(a){a=["object"==typeof globalThis&&globalThis,a,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var b=0;b>>0,$jscomp.propertyToPolyfillSymbol[e]=$jscomp.IS_SYMBOL_NATIVE?
-$jscomp.global.Symbol(e):$jscomp.POLYFILL_PREFIX+c+"$"+e),$jscomp.defineProperty(d,$jscomp.propertyToPolyfillSymbol[e],{configurable:!0,writable:!0,value:b})))};$jscomp.polyfill("Array.prototype.fill",function(a){return a?a:function(b,c,d){var e=this.length||0;0>c&&(c=Math.max(0,e+c));if(null==d||d>e)d=e;d=Number(d);0>d&&(d=Math.max(0,e+d));for(c=Number(c||0);c","GT"],["\u200f\u2265","GTE"]]},{type:"input_value",name:"B"}],inputsInline:!0,output:"Boolean",style:"logic_blocks",helpUrl:"%{BKY_LOGIC_COMPARE_HELPURL}",
-extensions:["logic_compare","logic_op_tooltip"]},{type:"logic_operation",message0:"%1 %2 %3",args0:[{type:"input_value",name:"A",check:"Boolean"},{type:"field_dropdown",name:"OP",options:[["%{BKY_LOGIC_OPERATION_AND}","AND"],["%{BKY_LOGIC_OPERATION_OR}","OR"]]},{type:"input_value",name:"B",check:"Boolean"}],inputsInline:!0,output:"Boolean",style:"logic_blocks",helpUrl:"%{BKY_LOGIC_OPERATION_HELPURL}",extensions:["logic_op_tooltip"]},{type:"logic_negate",message0:"%{BKY_LOGIC_NEGATE_TITLE}",args0:[{type:"input_value",
-name:"BOOL",check:"Boolean"}],output:"Boolean",style:"logic_blocks",tooltip:"%{BKY_LOGIC_NEGATE_TOOLTIP}",helpUrl:"%{BKY_LOGIC_NEGATE_HELPURL}"},{type:"logic_null",message0:"%{BKY_LOGIC_NULL}",output:null,style:"logic_blocks",tooltip:"%{BKY_LOGIC_NULL_TOOLTIP}",helpUrl:"%{BKY_LOGIC_NULL_HELPURL}"},{type:"logic_ternary",message0:"%{BKY_LOGIC_TERNARY_CONDITION} %1",args0:[{type:"input_value",name:"IF",check:"Boolean"}],message1:"%{BKY_LOGIC_TERNARY_IF_TRUE} %1",args1:[{type:"input_value",name:"THEN"}],
-message2:"%{BKY_LOGIC_TERNARY_IF_FALSE} %1",args2:[{type:"input_value",name:"ELSE"}],output:null,style:"logic_blocks",tooltip:"%{BKY_LOGIC_TERNARY_TOOLTIP}",helpUrl:"%{BKY_LOGIC_TERNARY_HELPURL}",extensions:["logic_ternary"]}]);
-Blockly.defineBlocksWithJsonArray([{type:"controls_if_if",message0:"%{BKY_CONTROLS_IF_IF_TITLE_IF}",nextStatement:null,enableContextMenu:!1,style:"logic_blocks",tooltip:"%{BKY_CONTROLS_IF_IF_TOOLTIP}"},{type:"controls_if_elseif",message0:"%{BKY_CONTROLS_IF_ELSEIF_TITLE_ELSEIF}",previousStatement:null,nextStatement:null,enableContextMenu:!1,style:"logic_blocks",tooltip:"%{BKY_CONTROLS_IF_ELSEIF_TOOLTIP}"},{type:"controls_if_else",message0:"%{BKY_CONTROLS_IF_ELSE_TITLE_ELSE}",previousStatement:null,
-enableContextMenu:!1,style:"logic_blocks",tooltip:"%{BKY_CONTROLS_IF_ELSE_TOOLTIP}"}]);Blockly.Constants.Logic.TOOLTIPS_BY_OP={EQ:"%{BKY_LOGIC_COMPARE_TOOLTIP_EQ}",NEQ:"%{BKY_LOGIC_COMPARE_TOOLTIP_NEQ}",LT:"%{BKY_LOGIC_COMPARE_TOOLTIP_LT}",LTE:"%{BKY_LOGIC_COMPARE_TOOLTIP_LTE}",GT:"%{BKY_LOGIC_COMPARE_TOOLTIP_GT}",GTE:"%{BKY_LOGIC_COMPARE_TOOLTIP_GTE}",AND:"%{BKY_LOGIC_OPERATION_TOOLTIP_AND}",OR:"%{BKY_LOGIC_OPERATION_TOOLTIP_OR}"};
-Blockly.Extensions.register("logic_op_tooltip",Blockly.Extensions.buildTooltipForDropdown("OP",Blockly.Constants.Logic.TOOLTIPS_BY_OP));
-Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN={elseifCount_:0,elseCount_:0,mutationToDom:function(){if(!this.elseifCount_&&!this.elseCount_)return null;var a=Blockly.utils.xml.createElement("mutation");this.elseifCount_&&a.setAttribute("elseif",this.elseifCount_);this.elseCount_&&a.setAttribute("else",1);return a},domToMutation:function(a){this.elseifCount_=parseInt(a.getAttribute("elseif"),10)||0;this.elseCount_=parseInt(a.getAttribute("else"),10)||0;this.rebuildShape_()},saveExtraState:function(){if(!this.elseifCount_&&
-!this.elseCount_)return null;var a=Object.create(null);this.elseifCount_&&(a.elseIfCount=this.elseifCount_);this.elseCount_&&(a.hasElse=!0);return a},loadExtraState:function(a){this.elseifCount_=a.elseIfCount||0;this.elseCount_=a.hasElse?1:0;this.updateShape_()},decompose:function(a){var b=a.newBlock("controls_if_if");b.initSvg();for(var c=b.nextConnection,d=1;d<=this.elseifCount_;d++){var e=a.newBlock("controls_if_elseif");e.initSvg();c.connect(e.previousConnection);c=e.nextConnection}this.elseCount_&&
-(a=a.newBlock("controls_if_else"),a.initSvg(),c.connect(a.previousConnection));return b},compose:function(a){a=a.nextConnection.targetBlock();this.elseCount_=this.elseifCount_=0;for(var b=[null],c=[null],d=null;a&&!a.isInsertionMarker();){switch(a.type){case "controls_if_elseif":this.elseifCount_++;b.push(a.valueConnection_);c.push(a.statementConnection_);break;case "controls_if_else":this.elseCount_++;d=a.statementConnection_;break;default:throw TypeError("Unknown block type: "+a.type);}a=a.nextConnection&&
-a.nextConnection.targetBlock()}this.updateShape_();this.reconnectChildBlocks_(b,c,d)},saveConnections:function(a){a=a.nextConnection.targetBlock();for(var b=1;a;){switch(a.type){case "controls_if_elseif":var c=this.getInput("IF"+b),d=this.getInput("DO"+b);a.valueConnection_=c&&c.connection.targetConnection;a.statementConnection_=d&&d.connection.targetConnection;b++;break;case "controls_if_else":d=this.getInput("ELSE");a.statementConnection_=d&&d.connection.targetConnection;break;default:throw TypeError("Unknown block type: "+
-a.type);}a=a.nextConnection&&a.nextConnection.targetBlock()}},rebuildShape_:function(){var a=[null],b=[null],c=null;this.getInput("ELSE")&&(c=this.getInput("ELSE").connection.targetConnection);for(var d=1;this.getInput("IF"+d);){var e=this.getInput("IF"+d),f=this.getInput("DO"+d);a.push(e.connection.targetConnection);b.push(f.connection.targetConnection);d++}this.updateShape_();this.reconnectChildBlocks_(a,b,c)},updateShape_:function(){this.getInput("ELSE")&&this.removeInput("ELSE");for(var a=1;this.getInput("IF"+
-a);)this.removeInput("IF"+a),this.removeInput("DO"+a),a++;for(a=1;a<=this.elseifCount_;a++)this.appendValueInput("IF"+a).setCheck("Boolean").appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSEIF),this.appendStatementInput("DO"+a).appendField(Blockly.Msg.CONTROLS_IF_MSG_THEN);this.elseCount_&&this.appendStatementInput("ELSE").appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSE)},reconnectChildBlocks_:function(a,b,c){for(var d=1;d<=this.elseifCount_;d++)Blockly.Mutator.reconnect(a[d],this,"IF"+d),Blockly.Mutator.reconnect(b[d],
-this,"DO"+d);Blockly.Mutator.reconnect(c,this,"ELSE")}};Blockly.Extensions.registerMutator("controls_if_mutator",Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN,null,["controls_if_elseif","controls_if_else"]);
-Blockly.Constants.Logic.CONTROLS_IF_TOOLTIP_EXTENSION=function(){this.setTooltip(function(){if(this.elseifCount_||this.elseCount_){if(!this.elseifCount_&&this.elseCount_)return Blockly.Msg.CONTROLS_IF_TOOLTIP_2;if(this.elseifCount_&&!this.elseCount_)return Blockly.Msg.CONTROLS_IF_TOOLTIP_3;if(this.elseifCount_&&this.elseCount_)return Blockly.Msg.CONTROLS_IF_TOOLTIP_4}else return Blockly.Msg.CONTROLS_IF_TOOLTIP_1;return""}.bind(this))};Blockly.Extensions.register("controls_if_tooltip",Blockly.Constants.Logic.CONTROLS_IF_TOOLTIP_EXTENSION);
-Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN={onchange:function(a){this.prevBlocks_||(this.prevBlocks_=[null,null]);var b=this.getInputTargetBlock("A"),c=this.getInputTargetBlock("B");b&&c&&!this.workspace.connectionChecker.doTypeChecks(b.outputConnection,c.outputConnection)&&(Blockly.Events.setGroup(a.group),a=this.prevBlocks_[0],a!==b&&(b.unplug(),!a||a.isDisposed()||a.isShadow()||this.getInput("A").connection.connect(a.outputConnection)),b=this.prevBlocks_[1],b!==c&&(c.unplug(),!b||b.isDisposed()||
-b.isShadow()||this.getInput("B").connection.connect(b.outputConnection)),this.bumpNeighbours(),Blockly.Events.setGroup(!1));this.prevBlocks_[0]=this.getInputTargetBlock("A");this.prevBlocks_[1]=this.getInputTargetBlock("B")}};Blockly.Constants.Logic.LOGIC_COMPARE_EXTENSION=function(){this.mixin(Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN)};Blockly.Extensions.register("logic_compare",Blockly.Constants.Logic.LOGIC_COMPARE_EXTENSION);
-Blockly.Constants.Logic.LOGIC_TERNARY_ONCHANGE_MIXIN={prevParentConnection_:null,onchange:function(a){var b=this.getInputTargetBlock("THEN"),c=this.getInputTargetBlock("ELSE"),d=this.outputConnection.targetConnection;if((b||c)&&d)for(var e=0;2>e;e++){var f=1==e?b:c;f&&!f.workspace.connectionChecker.doTypeChecks(f.outputConnection,d)&&(Blockly.Events.setGroup(a.group),d===this.prevParentConnection_?(this.unplug(),d.getSourceBlock().bumpNeighbours()):(f.unplug(),f.bumpNeighbours()),Blockly.Events.setGroup(!1))}this.prevParentConnection_=
-d}};Blockly.Extensions.registerMixin("logic_ternary",Blockly.Constants.Logic.LOGIC_TERNARY_ONCHANGE_MIXIN);Blockly.Blocks.loops={};Blockly.Constants.Loops={};Blockly.Constants.Loops.HUE=120;
-Blockly.defineBlocksWithJsonArray([{type:"controls_repeat_ext",message0:"%{BKY_CONTROLS_REPEAT_TITLE}",args0:[{type:"input_value",name:"TIMES",check:"Number"}],message1:"%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",args1:[{type:"input_statement",name:"DO"}],previousStatement:null,nextStatement:null,style:"loop_blocks",tooltip:"%{BKY_CONTROLS_REPEAT_TOOLTIP}",helpUrl:"%{BKY_CONTROLS_REPEAT_HELPURL}"},{type:"controls_repeat",message0:"%{BKY_CONTROLS_REPEAT_TITLE}",args0:[{type:"field_number",name:"TIMES",value:10,
-min:0,precision:1}],message1:"%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",args1:[{type:"input_statement",name:"DO"}],previousStatement:null,nextStatement:null,style:"loop_blocks",tooltip:"%{BKY_CONTROLS_REPEAT_TOOLTIP}",helpUrl:"%{BKY_CONTROLS_REPEAT_HELPURL}"},{type:"controls_whileUntil",message0:"%1 %2",args0:[{type:"field_dropdown",name:"MODE",options:[["%{BKY_CONTROLS_WHILEUNTIL_OPERATOR_WHILE}","WHILE"],["%{BKY_CONTROLS_WHILEUNTIL_OPERATOR_UNTIL}","UNTIL"]]},{type:"input_value",name:"BOOL",check:"Boolean"}],
-message1:"%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",args1:[{type:"input_statement",name:"DO"}],previousStatement:null,nextStatement:null,style:"loop_blocks",helpUrl:"%{BKY_CONTROLS_WHILEUNTIL_HELPURL}",extensions:["controls_whileUntil_tooltip"]},{type:"controls_for",message0:"%{BKY_CONTROLS_FOR_TITLE}",args0:[{type:"field_variable",name:"VAR",variable:null},{type:"input_value",name:"FROM",check:"Number",align:"RIGHT"},{type:"input_value",name:"TO",check:"Number",align:"RIGHT"},{type:"input_value",name:"BY",
-check:"Number",align:"RIGHT"}],message1:"%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",args1:[{type:"input_statement",name:"DO"}],inputsInline:!0,previousStatement:null,nextStatement:null,style:"loop_blocks",helpUrl:"%{BKY_CONTROLS_FOR_HELPURL}",extensions:["contextMenu_newGetVariableBlock","controls_for_tooltip"]},{type:"controls_forEach",message0:"%{BKY_CONTROLS_FOREACH_TITLE}",args0:[{type:"field_variable",name:"VAR",variable:null},{type:"input_value",name:"LIST",check:"Array"}],message1:"%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",
-args1:[{type:"input_statement",name:"DO"}],previousStatement:null,nextStatement:null,style:"loop_blocks",helpUrl:"%{BKY_CONTROLS_FOREACH_HELPURL}",extensions:["contextMenu_newGetVariableBlock","controls_forEach_tooltip"]},{type:"controls_flow_statements",message0:"%1",args0:[{type:"field_dropdown",name:"FLOW",options:[["%{BKY_CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK}","BREAK"],["%{BKY_CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE}","CONTINUE"]]}],previousStatement:null,style:"loop_blocks",helpUrl:"%{BKY_CONTROLS_FLOW_STATEMENTS_HELPURL}",
-suppressPrefixSuffix:!0,extensions:["controls_flow_tooltip","controls_flow_in_loop_check"]}]);Blockly.Constants.Loops.WHILE_UNTIL_TOOLTIPS={WHILE:"%{BKY_CONTROLS_WHILEUNTIL_TOOLTIP_WHILE}",UNTIL:"%{BKY_CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL}"};Blockly.Extensions.register("controls_whileUntil_tooltip",Blockly.Extensions.buildTooltipForDropdown("MODE",Blockly.Constants.Loops.WHILE_UNTIL_TOOLTIPS));Blockly.Constants.Loops.BREAK_CONTINUE_TOOLTIPS={BREAK:"%{BKY_CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK}",CONTINUE:"%{BKY_CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE}"};
-Blockly.Extensions.register("controls_flow_tooltip",Blockly.Extensions.buildTooltipForDropdown("FLOW",Blockly.Constants.Loops.BREAK_CONTINUE_TOOLTIPS));
-Blockly.Constants.Loops.CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN={customContextMenu:function(a){if(!this.isInFlyout){var b=this.getField("VAR").getVariable(),c=b.name;if(!this.isCollapsed()&&null!=c){var d={enabled:!0};d.text=Blockly.Msg.VARIABLES_SET_CREATE_GET.replace("%1",c);b=Blockly.Variables.generateVariableFieldDom(b);c=Blockly.utils.xml.createElement("block");c.setAttribute("type","variables_get");c.appendChild(b);d.callback=Blockly.ContextMenu.callbackFactory(this,c);a.push(d)}}}};
-Blockly.Extensions.registerMixin("contextMenu_newGetVariableBlock",Blockly.Constants.Loops.CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN);Blockly.Extensions.register("controls_for_tooltip",Blockly.Extensions.buildTooltipWithFieldText("%{BKY_CONTROLS_FOR_TOOLTIP}","VAR"));Blockly.Extensions.register("controls_forEach_tooltip",Blockly.Extensions.buildTooltipWithFieldText("%{BKY_CONTROLS_FOREACH_TOOLTIP}","VAR"));
-Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN={LOOP_TYPES:["controls_repeat","controls_repeat_ext","controls_forEach","controls_for","controls_whileUntil"],getSurroundLoop:function(a){do{if(-1!=Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.LOOP_TYPES.indexOf(a.type))return a;a=a.getSurroundParent()}while(a);return null},onchange:function(a){if(this.workspace.isDragging&&!this.workspace.isDragging()&&a.type==Blockly.Events.BLOCK_MOVE){var b=Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(this);
-this.setWarningText(b?null:Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING);if(!this.isInFlyout){var c=Blockly.Events.getGroup();Blockly.Events.setGroup(a.group);this.setEnabled(b);Blockly.Events.setGroup(c)}}}};Blockly.Extensions.registerMixin("controls_flow_in_loop_check",Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN);Blockly.Blocks.math={};Blockly.Constants.Math={};Blockly.Constants.Math.HUE=230;
-Blockly.defineBlocksWithJsonArray([{type:"math_number",message0:"%1",args0:[{type:"field_number",name:"NUM",value:0}],output:"Number",helpUrl:"%{BKY_MATH_NUMBER_HELPURL}",style:"math_blocks",tooltip:"%{BKY_MATH_NUMBER_TOOLTIP}",extensions:["parent_tooltip_when_inline"]},{type:"math_arithmetic",message0:"%1 %2 %3",args0:[{type:"input_value",name:"A",check:"Number"},{type:"field_dropdown",name:"OP",options:[["%{BKY_MATH_ADDITION_SYMBOL}","ADD"],["%{BKY_MATH_SUBTRACTION_SYMBOL}","MINUS"],["%{BKY_MATH_MULTIPLICATION_SYMBOL}",
-"MULTIPLY"],["%{BKY_MATH_DIVISION_SYMBOL}","DIVIDE"],["%{BKY_MATH_POWER_SYMBOL}","POWER"]]},{type:"input_value",name:"B",check:"Number"}],inputsInline:!0,output:"Number",style:"math_blocks",helpUrl:"%{BKY_MATH_ARITHMETIC_HELPURL}",extensions:["math_op_tooltip"]},{type:"math_single",message0:"%1 %2",args0:[{type:"field_dropdown",name:"OP",options:[["%{BKY_MATH_SINGLE_OP_ROOT}","ROOT"],["%{BKY_MATH_SINGLE_OP_ABSOLUTE}","ABS"],["-","NEG"],["ln","LN"],["log10","LOG10"],["e^","EXP"],["10^","POW10"]]},
-{type:"input_value",name:"NUM",check:"Number"}],output:"Number",style:"math_blocks",helpUrl:"%{BKY_MATH_SINGLE_HELPURL}",extensions:["math_op_tooltip"]},{type:"math_trig",message0:"%1 %2",args0:[{type:"field_dropdown",name:"OP",options:[["%{BKY_MATH_TRIG_SIN}","SIN"],["%{BKY_MATH_TRIG_COS}","COS"],["%{BKY_MATH_TRIG_TAN}","TAN"],["%{BKY_MATH_TRIG_ASIN}","ASIN"],["%{BKY_MATH_TRIG_ACOS}","ACOS"],["%{BKY_MATH_TRIG_ATAN}","ATAN"]]},{type:"input_value",name:"NUM",check:"Number"}],output:"Number",style:"math_blocks",
-helpUrl:"%{BKY_MATH_TRIG_HELPURL}",extensions:["math_op_tooltip"]},{type:"math_constant",message0:"%1",args0:[{type:"field_dropdown",name:"CONSTANT",options:[["\u03c0","PI"],["e","E"],["\u03c6","GOLDEN_RATIO"],["sqrt(2)","SQRT2"],["sqrt(\u00bd)","SQRT1_2"],["\u221e","INFINITY"]]}],output:"Number",style:"math_blocks",tooltip:"%{BKY_MATH_CONSTANT_TOOLTIP}",helpUrl:"%{BKY_MATH_CONSTANT_HELPURL}"},{type:"math_number_property",message0:"%1 %2",args0:[{type:"input_value",name:"NUMBER_TO_CHECK",check:"Number"},
-{type:"field_dropdown",name:"PROPERTY",options:[["%{BKY_MATH_IS_EVEN}","EVEN"],["%{BKY_MATH_IS_ODD}","ODD"],["%{BKY_MATH_IS_PRIME}","PRIME"],["%{BKY_MATH_IS_WHOLE}","WHOLE"],["%{BKY_MATH_IS_POSITIVE}","POSITIVE"],["%{BKY_MATH_IS_NEGATIVE}","NEGATIVE"],["%{BKY_MATH_IS_DIVISIBLE_BY}","DIVISIBLE_BY"]]}],inputsInline:!0,output:"Boolean",style:"math_blocks",tooltip:"%{BKY_MATH_IS_TOOLTIP}",mutator:"math_is_divisibleby_mutator"},{type:"math_change",message0:"%{BKY_MATH_CHANGE_TITLE}",args0:[{type:"field_variable",
-name:"VAR",variable:"%{BKY_MATH_CHANGE_TITLE_ITEM}"},{type:"input_value",name:"DELTA",check:"Number"}],previousStatement:null,nextStatement:null,style:"variable_blocks",helpUrl:"%{BKY_MATH_CHANGE_HELPURL}",extensions:["math_change_tooltip"]},{type:"math_round",message0:"%1 %2",args0:[{type:"field_dropdown",name:"OP",options:[["%{BKY_MATH_ROUND_OPERATOR_ROUND}","ROUND"],["%{BKY_MATH_ROUND_OPERATOR_ROUNDUP}","ROUNDUP"],["%{BKY_MATH_ROUND_OPERATOR_ROUNDDOWN}","ROUNDDOWN"]]},{type:"input_value",name:"NUM",
-check:"Number"}],output:"Number",style:"math_blocks",helpUrl:"%{BKY_MATH_ROUND_HELPURL}",tooltip:"%{BKY_MATH_ROUND_TOOLTIP}"},{type:"math_on_list",message0:"%1 %2",args0:[{type:"field_dropdown",name:"OP",options:[["%{BKY_MATH_ONLIST_OPERATOR_SUM}","SUM"],["%{BKY_MATH_ONLIST_OPERATOR_MIN}","MIN"],["%{BKY_MATH_ONLIST_OPERATOR_MAX}","MAX"],["%{BKY_MATH_ONLIST_OPERATOR_AVERAGE}","AVERAGE"],["%{BKY_MATH_ONLIST_OPERATOR_MEDIAN}","MEDIAN"],["%{BKY_MATH_ONLIST_OPERATOR_MODE}","MODE"],["%{BKY_MATH_ONLIST_OPERATOR_STD_DEV}",
-"STD_DEV"],["%{BKY_MATH_ONLIST_OPERATOR_RANDOM}","RANDOM"]]},{type:"input_value",name:"LIST",check:"Array"}],output:"Number",style:"math_blocks",helpUrl:"%{BKY_MATH_ONLIST_HELPURL}",mutator:"math_modes_of_list_mutator",extensions:["math_op_tooltip"]},{type:"math_modulo",message0:"%{BKY_MATH_MODULO_TITLE}",args0:[{type:"input_value",name:"DIVIDEND",check:"Number"},{type:"input_value",name:"DIVISOR",check:"Number"}],inputsInline:!0,output:"Number",style:"math_blocks",tooltip:"%{BKY_MATH_MODULO_TOOLTIP}",
-helpUrl:"%{BKY_MATH_MODULO_HELPURL}"},{type:"math_constrain",message0:"%{BKY_MATH_CONSTRAIN_TITLE}",args0:[{type:"input_value",name:"VALUE",check:"Number"},{type:"input_value",name:"LOW",check:"Number"},{type:"input_value",name:"HIGH",check:"Number"}],inputsInline:!0,output:"Number",style:"math_blocks",tooltip:"%{BKY_MATH_CONSTRAIN_TOOLTIP}",helpUrl:"%{BKY_MATH_CONSTRAIN_HELPURL}"},{type:"math_random_int",message0:"%{BKY_MATH_RANDOM_INT_TITLE}",args0:[{type:"input_value",name:"FROM",check:"Number"},
-{type:"input_value",name:"TO",check:"Number"}],inputsInline:!0,output:"Number",style:"math_blocks",tooltip:"%{BKY_MATH_RANDOM_INT_TOOLTIP}",helpUrl:"%{BKY_MATH_RANDOM_INT_HELPURL}"},{type:"math_random_float",message0:"%{BKY_MATH_RANDOM_FLOAT_TITLE_RANDOM}",output:"Number",style:"math_blocks",tooltip:"%{BKY_MATH_RANDOM_FLOAT_TOOLTIP}",helpUrl:"%{BKY_MATH_RANDOM_FLOAT_HELPURL}"},{type:"math_atan2",message0:"%{BKY_MATH_ATAN2_TITLE}",args0:[{type:"input_value",name:"X",check:"Number"},{type:"input_value",
-name:"Y",check:"Number"}],inputsInline:!0,output:"Number",style:"math_blocks",tooltip:"%{BKY_MATH_ATAN2_TOOLTIP}",helpUrl:"%{BKY_MATH_ATAN2_HELPURL}"}]);
-Blockly.Constants.Math.TOOLTIPS_BY_OP={ADD:"%{BKY_MATH_ARITHMETIC_TOOLTIP_ADD}",MINUS:"%{BKY_MATH_ARITHMETIC_TOOLTIP_MINUS}",MULTIPLY:"%{BKY_MATH_ARITHMETIC_TOOLTIP_MULTIPLY}",DIVIDE:"%{BKY_MATH_ARITHMETIC_TOOLTIP_DIVIDE}",POWER:"%{BKY_MATH_ARITHMETIC_TOOLTIP_POWER}",ROOT:"%{BKY_MATH_SINGLE_TOOLTIP_ROOT}",ABS:"%{BKY_MATH_SINGLE_TOOLTIP_ABS}",NEG:"%{BKY_MATH_SINGLE_TOOLTIP_NEG}",LN:"%{BKY_MATH_SINGLE_TOOLTIP_LN}",LOG10:"%{BKY_MATH_SINGLE_TOOLTIP_LOG10}",EXP:"%{BKY_MATH_SINGLE_TOOLTIP_EXP}",POW10:"%{BKY_MATH_SINGLE_TOOLTIP_POW10}",
-SIN:"%{BKY_MATH_TRIG_TOOLTIP_SIN}",COS:"%{BKY_MATH_TRIG_TOOLTIP_COS}",TAN:"%{BKY_MATH_TRIG_TOOLTIP_TAN}",ASIN:"%{BKY_MATH_TRIG_TOOLTIP_ASIN}",ACOS:"%{BKY_MATH_TRIG_TOOLTIP_ACOS}",ATAN:"%{BKY_MATH_TRIG_TOOLTIP_ATAN}",SUM:"%{BKY_MATH_ONLIST_TOOLTIP_SUM}",MIN:"%{BKY_MATH_ONLIST_TOOLTIP_MIN}",MAX:"%{BKY_MATH_ONLIST_TOOLTIP_MAX}",AVERAGE:"%{BKY_MATH_ONLIST_TOOLTIP_AVERAGE}",MEDIAN:"%{BKY_MATH_ONLIST_TOOLTIP_MEDIAN}",MODE:"%{BKY_MATH_ONLIST_TOOLTIP_MODE}",STD_DEV:"%{BKY_MATH_ONLIST_TOOLTIP_STD_DEV}",RANDOM:"%{BKY_MATH_ONLIST_TOOLTIP_RANDOM}"};
-Blockly.Extensions.register("math_op_tooltip",Blockly.Extensions.buildTooltipForDropdown("OP",Blockly.Constants.Math.TOOLTIPS_BY_OP));
-Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN={mutationToDom:function(){var a=Blockly.utils.xml.createElement("mutation"),b="DIVISIBLE_BY"==this.getFieldValue("PROPERTY");a.setAttribute("divisor_input",b);return a},domToMutation:function(a){a="true"==a.getAttribute("divisor_input");this.updateShape_(a)},updateShape_:function(a){var b=this.getInput("DIVISOR");a?b||this.appendValueInput("DIVISOR").setCheck("Number"):b&&this.removeInput("DIVISOR")}};
-Blockly.Constants.Math.IS_DIVISIBLE_MUTATOR_EXTENSION=function(){this.getField("PROPERTY").setValidator(function(a){a="DIVISIBLE_BY"==a;this.getSourceBlock().updateShape_(a)})};Blockly.Extensions.registerMutator("math_is_divisibleby_mutator",Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN,Blockly.Constants.Math.IS_DIVISIBLE_MUTATOR_EXTENSION);Blockly.Extensions.register("math_change_tooltip",Blockly.Extensions.buildTooltipWithFieldText("%{BKY_MATH_CHANGE_TOOLTIP}","VAR"));
-Blockly.Constants.Math.LIST_MODES_MUTATOR_MIXIN={updateType_:function(a){"MODE"==a?this.outputConnection.setCheck("Array"):this.outputConnection.setCheck("Number")},mutationToDom:function(){var a=Blockly.utils.xml.createElement("mutation");a.setAttribute("op",this.getFieldValue("OP"));return a},domToMutation:function(a){this.updateType_(a.getAttribute("op"))}};Blockly.Constants.Math.LIST_MODES_MUTATOR_EXTENSION=function(){this.getField("OP").setValidator(function(a){this.updateType_(a)}.bind(this))};
-Blockly.Extensions.registerMutator("math_modes_of_list_mutator",Blockly.Constants.Math.LIST_MODES_MUTATOR_MIXIN,Blockly.Constants.Math.LIST_MODES_MUTATOR_EXTENSION);Blockly.Blocks.procedures={};
-Blockly.Blocks.procedures_defnoreturn={init:function(){var a=Blockly.Procedures.findLegalName("",this);a=new Blockly.FieldTextInput(a,Blockly.Procedures.rename);a.setSpellcheck(!1);this.appendDummyInput().appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_TITLE).appendField(a,"NAME").appendField("","PARAMS");this.setMutator(new Blockly.Mutator(["procedures_mutatorarg"]));(this.workspace.options.comments||this.workspace.options.parentWorkspace&&this.workspace.options.parentWorkspace.options.comments)&&Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT&&
-this.setCommentText(Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT);this.setStyle("procedure_blocks");this.setTooltip(Blockly.Msg.PROCEDURES_DEFNORETURN_TOOLTIP);this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFNORETURN_HELPURL);this.arguments_=[];this.argumentVarModels_=[];this.setStatements_(!0);this.statementConnection_=null},setStatements_:function(a){this.hasStatements_!==a&&(a?(this.appendStatementInput("STACK").appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_DO),this.getInput("RETURN")&&this.moveInputBefore("STACK",
-"RETURN")):this.removeInput("STACK",!0),this.hasStatements_=a)},updateParams_:function(){var a="";this.arguments_.length&&(a=Blockly.Msg.PROCEDURES_BEFORE_PARAMS+" "+this.arguments_.join(", "));Blockly.Events.disable();try{this.setFieldValue(a,"PARAMS")}finally{Blockly.Events.enable()}},mutationToDom:function(a){var b=Blockly.utils.xml.createElement("mutation");a&&b.setAttribute("name",this.getFieldValue("NAME"));for(var c=0;c