diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..0bf273c3 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,24 @@ +module.exports = { + "env": { + "es6": true + }, + "extends": "eslint:recommended", + "rules": { + "indent": [ + "error", + 4 + ], + "linebreak-style": [ + "error", + "unix" + ], + "quotes": [ + "error", + "double" + ], + "semi": [ + "error", + "never" + ] + } +}; \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..33f8987e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +dist/ +myApp-darwin-x64/ +node_modules diff --git a/.idea/electron_dde.iml b/.idea/electron_dde.iml new file mode 100644 index 00000000..24643cc3 --- /dev/null +++ b/.idea/electron_dde.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 00000000..97626ba4 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml new file mode 100644 index 00000000..90212ddb --- /dev/null +++ b/.idea/jsLibraryMappings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..72abef0a --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..3b37baf1 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..94a25f7f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 00000000..2b1b440f --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,992 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + DEFINITION_ORDER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + project + + + + + + + + + + + + + + + + project + + + true + + + + DIRECTORY + + false + + + + + + + + + + + + + + + + + + + + 1484261819949 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Dexter Development Environment.js b/Dexter Development Environment.js new file mode 100644 index 00000000..030b213f --- /dev/null +++ b/Dexter Development Environment.js @@ -0,0 +1,1002 @@ +var dde_paper_text = ` + + + + + + + + + + + + + + + + + + + + + +
+ +

A Development Environment For +Robotic Software

+ +

Fry, cfry@media.mit.edu, September. 16, 2016

+ +

 

+ +

As consumers demand "mass +customization", the hardware of our robots is meeting the challenge by becoming +more capable. They have more degrees of freedom, higher accuracy, greater +speed, and additional sensors.  In +order to take advantage of this hardware, we need more sophisticated +software.  This is as it should be. +It is easier to change a line of code than to change a transmission line of +electricity or light.

+ +

 

+ +

Software

+ +

Unfortunately the cost of +software development can be quite high, especially if that cost is not +amortized over the manufacture of many copies of the same thing. The operators +of these robots may be factory workers, mechanical engineers or even home users +for personal manufacturing. With the luxury of professional programmers not +available, we must make "end user programming environments" that facilitate +part customization, fixing build-environment specific bugs and ultimately, +design of whole new parts.

+ +

 

+ +

3D printers are perhaps the +most common "manufacturing robot" in homes, but they typically use just +one-material and one-process for manufacturing. Complex products will need +multiple materials and multiple processes (CNC, laser cutting, sintering, pick +and place, assembly, etc.). 

+ +

 

+ +

As the complexity of the +build processes grows, so too must the job description. A conventional "app" +with a few buttons can't accommodate the breadth of customization necessary. A +user will need to interact at multiple levels that will permit an +ever-increasing control over complex procedures. Ultimately we need the full +power of a general purpose programming language. Our build process" description +looks less like a list of numbers and more like a full-fledged program.

+ +

 

+ +

Robots

+ +

The Dexter Development +Environment was designed to program the rather adept "Dexter" robot. It is a +5-axis arm designed for table or ceiling mounting. Dexter contains a +general-purpose processer that runs Linux as well as an FPGA supercomputer for +high-speed parallel operations.

+ +

 

+ +

As flexible as Dexter is, +complex multi-robot builds may involve not just multiple robots, but robots of +different kinds. DDE"s architecture +accommodates multiple kinds of robots that can perform in concert. The simplest +robot kind that DDE supports is called "Brain". It can't perform physical +operations on its own, but it can direct other robots to do so, just as an +orchestra conductor doesn"t play an instrument, but directs others that do.

+ +

 

+ +

The "Serial" robot is a +non-specific robot controller that drives processes through a serial port, such +as the USB port in a laptop.  It has +been used to control an Arduino. We might think of a Serial robot as a sort of +general purpose percussionist, who can play a variety of instruments dependent +upon the piece to be played (or rather built.)

+ +

 

+ +

The "Human" robot is perhaps +the most controversial yet conceptually interesting. Complex jobs may not be +able to be fully automated. The Human robot has an instruction set that includes +operations only a person can perform. These are either a textual description of +a task, or some choice that the human operator needs to make. The important +idea is that an instruction for a human can be stuck on a do-list and treated +just like any other kind of instruction. We can thus synchronize human tasks +and automated tasks in one coherent environment.  

+ +

 

+ +

The Human robot is the singer +in our orchestra. It does not need an instrument to perform its part. We can +even use DDE jobs to coordinate multiple humans, a chorus if you will!

+ +

 

+ +

Unlike a typical musical +performance, we don't require the person to memorize their part. Text, menus, other +graphical widgets and even speech can be used to make life easy for the singer +of the band. Our conductor tells the singer when to start singing, though the +singer must tell the conductor when she is done. This allows the person to take +as much time as the task requires, giving her maximum flexibility to perform +her best.

+ +

 

+ +

+ +

An +example of "lyrics" that DDE presents to the "singer".

+ +

 

+ +

Self Teaching

+ +

If this complex software +environment is to be effectively used, it must be understood by its users.  DDE utilizes a variety of media for +explaining itself to users.  Thus +DDE performs the role of "music teacher", though not so much for training +performers as training composers, who write the score (do-list) for each +instrument (robot). Because a do-list is a carefully ordered sequence of +instructions that must be synchronized with other instruments, our instructions +bear more than a passing resemblance to notes in an actual score.

+ +

+ +

Above we see the 4 panes of +DDE. The upper left pane is the code editor. It can contain any JavaScript. The +content in this screen shot was inserted from an example on the Jobs menu +(shown expanded). A job feeds the instructions on its do-list to a robot. This insertion +comes not just with the code, but with comments explaining the code's +functionality (in brown text).  This +particular example contains two jobs that coordinate by "synchronizing" at each +of their "sync_point" instructions.  +

+ +

 

+ +

Every character in the editor +has help available by clicking on it. Here we clicked on "sync_point".  Concise help appears in the Output pane +in the lower left. The blue text in this help is a link to extended +documentation from the reference manual, shown in the Documentation pane in the +upper right. The lower right is the Simulation pane, which shows a graphical +simulation of the robot under control, or mimics a real robot.

+ +

 

+ +

Orchestras usually have +scores with every note written out ahead of the performance. However, our real-world +builds need to be more flexible than that. Robot sensors can detect anomalies +that may need to be addressed during the build, just as professional musicians +can cover up for each other's mistakes. Since the do-list can contain arbitrary +JavaScript, it can actually generate new instructions on the fly, much as a +jazz improviser composes on the spot. One of DDE's instruction types is +literally a JavaScript "generator". It can produce a stream of instructions +who's length needn't even set before the generator starts producing +instructions, perhaps like some stage-hogging lead guitarist.

+ +

 

+ +

A Natural Language Application

+ +

We can take advantage of +DDE's window system programming, speech generation & recognition, natural +language parsing capability and AI reasoning to make easy-to-program, as well +as easy-to-use interfaces to sophisticated applications. In this example, we +use Google's speech I/O and the MIT InfoLab Group's English parser (named +START) to build an application that lets a user create a knowledge base and ask +questions about it, with a speech interface. The high level interface is:

+ +

 

+ +

  

+ +

 

+ +

If a user +presses Click to talk before saying +each of the above example sentences, they will create a knowledge base and get +speech feedback after each sentence, ending with "Robot is useful because robot +have hand."

+ +

 

+ +

Levels of Programming

+ +

Our base +level of programming for this application is JavaScript. We layer on DDE +utilities, making  access to I/O and +parsing easier in the next level up. Finally we use a knowledge base and +reasoning for our natural language interface. If a user needs functionality not +available at a high level, they can drop down a level, remaining in the same development environment, to gain increased +breadth at the expense of using a lower level language.

+ +

 

+ +

It is +important to understand that the above English sentences are, literally, code.  They create a program with a definitive +behavior that we can access via asking questions.

+ +

 

+ +

Debugging

+ +

The majority +of a programmer's time is not spent typing in code, it is in debugging that +code. Analogously, the majority of our natural language coder's time will not +be spent speaking the code, it will be in debugging.

+ +

 

+ +

A winning +strategy for developing working code quickly is to get feedback from our +development environment incrementally as we build our application.  As we construct our "Robot Knowledge +Base Application",  the development +environment gives us feedback after each sentence. For the two sentences that +add knowledge to the knowledge base, "A robot has a hand." and "If a +robot has a hand, a robot is useful.",  +our development environment responds with "OK" and "Got it." +(Identical acknowledgement in English is boring an unnatural!) This informs our +natural language coder that their utterances are syntactically correct.

+ +

 

+ +

If we +consider that the goal of our app is to answer the final question, the +intermediate questions are probing the semantic validity of the knowledge base +being built.  They take the place of +"print statements" in traditional programming. However, as you can see, they +are much higher level than print statements. They don't need to be embedded +inside some complex algorithm, and they produce output in a very understandable +way. For instance "Does a robot have a hand?" is responded to with "Yes, a robot +has a hand".

+ +

 

+ +

Knowledge Base Debugging

+ +

Applications +that rely on knowledge bases have a special kind of bug: bugs in the knowledge +base itself. We therefore need to be especially careful to inform the natural +language coder what's in that (potentially huge) knowledge base, but only with what's +relevant at the moment.

+ +

 

+ +

Here's a +dialog our app supports:

+ +
+ +

Human: A robot has a hand.

+ +

DevEnv: OK.

+ +

Human: A robot has a hand.

+ +

DevEnv: I already know that.

+ +
+ +

Our +application responds to the first sentence with "OK" but the 2nd +sentence with "I already know that." This informs our natural language coder about +redundancy, much as a fellow human would in a conversation. Furthermore, our +app does not stick into the knowledge base the same knowledge twice.

+ +

 

+ +

Here's +another example of a dialog:

+ +
+ +

Human: Why is a robot useful?

+ + + +

DevEnv: I think its never the case +that robot is    useful.

+ +

 

+ +

Human: If a robot has a hand, a +robot is useful.

+ +

DevEnv: OK

+ +

 

+ +

Human: Why is a robot +useful?

+ + + +

DevEnv: Sorry, robot is useful, is +only true under certain conditions.

+ +

 

+ +

Human: A robot has a hand.

+ +

DevEnv: Got it.

+ +

 

+ +

Human: Why is a robot useful?

+ +

DevEnv: Robot is useful because +robot have hand.

+ +
+ +

 

+ +

Notice that +there are three different responses to the Human's question of "Why is a robot +useful?". Each informs the user about what is in the knowledge base at time +time of the ask, giving clues about one of the most common bugs: missing +knowledge.

+ +

 

+ +

Conclusion

+ +

Dexter Development +Environment lets uses "print" a part from a design contained in Jobs that have +do-lists. But this rather passive interaction is analogous to an audience member +at a concert. Via end-user programming techniques, we enable the user to +orchestrate the process, ultimately giving them control of even the low-level +instructions in the process. With the "Human" robot, we can synchronize what +machines do best with what people can do best by providing appropriately timed +instructions, similar to real-time lyric presentation in a Karaoke bar. +The complexity of composing build-scripts can be mitigated by DDE's +self-teaching techniques and the AI of natural language processing plus +knowledge base management that we've only just begun (apologies to +the Carpenters).

+ +
+ + + +` diff --git a/ViewEyeRealTime.js b/ViewEyeRealTime.js new file mode 100755 index 00000000..e916835e --- /dev/null +++ b/ViewEyeRealTime.js @@ -0,0 +1,161 @@ + +// svg_text() +function SetGrid(){ +for (var i = 0;i < 511 ;i++){ + var thehtml = svg_circle({cx: i, cy: 0, r: 1}) + append_in_ui("svg_id", thehtml) + } +} + +var scACount = 0 +var MinADCx = 5000 +var MaxADCx = 0 +var MinADCy = 5000 +var MaxADCy = 0 + +//SetGrid() + +var centers_string = [[0x000, 0x000], + [0x000, 0x000], + [0x000, 0x000], + [0x000, 0x000], + [0x000, 0x000]] + + +var working_axis = undefined +var AxisTable = [[[500, 0, 0, 0, 0], Dexter.J1_A2D_SIN, Dexter.J1_A2D_COS, [-648000, 0, 0, 0, 0], 800], + [[0, 500, 0, 0, 0], Dexter.J2_A2D_SIN, Dexter.J2_A2D_COS, [0, -350000, 0, 0, 0], 400], + [[0, 0, 500, 0, 0], Dexter.J3_A2D_SIN, Dexter.J3_A2D_COS, [0, 0, -570000, 0, 0], 700], + [[0, 0, 0, 500, 0], Dexter.J4_A2D_SIN, Dexter.J4_A2D_COS, [0, 0, 0, -390000, 0], 300], + [[0, 0, 0, 0, 500], Dexter.J5_A2D_SIN, Dexter.J5_A2D_COS, [0, 0, 0, 0, -648000], 600]] + + +// AxisTable [axis][0] +function smLinex(size, axis){ + working_axis = axis + var result = [] + result.push (Dexter.move_all_joints(AxisTable [axis][3])) + for (var i = 0;i < size;i++){ + result.push (Dexter.move_all_joints_relative(AxisTable [axis][0])) + result.push (function () { + var x = Dexter.my_dex2.robot_status[AxisTable [axis][1]]/10 + var y = Dexter.my_dex2.robot_status[AxisTable [axis][2]]/10 + var thehtml = svg_circle({cx: x, cy: y, r: 1}) + append_in_ui("svg_id", thehtml) + })} + return result +} + + +function handle1(arg) { + if((arg.clicked_button_value === "background_id") || + (arg.clicked_button_value === "svg_id")) { + centers_string[working_axis][0] = "0x" + ((arg.offsetX * 10) * 65536).toString(16) + centers_string[working_axis][1] = "0x" + ((arg.offsetY * 10) * 65536).toString(16) + out ("0x" + ((arg.offsetX * 10) * 65536).toString(16) + " " + "0x" + ((arg.offsetY * 10) * 65536).toString(16)) + append_in_ui("svg_id", svg_circle({cx: arg.offsetX, cy: arg.offsetY, r: 3, color: "Red"})) + } + if(arg.clicked_button_value === "submit_id"){ + close_window(arg.window_index) + } +} + +function new_eye_window(){ + show_window({ + title: "Eye View", + content: + svg_svg({id: "svg_id", height: 410, width: 410, html_class: "clickable", child_elements: + [svg_rect({id: "submit_id", html_class: "clickable", x: 10, y: 350, width: 75, height: 25, color: "green"}) + ]}), + width: 500, // window width + height: 500, // window height + x: 0, // Distance from left of DDE window to this window's left + y: 100, // Distance from top of DDE window to this window's top + callback: handle1 +}) +} + +function centers_output(){ + out("copy from here" , "Red") + out(centers_string[0][0]) + out(centers_string[0][1]) + out(centers_string[2][0]) + out(centers_string[2][1]) + out(centers_string[1][0]) + out(centers_string[1][1]) + out(centers_string[3][0]) + out(centers_string[3][1]) + out(centers_string[4][0]) + out(centers_string[4][1]) + out("copy to here", "Red") + out("and place in //(Dexter ip address)/srv/samba/share/AdcCenters.txt") +} +function scan_axis(){ + var retCMD = [] + retCMD.push(Human.enter_number({ + title: "Calibrate LEDs", + task: "Do this calibration first.
" + + "
  1. Select each axis (0 through 4),
  2. " + + '
  3. click Submit get a the "Eye View" window.
  4. ' + + "
  5. With the eye view window drawing points
  6. " + + "
  7. adjust the current joints 2 pots until the points form a circle.
  8. " + + "
  9. Wait until points stop drawing (about 30 seconds)
  10. " + + "
  11. click in the center of the circle.
  12. " + + "
  13. click the green button
  14. " + + "
  15. repeat for the next joint.
", + user_data_variable_name: "measurement_axis", + initial_value: 0, + min: 0, + max: 5, + step: 1, + })) + retCMD.push(function () {if (this.user_data.measurement_axis != 5){ return new_eye_window()}}) + retCMD.push(function () {return Dexter.move_all_joints(0, 0, 0, 0, 0)}) + retCMD.push(function () {if (this.user_data.measurement_axis != 5){ return smLinex(AxisTable [this.user_data.measurement_axis][4], this.user_data.measurement_axis)}}) + retCMD.push(function () {if (this.user_data.measurement_axis != 5){ return scan_axis()}}) + return retCMD + +} + +function init_view_eye(){ //can't eval this until Dexter properly defined. + new Dexter({name: "basic_move_test_dex", ip_address: "192.168.1.144", port: 50000, + enable_heartbeat: false, simulate: false}) + new Job({name: "BasicMoveTest2", robot: Robot.basic_move_test_dex, keep_history: false, + inter_do_item_dur: 5, + do_list: [ Dexter.move_all_joints(0, 0, 0, 0, 0), + make_ins("S", "J1BoundryHigh",648000), + make_ins("S", "J1BoundryLow",-648000), + make_ins("S", "J2BoundryLow",-350000), + make_ins("S", "J2BoundryHigh",350000), + make_ins("S", "J3BoundryLow",-570000), + make_ins("S", "J3BoundryHigh",570000), + make_ins("S", "J4BoundryLow",-390000), + make_ins("S", "J4BoundryHigh",390000), + make_ins("S", "J5BoundryLow",-680000), + make_ins("S", "J5BoundryHigh",680000), + + make_ins("S", "MaxSpeed",200000), + make_ins("S", "Acceleration",1), + make_ins("S", "StartSpeed",7500), + scan_axis(), + function () {return centers_output()}, + make_ins("S", "MaxSpeed",300000), + make_ins("S", "Acceleration",1), + make_ins("S", "StartSpeed",500), + Dexter.move_all_joints(0, 0, 0, 0, 0) + ]}) +} +// Job.BasicMoveTest2.start() + + +/* +var centers_string = undefined + +file_content("AdcCenters.txt", function (str) {centers_string = str}) + +out (centers_string) + +write_file("AdcCenters.txt", centers_string) */ + + + diff --git a/app_builder.js b/app_builder.js new file mode 100644 index 00000000..015620c8 --- /dev/null +++ b/app_builder.js @@ -0,0 +1,764 @@ +/* Created by Fry on 2/1/16.*/ + +function ab(){} //just a namespace + +//in sandbox +ab.window_names = [] //don't put this in the init as we want it to persist accross tasks, whe user clicks New task + +ab.init = function(){ + // these are per training window use and get reinited when new training window is opened + ab.window_name = "" + ab.input_names = [] + ab.button_name_to_action_map = {} + ab.has_items = false //we might have only static text in which case, ab.input_names.length == 0 +} + +ab.post_creation_window_init = function(){ + var vals = {} //we don't have any as we're just initing + var new_win_default_name = "window_" + (ab.window_names.length + 1) + dex.set_in_window(undefined, "window_name", "value", new_win_default_name) + ab.fill_in_action_names(vals) +} + +ab.actions = function(){ + var result = ['out("clicked on " + vals.clicked_button_value)', 'out(vals)'] + for (var wn of ab.window_names){ + result.push(wn + "()") + } + return result +} + +ab.handle_fn_start = function(vals, always_add_function_header){ + //returns empty string unless the "function ..." code needed, in which case it returns it + var fn_start = "" + if(always_add_function_header || (ab.input_names.length == 0)){ + ab.window_name = vals.window_name + fn_start = "function " + ab.clean_name(vals.window_name) + "(){ //window \n" + + " show_window({content:`\n" + } + return fn_start +} + + +ab.insert_etc = function(pure_code, code, vals, can_have_action){ + Editor.insert(code) + ab.has_items = true //includes not just inputs but static text too. important to know that "something's been added" + var inp_name = vals.input_name + if (vals.clicked_button_value != "Button"){ + inp_name = ab.clean_name(inp_name) + } + var elt_to_add_to_input_names = inp_name //ab.clean_name(vals.input_name) + if (!can_have_action){ + elt_to_add_to_input_names = [elt_to_add_to_input_names, "cant_have_action"] + } + ab.input_names.push(elt_to_add_to_input_names) + //dex.train_number_of_insertions += 1 //the next index + //dex.train_action_name_to_pure_code[clean_action_or_task_name(vals.action_name)] = pure_code //for Do action button + //var action_options = "" + //for(var act of dex.train_action_names){ + // action_options += "" + //} + //dex.set_in_window(vals.window_index, "do_action_action_names", "innerHTML", action_options) + //dex.set_in_window(vals.window_index, "repeat_from_action_names", "innerHTML", action_options) + // dex.set_in_window(vals.window_index, "repeat_through_action_names", "innerHTML", action_options) + + var new_input_name_default = "input_" + (ab.input_names.length + 1) //make this 1 based so that the instruction "click to add the 1st action ..." will make most sense. + dex.set_in_window(vals.window_index, "input_name", "value", new_input_name_default) + ab.replace_top_instruction_line(vals) + ab.show_window(vals) +} + +ab.code_for_handle_fn = function(vals) { + var code = "function handle_" + vals.window_name + "_input(vals){\n" + var cond_keyword = "if" + //for (var inp_name of ab.input_names){ + for (var inp_name in ab.button_name_to_action_map){ + if (typeof(inp_name) == "string"){ + var inp_code = ' ' + cond_keyword + '(vals.clicked_button_value == "' + inp_name + '"){\n' + + ' ' + ab.button_name_to_action_map[inp_name] + + '\n }\n' + code += inp_code + cond_keyword = "else if" + } + //else inp_name looks like ["some_static_text_name", "cant_have_action"] + } + code += "}\n\n" + return code +} + + +ab.replace_top_instruction_line = function(vals, text){ + if (text == null){ + var index = ab.input_names.length + 1 + var index_string = integer_to_ordinal(index) + text = "Click on a button below to add the " + index_string + " input to this window." + } + text = "" + text + "" + dex.set_in_window(vals.window_index, "top_instruction_line", "innerHTML", text) +} + + + +ab.fill_in_action_names = function(vals){ //just called by New task + /* var task_options = "" + for (var task of dex.train_task_names){ //train_task_names whne this is called in new Task, + //has just been extended with vals.task_name but + //don't worry about recursion because we are now + //getting OUT of the cur task and into a new one. + task_options += "