diff --git a/README.md b/README.md
index 3e78ac75939ef83887ed9ec4836a54c977516de3..483cbe229169466926aa1d108f5c5712da272483 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,13 @@
-# PHP助手
+# PHP助手
+[](https://gitee.com/codekpy/php-helper/stargazers)
+[](https://gitee.com/codekpy/php-helper/members)
我们基于谷歌的开源程序Blockly开发了此程序——PHP助手
## 使用PHP助手
-PHP助手分为[在线版](http://www.codekpy.site/php-hepler-master/index.php)和[离线版](https://gitee.com/codekpy/php-helper/)
+PHP助手分为[在线版](http://www.codekpy.site/php-hepler-master/index.php)和[离线版](https://gitee.com/codekpy/php-helper/)以及[GithubPages版](https://wangs-offical.github.io/php-helper/ide.html)
### 安装PHP助手
diff --git a/blockly/colored_egg/colored_egg.html b/blockly/colored_egg/colored_egg.html
index 66e6127ee403835effcb727334cebd82ae62c7c4..109bd698dcfe5aa583c9bb0358704ce5cd25de7f 100644
--- a/blockly/colored_egg/colored_egg.html
+++ b/blockly/colored_egg/colored_egg.html
@@ -3,6 +3,7 @@
彩蛋
+
-
-
-
-
-
-
-
-
-
-
-
-
-
- ✓
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/blockly/python_compressed.js b/blockly/python_compressed.js
deleted file mode 100644
index 9b83d3bfe1583d45bd766a97ec80422bf2082a47..0000000000000000000000000000000000000000
--- a/blockly/python_compressed.js
+++ /dev/null
@@ -1,254 +0,0 @@
-// Do not edit this file; automatically generated.
-
-/* 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
- var factoryExports = factory(root.Blockly);
- root.Blockly.Python = factoryExports.pythonGenerator;
- root.Blockly.Python.__namespace__ = factoryExports.__namespace__;
- }
-}(this, function(__parent__) {
-var $=__parent__.__namespace__;
-var module$exports$Blockly$Python={},module$contents$Blockly$Python_stringUtils=$.module$build$src$core$utils$string,module$contents$Blockly$Python_Variables=$.module$build$src$core$variables,module$contents$Blockly$Python_Generator=$.Generator$$module$build$src$core$generator,module$contents$Blockly$Python_inputTypes=$.module$build$src$core$input_types.inputTypes,module$contents$Blockly$Python_Names=$.module$build$src$core$names.Names,module$contents$Blockly$Python_NameType=$.NameType$$module$build$src$core$names;
-module$exports$Blockly$Python.pythonGenerator=new $.Generator$$module$build$src$core$generator("Python");module$exports$Blockly$Python.pythonGenerator.addReservedWords("False,None,True,and,as,assert,break,class,continue,def,del,elif,else,except,exec,finally,for,from,global,if,import,in,is,lambda,nonlocal,not,or,pass,print,raise,return,try,while,with,yield,NotImplemented,Ellipsis,__debug__,quit,exit,copyright,license,credits,ArithmeticError,AssertionError,AttributeError,BaseException,BlockingIOError,BrokenPipeError,BufferError,BytesWarning,ChildProcessError,ConnectionAbortedError,ConnectionError,ConnectionRefusedError,ConnectionResetError,DeprecationWarning,EOFError,Ellipsis,EnvironmentError,Exception,FileExistsError,FileNotFoundError,FloatingPointError,FutureWarning,GeneratorExit,IOError,ImportError,ImportWarning,IndentationError,IndexError,InterruptedError,IsADirectoryError,KeyError,KeyboardInterrupt,LookupError,MemoryError,ModuleNotFoundError,NameError,NotADirectoryError,NotImplemented,NotImplementedError,OSError,OverflowError,PendingDeprecationWarning,PermissionError,ProcessLookupError,RecursionError,ReferenceError,ResourceWarning,RuntimeError,RuntimeWarning,StandardError,StopAsyncIteration,StopIteration,SyntaxError,SyntaxWarning,SystemError,SystemExit,TabError,TimeoutError,TypeError,UnboundLocalError,UnicodeDecodeError,UnicodeEncodeError,UnicodeError,UnicodeTranslateError,UnicodeWarning,UserWarning,ValueError,Warning,ZeroDivisionError,_,__build_class__,__debug__,__doc__,__import__,__loader__,__name__,__package__,__spec__,abs,all,any,apply,ascii,basestring,bin,bool,buffer,bytearray,bytes,callable,chr,classmethod,cmp,coerce,compile,complex,copyright,credits,delattr,dict,dir,divmod,enumerate,eval,exec,execfile,exit,file,filter,float,format,frozenset,getattr,globals,hasattr,hash,help,hex,id,input,int,intern,isinstance,issubclass,iter,len,license,list,locals,long,map,max,memoryview,min,next,object,oct,open,ord,pow,print,property,quit,range,raw_input,reduce,reload,repr,reversed,round,set,setattr,slice,sorted,staticmethod,str,sum,super,tuple,type,unichr,unicode,vars,xrange,zip");
-module$exports$Blockly$Python.pythonGenerator.ORDER_ATOMIC=0;module$exports$Blockly$Python.pythonGenerator.ORDER_COLLECTION=1;module$exports$Blockly$Python.pythonGenerator.ORDER_STRING_CONVERSION=1;module$exports$Blockly$Python.pythonGenerator.ORDER_MEMBER=2.1;module$exports$Blockly$Python.pythonGenerator.ORDER_FUNCTION_CALL=2.2;module$exports$Blockly$Python.pythonGenerator.ORDER_EXPONENTIATION=3;module$exports$Blockly$Python.pythonGenerator.ORDER_UNARY_SIGN=4;
-module$exports$Blockly$Python.pythonGenerator.ORDER_BITWISE_NOT=4;module$exports$Blockly$Python.pythonGenerator.ORDER_MULTIPLICATIVE=5;module$exports$Blockly$Python.pythonGenerator.ORDER_ADDITIVE=6;module$exports$Blockly$Python.pythonGenerator.ORDER_BITWISE_SHIFT=7;module$exports$Blockly$Python.pythonGenerator.ORDER_BITWISE_AND=8;module$exports$Blockly$Python.pythonGenerator.ORDER_BITWISE_XOR=9;module$exports$Blockly$Python.pythonGenerator.ORDER_BITWISE_OR=10;
-module$exports$Blockly$Python.pythonGenerator.ORDER_RELATIONAL=11;module$exports$Blockly$Python.pythonGenerator.ORDER_LOGICAL_NOT=12;module$exports$Blockly$Python.pythonGenerator.ORDER_LOGICAL_AND=13;module$exports$Blockly$Python.pythonGenerator.ORDER_LOGICAL_OR=14;module$exports$Blockly$Python.pythonGenerator.ORDER_CONDITIONAL=15;module$exports$Blockly$Python.pythonGenerator.ORDER_LAMBDA=16;module$exports$Blockly$Python.pythonGenerator.ORDER_NONE=99;
-module$exports$Blockly$Python.pythonGenerator.ORDER_OVERRIDES=[[module$exports$Blockly$Python.pythonGenerator.ORDER_FUNCTION_CALL,module$exports$Blockly$Python.pythonGenerator.ORDER_MEMBER],[module$exports$Blockly$Python.pythonGenerator.ORDER_FUNCTION_CALL,module$exports$Blockly$Python.pythonGenerator.ORDER_FUNCTION_CALL],[module$exports$Blockly$Python.pythonGenerator.ORDER_MEMBER,module$exports$Blockly$Python.pythonGenerator.ORDER_MEMBER],[module$exports$Blockly$Python.pythonGenerator.ORDER_MEMBER,
-module$exports$Blockly$Python.pythonGenerator.ORDER_FUNCTION_CALL],[module$exports$Blockly$Python.pythonGenerator.ORDER_LOGICAL_NOT,module$exports$Blockly$Python.pythonGenerator.ORDER_LOGICAL_NOT],[module$exports$Blockly$Python.pythonGenerator.ORDER_LOGICAL_AND,module$exports$Blockly$Python.pythonGenerator.ORDER_LOGICAL_AND],[module$exports$Blockly$Python.pythonGenerator.ORDER_LOGICAL_OR,module$exports$Blockly$Python.pythonGenerator.ORDER_LOGICAL_OR]];
-module$exports$Blockly$Python.pythonGenerator.isInitialized=!1;
-module$exports$Blockly$Python.pythonGenerator.init=function(a){Object.getPrototypeOf(this).init.call(this);this.PASS=this.INDENT+"pass\n";this.nameDB_?this.nameDB_.reset():this.nameDB_=new $.module$build$src$core$names.Names(this.RESERVED_WORDS_);this.nameDB_.setVariableMap(a.getVariableMap());this.nameDB_.populateVariables(a);this.nameDB_.populateProcedures(a);const b=[];var c=$.module$build$src$core$variables.allDeveloperVariables(a);for(let d=0;dc?"int("+a+" - "+-c+")":"int("+a+")",d&&(a="-"+a));return a};var module$exports$Blockly$Python$variables={},module$contents$Blockly$Python$variables_NameType=$.NameType$$module$build$src$core$names;module$exports$Blockly$Python.pythonGenerator.variables_get=function(a){return[module$exports$Blockly$Python.pythonGenerator.nameDB_.getName(a.getFieldValue("VAR"),$.NameType$$module$build$src$core$names.VARIABLE),module$exports$Blockly$Python.pythonGenerator.ORDER_ATOMIC]};
-module$exports$Blockly$Python.pythonGenerator.variables_set=function(a){const b=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"VALUE",module$exports$Blockly$Python.pythonGenerator.ORDER_NONE)||"0";return module$exports$Blockly$Python.pythonGenerator.nameDB_.getName(a.getFieldValue("VAR"),$.NameType$$module$build$src$core$names.VARIABLE)+" = "+b+"\n"};var module$exports$Blockly$Python$variablesDynamic={};module$exports$Blockly$Python.pythonGenerator.variables_get_dynamic=module$exports$Blockly$Python.pythonGenerator.variables_get;module$exports$Blockly$Python.pythonGenerator.variables_set_dynamic=module$exports$Blockly$Python.pythonGenerator.variables_set;var module$exports$Blockly$Python$texts={},module$contents$Blockly$Python$texts_stringUtils=$.module$build$src$core$utils$string,module$contents$Blockly$Python$texts_NameType=$.NameType$$module$build$src$core$names;module$exports$Blockly$Python.pythonGenerator.text=function(a){return[module$exports$Blockly$Python.pythonGenerator.quote_(a.getFieldValue("TEXT")),module$exports$Blockly$Python.pythonGenerator.ORDER_ATOMIC]};
-module$exports$Blockly$Python.pythonGenerator.text_multiline=function(a){a=module$exports$Blockly$Python.pythonGenerator.multiline_quote_(a.getFieldValue("TEXT"));const b=-1!==a.indexOf("+")?module$exports$Blockly$Python.pythonGenerator.ORDER_ADDITIVE:module$exports$Blockly$Python.pythonGenerator.ORDER_ATOMIC;return[a,b]};
-var module$contents$Blockly$Python$texts_strRegExp=/^\s*'([^']|\\')*'\s*$/,module$contents$Blockly$Python$texts_forceString=function(a){return module$contents$Blockly$Python$texts_strRegExp.test(a)?[a,module$exports$Blockly$Python.pythonGenerator.ORDER_ATOMIC]:["str("+a+")",module$exports$Blockly$Python.pythonGenerator.ORDER_FUNCTION_CALL]};
-module$exports$Blockly$Python.pythonGenerator.text_join=function(a){switch(a.itemCount_){case 0:return["''",module$exports$Blockly$Python.pythonGenerator.ORDER_ATOMIC];case 1:return a=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"ADD0",module$exports$Blockly$Python.pythonGenerator.ORDER_NONE)||"''",module$contents$Blockly$Python$texts_forceString(a);case 2:var b=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"ADD0",module$exports$Blockly$Python.pythonGenerator.ORDER_NONE)||
-"''";a=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"ADD1",module$exports$Blockly$Python.pythonGenerator.ORDER_NONE)||"''";return[module$contents$Blockly$Python$texts_forceString(b)[0]+" + "+module$contents$Blockly$Python$texts_forceString(a)[0],module$exports$Blockly$Python.pythonGenerator.ORDER_ADDITIVE];default:b=[];for(let c=0;ca?module$exports$Blockly$Python.pythonGenerator.ORDER_UNARY_SIGN:module$exports$Blockly$Python.pythonGenerator.ORDER_ATOMIC;return[a,b]};
-module$exports$Blockly$Python.pythonGenerator.math_arithmetic=function(a){var b={ADD:[" + ",module$exports$Blockly$Python.pythonGenerator.ORDER_ADDITIVE],MINUS:[" - ",module$exports$Blockly$Python.pythonGenerator.ORDER_ADDITIVE],MULTIPLY:[" * ",module$exports$Blockly$Python.pythonGenerator.ORDER_MULTIPLICATIVE],DIVIDE:[" / ",module$exports$Blockly$Python.pythonGenerator.ORDER_MULTIPLICATIVE],POWER:[" ** ",module$exports$Blockly$Python.pythonGenerator.ORDER_EXPONENTIATION]}[a.getFieldValue("OP")];
-const c=b[0];b=b[1];const d=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"A",b)||"0";a=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"B",b)||"0";return[d+c+a,b]};
-module$exports$Blockly$Python.pythonGenerator.math_single=function(a){const b=a.getFieldValue("OP");let c;if("NEG"===b)return c=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"NUM",module$exports$Blockly$Python.pythonGenerator.ORDER_UNARY_SIGN)||"0",["-"+c,module$exports$Blockly$Python.pythonGenerator.ORDER_UNARY_SIGN];module$exports$Blockly$Python.pythonGenerator.definitions_.import_math="import math";a="SIN"===b||"COS"===b||"TAN"===b?module$exports$Blockly$Python.pythonGenerator.valueToCode(a,
-"NUM",module$exports$Blockly$Python.pythonGenerator.ORDER_MULTIPLICATIVE)||"0":module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"NUM",module$exports$Blockly$Python.pythonGenerator.ORDER_NONE)||"0";switch(b){case "ABS":c="math.fabs("+a+")";break;case "ROOT":c="math.sqrt("+a+")";break;case "LN":c="math.log("+a+")";break;case "LOG10":c="math.log10("+a+")";break;case "EXP":c="math.exp("+a+")";break;case "POW10":c="math.pow(10,"+a+")";break;case "ROUND":c="round("+a+")";break;case "ROUNDUP":c=
-"math.ceil("+a+")";break;case "ROUNDDOWN":c="math.floor("+a+")";break;case "SIN":c="math.sin("+a+" / 180.0 * math.pi)";break;case "COS":c="math.cos("+a+" / 180.0 * math.pi)";break;case "TAN":c="math.tan("+a+" / 180.0 * math.pi)"}if(c)return[c,module$exports$Blockly$Python.pythonGenerator.ORDER_FUNCTION_CALL];switch(b){case "ASIN":c="math.asin("+a+") / math.pi * 180";break;case "ACOS":c="math.acos("+a+") / math.pi * 180";break;case "ATAN":c="math.atan("+a+") / math.pi * 180";break;default:throw Error("Unknown math operator: "+
-b);}return[c,module$exports$Blockly$Python.pythonGenerator.ORDER_MULTIPLICATIVE]};
-module$exports$Blockly$Python.pythonGenerator.math_constant=function(a){const b={PI:["math.pi",module$exports$Blockly$Python.pythonGenerator.ORDER_MEMBER],E:["math.e",module$exports$Blockly$Python.pythonGenerator.ORDER_MEMBER],GOLDEN_RATIO:["(1 + math.sqrt(5)) / 2",module$exports$Blockly$Python.pythonGenerator.ORDER_MULTIPLICATIVE],SQRT2:["math.sqrt(2)",module$exports$Blockly$Python.pythonGenerator.ORDER_MEMBER],SQRT1_2:["math.sqrt(1.0 / 2)",module$exports$Blockly$Python.pythonGenerator.ORDER_MEMBER],
-INFINITY:["float('inf')",module$exports$Blockly$Python.pythonGenerator.ORDER_ATOMIC]};a=a.getFieldValue("CONSTANT");"INFINITY"!==a&&(module$exports$Blockly$Python.pythonGenerator.definitions_.import_math="import math");return b[a]};
-module$exports$Blockly$Python.pythonGenerator.math_number_property=function(a){var b={EVEN:[" % 2 == 0",module$exports$Blockly$Python.pythonGenerator.ORDER_MULTIPLICATIVE,module$exports$Blockly$Python.pythonGenerator.ORDER_RELATIONAL],ODD:[" % 2 == 1",module$exports$Blockly$Python.pythonGenerator.ORDER_MULTIPLICATIVE,module$exports$Blockly$Python.pythonGenerator.ORDER_RELATIONAL],WHOLE:[" % 1 == 0",module$exports$Blockly$Python.pythonGenerator.ORDER_MULTIPLICATIVE,module$exports$Blockly$Python.pythonGenerator.ORDER_RELATIONAL],
-POSITIVE:[" > 0",module$exports$Blockly$Python.pythonGenerator.ORDER_RELATIONAL,module$exports$Blockly$Python.pythonGenerator.ORDER_RELATIONAL],NEGATIVE:[" < 0",module$exports$Blockly$Python.pythonGenerator.ORDER_RELATIONAL,module$exports$Blockly$Python.pythonGenerator.ORDER_RELATIONAL],DIVISIBLE_BY:[null,module$exports$Blockly$Python.pythonGenerator.ORDER_MULTIPLICATIVE,module$exports$Blockly$Python.pythonGenerator.ORDER_RELATIONAL],PRIME:[null,module$exports$Blockly$Python.pythonGenerator.ORDER_NONE,
-module$exports$Blockly$Python.pythonGenerator.ORDER_FUNCTION_CALL]};const c=a.getFieldValue("PROPERTY"),[d,e,f]=b[c];b=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"NUMBER_TO_CHECK",e)||"0";if("PRIME"===c)module$exports$Blockly$Python.pythonGenerator.definitions_.import_math="import math",module$exports$Blockly$Python.pythonGenerator.definitions_.from_numbers_import_Number="from numbers import Number",a=module$exports$Blockly$Python.pythonGenerator.provideFunction_("math_isPrime",`
-def ${module$exports$Blockly$Python.pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(n):
- # https://en.wikipedia.org/wiki/Primality_test#Naive_methods
- # If n is not a number but a string, try parsing it.
- if not isinstance(n, Number):
- try:
- n = float(n)
- except:
- return False
- if n == 2 or n == 3:
- return True
- # False if n is negative, is 1, or not whole, or if n is divisible by 2 or 3.
- if n <= 1 or n % 1 != 0 or n % 2 == 0 or n % 3 == 0:
- return False
- # Check all the numbers of form 6k +/- 1, up to sqrt(n).
- for x in range(6, int(math.sqrt(n)) + 2, 6):
- if n % (x - 1) == 0 or n % (x + 1) == 0:
- return False
- return True
-`)+"("+b+")";else if("DIVISIBLE_BY"===c){a=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"DIVISOR",module$exports$Blockly$Python.pythonGenerator.ORDER_MULTIPLICATIVE)||"0";if("0"===a)return["False",module$exports$Blockly$Python.pythonGenerator.ORDER_ATOMIC];a=b+" % "+a+" == 0"}else a=b+d;return[a,f]};
-module$exports$Blockly$Python.pythonGenerator.math_change=function(a){module$exports$Blockly$Python.pythonGenerator.definitions_.from_numbers_import_Number="from numbers import Number";const b=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"DELTA",module$exports$Blockly$Python.pythonGenerator.ORDER_ADDITIVE)||"0";a=module$exports$Blockly$Python.pythonGenerator.nameDB_.getName(a.getFieldValue("VAR"),$.NameType$$module$build$src$core$names.VARIABLE);return a+" = ("+a+" if isinstance("+
-a+", Number) else 0) + "+b+"\n"};module$exports$Blockly$Python.pythonGenerator.math_round=module$exports$Blockly$Python.pythonGenerator.math_single;module$exports$Blockly$Python.pythonGenerator.math_trig=module$exports$Blockly$Python.pythonGenerator.math_single;
-module$exports$Blockly$Python.pythonGenerator.math_on_list=function(a){var b=a.getFieldValue("OP");a=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"LIST",module$exports$Blockly$Python.pythonGenerator.ORDER_NONE)||"[]";switch(b){case "SUM":b="sum("+a+")";break;case "MIN":b="min("+a+")";break;case "MAX":b="max("+a+")";break;case "AVERAGE":module$exports$Blockly$Python.pythonGenerator.definitions_.from_numbers_import_Number="from numbers import Number";b=module$exports$Blockly$Python.pythonGenerator.provideFunction_("math_mean",
-`
-def ${module$exports$Blockly$Python.pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(myList):
- localList = [e for e in myList if isinstance(e, Number)]
- if not localList: return
- return float(sum(localList)) / len(localList)
-`)+"("+a+")";break;case "MEDIAN":module$exports$Blockly$Python.pythonGenerator.definitions_.from_numbers_import_Number="from numbers import Number";b=module$exports$Blockly$Python.pythonGenerator.provideFunction_("math_median",`
-def ${module$exports$Blockly$Python.pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(myList):
- localList = sorted([e for e in myList if isinstance(e, Number)])
- if not localList: return
- if len(localList) % 2 == 0:
- return (localList[len(localList) // 2 - 1] + localList[len(localList) // 2]) / 2.0
- else:
- return localList[(len(localList) - 1) // 2]
-`)+"("+a+")";break;case "MODE":b=module$exports$Blockly$Python.pythonGenerator.provideFunction_("math_modes",`
-def ${module$exports$Blockly$Python.pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(some_list):
- modes = []
- # Using a lists of [item, count] to keep count rather than dict
- # to avoid "unhashable" errors when the counted item is itself a list or dict.
- counts = []
- maxCount = 1
- for item in some_list:
- found = False
- for count in counts:
- if count[0] == item:
- count[1] += 1
- maxCount = max(maxCount, count[1])
- found = True
- if not found:
- counts.append([item, 1])
- for counted_item, item_count in counts:
- if item_count == maxCount:
- modes.append(counted_item)
- return modes
-`)+"("+a+")";break;case "STD_DEV":module$exports$Blockly$Python.pythonGenerator.definitions_.import_math="import math";b=module$exports$Blockly$Python.pythonGenerator.provideFunction_("math_standard_deviation",`
-def ${module$exports$Blockly$Python.pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(numbers):
- n = len(numbers)
- if n == 0: return
- mean = float(sum(numbers)) / n
- variance = sum((x - mean) ** 2 for x in numbers) / n
- return math.sqrt(variance)
-`)+"("+a+")";break;case "RANDOM":module$exports$Blockly$Python.pythonGenerator.definitions_.import_random="import random";b="random.choice("+a+")";break;default:throw Error("Unknown operator: "+b);}return[b,module$exports$Blockly$Python.pythonGenerator.ORDER_FUNCTION_CALL]};
-module$exports$Blockly$Python.pythonGenerator.math_modulo=function(a){const b=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"DIVIDEND",module$exports$Blockly$Python.pythonGenerator.ORDER_MULTIPLICATIVE)||"0";a=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"DIVISOR",module$exports$Blockly$Python.pythonGenerator.ORDER_MULTIPLICATIVE)||"0";return[b+" % "+a,module$exports$Blockly$Python.pythonGenerator.ORDER_MULTIPLICATIVE]};
-module$exports$Blockly$Python.pythonGenerator.math_constrain=function(a){const b=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"VALUE",module$exports$Blockly$Python.pythonGenerator.ORDER_NONE)||"0",c=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"LOW",module$exports$Blockly$Python.pythonGenerator.ORDER_NONE)||"0";a=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"HIGH",module$exports$Blockly$Python.pythonGenerator.ORDER_NONE)||"float('inf')";return["min(max("+
-b+", "+c+"), "+a+")",module$exports$Blockly$Python.pythonGenerator.ORDER_FUNCTION_CALL]};
-module$exports$Blockly$Python.pythonGenerator.math_random_int=function(a){module$exports$Blockly$Python.pythonGenerator.definitions_.import_random="import random";const b=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"FROM",module$exports$Blockly$Python.pythonGenerator.ORDER_NONE)||"0";a=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"TO",module$exports$Blockly$Python.pythonGenerator.ORDER_NONE)||"0";return["random.randint("+b+", "+a+")",module$exports$Blockly$Python.pythonGenerator.ORDER_FUNCTION_CALL]};
-module$exports$Blockly$Python.pythonGenerator.math_random_float=function(a){module$exports$Blockly$Python.pythonGenerator.definitions_.import_random="import random";return["random.random()",module$exports$Blockly$Python.pythonGenerator.ORDER_FUNCTION_CALL]};
-module$exports$Blockly$Python.pythonGenerator.math_atan2=function(a){module$exports$Blockly$Python.pythonGenerator.definitions_.import_math="import math";const b=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"X",module$exports$Blockly$Python.pythonGenerator.ORDER_NONE)||"0";return["math.atan2("+(module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"Y",module$exports$Blockly$Python.pythonGenerator.ORDER_NONE)||"0")+", "+b+") / math.pi * 180",module$exports$Blockly$Python.pythonGenerator.ORDER_MULTIPLICATIVE]};var module$exports$Blockly$Python$loops={},module$contents$Blockly$Python$loops_stringUtils=$.module$build$src$core$utils$string,module$contents$Blockly$Python$loops_NameType=$.NameType$$module$build$src$core$names;
-module$exports$Blockly$Python.pythonGenerator.controls_repeat_ext=function(a){let b;b=a.getField("TIMES")?String(parseInt(a.getFieldValue("TIMES"),10)):module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"TIMES",module$exports$Blockly$Python.pythonGenerator.ORDER_NONE)||"0";b=$.module$build$src$core$utils$string.isNumber(b)?parseInt(b,10):"int("+b+")";let c=module$exports$Blockly$Python.pythonGenerator.statementToCode(a,"DO");c=module$exports$Blockly$Python.pythonGenerator.addLoopTrap(c,a)||
-module$exports$Blockly$Python.pythonGenerator.PASS;return"for "+module$exports$Blockly$Python.pythonGenerator.nameDB_.getDistinctName("count",$.NameType$$module$build$src$core$names.VARIABLE)+" in range("+b+"):\n"+c};module$exports$Blockly$Python.pythonGenerator.controls_repeat=module$exports$Blockly$Python.pythonGenerator.controls_repeat_ext;
-module$exports$Blockly$Python.pythonGenerator.controls_whileUntil=function(a){const b="UNTIL"===a.getFieldValue("MODE");let c=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"BOOL",b?module$exports$Blockly$Python.pythonGenerator.ORDER_LOGICAL_NOT:module$exports$Blockly$Python.pythonGenerator.ORDER_NONE)||"False",d=module$exports$Blockly$Python.pythonGenerator.statementToCode(a,"DO");d=module$exports$Blockly$Python.pythonGenerator.addLoopTrap(d,a)||module$exports$Blockly$Python.pythonGenerator.PASS;
-b&&(c="not "+c);return"while "+c+":\n"+d};
-module$exports$Blockly$Python.pythonGenerator.controls_for=function(a){const b=module$exports$Blockly$Python.pythonGenerator.nameDB_.getName(a.getFieldValue("VAR"),$.NameType$$module$build$src$core$names.VARIABLE);var c=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"FROM",module$exports$Blockly$Python.pythonGenerator.ORDER_NONE)||"0",d=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"TO",module$exports$Blockly$Python.pythonGenerator.ORDER_NONE)||"0",e=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,
-"BY",module$exports$Blockly$Python.pythonGenerator.ORDER_NONE)||"1";let f=module$exports$Blockly$Python.pythonGenerator.statementToCode(a,"DO");f=module$exports$Blockly$Python.pythonGenerator.addLoopTrap(f,a)||module$exports$Blockly$Python.pythonGenerator.PASS;let g="";const h=function(){return module$exports$Blockly$Python.pythonGenerator.provideFunction_("upRange",`
-def ${module$exports$Blockly$Python.pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(start, stop, step):
- while start <= stop:
- yield start
- start += abs(step)
-`)},k=function(){return module$exports$Blockly$Python.pythonGenerator.provideFunction_("downRange",`
-def ${module$exports$Blockly$Python.pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(start, stop, step):
- while start >= stop:
- yield start
- start -= abs(step)
-`)};a=function(l,m,n){return"("+l+" <= "+m+") and "+h()+"("+l+", "+m+", "+n+") or "+k()+"("+l+", "+m+", "+n+")"};if($.module$build$src$core$utils$string.isNumber(c)&&$.module$build$src$core$utils$string.isNumber(d)&&$.module$build$src$core$utils$string.isNumber(e))c=Number(c),d=Number(d),e=Math.abs(Number(e)),0===c%1&&0===d%1&&0===e%1?(c<=d?(d++,a=0===c&&1===e?d:c+", "+d,1!==e&&(a+=", "+e)):(d--,a=c+", "+d+", -"+e),a="range("+a+")"):(a=c",GTE:">="}[a.getFieldValue("OP")],c=module$exports$Blockly$Python.pythonGenerator.ORDER_RELATIONAL,d=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"A",c)||"0";a=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"B",c)||"0";return[d+" "+b+" "+a,c]};
-module$exports$Blockly$Python.pythonGenerator.logic_operation=function(a){const b="AND"===a.getFieldValue("OP")?"and":"or",c="and"===b?module$exports$Blockly$Python.pythonGenerator.ORDER_LOGICAL_AND:module$exports$Blockly$Python.pythonGenerator.ORDER_LOGICAL_OR;let d=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"A",c);a=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"B",c);if(d||a){const e="and"===b?"True":"False";d||(d=e);a||(a=e)}else a=d="False";return[d+" "+b+" "+a,
-c]};module$exports$Blockly$Python.pythonGenerator.logic_negate=function(a){return["not "+(module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"BOOL",module$exports$Blockly$Python.pythonGenerator.ORDER_LOGICAL_NOT)||"True"),module$exports$Blockly$Python.pythonGenerator.ORDER_LOGICAL_NOT]};module$exports$Blockly$Python.pythonGenerator.logic_boolean=function(a){return["TRUE"===a.getFieldValue("BOOL")?"True":"False",module$exports$Blockly$Python.pythonGenerator.ORDER_ATOMIC]};
-module$exports$Blockly$Python.pythonGenerator.logic_null=function(a){return["None",module$exports$Blockly$Python.pythonGenerator.ORDER_ATOMIC]};
-module$exports$Blockly$Python.pythonGenerator.logic_ternary=function(a){const b=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"IF",module$exports$Blockly$Python.pythonGenerator.ORDER_CONDITIONAL)||"False",c=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"THEN",module$exports$Blockly$Python.pythonGenerator.ORDER_CONDITIONAL)||"None";a=module$exports$Blockly$Python.pythonGenerator.valueToCode(a,"ELSE",module$exports$Blockly$Python.pythonGenerator.ORDER_CONDITIONAL)||"None";
-return[c+" if "+b+" else "+a,module$exports$Blockly$Python.pythonGenerator.ORDER_CONDITIONAL]};var module$exports$Blockly$Python$lists={},module$contents$Blockly$Python$lists_stringUtils=$.module$build$src$core$utils$string,module$contents$Blockly$Python$lists_NameType=$.NameType$$module$build$src$core$names;module$exports$Blockly$Python.pythonGenerator.lists_create_empty=function(a){return["[]",module$exports$Blockly$Python.pythonGenerator.ORDER_ATOMIC]};
-module$exports$Blockly$Python.pythonGenerator.lists_create_with=function(a){const b=Array(a.itemCount_);for(let c=0;c>> print(','.join(sorted(dir(__builtins__))))\n // https://docs.python.org/3/library/functions.html\n // https://docs.python.org/2/library/functions.html\n 'ArithmeticError,AssertionError,AttributeError,BaseException,' +\n 'BlockingIOError,BrokenPipeError,BufferError,BytesWarning,' +\n 'ChildProcessError,ConnectionAbortedError,ConnectionError,' +\n 'ConnectionRefusedError,ConnectionResetError,DeprecationWarning,EOFError,' +\n 'Ellipsis,EnvironmentError,Exception,FileExistsError,FileNotFoundError,' +\n 'FloatingPointError,FutureWarning,GeneratorExit,IOError,ImportError,' +\n 'ImportWarning,IndentationError,IndexError,InterruptedError,' +\n 'IsADirectoryError,KeyError,KeyboardInterrupt,LookupError,MemoryError,' +\n 'ModuleNotFoundError,NameError,NotADirectoryError,NotImplemented,' +\n 'NotImplementedError,OSError,OverflowError,PendingDeprecationWarning,' +\n 'PermissionError,ProcessLookupError,RecursionError,ReferenceError,' +\n 'ResourceWarning,RuntimeError,RuntimeWarning,StandardError,' +\n 'StopAsyncIteration,StopIteration,SyntaxError,SyntaxWarning,SystemError,' +\n 'SystemExit,TabError,TimeoutError,TypeError,UnboundLocalError,' +\n 'UnicodeDecodeError,UnicodeEncodeError,UnicodeError,' +\n 'UnicodeTranslateError,UnicodeWarning,UserWarning,ValueError,Warning,' +\n 'ZeroDivisionError,_,__build_class__,__debug__,__doc__,__import__,' +\n '__loader__,__name__,__package__,__spec__,abs,all,any,apply,ascii,' +\n 'basestring,bin,bool,buffer,bytearray,bytes,callable,chr,classmethod,cmp,' +\n 'coerce,compile,complex,copyright,credits,delattr,dict,dir,divmod,' +\n 'enumerate,eval,exec,execfile,exit,file,filter,float,format,frozenset,' +\n 'getattr,globals,hasattr,hash,help,hex,id,input,int,intern,isinstance,' +\n 'issubclass,iter,len,license,list,locals,long,map,max,memoryview,min,' +\n 'next,object,oct,open,ord,pow,print,property,quit,range,raw_input,reduce,' +\n 'reload,repr,reversed,round,set,setattr,slice,sorted,staticmethod,str,' +\n 'sum,super,tuple,type,unichr,unicode,vars,xrange,zip');\n\n/**\n * Order of operation ENUMs.\n * http://docs.python.org/reference/expressions.html#summary\n */\nPython.ORDER_ATOMIC = 0; // 0 \"\" ...\nPython.ORDER_COLLECTION = 1; // tuples, lists, dictionaries\nPython.ORDER_STRING_CONVERSION = 1; // `expression...`\nPython.ORDER_MEMBER = 2.1; // . []\nPython.ORDER_FUNCTION_CALL = 2.2; // ()\nPython.ORDER_EXPONENTIATION = 3; // **\nPython.ORDER_UNARY_SIGN = 4; // + -\nPython.ORDER_BITWISE_NOT = 4; // ~\nPython.ORDER_MULTIPLICATIVE = 5; // * / // %\nPython.ORDER_ADDITIVE = 6; // + -\nPython.ORDER_BITWISE_SHIFT = 7; // << >>\nPython.ORDER_BITWISE_AND = 8; // &\nPython.ORDER_BITWISE_XOR = 9; // ^\nPython.ORDER_BITWISE_OR = 10; // |\nPython.ORDER_RELATIONAL = 11; // in, not in, is, is not,\n // <, <=, >, >=, <>, !=, ==\nPython.ORDER_LOGICAL_NOT = 12; // not\nPython.ORDER_LOGICAL_AND = 13; // and\nPython.ORDER_LOGICAL_OR = 14; // or\nPython.ORDER_CONDITIONAL = 15; // if else\nPython.ORDER_LAMBDA = 16; // lambda\nPython.ORDER_NONE = 99; // (...)\n\n/**\n * List of outer-inner pairings that do NOT require parentheses.\n * @type {!Array>}\n */\nPython.ORDER_OVERRIDES = [\n // (foo()).bar -> foo().bar\n // (foo())[0] -> foo()[0]\n [Python.ORDER_FUNCTION_CALL, Python.ORDER_MEMBER],\n // (foo())() -> foo()()\n [Python.ORDER_FUNCTION_CALL, Python.ORDER_FUNCTION_CALL],\n // (foo.bar).baz -> foo.bar.baz\n // (foo.bar)[0] -> foo.bar[0]\n // (foo[0]).bar -> foo[0].bar\n // (foo[0])[1] -> foo[0][1]\n [Python.ORDER_MEMBER, Python.ORDER_MEMBER],\n // (foo.bar)() -> foo.bar()\n // (foo[0])() -> foo[0]()\n [Python.ORDER_MEMBER, Python.ORDER_FUNCTION_CALL],\n\n // not (not foo) -> not not foo\n [Python.ORDER_LOGICAL_NOT, Python.ORDER_LOGICAL_NOT],\n // a and (b and c) -> a and b and c\n [Python.ORDER_LOGICAL_AND, Python.ORDER_LOGICAL_AND],\n // a or (b or c) -> a or b or c\n [Python.ORDER_LOGICAL_OR, Python.ORDER_LOGICAL_OR]\n];\n\n/**\n * Whether the init method has been called.\n * @type {?boolean}\n */\nPython.isInitialized = false;\n\n/**\n * Initialise the database of variable names.\n * @param {!Workspace} workspace Workspace to generate code from.\n * @this {Generator}\n */\nPython.init = function(workspace) {\n // Call Blockly.Generator's init.\n Object.getPrototypeOf(this).init.call(this);\n\n /**\n * Empty loops or conditionals are not allowed in Python.\n */\n this.PASS = this.INDENT + 'pass\\n';\n\n if (!this.nameDB_) {\n this.nameDB_ = new Names(this.RESERVED_WORDS_);\n } else {\n this.nameDB_.reset();\n }\n\n this.nameDB_.setVariableMap(workspace.getVariableMap());\n this.nameDB_.populateVariables(workspace);\n this.nameDB_.populateProcedures(workspace);\n\n const defvars = [];\n // Add developer variables (not created or named by the user).\n const devVarList = Variables.allDeveloperVariables(workspace);\n for (let i = 0; i < devVarList.length; i++) {\n defvars.push(\n this.nameDB_.getName(devVarList[i], Names.DEVELOPER_VARIABLE_TYPE) +\n ' = None');\n }\n\n // Add user variables, but only ones that are being used.\n const variables = Variables.allUsedVarModels(workspace);\n for (let i = 0; i < variables.length; i++) {\n defvars.push(\n this.nameDB_.getName(variables[i].getId(), NameType.VARIABLE) +\n ' = None');\n }\n\n this.definitions_['variables'] = defvars.join('\\n');\n this.isInitialized = true;\n};\n\n/**\n * Prepend the generated code with import statements and variable definitions.\n * @param {string} code Generated code.\n * @return {string} Completed code.\n */\nPython.finish = function(code) {\n // Convert the definitions dictionary into a list.\n const imports = [];\n const definitions = [];\n for (let name in this.definitions_) {\n const def = this.definitions_[name];\n if (def.match(/^(from\\s+\\S+\\s+)?import\\s+\\S+/)) {\n imports.push(def);\n } else {\n definitions.push(def);\n }\n }\n // Call Blockly.Generator's finish.\n code = Object.getPrototypeOf(this).finish.call(this, code);\n this.isInitialized = false;\n\n this.nameDB_.reset();\n const allDefs = imports.join('\\n') + '\\n\\n' + definitions.join('\\n\\n');\n return allDefs.replace(/\\n\\n+/g, '\\n\\n').replace(/\\n*$/, '\\n\\n\\n') + code;\n};\n\n/**\n * Naked values are top-level blocks with outputs that aren't plugged into\n * anything.\n * @param {string} line Line of generated code.\n * @return {string} Legal line of code.\n */\nPython.scrubNakedValue = function(line) {\n return line + '\\n';\n};\n\n/**\n * Encode a string as a properly escaped Python string, complete with quotes.\n * @param {string} string Text to encode.\n * @return {string} Python string.\n * @protected\n */\nPython.quote_ = function(string) {\n // Can't use goog.string.quote since % must also be escaped.\n string = string.replace(/\\\\/g, '\\\\\\\\').replace(/\\n/g, '\\\\\\n');\n\n // Follow the CPython behaviour of repr() for a non-byte string.\n let quote = '\\'';\n if (string.indexOf('\\'') !== -1) {\n if (string.indexOf('\"') === -1) {\n quote = '\"';\n } else {\n string = string.replace(/'/g, '\\\\\\'');\n }\n }\n return quote + string + quote;\n};\n\n/**\n * Encode a string as a properly escaped multiline Python string, complete\n * with quotes.\n * @param {string} string Text to encode.\n * @return {string} Python string.\n * @protected\n */\nPython.multiline_quote_ = function(string) {\n const lines = string.split(/\\n/g).map(this.quote_);\n // Join with the following, plus a newline:\n // + '\\n' +\n return lines.join(' + \\'\\\\n\\' + \\n');\n};\n\n/**\n * Common tasks for generating Python from blocks.\n * Handles comments for the specified block and any connected value blocks.\n * Calls any statements following this block.\n * @param {!Block} block The current block.\n * @param {string} code The Python code created for this block.\n * @param {boolean=} opt_thisOnly True to generate code for only this statement.\n * @return {string} Python code with comments and subsequent blocks added.\n * @protected\n */\nPython.scrub_ = function(block, code, opt_thisOnly) {\n let commentCode = '';\n // Only collect comments for blocks that aren't inline.\n if (!block.outputConnection || !block.outputConnection.targetConnection) {\n // Collect comment for this block.\n let comment = block.getCommentText();\n if (comment) {\n comment = stringUtils.wrap(comment, this.COMMENT_WRAP - 3);\n commentCode += this.prefixLines(comment + '\\n', '# ');\n }\n // Collect comments for all value arguments.\n // Don't collect comments for nested statements.\n for (let i = 0; i < block.inputList.length; i++) {\n if (block.inputList[i].type === inputTypes.VALUE) {\n const childBlock = block.inputList[i].connection.targetBlock();\n if (childBlock) {\n comment = this.allNestedComments(childBlock);\n if (comment) {\n commentCode += this.prefixLines(comment, '# ');\n }\n }\n }\n }\n }\n const nextBlock = block.nextConnection && block.nextConnection.targetBlock();\n const nextCode = opt_thisOnly ? '' : this.blockToCode(nextBlock);\n return commentCode + code + nextCode;\n};\n\n/**\n * Gets a property and adjusts the value, taking into account indexing.\n * If a static int, casts to an integer, otherwise returns a code string.\n * @param {!Block} block The block.\n * @param {string} atId The property ID of the element to get.\n * @param {number=} opt_delta Value to add.\n * @param {boolean=} opt_negate Whether to negate the value.\n * @return {string|number}\n */\nPython.getAdjustedInt = function(block, atId, opt_delta, opt_negate) {\n let delta = opt_delta || 0;\n if (block.workspace.options.oneBasedIndex) {\n delta--;\n }\n const defaultAtIndex = block.workspace.options.oneBasedIndex ? '1' : '0';\n const atOrder = delta ? this.ORDER_ADDITIVE : this.ORDER_NONE;\n let at = this.valueToCode(block, atId, atOrder) || defaultAtIndex;\n\n if (stringUtils.isNumber(at)) {\n // If the index is a naked number, adjust it right now.\n at = parseInt(at, 10) + delta;\n if (opt_negate) {\n at = -at;\n }\n } else {\n // If the index is dynamic, adjust it in code.\n if (delta > 0) {\n at = 'int(' + at + ' + ' + delta + ')';\n } else if (delta < 0) {\n at = 'int(' + at + ' - ' + -delta + ')';\n } else {\n at = 'int(' + at + ')';\n }\n if (opt_negate) {\n at = '-' + at;\n }\n }\n return at;\n};\n\nexports.pythonGenerator = Python;\n","/**\n * @license\n * Copyright 2012 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * @fileoverview Generating Python for variable blocks.\n */\n'use strict';\n\ngoog.module('Blockly.Python.variables');\n\nconst {NameType} = goog.require('Blockly.Names');\nconst {pythonGenerator: Python} = goog.require('Blockly.Python');\n\n\nPython['variables_get'] = function(block) {\n // Variable getter.\n const code =\n Python.nameDB_.getName(block.getFieldValue('VAR'), NameType.VARIABLE);\n return [code, Python.ORDER_ATOMIC];\n};\n\nPython['variables_set'] = function(block) {\n // Variable setter.\n const argument0 =\n Python.valueToCode(block, 'VALUE', Python.ORDER_NONE) || '0';\n const varName =\n Python.nameDB_.getName(block.getFieldValue('VAR'), NameType.VARIABLE);\n return varName + ' = ' + argument0 + '\\n';\n};\n","/**\n * @license\n * Copyright 2018 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * @fileoverview Generating Python for dynamic variable blocks.\n */\n'use strict';\n\ngoog.module('Blockly.Python.variablesDynamic');\n\nconst {pythonGenerator: Python} = goog.require('Blockly.Python');\n/** @suppress {extraRequire} */\ngoog.require('Blockly.Python.variables');\n\n\n// Python is dynamically typed.\nPython['variables_get_dynamic'] = Python['variables_get'];\nPython['variables_set_dynamic'] = Python['variables_set'];\n","/**\n * @license\n * Copyright 2012 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * @fileoverview Generating Python for text blocks.\n */\n'use strict';\n\ngoog.module('Blockly.Python.texts');\n\nconst stringUtils = goog.require('Blockly.utils.string');\nconst {NameType} = goog.require('Blockly.Names');\nconst {pythonGenerator: Python} = goog.require('Blockly.Python');\n\n\nPython['text'] = function(block) {\n // Text value.\n const code = Python.quote_(block.getFieldValue('TEXT'));\n return [code, Python.ORDER_ATOMIC];\n};\n\nPython['text_multiline'] = function(block) {\n // Text value.\n const code = Python.multiline_quote_(block.getFieldValue('TEXT'));\n const order =\n code.indexOf('+') !== -1 ? Python.ORDER_ADDITIVE : Python.ORDER_ATOMIC;\n return [code, order];\n};\n\n/**\n * Regular expression to detect a single-quoted string literal.\n */\nconst strRegExp = /^\\s*'([^']|\\\\')*'\\s*$/;\n\n/**\n * Enclose the provided value in 'str(...)' function.\n * Leave string literals alone.\n * @param {string} value Code evaluating to a value.\n * @return {Array} Array containing code evaluating to a string\n * and\n * the order of the returned code.[string, number]\n */\nconst forceString = function(value) {\n if (strRegExp.test(value)) {\n return [value, Python.ORDER_ATOMIC];\n }\n return ['str(' + value + ')', Python.ORDER_FUNCTION_CALL];\n};\n\nPython['text_join'] = function(block) {\n // Create a string made up of any number of elements of any type.\n // Should we allow joining by '-' or ',' or any other characters?\n switch (block.itemCount_) {\n case 0:\n return [\"''\", Python.ORDER_ATOMIC];\n case 1: {\n const element =\n Python.valueToCode(block, 'ADD0', Python.ORDER_NONE) || \"''\";\n const codeAndOrder = forceString(element);\n return codeAndOrder;\n }\n case 2: {\n const element0 =\n Python.valueToCode(block, 'ADD0', Python.ORDER_NONE) || \"''\";\n const element1 =\n Python.valueToCode(block, 'ADD1', Python.ORDER_NONE) || \"''\";\n const code = forceString(element0)[0] + ' + ' + forceString(element1)[0];\n return [code, Python.ORDER_ADDITIVE];\n }\n default: {\n const elements = [];\n for (let i = 0; i < block.itemCount_; i++) {\n elements[i] =\n Python.valueToCode(block, 'ADD' + i, Python.ORDER_NONE) || \"''\";\n }\n const tempVar = Python.nameDB_.getDistinctName('x', NameType.VARIABLE);\n const code = '\\'\\'.join([str(' + tempVar + ') for ' + tempVar + ' in [' +\n elements.join(', ') + ']])';\n return [code, Python.ORDER_FUNCTION_CALL];\n }\n }\n};\n\nPython['text_append'] = function(block) {\n // Append to a variable in place.\n const varName =\n Python.nameDB_.getName(block.getFieldValue('VAR'), NameType.VARIABLE);\n const value = Python.valueToCode(block, 'TEXT', Python.ORDER_NONE) || \"''\";\n return varName + ' = str(' + varName + ') + ' + forceString(value)[0] + '\\n';\n};\n\nPython['text_length'] = function(block) {\n // Is the string null or array empty?\n const text = Python.valueToCode(block, 'VALUE', Python.ORDER_NONE) || \"''\";\n return ['len(' + text + ')', Python.ORDER_FUNCTION_CALL];\n};\n\nPython['text_isEmpty'] = function(block) {\n // Is the string null or array empty?\n const text = Python.valueToCode(block, 'VALUE', Python.ORDER_NONE) || \"''\";\n const code = 'not len(' + text + ')';\n return [code, Python.ORDER_LOGICAL_NOT];\n};\n\nPython['text_indexOf'] = function(block) {\n // Search the text for a substring.\n // Should we allow for non-case sensitive???\n const operator = block.getFieldValue('END') === 'FIRST' ? 'find' : 'rfind';\n const substring =\n Python.valueToCode(block, 'FIND', Python.ORDER_NONE) || \"''\";\n const text =\n Python.valueToCode(block, 'VALUE', Python.ORDER_MEMBER) || \"''\";\n const code = text + '.' + operator + '(' + substring + ')';\n if (block.workspace.options.oneBasedIndex) {\n return [code + ' + 1', Python.ORDER_ADDITIVE];\n }\n return [code, Python.ORDER_FUNCTION_CALL];\n};\n\nPython['text_charAt'] = function(block) {\n // Get letter at index.\n // Note: Until January 2013 this block did not have the WHERE input.\n const where = block.getFieldValue('WHERE') || 'FROM_START';\n const textOrder =\n (where === 'RANDOM') ? Python.ORDER_NONE : Python.ORDER_MEMBER;\n const text = Python.valueToCode(block, 'VALUE', textOrder) || \"''\";\n switch (where) {\n case 'FIRST': {\n const code = text + '[0]';\n return [code, Python.ORDER_MEMBER];\n }\n case 'LAST': {\n const code = text + '[-1]';\n return [code, Python.ORDER_MEMBER];\n }\n case 'FROM_START': {\n const at = Python.getAdjustedInt(block, 'AT');\n const code = text + '[' + at + ']';\n return [code, Python.ORDER_MEMBER];\n }\n case 'FROM_END': {\n const at = Python.getAdjustedInt(block, 'AT', 1, true);\n const code = text + '[' + at + ']';\n return [code, Python.ORDER_MEMBER];\n }\n case 'RANDOM': {\n Python.definitions_['import_random'] = 'import random';\n const functionName = Python.provideFunction_('text_random_letter', `\ndef ${Python.FUNCTION_NAME_PLACEHOLDER_}(text):\n x = int(random.random() * len(text))\n return text[x]\n`);\n const code = functionName + '(' + text + ')';\n return [code, Python.ORDER_FUNCTION_CALL];\n }\n }\n throw Error('Unhandled option (text_charAt).');\n};\n\nPython['text_getSubstring'] = function(block) {\n // Get substring.\n const where1 = block.getFieldValue('WHERE1');\n const where2 = block.getFieldValue('WHERE2');\n const text =\n Python.valueToCode(block, 'STRING', Python.ORDER_MEMBER) || \"''\";\n let at1;\n switch (where1) {\n case 'FROM_START':\n at1 = Python.getAdjustedInt(block, 'AT1');\n if (at1 === 0) {\n at1 = '';\n }\n break;\n case 'FROM_END':\n at1 = Python.getAdjustedInt(block, 'AT1', 1, true);\n break;\n case 'FIRST':\n at1 = '';\n break;\n default:\n throw Error('Unhandled option (text_getSubstring)');\n }\n\n let at2;\n switch (where2) {\n case 'FROM_START':\n at2 = Python.getAdjustedInt(block, 'AT2', 1);\n break;\n case 'FROM_END':\n at2 = Python.getAdjustedInt(block, 'AT2', 0, true);\n // Ensure that if the result calculated is 0 that sub-sequence will\n // include all elements as expected.\n if (!stringUtils.isNumber(String(at2))) {\n Python.definitions_['import_sys'] = 'import sys';\n at2 += ' or sys.maxsize';\n } else if (at2 === 0) {\n at2 = '';\n }\n break;\n case 'LAST':\n at2 = '';\n break;\n default:\n throw Error('Unhandled option (text_getSubstring)');\n }\n const code = text + '[' + at1 + ' : ' + at2 + ']';\n return [code, Python.ORDER_MEMBER];\n};\n\nPython['text_changeCase'] = function(block) {\n // Change capitalization.\n const OPERATORS = {\n 'UPPERCASE': '.upper()',\n 'LOWERCASE': '.lower()',\n 'TITLECASE': '.title()'\n };\n const operator = OPERATORS[block.getFieldValue('CASE')];\n const text = Python.valueToCode(block, 'TEXT', Python.ORDER_MEMBER) || \"''\";\n const code = text + operator;\n return [code, Python.ORDER_FUNCTION_CALL];\n};\n\nPython['text_trim'] = function(block) {\n // Trim spaces.\n const OPERATORS = {\n 'LEFT': '.lstrip()',\n 'RIGHT': '.rstrip()',\n 'BOTH': '.strip()'\n };\n const operator = OPERATORS[block.getFieldValue('MODE')];\n const text = Python.valueToCode(block, 'TEXT', Python.ORDER_MEMBER) || \"''\";\n const code = text + operator;\n return [code, Python.ORDER_FUNCTION_CALL];\n};\n\nPython['text_print'] = function(block) {\n // Print statement.\n const msg = Python.valueToCode(block, 'TEXT', Python.ORDER_NONE) || \"''\";\n return 'print(' + msg + ')\\n';\n};\n\nPython['text_prompt_ext'] = function(block) {\n // Prompt function.\n const functionName = Python.provideFunction_('text_prompt', `\ndef ${Python.FUNCTION_NAME_PLACEHOLDER_}(msg):\n try:\n return raw_input(msg)\n except NameError:\n return input(msg)\n`);\n let msg;\n if (block.getField('TEXT')) {\n // Internal message.\n msg = Python.quote_(block.getFieldValue('TEXT'));\n } else {\n // External message.\n msg = Python.valueToCode(block, 'TEXT', Python.ORDER_NONE) || \"''\";\n }\n let code = functionName + '(' + msg + ')';\n const toNumber = block.getFieldValue('TYPE') === 'NUMBER';\n if (toNumber) {\n code = 'float(' + code + ')';\n }\n return [code, Python.ORDER_FUNCTION_CALL];\n};\n\nPython['text_prompt'] = Python['text_prompt_ext'];\n\nPython['text_count'] = function(block) {\n const text = Python.valueToCode(block, 'TEXT', Python.ORDER_MEMBER) || \"''\";\n const sub = Python.valueToCode(block, 'SUB', Python.ORDER_NONE) || \"''\";\n const code = text + '.count(' + sub + ')';\n return [code, Python.ORDER_FUNCTION_CALL];\n};\n\nPython['text_replace'] = function(block) {\n const text = Python.valueToCode(block, 'TEXT', Python.ORDER_MEMBER) || \"''\";\n const from = Python.valueToCode(block, 'FROM', Python.ORDER_NONE) || \"''\";\n const to = Python.valueToCode(block, 'TO', Python.ORDER_NONE) || \"''\";\n const code = text + '.replace(' + from + ', ' + to + ')';\n return [code, Python.ORDER_MEMBER];\n};\n\nPython['text_reverse'] = function(block) {\n const text = Python.valueToCode(block, 'TEXT', Python.ORDER_MEMBER) || \"''\";\n const code = text + '[::-1]';\n return [code, Python.ORDER_MEMBER];\n};\n","/**\n * @license\n * Copyright 2012 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * @fileoverview Generating Python for procedure blocks.\n */\n'use strict';\n\ngoog.module('Blockly.Python.procedures');\n\nconst Variables = goog.require('Blockly.Variables');\nconst {NameType} = goog.require('Blockly.Names');\nconst {pythonGenerator: Python} = goog.require('Blockly.Python');\n\n\nPython['procedures_defreturn'] = function(block) {\n // Define a procedure with a return value.\n // First, add a 'global' statement for every variable that is not shadowed by\n // a local parameter.\n const globals = [];\n const workspace = block.workspace;\n const usedVariables = Variables.allUsedVarModels(workspace) || [];\n for (let i = 0, variable; (variable = usedVariables[i]); i++) {\n const varName = variable.name;\n if (block.getVars().indexOf(varName) === -1) {\n globals.push(Python.nameDB_.getName(varName, NameType.VARIABLE));\n }\n }\n // Add developer variables.\n const devVarList = Variables.allDeveloperVariables(workspace);\n for (let i = 0; i < devVarList.length; i++) {\n globals.push(\n Python.nameDB_.getName(devVarList[i], NameType.DEVELOPER_VARIABLE));\n }\n\n const globalString = globals.length ?\n Python.INDENT + 'global ' + globals.join(', ') + '\\n' :\n '';\n const funcName =\n Python.nameDB_.getName(block.getFieldValue('NAME'), NameType.PROCEDURE);\n let xfix1 = '';\n if (Python.STATEMENT_PREFIX) {\n xfix1 += Python.injectId(Python.STATEMENT_PREFIX, block);\n }\n if (Python.STATEMENT_SUFFIX) {\n xfix1 += Python.injectId(Python.STATEMENT_SUFFIX, block);\n }\n if (xfix1) {\n xfix1 = Python.prefixLines(xfix1, Python.INDENT);\n }\n let loopTrap = '';\n if (Python.INFINITE_LOOP_TRAP) {\n loopTrap = Python.prefixLines(\n Python.injectId(Python.INFINITE_LOOP_TRAP, block), Python.INDENT);\n }\n let branch = Python.statementToCode(block, 'STACK');\n let returnValue =\n Python.valueToCode(block, 'RETURN', Python.ORDER_NONE) || '';\n let xfix2 = '';\n if (branch && returnValue) {\n // After executing the function body, revisit this block for the return.\n xfix2 = xfix1;\n }\n if (returnValue) {\n returnValue = Python.INDENT + 'return ' + returnValue + '\\n';\n } else if (!branch) {\n branch = Python.PASS;\n }\n const args = [];\n const variables = block.getVars();\n for (let i = 0; i < variables.length; i++) {\n args[i] = Python.nameDB_.getName(variables[i], NameType.VARIABLE);\n }\n let code = 'def ' + funcName + '(' + args.join(', ') + '):\\n' + globalString +\n xfix1 + loopTrap + branch + xfix2 + returnValue;\n code = Python.scrub_(block, code);\n // Add % so as not to collide with helper functions in definitions list.\n Python.definitions_['%' + funcName] = code;\n return null;\n};\n\n// Defining a procedure without a return value uses the same generator as\n// a procedure with a return value.\nPython['procedures_defnoreturn'] = Python['procedures_defreturn'];\n\nPython['procedures_callreturn'] = function(block) {\n // Call a procedure with a return value.\n const funcName =\n Python.nameDB_.getName(block.getFieldValue('NAME'), NameType.PROCEDURE);\n const args = [];\n const variables = block.getVars();\n for (let i = 0; i < variables.length; i++) {\n args[i] = Python.valueToCode(block, 'ARG' + i, Python.ORDER_NONE) || 'None';\n }\n const code = funcName + '(' + args.join(', ') + ')';\n return [code, Python.ORDER_FUNCTION_CALL];\n};\n\nPython['procedures_callnoreturn'] = function(block) {\n // Call a procedure with no return value.\n // Generated code is for a function call as a statement is the same as a\n // function call as a value, with the addition of line ending.\n const tuple = Python['procedures_callreturn'](block);\n return tuple[0] + '\\n';\n};\n\nPython['procedures_ifreturn'] = function(block) {\n // Conditionally return value from a procedure.\n const condition =\n Python.valueToCode(block, 'CONDITION', Python.ORDER_NONE) || 'False';\n let code = 'if ' + condition + ':\\n';\n if (Python.STATEMENT_SUFFIX) {\n // Inject any statement suffix here since the regular one at the end\n // will not get executed if the return is triggered.\n code += Python.prefixLines(\n Python.injectId(Python.STATEMENT_SUFFIX, block), Python.INDENT);\n }\n if (block.hasReturnValue_) {\n const value =\n Python.valueToCode(block, 'VALUE', Python.ORDER_NONE) || 'None';\n code += Python.INDENT + 'return ' + value + '\\n';\n } else {\n code += Python.INDENT + 'return\\n';\n }\n return code;\n};\n","/**\n * @license\n * Copyright 2012 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * @fileoverview Generating Python for math blocks.\n */\n'use strict';\n\ngoog.module('Blockly.Python.math');\n\nconst {NameType} = goog.require('Blockly.Names');\nconst {pythonGenerator: Python} = goog.require('Blockly.Python');\n\n\n// If any new block imports any library, add that library name here.\nPython.addReservedWords('math,random,Number');\n\nPython['math_number'] = function(block) {\n // Numeric value.\n let code = Number(block.getFieldValue('NUM'));\n let order;\n if (code === Infinity) {\n code = 'float(\"inf\")';\n order = Python.ORDER_FUNCTION_CALL;\n } else if (code === -Infinity) {\n code = '-float(\"inf\")';\n order = Python.ORDER_UNARY_SIGN;\n } else {\n order = code < 0 ? Python.ORDER_UNARY_SIGN : Python.ORDER_ATOMIC;\n }\n return [code, order];\n};\n\nPython['math_arithmetic'] = function(block) {\n // Basic arithmetic operators, and power.\n const OPERATORS = {\n 'ADD': [' + ', Python.ORDER_ADDITIVE],\n 'MINUS': [' - ', Python.ORDER_ADDITIVE],\n 'MULTIPLY': [' * ', Python.ORDER_MULTIPLICATIVE],\n 'DIVIDE': [' / ', Python.ORDER_MULTIPLICATIVE],\n 'POWER': [' ** ', Python.ORDER_EXPONENTIATION],\n };\n const tuple = OPERATORS[block.getFieldValue('OP')];\n const operator = tuple[0];\n const order = tuple[1];\n const argument0 = Python.valueToCode(block, 'A', order) || '0';\n const argument1 = Python.valueToCode(block, 'B', order) || '0';\n const code = argument0 + operator + argument1;\n return [code, order];\n // In case of 'DIVIDE', division between integers returns different results\n // in Python 2 and 3. However, is not an issue since Blockly does not\n // guarantee identical results in all languages. To do otherwise would\n // require every operator to be wrapped in a function call. This would kill\n // legibility of the generated code.\n};\n\nPython['math_single'] = function(block) {\n // Math operators with single operand.\n const operator = block.getFieldValue('OP');\n let code;\n let arg;\n if (operator === 'NEG') {\n // Negation is a special case given its different operator precedence.\n code = Python.valueToCode(block, 'NUM', Python.ORDER_UNARY_SIGN) || '0';\n return ['-' + code, Python.ORDER_UNARY_SIGN];\n }\n Python.definitions_['import_math'] = 'import math';\n if (operator === 'SIN' || operator === 'COS' || operator === 'TAN') {\n arg = Python.valueToCode(block, 'NUM', Python.ORDER_MULTIPLICATIVE) || '0';\n } else {\n arg = Python.valueToCode(block, 'NUM', Python.ORDER_NONE) || '0';\n }\n // First, handle cases which generate values that don't need parentheses\n // wrapping the code.\n switch (operator) {\n case 'ABS':\n code = 'math.fabs(' + arg + ')';\n break;\n case 'ROOT':\n code = 'math.sqrt(' + arg + ')';\n break;\n case 'LN':\n code = 'math.log(' + arg + ')';\n break;\n case 'LOG10':\n code = 'math.log10(' + arg + ')';\n break;\n case 'EXP':\n code = 'math.exp(' + arg + ')';\n break;\n case 'POW10':\n code = 'math.pow(10,' + arg + ')';\n break;\n case 'ROUND':\n code = 'round(' + arg + ')';\n break;\n case 'ROUNDUP':\n code = 'math.ceil(' + arg + ')';\n break;\n case 'ROUNDDOWN':\n code = 'math.floor(' + arg + ')';\n break;\n case 'SIN':\n code = 'math.sin(' + arg + ' / 180.0 * math.pi)';\n break;\n case 'COS':\n code = 'math.cos(' + arg + ' / 180.0 * math.pi)';\n break;\n case 'TAN':\n code = 'math.tan(' + arg + ' / 180.0 * math.pi)';\n break;\n }\n if (code) {\n return [code, Python.ORDER_FUNCTION_CALL];\n }\n // Second, handle cases which generate values that may need parentheses\n // wrapping the code.\n switch (operator) {\n case 'ASIN':\n code = 'math.asin(' + arg + ') / math.pi * 180';\n break;\n case 'ACOS':\n code = 'math.acos(' + arg + ') / math.pi * 180';\n break;\n case 'ATAN':\n code = 'math.atan(' + arg + ') / math.pi * 180';\n break;\n default:\n throw Error('Unknown math operator: ' + operator);\n }\n return [code, Python.ORDER_MULTIPLICATIVE];\n};\n\nPython['math_constant'] = function(block) {\n // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY.\n const CONSTANTS = {\n 'PI': ['math.pi', Python.ORDER_MEMBER],\n 'E': ['math.e', Python.ORDER_MEMBER],\n 'GOLDEN_RATIO': ['(1 + math.sqrt(5)) / 2', Python.ORDER_MULTIPLICATIVE],\n 'SQRT2': ['math.sqrt(2)', Python.ORDER_MEMBER],\n 'SQRT1_2': ['math.sqrt(1.0 / 2)', Python.ORDER_MEMBER],\n 'INFINITY': ['float(\\'inf\\')', Python.ORDER_ATOMIC],\n };\n const constant = block.getFieldValue('CONSTANT');\n if (constant !== 'INFINITY') {\n Python.definitions_['import_math'] = 'import math';\n }\n return CONSTANTS[constant];\n};\n\nPython['math_number_property'] = function(block) {\n // Check if a number is even, odd, prime, whole, positive, or negative\n // or if it is divisible by certain number. Returns true or false.\n const PROPERTIES = {\n 'EVEN': [' % 2 == 0', Python.ORDER_MULTIPLICATIVE, Python.ORDER_RELATIONAL],\n 'ODD': [' % 2 == 1', Python.ORDER_MULTIPLICATIVE, Python.ORDER_RELATIONAL],\n 'WHOLE': [' % 1 == 0', Python.ORDER_MULTIPLICATIVE,\n Python.ORDER_RELATIONAL],\n 'POSITIVE': [' > 0', Python.ORDER_RELATIONAL, Python.ORDER_RELATIONAL],\n 'NEGATIVE': [' < 0', Python.ORDER_RELATIONAL, Python.ORDER_RELATIONAL],\n 'DIVISIBLE_BY': [null, Python.ORDER_MULTIPLICATIVE,\n Python.ORDER_RELATIONAL],\n 'PRIME': [null, Python.ORDER_NONE, Python.ORDER_FUNCTION_CALL],\n }\n const dropdownProperty = block.getFieldValue('PROPERTY');\n const [suffix, inputOrder, outputOrder] = PROPERTIES[dropdownProperty];\n const numberToCheck = Python.valueToCode(block, 'NUMBER_TO_CHECK',\n inputOrder) || '0';\n let code;\n if (dropdownProperty === 'PRIME') {\n // Prime is a special case as it is not a one-liner test.\n Python.definitions_['import_math'] = 'import math';\n Python.definitions_['from_numbers_import_Number'] =\n 'from numbers import Number';\n const functionName = Python.provideFunction_('math_isPrime', `\ndef ${Python.FUNCTION_NAME_PLACEHOLDER_}(n):\n # https://en.wikipedia.org/wiki/Primality_test#Naive_methods\n # If n is not a number but a string, try parsing it.\n if not isinstance(n, Number):\n try:\n n = float(n)\n except:\n return False\n if n == 2 or n == 3:\n return True\n # False if n is negative, is 1, or not whole, or if n is divisible by 2 or 3.\n if n <= 1 or n % 1 != 0 or n % 2 == 0 or n % 3 == 0:\n return False\n # Check all the numbers of form 6k +/- 1, up to sqrt(n).\n for x in range(6, int(math.sqrt(n)) + 2, 6):\n if n % (x - 1) == 0 or n % (x + 1) == 0:\n return False\n return True\n`);\n code = functionName + '(' + numberToCheck + ')';\n } else if (dropdownProperty === 'DIVISIBLE_BY') {\n const divisor = Python.valueToCode(block, 'DIVISOR',\n Python.ORDER_MULTIPLICATIVE) || '0';\n // If 'divisor' is some code that evals to 0, Python will raise an error.\n if (divisor === '0') {\n return ['False', Python.ORDER_ATOMIC];\n }\n code = numberToCheck + ' % ' + divisor + ' == 0';\n } else {\n code = numberToCheck + suffix;\n };\n return [code, outputOrder];\n};\n\nPython['math_change'] = function(block) {\n // Add to a variable in place.\n Python.definitions_['from_numbers_import_Number'] =\n 'from numbers import Number';\n const argument0 =\n Python.valueToCode(block, 'DELTA', Python.ORDER_ADDITIVE) || '0';\n const varName =\n Python.nameDB_.getName(block.getFieldValue('VAR'), NameType.VARIABLE);\n return varName + ' = (' + varName + ' if isinstance(' + varName +\n ', Number) else 0) + ' + argument0 + '\\n';\n};\n\n// Rounding functions have a single operand.\nPython['math_round'] = Python['math_single'];\n// Trigonometry functions have a single operand.\nPython['math_trig'] = Python['math_single'];\n\nPython['math_on_list'] = function(block) {\n // Math functions for lists.\n const func = block.getFieldValue('OP');\n const list = Python.valueToCode(block, 'LIST', Python.ORDER_NONE) || '[]';\n let code;\n switch (func) {\n case 'SUM':\n code = 'sum(' + list + ')';\n break;\n case 'MIN':\n code = 'min(' + list + ')';\n break;\n case 'MAX':\n code = 'max(' + list + ')';\n break;\n case 'AVERAGE': {\n Python.definitions_['from_numbers_import_Number'] =\n 'from numbers import Number';\n // This operation excludes null and values that aren't int or float:\n // math_mean([null, null, \"aString\", 1, 9]) -> 5.0\n const functionName = Python.provideFunction_('math_mean', `\ndef ${Python.FUNCTION_NAME_PLACEHOLDER_}(myList):\n localList = [e for e in myList if isinstance(e, Number)]\n if not localList: return\n return float(sum(localList)) / len(localList)\n`);\n code = functionName + '(' + list + ')';\n break;\n }\n case 'MEDIAN': {\n Python.definitions_['from_numbers_import_Number'] =\n 'from numbers import Number';\n // This operation excludes null values:\n // math_median([null, null, 1, 3]) -> 2.0\n const functionName = Python.provideFunction_( 'math_median', `\ndef ${Python.FUNCTION_NAME_PLACEHOLDER_}(myList):\n localList = sorted([e for e in myList if isinstance(e, Number)])\n if not localList: return\n if len(localList) % 2 == 0:\n return (localList[len(localList) // 2 - 1] + localList[len(localList) // 2]) / 2.0\n else:\n return localList[(len(localList) - 1) // 2]\n`);\n code = functionName + '(' + list + ')';\n break;\n }\n case 'MODE': {\n // As a list of numbers can contain more than one mode,\n // the returned result is provided as an array.\n // Mode of [3, 'x', 'x', 1, 1, 2, '3'] -> ['x', 1]\n const functionName = Python.provideFunction_('math_modes', `\ndef ${Python.FUNCTION_NAME_PLACEHOLDER_}(some_list):\n modes = []\n # Using a lists of [item, count] to keep count rather than dict\n # to avoid \"unhashable\" errors when the counted item is itself a list or dict.\n counts = []\n maxCount = 1\n for item in some_list:\n found = False\n for count in counts:\n if count[0] == item:\n count[1] += 1\n maxCount = max(maxCount, count[1])\n found = True\n if not found:\n counts.append([item, 1])\n for counted_item, item_count in counts:\n if item_count == maxCount:\n modes.append(counted_item)\n return modes\n`);\n code = functionName + '(' + list + ')';\n break;\n }\n case 'STD_DEV': {\n Python.definitions_['import_math'] = 'import math';\n const functionName = Python.provideFunction_('math_standard_deviation', `\ndef ${Python.FUNCTION_NAME_PLACEHOLDER_}(numbers):\n n = len(numbers)\n if n == 0: return\n mean = float(sum(numbers)) / n\n variance = sum((x - mean) ** 2 for x in numbers) / n\n return math.sqrt(variance)\n`);\n code = functionName + '(' + list + ')';\n break;\n }\n case 'RANDOM':\n Python.definitions_['import_random'] = 'import random';\n code = 'random.choice(' + list + ')';\n break;\n default:\n throw Error('Unknown operator: ' + func);\n }\n return [code, Python.ORDER_FUNCTION_CALL];\n};\n\nPython['math_modulo'] = function(block) {\n // Remainder computation.\n const argument0 =\n Python.valueToCode(block, 'DIVIDEND', Python.ORDER_MULTIPLICATIVE) || '0';\n const argument1 =\n Python.valueToCode(block, 'DIVISOR', Python.ORDER_MULTIPLICATIVE) || '0';\n const code = argument0 + ' % ' + argument1;\n return [code, Python.ORDER_MULTIPLICATIVE];\n};\n\nPython['math_constrain'] = function(block) {\n // Constrain a number between two limits.\n const argument0 =\n Python.valueToCode(block, 'VALUE', Python.ORDER_NONE) || '0';\n const argument1 = Python.valueToCode(block, 'LOW', Python.ORDER_NONE) || '0';\n const argument2 =\n Python.valueToCode(block, 'HIGH', Python.ORDER_NONE) || 'float(\\'inf\\')';\n const code =\n 'min(max(' + argument0 + ', ' + argument1 + '), ' + argument2 + ')';\n return [code, Python.ORDER_FUNCTION_CALL];\n};\n\nPython['math_random_int'] = function(block) {\n // Random integer between [X] and [Y].\n Python.definitions_['import_random'] = 'import random';\n const argument0 = Python.valueToCode(block, 'FROM', Python.ORDER_NONE) || '0';\n const argument1 = Python.valueToCode(block, 'TO', Python.ORDER_NONE) || '0';\n const code = 'random.randint(' + argument0 + ', ' + argument1 + ')';\n return [code, Python.ORDER_FUNCTION_CALL];\n};\n\nPython['math_random_float'] = function(block) {\n // Random fraction between 0 and 1.\n Python.definitions_['import_random'] = 'import random';\n return ['random.random()', Python.ORDER_FUNCTION_CALL];\n};\n\nPython['math_atan2'] = function(block) {\n // Arctangent of point (X, Y) in degrees from -180 to 180.\n Python.definitions_['import_math'] = 'import math';\n const argument0 = Python.valueToCode(block, 'X', Python.ORDER_NONE) || '0';\n const argument1 = Python.valueToCode(block, 'Y', Python.ORDER_NONE) || '0';\n return [\n 'math.atan2(' + argument1 + ', ' + argument0 + ') / math.pi * 180',\n Python.ORDER_MULTIPLICATIVE\n ];\n};\n","/**\n * @license\n * Copyright 2012 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * @fileoverview Generating Python for loop blocks.\n */\n'use strict';\n\ngoog.module('Blockly.Python.loops');\n\nconst stringUtils = goog.require('Blockly.utils.string');\nconst {NameType} = goog.require('Blockly.Names');\nconst {pythonGenerator: Python} = goog.require('Blockly.Python');\n\n\nPython['controls_repeat_ext'] = function(block) {\n // Repeat n times.\n let repeats;\n if (block.getField('TIMES')) {\n // Internal number.\n repeats = String(parseInt(block.getFieldValue('TIMES'), 10));\n } else {\n // External number.\n repeats = Python.valueToCode(block, 'TIMES', Python.ORDER_NONE) || '0';\n }\n if (stringUtils.isNumber(repeats)) {\n repeats = parseInt(repeats, 10);\n } else {\n repeats = 'int(' + repeats + ')';\n }\n let branch = Python.statementToCode(block, 'DO');\n branch = Python.addLoopTrap(branch, block) || Python.PASS;\n const loopVar = Python.nameDB_.getDistinctName('count', NameType.VARIABLE);\n const code = 'for ' + loopVar + ' in range(' + repeats + '):\\n' + branch;\n return code;\n};\n\nPython['controls_repeat'] = Python['controls_repeat_ext'];\n\nPython['controls_whileUntil'] = function(block) {\n // Do while/until loop.\n const until = block.getFieldValue('MODE') === 'UNTIL';\n let argument0 = Python.valueToCode(\n block, 'BOOL',\n until ? Python.ORDER_LOGICAL_NOT : Python.ORDER_NONE) ||\n 'False';\n let branch = Python.statementToCode(block, 'DO');\n branch = Python.addLoopTrap(branch, block) || Python.PASS;\n if (until) {\n argument0 = 'not ' + argument0;\n }\n return 'while ' + argument0 + ':\\n' + branch;\n};\n\nPython['controls_for'] = function(block) {\n // For loop.\n const variable0 =\n Python.nameDB_.getName(block.getFieldValue('VAR'), NameType.VARIABLE);\n let argument0 = Python.valueToCode(block, 'FROM', Python.ORDER_NONE) || '0';\n let argument1 = Python.valueToCode(block, 'TO', Python.ORDER_NONE) || '0';\n let increment = Python.valueToCode(block, 'BY', Python.ORDER_NONE) || '1';\n let branch = Python.statementToCode(block, 'DO');\n branch = Python.addLoopTrap(branch, block) || Python.PASS;\n\n let code = '';\n let range;\n\n // Helper functions.\n const defineUpRange = function() {\n return Python.provideFunction_('upRange', `\ndef ${Python.FUNCTION_NAME_PLACEHOLDER_}(start, stop, step):\n while start <= stop:\n yield start\n start += abs(step)\n`);\n };\n const defineDownRange = function() {\n return Python.provideFunction_('downRange', `\ndef ${Python.FUNCTION_NAME_PLACEHOLDER_}(start, stop, step):\n while start >= stop:\n yield start\n start -= abs(step)\n`);\n };\n // Arguments are legal Python code (numbers or strings returned by scrub()).\n const generateUpDownRange = function(start, end, inc) {\n return '(' + start + ' <= ' + end + ') and ' + defineUpRange() + '(' +\n start + ', ' + end + ', ' + inc + ') or ' + defineDownRange() + '(' +\n start + ', ' + end + ', ' + inc + ')';\n };\n\n if (stringUtils.isNumber(argument0) && stringUtils.isNumber(argument1) &&\n stringUtils.isNumber(increment)) {\n // All parameters are simple numbers.\n argument0 = Number(argument0);\n argument1 = Number(argument1);\n increment = Math.abs(Number(increment));\n if (argument0 % 1 === 0 && argument1 % 1 === 0 && increment % 1 === 0) {\n // All parameters are integers.\n if (argument0 <= argument1) {\n // Count up.\n argument1++;\n if (argument0 === 0 && increment === 1) {\n // If starting index is 0, omit it.\n range = argument1;\n } else {\n range = argument0 + ', ' + argument1;\n }\n // If increment isn't 1, it must be explicit.\n if (increment !== 1) {\n range += ', ' + increment;\n }\n } else {\n // Count down.\n argument1--;\n range = argument0 + ', ' + argument1 + ', -' + increment;\n }\n range = 'range(' + range + ')';\n } else {\n // At least one of the parameters is not an integer.\n if (argument0 < argument1) {\n range = defineUpRange();\n } else {\n range = defineDownRange();\n }\n range += '(' + argument0 + ', ' + argument1 + ', ' + increment + ')';\n }\n } else {\n // Cache non-trivial values to variables to prevent repeated look-ups.\n const scrub = function(arg, suffix) {\n if (stringUtils.isNumber(arg)) {\n // Simple number.\n arg = Number(arg);\n } else if (!arg.match(/^\\w+$/)) {\n // Not a variable, it's complicated.\n const varName = Python.nameDB_.getDistinctName(\n variable0 + suffix, NameType.VARIABLE);\n code += varName + ' = ' + arg + '\\n';\n arg = varName;\n }\n return arg;\n };\n const startVar = scrub(argument0, '_start');\n const endVar = scrub(argument1, '_end');\n const incVar = scrub(increment, '_inc');\n\n if (typeof startVar === 'number' && typeof endVar === 'number') {\n if (startVar < endVar) {\n range = defineUpRange();\n } else {\n range = defineDownRange();\n }\n range += '(' + startVar + ', ' + endVar + ', ' + incVar + ')';\n } else {\n // We cannot determine direction statically.\n range = generateUpDownRange(startVar, endVar, incVar);\n }\n }\n code += 'for ' + variable0 + ' in ' + range + ':\\n' + branch;\n return code;\n};\n\nPython['controls_forEach'] = function(block) {\n // For each loop.\n const variable0 =\n Python.nameDB_.getName(block.getFieldValue('VAR'), NameType.VARIABLE);\n const argument0 =\n Python.valueToCode(block, 'LIST', Python.ORDER_RELATIONAL) || '[]';\n let branch = Python.statementToCode(block, 'DO');\n branch = Python.addLoopTrap(branch, block) || Python.PASS;\n const code = 'for ' + variable0 + ' in ' + argument0 + ':\\n' + branch;\n return code;\n};\n\nPython['controls_flow_statements'] = function(block) {\n // Flow statements: continue, break.\n let xfix = '';\n if (Python.STATEMENT_PREFIX) {\n // Automatic prefix insertion is switched off for this block. Add manually.\n xfix += Python.injectId(Python.STATEMENT_PREFIX, block);\n }\n if (Python.STATEMENT_SUFFIX) {\n // Inject any statement suffix here since the regular one at the end\n // will not get executed if the break/continue is triggered.\n xfix += Python.injectId(Python.STATEMENT_SUFFIX, block);\n }\n if (Python.STATEMENT_PREFIX) {\n const loop = block.getSurroundLoop();\n if (loop && !loop.suppressPrefixSuffix) {\n // Inject loop's statement prefix here since the regular one at the end\n // of the loop will not get executed if 'continue' is triggered.\n // In the case of 'break', a prefix is needed due to the loop's suffix.\n xfix += Python.injectId(Python.STATEMENT_PREFIX, loop);\n }\n }\n switch (block.getFieldValue('FLOW')) {\n case 'BREAK':\n return xfix + 'break\\n';\n case 'CONTINUE':\n return xfix + 'continue\\n';\n }\n throw Error('Unknown flow statement.');\n};\n","/**\n * @license\n * Copyright 2012 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * @fileoverview Generating Python for logic blocks.\n */\n'use strict';\n\ngoog.module('Blockly.Python.logic');\n\nconst {pythonGenerator: Python} = goog.require('Blockly.Python');\n\n\nPython['controls_if'] = function(block) {\n // If/elseif/else condition.\n let n = 0;\n let code = '', branchCode, conditionCode;\n if (Python.STATEMENT_PREFIX) {\n // Automatic prefix insertion is switched off for this block. Add manually.\n code += Python.injectId(Python.STATEMENT_PREFIX, block);\n }\n do {\n conditionCode =\n Python.valueToCode(block, 'IF' + n, Python.ORDER_NONE) || 'False';\n branchCode = Python.statementToCode(block, 'DO' + n) || Python.PASS;\n if (Python.STATEMENT_SUFFIX) {\n branchCode =\n Python.prefixLines(\n Python.injectId(Python.STATEMENT_SUFFIX, block), Python.INDENT) +\n branchCode;\n }\n code += (n === 0 ? 'if ' : 'elif ') + conditionCode + ':\\n' + branchCode;\n n++;\n } while (block.getInput('IF' + n));\n\n if (block.getInput('ELSE') || Python.STATEMENT_SUFFIX) {\n branchCode = Python.statementToCode(block, 'ELSE') || Python.PASS;\n if (Python.STATEMENT_SUFFIX) {\n branchCode =\n Python.prefixLines(\n Python.injectId(Python.STATEMENT_SUFFIX, block), Python.INDENT) +\n branchCode;\n }\n code += 'else:\\n' + branchCode;\n }\n return code;\n};\n\nPython['controls_ifelse'] = Python['controls_if'];\n\nPython['logic_compare'] = function(block) {\n // Comparison operator.\n const OPERATORS =\n {'EQ': '==', 'NEQ': '!=', 'LT': '<', 'LTE': '<=', 'GT': '>', 'GTE': '>='};\n const operator = OPERATORS[block.getFieldValue('OP')];\n const order = Python.ORDER_RELATIONAL;\n const argument0 = Python.valueToCode(block, 'A', order) || '0';\n const argument1 = Python.valueToCode(block, 'B', order) || '0';\n const code = argument0 + ' ' + operator + ' ' + argument1;\n return [code, order];\n};\n\nPython['logic_operation'] = function(block) {\n // Operations 'and', 'or'.\n const operator = (block.getFieldValue('OP') === 'AND') ? 'and' : 'or';\n const order =\n (operator === 'and') ? Python.ORDER_LOGICAL_AND : Python.ORDER_LOGICAL_OR;\n let argument0 = Python.valueToCode(block, 'A', order);\n let argument1 = Python.valueToCode(block, 'B', order);\n if (!argument0 && !argument1) {\n // If there are no arguments, then the return value is false.\n argument0 = 'False';\n argument1 = 'False';\n } else {\n // Single missing arguments have no effect on the return value.\n const defaultArgument = (operator === 'and') ? 'True' : 'False';\n if (!argument0) {\n argument0 = defaultArgument;\n }\n if (!argument1) {\n argument1 = defaultArgument;\n }\n }\n const code = argument0 + ' ' + operator + ' ' + argument1;\n return [code, order];\n};\n\nPython['logic_negate'] = function(block) {\n // Negation.\n const argument0 =\n Python.valueToCode(block, 'BOOL', Python.ORDER_LOGICAL_NOT) || 'True';\n const code = 'not ' + argument0;\n return [code, Python.ORDER_LOGICAL_NOT];\n};\n\nPython['logic_boolean'] = function(block) {\n // Boolean values true and false.\n const code = (block.getFieldValue('BOOL') === 'TRUE') ? 'True' : 'False';\n return [code, Python.ORDER_ATOMIC];\n};\n\nPython['logic_null'] = function(block) {\n // Null data type.\n return ['None', Python.ORDER_ATOMIC];\n};\n\nPython['logic_ternary'] = function(block) {\n // Ternary operator.\n const value_if =\n Python.valueToCode(block, 'IF', Python.ORDER_CONDITIONAL) || 'False';\n const value_then =\n Python.valueToCode(block, 'THEN', Python.ORDER_CONDITIONAL) || 'None';\n const value_else =\n Python.valueToCode(block, 'ELSE', Python.ORDER_CONDITIONAL) || 'None';\n const code = value_then + ' if ' + value_if + ' else ' + value_else;\n return [code, Python.ORDER_CONDITIONAL];\n};\n","/**\n * @license\n * Copyright 2012 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * @fileoverview Generating Python for list blocks.\n */\n'use strict';\n\ngoog.module('Blockly.Python.lists');\n\nconst stringUtils = goog.require('Blockly.utils.string');\nconst {NameType} = goog.require('Blockly.Names');\nconst {pythonGenerator: Python} = goog.require('Blockly.Python');\n\n\nPython['lists_create_empty'] = function(block) {\n // Create an empty list.\n return ['[]', Python.ORDER_ATOMIC];\n};\n\nPython['lists_create_with'] = function(block) {\n // Create a list with any number of elements of any type.\n const elements = new Array(block.itemCount_);\n for (let i = 0; i < block.itemCount_; i++) {\n elements[i] =\n Python.valueToCode(block, 'ADD' + i, Python.ORDER_NONE) || 'None';\n }\n const code = '[' + elements.join(', ') + ']';\n return [code, Python.ORDER_ATOMIC];\n};\n\nPython['lists_repeat'] = function(block) {\n // Create a list with one element repeated.\n const item = Python.valueToCode(block, 'ITEM', Python.ORDER_NONE) || 'None';\n const times =\n Python.valueToCode(block, 'NUM', Python.ORDER_MULTIPLICATIVE) || '0';\n const code = '[' + item + '] * ' + times;\n return [code, Python.ORDER_MULTIPLICATIVE];\n};\n\nPython['lists_length'] = function(block) {\n // String or array length.\n const list = Python.valueToCode(block, 'VALUE', Python.ORDER_NONE) || '[]';\n return ['len(' + list + ')', Python.ORDER_FUNCTION_CALL];\n};\n\nPython['lists_isEmpty'] = function(block) {\n // Is the string null or array empty?\n const list = Python.valueToCode(block, 'VALUE', Python.ORDER_NONE) || '[]';\n const code = 'not len(' + list + ')';\n return [code, Python.ORDER_LOGICAL_NOT];\n};\n\nPython['lists_indexOf'] = function(block) {\n // Find an item in the list.\n const item = Python.valueToCode(block, 'FIND', Python.ORDER_NONE) || '[]';\n const list = Python.valueToCode(block, 'VALUE', Python.ORDER_NONE) || \"''\";\n let errorIndex = ' -1';\n let firstIndexAdjustment = '';\n let lastIndexAdjustment = ' - 1';\n\n if (block.workspace.options.oneBasedIndex) {\n errorIndex = ' 0';\n firstIndexAdjustment = ' + 1';\n lastIndexAdjustment = '';\n }\n\n let functionName;\n if (block.getFieldValue('END') === 'FIRST') {\n functionName = Python.provideFunction_('first_index', `\ndef ${Python.FUNCTION_NAME_PLACEHOLDER_}(my_list, elem):\n try: index = my_list.index(elem)${firstIndexAdjustment}\n except: index =${errorIndex}\n return index\n`);\n } else {\n functionName = Python.provideFunction_('last_index', `\ndef ${Python.FUNCTION_NAME_PLACEHOLDER_}(my_list, elem):\n try: index = len(my_list) - my_list[::-1].index(elem)${lastIndexAdjustment}\n except: index =${errorIndex}\n return index\n`);\n }\n const code = functionName + '(' + list + ', ' + item + ')';\n return [code, Python.ORDER_FUNCTION_CALL];\n};\n\nPython['lists_getIndex'] = function(block) {\n // Get element at index.\n // Note: Until January 2013 this block did not have MODE or WHERE inputs.\n const mode = block.getFieldValue('MODE') || 'GET';\n const where = block.getFieldValue('WHERE') || 'FROM_START';\n const listOrder =\n (where === 'RANDOM') ? Python.ORDER_NONE : Python.ORDER_MEMBER;\n const list = Python.valueToCode(block, 'VALUE', listOrder) || '[]';\n\n switch (where) {\n case 'FIRST':\n if (mode === 'GET') {\n const code = list + '[0]';\n return [code, Python.ORDER_MEMBER];\n } else if (mode === 'GET_REMOVE') {\n const code = list + '.pop(0)';\n return [code, Python.ORDER_FUNCTION_CALL];\n } else if (mode === 'REMOVE') {\n return list + '.pop(0)\\n';\n }\n break;\n case 'LAST':\n if (mode === 'GET') {\n const code = list + '[-1]';\n return [code, Python.ORDER_MEMBER];\n } else if (mode === 'GET_REMOVE') {\n const code = list + '.pop()';\n return [code, Python.ORDER_FUNCTION_CALL];\n } else if (mode === 'REMOVE') {\n return list + '.pop()\\n';\n }\n break;\n case 'FROM_START': {\n const at = Python.getAdjustedInt(block, 'AT');\n if (mode === 'GET') {\n const code = list + '[' + at + ']';\n return [code, Python.ORDER_MEMBER];\n } else if (mode === 'GET_REMOVE') {\n const code = list + '.pop(' + at + ')';\n return [code, Python.ORDER_FUNCTION_CALL];\n } else if (mode === 'REMOVE') {\n return list + '.pop(' + at + ')\\n';\n }\n break;\n }\n case 'FROM_END': {\n const at = Python.getAdjustedInt(block, 'AT', 1, true);\n if (mode === 'GET') {\n const code = list + '[' + at + ']';\n return [code, Python.ORDER_MEMBER];\n } else if (mode === 'GET_REMOVE') {\n const code = list + '.pop(' + at + ')';\n return [code, Python.ORDER_FUNCTION_CALL];\n } else if (mode === 'REMOVE') {\n return list + '.pop(' + at + ')\\n';\n }\n break;\n }\n case 'RANDOM':\n Python.definitions_['import_random'] = 'import random';\n if (mode === 'GET') {\n const code = 'random.choice(' + list + ')';\n return [code, Python.ORDER_FUNCTION_CALL];\n } else {\n const functionName =\n Python.provideFunction_('lists_remove_random_item', `\ndef ${Python.FUNCTION_NAME_PLACEHOLDER_}(myList):\n x = int(random.random() * len(myList))\n return myList.pop(x)\n`);\n const code = functionName + '(' + list + ')';\n if (mode === 'GET_REMOVE') {\n return [code, Python.ORDER_FUNCTION_CALL];\n } else if (mode === 'REMOVE') {\n return code + '\\n';\n }\n }\n break;\n }\n throw Error('Unhandled combination (lists_getIndex).');\n};\n\nPython['lists_setIndex'] = function(block) {\n // Set element at index.\n // Note: Until February 2013 this block did not have MODE or WHERE inputs.\n let list = Python.valueToCode(block, 'LIST', Python.ORDER_MEMBER) || '[]';\n const mode = block.getFieldValue('MODE') || 'GET';\n const where = block.getFieldValue('WHERE') || 'FROM_START';\n const value = Python.valueToCode(block, 'TO', Python.ORDER_NONE) || 'None';\n // Cache non-trivial values to variables to prevent repeated look-ups.\n // Closure, which accesses and modifies 'list'.\n function cacheList() {\n if (list.match(/^\\w+$/)) {\n return '';\n }\n const listVar =\n Python.nameDB_.getDistinctName('tmp_list', NameType.VARIABLE);\n const code = listVar + ' = ' + list + '\\n';\n list = listVar;\n return code;\n }\n\n switch (where) {\n case 'FIRST':\n if (mode === 'SET') {\n return list + '[0] = ' + value + '\\n';\n } else if (mode === 'INSERT') {\n return list + '.insert(0, ' + value + ')\\n';\n }\n break;\n case 'LAST':\n if (mode === 'SET') {\n return list + '[-1] = ' + value + '\\n';\n } else if (mode === 'INSERT') {\n return list + '.append(' + value + ')\\n';\n }\n break;\n case 'FROM_START': {\n const at = Python.getAdjustedInt(block, 'AT');\n if (mode === 'SET') {\n return list + '[' + at + '] = ' + value + '\\n';\n } else if (mode === 'INSERT') {\n return list + '.insert(' + at + ', ' + value + ')\\n';\n }\n break;\n }\n case 'FROM_END': {\n const at = Python.getAdjustedInt(block, 'AT', 1, true);\n if (mode === 'SET') {\n return list + '[' + at + '] = ' + value + '\\n';\n } else if (mode === 'INSERT') {\n return list + '.insert(' + at + ', ' + value + ')\\n';\n }\n break;\n }\n case 'RANDOM': {\n Python.definitions_['import_random'] = 'import random';\n let code = cacheList();\n const xVar = Python.nameDB_.getDistinctName('tmp_x', NameType.VARIABLE);\n code += xVar + ' = int(random.random() * len(' + list + '))\\n';\n if (mode === 'SET') {\n code += list + '[' + xVar + '] = ' + value + '\\n';\n return code;\n } else if (mode === 'INSERT') {\n code += list + '.insert(' + xVar + ', ' + value + ')\\n';\n return code;\n }\n break;\n }\n }\n throw Error('Unhandled combination (lists_setIndex).');\n};\n\nPython['lists_getSublist'] = function(block) {\n // Get sublist.\n const list = Python.valueToCode(block, 'LIST', Python.ORDER_MEMBER) || '[]';\n const where1 = block.getFieldValue('WHERE1');\n const where2 = block.getFieldValue('WHERE2');\n let at1;\n switch (where1) {\n case 'FROM_START':\n at1 = Python.getAdjustedInt(block, 'AT1');\n if (at1 === 0) {\n at1 = '';\n }\n break;\n case 'FROM_END':\n at1 = Python.getAdjustedInt(block, 'AT1', 1, true);\n break;\n case 'FIRST':\n at1 = '';\n break;\n default:\n throw Error('Unhandled option (lists_getSublist)');\n }\n\n let at2;\n switch (where2) {\n case 'FROM_START':\n at2 = Python.getAdjustedInt(block, 'AT2', 1);\n break;\n case 'FROM_END':\n at2 = Python.getAdjustedInt(block, 'AT2', 0, true);\n // Ensure that if the result calculated is 0 that sub-sequence will\n // include all elements as expected.\n if (!stringUtils.isNumber(String(at2))) {\n Python.definitions_['import_sys'] = 'import sys';\n at2 += ' or sys.maxsize';\n } else if (at2 === 0) {\n at2 = '';\n }\n break;\n case 'LAST':\n at2 = '';\n break;\n default:\n throw Error('Unhandled option (lists_getSublist)');\n }\n const code = list + '[' + at1 + ' : ' + at2 + ']';\n return [code, Python.ORDER_MEMBER];\n};\n\nPython['lists_sort'] = function(block) {\n // Block for sorting a list.\n const list = (Python.valueToCode(block, 'LIST', Python.ORDER_NONE) || '[]');\n const type = block.getFieldValue('TYPE');\n const reverse = block.getFieldValue('DIRECTION') === '1' ? 'False' : 'True';\n const sortFunctionName = Python.provideFunction_('lists_sort', `\ndef ${Python.FUNCTION_NAME_PLACEHOLDER_}(my_list, type, reverse):\n def try_float(s):\n try:\n return float(s)\n except:\n return 0\n key_funcs = {\n \"NUMERIC\": try_float,\n \"TEXT\": str,\n \"IGNORE_CASE\": lambda s: str(s).lower()\n }\n key_func = key_funcs[type]\n list_cpy = list(my_list)\n return sorted(list_cpy, key=key_func, reverse=reverse)\n`);\n\n const code =\n sortFunctionName + '(' + list + ', \"' + type + '\", ' + reverse + ')';\n return [code, Python.ORDER_FUNCTION_CALL];\n};\n\nPython['lists_split'] = function(block) {\n // Block for splitting text into a list, or joining a list into text.\n const mode = block.getFieldValue('MODE');\n let code;\n if (mode === 'SPLIT') {\n const value_input =\n Python.valueToCode(block, 'INPUT', Python.ORDER_MEMBER) || \"''\";\n const value_delim = Python.valueToCode(block, 'DELIM', Python.ORDER_NONE);\n code = value_input + '.split(' + value_delim + ')';\n } else if (mode === 'JOIN') {\n const value_input =\n Python.valueToCode(block, 'INPUT', Python.ORDER_NONE) || '[]';\n const value_delim =\n Python.valueToCode(block, 'DELIM', Python.ORDER_MEMBER) || \"''\";\n code = value_delim + '.join(' + value_input + ')';\n } else {\n throw Error('Unknown mode: ' + mode);\n }\n return [code, Python.ORDER_FUNCTION_CALL];\n};\n\nPython['lists_reverse'] = function(block) {\n // Block for reversing a list.\n const list = Python.valueToCode(block, 'LIST', Python.ORDER_NONE) || '[]';\n const code = 'list(reversed(' + list + '))';\n return [code, Python.ORDER_FUNCTION_CALL];\n};\n","/**\n * @license\n * Copyright 2012 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * @fileoverview Generating Python for colour blocks.\n */\n'use strict';\n\ngoog.module('Blockly.Python.colour');\n\nconst {pythonGenerator: Python} = goog.require('Blockly.Python');\n\n\nPython['colour_picker'] = function(block) {\n // Colour picker.\n const code = Python.quote_(block.getFieldValue('COLOUR'));\n return [code, Python.ORDER_ATOMIC];\n};\n\nPython['colour_random'] = function(block) {\n // Generate a random colour.\n Python.definitions_['import_random'] = 'import random';\n const code = '\\'#%06x\\' % random.randint(0, 2**24 - 1)';\n return [code, Python.ORDER_FUNCTION_CALL];\n};\n\nPython['colour_rgb'] = function(block) {\n // Compose a colour from RGB components expressed as percentages.\n const functionName = Python.provideFunction_('colour_rgb', `\ndef ${Python.FUNCTION_NAME_PLACEHOLDER_}(r, g, b):\n r = round(min(100, max(0, r)) * 2.55)\n g = round(min(100, max(0, g)) * 2.55)\n b = round(min(100, max(0, b)) * 2.55)\n return '#%02x%02x%02x' % (r, g, b)\n`);\n const r = Python.valueToCode(block, 'RED', Python.ORDER_NONE) || 0;\n const g = Python.valueToCode(block, 'GREEN', Python.ORDER_NONE) || 0;\n const b = Python.valueToCode(block, 'BLUE', Python.ORDER_NONE) || 0;\n const code = functionName + '(' + r + ', ' + g + ', ' + b + ')';\n return [code, Python.ORDER_FUNCTION_CALL];\n};\n\nPython['colour_blend'] = function(block) {\n // Blend two colours together.\n const functionName = Python.provideFunction_('colour_blend', `\ndef ${Python.FUNCTION_NAME_PLACEHOLDER_}(colour1, colour2, ratio):\n r1, r2 = int(colour1[1:3], 16), int(colour2[1:3], 16)\n g1, g2 = int(colour1[3:5], 16), int(colour2[3:5], 16)\n b1, b2 = int(colour1[5:7], 16), int(colour2[5:7], 16)\n ratio = min(1, max(0, ratio))\n r = round(r1 * (1 - ratio) + r2 * ratio)\n g = round(g1 * (1 - ratio) + g2 * ratio)\n b = round(b1 * (1 - ratio) + b2 * ratio)\n return '#%02x%02x%02x' % (r, g, b)\n`);\n const colour1 =\n Python.valueToCode(block, 'COLOUR1', Python.ORDER_NONE) || '\\'#000000\\'';\n const colour2 =\n Python.valueToCode(block, 'COLOUR2', Python.ORDER_NONE) || '\\'#000000\\'';\n const ratio = Python.valueToCode(block, 'RATIO', Python.ORDER_NONE) || 0;\n const code =\n functionName + '(' + colour1 + ', ' + colour2 + ', ' + ratio + ')';\n return [code, Python.ORDER_FUNCTION_CALL];\n};\n","/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * @fileoverview Complete helper functions for generating Python for\n * blocks. This is the entrypoint for python_compressed.js.\n * @suppress {extraRequire}\n */\n'use strict';\n\ngoog.module('Blockly.Python.all');\n\nconst moduleExports = goog.require('Blockly.Python');\ngoog.require('Blockly.Python.colour');\ngoog.require('Blockly.Python.lists');\ngoog.require('Blockly.Python.logic');\ngoog.require('Blockly.Python.loops');\ngoog.require('Blockly.Python.math');\ngoog.require('Blockly.Python.procedures');\ngoog.require('Blockly.Python.texts');\ngoog.require('Blockly.Python.variables');\ngoog.require('Blockly.Python.variablesDynamic');\n\nexports = moduleExports;\n"]}
\ No newline at end of file
diff --git a/blockly/tests/playgrounds/advanced_playground.html b/blockly/tests/playgrounds/advanced_playground.html
deleted file mode 100644
index 26040127c58a2c3c9edd7d164598ac7d3e85d68d..0000000000000000000000000000000000000000
--- a/blockly/tests/playgrounds/advanced_playground.html
+++ /dev/null
@@ -1,168 +0,0 @@
-
-
-
-
-Advanced Blockly Playground
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/blockly/tests/playgrounds/iframe.html b/blockly/tests/playgrounds/iframe.html
deleted file mode 100644
index 42a253956a8367578f61b1ba43869fd8f8954d87..0000000000000000000000000000000000000000
--- a/blockly/tests/playgrounds/iframe.html
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-Blockly <iframe> Playground
-
-
-
-
- Outer Frame
-
-
-
\ No newline at end of file
diff --git a/blockly/tests/playgrounds/screenshot.js b/blockly/tests/playgrounds/screenshot.js
deleted file mode 100644
index 6b2b22e3e4ad68682ac940468c61a31ba4caec5a..0000000000000000000000000000000000000000
--- a/blockly/tests/playgrounds/screenshot.js
+++ /dev/null
@@ -1,110 +0,0 @@
-/**
- * @license
- * Copyright 2019 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-
-/**
- * @fileoverview Download screenshot.
- */
-'use strict';
-
-/**
- * Convert an SVG datauri into a PNG datauri.
- * @param {string} data SVG datauri.
- * @param {number} width Image width.
- * @param {number} height Image height.
- * @param {!Function} callback Callback.
- */
-function svgToPng_(data, width, height, callback) {
- const canvas = document.createElement("canvas");
- const context = canvas.getContext("2d");
- const img = new Image();
-
- const pixelDensity = 10;
- canvas.width = width * pixelDensity;
- canvas.height = height * pixelDensity;
- img.onload = function() {
- context.drawImage(
- img, 0, 0, width, height, 0, 0, canvas.width, canvas.height);
- try {
- const dataUri = canvas.toDataURL('image/png');
- callback(dataUri);
- } catch (err) {
- console.warn('Error converting the workspace svg to a png');
- callback('');
- }
- };
- img.src = data;
-}
-
-/**
- * Create an SVG of the blocks on the workspace.
- * @param {!Blockly.WorkspaceSvg} workspace The workspace.
- * @param {!Function} callback Callback.
- * @param {string=} customCss Custom CSS to append to the SVG.
- */
-function workspaceToSvg_(workspace, callback, customCss) {
- // Go through all text areas and set their value.
- const textAreas = document.getElementsByTagName("textarea");
- for (let i = 0; i < textAreas.length; i++) {
- textAreas[i].innerHTML = textAreas[i].value;
- }
-
- const bBox = workspace.getBlocksBoundingBox();
- const x = bBox.x || bBox.left;
- const y = bBox.y || bBox.top;
- const width = bBox.width || bBox.right - x;
- const height = bBox.height || bBox.bottom - y;
-
- const blockCanvas = workspace.getCanvas();
- const clone = blockCanvas.cloneNode(true);
- clone.removeAttribute('transform');
-
- const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
- svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
- svg.appendChild(clone);
- svg.setAttribute('viewBox',
- x + ' ' + y + ' ' + width + ' ' + height);
-
- svg.setAttribute('class', 'blocklySvg ' +
- (workspace.options.renderer || 'geras') + '-renderer ' +
- (workspace.getTheme ? workspace.getTheme().name + '-theme' : ''));
- svg.setAttribute('width', width);
- svg.setAttribute('height', height);
- svg.setAttribute("style", 'background-color: transparent');
-
- const css = [].slice.call(document.head.querySelectorAll('style'))
- .filter(
- (el) => /\.blocklySvg/.test(el.innerText) ||
- (el.id.indexOf('blockly-') === 0))
- .map((el) => el.innerText)
- .join('\n');
- const style = document.createElement('style');
- style.innerHTML = css + '\n' + customCss;
- svg.insertBefore(style, svg.firstChild);
-
- let svgAsXML = (new XMLSerializer).serializeToString(svg);
- svgAsXML = svgAsXML.replace(/ /g, ' ');
- const data = 'data:image/svg+xml,' + encodeURIComponent(svgAsXML);
-
- svgToPng_(data, width, height, callback);
-}
-
-/* eslint-disable no-unused-vars */
-/**
- * Download a screenshot of the blocks on a Blockly workspace.
- * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace.
- */
-function downloadScreenshot(workspace) {
- workspaceToSvg_(workspace, function(datauri) {
- const a = document.createElement('a');
- a.download = 'screenshot.png';
- a.target = '_self';
- a.href = datauri;
- document.body.appendChild(a);
- a.click();
- a.parentNode.removeChild(a);
- });
-}
-/* eslint-enable */
diff --git a/blockly/tests/playgrounds/shared_procedures.html b/blockly/tests/playgrounds/shared_procedures.html
deleted file mode 100644
index 63a1a9054f60b9879334ac28e19b2aa406c06846..0000000000000000000000000000000000000000
--- a/blockly/tests/playgrounds/shared_procedures.html
+++ /dev/null
@@ -1,179 +0,0 @@
-
-
-
-
-Shared Procedures Playground
-
-
-
-
-
-
-
-
-
- Shared Procedures Playground
-
-
-
-
-
diff --git a/css/style.css b/css/style.css
index d91771b308762fe502711ae9afdf21b31f64f2a2..3df8fb2d0ad5681d1c2b06d0d63d9a330432f6af 100644
--- a/css/style.css
+++ b/css/style.css
@@ -140,6 +140,7 @@ html,body{
width: 120px;
padding-inline-end: 10px;
padding-left: 10px;
+ padding-top: 10px;
}
.blocklyTreeRow{
@@ -152,3 +153,23 @@ html,body{
.blocklyTreeSelected{
border-radius: 5px;
}
+
+.dropdown {
+ position: relative;
+ display: inline-block;
+}
+
+.dropdown-content {
+ display: none;
+ position: absolute;
+ background-color: #ffffff;
+ min-width: 160px;
+ box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
+ padding: 12px 16px;
+ z-index: 1;
+ border-radius: 10px;
+}
+
+.dropdown:hover .dropdown-content {
+ display: block;
+}
diff --git a/develop_doc.md b/develop_doc.md
deleted file mode 100644
index 22f02aeedc743ad6d8990726c9e88927c18167a7..0000000000000000000000000000000000000000
--- a/develop_doc.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# PHP助手开发文档 #
-开发人员务必仔细阅读
-## 开发工具 ##
-### 定义积木 ###
-#### 使用Blockly Developer Tools ####
-#### 链接:[http://blockly.daobanmojie.com/demos/blockfactory/](http://blockly.daobanmojie.com/demos/blockfactory/) ####
-### 代码编辑器 ###
-建议使用Web IDE或Visual Studio Code(需安装Git)。
-## 文件介绍 ##
-### kzhzbcphp.php ###
-用来更新ide.html。当修改了积木,工作箱,代码转换器时,就需要运行kzhzbcphp.php来更新ide.html
-### index.php ###
-官网
-### index.html ###
-使用文档
-### blockly ###
-包含了原生blockly的代码
-### blockly/media ###
-存放blockly工作区媒体文件
-### blockly/ini ###
-定制blockly的地方。里面有三个文件夹,分别是workspace,block和site
-### blockly/ini/workspace ###
-存放工作区定义(workspace.xml workspace.js),工作箱定义(toolbox.xml),块库(library.xml)
-### blockly/ini/block ###
-存放积木定义(get.js)和积木转换器(get.js.js)
-### blockly/ini/site ###
-存放网站的一些图片
-### blockly/colored_egg ###
-存放彩蛋
-## 注意事项 ##
-1. 提交时**一定要提交到Dev分支!一定要提交到Dev分支! 一定要提交到Dev分支!**
-2. 如果提示存在**冲突**,请在讨论群中说明情况,说清文件名。**千万不要擅自建立分支!**
-## 文档编写人员 ##
-### CodeKpy ###
-### ZouBochen ###
\ No newline at end of file
diff --git a/ide.html b/ide.html
index fd21c2170d80181055489fe699b86563e347b8d8..3e24faec8ff09c495aefd7590bed7b06a6615b42 100644
--- a/ide.html
+++ b/ide.html
@@ -1,5 +1,6 @@
+
PHP助手——让世界没有难写的网页后端
@@ -8,65 +9,140 @@
+
-
+
+
-