├── README.md ├── blockly.html ├── blockly ├── blockly.html ├── blockly_compressed.js ├── blockly_espruino.js ├── blocks_compressed.js ├── changes.diff ├── en.js ├── field_textarea.js ├── javascript_compressed.js └── media │ ├── 1x1.gif │ ├── anon.jpeg │ ├── click.mp3 │ ├── click.ogg │ ├── click.wav │ ├── delete.mp3 │ ├── delete.ogg │ ├── delete.wav │ ├── handclosed.cur │ ├── handopen.cur │ ├── progress.gif │ ├── quote0.png │ ├── quote1.png │ ├── sprites.png │ ├── trashbody.png │ ├── trashlid.png │ └── tree.png ├── blockly_simple.html ├── circuit.fzz ├── circuit.png ├── circuit_single.fzz ├── circuit_single.png ├── colour_chooser.html ├── data └── terminal_initial.html ├── ide.html ├── index.html ├── plugin.html ├── plugin.js ├── serial_to_audio.js ├── terminal.css └── test.html /README.md: -------------------------------------------------------------------------------- 1 | EspruinoOrion - Eclipse Orion plugin 2 | ==================================== 3 | 4 | 5 | Espruino plugin for Eclipse Orion. 6 | 7 | [There's a forum post about it here](http://forum.espruino.com/conversations/257732/) 8 | 9 | Simply: 10 | 11 | * Host this on an HTTPS capable webserver (or use [GitHub](https://espruino.github.io/EspruinoOrion/)) 12 | * Add [plugin.html](https://espruino.github.io/EspruinoOrion/plugin.html) to Eclipse Orion 13 | * Open [index.html](https://espruino.github.io/EspruinoOrion/index.html) in a new window 14 | * Connect Espruino to your AUDIO JACKS (wiring below) 15 | * In Orion, open a file, go to 'Tools', and click 'Send to Espruino' 16 | 17 | If you'd rather just use USB and the Web IDE... 18 | 19 | * Use Chrome and install the [Web IDE](http://github.com/espruino/EspruinoWebIDE) 20 | * Add [plugin.html](https://espruino.github.io/EspruinoOrion/plugin.html) to Eclipse Orion 21 | * Open [ide.html](https://espruino.github.io/EspruinoOrion/ide.html) in a new window 22 | 23 | Or if you want to use Blockly instead: 24 | 25 | * Open [index.html](https://espruino.github.io/EspruinoOrion/index.html) in a new window 26 | * Open [blockly.html](https://espruino.github.io/EspruinoOrion/blockly.html) 27 | 28 | **Note:** If this doesn't work, your device may have RX and/or TX polarity mixed up. Try clicking the checkboxes and trying again. 29 | 30 | One-way communication 31 | ------------------ 32 | 33 | You can also do one-directional communication (from the PC to an Espruino board). There's a simple library for this called [serial_to_audio.js](serial_to_audio.js). 34 | 35 | Examples of this are: 36 | 37 | * [blockly_simple.html](https://espruino.github.io/EspruinoOrion/blockly_simple.html) - the previous Blockly Example, but with no need for a separate window. Works perfectly on tablets! 38 | * [colour_chooser.html](https://espruino.github.io/EspruinoOrion/colour_chooser.html) - a simple colour chooser that will change the colour of connected WS2811 lights (on B15) when you click a coloured square. 39 | 40 | How it works 41 | ---------- 42 | 43 | Data is sent and received at 9600 baud using your headphone and microphone jacks - no local software needed! 44 | 45 | When you click 'Send to Espruino' in Orion, a cookie is set with the code in. 46 | 47 | The Terminal (index.html) reads this code and converts it to sound waves which it sends to Espruino. 48 | 49 | 50 | Connections 51 | ---------- 52 | 53 | ![Espruino Wiring](circuit.png) 54 | 55 | * Connect Espruino GND to the sheath on both headphone and microphone jacks 56 | * Connect Espruino A9 (TX) to a 10k resistor, and connect that to the microphone Left+Right 57 | * Connect a 10k resistor to the microphone sheath and connect that to microphone Left+Right too 58 | * Connect Espruino A10 (RX) to the Left channel of the headphone jack 59 | * Connect a 40k resistor between the headphone jack left channel and the headphone jack sheath 60 | 61 | This creates: 62 | * A potential divider to convert the 3.3v Espruino TX signal to a 1.6v signal for the microphone 63 | * A bias to 1.6v for Espruino's RX (by default Espruino turns on an internal 40k pullup resistor on the Usart to stop noise getting in) 64 | 65 | **Note:** Most computers have a ~10uF capacitor in their headphone output - this allows the DC bias to work. However some computers may not have it, in which case the resting voltage for A10 will be 0v insread of 1.6v. In that case, you'll need to add a 10uF capacitor between Espruino + the resistor and the actual headphone output. 66 | 67 | Connections for One-way communication 68 | ---------------------------------------- 69 | 70 | ![One-way Espruino Wiring](circuit_single.png) 71 | 72 | This is just as before, but with the microphone part removed - so you only have two parts to solder! 73 | -------------------------------------------------------------------------------- /blockly.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 39 | 40 | 63 | 64 | 65 | 66 | 69 |
70 | 71 |
72 | 73 | 74 | -------------------------------------------------------------------------------- /blockly/blockly.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 22 | 23 | 24 | 25 | 26 | 292 | 293 | 294 | 297 | 298 | 299 | 300 | -------------------------------------------------------------------------------- /blockly/blockly_espruino.js: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2014 Gordon Williams (gw@pur3.co.uk) 3 | 4 | This Source Code is subject to the terms of the Mozilla Public 5 | License, v2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | 8 | ------------------------------------------------------------------ 9 | Blockly blocks for Espruino 10 | ------------------------------------------------------------------ 11 | **/ 12 | 13 | // --------------------------------- Blockly init code - see /js/core/editorBlockly.js 14 | window.onload = function() { 15 | Blockly.inject(document.body,{path: '', toolbox: document.getElementById('toolbox')}); 16 | Blockly.Xml.domToWorkspace(Blockly.mainWorkspace, document.getElementById('blocklyInitial')); 17 | window.parent.window.blocklyLoaded(Blockly, window); // see core/editorBlockly.js 18 | }; 19 | // When we have JSON from the board, use it to 20 | // update our list of available pins 21 | Blockly.setBoardJSON = function(info) { 22 | console.log("Blockly.setBoardJSON ", info); 23 | if (!("pins" in info)) return; 24 | if (!("devices" in info)) return; 25 | PINS = []; 26 | var i,s; 27 | for (i=1;i<8;i++) { 28 | s = "LED"+i; 29 | if (s in info.devices) PINS.push([s,s]); 30 | } 31 | for (i=1;i<8;i++) { 32 | s = "BTN"+i; 33 | if (s in info.devices) PINS.push([s,s]); 34 | } 35 | for (i in info.pins) 36 | PINS.push([info.pins[i].name, info.pins[i].name]); 37 | 38 | 39 | }; 40 | // --------------------------------- 41 | 42 | var ESPRUINO_COL = 190; 43 | 44 | var PORTS = ["A","B","C"]; 45 | var PINS = [ 46 | ["LED1", 'LED1'], 47 | ["LED2", 'LED2'], 48 | ["LED3", 'LED3'], 49 | ["BTN1", 'BTN1']]; 50 | for (var p in PORTS) 51 | for (var i=0;i<16;i++) { 52 | var pinname = PORTS[p]+i; 53 | PINS.push([pinname,pinname]); 54 | } 55 | 56 | Blockly.Blocks.espruino_timeout = { 57 | category: 'Espruino', 58 | init: function() { 59 | this.appendValueInput('SECONDS') 60 | .setCheck('Number') 61 | .appendField('wait'); 62 | this.appendDummyInput() 63 | .appendField("seconds"); 64 | this.appendStatementInput('DO') 65 | .appendField('do'); 66 | 67 | this.setPreviousStatement(true); 68 | this.setNextStatement(true); 69 | this.setColour(ESPRUINO_COL); 70 | this.setInputsInline(true); 71 | this.setTooltip('Waits for a certain period before running code'); 72 | } 73 | }; 74 | Blockly.Blocks.espruino_interval = { 75 | category: 'Espruino', 76 | init: function() { 77 | this.appendValueInput('SECONDS') 78 | .setCheck('Number') 79 | .appendField('every'); 80 | this.appendDummyInput() 81 | .appendField("seconds"); 82 | this.appendStatementInput('DO') 83 | .appendField('do'); 84 | 85 | this.setPreviousStatement(true); 86 | this.setNextStatement(true); 87 | this.setColour(ESPRUINO_COL); 88 | this.setInputsInline(true); 89 | this.setTooltip('Runs code repeatedly, every so many seconds'); 90 | } 91 | }; 92 | 93 | Blockly.Blocks.espruino_pin = { 94 | // category: 'Espruino', 95 | init: function() { 96 | 97 | var start = 0; 98 | var incrementStep = 10; 99 | var originalPin = undefined; 100 | var listGen = function() { 101 | originalPin = this.value_; 102 | var list = PINS.slice(start, start+incrementStep); 103 | if (start>0) list.unshift(['Back...', 'Back']); 104 | if (start+incrementStep","LT"],["\u2265","LTE"],["<","GT"],["\u2264","GTE"]]:[["=","EQ"],["\u2260","NEQ"],["<","LT"],["\u2264","LTE"],[">","GT"],["\u2265","GTE"]];this.setHelpUrl(Blockly.Msg.LOGIC_COMPARE_HELPURL);this.setColour(210);this.setOutput(!0,"Boolean");this.appendValueInput("A");this.appendValueInput("B").appendField(new Blockly.FieldDropdown(a),"OP");this.setInputsInline(!0);var b=this;this.setTooltip(function(){var a= 116 | b.getFieldValue("OP");return{EQ:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_EQ,NEQ:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_NEQ,LT:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LT,LTE:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LTE,GT:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GT,GTE:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GTE}[a]})}}; 117 | Blockly.Blocks.logic_operation={init:function(){var a=[[Blockly.Msg.LOGIC_OPERATION_AND,"AND"],[Blockly.Msg.LOGIC_OPERATION_OR,"OR"]];this.setHelpUrl(Blockly.Msg.LOGIC_OPERATION_HELPURL);this.setColour(210);this.setOutput(!0,"Boolean");this.appendValueInput("A").setCheck("Boolean");this.appendValueInput("B").setCheck("Boolean").appendField(new Blockly.FieldDropdown(a),"OP");this.setInputsInline(!0);var b=this;this.setTooltip(function(){var a=b.getFieldValue("OP");return{AND:Blockly.Msg.LOGIC_OPERATION_TOOLTIP_AND, 118 | OR:Blockly.Msg.LOGIC_OPERATION_TOOLTIP_OR}[a]})}};Blockly.Blocks.logic_negate={init:function(){this.setHelpUrl(Blockly.Msg.LOGIC_NEGATE_HELPURL);this.setColour(210);this.setOutput(!0,"Boolean");this.interpolateMsg(Blockly.Msg.LOGIC_NEGATE_TITLE,["BOOL","Boolean",Blockly.ALIGN_RIGHT],Blockly.ALIGN_RIGHT);this.setTooltip(Blockly.Msg.LOGIC_NEGATE_TOOLTIP)}}; 119 | Blockly.Blocks.logic_boolean={init:function(){var a=[[Blockly.Msg.LOGIC_BOOLEAN_TRUE,"TRUE"],[Blockly.Msg.LOGIC_BOOLEAN_FALSE,"FALSE"]];this.setHelpUrl(Blockly.Msg.LOGIC_BOOLEAN_HELPURL);this.setColour(210);this.setOutput(!0,"Boolean");this.appendDummyInput().appendField(new Blockly.FieldDropdown(a),"BOOL");this.setTooltip(Blockly.Msg.LOGIC_BOOLEAN_TOOLTIP)}}; 120 | Blockly.Blocks.logic_null={init:function(){this.setHelpUrl(Blockly.Msg.LOGIC_NULL_HELPURL);this.setColour(210);this.setOutput(!0);this.appendDummyInput().appendField(Blockly.Msg.LOGIC_NULL);this.setTooltip(Blockly.Msg.LOGIC_NULL_TOOLTIP)}}; 121 | Blockly.Blocks.logic_ternary={init:function(){this.setHelpUrl(Blockly.Msg.LOGIC_TERNARY_HELPURL);this.setColour(210);this.appendValueInput("IF").setCheck("Boolean").appendField(Blockly.Msg.LOGIC_TERNARY_CONDITION);this.appendValueInput("THEN").appendField(Blockly.Msg.LOGIC_TERNARY_IF_TRUE);this.appendValueInput("ELSE").appendField(Blockly.Msg.LOGIC_TERNARY_IF_FALSE);this.setOutput(!0);this.setTooltip(Blockly.Msg.LOGIC_TERNARY_TOOLTIP)}}; 122 | // Copyright 2012 Google Inc. Apache License 2.0 123 | Blockly.Blocks.procedures={}; 124 | Blockly.Blocks.procedures_defnoreturn={init:function(){this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFNORETURN_HELPURL);this.setColour(290);var a=Blockly.Procedures.findLegalName(Blockly.Msg.PROCEDURES_DEFNORETURN_PROCEDURE,this);this.appendDummyInput().appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_TITLE).appendField(new Blockly.FieldTextInput(a,Blockly.Procedures.rename),"NAME").appendField("","PARAMS");this.appendStatementInput("STACK").appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_DO);this.setMutator(new Blockly.Mutator(["procedures_mutatorarg"])); 125 | this.setTooltip(Blockly.Msg.PROCEDURES_DEFNORETURN_TOOLTIP);this.arguments_=[];this.statementConnection_=null},updateParams_:function(){for(var a=!1,b={},c=0;cSeveral lines: 114 | First line. 115 | Second line. 116 | */ 117 | var y=2; 118 | var that=this; 119 | //var textNode = document.createTextNode(text); 120 | text.split(/\n/).map(function(textline){ 121 | textline = textline.replace(/\s/g, Blockly.Field.NBSP); 122 | var tspan = Blockly.createSvgElement('tspan', {x:0,y:y}, that.textElement_) 123 | .appendChild(document.createTextNode(textline)); 124 | y+=20; 125 | }); 126 | 127 | //this.textElement_.appendChild(textNode); 128 | 129 | // Cached width is obsolete. Clear it. 130 | this.size_.width = 0; 131 | 132 | if (this.sourceBlock_ && this.sourceBlock_.rendered) { 133 | this.sourceBlock_.render(); 134 | this.sourceBlock_.bumpNeighbours_(); 135 | this.sourceBlock_.workspace.fireChangeEvent(); 136 | } 137 | }; 138 | 139 | /** 140 | * Draws the border with the correct width. 141 | * Saves the computed width in a property. 142 | * @private 143 | */ 144 | Blockly.FieldTextArea.prototype.render_ = function() { 145 | 146 | this.size_.width = this.textElement_.getBBox().width + 5; 147 | 148 | this.size_.height= (this.text_.split(/\n/).length ||1)*20 + (Blockly.BlockSvg.SEP_SPACE_Y+5) ; 149 | 150 | if (this.borderRect_) { 151 | this.borderRect_.setAttribute('width', 152 | this.size_.width + Blockly.BlockSvg.SEP_SPACE_X); 153 | this.borderRect_.setAttribute('height', 154 | this.size_.height - (Blockly.BlockSvg.SEP_SPACE_Y+5)); 155 | } 156 | 157 | }; 158 | 159 | 160 | 161 | /** 162 | * Show the inline free-text editor on top of the text. 163 | * @param {boolean=} opt_quietInput True if editor should be created without 164 | * focus. Defaults to false. 165 | * @private 166 | */ 167 | Blockly.FieldTextArea.prototype.showEditor_ = function(opt_quietInput) { 168 | var quietInput = opt_quietInput || false; 169 | if (!quietInput && (goog.userAgent.MOBILE || goog.userAgent.ANDROID || 170 | goog.userAgent.IPAD)) { 171 | // Mobile browsers have issues with in-line textareas (focus & keyboards). 172 | var newValue = window.prompt(Blockly.Msg.CHANGE_VALUE_TITLE, this.text_); 173 | if (this.changeHandler_) { 174 | var override = this.changeHandler_(newValue); 175 | if (override !== undefined) { 176 | newValue = override; 177 | } 178 | } 179 | if (newValue !== null) { 180 | this.setText(newValue); 181 | } 182 | return; 183 | } 184 | 185 | Blockly.WidgetDiv.show(this, this.widgetDispose_()); 186 | var div = Blockly.WidgetDiv.DIV; 187 | // Create the input. 188 | var htmlInput = goog.dom.createDom('textarea', 'blocklyHtmlInput'); 189 | Blockly.FieldTextArea.htmlInput_ = htmlInput; 190 | htmlInput.style.resize = 'none'; 191 | htmlInput.style['line-height'] = '20px'; 192 | htmlInput.style.height = '100%';//this.size_.height - Blockly.BlockSvg.SEP_SPACE_Y + 'px'; 193 | div.appendChild(htmlInput); 194 | 195 | htmlInput.value = htmlInput.defaultValue = this.text_; 196 | htmlInput.oldValue_ = null; 197 | this.validate_(); 198 | this.resizeEditor_(); 199 | if (!quietInput) { 200 | htmlInput.focus(); 201 | htmlInput.select(); 202 | } 203 | 204 | // Bind to keyup -- trap Enter and Esc; resize after every keystroke. 205 | htmlInput.onKeyUpWrapper_ = 206 | Blockly.bindEvent_(htmlInput, 'keyup', this, this.onHtmlInputChange_); 207 | // Bind to keyPress -- repeatedly resize when holding down a key. 208 | htmlInput.onKeyPressWrapper_ = 209 | Blockly.bindEvent_(htmlInput, 'keypress', this, this.onHtmlInputChange_); 210 | var workspaceSvg = this.sourceBlock_.workspace.getCanvas(); 211 | htmlInput.onWorkspaceChangeWrapper_ = 212 | Blockly.bindEvent_(workspaceSvg, 'blocklyWorkspaceChange', this, 213 | this.resizeEditor_); 214 | }; 215 | 216 | /** 217 | * Handle a change to the editor. 218 | * @param {!Event} e Keyboard event. 219 | * @private 220 | */ 221 | Blockly.FieldTextArea.prototype.onHtmlInputChange_ = function(e) { 222 | var htmlInput = Blockly.FieldTextArea.htmlInput_; 223 | if (e.keyCode == 27) { 224 | // Esc 225 | this.setText(htmlInput.defaultValue); 226 | Blockly.WidgetDiv.hide(); 227 | } else { 228 | // Update source block. 229 | var text = htmlInput.value; 230 | if (text !== htmlInput.oldValue_) { 231 | htmlInput.oldValue_ = text; 232 | this.setText(text); 233 | this.validate_(); 234 | } else if (goog.userAgent.WEBKIT) { 235 | // Cursor key. Render the source block to show the caret moving. 236 | // Chrome only (version 26, OS X). 237 | this.sourceBlock_.render(); 238 | } 239 | this.resizeEditor_(); 240 | } 241 | }; 242 | 243 | /** 244 | * Check to see if the contents of the editor validates. 245 | * Style the editor accordingly. 246 | * @private 247 | */ 248 | Blockly.FieldTextArea.prototype.validate_ = function() { 249 | var valid = true; 250 | goog.asserts.assertObject(Blockly.FieldTextArea.htmlInput_); 251 | var htmlInput = /** @type {!Element} */ (Blockly.FieldTextArea.htmlInput_); 252 | if (this.changeHandler_) { 253 | valid = this.changeHandler_(htmlInput.value); 254 | } 255 | if (valid === null) { 256 | Blockly.addClass_(htmlInput, 'blocklyInvalidInput'); 257 | } else { 258 | Blockly.removeClass_(htmlInput, 'blocklyInvalidInput'); 259 | } 260 | }; 261 | 262 | /** 263 | * Resize the editor and the underlying block to fit the text. 264 | * @private 265 | */ 266 | Blockly.FieldTextArea.prototype.resizeEditor_ = function() { 267 | var div = Blockly.WidgetDiv.DIV; 268 | var bBox = this.fieldGroup_.getBBox(); 269 | div.style.width = bBox.width + 'px'; 270 | div.style.height = bBox.height + 'px'; 271 | var xy = Blockly.getAbsoluteXY_(/** @type {!Element} */ (this.borderRect_)); 272 | // In RTL mode block fields and LTR input fields the left edge moves, 273 | // whereas the right edge is fixed. Reposition the editor. 274 | if (Blockly.RTL) { 275 | var borderBBox = this.borderRect_.getBBox(); 276 | xy.x += borderBBox.width; 277 | xy.x -= div.offsetWidth; 278 | } 279 | // Shift by a few pixels to line up exactly. 280 | xy.y += 1; 281 | if (goog.userAgent.WEBKIT) { 282 | xy.y -= 3; 283 | } 284 | div.style.left = xy.x + 'px'; 285 | div.style.top = xy.y + 'px'; 286 | }; 287 | 288 | /** 289 | * Close the editor, save the results, and dispose of the editable 290 | * text field's elements. 291 | * @return {!Function} Closure to call on destruction of the WidgetDiv. 292 | * @private 293 | */ 294 | Blockly.FieldTextArea.prototype.widgetDispose_ = function() { 295 | var thisField = this; 296 | return function() { 297 | var htmlInput = Blockly.FieldTextArea.htmlInput_; 298 | // Save the edit (if it validates). 299 | var text = htmlInput.value; 300 | if (thisField.changeHandler_) { 301 | text = thisField.changeHandler_(text); 302 | if (text === null) { 303 | // Invalid edit. 304 | text = htmlInput.defaultValue; 305 | } 306 | } 307 | thisField.setText(text); 308 | thisField.sourceBlock_.rendered && thisField.sourceBlock_.render(); 309 | Blockly.unbindEvent_(htmlInput.onKeyUpWrapper_); 310 | Blockly.unbindEvent_(htmlInput.onKeyPressWrapper_); 311 | Blockly.unbindEvent_(htmlInput.onWorkspaceChangeWrapper_); 312 | Blockly.FieldTextArea.htmlInput_ = null; 313 | // Delete the width property. 314 | Blockly.WidgetDiv.DIV.style.width = 'auto'; 315 | }; 316 | }; 317 | 318 | 319 | -------------------------------------------------------------------------------- /blockly/javascript_compressed.js: -------------------------------------------------------------------------------- 1 | // Do not edit this file; automatically generated by build.py. 2 | "use strict"; 3 | 4 | 5 | // Copyright 2012 Google Inc. Apache License 2.0 6 | Blockly.JavaScript=new Blockly.Generator("JavaScript");Blockly.JavaScript.addReservedWords("Blockly,break,case,catch,continue,debugger,default,delete,do,else,finally,for,function,if,in,instanceof,new,return,switch,this,throw,try,typeof,var,void,while,with,class,enum,export,extends,import,super,implements,interface,let,package,private,protected,public,static,yield,const,null,true,false,Array,ArrayBuffer,Boolean,Date,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Error,eval,EvalError,Float32Array,Float64Array,Function,Infinity,Int16Array,Int32Array,Int8Array,isFinite,isNaN,Iterator,JSON,Math,NaN,Number,Object,parseFloat,parseInt,RangeError,ReferenceError,RegExp,StopIteration,String,SyntaxError,TypeError,Uint16Array,Uint32Array,Uint8Array,Uint8ClampedArray,undefined,uneval,URIError,applicationCache,closed,Components,content,_content,controllers,crypto,defaultStatus,dialogArguments,directories,document,frameElement,frames,fullScreen,globalStorage,history,innerHeight,innerWidth,length,location,locationbar,localStorage,menubar,messageManager,mozAnimationStartTime,mozInnerScreenX,mozInnerScreenY,mozPaintCount,name,navigator,opener,outerHeight,outerWidth,pageXOffset,pageYOffset,parent,performance,personalbar,pkcs11,returnValue,screen,screenX,screenY,scrollbars,scrollMaxX,scrollMaxY,scrollX,scrollY,self,sessionStorage,sidebar,status,statusbar,toolbar,top,URL,window,addEventListener,alert,atob,back,blur,btoa,captureEvents,clearImmediate,clearInterval,clearTimeout,close,confirm,disableExternalCapture,dispatchEvent,dump,enableExternalCapture,escape,find,focus,forward,GeckoActiveXObject,getAttention,getAttentionWithCycleCount,getComputedStyle,getSelection,home,matchMedia,maximize,minimize,moveBy,moveTo,mozRequestAnimationFrame,open,openDialog,postMessage,print,prompt,QueryInterface,releaseEvents,removeEventListener,resizeBy,resizeTo,restore,routeEvent,scroll,scrollBy,scrollByLines,scrollByPages,scrollTo,setCursor,setImmediate,setInterval,setResizable,setTimeout,showModalDialog,sizeToContent,stop,unescape,updateCommands,XPCNativeWrapper,XPCSafeJSObjectWrapper,onabort,onbeforeunload,onblur,onchange,onclick,onclose,oncontextmenu,ondevicemotion,ondeviceorientation,ondragdrop,onerror,onfocus,onhashchange,onkeydown,onkeypress,onkeyup,onload,onmousedown,onmousemove,onmouseout,onmouseover,onmouseup,onmozbeforepaint,onpaint,onpopstate,onreset,onresize,onscroll,onselect,onsubmit,onunload,onpageshow,onpagehide,Image,Option,Worker,Event,Range,File,FileReader,Blob,BlobBuilder,Attr,CDATASection,CharacterData,Comment,console,DocumentFragment,DocumentType,DomConfiguration,DOMError,DOMErrorHandler,DOMException,DOMImplementation,DOMImplementationList,DOMImplementationRegistry,DOMImplementationSource,DOMLocator,DOMObject,DOMString,DOMStringList,DOMTimeStamp,DOMUserData,Entity,EntityReference,MediaQueryList,MediaQueryListListener,NameList,NamedNodeMap,Node,NodeFilter,NodeIterator,NodeList,Notation,Plugin,PluginArray,ProcessingInstruction,SharedWorker,Text,TimeRanges,Treewalker,TypeInfo,UserDataHandler,Worker,WorkerGlobalScope,HTMLDocument,HTMLElement,HTMLAnchorElement,HTMLAppletElement,HTMLAudioElement,HTMLAreaElement,HTMLBaseElement,HTMLBaseFontElement,HTMLBodyElement,HTMLBRElement,HTMLButtonElement,HTMLCanvasElement,HTMLDirectoryElement,HTMLDivElement,HTMLDListElement,HTMLEmbedElement,HTMLFieldSetElement,HTMLFontElement,HTMLFormElement,HTMLFrameElement,HTMLFrameSetElement,HTMLHeadElement,HTMLHeadingElement,HTMLHtmlElement,HTMLHRElement,HTMLIFrameElement,HTMLImageElement,HTMLInputElement,HTMLKeygenElement,HTMLLabelElement,HTMLLIElement,HTMLLinkElement,HTMLMapElement,HTMLMenuElement,HTMLMetaElement,HTMLModElement,HTMLObjectElement,HTMLOListElement,HTMLOptGroupElement,HTMLOptionElement,HTMLOutputElement,HTMLParagraphElement,HTMLParamElement,HTMLPreElement,HTMLQuoteElement,HTMLScriptElement,HTMLSelectElement,HTMLSourceElement,HTMLSpanElement,HTMLStyleElement,HTMLTableElement,HTMLTableCaptionElement,HTMLTableCellElement,HTMLTableDataCellElement,HTMLTableHeaderCellElement,HTMLTableColElement,HTMLTableRowElement,HTMLTableSectionElement,HTMLTextAreaElement,HTMLTimeElement,HTMLTitleElement,HTMLTrackElement,HTMLUListElement,HTMLUnknownElement,HTMLVideoElement,HTMLCanvasElement,CanvasRenderingContext2D,CanvasGradient,CanvasPattern,TextMetrics,ImageData,CanvasPixelArray,HTMLAudioElement,HTMLVideoElement,NotifyAudioAvailableEvent,HTMLCollection,HTMLAllCollection,HTMLFormControlsCollection,HTMLOptionsCollection,HTMLPropertiesCollection,DOMTokenList,DOMSettableTokenList,DOMStringMap,RadioNodeList,SVGDocument,SVGElement,SVGAElement,SVGAltGlyphElement,SVGAltGlyphDefElement,SVGAltGlyphItemElement,SVGAnimationElement,SVGAnimateElement,SVGAnimateColorElement,SVGAnimateMotionElement,SVGAnimateTransformElement,SVGSetElement,SVGCircleElement,SVGClipPathElement,SVGColorProfileElement,SVGCursorElement,SVGDefsElement,SVGDescElement,SVGEllipseElement,SVGFilterElement,SVGFilterPrimitiveStandardAttributes,SVGFEBlendElement,SVGFEColorMatrixElement,SVGFEComponentTransferElement,SVGFECompositeElement,SVGFEConvolveMatrixElement,SVGFEDiffuseLightingElement,SVGFEDisplacementMapElement,SVGFEDistantLightElement,SVGFEFloodElement,SVGFEGaussianBlurElement,SVGFEImageElement,SVGFEMergeElement,SVGFEMergeNodeElement,SVGFEMorphologyElement,SVGFEOffsetElement,SVGFEPointLightElement,SVGFESpecularLightingElement,SVGFESpotLightElement,SVGFETileElement,SVGFETurbulenceElement,SVGComponentTransferFunctionElement,SVGFEFuncRElement,SVGFEFuncGElement,SVGFEFuncBElement,SVGFEFuncAElement,SVGFontElement,SVGFontFaceElement,SVGFontFaceFormatElement,SVGFontFaceNameElement,SVGFontFaceSrcElement,SVGFontFaceUriElement,SVGForeignObjectElement,SVGGElement,SVGGlyphElement,SVGGlyphRefElement,SVGGradientElement,SVGLinearGradientElement,SVGRadialGradientElement,SVGHKernElement,SVGImageElement,SVGLineElement,SVGMarkerElement,SVGMaskElement,SVGMetadataElement,SVGMissingGlyphElement,SVGMPathElement,SVGPathElement,SVGPatternElement,SVGPolylineElement,SVGPolygonElement,SVGRectElement,SVGScriptElement,SVGStopElement,SVGStyleElement,SVGSVGElement,SVGSwitchElement,SVGSymbolElement,SVGTextElement,SVGTextPathElement,SVGTitleElement,SVGTRefElement,SVGTSpanElement,SVGUseElement,SVGViewElement,SVGVKernElement,SVGAngle,SVGColor,SVGICCColor,SVGElementInstance,SVGElementInstanceList,SVGLength,SVGLengthList,SVGMatrix,SVGNumber,SVGNumberList,SVGPaint,SVGPoint,SVGPointList,SVGPreserveAspectRatio,SVGRect,SVGStringList,SVGTransform,SVGTransformList,SVGAnimatedAngle,SVGAnimatedBoolean,SVGAnimatedEnumeration,SVGAnimatedInteger,SVGAnimatedLength,SVGAnimatedLengthList,SVGAnimatedNumber,SVGAnimatedNumberList,SVGAnimatedPreserveAspectRatio,SVGAnimatedRect,SVGAnimatedString,SVGAnimatedTransformList,SVGPathSegList,SVGPathSeg,SVGPathSegArcAbs,SVGPathSegArcRel,SVGPathSegClosePath,SVGPathSegCurvetoCubicAbs,SVGPathSegCurvetoCubicRel,SVGPathSegCurvetoCubicSmoothAbs,SVGPathSegCurvetoCubicSmoothRel,SVGPathSegCurvetoQuadraticAbs,SVGPathSegCurvetoQuadraticRel,SVGPathSegCurvetoQuadraticSmoothAbs,SVGPathSegCurvetoQuadraticSmoothRel,SVGPathSegLinetoAbs,SVGPathSegLinetoHorizontalAbs,SVGPathSegLinetoHorizontalRel,SVGPathSegLinetoRel,SVGPathSegLinetoVerticalAbs,SVGPathSegLinetoVerticalRel,SVGPathSegMovetoAbs,SVGPathSegMovetoRel,ElementTimeControl,TimeEvent,SVGAnimatedPathData,SVGAnimatedPoints,SVGColorProfileRule,SVGCSSRule,SVGExternalResourcesRequired,SVGFitToViewBox,SVGLangSpace,SVGLocatable,SVGRenderingIntent,SVGStylable,SVGTests,SVGTextContentElement,SVGTextPositioningElement,SVGTransformable,SVGUnitTypes,SVGURIReference,SVGViewSpec,SVGZoomAndPan"); 7 | Blockly.JavaScript.ORDER_ATOMIC=0;Blockly.JavaScript.ORDER_MEMBER=1;Blockly.JavaScript.ORDER_NEW=1;Blockly.JavaScript.ORDER_FUNCTION_CALL=2;Blockly.JavaScript.ORDER_INCREMENT=3;Blockly.JavaScript.ORDER_DECREMENT=3;Blockly.JavaScript.ORDER_LOGICAL_NOT=4;Blockly.JavaScript.ORDER_BITWISE_NOT=4;Blockly.JavaScript.ORDER_UNARY_PLUS=4;Blockly.JavaScript.ORDER_UNARY_NEGATION=4;Blockly.JavaScript.ORDER_TYPEOF=4;Blockly.JavaScript.ORDER_VOID=4;Blockly.JavaScript.ORDER_DELETE=4; 8 | Blockly.JavaScript.ORDER_MULTIPLICATION=5;Blockly.JavaScript.ORDER_DIVISION=5;Blockly.JavaScript.ORDER_MODULUS=5;Blockly.JavaScript.ORDER_ADDITION=6;Blockly.JavaScript.ORDER_SUBTRACTION=6;Blockly.JavaScript.ORDER_BITWISE_SHIFT=7;Blockly.JavaScript.ORDER_RELATIONAL=8;Blockly.JavaScript.ORDER_IN=8;Blockly.JavaScript.ORDER_INSTANCEOF=8;Blockly.JavaScript.ORDER_EQUALITY=9;Blockly.JavaScript.ORDER_BITWISE_AND=10;Blockly.JavaScript.ORDER_BITWISE_XOR=11;Blockly.JavaScript.ORDER_BITWISE_OR=12; 9 | Blockly.JavaScript.ORDER_LOGICAL_AND=13;Blockly.JavaScript.ORDER_LOGICAL_OR=14;Blockly.JavaScript.ORDER_CONDITIONAL=15;Blockly.JavaScript.ORDER_ASSIGNMENT=16;Blockly.JavaScript.ORDER_COMMA=17;Blockly.JavaScript.ORDER_NONE=99; 10 | Blockly.JavaScript.init=function(){Blockly.JavaScript.definitions_=Object.create(null);Blockly.JavaScript.functionNames_=Object.create(null);if(Blockly.Variables){Blockly.JavaScript.variableDB_?Blockly.JavaScript.variableDB_.reset():Blockly.JavaScript.variableDB_=new Blockly.Names(Blockly.JavaScript.RESERVED_WORDS_);for(var a=[],b=Blockly.Variables.allVariables(),c=0;c",GTE:">="}[a.getFieldValue("OP")],c="=="==b||"!="==b?Blockly.JavaScript.ORDER_EQUALITY:Blockly.JavaScript.ORDER_RELATIONAL,d=Blockly.JavaScript.valueToCode(a,"A",c)||"0";a=Blockly.JavaScript.valueToCode(a,"B",c)||"0";return[d+" "+b+" "+a,c]}; 39 | Blockly.JavaScript.logic_operation=function(a){var b="AND"==a.getFieldValue("OP")?"&&":"||",c="&&"==b?Blockly.JavaScript.ORDER_LOGICAL_AND:Blockly.JavaScript.ORDER_LOGICAL_OR,d=Blockly.JavaScript.valueToCode(a,"A",c);a=Blockly.JavaScript.valueToCode(a,"B",c);if(d||a){var e="&&"==b?"true":"false";d||(d=e);a||(a=e)}else a=d="false";return[d+" "+b+" "+a,c]}; 40 | Blockly.JavaScript.logic_negate=function(a){var b=Blockly.JavaScript.ORDER_LOGICAL_NOT;return["!"+(Blockly.JavaScript.valueToCode(a,"BOOL",b)||"true"),b]};Blockly.JavaScript.logic_boolean=function(a){return["TRUE"==a.getFieldValue("BOOL")?"true":"false",Blockly.JavaScript.ORDER_ATOMIC]};Blockly.JavaScript.logic_null=function(a){return["null",Blockly.JavaScript.ORDER_ATOMIC]}; 41 | Blockly.JavaScript.logic_ternary=function(a){var b=Blockly.JavaScript.valueToCode(a,"IF",Blockly.JavaScript.ORDER_CONDITIONAL)||"false",c=Blockly.JavaScript.valueToCode(a,"THEN",Blockly.JavaScript.ORDER_CONDITIONAL)||"null";a=Blockly.JavaScript.valueToCode(a,"ELSE",Blockly.JavaScript.ORDER_CONDITIONAL)||"null";return[b+" ? "+c+" : "+a,Blockly.JavaScript.ORDER_CONDITIONAL]}; 42 | // Copyright 2012 Google Inc. Apache License 2.0 43 | Blockly.JavaScript.loops={};Blockly.JavaScript.controls_repeat=function(a){var b=Number(a.getFieldValue("TIMES")),c=Blockly.JavaScript.statementToCode(a,"DO"),c=Blockly.JavaScript.addLoopTrap(c,a.id);a=Blockly.JavaScript.variableDB_.getDistinctName("count",Blockly.Variables.NAME_TYPE);return"for (var "+a+" = 0; "+a+" < "+b+"; "+a+"++) {\n"+c+"}\n"}; 44 | Blockly.JavaScript.controls_repeat_ext=function(a){var b=Blockly.JavaScript.valueToCode(a,"TIMES",Blockly.JavaScript.ORDER_ASSIGNMENT)||"0",c=Blockly.JavaScript.statementToCode(a,"DO"),c=Blockly.JavaScript.addLoopTrap(c,a.id);a="";var d=Blockly.JavaScript.variableDB_.getDistinctName("count",Blockly.Variables.NAME_TYPE),e=b;b.match(/^\w+$/)||Blockly.isNumber(b)||(e=Blockly.JavaScript.variableDB_.getDistinctName("repeat_end",Blockly.Variables.NAME_TYPE),a+="var "+e+" = "+b+";\n");return a+("for (var "+ 45 | d+" = 0; "+d+" < "+e+"; "+d+"++) {\n"+c+"}\n")};Blockly.JavaScript.controls_whileUntil=function(a){var b="UNTIL"==a.getFieldValue("MODE"),c=Blockly.JavaScript.valueToCode(a,"BOOL",b?Blockly.JavaScript.ORDER_LOGICAL_NOT:Blockly.JavaScript.ORDER_NONE)||"false",d=Blockly.JavaScript.statementToCode(a,"DO"),d=Blockly.JavaScript.addLoopTrap(d,a.id);b&&(c="!"+c);return"while ("+c+") {\n"+d+"}\n"}; 46 | Blockly.JavaScript.controls_for=function(a){var b=Blockly.JavaScript.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.JavaScript.valueToCode(a,"FROM",Blockly.JavaScript.ORDER_ASSIGNMENT)||"0",d=Blockly.JavaScript.valueToCode(a,"TO",Blockly.JavaScript.ORDER_ASSIGNMENT)||"0",e=Blockly.JavaScript.valueToCode(a,"BY",Blockly.JavaScript.ORDER_ASSIGNMENT)||"1",f=Blockly.JavaScript.statementToCode(a,"DO"),f=Blockly.JavaScript.addLoopTrap(f,a.id);if(Blockly.isNumber(c)&&Blockly.isNumber(d)&& 47 | Blockly.isNumber(e)){var g=parseFloat(c)<=parseFloat(d);a="for ("+b+" = "+c+"; "+b+(g?" <= ":" >= ")+d+"; "+b;b=Math.abs(parseFloat(e));a=(1==b?a+(g?"++":"--"):a+((g?" += ":" -= ")+b))+(") {\n"+f+"}\n")}else a="",g=c,c.match(/^\w+$/)||Blockly.isNumber(c)||(g=Blockly.JavaScript.variableDB_.getDistinctName(b+"_start",Blockly.Variables.NAME_TYPE),a+="var "+g+" = "+c+";\n"),c=d,d.match(/^\w+$/)||Blockly.isNumber(d)||(c=Blockly.JavaScript.variableDB_.getDistinctName(b+"_end",Blockly.Variables.NAME_TYPE), 48 | a+="var "+c+" = "+d+";\n"),d=Blockly.JavaScript.variableDB_.getDistinctName(b+"_inc",Blockly.Variables.NAME_TYPE),a+="var "+d+" = ",a=Blockly.isNumber(e)?a+(Math.abs(e)+";\n"):a+("Math.abs("+e+");\n"),a+="if ("+g+" > "+c+") {\n",a+=Blockly.JavaScript.INDENT+d+" = -"+d+";\n",a+="}\n",a+="for ("+b+" = "+g+";\n "+d+" >= 0 ? "+b+" <= "+c+" : "+b+" >= "+c+";\n "+b+" += "+d+") {\n"+f+"}\n";return a}; 49 | Blockly.JavaScript.controls_forEach=function(a){var b=Blockly.JavaScript.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_ASSIGNMENT)||"[]",d=Blockly.JavaScript.statementToCode(a,"DO"),d=Blockly.JavaScript.addLoopTrap(d,a.id);a=Blockly.JavaScript.variableDB_.getDistinctName(b+"_index",Blockly.Variables.NAME_TYPE);d=Blockly.JavaScript.INDENT+b+" = "+c+"["+a+"];\n"+d;return"for (var "+a+" in "+c+") {\n"+d+"}\n"}; 50 | Blockly.JavaScript.controls_flow_statements=function(a){switch(a.getFieldValue("FLOW")){case "BREAK":return"break;\n";case "CONTINUE":return"continue;\n"}throw"Unknown flow statement.";}; 51 | // Copyright 2012 Google Inc. Apache License 2.0 52 | Blockly.JavaScript.math={};Blockly.JavaScript.math_number=function(a){return[parseFloat(a.getFieldValue("NUM")),Blockly.JavaScript.ORDER_ATOMIC]}; 53 | Blockly.JavaScript.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.JavaScript.ORDER_ADDITION],MINUS:[" - ",Blockly.JavaScript.ORDER_SUBTRACTION],MULTIPLY:[" * ",Blockly.JavaScript.ORDER_MULTIPLICATION],DIVIDE:[" / ",Blockly.JavaScript.ORDER_DIVISION],POWER:[null,Blockly.JavaScript.ORDER_COMMA]}[a.getFieldValue("OP")],c=b[0],b=b[1],d=Blockly.JavaScript.valueToCode(a,"A",b)||"0";a=Blockly.JavaScript.valueToCode(a,"B",b)||"0";return c?[d+c+a,b]:["Math.pow("+d+", "+a+")",Blockly.JavaScript.ORDER_FUNCTION_CALL]}; 54 | Blockly.JavaScript.math_single=function(a){var b=a.getFieldValue("OP"),c;if("NEG"==b)return a=Blockly.JavaScript.valueToCode(a,"NUM",Blockly.JavaScript.ORDER_UNARY_NEGATION)||"0","-"==a[0]&&(a=" "+a),["-"+a,Blockly.JavaScript.ORDER_UNARY_NEGATION];a="SIN"==b||"COS"==b||"TAN"==b?Blockly.JavaScript.valueToCode(a,"NUM",Blockly.JavaScript.ORDER_DIVISION)||"0":Blockly.JavaScript.valueToCode(a,"NUM",Blockly.JavaScript.ORDER_NONE)||"0";switch(b){case "ABS":c="Math.abs("+a+")";break;case "ROOT":c="Math.sqrt("+ 55 | a+")";break;case "LN":c="Math.log("+a+")";break;case "EXP":c="Math.exp("+a+")";break;case "POW10":c="Math.pow(10,"+a+")";break;case "ROUND":c="Math.round("+a+")";break;case "ROUNDUP":c="Math.ceil("+a+")";break;case "ROUNDDOWN":c="Math.floor("+a+")";break;case "SIN":c="Math.sin("+a+" / 180 * Math.PI)";break;case "COS":c="Math.cos("+a+" / 180 * Math.PI)";break;case "TAN":c="Math.tan("+a+" / 180 * Math.PI)"}if(c)return[c,Blockly.JavaScript.ORDER_FUNCTION_CALL];switch(b){case "LOG10":c="Math.log("+a+ 56 | ") / Math.log(10)";break;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"Unknown math operator: "+b;}return[c,Blockly.JavaScript.ORDER_DIVISION]}; 57 | Blockly.JavaScript.math_constant=function(a){return{PI:["Math.PI",Blockly.JavaScript.ORDER_MEMBER],E:["Math.E",Blockly.JavaScript.ORDER_MEMBER],GOLDEN_RATIO:["(1 + Math.sqrt(5)) / 2",Blockly.JavaScript.ORDER_DIVISION],SQRT2:["Math.SQRT2",Blockly.JavaScript.ORDER_MEMBER],SQRT1_2:["Math.SQRT1_2",Blockly.JavaScript.ORDER_MEMBER],INFINITY:["Infinity",Blockly.JavaScript.ORDER_ATOMIC]}[a.getFieldValue("CONSTANT")]}; 58 | Blockly.JavaScript.math_number_property=function(a){var b=Blockly.JavaScript.valueToCode(a,"NUMBER_TO_CHECK",Blockly.JavaScript.ORDER_MODULUS)||"0",c=a.getFieldValue("PROPERTY"),d;if("PRIME"==c)return d=Blockly.JavaScript.provideFunction_("math_isPrime",["function "+Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_+"(n) {"," // https://en.wikipedia.org/wiki/Primality_test#Naive_methods"," if (n == 2 || n == 3) {"," return true;"," }"," // False if n is NaN, negative, is 1, or not whole."," // And false if n is divisible by 2 or 3.", 59 | " if (isNaN(n) || n <= 1 || n % 1 != 0 || n % 2 == 0 || n % 3 == 0) {"," return false;"," }"," // Check all the numbers of form 6k +/- 1, up to sqrt(n)."," for (var x = 6; x <= Math.sqrt(n) + 1; x += 6) {"," if (n % (x - 1) == 0 || n % (x + 1) == 0) {"," return false;"," }"," }"," return true;","}"])+"("+b+")",[d,Blockly.JavaScript.ORDER_FUNCTION_CALL];switch(c){case "EVEN":d=b+" % 2 == 0";break;case "ODD":d=b+" % 2 == 1";break;case "WHOLE":d=b+" % 1 == 0";break;case "POSITIVE":d= 60 | b+" > 0";break;case "NEGATIVE":d=b+" < 0";break;case "DIVISIBLE_BY":a=Blockly.JavaScript.valueToCode(a,"DIVISOR",Blockly.JavaScript.ORDER_MODULUS)||"0",d=b+" % "+a+" == 0"}return[d,Blockly.JavaScript.ORDER_EQUALITY]};Blockly.JavaScript.math_change=function(a){var b=Blockly.JavaScript.valueToCode(a,"DELTA",Blockly.JavaScript.ORDER_ADDITION)||"0";a=Blockly.JavaScript.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE);return a+" = (typeof "+a+" == 'number' ? "+a+" : 0) + "+b+";\n"}; 61 | Blockly.JavaScript.math_round=Blockly.JavaScript.math_single;Blockly.JavaScript.math_trig=Blockly.JavaScript.math_single; 62 | Blockly.JavaScript.math_on_list=function(a){var b=a.getFieldValue("OP");switch(b){case "SUM":a=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_MEMBER)||"[]";a+=".reduce(function(x, y) {return x + y;})";break;case "MIN":a=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_COMMA)||"[]";a="Math.min.apply(null, "+a+")";break;case "MAX":a=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_COMMA)||"[]";a="Math.max.apply(null, "+a+")";break;case "AVERAGE":b=Blockly.JavaScript.provideFunction_("math_mean", 63 | ["function "+Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_+"(myList) {"," return myList.reduce(function(x, y) {return x + y;}) / myList.length;","}"]);a=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_NONE)||"[]";a=b+"("+a+")";break;case "MEDIAN":b=Blockly.JavaScript.provideFunction_("math_median",["function "+Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_+"(myList) {"," var localList = myList.filter(function (x) {return typeof x == 'number';});"," if (!localList.length) return null;", 64 | " localList.sort(function(a, b) {return b - a;});"," if (localList.length % 2 == 0) {"," return (localList[localList.length / 2 - 1] + localList[localList.length / 2]) / 2;"," } else {"," return localList[(localList.length - 1) / 2];"," }","}"]);a=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_NONE)||"[]";a=b+"("+a+")";break;case "MODE":b=Blockly.JavaScript.provideFunction_("math_modes",["function "+Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_+"(values) {"," var modes = [];", 65 | " var counts = [];"," var maxCount = 0;"," for (var i = 0; i < values.length; i++) {"," var value = values[i];"," var found = false;"," var thisCount;"," for (var j = 0; j < counts.length; j++) {"," if (counts[j][0] === value) {"," thisCount = ++counts[j][1];"," found = true;"," break;"," }"," }"," if (!found) {"," counts.push([value, 1]);"," thisCount = 1;"," }"," maxCount = Math.max(thisCount, maxCount);"," }"," for (var j = 0; j < counts.length; j++) {", 66 | " if (counts[j][1] == maxCount) {"," modes.push(counts[j][0]);"," }"," }"," return modes;","}"]);a=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_NONE)||"[]";a=b+"("+a+")";break;case "STD_DEV":b=Blockly.JavaScript.provideFunction_("math_standard_deviation",["function "+Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_+"(numbers) {"," var n = numbers.length;"," if (!n) return null;"," var mean = numbers.reduce(function(x, y) {return x + y;}) / n;"," var variance = 0;", 67 | " for (var j = 0; j < n; j++) {"," variance += Math.pow(numbers[j] - mean, 2);"," }"," variance = variance / n;"," return Math.sqrt(variance);","}"]);a=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_NONE)||"[]";a=b+"("+a+")";break;case "RANDOM":b=Blockly.JavaScript.provideFunction_("math_random_list",["function "+Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_+"(list) {"," var x = Math.floor(Math.random() * list.length);"," return list[x];","}"]);a=Blockly.JavaScript.valueToCode(a, 68 | "LIST",Blockly.JavaScript.ORDER_NONE)||"[]";a=b+"("+a+")";break;default:throw"Unknown operator: "+b;}return[a,Blockly.JavaScript.ORDER_FUNCTION_CALL]};Blockly.JavaScript.math_modulo=function(a){var b=Blockly.JavaScript.valueToCode(a,"DIVIDEND",Blockly.JavaScript.ORDER_MODULUS)||"0";a=Blockly.JavaScript.valueToCode(a,"DIVISOR",Blockly.JavaScript.ORDER_MODULUS)||"0";return[b+" % "+a,Blockly.JavaScript.ORDER_MODULUS]}; 69 | Blockly.JavaScript.math_constrain=function(a){var b=Blockly.JavaScript.valueToCode(a,"VALUE",Blockly.JavaScript.ORDER_COMMA)||"0",c=Blockly.JavaScript.valueToCode(a,"LOW",Blockly.JavaScript.ORDER_COMMA)||"0";a=Blockly.JavaScript.valueToCode(a,"HIGH",Blockly.JavaScript.ORDER_COMMA)||"Infinity";return["Math.min(Math.max("+b+", "+c+"), "+a+")",Blockly.JavaScript.ORDER_FUNCTION_CALL]}; 70 | Blockly.JavaScript.math_random_int=function(a){var b=Blockly.JavaScript.valueToCode(a,"FROM",Blockly.JavaScript.ORDER_COMMA)||"0";a=Blockly.JavaScript.valueToCode(a,"TO",Blockly.JavaScript.ORDER_COMMA)||"0";return[Blockly.JavaScript.provideFunction_("math_random_int",["function "+Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_+"(a, b) {"," if (a > b) {"," // Swap a and b to ensure a is smaller."," var c = a;"," a = b;"," b = c;"," }"," return Math.floor(Math.random() * (b - a + 1) + a);", 71 | "}"])+"("+b+", "+a+")",Blockly.JavaScript.ORDER_FUNCTION_CALL]};Blockly.JavaScript.math_random_float=function(a){return["Math.random()",Blockly.JavaScript.ORDER_FUNCTION_CALL]}; 72 | // Copyright 2012 Google Inc. Apache License 2.0 73 | Blockly.JavaScript.procedures={}; 74 | Blockly.JavaScript.procedures_defreturn=function(a){var b=Blockly.JavaScript.variableDB_.getName(a.getFieldValue("NAME"),Blockly.Procedures.NAME_TYPE),c=Blockly.JavaScript.statementToCode(a,"STACK");Blockly.JavaScript.STATEMENT_PREFIX&&(c=Blockly.JavaScript.prefixLines(Blockly.JavaScript.STATEMENT_PREFIX.replace(/%1/g,"'"+a.id+"'"),Blockly.JavaScript.INDENT)+c);Blockly.JavaScript.INFINITE_LOOP_TRAP&&(c=Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+a.id+"'")+c);var d=Blockly.JavaScript.valueToCode(a, 75 | "RETURN",Blockly.JavaScript.ORDER_NONE)||"";d&&(d=" return "+d+";\n");for(var e=[],f=0;f 2 | 3 | 4 | 40 | 41 | 42 | 76 | 77 | 78 | 79 | 83 |
84 | 85 |
86 | 87 | 88 | -------------------------------------------------------------------------------- /circuit.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espruino/EspruinoOrion/acd47b1e331fc30a8deae9a5ebcd2b44be8d9d7e/circuit.fzz -------------------------------------------------------------------------------- /circuit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espruino/EspruinoOrion/acd47b1e331fc30a8deae9a5ebcd2b44be8d9d7e/circuit.png -------------------------------------------------------------------------------- /circuit_single.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espruino/EspruinoOrion/acd47b1e331fc30a8deae9a5ebcd2b44be8d9d7e/circuit_single.fzz -------------------------------------------------------------------------------- /circuit_single.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espruino/EspruinoOrion/acd47b1e331fc30a8deae9a5ebcd2b44be8d9d7e/circuit_single.png -------------------------------------------------------------------------------- /colour_chooser.html: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 28 | 29 | 30 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /data/terminal_initial.html: -------------------------------------------------------------------------------- 1 |

Hello.

2 | -------------------------------------------------------------------------------- /ide.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Espruino IDE to Orion Link 5 | 6 | 7 | 20 | 21 | 22 | 23 |

Great! Keep this window open, and when you click 'Send to Espruino' from the Orion plugin, your code will be loaded into the Web IDE.

24 | 25 | 26 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Terminal 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 81 | 82 | 83 | 84 | 86 |
87 |
88 |
89 |
90 |
91 | RX Polarity
92 | TX Polarity
93 |
94 | 95 | 96 | -------------------------------------------------------------------------------- /plugin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 23 | 24 | 25 |

Espruino Orion Plugin

26 |
    27 |
  • Add this plugin to Orion
  • 28 |
  • Open https://www.espruino.com/orion in a separate window
  • 29 |
  • Press Ctrl+Shift+R to program Espruino
  • 30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /plugin.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * @license 3 | * Copyright (c) 2011, 2014 IBM Corporation and others. 4 | * All rights reserved. This program and the accompanying materials are made 5 | * available under the terms of the Eclipse Public License v1.0 6 | * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 7 | * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 8 | * 9 | * Contributors: 10 | * IBM Corporation - initial API and implementation 11 | *******************************************************************************/ 12 | /*eslint-env browser, amd, node*/ 13 | (function(root, factory) { // UMD 14 | if (typeof define === "function" && define.amd) { //$NON-NLS-0$ 15 | define(["orion/Deferred"], factory); 16 | } else if (typeof exports === "object") { //$NON-NLS-0$ 17 | module.exports = factory(require("orion/Deferred")); 18 | } else { 19 | root.orion = root.orion || {}; 20 | root.orion.PluginProvider = factory(root.orion.Deferred); 21 | } 22 | }(this, function(Deferred) { 23 | function ObjectReference(objectId, methods) { 24 | this.__objectId = objectId; 25 | this.__methods = methods; 26 | } 27 | 28 | function PluginProvider(headers) { 29 | var _headers = headers; 30 | var _connected = false; 31 | var _target = null; 32 | 33 | var _currentMessageId = 0; 34 | var _currentObjectId = 0; 35 | var _currentServiceId = 0; 36 | 37 | var _requestReferences = {}; 38 | var _responseReferences = {}; 39 | var _objectReferences = {}; 40 | var _serviceReferences = {}; 41 | 42 | function _publish(message) { 43 | if (_target) { 44 | if (typeof(ArrayBuffer) === "undefined") { //$NON-NLS-0$ 45 | message = JSON.stringify(message); 46 | } 47 | if (_target === self) { 48 | _target.postMessage(message); 49 | } else { 50 | _target.postMessage(message, "*"); //$NON-NLS-0$ 51 | } 52 | } 53 | } 54 | var _notify = _publish; 55 | 56 | function _getPluginData() { 57 | var services = []; 58 | // we filter out the service implementation from the data 59 | Object.keys(_serviceReferences).forEach(function(serviceId) { 60 | var serviceReference = _serviceReferences[serviceId]; 61 | services.push({ 62 | serviceId: serviceId, 63 | names: serviceReference.names, 64 | methods: serviceReference.methods, 65 | properties: serviceReference.properties 66 | }); 67 | }); 68 | return { 69 | headers: _headers || {}, 70 | services: services 71 | }; 72 | } 73 | 74 | function _jsonXMLHttpRequestReplacer(name, value) { 75 | if (value && value instanceof XMLHttpRequest) { 76 | var status, statusText; 77 | try { 78 | status = value.status; 79 | statusText = value.statusText; 80 | } catch (e) { 81 | // https://bugs.webkit.org/show_bug.cgi?id=45994 82 | status = 0; 83 | statusText = ""; //$NON-NLS-0 84 | } 85 | return { 86 | status: status || 0, 87 | statusText: statusText 88 | }; 89 | } 90 | return value; 91 | } 92 | 93 | function _serializeError(error) { 94 | var result = error ? JSON.parse(JSON.stringify(error, _jsonXMLHttpRequestReplacer)) : error; // sanitizing Error object 95 | if (error instanceof Error) { 96 | result.__isError = true; 97 | result.message = result.message || error.message; 98 | result.name = result.name || error.name; 99 | } 100 | return result; 101 | } 102 | 103 | function _request(message) { 104 | if (!_target) { 105 | return new Deferred().reject(new Error("plugin not connected")); 106 | } 107 | 108 | message.id = String(_currentMessageId++); 109 | var d = new Deferred(); 110 | _responseReferences[message.id] = d; 111 | d.then(null, function(error) { 112 | if (_connected && error instanceof Error && error.name === "Cancel") { 113 | _notify({ 114 | requestId: message.id, 115 | method: "cancel", 116 | params: error.message ? [error.message] : [] 117 | }); 118 | } 119 | }); 120 | 121 | var toString = Object.prototype.toString; 122 | message.params.forEach(function(param, i) { 123 | if (toString.call(param) === "[object Object]" && !(param instanceof ObjectReference)) { 124 | var candidate, methods; 125 | for (candidate in param) { 126 | if (toString.call(param[candidate]) === "[object Function]") { 127 | methods = methods || []; 128 | methods.push(candidate); 129 | } 130 | } 131 | if (methods) { 132 | var objectId = _currentObjectId++; 133 | _objectReferences[objectId] = param; 134 | var removeReference = function() { 135 | delete _objectReferences[objectId]; 136 | }; 137 | d.then(removeReference, removeReference); 138 | message.params[i] = new ObjectReference(objectId, methods); 139 | } 140 | } 141 | }); 142 | _notify(message); 143 | return d.promise; 144 | } 145 | 146 | function _throwError(messageId, error) { 147 | if (messageId || messageId === 0) { 148 | _notify({ 149 | id: messageId, 150 | result: null, 151 | error: error 152 | }); 153 | } else { 154 | console.log(error); 155 | } 156 | 157 | } 158 | 159 | function _callMethod(messageId, implementation, method, params) { 160 | params.forEach(function(param, i) { 161 | if (param && typeof param.__objectId !== "undefined") { 162 | var obj = {}; 163 | param.__methods.forEach(function(method) { 164 | obj[method] = function() { 165 | return _request({ 166 | objectId: param.__objectId, 167 | method: method, 168 | params: Array.prototype.slice.call(arguments) 169 | }); 170 | }; 171 | }); 172 | params[i] = obj; 173 | } 174 | }); 175 | var response = typeof messageId === undefined ? null : { 176 | id: messageId, 177 | result: null, 178 | error: null 179 | }; 180 | try { 181 | var promiseOrResult = method.apply(implementation, params); 182 | if (!response) { 183 | return; 184 | } 185 | 186 | if (promiseOrResult && typeof promiseOrResult.then === "function") { //$NON-NLS-0$ 187 | _requestReferences[messageId] = promiseOrResult; 188 | promiseOrResult.then(function(result) { 189 | delete _requestReferences[messageId]; 190 | response.result = result; 191 | _notify(response); 192 | }, function(error) { 193 | if (_requestReferences[messageId]) { 194 | delete _requestReferences[messageId]; 195 | response.error = _serializeError(error); 196 | _notify(response); 197 | } 198 | }, function() { 199 | _notify({ 200 | responseId: messageId, 201 | method: "progress", 202 | params: Array.prototype.slice.call(arguments) 203 | }); //$NON-NLS-0$ 204 | }); 205 | } else { 206 | response.result = promiseOrResult; 207 | _notify(response); 208 | } 209 | } catch (error) { 210 | if (response) { 211 | response.error = _serializeError(error); 212 | _notify(response); 213 | } 214 | } 215 | } 216 | 217 | function _handleMessage(event) { 218 | if (event.source !== _target && typeof window !== "undefined") { 219 | return; 220 | } 221 | var message = (typeof event.data !== "string" ? event.data : JSON.parse(event.data)); //$NON-NLS-0$ 222 | try { 223 | if (message.method) { // request 224 | var method = message.method, 225 | params = message.params || []; 226 | if ("serviceId" in message) { 227 | var service = _serviceReferences[message.serviceId]; 228 | if (!service) { 229 | _throwError(message.id, "service not found"); 230 | } 231 | service = service.implementation; 232 | if (method in service) { 233 | _callMethod(message.id, service, service[method], params); 234 | } else { 235 | _throwError(message.id, "method not found"); 236 | } 237 | } else if ("objectId" in message) { 238 | var object = _objectReferences[message.objectId]; 239 | if (!object) { 240 | _throwError(message.id, "object not found"); 241 | } 242 | if (!method in object) { 243 | _callMethod(message.id, object, object[method], params); 244 | } else { 245 | _throwError(message.id, "method not found"); 246 | } 247 | } else if ("requestId" in message) { 248 | var request = _requestReferences[message.requestId]; 249 | if (request && method === "cancel" && request.cancel) { 250 | request.cancel.apply(request, params); 251 | } 252 | } else if ("responseId" in message) { 253 | var response = _responseReferences[message.responseId]; 254 | if (response && method === "progress" && response.progress) { 255 | response.progress.apply(response, params); 256 | } 257 | } else { 258 | throw new Error("Bad method: " + message.method); 259 | } 260 | } else { 261 | var deferred = _responseReferences[String(message.id)]; 262 | delete _responseReferences[String(message.id)]; 263 | if (message.error) { 264 | deferred.reject(message.error); 265 | } else { 266 | deferred.resolve(message.result); 267 | } 268 | } 269 | } catch (e) { 270 | console.log("Plugin._messageHandler " + e); 271 | } 272 | } 273 | 274 | this.updateHeaders = function(headers) { 275 | if (_connected) { 276 | throw new Error("Cannot update headers. Plugin Provider is connected"); 277 | } 278 | _headers = headers; 279 | }; 280 | 281 | this.registerService = function(names, implementation, properties) { 282 | if (_connected) { 283 | throw new Error("Cannot register service. Plugin Provider is connected"); 284 | } 285 | 286 | if (typeof names === "string") { 287 | names = [names]; 288 | } else if (!Array.isArray(names)) { 289 | names = []; 290 | } 291 | 292 | var method = null; 293 | var methods = []; 294 | for (method in implementation) { 295 | if (typeof implementation[method] === 'function') { //$NON-NLS-0$ 296 | methods.push(method); 297 | } 298 | } 299 | _serviceReferences[_currentServiceId++] = { 300 | names: names, 301 | methods: methods, 302 | implementation: implementation, 303 | properties: properties || {}, 304 | listeners: {} 305 | }; 306 | }; 307 | this.registerServiceProvider = this.registerService; 308 | 309 | this.connect = function(callback, errback) { 310 | if (_connected) { 311 | if (callback) { 312 | callback(); 313 | } 314 | return; 315 | } 316 | 317 | if (typeof(window) === "undefined") { //$NON-NLS-0$ 318 | _target = self; 319 | } else if (window !== window.parent) { 320 | _target = window.parent; 321 | } else if (window.opener !== null) { 322 | _target = window.opener; 323 | } else { 324 | if (errback) { 325 | errback("No valid plugin target"); 326 | } 327 | return; 328 | } 329 | addEventListener("message", _handleMessage, false); //$NON-NLS-0$ 330 | var message = { 331 | method: "plugin", //$NON-NLS-0$ 332 | params: [_getPluginData()] 333 | }; 334 | _publish(message); 335 | _connected = true; 336 | if (callback) { 337 | callback(); 338 | } 339 | }; 340 | 341 | this.disconnect = function() { 342 | if (_connected) { 343 | removeEventListener("message", _handleMessage); //$NON-NLS-0$ 344 | _target = null; 345 | _connected = false; 346 | } 347 | // Note: re-connecting is not currently supported 348 | }; 349 | } 350 | return PluginProvider; 351 | })); -------------------------------------------------------------------------------- /serial_to_audio.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Espruino, a JavaScript interpreter for Microcontrollers 3 | * 4 | * Copyright (C) 2013 Gordon Williams 5 | * 6 | * This Source Code Form is subject to the terms of the Mozilla Public 7 | * License, v. 2.0. If a copy of the MPL was not distributed with this 8 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 | */ 10 | 11 | var AudioContext = window.AudioContext || window.webkitAudioContext; 12 | var context = new AudioContext(); 13 | 14 | // some devices output an inverted waveform, some don't 15 | var audio_serial_invert = false; 16 | 17 | /** Send the given string of data out over audio. 18 | 19 | This adds a 1 second preamble/postable to give the 20 | capacitor time to charge (so we get a full 2V swing 21 | on the output. 22 | 23 | If you send characters outside the range 0-255, 24 | they will be interpreted as a break (so not transmitted). 25 | */ 26 | function audio_serial_write(data, callback) { 27 | var sampleRate = 44100; 28 | var header = sampleRate; // 1 sec to charge/discharge the cap 29 | var baud = 9600; 30 | var samplesPerByte = parseInt(sampleRate*11/baud); 31 | var bufferSize = samplesPerByte*data.length/*samples*/ + header*2; 32 | var buffer = context.createBuffer(1, bufferSize, sampleRate); 33 | var b = buffer.getChannelData(0); 34 | 35 | for (var i=0;i=0 && byte<=255) { 42 | for (var i=0;i 2 | 3 | 4 | Terminal 5 | 6 | 7 | 8 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | --------------------------------------------------------------------------------