<snapdata remixID="12"><project name="RIAC Sound Levels" app="Snap! 9.0, https://snap.berkeley.edu" version="2"><notes>Created By Li and Ben. This application explores looking at sound levels and clones.</notes><thumbnail>data:image/png;base64,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</thumbnail><scenes select="1"><scene name="RIAC Sound Levels"><notes>Created By Li and Ben. This application explores looking at sound levels and clones.</notes><palette><category name="RIAC" color="216,45,45,1"/><category name="eBrain" color="33,33,33,1"/><category name="Advanced eBrain" color="0,116,143,1"/><category name="Servo Robot" color="187,5,255,1"/></palette><hidden></hidden><headers></headers><code></code><blocks><block-definition s="Set wheel diameter: %&apos;diameter&apos; mm and wheel distance: %&apos;distance&apos; mm" type="command" category="eBrain"><header></header><code></code><translations>fr:Mettre le diamètre de la roue à: _ mm et la distance entre les roues à: _ mm&#xD;</translations><inputs><input type="%s">81</input><input type="%s">108.5</input></inputs><script><block s="doIfElse"><custom-block s="version is at least %s"><l>3.3.1</l></custom-block><script><block s="doRun"><block s="reportJSFunction"><list><l>diameter</l><l>distance</l><l>eb</l></list><l>world.moveon = 0;&#xD;eb.setWheelDimensions(diameter, distance, function(state, msg){&#xD;  if (state == &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><block var="diameter"/><block var="distance"/><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block></script><script><block s="doRun"><block s="reportJSFunction"><list></list><l>morphicAlert("Error!", "Your eBrain must be at least at firmware version 3.3.1 to use this block");</l></block><list></list></block></script></block></script></block-definition><block-definition s="Get eBrain version" type="reporter" category="other"><header></header><code></code><translations>fr:Obtenir la version du eBrain&#xD;</translations><inputs></inputs><script><block s="doIf"><block s="evaluate"><block s="reportJSFunction"><list><l>eb</l></list><l>return !!eb.eBrainVersion</l></block><list><custom-block s="connection object"></custom-block></list></block><script><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l>eb</l></list><l>return eb.eBrainVersion;</l></block><list><custom-block s="connection object"></custom-block></list></block></block></script><list></list></block><block s="doRun"><block s="reportJSFunction"><list><l>eb</l></list><l>world.moveon = 0;&#xD;eb.getVersion(function(state, msg){&#xD;  if (state === &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list></list><l>return world.moveon;</l></block><list></list></block></block><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l>eb</l></list><l>return eb.eBrainVersion;</l></block><list><custom-block s="connection object"></custom-block></list></block></block></script></block-definition><block-definition s="version is at least %&apos;version&apos;" type="reporter" category="other"><header></header><code></code><translations>fr:La version est au moins _&#xD;</translations><inputs><input type="%s"></input></inputs><script><block s="doDeclareVariables"><list><l>ebVersion</l><l>target version</l></list></block><block s="doSetVar"><l>ebVersion</l><block s="reportTextSplit"><custom-block s="Get eBrain version"></custom-block><l>.</l></block></block><block s="doSetVar"><l>target version</l><block s="reportTextSplit"><block var="version"/><l>.</l></block></block><block s="doFor"><l>i</l><l>1</l><l>3</l><script><block s="doIfElse"><block s="reportVariadicGreaterThan"><list><block s="reportListItem"><block var="i"/><block var="ebVersion"/></block><block s="reportListItem"><block var="i"/><block var="target version"/></block></list></block><script><block s="doReport"><block s="reportBoolean"><l><bool>true</bool></l></block></block></script><script><block s="doIf"><block s="reportVariadicLessThan"><list><block s="reportListItem"><block var="i"/><block var="ebVersion"/></block><block s="reportListItem"><block var="i"/><block var="target version"/></block></list></block><script><block s="doReport"><block s="reportBoolean"><l><bool>false</bool></l></block></block></script><list></list></block></script></block></script></block><block s="doReport"><block s="reportBoolean"><l><bool>true</bool></l></block></block></script></block-definition><block-definition s="connect to IP %&apos;ip&apos;" type="command" category="other"><header></header><code></code><translations>fr:se connecter à l&apos;adresse IP _&#xD;</translations><inputs><input type="%s"></input></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l></l></list><block s="reportJoinWords"><list><l>if (eb == undefined ) {eb = new EveBrain(&apos;ws://</l><block var="ip"/><l>:8899/websocket&apos;);&#xD;console.log(eb.connected);&#xD;} else {&#xD;if (eb.connected == false) {&#xD;eb.url= "ws://</l><block var="ip"/><l>:8899/websocket";  eb.initializeAndConnect();}}</l></list></block></block><list></list></block><block s="doRun"><block s="reportJSFunction"><list><l></l></list><l>ebUSB = undefined; // signal not connected by usb</l></block><list></list></block></script></block-definition><block-definition s="connect USB" type="command" category="other"><header></header><code></code><translations>fr:se connecter par USB&#xD;</translations><inputs></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l></l></list><l>eb = undefined; // signal that not connected by wifi&#xD;USBconnect().then(function() {&#xD;  world.moveon = 1;&#xD;}).catch(function(s) {&#xD;  if (SnapTranslator.language.startsWith(&apos;fr&apos;)) {&#xD;    morphicAlert("Échec de la connexion USB!",&#xD;      "Échec de la connexion USB.",&#xD;      "Assure-toi de sélectionner un port quand la fenêtre apparaît");&#xD;  } else {&#xD;    morphicAlert("USB Connection Failed!",&#xD;      "Connection to robot by USB failed.",&#xD;      "Make sure to select a port when the window shows up.");&#xD;  }&#xD;  world.moveon = -1;&#xD;});&#xD;&#xD;ebUSB = new EveBrainUSB();</l></block><list></list></block></script></block-definition><block-definition s="connected" type="reporter" category="other"><header></header><code></code><translations>fr:connecté&#xD;</translations><inputs></inputs><script><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>&#xD;try {&#xD;  if ((eb != undefined ? eb.connected : false) || (ebUSB != undefined ? ebUSB.connected : false)){&#xD;    return true; &#xD;  } else {&#xD;    return false;&#xD;  }&#xD;} catch(e) {&#xD;  return false;&#xD;}</l></block><list></list></block></block></script></block-definition><block-definition s="test connection" type="command" category="other"><header></header><code></code><translations>fr:tester la connexion&#xD;</translations><inputs></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l></l></list><l>try {&#xD;  if ((eb != undefined ? eb.connected : false) || (ebUSB != undefined)){&#xD;    //it thinks its connected over websock, let&apos;s test the connection&#xD;   if (eb != undefined ? eb.connected : false) {&#xD;     eb.connected = false;&#xD;     eb.version(function(status,msg){eb.connected = true;});&#xD;   } else {&#xD;     //it thinks we are connected over USB&#xD;     ebUSB.testConnection();&#xD;   } &#xD;  }&#xD;} catch(e) {&#xD;  console.log(e);&#xD;}</l></block><list></list></block></script></block-definition><block-definition s="Connect to eBrain %&apos;ip&apos;" type="command" category="RIAC"><header></header><code></code><translations>fr:Se connecter au eBrain _&#xD;</translations><inputs><input type="%s">USB<options>USB&#xD;WIFI =192.168.4.1</options></input></inputs><script><block s="doIf"><block s="reportNot"><custom-block s="world modified"></custom-block></block><script><custom-block s="addJS %s"><custom-block s="eBrainJS"></custom-block></custom-block><block s="doRun"><block s="reportJSFunction"><list><l></l></list><l>world.modified = 1;</l></block><list></list></block></script><list></list></block><custom-block s="test connection"></custom-block><block s="doWait"><l>0.1</l></block><block s="doIf"><block s="reportNot"><custom-block s="connected"></custom-block></block><script><block s="doIfElse"><block s="reportVariadicEquals"><list><block var="ip"/><l>USB</l></list></block><script><block s="doIfElse"><custom-block s="can use webserial"></custom-block><script><block s="doRun"><block s="reportJSFunction"><list><l></l></list><l>world.port = &apos;&apos;;&#xD;world.moveon = 0;</l></block><list></list></block><custom-block s="connect USB"></custom-block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block><block s="doIf"><block s="reportVariadicEquals"><list><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block><l>-1</l></list></block><script><block s="doStopThis"><l><option>this block</option></l></block></script><list></list></block></script><script><block s="doRun"><block s="reportJSFunction"><list><l></l></list><l>if (SnapTranslator.language.startsWith(&apos;fr&apos;)) {&#xD;  morphicAlert("ERREUR!", "ERREUR! Cet appareil sur ce navigateur ne peut pas utiliser une connexion USB!",&#xD;  "Note spéciale: si tu es sur snap.robotinacan.com et tu veux une connexion USB, s&apos;il vous plaît changer le http à https  dans la barre d&apos;URL");&#xD;} else {&#xD;  morphicAlert("ERROR!", "ERROR! This device on this browser cannot use a USB connection!",&#xD;   "Special note: if you are on snap.robotinacan.com and you wish to connect using USB please change http to https in the URL bar");&#xD;}</l></block><list></list></block><block s="doStopThis"><l><option>this block</option></l></block></script></block></script><script><block s="doIfElse"><custom-block s="can use unsecure websocket"></custom-block><script><block s="doIfElse"><block var="ip"/><script><custom-block s="connect to IP %s"><block var="ip"/></custom-block></script><script><custom-block s="connect"></custom-block></script></block></script><script><block s="doRun"><block s="reportJSFunction"><list><l></l></list><l>if (SnapTranslator.language.startsWith(&apos;fr&apos;)) {&#xD;  morphicAlert("ERREUR!", "ERREUR! Cet appareil sur ce navigateur ne peut pas utiliser une connexion WiFi!",&#xD;  "Note spéciale: si tu es sur snap.robotinacan.com et tu veux une connexion WiFi s&apos;il vous plaît changer https à http dans la barre d&apos;URL");&#xD;} else {&#xD;  morphicAlert("ERROR!", "ERROR! This device on this browser cannot use a WiFi connection!",&#xD;  "Special note: if you are on snap.robotinacan.com and you wish to connect using WiFi please change https to http in the titlebar");&#xD;}</l></block><list></list></block><block s="doStopThis"><l><option>this block</option></l></block></script></block></script></block><custom-block s="test connection"></custom-block><block s="doWait"><l>0.3</l></block><block s="doIf"><block s="reportNot"><custom-block s="connected"></custom-block></block><script><custom-block s="test connection"></custom-block><block s="doWait"><l>0.3</l></block><block s="doIf"><block s="reportNot"><custom-block s="connected"></custom-block></block><script><block s="doIfElse"><block s="reportVariadicAnd"><list><custom-block s="can use unsecure websocket"></custom-block><block s="reportNot"><custom-block s="can use webserial"></custom-block></block></list></block><script><block s="doRun"><block s="reportJSFunction"><list><l></l></list><l>if (SnapTranslator.language.startsWith(&apos;fr&apos;)) {&#xD;  morphicAlert("Problème de connexion!",&#xD;  "Problème de connexion!",&#xD;  "Assure-toi que tu tentes de te connecter avec WiFi, cet appareil ne peut utiliser les ports USB",&#xD;  "Note spéciale: si tu es sur snap.robotinacan.com et tu veux une connexion USB, s&apos;il vous plaît changer http à https dans la barre d&apos;URL");&#xD;} else {&#xD;  morphicAlert("Connection Failure!", &#xD;  "Connection Failure!",&#xD;  "Ensure you are connected to the eBrain over WiFi, this device cannot use the USB port.",&#xD;  "Special note: if you are on snap.robotinacan.com and want to connect over USB, go to the https version.", "See Help for more details");&#xD;}</l></block><list></list></block></script><script><block s="doIfElse"><block s="reportVariadicAnd"><list><custom-block s="can use webserial"></custom-block><block s="reportNot"><custom-block s="can use unsecure websocket"></custom-block></block></list></block><script><block s="doRun"><block s="reportJSFunction"><list><l></l></list><l>if (SnapTranslator.language.startsWith(&apos;fr&apos;)) {&#xD;  morphicAlert("Problème de connexion!",&#xD;  "Assure-toi que tu tentes de te connecter avec USB, cet appareil sur ce navigateur peut seulement utiliser USB",&#xD;  "Note spéciale: si tu es sur snap.robotinacan.com et tu veux une connexion WiFi, s&apos;il vous plaît changer le https à http dans la barre d&apos;URL");&#xD;} else {&#xD;  morphicAlert("Connection Failure!", "Connection Failure! Please ensure you have connected to the right USB port.",&#xD;  "Ensure you are connected to the eBrain over USB, this device on this browser can only connect over USB.",&#xD;  "Special note: if you are on snap.robotinacan.com and you wish to connect using WiFi please change https to http in the titlebar.");&#xD;}</l></block><list></list></block></script><script><block s="doIfElse"><block s="reportVariadicAnd"><list><custom-block s="can use webserial"></custom-block><custom-block s="can use unsecure websocket"></custom-block></list></block><script><block s="doRun"><block s="reportJSFunction"><list><l></l></list><l>if (SnapTranslator.language.startsWith(&apos;fr&apos;)) {&#xD;  morphicAlert("Échec de connexion!", "Échec de connexion!",&#xD;  "Dans ce mode tu peux connecter par USB ou WiFi",&#xD;  "Tapez USB pour une connexion USB ou tapez l&apos;addresse IP pour utiliser WiFi");&#xD;} else {&#xD;  morphicAlert("Connection Failure!", "Connection failed!",&#xD;  "In this mode you may connect via USB or over WiFi",&#xD;  "Please type the IP address to use WiFi or type USB to use the USB port");&#xD;}</l></block><list></list></block></script><script><block s="doRun"><block s="reportJSFunction"><list><l></l></list><l>if (SnapTranslator.language.startsWith(&apos;fr&apos;)) {&#xD;  morphicAlert("Échec de connexion!", "Échec de connexion!",&#xD;  "Snap n&apos;a détecté aucune méthode pour connecter au eBrain. Recharge la page ou ferme et repart Snap.");&#xD;} else {&#xD;  morphicAlert("Connection Failure!", "Connection Failure!",&#xD;  "Snap was unable to detect any method of connecting to the eBrain. Try reloading or closing and opening Snap.");&#xD;}</l></block><list></list></block></script></block></script></block></script></block></script><list></list><comment w="90" collapsed="false">Signal to user connection failure</comment></block></script><list></list></block></script><list></list></block></script></block-definition><block-definition s="eBrainJS" type="reporter" category="other"><header></header><code></code><translations></translations><inputs></inputs><script><block s="doReport"><l>var escapable = /[\x00-\x1f\ud800-\udfff\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufff0-\uffff]/g;&#xD;var attempts = 0;&#xD;var eb;&#xD;var ebUSB;&#xD;// this is used by some RIAC Snap blocks to send a signal to snap when&#xD;// they are done waiting.&#xD;world.moveons = {};&#xD;&#xD;function filterUnicode(quoted){&#xD;&#xD;  escapable.lastIndex = 0;&#xD;  if( !escapable.test(quoted)) return quoted;&#xD;&#xD;  return quoted.replace( escapable, function(a){&#xD;    return &apos;&apos;;&#xD;  });&#xD;}&#xD;&#xD;/**&#xD; * ParentEveBrain has the movement functions (move, turn,&#xD; * forward, etc) and digitalInput. These functions then &#xD; * call the send function, which subclasses need to define.&#xD; * Methods required to implement: send_msg.&#xD; * &#xD; * NOTE: the API for callbacks here is: state (usually started &#xD; * or complete), message (the returned message from the robot), optional.&#xD; * Optional is not passed usually, so it is undefined (except when stop() is used).&#xD; */&#xD;var ParentEveBrain = function() {&#xD;  this.digitalSensor = [];&#xD;  this.robot_state = &apos;idle&apos;;&#xD;  this.cbs = {};&#xD;  this.msg_stack = [];&#xD;  this.analogSensor = {level: null};&#xD;  this.distanceSensor = {level: null};&#xD;  this.tempSensor = {level: null};&#xD;  this.humidSensor = {level: null};&#xD;  this.compassSensor = {x: null, y: null, z: null};&#xD;  this.config = null;&#xD;  this.sensorState = {};&#xD;  this.eBrainVersion = null;&#xD;  this.lastPausedState = null;&#xD;}&#xD;&#xD;ParentEveBrain.prototype = {&#xD;  constructor: ParentEveBrain,&#xD;&#xD;  /**&#xD;   * Deals with the callback, and queues up the message to be sent to ebrain.&#xD;   * If the command is not &apos;important&apos; (ie not &apos;stop&apos;, etc) or it is a command &#xD;   * that runs immediately, like &apos;pinServo&apos;, it is queued up.&#xD;   * The subclasses must call process_msg_queue when the robot is idle to&#xD;   * make sure queued messages are indeed sent, and must shift() the queue once &#xD;   * a response is received.&#xD;   * @param msg Message to send&#xD;   * @param cb callback for message&#xD;   */&#xD;  send: function(msg, cb){&#xD;    msg = filterUnicode(msg);&#xD;    msg.id = Math.random().toString(36).substring(2, 12);&#xD;    if(cb){&#xD;      this.cbs[msg.id] = cb;&#xD;    }&#xD;    if(msg.arg &amp;&amp; msg.arg.toString() != &apos;[object Object]&apos;) {&#xD;      msg.arg = msg.arg.toString();&#xD;    }&#xD;    if([&apos;stop&apos;, &apos;pause&apos;, &apos;resume&apos;, &apos;ping&apos;, &apos;version&apos;, &apos;pinServo&apos;].indexOf(msg.cmd) &gt;= 0){&#xD;      this.send_msg(msg);&#xD;    }else{&#xD;      this.msg_stack.push(msg);&#xD;      this.process_msg_queue();&#xD;    }&#xD;  },&#xD;&#xD;  process_msg_queue: function(){&#xD;    if(this.robot_state === &apos;idle&apos; &amp;&amp; this.msg_stack.length &gt; 0){&#xD;      this.robot_state = &apos;receiving&apos;;&#xD;      this.send_msg(this.msg_stack[0]);&#xD;    }&#xD;  },&#xD;&#xD;  clearMessagesCallbacks: function() {&#xD;    this.cbs = {};&#xD;    this.msg_stack = [];&#xD;  },&#xD;&#xD;  version: function(cb){&#xD;    this.send({cmd:&apos;version&apos;}, cb);&#xD;  },&#xD;&#xD;&#xD;  getVersion: function(cb) {&#xD;    var self = this;&#xD;    this.send({cmd:&apos;version&apos;}, function(state, msg) {&#xD;      if (state === &apos;complete&apos; &amp;&amp; undefined !== msg) {&#xD;        self.eBrainVersion = msg.msg;&#xD;      }&#xD;      cb(state, msg);&#xD;    });&#xD;  },&#xD;&#xD;  stop: function(cb){&#xD;    var self = this;&#xD;    this.send({cmd:&apos;stop&apos;}, function(state, msg, recursion){&#xD;      if(state === &apos;complete&apos; &amp;&amp; !recursion){&#xD;        for(var i in self.cbs){&#xD;          // console.log(&apos;calling callback &apos; + self.cbs[i]);&#xD;          self.cbs[i](&apos;complete&apos;, undefined, true);&#xD;        }&#xD;        self.robot_state = &apos;idle&apos;;&#xD;        cb(state, msg);&#xD;        self.clearMessagesCallbacks();&#xD;      }&#xD;    });&#xD;  },&#xD;  /**&#xD;   * Initiates wifi scan.&#xD;   * @param {function} callback Called when info on the WiFi networks is received.&#xD;   */&#xD;  wifiScan: function(callback) {&#xD;    var self = this;&#xD;    this.send({cmd: "startWifiScan"}, null); // don&apos;t need a callback when the scan has started&#xD;    this.cbs[&apos;wifiScan&apos;] = function(state, message) {&#xD;      callback(state, message); // chain given callback&#xD;    }&#xD;  },&#xD;&#xD;  connect_to_network: function(SSID, PASS, callback) {&#xD;    this.send({cmd: &apos;setConfig&apos;, arg: {sta_ssid: SSID, sta_pass: PASS}}, callback);&#xD;  },&#xD;&#xD;  setWheelDimensions: function(wheelDiameter, wheelDistance, callback) {&#xD;    this.send({cmd: &apos;setConfig&apos;, arg: {&apos;wheelDiameter&apos;: wheelDiameter, &apos;wheelDistance&apos;: wheelDistance}}, callback);&#xD;  },&#xD;&#xD;  postToServer: function (onOff, server_host, sec, temp, dist, callback) {&#xD;    onOff = onOff === &apos;On&apos; ? 1 : 0;&#xD;    this.send({&#xD;      cmd: "postToServer",&#xD;      arg: { "onOff": onOff, "server": server_host, "time": sec, "toggleTempHumidity":temp,"toggleDistance":dist }&#xD;    }, callback);&#xD;  },&#xD;&#xD;  digitalInput: function(pin_number, cb){&#xD;    var self = this;&#xD;    this.send({cmd: &apos;digitalInput&apos;, arg:pin_number}, function(state, msg){&#xD;      cb(state, msg);&#xD;      if(state === &apos;complete&apos; &amp;&amp; undefined != msg){&#xD;        self.digitalSensor[pin_number] = msg.msg;&#xD;      }&#xD;    });&#xD;  },&#xD;&#xD;  digitalNotify: function(pin_number, cb) {&#xD;    var self = this;&#xD;    this.send({cmd: &apos;digitalNotify&apos;, arg:pin_number}, cb);&#xD;  },&#xD;&#xD;  digitalStopNotify: function(pin_number, cb) {&#xD;    // Remove the pin status from sensorState&#xD;    var index = &apos;pin_&apos; + pin_number + &apos;_status&apos;;&#xD;    delete this.sensorState[index];&#xD;    this.send({cmd: &apos;digitalStopNotify&apos;, arg:pin_number}, cb);&#xD;  },&#xD;&#xD;  analogInput: function(pin_number, cb){&#xD;    var self = this;&#xD;    this.send({cmd: &apos;analogInput&apos;, arg:pin_number}, function(state, msg){&#xD;      if(state === &apos;complete&apos; &amp;&amp; undefined != msg){&#xD;        self.analogSensor.level = msg.msg;&#xD;        cb(state, msg);&#xD;      }&#xD;    });&#xD;  },&#xD;&#xD;  gpio: function(pin, pin_state, cb){&#xD;    this.send({cmd: pin_state[0], arg:pin}, cb);&#xD;  },&#xD;&#xD;  gpio_pwm: function(pin_select,pin_value, cb){&#xD;    this.send({cmd: pin_select, arg:pin_value}, cb);&#xD;  },&#xD;&#xD;  distanceInput: function(cb){&#xD;    var self = this;&#xD;    this.send({cmd: &apos;distanceSensor&apos;}, function(state, msg){&#xD;      cb(state, msg);&#xD;      if(state === &apos;complete&apos; &amp;&amp; undefined != msg){&#xD;        self.distanceSensor.level = msg.msg;&#xD;      }&#xD;    });&#xD;  },&#xD;&#xD;  compass: function(cb){&#xD;    var self = this;&#xD;    this.send({cmd: &apos;compassSensor&apos;}, function(state, msg){&#xD;      cb(state, msg);&#xD;      if(state === &apos;complete&apos; &amp;&amp; undefined != msg){&#xD;        self.compassSensor.x = msg.X;&#xD;        self.compassSensor.y = msg.Y;&#xD;        self.compassSensor.z = msg.Z;&#xD;      }&#xD;    });&#xD;  },&#xD;&#xD;  temperature: function(cb){&#xD;    var self = this;&#xD;    this.send({cmd: &apos;temperature&apos;}, function(state, msg){&#xD;      cb(state, msg);&#xD;      if(state === &apos;complete&apos; &amp;&amp; undefined != msg){&#xD;        self.tempSensor.level = msg.msg;&#xD;      }&#xD;    });&#xD;  },&#xD;&#xD;  humidity: function(cb){&#xD;    var self = this;&#xD;    this.send({cmd: &apos;humidity&apos;}, function(state, msg){&#xD;      cb(state, msg);&#xD;      if(state === &apos;complete&apos; &amp;&amp; undefined != msg){&#xD;        self.humidSensor.level = msg.msg;&#xD;      }&#xD;    });&#xD;  },&#xD;&#xD;  beep: function(note,duration,cb){&#xD;    this.send({cmd: &apos;beep&apos; , arg: [note, duration*1000]}, cb);&#xD;  },&#xD;&#xD;  getConfig: function(callback) {&#xD;    var self = this;&#xD;    this.send({cmd: &apos;getConfig&apos;}, function(state, msg) {&#xD;      if(state === &apos;complete&apos; &amp;&amp; undefined != msg){&#xD;        self.config = msg.msg;&#xD;      }&#xD;      callback(state, msg);&#xD;    });&#xD;  },&#xD;&#xD;  setServo: function(servoNum, angle, callback) {&#xD;    if (servoNum == 1) { // This is delierately a loose comparison&#xD;      this.send({cmd: "servo", arg: angle}, callback);&#xD;    } else if (servoNum == 2) {&#xD;      this.send({cmd: "servoII", arg: angle}, callback);&#xD;    }&#xD;  },&#xD;&#xD;  pinServo: function(pin, angle, callback) {&#xD;    this.send({cmd: "pinServo", arg: {pin: pin, angle:angle}}, callback);&#xD;  },&#xD;&#xD;  move: function(direction, distance, cb){&#xD;    // If we pass this first check, distance is a number or a string parseable as such&#xD;    if (!(typeof distance === &apos;number&apos; || !isNaN(distance))) {&#xD;      throw new Error(&apos;The distance must be a number&apos;);&#xD;    } else if (+distance &lt; 0) {&#xD;      throw new Error(&apos;For this command, distance must be positive.&apos;);&#xD;    }&#xD;    this.send({cmd: direction, arg: distance}, cb);&#xD;  },&#xD;&#xD;  turn: function(direction, angle, cb){&#xD;    this.send({cmd: direction, arg: angle}, cb);&#xD;  },&#xD;&#xD;  forward: function(distance, cb){&#xD;    this.move(&apos;forward&apos;, distance, cb);&#xD;  },&#xD;&#xD;  back: function(distance, cb){&#xD;    this.move(&apos;back&apos;, distance, cb);&#xD;  },&#xD;&#xD;  left: function(distance, cb){&#xD;    this.move(&apos;right&apos;, distance, cb);&#xD;  },&#xD;&#xD;  right: function(distance, cb){&#xD;    this.move(&apos;left&apos;, distance, cb);&#xD;  },&#xD;&#xD;  leftMotorForward: function(distance, cb){&#xD;    this.move(&apos;leftMotorF&apos;, distance, cb);&#xD;  },&#xD;&#xD;  rightMotorForward: function(distance, cb){&#xD;    this.move(&apos;rightMotorF&apos;, distance, cb);&#xD;  },&#xD;&#xD;  &#xD;  leftMotorBackward: function(distance, cb){&#xD;    this.move(&apos;leftMotorB&apos;, distance, cb);&#xD;  },&#xD;&#xD;  rightMotorBackward: function(distance, cb){&#xD;    this.move(&apos;rightMotorB&apos;, distance, cb);&#xD;  },&#xD;&#xD;  advancedMove: function(leftDistance, leftSpeed, rightDistance, rightSpeed, cb) {&#xD;    this.send({cmd: "speedMove", arg: {"leftDistance": leftDistance, "leftSpeed": leftSpeed,&#xD;    "rightDistance": rightDistance, "rightSpeed": rightSpeed}}, cb);&#xD;  },&#xD;&#xD;  advancedMoveSteps: function(leftDistance, leftSpeed, rightDistance, rightSpeed, cb) {&#xD;    this.send({cmd: "speedMoveSteps", arg: {"leftSteps": leftDistance, "leftSpeed": leftSpeed,&#xD;    "rightSteps": rightDistance, "rightSpeed": rightSpeed}}, cb);&#xD;  },&#xD;&#xD;  calibrateSlack: function(slackAmount, cb) {&#xD;    this.send({cmd:"calibrateSlack", arg: slackAmount}, cb);&#xD;  },&#xD;&#xD;  pause: function(cb){&#xD;    var self = this;&#xD;    this.send({cmd:&apos;pause&apos;}, function(state, msg) {&#xD;      if (state === &apos;complete&apos; &amp;&amp; msg) {&#xD;        // put the remaining millimeters in this ebrain object&#xD;        self.lastPausedState = msg.msg;&#xD;      }&#xD;      cb(state, msg);&#xD;    });&#xD;  },&#xD;&#xD;  resume: function(cb){&#xD;    this.send({cmd:&apos;resume&apos;}, cb);&#xD;  }&#xD;}&#xD;&#xD;var EveBrain = function(url){&#xD;  ParentEveBrain.call(this);&#xD;  this.url = url;&#xD;  this.initializeAndConnect();&#xD;  this.cbs = {};&#xD;  this.listeners = [];&#xD;  this.wifiNetworks = {};&#xD;}&#xD;&#xD;EveBrain.prototype = {&#xD;&#xD;  connected: false,&#xD;  error: false,&#xD;  timeoutTimer: undefined,&#xD;&#xD;  /**&#xD;   * Called by the connect block. Performs initialization&#xD;   * to ensure that the disconnected dialogs behave as expected,&#xD;   * and attempts to connect to the ebrain&#xD;   */&#xD;  initializeAndConnect: function() {&#xD;    // Stores whether the ebrain was connected once at least once since executing &#xD;    // the Connect block. Prevents the disconnected dialog from showing when using the Connect block.&#xD;    this.wasConnectedOnce = false;&#xD;    // also prevents the disconnected dialog from showing when using the Connect&#xD;    attempts = 0;&#xD;    this.connect();&#xD;  },&#xD;&#xD;  connect: function(){&#xD;    if(!this.connected &amp;&amp; !this.error){&#xD;      var self = this;&#xD;      try { &#xD;        //clear any previous websockets and clear msg queue and all timers&#xD;        clearTimeout(self.timeoutTimer);&#xD;        clearTimeout(self.connTimeout);&#xD;        clearTimeout(self.reconnectTimer);&#xD;        self.ws.close();&#xD;        self.robot_state = &apos;idle&apos;;&#xD;        self.msg_stack = [];&#xD;        self.cbs = {};&#xD;      }&#xD;      catch(error) {&#xD;        console.log(error);&#xD;      }&#xD;      this.has_connected = false;&#xD;      this.ws = filterUnicode(new WebSocket(this.url));&#xD;      this.ws.onmessage = function(ws_msg){self.handle_ws(ws_msg)};&#xD;      this.ws.onopen = function(){&#xD;        self.wasConnectedOnce = true;&#xD;        self.version(function(){&#xD;          self.setConnectedState(true);&#xD;          attempts = 0;&#xD;        });&#xD;      }&#xD;      this.ws.onerror = function(err){self.handleError(err); attempts += 1;}&#xD;      this.ws.onclose = function(err){self.handleError(err); attempts += 1;}&#xD;      if (attempts &lt; 10) {&#xD;        this.connTimeout = window.setTimeout(function(){&#xD;          if(!self.connected){&#xD;            try { &#xD;              self.ws.close();&#xD;            }&#xD;            catch(error) {&#xD;              console.log(error);&#xD;            }&#xD;          } &#xD;        }, 1000);&#xD;        // checks that the robot was connected at least once over wifi, and is not connected by USB&#xD;      } else if (this.wasConnectedOnce &amp;&amp; eb) {&#xD;        // on the last attempt, show the disconnected message.&#xD;        if (SnapTranslator.language.startsWith(&apos;fr&apos;)) {&#xD;          morphicAlert("Robot déconnecté",&#xD;          "Connexion WiFi au robot interrompu!", "S&apos;il te plaît, reconnecte avec le bloc Connecter et reprends l&apos;exécution.");&#xD;        } else {&#xD;          morphicAlert("Robot Disconnected!",&#xD;            "Robot disconnected by WiFi!", "Please reconnect using the Connect block and unpause.");&#xD;        }&#xD;        world.moveon = 1;&#xD;        world.children[0].stage.threads.pauseAll();&#xD;      }&#xD;    }&#xD;  },&#xD;&#xD;  refresh: function(){&#xD;    var self = this;&#xD;    self.ws.close();&#xD;    clearTimeout(self.connTimeout);&#xD;    self.robot_state = &apos;idle&apos;;&#xD;    self.msg_stack = [];&#xD;    self.cbs = {};&#xD;    this.has_connected = false;&#xD;    this.ws = filterUnicode(new WebSocket(this.url));&#xD;    this.ws.onmessage = function(ws_msg){self.handle_ws(ws_msg)};&#xD;    this.ws.onopen = function(){&#xD;      self.version(function(){&#xD;        self.setConnectedState(true);&#xD;      });&#xD;    }&#xD;    this.ws.onerror = function(err){self.handleError(err)}&#xD;    this.ws.onclose = function(err){self.handleError(err)}&#xD;  },&#xD;&#xD;  setConnectedState: function(state){&#xD;    var self = this;&#xD;    clearTimeout(self.connTimeout);&#xD;    self.connected = state;&#xD;    if(state){ self.has_connected = true; }&#xD;    if(self.has_connected){&#xD;      setTimeout(function(){&#xD;        self.broadcast(self.connected ? &apos;connected&apos; : &apos;disconnected&apos;);&#xD;      }, 100);&#xD;    }&#xD;    // Try to auto reconnect if disconnected&#xD;    if(state){&#xD;      if(self.reconnectTimer){&#xD;        clearTimeout(self.reconnectTimer);&#xD;        self.reconnectTimer = undefined;&#xD;      }&#xD;    }else{&#xD;      if(!self.reconnectTimer &amp;&amp; attempts &lt; 10){&#xD;          self.reconnectTimer = setTimeout(function(){&#xD;          self.reconnectTimer = undefined;&#xD;          self.connect();&#xD;        }, 1000);&#xD;        // If at the end of the attempts and was connected at least once, &#xD;        // show the user an alert and pause their code.&#xD;      }&#xD;    }&#xD;  },&#xD;&#xD;  broadcast: function(msg){&#xD;    for(i in this.listeners){&#xD;      if(this.listeners.hasOwnProperty(i)){&#xD;        this.listeners[i](msg);&#xD;      }&#xD;    }&#xD;  },&#xD;&#xD;  addListener: function(listener){&#xD;    this.listeners.push(listener);&#xD;  },&#xD;&#xD;  handleError: function(err){&#xD;    console.log("websocket error: " + JSON.stringify(err));&#xD;    if(err instanceof CloseEvent || err === &apos;Timeout&apos;){&#xD;      if(this.ws.readyState === WebSocket.OPEN){&#xD;        this.ws.close()&#xD;      }&#xD;      this.setConnectedState(false);&#xD;      clearTimeout(self.reconnectTimer);&#xD;      self.reconnectTimer = undefined;&#xD;      this.msg_stack = [];&#xD;    }else{&#xD;      console.log(err);&#xD;    }&#xD;  },&#xD;&#xD;  // note: many functions are in the ParentEveBrain.&#xD;&#xD;  //EveOneCommands&#xD;&#xD;  analogInputPCF: function(pin_number, cb){&#xD;    var self = this;&#xD;    this.send({cmd: &apos;readSensors&apos;, arg:pin_number}, function(state, msg){&#xD;      if(state === &apos;complete&apos; &amp;&amp; undefined != msg){&#xD;        self.analogSensor.level = msg.msg;&#xD;        cb(self.analogSensor.level);&#xD;      }&#xD;    });&#xD;  },&#xD;&#xD;  ping: function(cb){&#xD;    this.send({cmd:&apos;ping&apos;}, cb);&#xD;  },&#xD;&#xD;  send_msg: function(msg){&#xD;    var self = this;&#xD;    msg = filterUnicode(msg);&#xD;    console.log(msg);&#xD;    if(this.ws.readyState === WebSocket.OPEN){&#xD;      this.ws.send(JSON.stringify(msg));&#xD;    }&#xD;    this.timeoutTimer = window.setTimeout(function(){ self.handleError("Timeout") }, 3000);&#xD;  },&#xD;&#xD;  handle_ws: function(ws_msg){&#xD;    if (typeof ws_msg != &apos;undefined&apos;) {&#xD;      msg = JSON.parse(ws_msg.data);&#xD;      msg.msg = filterUnicode(msg.msg);&#xD;      msg.id = filterUnicode(msg.id);&#xD;      msg.status = filterUnicode(msg.status);&#xD;      console.log(msg);&#xD;      clearTimeout(this.timeoutTimer);&#xD;      if(msg.status === &apos;notify&apos;){&#xD;        this.broadcast(msg.id);&#xD;        this.sensorState[msg.id] = msg.msg;&#xD;        if (this.cbs[msg.id]) {&#xD;          this.cbs[msg.id](&apos;notify&apos;, msg);&#xD;          delete this.cbs[msg.id];&#xD;        }&#xD;        return;&#xD;      }&#xD;      if(this.msg_stack.length &gt; 0 &amp;&amp; this.msg_stack[0].id == msg.id){&#xD;        if(msg.status === &apos;accepted&apos;){&#xD;          if(this.cbs[msg.id]){&#xD;            this.cbs[msg.id](&apos;started&apos;, msg);&#xD;          }&#xD;          this.robot_state = &apos;running&apos;;&#xD;        } else {&#xD;          // this branch does the same thing in the event of &apos;complete&apos;, &apos;error&apos; etc&#xD;          // statuses, since otherwise if a command returns an error this object will be&#xD;          // in an inconsistent state, where the only way to get out of it is to&#xD;          // run the stop() block.&#xD;          if(this.cbs[msg.id]){&#xD;            this.cbs[msg.id](msg.status, msg);&#xD;            delete this.cbs[msg.id];&#xD;          }&#xD;          this.msg_stack.shift();&#xD;          if(this.msg_stack.length === 0){&#xD;            this.broadcast(&apos;program_complete&apos;);&#xD;          }&#xD;          this.robot_state = &apos;idle&apos;;&#xD;          this.process_msg_queue();&#xD;        }&#xD;      } else {&#xD;        // here: if it&apos;s something like a version command, that bypasses the msg_stack&#xD;        if(this.cbs[msg.id]){&#xD;          this.cbs[msg.id](&apos;complete&apos;, msg);&#xD;          delete this.cbs[msg.id];&#xD;        }&#xD;      }&#xD;      &#xD;      if (msg.status === &apos;error&apos;) {&#xD;        morphicAlert("Error", msg[&apos;msg&apos;]); // Alert user about error&#xD;      }&#xD;      if(msg.status &amp;&amp; msg.status === &apos;error&apos; &amp;&amp; msg.msg === &apos;Too many connections&apos;){&#xD;        this.error = true;&#xD;        this.broadcast(&apos;error&apos;);&#xD;      }&#xD;    } else {&#xD;      ws_msg.data = 0;&#xD;      ws_msg.status = 0;&#xD;      ws_msg.id = 0;&#xD;    }&#xD;  },&#xD;&#xD;  robot_state: &apos;idle&apos;,&#xD;  msg_stack: []&#xD;}&#xD;&#xD;// Add the movement functions to the EveBrain prototype&#xD;for (parentMemberName in ParentEveBrain.prototype) {&#xD;  EveBrain.prototype[parentMemberName] = ParentEveBrain.prototype[parentMemberName];&#xD;}&#xD;&#xD;&#xD;var EveBrainUSB = function() {&#xD;  ParentEveBrain.call(this);&#xD;  this.cbs = {};&#xD;  // Initially, set connected to true if there is a port.&#xD;  if (world.port) {&#xD;    this.connected = true;&#xD;  } else {&#xD;    this.connected = false;&#xD;  }&#xD;};&#xD;&#xD;EveBrainUSB.prototype = Object.create(ParentEveBrain.prototype);&#xD;Object.defineProperty(EveBrainUSB.prototype, &apos;constructor&apos;, {&#xD;  value: EveBrainUSB,&#xD;  enumerable: false,&#xD;  writable: true&#xD;});&#xD;&#xD;EveBrainUSB.prototype.send_msg = function(message, callback) {&#xD;  message = filterUnicode(message);&#xD;  writeToStream(JSON.stringify(message));&#xD;}&#xD;&#xD;/**&#xD; * Runs the callback associated with the given message and manages&#xD; * the robot&apos;s state.&#xD; * @param message Message from ebrain&#xD; */&#xD;EveBrainUSB.prototype.doCallback = function(message) {&#xD;  if(message &amp;&amp; message.status === &apos;notify&apos;){&#xD;    this.sensorState[message.id] = message.msg;&#xD;    if (this.cbs[message.id]) {&#xD;      this.cbs[message.id](&apos;notify&apos;, message);&#xD;      delete this.cbs[message.id];&#xD;    }&#xD;    return;&#xD;  }&#xD;&#xD;  if(this.msg_stack.length &gt; 0 &amp;&amp; this.msg_stack[0].id == message.id){&#xD;    if(message &amp;&amp; message.status == &apos;accepted&apos;) {&#xD;      this.robot_state = &apos;running&apos;;&#xD;      if(this.cbs[message.id]){&#xD;        this.cbs[message.id](&apos;started&apos;, message);&#xD;      }&#xD;    } else {&#xD;      // this branch does the same thing in the event of &apos;complete&apos;, &apos;error&apos; etc&#xD;      // statuses, since otherwise if a command returns an error this object will be&#xD;      // in an inconsistent state, where the only way to get out of it is to&#xD;      // run the stop() block.&#xD;      if (this.cbs[message.id]) {&#xD;        this.cbs[message.id](message.status, message);&#xD;        delete this.cbs[message.id];&#xD;      }&#xD;      this.robot_state = &apos;idle&apos;;&#xD;      this.msg_stack.shift(); // Pop message that prompted this response off queue&#xD;      this.process_msg_queue();&#xD;    }&#xD;  } else {&#xD;    // here: if it&apos;s something like a version command, that bypasses the msg_stack&#xD;    if(this.cbs[message.id]){&#xD;      this.cbs[message.id](&apos;complete&apos;, message);&#xD;      delete this.cbs[message.id];&#xD;    }&#xD;  }&#xD;&#xD;  if (message &amp;&amp; message.status === &apos;error&apos;) {&#xD;    morphicAlert("Error", message.msg);&#xD;  }&#xD;}&#xD;&#xD;/**&#xD; * Tests the connection. If the robot is connected, will&#xD; * (async) set this.connected = true (once the robot responds).&#xD; * Sets this.connected = false at the start.&#xD; */&#xD;EveBrainUSB.prototype.testConnection = function() {&#xD;  this.connected = false;&#xD;  var self = this;&#xD;  this.version(function(status, msg) {&#xD;    if (status === &apos;complete&apos;) {&#xD;      self.connected = true;&#xD;    }&#xD;  });&#xD;}&#xD;&#xD;let inputDone;&#xD;let outputDone;&#xD;world.outputStream = undefined; // Set this to undefined so it is easy to check for its existence&#xD;&#xD;async function USBconnect() {&#xD;  // Request &amp; open port here.&#xD;  world.port = await navigator.serial.requestPort();&#xD;  if (ebUSB) {&#xD;    ebUSB.connected = true;&#xD;  }&#xD;  // Wait for the port to open.&#xD;  await world.port.open({ baudRate: 230400 });&#xD;&#xD;  // on disconnect, alert user and pause Snap!&#xD;  world.port.addEventListener(&apos;disconnect&apos;, event =&gt; {&#xD;    if (ebUSB) {&#xD;      ebUSB.connected = false; // signal disconnection to other code.&#xD;    }&#xD;    if (SnapTranslator.language.startsWith(&apos;fr&apos;)) {&#xD;      morphicAlert("Robot déconnecté!",&#xD;      "Connexion USB au robot interrompu!", "S&apos;il te plaît reconnecte avec le bloc Connecter et reprends l&apos;exécution.");&#xD;    } else {&#xD;      morphicAlert("Robot Disconnected!", &#xD;      "Robot disconnected by USB!", "Please reconnect using the Connect block and unpause.");&#xD;    }&#xD;    world.moveon = 1;&#xD;    world.children[0].stage.threads.pauseAll();&#xD;  });&#xD;&#xD;  // Setup the output stream&#xD;  const encoder = new TextEncoderStream();&#xD;  outputDone = encoder.readable.pipeTo(world.port.writable);&#xD;  world.outputStream = encoder.writable;&#xD;&#xD;  // Make stream&#xD;  let decoder = new TextDecoderStream();&#xD;  inputDone = world.port.readable.pipeTo(decoder.writable);&#xD;  inputStream = decoder.readable;&#xD;&#xD;  world.reader = inputStream.getReader();&#xD;  readLoop(); // Start infinite read loop&#xD;}&#xD;&#xD;/**&#xD; * This reads from the serial in a loop, and &#xD; * runs the given callbacks (using ebUSB).&#xD; */&#xD;async function readLoop() {&#xD;  world.USB = &apos;&apos;;&#xD;  console.log("USB Reader Listening...");&#xD;&#xD;  while (true) {&#xD;    const { value, done } = await world.reader.read();&#xD;    if (value) {&#xD;      world.USB += value;&#xD;      console.log (value + &apos;\n&apos;);&#xD;&#xD;      // Now, I check if the JSON is complete and respond to the callback if necessary&#xD;      // and remove the message from the stack&#xD;      if (world.USB.includes(&apos;}&apos;)) {&#xD;        var messages = tryParseeBrainResponse(world.USB);&#xD;        for (var i = 0; i &lt; messages.parsed.length; i++ ) {&#xD;          var message = messages.parsed[i];&#xD;          if (ebUSB) {&#xD;            ebUSB.doCallback(message);&#xD;          }&#xD;        }&#xD;        world.USB = &apos;&apos;;&#xD;        if (messages.unparseable) {&#xD;          world.USB = messages.unparseable;&#xD;        }&#xD;      }&#xD;    }&#xD;    if (done) {&#xD;      console.log(&apos;[readLoop] DONE&apos;, done);&#xD;      world.reader.releaseLock();&#xD;      break;&#xD;    }&#xD;  }&#xD;}&#xD;&#xD;/**&#xD; * Tries to parse string as json. Also verifies that it is valid (check it has an id).&#xD; * NOTE: the json MUST end with &apos;\r\n&apos;&#xD; * @return An object of form {parsed, unparseable}, where parseable is a &#xD; * list of all parseable objects and, unparseable is a string representing what remaining&#xD; * bits couldn&apos;t be parsed (if such exists).&#xD;*/&#xD;function tryParseeBrainResponse(jsonString) {&#xD;  var out = {parsed: []};&#xD;&#xD;  // First, try and split if there are multiple objects being returned&#xD;  var jsons = jsonString.split(&apos;\r\n&apos;);&#xD;  for (var i = 0; i &lt; jsons.length; i++) {&#xD;    try {&#xD;      var response = JSON.parse(jsons[i]);&#xD;      if (response &amp;&amp; typeof response === "object" &amp;&amp; response.id) {&#xD;        out.parsed.push(response);&#xD;      }&#xD;    } catch (e) {&#xD;      // Only add a str to unparseable if it&apos;s at the end.&#xD;      if (i == jsons.length - 1) {&#xD;        out.unparseable = jsons[i];&#xD;      }&#xD;    }&#xD;  }&#xD;  return out;&#xD;}&#xD;&#xD;function writeToStream(...lines) {&#xD;  // Write to output stream&#xD;  const writer = world.outputStream.getWriter();&#xD;  lines.forEach((line) =&gt; {&#xD;    console.log(&apos;[SEND]&apos;, line);&#xD;    writer.write(line + &apos;\n&apos;);&#xD;  });&#xD;  writer.releaseLock();&#xD;}&#xD;&#xD;// https://forum.snap.berkeley.edu/t/how-do-i-make-a-dialog-box-with-custom-buttons/6347/4&#xD;/**&#xD; * Creates a red morhpic dialog and shows it to the user, with one &apos;Close&apos; button.&#xD; * If there is another alert with the same title and message, this one will not be shown.&#xD; * NOTE: this uses non bold text, otherwise the text is clipped.&#xD; * @param {string} title Title for the dialog&#xD; * @param {String} message Rest parameters of lines to show in the body of the dialog.&#xD; * If it does not contain Strings, calls toString on it.&#xD; */&#xD;function morphicAlert(title, ...messages) {&#xD;  morphicDialog(new Color(255, 0, 0, 1), title, ...messages);&#xD;}&#xD;/**&#xD; * Creates a morhpic dialog and shows it to the user, with one &apos;Close&apos; button.&#xD; * If there is another alert with the same title and message, this one will not be shown.&#xD; * NOTE: this uses non bold text, otherwise the text is clipped.&#xD; * @param {Color} color The title bar color.&#xD; * @param {string} title Title for the dialog&#xD; * @param {String} message Rest parameters of lines to show in the body of the dialog.&#xD; * If it does not contain Strings, calls toString on it.&#xD; */&#xD;function morphicDialog(color, title, ...messages) {&#xD;  if (Array.isArray(messages) &amp;&amp; messages.length &gt; 0) {&#xD;    var message = "";&#xD;    for (var i = 0; i &lt; messages.length - 1; i++) {&#xD;      message += messages[i] + "\n";&#xD;    }&#xD;    message += messages[messages.length - 1];&#xD;    morphicAlertString(title, message, color);&#xD;  } else if (typeof messages === "string") {&#xD;    morphicAlertString(title, messages, color);&#xD;  } else if (messages === null || messages === undefined) {&#xD;    morphicAlertString(title, "[Error message is missing. Please report that this happened to the developers.]", color);&#xD;  } else {&#xD;    morphicAlertString(title, messages.toString(), color);&#xD;  }&#xD;}&#xD;&#xD;var activeAlerts = new Map();&#xD;&#xD;/**&#xD; * Creates a morhpic dialog and shows it to the user, with one &apos;Close&apos; button.&#xD; * NOTE: use morphicAlert instead, it has more robust type checking.&#xD; * @param {string} title Title for the dialog&#xD; * @param {string} message Message in the body of the dialog&#xD; * @param {Color} color Colour of the title bar, red by default.&#xD; */&#xD; function morphicAlertString(title, message, color) {&#xD;  var alertContents = title + message;&#xD;  if (activeAlerts.get(alertContents) !== undefined) {&#xD;    // don&apos;t create a dialog if an identical one exists.&#xD;    return;&#xD;  }&#xD;&#xD;  let box = new DialogBoxMorph(); // make dialog&#xD;  // add label (in the weirdest way imaginable)&#xD;  box.labelString = title;&#xD;  box.createLabel();&#xD;  const addLabel = function (text, type) {&#xD;    let txt = new TextMorph(text);&#xD;    // Text should be bold to match the snap style but has to be &#xD;    // false here, otherwise the text overflows.&#xD;    txt.isBold = false;&#xD;    box[&apos;add&apos; + type](txt);&#xD;  }&#xD;  addLabel(message, &apos;Body&apos;) // do not change the second input of these&#xD;  box.titleBarColor = color || new Color(255, 0, 0, 1); // Make titlebar red if not specified.&#xD;  box.titlePadding = 12; // make titlebar taller&#xD;&#xD;  // Add this box to the activeAlerts map, and make the close button work.&#xD;  activeAlerts.set(alertContents, box);&#xD;  box.cancelAndProcess = function() {&#xD;    box.ok();&#xD;    activeAlerts.delete(alertContents);&#xD;  }&#xD;  // This button will close the dialog and remove it from the list of active alerts&#xD;  box.addButton(&apos;cancelAndProcess&apos;, &apos;Close&apos;);&#xD;  box.fixLayout(); // required, otherwise box looks weird&#xD;  box.popUp(world); // popup box&#xD;}</l></block></script></block-definition><block-definition s="addJS %&apos;JS_FILE&apos;" type="command" category="other"><header></header><code></code><translations></translations><inputs><input type="%s"></input></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>JS_FILE</l></list><l>var po = document.createElement(&apos;script&apos;);&#xD;  po.type = &apos;text/javascript&apos;;&#xD;  po.async = true;&#xD;  po.innerHTML = JS_FILE;&#xD;  var s = document.getElementsByTagName(&apos;script&apos;)[0];&#xD;  s.parentNode.insertBefore(po, s)</l></block><list><block var="JS_FILE"/></list></block></script></block-definition><block-definition s="world modified" type="reporter" category="other"><header></header><code></code><translations>fr:world est modifié&#xD;</translations><inputs></inputs><script><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.modified == 1 || world.modified != undefined;</l></block><list></list></block></block></script></block-definition><block-definition s="Forward $arrowUp %&apos;mm&apos; mm" type="command" category="RIAC"><header></header><code></code><translations>fr:Avancer $arrowUp de _ mm&#xD;</translations><inputs><input type="%s">100</input></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>mm</l><l>eb</l></list><l>world.moveon = 0;&#xD;eb.forward(mm,function(state, msg){&#xD;  if(state == &apos;complete&apos;){&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><block var="mm"/><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block></script></block-definition><block-definition s="Back $arrowDown %&apos;mm&apos; mm" type="command" category="RIAC"><header></header><code></code><translations>fr:Reculer $arrowDown de _ mm&#xD;</translations><inputs><input type="%s">100</input></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>mm</l><l>eb</l></list><l>world.moveon = 0;&#xD;eb.back(mm,function(state,msg){&#xD;  if(state == &apos;complete&apos;){&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><block var="mm"/><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block></script></block-definition><block-definition s="Turn $turnLeft %&apos;mm&apos; degrees" type="command" category="RIAC"><header></header><code></code><translations>fr:Tourner de _ degrés $turnLeft&#xD;</translations><inputs><input type="%s">90</input></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>mm</l><l>eb</l></list><l>world.moveon = 0;&#xD;eb.left(mm,function(state,msg){&#xD;  if(state == &apos;complete&apos;){&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><block var="mm"/><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block></script></block-definition><block-definition s="Turn $turnRight %&apos;mm&apos; degrees" type="command" category="RIAC"><header></header><code></code><translations>fr:Tourner de _ degrés $turnRight&#xD;</translations><inputs><input type="%s">90</input></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>mm</l><l>eb</l></list><l>world.moveon = 0;&#xD;eb.right(mm,function(state,msg){&#xD;  if(state == &apos;complete&apos;){&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><block var="mm"/><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block></script></block-definition><block-definition s="connect" type="command" category="other"><header></header><code></code><translations>fr:se connecter&#xD;</translations><inputs></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l></l></list><l>ebUSB = undefined; // signal not connected by usb&#xD;if (eb == undefined) {&#xD;  eb = new EveBrain(&apos;ws://192.168.4.1:8899/websocket&apos;);&#xD;  console.log(eb.connected);&#xD;} else {&#xD;  if (eb.connected == false) {&#xD;    eb.url = "ws://192.168.4.1:8899/websocket";&#xD;    eb.initializeAndConnect();&#xD;  }&#xD;}</l></block><list></list></block></script></block-definition><block-definition s="connection type" type="reporter" category="other"><header></header><code></code><translations>fr:type de connexion&#xD;</translations><inputs></inputs><script><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>try {&#xD;  if(eb != undefined ? eb.connected : false){&#xD;    return &apos;WEB&apos;; &#xD;  }  &#xD; else if(ebUSB != undefined ? ebUSB.connected: false){&#xD;    return &apos;USB&apos;; &#xD;  }&#xD; else {&#xD;   return &apos;NONE&apos;; &#xD;  }&#xD;} catch(e) {&#xD;  return "NONE";&#xD;}</l></block><list></list></block></block></script></block-definition><block-definition s="Stop $octagon" type="command" category="RIAC"><header></header><code></code><translations>fr:Arrêter $octagon&#xD;</translations><inputs></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>eb</l></list><l>world.moveons.stop = 0;&#xD;eb.stop(function(state, msg) {&#xD;  if (state === &apos;complete&apos;) {&#xD;    world.moveons.stop = 1;&#xD;  }&#xD;});</l></block><list><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveons.stop;</l></block><list></list></block></block></script></block-definition><block-definition s="GPIO Write Pin: %&apos;Pin&apos; %&apos;ON/OFF&apos;" type="command" category="eBrain"><header></header><code></code><translations>fr:Mettre la broche (pin) GPIO _ à _&#xD;</translations><inputs><input type="%s" readonly="true">4<options>4&#xD;5&#xD;10&#xD;16&#xD;14&#xD;12&#xD;13&#xD;0&#xD;2</options></input><input type="%b" readonly="true">true<options>en: gpio_on&#xD;en: gpio_off</options></input></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>Pin</l><l>State</l><l>eb</l></list><l>world.moveon = 0;&#xD;State = State ? &apos;gpio_on&apos; : &apos;gpio_off&apos;;&#xD;try{&#xD;  eb.gpio(Pin,[State],function(state, msg){&#xD;    if (state == &apos;complete&apos;) {&#xD;      world.moveon = 1;&#xD;    }&#xD;  });&#xD;}&#xD;catch(e){&#xD;}</l></block><list><block var="Pin"/><block var="ON/OFF"/><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block></script></block-definition><block-definition s="GPIO Read Pin %&apos;Pin&apos;" type="reporter" category="eBrain"><header></header><code></code><translations>fr:Lire la broche (pin) GPIO _&#xD;</translations><inputs><input type="%s" readonly="true">4<options>4&#xD;5&#xD;10&#xD;16&#xD;14&#xD;12&#xD;13&#xD;0&#xD;2</options></input></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>Pin</l><l>eb</l></list><l>world.moveon = 0;&#xD;eb.digitalInput(Pin,function(state, msg){&#xD;  if (state === &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><block var="Pin"/><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list></list><l>return world.moveon;</l></block><list></list></block></block><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l>Pin</l><l>eb</l></list><l>return eb.digitalSensor[Pin];</l></block><list><block var="Pin"/><custom-block s="connection object"></custom-block></list></block></block></script></block-definition><block-definition s="Analog Read" type="reporter" category="eBrain"><header></header><code></code><translations>en:Analog Read&#xD;fr:Lecture analogique&#xD;</translations><inputs></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>eb</l></list><l>world.moveon = 0;&#xD;eb.analogInput(0,function(state, msg){&#xD;  if (state === &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list></list><l>return world.moveon;</l></block><list></list></block></block><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l>eb</l></list><l>return eb.analogSensor.level;</l></block><list><custom-block s="connection object"></custom-block></list></block></block></script></block-definition><block-definition s="Read Distance" type="reporter" category="eBrain"><header></header><code></code><translations>fr:Lire la distance&#xD;</translations><inputs></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>eb</l></list><l>world.moveon = 0;&#xD;eb.distanceInput(function(state, msg) { &#xD;  if (state === &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l>eb</l></list><l>return  eb.distanceSensor.level;</l></block><list><custom-block s="connection object"></custom-block></list></block></block></script></block-definition><block-definition s="Temperature Read" type="reporter" category="eBrain"><header></header><code></code><translations>fr:Lire la température&#xD;</translations><inputs></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>eb</l></list><l>world.moveon = 0;&#xD;eb.temperature(function(state, msg){&#xD;  if (state === &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l>eb</l></list><l>return eb.tempSensor.level;</l></block><list><custom-block s="connection object"></custom-block></list></block></block></script></block-definition><block-definition s="Humidity Read" type="reporter" category="eBrain"><header></header><code></code><translations>fr:Lire l&apos;humidité&#xD;</translations><inputs></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>eb</l></list><l>world.moveon = 0;&#xD;eb.humidity(function(state, msg){&#xD;  if (state === &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l>eb</l></list><l>return eb.humidSensor.level;</l></block><list><custom-block s="connection object"></custom-block></list></block></block></script></block-definition><block-definition s="PWM Pin: %&apos;Pin&apos; Value (0-255): %&apos;pin_value&apos;" type="command" category="eBrain"><header></header><code></code><translations>fr:Broche PWM: _ valeur (0-255): _&#xD;</translations><inputs><input type="%s" readonly="true">5<options>5&#xD;10&#xD;16</options></input><input type="%n">255</input></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>pin</l><l>pin_value</l><l>eb</l></list><l>world.moveon = 0;&#xD;eb.gpio_pwm("gpio_pwm_" + pin, pin_value, function(state, msg){&#xD;  if (state == &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><block var="Pin"/><block var="pin_value"/><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block></script></block-definition><block-definition s="Beep Pin 5 Duration: %&apos;duration&apos; sec Note: %&apos;note&apos;" type="command" category="eBrain"><header></header><code></code><translations>fr:Bip (GPIO 5) durée: _ sec note: _&#xD;</translations><inputs><input type="%n">1</input><input type="%n">60</input></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>duration</l><l>note</l><l>eb</l></list><l>world.moveon = 0;&#xD;eb.beep(note,duration,function(state, msg){&#xD;  if (state == &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><block var="duration"/><block var="note"/><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block></script></block-definition><block-definition s="Connect to Wireless Network SSID: %&apos;SSID&apos; Password: %&apos;PASS&apos;" type="command" category="eBrain"><header></header><code></code><translations>fr:Connexion au réseau sans-fil SSID: _ Mot de pase: _&#xD;</translations><inputs><input type="%s"></input><input type="%s"></input></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>SSID</l><l>PASS</l><l>eb</l></list><l>world.moveon = 0;&#xD;eb.connect_to_network(SSID, PASS, function(state, msg){&#xD;  if (state == &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><block var="SSID"/><block var="PASS"/><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block></script></block-definition><block-definition s="Get WiFi Networks" type="reporter" category="other"><header></header><code></code><translations>fr:Obtenir la liste des réseaux WiFi&#xD;</translations><inputs></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>eb</l></list><l>world.moveon = 0;&#xD;eb.wifiScan(function(){&#xD;  world.moveon = 1;&#xD;});</l></block><list><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l>eb</l></list><l>&#xD;var networks = eb.sensorState["wifiScan"];&#xD;let txt = "";&#xD;for (let i = 0; i &lt; networks.length; i++){&#xD;&#xD;txt = txt.concat(networks[i][0]);&#xD;if(i != networks.length){  &#xD;  txt = txt.concat(",");}&#xD;}&#xD;return(networks);</l></block><list><custom-block s="connection object"></custom-block></list></block></block></script></block-definition><block-definition s="Set Servo Port %&apos;one&apos; to %&apos;angle&apos; degrees" type="command" category="eBrain"><header></header><code></code><translations>fr:Mettre le servo au port _ à _ degrés&#xD;</translations><inputs><input type="%s" readonly="true">1<options>1&#xD;2</options></input><input type="%n">90</input></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>angle</l><l>one</l><l>eb</l></list><l>world.moveon = 0;&#xD;eb.setServo(one, angle, function(state, msg){&#xD;  if (state === &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><block var="angle"/><block var="one"/><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block></script></block-definition><block-definition s="Get IP" type="reporter" category="other"><header></header><code></code><translations>fr:Obtenir l&apos;adresse IP&#xD;</translations><inputs></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>eb</l></list><l>world.moveon = 0;&#xD;eb.getConfig(function(state, msg){&#xD;  if (state === &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list></list><l>return world.moveon;</l></block><list></list></block></block><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l>eb</l></list><l>return eb.config.sta_ip;</l></block><list><custom-block s="connection object"></custom-block></list></block></block></script></block-definition><block-definition s="Get Config" type="reporter" category="other"><header></header><code></code><translations>fr:Obtenir la configuration&#xD;</translations><inputs></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>eb</l></list><l>world.moveon = 0;&#xD;eb.getConfig(function(state, message){&#xD;  if (state === &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list></list><l>return world.moveon;</l></block><list></list></block></block><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l>eb</l></list><l>return  JSON.stringify(eb.config);</l></block><list><custom-block s="connection object"></custom-block></list></block></block></script></block-definition><block-definition s="Get Robot Name" type="reporter" category="other"><header></header><code></code><translations>fr:Obtenir le nom du robot&#xD;</translations><inputs></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>eb</l></list><l>world.moveon = 0;&#xD;eb.getConfig(function(state, msg){&#xD;  if (state === &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list></list><l>return world.moveon;</l></block><list></list></block></block><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l>eb</l></list><l>return  eb.config.ap_ssid;</l></block><list><custom-block s="connection object"></custom-block></list></block></block></script></block-definition><block-definition s="%&apos;motor&apos; Motor in direction %&apos;direction&apos; for %&apos;mm&apos; mm" type="command" category="eBrain"><header></header><code></code><translations>fr:moteur _ en direction _ pour _ mm&#xD;</translations><inputs><input type="%s" readonly="true">◄<options>◄&#xD;►</options></input><input type="%s" readonly="true">▲<options>▲&#xD;▼</options></input><input type="%n">100</input></inputs><script><block s="doIfElse"><block s="reportNot"><block s="reportListContainsItem"><block s="reportNewList"><list><l>◄</l><l>►</l></list></block><block var="motor"/></block></block><script><block s="doRun"><block s="reportJSFunction"><list></list><l>alert(&apos;Must use with "◄" or "►" motor &apos;);</l></block><list></list></block></script><script><block s="doIfElse"><block s="reportNot"><block s="reportListContainsItem"><block s="reportNewList"><list><l>▲</l><l>▼</l></list></block><block var="direction"/></block></block><script><block s="doRun"><block s="reportJSFunction"><list></list><l>alert(&apos;Must use going "▲" or "▼"&apos;);</l></block><list></list></block></script><script><block s="doRun"><block s="reportJSFunction"><list><l>motor</l><l>direction</l><l>mm</l><l>eb</l></list><l>world.moveon = 0;&#xD;whichMotor = motor === &apos;◄&apos; ? &apos;left&apos; : &apos;right&apos;;&#xD;var actionStr = whichMotor + &apos;Motor&apos; + (direction === &apos;▲&apos; ? &apos;F&apos; : &apos;B&apos;);&#xD;eb.move(actionStr, mm, function(state, msg) {&#xD;  if (state === &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><block var="motor"/><block var="direction"/><block var="mm"/><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block></script></block></script></block></script></block-definition><block-definition s="Close Connection" type="command" category="other"><header></header><code></code><translations>fr:Fermer la connexion&#xD;</translations><inputs></inputs><script><block s="doIf"><block s="reportVariadicEquals"><list><custom-block s="connection type"></custom-block><l>WEB</l></list></block><script><block s="doRun"><block s="reportJSFunction"><list><l></l></list><l>eb.ws.close();</l></block><list></list></block></script><list></list></block><block s="doIf"><block s="reportVariadicEquals"><list><custom-block s="connection type"></custom-block><l>USB</l></list></block><script><block s="doRun"><block s="reportJSFunction"><list><l></l></list><l>world.port.close()</l></block><list></list></block></script><list></list></block></script></block-definition><block-definition s="Set eBrain Posting to %&apos;onOff&apos; to Server %&apos;server_host&apos; every %&apos;sec&apos; Seconds Post Distance Sensor: %&apos;dist&apos; Temperature and Humidity Sensor: %&apos;temp&apos;" type="command" category="Advanced eBrain"><header></header><code></code><translations>fr:Commencer les publications du eBrain? _ au serveur _ chaque _ secondes. Publier le capteur de distance? _ Publier le capteur d&apos;humidité et de température? _&#xD;</translations><inputs><input type="%b" readonly="true">true<options>On&#xD;Off</options></input><input type="%s">https://json.robotinacan.com/posts</input><input type="%n">10</input><input type="%b" readonly="true">false<options>0&#xD;1</options></input><input type="%b" readonly="true">false<options>0&#xD;1</options></input></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>onOff</l><l>server_host</l><l>sec</l><l>temp</l><l>dist</l><l>eb</l></list><l>world.moveon = 0;&#xD;// convert onOff from true/false to the needed string&#xD;onOff = onOff ? &apos;On&apos; : &apos;Off&apos;;&#xD;eb.postToServer(onOff, server_host, sec, temp?1:0, dist?1:0, function(state, msg){&#xD;  if (state === &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><block var="onOff"/><block var="server_host"/><block var="sec"/><block var="temp"/><block var="dist"/><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list></list><l>return world.moveon;</l></block><list></list></block></block></script></block-definition><block-definition s="Move Left Motor %&apos;LeftMM&apos; mm and Right Motor %&apos;RightMM&apos; mm" type="command" category="eBrain"><header></header><code></code><translations>fr:Bouger le moteur de gauche _ mm et le moteur de droite _ mm&#xD;</translations><inputs><input type="%s">100</input><input type="%s">200</input></inputs><script><block s="doIfElse"><block s="reportVariadicEquals"><list><block var="LeftMM"/><block var="RightMM"/></list></block><script><block s="doRun"><block s="reportJSFunction"><list><l>mm</l><l>eb</l></list><l>world.moveon = 0;&#xD;var callback = function(state, msg) {&#xD;    if (state === &apos;complete&apos;) {&#xD;        world.moveon = 1;&#xD;    }&#xD;};&#xD;if (mm &gt; 0) {&#xD;    eb.forward(mm, callback);&#xD;} else {&#xD;    eb.back(-mm, callback);&#xD;}</l></block><list><block var="LeftMM"/><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block></script><script><block s="doRun"><block s="reportJSFunction"><list><l>LeftMM</l><l>RightMM</l><l>eb</l></list><l>// Calculate the ratio between mm and degrees&#xD;var steps_per_mm = 2038.0 / 254.4;&#xD;var steps_per_degree = ((108.5 * 3.1416) / 360) * steps_per_mm;&#xD;var degrees_per_mm = steps_per_degree / steps_per_mm;&#xD;&#xD;// Find the absolute values of the distances&#xD;var absLeftMM = Math.abs(LeftMM);&#xD;var absRightMM = Math.abs(RightMM);&#xD;&#xD;world.moveon = 0;&#xD;var callback = function(state, msg) {&#xD;    if (state === &apos;complete&apos;) {&#xD;        world.moveon = 1;&#xD;    }&#xD;};&#xD;&#xD;// start of with moving both motors&#xD;var minDistance = Math.min(absLeftMM, absRightMM);&#xD;if (LeftMM &gt;= 0 &amp;&amp; RightMM &gt;= 0) {&#xD;    eb.forward(minDistance, callback);&#xD;} else if (LeftMM &lt;= 0 &amp;&amp; RightMM &lt;= 0) {&#xD;    eb.back(minDistance, callback);&#xD;} else if (LeftMM &gt; 0) {&#xD;    eb.right(minDistance * degrees_per_mm, callback);&#xD;} else {&#xD;    eb.left(minDistance * degrees_per_mm, callback);&#xD;}</l></block><list><block var="LeftMM"/><block var="RightMM"/><custom-block s="connection object"></custom-block></list><comment w="140.83333333333334" collapsed="false">Here, run the command to run the motors as long as the smaller distance (ie if we are moving the Left one 50mm and the Right one 80mm, move both 50mm first).</comment></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block><block s="doRun"><block s="reportJSFunction"><list><l>LeftMM</l><l>RightMM</l><l>eb</l></list><l>// Calculate the ratio between mm and degrees&#xD;var steps_per_mm = 2038.0 / 254.4;&#xD;var steps_per_degree = ((108.5 * 3.1416) / 360) * steps_per_mm;&#xD;var degrees_per_mm = steps_per_degree / steps_per_mm;&#xD;// Find the absolute values of the distances&#xD;var absLeftMM = Math.abs(LeftMM);&#xD;var absRightMM = Math.abs(RightMM);&#xD;&#xD;world.moveon = 0;&#xD;var callback = function(state, msg) {&#xD;    if (state === &apos;complete&apos;) {&#xD;        world.moveon = 1;&#xD;    }&#xD;};&#xD;&#xD;var minDistance = Math.min(absLeftMM, absRightMM);&#xD;&#xD;&#xD;//End with moving the remaining motor the remaining distance&#xD;if (absLeftMM &gt; absRightMM) {&#xD;    var remainingDistance = absLeftMM - minDistance;&#xD;    if (LeftMM &lt; 0) {&#xD;        eb.rightMotorBackward(remainingDistance, callback);&#xD;    } else {&#xD;        eb.rightMotorForward(remainingDistance, callback);&#xD;    }&#xD;} else {&#xD;    var remainingDistance = absRightMM - minDistance;&#xD;    if (RightMM &lt; 0) {&#xD;        eb.leftMotorForward(remainingDistance, callback);&#xD;    } else {&#xD;        eb.leftMotorBackward(remainingDistance, callback);&#xD;    }&#xD;}&#xD;&#xD;</l></block><list><block var="LeftMM"/><block var="RightMM"/><custom-block s="connection object"></custom-block></list><comment w="90" collapsed="false">Here, run the motor with the longer distance to move (ie if we are moving the Left one 50mm and the Right one 80mm, now we are moving the Right one 30mm).</comment></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block></script><comment w="90" collapsed="false">If both distances are the same, run a forward/backwards command</comment></block></script></block-definition><block-definition s="connection object" type="reporter" category="other"><header></header><code></code><translations>fr:objet de connexion&#xD;</translations><inputs></inputs><script><block s="doIf"><block s="reportVariadicEquals"><list><custom-block s="connection type"></custom-block><l>NONE</l></list></block><script><custom-block s="Connect to eBrain %s"><l>192.168.4.1</l></custom-block></script><list></list></block><block s="doIfElse"><block s="reportVariadicEquals"><list><custom-block s="connection type"></custom-block><l>WEB</l></list></block><script><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return eb;</l></block><list></list></block></block></script><script><block s="doIfElse"><block s="reportVariadicEquals"><list><custom-block s="connection type"></custom-block><l>USB</l></list></block><script><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return ebUSB;</l></block><list></list></block></block></script><script><block s="doRun"><block s="reportJSFunction"><list><l></l></list><l>// Since this block might be called before Connect, and Connect loads in morphicAlert,&#xD;// this falls back to a js alert.&#xD;try {&#xD;  morphicAlert("Connection Error!", "You are not connected to your eBrain!", &#xD;  "You need to connect to your robot before you run any eBrain or RIAC blocks!");&#xD;} catch (e) {&#xD;  alert("You are not connected to your eBrain!");&#xD;}</l></block><list></list></block><block s="doStopThis"><l><option>all</option></l></block></script></block></script></block></script></block-definition><block-definition s="delete var %&apos;names&apos;" type="command" category="variables"><comment x="0" y="0" w="217" collapsed="false">This block deletes all the variables with the names given (inside input list).&#xD;&#xD;Each name will make only one variable deletion, and this will be the variable found following the scope order: &apos;script&apos; -&gt; &apos;sprite&apos; -&gt; &apos;global&apos;.&#xD;&#xD;If we have a &quot;testing&quot; sprite variable and also a &quot;testing&quot; global one, deleting &quot;testing&quot; will delete only the sprite one (Yes! we can also do &quot;delete var (testing, testing)&quot; to delete both.&#xD;&#xD;If one variable does not exists (in any scope) an error happens, stopping block action in that point. You can check it before with the &quot;does var (name) exists?&quot;block. </comment><header></header><code></code><translations>pt:remove as variáveis _&#xD;ca:esborra les variables _&#xD;es:borrar variables _&#xD;de:löschen var _&#xD;</translations><inputs><input type="%mult%txt"></input></inputs><script><block s="doForEach"><l>each item</l><block var="names"/><script><block s="doRun"><block s="reportJSFunction"><list><l>varName</l><l>proc</l></list><l>if ((typeof varName) != "string" || varName === "") {&#xD;    throw new Error("name isn&apos;t a string: " + varName);&#xD;}&#xD;if (typeof proc.homeContext.variables.vars[varName] !== &apos;undefined&apos;) {&#xD;    delete proc.homeContext.variables.vars[varName];&#xD;} else if (this.deletableVariableNames().indexOf(varName) != -1) {&#xD;    this.deleteVariable(varName);&#xD;} else {&#xD;    throw new Error("variable doesn&apos;t exist: " + varName);&#xD;}</l></block><list><block var="each item"/></list></block></script></block><block s="doRun"><block s="reportJSFunction"><list></list><l>var ide = this.parentThatIsA(IDE_Morph);&#xD;ide.flushBlocksCache(&apos;variables&apos;); // b/c of inheritance&#xD;ide.refreshPalette();</l></block><list></list></block></script></block-definition><block-definition s="set var %&apos;name&apos; to %&apos;value&apos;" type="command" category="variables"><comment x="0" y="0" w="240.4931640625" collapsed="false">This block sets the given value (last input) to the variable named with the name givent (var input).&#xD;&#xD;It looks for that variable following the scope order &apos;script&apos; -&gt; &apos;sprite&apos; -&gt; &apos;global&apos; (the first match it finds).&#xD;&#xD;If that variable does not exist (in any scope) an error happens, stopping their script. You can check it before using the &quot;does var (name) exists?&quot; block. </comment><header></header><code></code><translations>ca:assigna a _ el valor _&#xD;es:asignar a _ el valor _&#xD;pt:altera _ para _&#xD;de:setze var _ auf _&#xD;</translations><inputs><input type="%s"><options>§_getVarNamesDict</options></input><input type="%s"></input></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>varName</l><l>value</l><l>proc</l></list><l>if ((typeof varName) != "string") {&#xD;    throw new Error("name isn&apos;t a string: " + varName);&#xD;}&#xD;proc.homeContext.variables.setVar(varName, value);</l></block><list><block var="name"/><block var="value"/></list></block></script></block-definition><block-definition s="listify %&apos;jsonString&apos;" type="reporter" category="operators"><header></header><code></code><translations>pt:os dados JSON _ em formato de lista&#xD;</translations><inputs><input type="%mlt"></input></inputs><script><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l>jsonString</l></list><l>return listify(JSON.parse(jsonString));&#xD;&#xD;function listify(jsonObject) {&#xD;  if (jsonObject instanceof Array) {&#xD;    return new List(jsonObject.map(function(eachElement) { return listify(eachElement)}));&#xD;  } else if (jsonObject instanceof Object) {&#xD;    return new List(Object.keys(jsonObject).map(function(eachKey) { return new List([eachKey,listify(jsonObject[eachKey])])} ))&#xD;  } else {&#xD;    return jsonObject&#xD;  }&#xD;}</l></block><list><block var="jsonString"/></list></block></block></script></block-definition><block-definition s="value at key %&apos;key&apos; of %&apos;lst&apos;" type="reporter" category="operators"><header></header><code></code><translations>pt:o valor com chave _ em _&#xD;</translations><inputs><input type="%s"></input><input type="%l"></input></inputs><script><block s="doWarp"><script><block s="doForEach"><l>each item</l><block var="lst"/><script><block s="doIf"><block s="reportVariadicEquals"><list><block s="reportListItem"><l>1</l><block var="each item"/></block><block var="key"/></list></block><script><block s="doReport"><block s="reportListItem"><l>2</l><block var="each item"/></block></block></script><list></list></block></script></block></script></block><block s="doReport"><l></l></block></script></block-definition><block-definition s="key: %&apos;key&apos; value: %&apos;value&apos;" type="reporter" category="operators"><header></header><code></code><translations>pt:um par (chave: _ , valor: _ )&#xD;</translations><inputs><input type="%s"></input><input type="%s"></input></inputs><script><block s="doReport"><block s="reportNewList"><list><block var="key"/><block var="value"/></list></block></block></script></block-definition><block-definition s="var %&apos;name&apos;" type="reporter" category="variables"><comment x="0" y="0" w="178.00000000000003" collapsed="false">This block reports the value of the variable with the name given.&#xD;&#xD;It looks for that variable following the scope order &apos;script&apos; -&gt; &apos;sprite&apos; -&gt; &apos;global&apos; (the first match it finds).&#xD;&#xD;If that variable does not exist (in any scope) an error happens, stopping their script. You can check it before using the &quot;does var (name) exists?&quot; block. </comment><header></header><code></code><translations>pt:o valor de _&#xD;</translations><inputs><input type="%s"><options>§_getVarNamesDict</options></input></inputs><script><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l>varName</l><l>proc</l></list><l>if ((typeof varName) != "string") {&#xD;    throw new Error("name isn&apos;t a string: " + varName);&#xD;}&#xD;return proc.homeContext.variables.getVar(varName);</l></block><list><block var="name"/></list></block></block></script></block-definition><block-definition s="does var %&apos;name&apos; exist?" type="predicate" category="variables"><comment x="0" y="0" w="146" collapsed="false">This block reports &quot;true&quot; if there is a variable with this given name (input slot) in that context.&#xD;&#xD;It can be a global, sprite or script variable.&#xD;&#xD;Otherwise it reports &quot;false&quot;.</comment><header></header><code></code><translations>pt:a variável _ existe&#xD;ca:existeix la variable _ ?&#xD;es:existe la variable _ ?&#xD;de:existiert var _ ?&#xD;</translations><inputs><input type="%s"></input></inputs><script><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l>varName</l><l>proc</l></list><l>if ((typeof varName) != "string" || varName === "") {&#xD;    throw new Error("name isn&apos;t a string: " + varName);&#xD;}&#xD;return proc.homeContext.variables.silentFind(varName)? true:false;</l></block><list><block var="name"/></list></block></block></script></block-definition><block-definition s="show var %&apos;name&apos;" type="command" category="variables"><comment x="0" y="0" w="181" collapsed="false">This block turns on (show) the watcher view on stage (if it was not already activated) of the variable with the given name (slot input).&#xD;&#xD;It can only access to the closest variable scope (if there different variables with the same name in different scopes) following the order &apos;script&apos; -&gt; &apos;sprite&apos; -&gt; &apos;global&apos;.&#xD;&#xD;No errors if that variable does not exist.</comment><header></header><code></code><translations>ca:mostra la variable _&#xD;es:mostrar variable _&#xD;pt:mostra a variável _&#xD;de:zeige var _&#xD;</translations><inputs><input type="%s"><options>§_getVarNamesDict</options></input></inputs><script><block s="doIf"><custom-block s="does var %s exist?"><block var="name"/></custom-block><script><block s="doRun"><block s="reportJSFunction"><list><l>varName</l><l>proc</l></list><l>    var varFrame = proc.homeContext.variables,&#xD;        stage,&#xD;        watcher,&#xD;        target,&#xD;        label,&#xD;        others,&#xD;        isGlobal,&#xD;        name = varName;&#xD;&#xD;    if (name instanceof Context) {&#xD;        if (name.expression.selector === &apos;reportGetVar&apos;) {&#xD;            name = name.expression.blockSpec;&#xD;        } else {&#xD;            proc.doChangePrimitiveVisibility(name.expression, false);&#xD;            return;&#xD;        }&#xD;    }&#xD;    if (proc.homeContext.receiver) {&#xD;        stage = proc.homeContext.receiver.parentThatIsA(StageMorph);&#xD;        if (stage) {&#xD;            target = varFrame.silentFind(name);&#xD;            if (!target) {return; }&#xD;            // first try to find an existing (hidden) watcher&#xD;            watcher = detect(&#xD;                stage.children,&#xD;                morph =&gt; morph instanceof WatcherMorph &amp;&amp;&#xD;                    morph.target === target &amp;&amp;&#xD;                        morph.getter === name&#xD;            );&#xD;            if (watcher !== null) {&#xD;                watcher.show();&#xD;                watcher.fixLayout(); // re-hide hidden parts&#xD;                return;&#xD;            }&#xD;            // if no watcher exists, create a new one&#xD;            isGlobal = contains(&#xD;                proc.homeContext.receiver.globalVariables().names(),&#xD;                varName&#xD;            );&#xD;            if (isGlobal || target.owner) {&#xD;                label = name;&#xD;            } else {&#xD;                label = name + &apos; &apos; + localize(&apos;(temporary)&apos;);&#xD;            }&#xD;            watcher = new WatcherMorph(&#xD;                label,&#xD;                SpriteMorph.prototype.blockColor.variables,&#xD;                target,&#xD;                name&#xD;            );&#xD;            watcher.setPosition(stage.position().add(10));&#xD;            others = stage.watchers(watcher.left());&#xD;            if (others.length &gt; 0) {&#xD;                watcher.setTop(others[others.length - 1].bottom());&#xD;            }&#xD;            stage.add(watcher);&#xD;            watcher.fixLayout();&#xD;        }&#xD;    }</l></block><list><block var="name"/></list></block></script><list></list></block></script></block-definition><block-definition s="hide var %&apos;name&apos;" type="command" category="variables"><comment x="0" y="0" w="181" collapsed="false">This block turns off (hide) the watcher view on stage (if it was not already activated) of the variable with the given name (slot input).&#xD;&#xD;It can only access to the closest variable scope (if there different variables with the same name in different scopes) following the order &apos;script&apos; -&gt; &apos;sprite&apos; -&gt; &apos;global&apos;.&#xD;&#xD;No errors if that variable does not exist.</comment><header></header><code></code><translations>ca:amaga la variable _&#xD;es:esconder variable _&#xD;pt:esconde a variável _&#xD;de:verstecke var _&#xD;</translations><inputs><input type="%s"><options>§_getVarNamesDict</options></input></inputs><script><block s="doIf"><custom-block s="does var %s exist?"><block var="name"/></custom-block><script><block s="doRun"><block s="reportJSFunction"><list><l>varName</l><l>proc</l></list><l>    // to delete all temporary watchers, use the primitive "hide" with no inputs&#xD;    var varFrame = proc.homeContext.variables,&#xD;        stage,&#xD;        watcher,&#xD;        target,&#xD;        name = varName;&#xD;&#xD;    if (name instanceof Context) {&#xD;        if (name.expression.selector === &apos;reportGetVar&apos;) {&#xD;            name = name.expression.blockSpec;&#xD;        } else {&#xD;            proc.doChangePrimitiveVisibility(name.expression, true);&#xD;            return;&#xD;        }&#xD;    }&#xD;    if (!name) {&#xD;        proc.doRemoveTemporaries();&#xD;        return;&#xD;    }&#xD;    if (proc.homeContext.receiver) {&#xD;        stage = proc.homeContext.receiver.parentThatIsA(StageMorph);&#xD;        if (stage) {&#xD;            target = varFrame.find(name);&#xD;            watcher = detect(&#xD;                stage.children,&#xD;                morph =&gt; morph instanceof WatcherMorph &amp;&amp;&#xD;                    morph.target === target &amp;&amp;&#xD;                        morph.getter === name&#xD;            );&#xD;            if (watcher !== null) {&#xD;                if (watcher.isTemporary()) {&#xD;                    watcher.destroy();&#xD;                } else {&#xD;                    watcher.hide();&#xD;                }&#xD;            }&#xD;        }&#xD;    }&#xD;</l></block><list><block var="name"/></list></block></script><list></list></block></script></block-definition><block-definition s="create %&apos;scope&apos; var %&apos;names&apos;" type="command" category="variables"><comment x="0" y="0" w="146" collapsed="false">This block creates  new variables on the selected scope: global (for all sprites), sprite (for this sprite only) or script (only for that blocks stack) with the names given (in &apos;names&apos; list).&#xD;&#xD;If there is already a variable with that name in that scope, it does nothing: no errors and no overwrites.</comment><header></header><code></code><translations>pt:cria as variáveis _ _&#xD;ca:crea les _ variables _&#xD;es:crear las _ variables _&#xD;de:erstellen _ var _&#xD;</translations><inputs><input type="%s" readonly="true">global<options>global&#xD;sprite&#xD;script</options></input><input type="%mult%txt"></input></inputs><script><block s="doIfElse"><block s="reportVariadicEquals"><list><block var="scope"/><l>script</l></list></block><script><block s="doForEach"><l>each item</l><block var="names"/><script><block s="doRun"><block s="reportJSFunction"><list><l>varName</l><l>proc</l></list><l>if ((typeof varName) != "string" || varName === "") {&#xD;    throw new Error("name isn&apos;t a string: " + varName);&#xD;}&#xD;if (!proc.homeContext.variables.vars[varName]) proc.homeContext.variables.addVar(varName);</l></block><list><block var="each item"/></list></block></script></block></script><script><block s="doDeclareVariables"><list><l>global</l></list></block><block s="doIfElse"><block s="reportVariadicEquals"><list><block var="scope"/><l>sprite</l></list></block><script><block s="doSetVar"><l>global</l><block s="reportBoolean"><l><bool>false</bool></l></block></block></script><script><block s="doSetVar"><l>global</l><block s="reportBoolean"><l><bool>true</bool></l></block></block></script></block><block s="doForEach"><l>each item</l><block var="names"/><script><block s="doRun"><block s="reportJSFunction"><list><l>varName</l><l>global</l><l>proc</l></list><l>if ((typeof varName) != "string" || varName === "") {&#xD;    throw new Error("name isn&apos;t a string: " + varName);&#xD;}&#xD;if (global &amp;&amp; !proc.homeContext.variables.parentFrame.parentFrame.vars[varName]) this.addVariable(varName, true);&#xD;if (!global &amp;&amp; !proc.homeContext.variables.parentFrame.vars[varName]) this.addVariable(varName, false);</l></block><list><block var="each item"/><block var="global"/></list></block></script></block><block s="doRun"><block s="reportJSFunction"><list></list><l>var ide = this.parentThatIsA(IDE_Morph);&#xD;ide.flushBlocksCache(&apos;variables&apos;); // b/c of inheritance&#xD;ide.refreshPalette();</l></block><list></list></block></script></block></script></block-definition><block-definition s="fetch %&apos;url&apos; %&apos;data&apos;" type="reporter" category="sensing"><header></header><code></code><translations></translations><inputs><input type="%s"></input><input type="%s"></input></inputs><script><custom-block s="create %s var %mult%txt"><l>sprite</l><list><l>response</l></list></custom-block><block s="doRun"><block s="reportJSFunction"><list><l>url</l><l>proc</l></list><l>//Fetches data as a promise , on compleation saves to varable as text.&#xD;//if ((typeof varName) != "string") {&#xD;if ((typeof "response") != "string") {&#xD;    throw new Error("name isn&apos;t a string: " + varName);&#xD;}&#xD;&#xD;fetch(url)&#xD;  .then(response =&gt; response.json())&#xD;  .then(data =&gt; proc.homeContext.variables.setVar("response", JSON.stringify(data)));&#xD;&#xD;console.log(proc.homeContext.variables.allNames())</l></block><list><block var="url"/></list></block><block s="doWait"><l>0.2</l></block><block s="doReport"><block var="response"/></block></script></block-definition><block-definition s="%&apos;method&apos; url: %&apos;url&apos; send: %&apos;payload&apos; headers: %&apos;headers&apos;" type="reporter" category="sensing"><header></header><code></code><translations>pt:a resposta a _ de _ enviando _ e cabeçalhos _&#xD;</translations><inputs><input type="%s" readonly="true">GET<options>GET&#xD;POST&#xD;PUT&#xD;DELETE</options></input><input type="%s">https://snap.berkeley.edu</input><input type="%s"></input><input type="%mult%l" readonly="true"></input></inputs><script><custom-block s="create %s var %mult%txt"><l>sprite</l><list><l>response</l></list></custom-block><block s="doRun"><block s="reportJSFunction"><list><l>chosen_method</l><l>url</l><l>payload</l><l>headers</l><l>proc</l></list><l>console.log(chosen_method)&#xD;&#xD;payload = JSON.parse(payload)&#xD;&#xD;if (chosen_method == "GET") {&#xD;    fetch(url, {&#xD;            method: chosen_method&#xD;        })&#xD;        .then(response =&gt; response.json())&#xD;        .then(data =&gt; proc.homeContext.variables.setVar("response", JSON.stringify(data)))&#xD;} else if (chosen_method == "POST") {&#xD;    fetch(url, {&#xD;            method: chosen_method,&#xD;            headers: {&#xD;                &apos;Content-Type&apos;: &apos;application/json&apos;,&#xD;            },&#xD;            body: JSON.stringify(payload)&#xD;        })&#xD;        .then(response =&gt; response.json())&#xD;        .then(data =&gt; proc.homeContext.variables.setVar("response", JSON.stringify(data)))&#xD;}</l></block><list><block var="method"/><block var="url"/><block var="payload"/><block var="headers"/></list></block><block s="doWait"><l>0.5</l></block><block s="doReport"><block var="response"/></block></script></block-definition><block-definition s="Get Status of Robot: %&apos;robot&apos; at Server: %&apos;server&apos;" type="reporter" category="Advanced eBrain"><comment x="0" y="0" w="90" collapsed="false">#### - change to your robot&apos;s alphanumeric name</comment><header></header><code></code><translations>fr:Obtenir l&apos;état du robot: _ du serveur: _&#xD;</translations><inputs><input type="%s">RobotInACan-####</input><input type="%s">https://json.robotinacan.com/posts</input></inputs><script><block s="doReport"><custom-block s="fetch %s %s"><block s="reportJoinWords"><list><block var="server"/><l>?_sort=id&amp;_order=desc&amp;_limit=1&amp;bot=</l><block var="robot"/></list></block><l></l></custom-block></block></script></block-definition><block-definition s="Post to Server: %&apos;server&apos; Robot: %&apos;robot&apos; Command: %&apos;cmd&apos; Argument: %&apos;arg&apos;" type="command" category="Advanced eBrain"><header></header><code></code><translations>fr:Publier au serveur: _ robot: _ commande: _ argument: _&#xD;</translations><inputs><input type="%s">https://json.robotinacan.com/posts</input><input type="%s">RobotInACan-####</input><input type="%s">gpio_on<options>gpio_on&#xD;gpio_off&#xD;servo&#xD;servoII&#xD;forward&#xD;back&#xD;left&#xD;right&#xD;gpio_pwm_5&#xD;gpio_pwm_10&#xD;gpio_pwm_16</options></input><input type="%s">14</input></inputs><script><block s="doReport"><block s="evaluate"><block s="reifyReporter"><autolambda><custom-block s="%s url: %s send: %s headers: %mult%l"><l>POST</l><block var="server"/><block s="reportJoinWords"><list><l>{"cmd":"</l><block var="cmd"/><l>",  "arg":"</l><block var="arg"/><l>","bot":"</l><block var="robot"/><l>"}</l></list></block><list><l/></list></custom-block></autolambda><list></list></block><list></list></block></block></script></block-definition><block-definition s="Get Robot %&apos;Status&apos; Server: %&apos;server&apos; Robot: %&apos;robot&apos;" type="reporter" category="Advanced eBrain"><comment x="0" y="0" w="90" collapsed="false">#### - change to your robot&apos;s alphanumeric name</comment><header></header><code></code><translations>fr:Obtenir _ du serveur: _ et du robot: _&#xD;</translations><inputs><input type="%mlt" readonly="true">analog<options>analog&#xD;digital_pins&#xD;refresh_rate&#xD;distance&#xD;temperature&#xD;humidity&#xD;bot&#xD;id</options></input><input type="%s">https://json.robotinacan.com/posts</input><input type="%s">RobotInACan-####</input></inputs><script><block s="doDeclareVariables"><list><l>response</l></list></block><block s="doSetVar"><l>response</l><custom-block s="fetch %s %s"><block s="reportJoinWords"><list><block var="server"/><l>?_sort=id&amp;_order=desc&amp;_limit=1&amp;bot=</l><block var="robot"/></list></block><l></l></custom-block></block><block s="doIfElse"><block s="reportVariadicEquals"><list><block s="reportLetter"><l>1</l><block var="response"/></block><l>[</l></list></block><script><block s="doReport"><custom-block s="value at key %s of %l"><block var="Status"/><block s="reportListItem"><l>1</l><custom-block s="listify %mlt"><block var="response"/></custom-block></block></custom-block></block></script><script><block s="doReport"><l></l></block></script></block></script></block-definition><block-definition s="can use unsecure websocket" type="reporter" category="other"><header></header><code></code><translations>fr:peut utiliser un websocket non protégé&#xD;</translations><inputs></inputs><script><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>try {&#xD;    websock = new WebSocket(&apos;ws://example.com&apos;);&#xD;} catch (e) {&#xD;    return false;&#xD;}&#xD;return true;</l></block><list></list></block></block></script></block-definition><block-definition s="can use webserial" type="reporter" category="other"><header></header><code></code><translations>fr:peut utiliser webserial&#xD;</translations><inputs></inputs><script><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return navigator.serial !== undefined;</l></block><list></list></block></block></script></block-definition><block-definition s="subscribe to notifications on pin %&apos;pin&apos;" type="command" category="Advanced eBrain"><header></header><code></code><translations>fr:S&apos;abonner aux notifications de la broche _&#xD;</translations><inputs><input type="%n" readonly="true">4<options>4&#xD;14&#xD;12&#xD;13&#xD;0&#xD;2</options></input></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>pin</l><l>eb</l></list><l>world.moveon = 0;&#xD;eb.digitalNotify(pin,function(state, msg){&#xD;  if (state === &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><block var="pin"/><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list></list><l>return world.moveon;</l></block><list></list></block></block></script></block-definition><block-definition s="unsubscribe from notifications on pin %&apos;pin&apos;" type="command" category="Advanced eBrain"><header></header><code></code><translations>fr:Se désabonner aux notifications de la broche _&#xD;</translations><inputs><input type="%n" readonly="true">4<options>4&#xD;14&#xD;12&#xD;13&#xD;0&#xD;2</options></input></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>pin</l><l>eb</l></list><l>world.moveon = 0;&#xD;eb.digitalStopNotify(pin,function(state, msg){&#xD;  if (state === &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><block var="pin"/><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list></list><l>return world.moveon;</l></block><list></list></block></block></script></block-definition><block-definition s="subscription read from pin %&apos;pin&apos;" type="reporter" category="Advanced eBrain"><header></header><code></code><translations>fr:Lire de l&apos;abonnement à la broche _&#xD;</translations><inputs><input type="%s" readonly="true">4<options>4&#xD;14&#xD;12&#xD;13&#xD;0&#xD;2</options></input></inputs><script><block s="doIf"><block s="evaluate"><block s="reportJSFunction"><list><l>eb</l><l>pin</l></list><l>var index = &apos;pin_&apos; + pin + &apos;_status&apos;;&#xD;var pinValue = eb.sensorState[index];&#xD;return pinValue === null || pinValue === undefined;</l></block><list><custom-block s="connection object"></custom-block><block var="pin"/></list></block><script><block s="doRun"><block s="reportJSFunction"><list><l>pin</l></list><l>if (SnapTranslator.language.startsWith(&apos;fr&apos;)) {&#xD;  morphicAlert("Erreur", "Pas abonné à la broche " + pin + "!");&#xD;} else {&#xD;  morphicAlert("Error", "Not subscribed to pin " + pin + "!");&#xD;}</l></block><list><block var="pin"/></list></block></script><list></list></block><block s="doReport"><block s="evaluate"><block s="reportJSFunction"><list><l>eb</l><l>pin</l></list><l>var index = &apos;pin_&apos; + pin + &apos;_status&apos;;&#xD;var pinValue = eb.sensorState[index];&#xD;return pinValue;</l></block><list><custom-block s="connection object"></custom-block><block var="pin"/></list></block></block></script></block-definition><block-definition s="Compass Read" type="reporter" category="eBrain"><header></header><code></code><translations>fr:Lire la boussole&#xD;</translations><inputs></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>eb</l></list><l>world.moveon = 0;&#xD;eb.compass(function(state, msg){&#xD;  if (state === &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block><block s="doReport"><block s="reportNewList"><list><block s="evaluate"><block s="reportJSFunction"><list><l>eb</l></list><l>return eb.compassSensor.x;</l></block><list><custom-block s="connection object"></custom-block></list></block><block s="evaluate"><block s="reportJSFunction"><list><l>eb</l></list><l>return eb.compassSensor.y;</l></block><list><custom-block s="connection object"></custom-block></list></block><block s="evaluate"><block s="reportJSFunction"><list><l>eb</l></list><l>return eb.compassSensor.z;</l></block><list><custom-block s="connection object"></custom-block></list></block></list></block></block></script></block-definition><block-definition s="Pause" type="command" category="other"><header></header><code></code><translations>fr:Pauser&#xD;</translations><inputs></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>eb</l></list><l>world.moveons.pause = 0;&#xD;eb.pause(function(state, msg){&#xD;  if (state === &apos;complete&apos;) {&#xD;    world.moveons.pause = 1;&#xD;  }&#xD;});</l></block><list><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list></list><l>return world.moveons.pause;</l></block><list></list></block></block></script></block-definition><block-definition s="Resume" type="command" category="other"><header></header><code></code><translations>fr:Résumer&#xD;</translations><inputs></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>eb</l></list><l>world.moveons.resume = 0;&#xD;eb.resume(function(state, msg){&#xD;  if (state === &apos;complete&apos;) {&#xD;    world.moveons.resume = 1;&#xD;  }&#xD;});</l></block><list><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list></list><l>return world.moveons.resume;</l></block><list></list></block></block></script></block-definition><block-definition s="Advanced Move: Left: %&apos;leftAmount&apos; mm speed: %&apos;leftSpeed&apos; Right: %&apos;rightAmount&apos; mm speed: %&apos;rightSpeed&apos; Unit: %&apos;unit&apos;" type="command" category="eBrain"><header></header><code></code><translations>fr:Déplacement avancé: Moteur de gauche: _ mm vitesse: _ Moteur de droite: _ mm vitesse: _ Unité: _&#xD;</translations><inputs><input type="%n">50</input><input type="%n">1</input><input type="%n">100</input><input type="%n">0.8</input><input type="%s" readonly="true">mm<options>mm&#xD;steps</options></input></inputs><script><block s="doIfElse"><custom-block s="version is at least %s"><l>3.3.1</l></custom-block><script><block s="doIfElse"><block s="reportVariadicEquals"><list><block var="unit"/><l>steps</l></list></block><script><block s="doRun"><block s="reportJSFunction"><list><l>leftSteps</l><l>leftSpeed</l><l>rightSteps</l><l>rightSpeed</l><l>eb</l></list><l>world.moveon = 0;&#xD;eb.advancedMoveSteps(leftSteps, leftSpeed, rightSteps, rightSpeed,&#xD;function(state, msg){&#xD;  if (state == &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});&#xD;</l></block><list><block var="leftAmount"/><block var="leftSpeed"/><block var="rightAmount"/><block var="rightSpeed"/><custom-block s="connection object"></custom-block></list></block></script><script><block s="doRun"><block s="reportJSFunction"><list><l>leftMM</l><l>leftSpeed</l><l>rightMM</l><l>rightSpeed</l><l>eb</l></list><l>world.moveon = 0;&#xD;eb.advancedMove(leftMM, leftSpeed, rightMM, rightSpeed,&#xD;function(state, msg){&#xD;  if (state == &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});&#xD;</l></block><list><block var="leftAmount"/><block var="leftSpeed"/><block var="rightAmount"/><block var="rightSpeed"/><custom-block s="connection object"></custom-block></list></block></script></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list></list><l>return world.moveon;</l></block><list></list></block></block></script><script><block s="doRun"><block s="reportJSFunction"><list></list><l>morphicAlert("Error!", "Your eBrain must be at least at firmware version 3.3.1 to use this block");</l></block><list></list></block></script></block></script></block-definition><block-definition s="Get Config Value %&apos;name&apos;" type="reporter" category="other"><header></header><code></code><translations>fr:Obtenir la valeur de la configuration: _&#xD;</translations><inputs><input type="%s"></input></inputs><script><block s="doReport"><block s="reportListItem"><l>2</l><block s="reportFindFirst"><block s="reifyPredicate"><autolambda><block s="reportVariadicEquals"><list><block s="reportListItem"><l>1</l><block var="value"/></block><block var="name"/></list></block></autolambda><list><l>value</l></list></block><block s="reportTextSplit"><custom-block s="Get Config"></custom-block><l><option>json</option></l></block></block></block></block></script></block-definition><block-definition s="Calibrate slack %&apos;slack amount&apos;" type="command" category="eBrain"><header></header><code></code><translations>fr:Calibrer le jeu des moteurs: _&#xD;</translations><inputs><input type="%n">20</input></inputs><script><block s="doRun"><block s="reportJSFunction"><list><l>slackAmount</l><l>eb</l></list><l>world.moveon = 0;&#xD;eb.calibrateSlack(slackAmount,function(state, msg){&#xD;  if (state == &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});&#xD;</l></block><list><block var="slack amount"/><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list></list><l>return world.moveon;</l></block><list></list></block></block></script></block-definition><block-definition s="Set Servo on Pin: %&apos;pin&apos; to Angle: %&apos;angle&apos;" type="command" category="eBrain"><header></header><code></code><translations>fr:Mettre le servo à la broche: _ à l&apos;angle: _&#xD;</translations><inputs><input type="%n" readonly="true">16<options>0&#xD;2&#xD;4&#xD;5&#xD;10&#xD;16&#xD;14&#xD;12&#xD;13</options></input><input type="%n">90</input></inputs><script><block s="doIfElse"><custom-block s="version is at least %s"><l>3.3.1</l></custom-block><script><block s="doRun"><block s="reportJSFunction"><list><l>pin</l><l>angle</l><l>eb</l></list><l>world.moveon = 0;&#xD;eb.pinServo(pin, angle, function(state, msg){&#xD;  if (state === &apos;complete&apos;) {&#xD;    world.moveon = 1;&#xD;  }&#xD;});</l></block><list><block var="pin"/><block var="angle"/><custom-block s="connection object"></custom-block></list></block><block s="doWaitUntil"><block s="evaluate"><block s="reportJSFunction"><list><l></l></list><l>return world.moveon;</l></block><list></list></block></block></script><script><block s="doRun"><block s="reportJSFunction"><list></list><l>morphicAlert("Error!", "Your eBrain must be at least at firmware version 3.3.1 to use this block");</l></block><list></list></block></script></block></script></block-definition><block-definition s="Servo Robot $arrowUp %&apos;n&apos; seconds" type="command" category="Servo Robot"><header></header><code></code><translations></translations><inputs><input type="%n">1</input></inputs><script><block s="doRepeat"><block var="n"/><script><custom-block s="Set Servo on Pin: %n to Angle: %n"><l>16</l><l>180</l></custom-block><custom-block s="Set Servo on Pin: %n to Angle: %n"><l>10</l><l>0</l></custom-block><block s="doWait"><l>1</l></block></script></block></script></block-definition><block-definition s="Servo Robot $arrowLeft %&apos;n&apos; seconds" type="command" category="Servo Robot"><header></header><code></code><translations></translations><inputs><input type="%n">0.4</input></inputs><script><block s="doResetTimer"></block><block s="doIfElse"><block s="reportVariadicLessThan"><list><block var="n"/><l>1</l></list></block><script><block s="doUntil"><block s="reportVariadicGreaterThan"><list><block s="getTimer"></block><block var="n"/></list></block><script><custom-block s="Set Servo on Pin: %n to Angle: %n"><l>16</l><l>0</l></custom-block><custom-block s="Set Servo on Pin: %n to Angle: %n"><l>10</l><l>0</l></custom-block><block s="doWait"><l>0.1</l></block></script></block><custom-block s="Set Servo on Pin: %n to Angle: %n"><l>16</l><l>90</l></custom-block><custom-block s="Set Servo on Pin: %n to Angle: %n"><l>10</l><l>90</l></custom-block></script><script><block s="doRepeat"><block var="n"/><script><custom-block s="Set Servo on Pin: %n to Angle: %n"><l>16</l><l>0</l></custom-block><custom-block s="Set Servo on Pin: %n to Angle: %n"><l>10</l><l>0</l></custom-block><block s="doWait"><l>1</l></block></script></block></script></block></script></block-definition><block-definition s="Servo Robot $arrowRight %&apos;n&apos; seconds" type="command" category="Servo Robot"><header></header><code></code><translations></translations><inputs><input type="%n">0.4</input></inputs><script><block s="doResetTimer"></block><block s="doIfElse"><block s="reportVariadicLessThan"><list><block var="n"/><l>1</l></list></block><script><block s="doUntil"><block s="reportVariadicGreaterThan"><list><block s="getTimer"></block><block var="n"/></list></block><script><custom-block s="Set Servo on Pin: %n to Angle: %n"><l>16</l><l>180</l></custom-block><custom-block s="Set Servo on Pin: %n to Angle: %n"><l>10</l><l>180</l></custom-block><block s="doWait"><l>0.1</l></block></script></block><custom-block s="Set Servo on Pin: %n to Angle: %n"><l>16</l><l>90</l></custom-block><custom-block s="Set Servo on Pin: %n to Angle: %n"><l>10</l><l>90</l></custom-block></script><script><block s="doRepeat"><block var="n"/><script><custom-block s="Set Servo on Pin: %n to Angle: %n"><l>16</l><l>180</l></custom-block><custom-block s="Set Servo on Pin: %n to Angle: %n"><l>10</l><l>180</l></custom-block><block s="doWait"><l>1</l></block></script></block></script></block></script></block-definition><block-definition s="Servo Robot $arrowDown %&apos;n&apos; seconds" type="command" category="Servo Robot"><header></header><code></code><translations></translations><inputs><input type="%n">1</input></inputs><script><block s="doRepeat"><block var="n"/><script><custom-block s="Set Servo on Pin: %n to Angle: %n"><l>16</l><l>0</l></custom-block><custom-block s="Set Servo on Pin: %n to Angle: %n"><l>10</l><l>180</l></custom-block><block s="doWait"><l>1</l></block></script></block></script></block-definition></blocks><stage name="Stage" width="480" height="360" costume="0" color="35,0,157,1" tempo="60" threadsafe="false" penlog="false" volume="100" pan="0" lines="round" ternary="false" hyperops="true" codify="false" inheritance="true" sublistIDs="false" id="2376"><pentrails>data:image/png;base64,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</pentrails><costumes><list struct="atomic" id="2377"></list></costumes><sounds><list struct="atomic" id="2378"></list></sounds><variables></variables><blocks></blocks><scripts><script x="99.16666666666667" y="57.5"><block s="receiveGo"></block><block s="setBackgroundColor"><color>35,0,157,1</color></block></script></scripts><sprites select="0"><watcher scope="Sprite" var="id" style="normal" x="10" y="10" color="243,118,29"/><sprite name="Sprite" idx="1" x="-99" y="1" heading="90" scale="0.4" volume="100" pan="0" rotation="1" draggable="true" costume="1" color="80,80,80,1" pen="tip" id="2387"><costumes><list id="2388"><item><ref mediaID="Sprite_cst_costume1"></ref></item></list></costumes><sounds><list struct="atomic" id="2389"></list></sounds><blocks></blocks><variables><variable name="id"><l>0</l></variable></variables><scripts><script x="8.333333333333334" y="8.333333333333334"><block s="receiveGo"></block><block s="doSetVar"><l>id</l><l>0</l></block><block s="clearEffects"></block><block s="show"></block><block s="gotoXY"><l>-120</l><l>0</l></block><block s="setScale"><l>40</l></block><block s="doRepeat"><l>7</l><script><block s="doChangeVar"><l>id</l><l>1</l></block><block s="createClone"><l><option>myself</option></l></block><block s="forward"><l>40</l></block><block s="changeEffect"><l><option>color</option></l><l>-5</l></block></script></block><block s="doSetVar"><l>id</l><l>0</l></block><block s="gotoXY"><l>-150</l><l>100</l></block><block s="doForever"><script><block s="bubble"><block s="reportAudio"><l><option>volume</option></l></block></block><block s="doIf"><block s="reportVariadicGreaterThan"><list><block s="reportAudio"><l><option>volume</option></l></block><l>36</l></list></block><script><block s="doRepeat"><l>5</l><script><block s="doPlayNote"><l>71</l><l>0.2</l></block><block s="doPlayNote"><l>70</l><l>0.2</l></block></script></block></script><list></list></block></script></block></script><script x="295" y="114.49999999999999"><block s="receiveOnClone"></block><block s="doForever"><script><block s="bubble"><block var="id"/></block><block s="doIfElse"><block s="reportVariadicGreaterThan"><list><block s="reportAudio"><l><option>volume</option></l></block><block s="reportVariadicProduct"><list><block var="id"/><l>5</l></list></block></list></block><script><block s="setEffect"><l><option>brightness</option></l><l>70</l></block></script><script><block s="setEffect"><l><option>brightness</option></l><l>0</l></block></script></block></script></block></script></scripts></sprite></sprites></stage><variables></variables></scene></scenes></project><media name="RIAC Sound Levels" app="Snap! 9.0, https://snap.berkeley.edu" version="2"><costume name="costume1" center-x="47.5" center-y="47.5" image="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHNuYXA9Imh0dHA6Ly9zbmFwLmJlcmtlbGV5LmVkdS9ydW4iIHZlcnNpb249IjEuMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSBtZWV0IiB2aWV3Qm94PSI2NTMuNSAyMjkuNSA5NSA5NSIgd2lkdGg9Ijk1IiBoZWlnaHQ9Ijk1Ij48ZWxsaXBzZSBzdHJva2U9InJnYigwLDAsMCkiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS13aWR0aD0iMyIgZmlsbD0icmdiKDAsNzcsNSkiIHByb3RvdHlwZT0iVmVjdG9yRWxsaXBzZSIgY3g9IjcwMSIgY3k9IjI3NyIgcng9IjQ2IiByeT0iNDYiLz48L3N2Zz4=" mediaID="Sprite_cst_costume1"/></media></snapdata>