text: //basic nodes
  (function(global) {
      var LiteGraph = global.LiteGraph;
  
      //Constant
      function Time() {
          this.addOutput("in ms", "number");
          this.addOutput("in sec", "number");
      }
  
      Time.title = "Time";
      Time.desc = "Time";
  
      Time.prototype.onExecute = function() {
          this.setOutputData(0, this.graph.globaltime * 1000);
          this.setOutputData(1, this.graph.globaltime);
      };
  
      LiteGraph.registerNodeType("basic/time", Time);
  
      //Subgraph: a node that contains a graph
      function Subgraph() {
          var that = this;
          this.size = [140, 80];
          this.properties = { enabled: true };
          this.enabled = true;
  
          //create inner graph
          this.subgraph = new LiteGraph.LGraph();
          this.subgraph._subgraph_node = this;
          this.subgraph._is_subgraph = true;
  
          this.subgraph.onTrigger = this.onSubgraphTrigger.bind(this);
  
          this.subgraph.onInputAdded = this.onSubgraphNewInput.bind(this);
          this.subgraph.onInputRenamed = this.onSubgraphRenamedInput.bind(this);
          this.subgraph.onInputTypeChanged = this.onSubgraphTypeChangeInput.bind(
              this
          );
          this.subgraph.onInputRemoved = this.onSubgraphRemovedInput.bind(this);
  
          this.subgraph.onOutputAdded = this.onSubgraphNewOutput.bind(this);
          this.subgraph.onOutputRenamed = this.onSubgraphRenamedOutput.bind(this);
          this.subgraph.onOutputTypeChanged = this.onSubgraphTypeChangeOutput.bind(
              this
          );
          this.subgraph.onOutputRemoved = this.onSubgraphRemovedOutput.bind(this);
      }
  
      Subgraph.title = "Subgraph";
      Subgraph.desc = "Graph inside a node";
      Subgraph.title_color = "#334";
  
      Subgraph.prototype.onGetInputs = function() {
          return [["enabled", "boolean"]];
      };
  
      Subgraph.prototype.onDrawTitle = function(ctx) {
          if (this.flags.collapsed) {
              return;
          }
  
          ctx.fillStyle = "#555";
          var w = LiteGraph.NODE_TITLE_HEIGHT;
          var x = this.size[0] - w;
          ctx.fillRect(x, -w, w, w);
          ctx.fillStyle = "#333";
          ctx.beginPath();
          ctx.moveTo(x + w * 0.2, -w * 0.6);
          ctx.lineTo(x + w * 0.8, -w * 0.6);
          ctx.lineTo(x + w * 0.5, -w * 0.3);
          ctx.fill();
      };
  
      Subgraph.prototype.onDblClick = function(e, pos, graphcanvas) {
          var that = this;
          setTimeout(function() {
              graphcanvas.openSubgraph(that.subgraph);
          }, 10);
      };
  
      Subgraph.prototype.onMouseDown = function(e, pos, graphcanvas) {
          if (
              !this.flags.collapsed &&
              pos[0] > this.size[0] - LiteGraph.NODE_TITLE_HEIGHT &&
              pos[1] < 0
          ) {
              var that = this;
              setTimeout(function() {
                  graphcanvas.openSubgraph(that.subgraph);
              }, 10);
          }
      };
  
      Subgraph.prototype.onAction = function(action, param) {
          this.subgraph.onAction(action, param);
      };
  
      Subgraph.prototype.onExecute = function() {
          this.enabled = this.getInputOrProperty("enabled");
          if (!this.enabled) {
              return;
          }
  
          //send inputs to subgraph global inputs
          if (this.inputs) {
              for (var i = 0; i < this.inputs.length; i++) {
                  var input = this.inputs[i];
                  var value = this.getInputData(i);
                  this.subgraph.setInputData(input.name, value);
              }
          }
  
          //execute
          this.subgraph.runStep();
  
          //send subgraph global outputs to outputs
          if (this.outputs) {
              for (var i = 0; i < this.outputs.length; i++) {
                  var output = this.outputs[i];
                  var value = this.subgraph.getOutputData(output.name);
                  this.setOutputData(i, value);
              }
          }
      };
  
      Subgraph.prototype.sendEventToAllNodes = function(eventname, param, mode) {
          if (this.enabled) {
              this.subgraph.sendEventToAllNodes(eventname, param, mode);
          }
      };
  
      //**** INPUTS ***********************************
      Subgraph.prototype.onSubgraphTrigger = function(event, param) {
          var slot = this.findOutputSlot(event);
          if (slot != -1) {
              this.triggerSlot(slot);
          }
      };
  
      Subgraph.prototype.onSubgraphNewInput = function(name, type) {
          var slot = this.findInputSlot(name);
          if (slot == -1) {
              //add input to the node
              this.addInput(name, type);
          }
      };
  
      Subgraph.prototype.onSubgraphRenamedInput = function(oldname, name) {
          var slot = this.findInputSlot(oldname);
          if (slot == -1) {
              return;
          }
          var info = this.getInputInfo(slot);
          info.name = name;
      };
  
      Subgraph.prototype.onSubgraphTypeChangeInput = function(name, type) {
          var slot = this.findInputSlot(name);
          if (slot == -1) {
              return;
          }
          var info = this.getInputInfo(slot);
          info.type = type;
      };
  
      Subgraph.prototype.onSubgraphRemovedInput = function(name) {
          var slot = this.findInputSlot(name);
          if (slot == -1) {
              return;
          }
          this.removeInput(slot);
      };
  
      //**** OUTPUTS ***********************************
      Subgraph.prototype.onSubgraphNewOutput = function(name, type) {
          var slot = this.findOutputSlot(name);
          if (slot == -1) {
              this.addOutput(name, type);
          }
      };
  
      Subgraph.prototype.onSubgraphRenamedOutput = function(oldname, name) {
          var slot = this.findOutputSlot(oldname);
          if (slot == -1) {
              return;
          }
          var info = this.getOutputInfo(slot);
          info.name = name;
      };
  
      Subgraph.prototype.onSubgraphTypeChangeOutput = function(name, type) {
          var slot = this.findOutputSlot(name);
          if (slot == -1) {
              return;
          }
          var info = this.getOutputInfo(slot);
          info.type = type;
      };
  
      Subgraph.prototype.onSubgraphRemovedOutput = function(name) {
          var slot = this.findInputSlot(name);
          if (slot == -1) {
              return;
          }
          this.removeOutput(slot);
      };
      // *****************************************************
  
      Subgraph.prototype.getExtraMenuOptions = function(graphcanvas) {
          var that = this;
          return [
              {
                  content: "Open",
                  callback: function() {
                      graphcanvas.openSubgraph(that.subgraph);
                  }
              }
          ];
      };
  
      Subgraph.prototype.onResize = function(size) {
          size[1] += 20;
      };
  
      Subgraph.prototype.serialize = function() {
          var data = LGraphNode.prototype.serialize.call(this);
          data.subgraph = this.subgraph.serialize();
          return data;
      };
      //no need to define node.configure, the default method detects node.subgraph and passes the object to node.subgraph.configure()
  
      Subgraph.prototype.clone = function() {
          var node = LiteGraph.createNode(this.type);
          var data = this.serialize();
          delete data["id"];
          delete data["inputs"];
          delete data["outputs"];
          node.configure(data);
          return node;
      };
  
      LiteGraph.Subgraph = Subgraph;
      LiteGraph.registerNodeType("graph/subgraph", Subgraph);
  
      //Input for a subgraph
      function GraphInput() {
          this.addOutput("", "number");
  
          this.name_in_graph = "";
          this.properties = {
  			name: "",
  			type: "number",
  			value: 0
  		}; 
  
          var that = this;
  
          this.name_widget = this.addWidget(
              "text",
              "Name",
              this.properties.name,
              function(v) {
                  if (!v) {
                      return;
                  }
                  that.setProperty("name",v);
              }
          );
          this.type_widget = this.addWidget(
              "text",
              "Type",
              this.properties.type,
              function(v) {
  				that.setProperty("type",v);
              }
          );
  
          this.value_widget = this.addWidget(
              "number",
              "Value",
              this.properties.value,
              function(v) {
                  that.setProperty("value",v);
              }
          );
  
          this.widgets_up = true;
          this.size = [180, 90];
      }
  
      GraphInput.title = "Input";
      GraphInput.desc = "Input of the graph";
  
  	GraphInput.prototype.onConfigure = function()
  	{
  		this.updateType();
  	}
  
  	GraphInput.prototype.updateType = function()
  	{
  		var type = this.properties.type;
  		this.type_widget.value = type;
  		if(type == "number")
  		{
  			this.value_widget.type = "number";
  			this.value_widget.value = 0;
  		}
  		else if(type == "bool")
  		{
  			this.value_widget.type = "toggle";
  			this.value_widget.value = true;
  		}
  		else if(type == "string")
  		{
  			this.value_widget.type = "text";
  			this.value_widget.value = "";
  		}
  		else
  		{
  			this.value_widget.type = null;
  			this.value_widget.value = null;
  		}
  		this.properties.value = this.value_widget.value;
  	}
  
  	GraphInput.prototype.onPropertyChanged = function(name,v)
  	{
  		if( name == "name" )
  		{
  			if (v == "" || v == this.name_in_graph || v == "enabled") {
  				return false;
  			}
  			if(this.graph)
  			{
  				if (this.name_in_graph) {
  					//already added
  					this.graph.renameInput( this.name_in_graph, v );
  				} else {
  					this.graph.addInput( v, this.properties.type );
  				}
  			} //what if not?!
  			this.name_widget.value = v;
  			this.name_in_graph = v;
  		}
  		else if( name == "type" )
  		{
  			v = v || "";
  			this.updateType(v);
  		}
  		else if( name == "value" )
  		{
  		}
  	}
  
      GraphInput.prototype.getTitle = function() {
          if (this.flags.collapsed) {
              return this.properties.name;
          }
          return this.title;
      };
  
      GraphInput.prototype.onAction = function(action, param) {
          if (this.properties.type == LiteGraph.EVENT) {
              this.triggerSlot(0, param);
          }
      };
  
      GraphInput.prototype.onExecute = function() {
          var name = this.properties.name;
          //read from global input
          var data = this.graph.inputs[name];
          if (!data) {
              this.setOutputData(0, this.properties.value );
          }
          this.setOutputData(0, data.value === undefined ? this.properties.value : data.value);
      };
  
      GraphInput.prototype.onRemoved = function() {
          if (this.name_in_graph) {
              this.graph.removeInput(this.name_in_graph);
          }
      };
  
      LiteGraph.GraphInput = GraphInput;
      LiteGraph.registerNodeType("graph/input", GraphInput);
  
      //Output for a subgraph
      function GraphOutput() {
          this.addInput("", "");
  
          this.name_in_graph = "";
          this.properties = {};
          var that = this;
  
          Object.defineProperty(this.properties, "name", {
              get: function() {
                  return that.name_in_graph;
              },
              set: function(v) {
                  if (v == "" || v == that.name_in_graph) {
                      return;
                  }
                  if (that.name_in_graph) {
                      //already added
                      that.graph.renameOutput(that.name_in_graph, v);
                  } else {
                      that.graph.addOutput(v, that.properties.type);
                  }
                  that.name_widget.value = v;
                  that.name_in_graph = v;
              },
              enumerable: true
          });
  
          Object.defineProperty(this.properties, "type", {
              get: function() {
                  return that.inputs[0].type;
              },
              set: function(v) {
                  if (v == "action" || v == "event") {
                      v = LiteGraph.ACTION;
                  }
                  that.inputs[0].type = v;
                  if (that.name_in_graph) {
                      //already added
                      that.graph.changeOutputType(
                          that.name_in_graph,
                          that.inputs[0].type
                      );
                  }
                  that.type_widget.value = v || "";
              },
              enumerable: true
          });
  
          this.name_widget = this.addWidget(
              "text",
              "Name",
              this.properties.name,
              function(v) {
                  if (!v) {
                      return;
                  }
                  that.properties.name = v;
              }
          );
          this.type_widget = this.addWidget(
              "text",
              "Type",
              this.properties.type,
              function(v) {
                  v = v || "";
                  that.properties.type = v;
              }
          );
  
          this.widgets_up = true;
          this.size = [180, 60];
      }
  
      GraphOutput.title = "Output";
      GraphOutput.desc = "Output of the graph";
  
      GraphOutput.prototype.onExecute = function() {
          this._value = this.getInputData(0);
          this.graph.setOutputData(this.properties.name, this._value);
      };
  
      GraphOutput.prototype.onAction = function(action, param) {
          if (this.properties.type == LiteGraph.ACTION) {
              this.graph.trigger(this.properties.name, param);
          }
      };
  
      GraphOutput.prototype.onRemoved = function() {
          if (this.name_in_graph) {
              this.graph.removeOutput(this.name_in_graph);
          }
      };
  
      GraphOutput.prototype.getTitle = function() {
          if (this.flags.collapsed) {
              return this.properties.name;
          }
          return this.title;
      };
  
      LiteGraph.GraphOutput = GraphOutput;
      LiteGraph.registerNodeType("graph/output", GraphOutput);
  
      //Constant
      function ConstantNumber() {
          this.addOutput("value", "number");
          this.addProperty("value", 1.0);
      }
  
      ConstantNumber.title = "Const Number";
      ConstantNumber.desc = "Constant number";
  
      ConstantNumber.prototype.onExecute = function() {
          this.setOutputData(0, parseFloat(this.properties["value"]));
      };
  
      ConstantNumber.prototype.getTitle = function() {
          if (this.flags.collapsed) {
              return this.properties.value;
          }
          return this.title;
      };
  
      ConstantNumber.prototype.setValue = function(v) {
          this.properties.value = v;
      };
  
      ConstantNumber.prototype.onDrawBackground = function(ctx) {
          //show the current value
          this.outputs[0].label = this.properties["value"].toFixed(3);
      };
  
      LiteGraph.registerNodeType("basic/const", ConstantNumber);
  
      function ConstantString() {
          this.addOutput("", "string");
          this.addProperty("value", "");
          this.widget = this.addWidget(
              "text",
              "value",
              "",
              this.setValue.bind(this)
          );
          this.widgets_up = true;
          this.size = [100, 30];
      }
  
      ConstantString.title = "Const String";
      ConstantString.desc = "Constant string";
  
      ConstantString.prototype.setValue = function(v) {
          this.properties.value = v;
      };
  
      ConstantString.prototype.onPropertyChanged = function(name, value) {
          this.widget.value = value;
      };
  
      ConstantString.prototype.getTitle = ConstantNumber.prototype.getTitle;
  
      ConstantString.prototype.onExecute = function() {
          this.setOutputData(0, this.properties["value"]);
      };
  
      LiteGraph.registerNodeType("basic/string", ConstantString);
  
      function ConstantData() {
          this.addOutput("", "");
          this.addProperty("value", "");
          this.widget = this.addWidget(
              "text",
              "json",
              "",
              this.setValue.bind(this)
          );
          this.widgets_up = true;
          this.size = [140, 30];
          this._value = null;
      }
  
      ConstantData.title = "Const Data";
      ConstantData.desc = "Constant Data";
  
      ConstantData.prototype.setValue = function(v) {
          this.properties.value = v;
          this.onPropertyChanged("value", v);
      };
  
      ConstantData.prototype.onPropertyChanged = function(name, value) {
          this.widget.value = value;
          if (value == null || value == "") {
              return;
          }
  
          try {
              this._value = JSON.parse(value);
              this.boxcolor = "#AEA";
          } catch (err) {
              this.boxcolor = "red";
          }
      };
  
      ConstantData.prototype.onExecute = function() {
          this.setOutputData(0, this._value);
      };
  
      LiteGraph.registerNodeType("basic/data", ConstantData);
  
      function ObjectProperty() {
          this.addInput("obj", "");
          this.addOutput("", "");
          this.addProperty("value", "");
          this.widget = this.addWidget(
              "text",
              "prop.",
              "",
              this.setValue.bind(this)
          );
          this.widgets_up = true;
          this.size = [140, 30];
          this._value = null;
      }
  
      ObjectProperty.title = "Object property";
      ObjectProperty.desc = "Outputs the property of an object";
  
      ObjectProperty.prototype.setValue = function(v) {
          this.properties.value = v;
          this.widget.value = v;
      };
  
      ObjectProperty.prototype.getTitle = function() {
          if (this.flags.collapsed) {
              return "in." + this.properties.value;
          }
          return this.title;
      };
  
      ObjectProperty.prototype.onPropertyChanged = function(name, value) {
          this.widget.value = value;
      };
  
      ObjectProperty.prototype.onExecute = function() {
          var data = this.getInputData(0);
          if (data != null) {
              this.setOutputData(0, data[this.properties.value]);
          }
      };
  
      LiteGraph.registerNodeType("basic/object_property", ObjectProperty);
  
      function ObjectKeys() {
          this.addInput("obj", "");
          this.addOutput("keys", "array");
          this.size = [140, 30];
      }
  
      ObjectKeys.title = "Object keys";
      ObjectKeys.desc = "Outputs an array with the keys of an object";
  
      ObjectKeys.prototype.onExecute = function() {
          var data = this.getInputData(0);
          if (data != null) {
              this.setOutputData(0, Object.keys(data) );
          }
      };
  
      LiteGraph.registerNodeType("basic/object_keys", ObjectKeys);
  
      function MergeObjects() {
          this.addInput("A", "object");
          this.addInput("B", "object");
          this.addOutput("", "object");
  		this._result = {};
  		var that = this;
  		this.addWidget("button","clear","",function(){
  			that._result = {};
  		});
  		this.size = this.computeSize();
      }
  
      MergeObjects.title = "Merge Objects";
      MergeObjects.desc = "Creates an object copying properties from others";
  
      MergeObjects.prototype.onExecute = function() {
          var A = this.getInputData(0);
          var B = this.getInputData(1);
  		var C = this._result;
  		if(A)
  			for(var i in A)
  				C[i] = A[i];
  		if(B)
  			for(var i in B)
  				C[i] = B[i];
  		this.setOutputData(0,C);
      };
  
      LiteGraph.registerNodeType("basic/merge_objects", MergeObjects );
  
      //Store as variable
      function Variable() {
          this.size = [60, 30];
          this.addInput("in");
          this.addOutput("out");
  		this.properties = { varname: "myname", global: false };
          this.value = null;
      }
  
      Variable.title = "Variable";
      Variable.desc = "store/read variable value";
  
      Variable.prototype.onExecute = function() {
  		this.value = this.getInputData(0);
  		if(this.graph)
  			this.graph.vars[ this.properties.varname ] = this.value;
  		if(this.properties.global)
  			global[this.properties.varname] = this.value;
  		this.setOutputData(0, this.value );
      };
  
      Variable.prototype.getTitle = function() {
          return this.properties.varname;
      };
  
      LiteGraph.registerNodeType("basic/variable", Variable);
  
  
  	function DownloadData() {
          this.size = [60, 30];
          this.addInput("data", 0 );
          this.addInput("download", LiteGraph.ACTION );
  		this.properties = { filename: "data.json" };
          this.value = null;
  		var that = this;
  		this.addWidget("button","Download","", function(v){
  			if(!that.value)
  				return;
  			that.downloadAsFile();
  		});
      }
  
      DownloadData.title = "Download";
      DownloadData.desc = "Download some data";
  
  	DownloadData.prototype.downloadAsFile = function()
  	{
  		if(this.value == null)
  			return;
  
  		var str = null;
  		if(this.value.constructor === String)
  			str = this.value;
  		else
  			str = JSON.stringify(this.value);
  
  		var file = new Blob([str]);
  		var url = URL.createObjectURL( file );
  		var element = document.createElement("a");
  		element.setAttribute('href', url);
  		element.setAttribute('download', this.properties.filename );
  		element.style.display = 'none';
  		document.body.appendChild(element);
  		element.click();
  		document.body.removeChild(element);
  		setTimeout( function(){ URL.revokeObjectURL( url ); }, 1000*60 ); //wait one minute to revoke url
  	}
  
      DownloadData.prototype.onAction = function(action, param) {
  		var that = this;
  		setTimeout( function(){ that.downloadAsFile(); }, 100); //deferred to avoid blocking the renderer with the popup
  	}
  
      DownloadData.prototype.onExecute = function() {
          if (this.inputs[0]) {
              this.value = this.getInputData(0);
          }
      };
  
      DownloadData.prototype.getTitle = function() {
          if (this.flags.collapsed) {
              return this.properties.filename;
          }
          return this.title;
      };
  
      LiteGraph.registerNodeType("basic/download", DownloadData);
  
  
  
      //Watch a value in the editor
      function Watch() {
          this.size = [60, 30];
          this.addInput("value", 0, { label: "" });
          this.value = 0;
      }
  
      Watch.title = "Watch";
      Watch.desc = "Show value of input";
  
      Watch.prototype.onExecute = function() {
          if (this.inputs[0]) {
              this.value = this.getInputData(0);
          }
      };
  
      Watch.prototype.getTitle = function() {
          if (this.flags.collapsed) {
              return this.inputs[0].label;
          }
          return this.title;
      };
  
      Watch.toString = function(o) {
          if (o == null) {
              return "null";
          } else if (o.constructor === Number) {
              return o.toFixed(3);
          } else if (o.constructor === Array) {
              var str = "[";
              for (var i = 0; i < o.length; ++i) {
                  str += Watch.toString(o[i]) + (i + 1 != o.length ? "," : "");
              }
              str += "]";
              return str;
          } else {
              return String(o);
          }
      };
  
      Watch.prototype.onDrawBackground = function(ctx) {
          //show the current value
          this.inputs[0].label = Watch.toString(this.value);
      };
  
      LiteGraph.registerNodeType("basic/watch", Watch);
  
      //in case one type doesnt match other type but you want to connect them anyway
      function Cast() {
          this.addInput("in", 0);
          this.addOutput("out", 0);
          this.size = [40, 30];
      }
  
      Cast.title = "Cast";
      Cast.desc = "Allows to connect different types";
  
      Cast.prototype.onExecute = function() {
          this.setOutputData(0, this.getInputData(0));
      };
  
      LiteGraph.registerNodeType("basic/cast", Cast);
  
      //Show value inside the debug console
      function Console() {
          this.mode = LiteGraph.ON_EVENT;
          this.size = [80, 30];
          this.addProperty("msg", "");
          this.addInput("log", LiteGraph.EVENT);
          this.addInput("msg", 0);
      }
  
      Console.title = "Console";
      Console.desc = "Show value inside the console";
  
      Console.prototype.onAction = function(action, param) {
          if (action == "log") {
              console.log(param);
          } else if (action == "warn") {
              console.warn(param);
          } else if (action == "error") {
              console.error(param);
          }
      };
  
      Console.prototype.onExecute = function() {
          var msg = this.getInputData(1);
          if (msg !== null) {
              this.properties.msg = msg;
          }
          console.log(msg);
      };
  
      Console.prototype.onGetInputs = function() {
          return [
              ["log", LiteGraph.ACTION],
              ["warn", LiteGraph.ACTION],
              ["error", LiteGraph.ACTION]
          ];
      };
  
      LiteGraph.registerNodeType("basic/console", Console);
  
      //Show value inside the debug console
      function Alert() {
          this.mode = LiteGraph.ON_EVENT;
          this.addProperty("msg", "");
          this.addInput("", LiteGraph.EVENT);
          var that = this;
          this.widget = this.addWidget("text", "Text", "", function(v) {
              that.properties.msg = v;
          });
          this.widgets_up = true;
          this.size = [200, 30];
      }
  
      Alert.title = "Alert";
      Alert.desc = "Show an alert window";
      Alert.color = "#510";
  
      Alert.prototype.onConfigure = function(o) {
          this.widget.value = o.properties.msg;
      };
  
      Alert.prototype.onAction = function(action, param) {
          var msg = this.properties.msg;
          setTimeout(function() {
              alert(msg);
          }, 10);
      };
  
      LiteGraph.registerNodeType("basic/alert", Alert);
  
      //Execites simple code
      function NodeScript() {
          this.size = [60, 30];
          this.addProperty("onExecute", "return A;");
          this.addInput("A", "");
          this.addInput("B", "");
          this.addOutput("out", "");
  
          this._func = null;
          this.data = {};
      }
  
      NodeScript.prototype.onConfigure = function(o) {
          if (o.properties.onExecute && LiteGraph.allow_scripts)
              this.compileCode(o.properties.onExecute);
  		else
  			console.warn("Script not compiled, LiteGraph.allow_scripts is false");
      };
  
      NodeScript.title = "Script";
      NodeScript.desc = "executes a code (max 100 characters)";
  
      NodeScript.widgets_info = {
          onExecute: { type: "code" }
      };
  
      NodeScript.prototype.onPropertyChanged = function(name, value) {
          if (name == "onExecute" && LiteGraph.allow_scripts)
              this.compileCode(value);
  		else
  			console.warn("Script not compiled, LiteGraph.allow_scripts is false");
      };
  
      NodeScript.prototype.compileCode = function(code) {
          this._func = null;
          if (code.length > 256) {
              console.warn("Script too long, max 256 chars");
          } else {
              var code_low = code.toLowerCase();
              var forbidden_words = [
                  "script",
                  "body",
                  "document",
                  "eval",
                  "nodescript",
                  "function"
              ]; //bad security solution
              for (var i = 0; i < forbidden_words.length; ++i) {
                  if (code_low.indexOf(forbidden_words[i]) != -1) {
                      console.warn("invalid script");
                      return;
                  }
              }
              try {
                  this._func = new Function("A", "B", "C", "DATA", "node", code);
              } catch (err) {
                  console.error("Error parsing script");
                  console.error(err);
              }
          }
      };
  
      NodeScript.prototype.onExecute = function() {
          if (!this._func) {
              return;
          }
  
          try {
              var A = this.getInputData(0);
              var B = this.getInputData(1);
              var C = this.getInputData(2);
              this.setOutputData(0, this._func(A, B, C, this.data, this));
          } catch (err) {
              console.error("Error in script");
              console.error(err);
          }
      };
  
      NodeScript.prototype.onGetOutputs = function() {
          return [["C", ""]];
      };
  
      LiteGraph.registerNodeType("basic/script", NodeScript);
  })(this);
  