diff options
| author | hallgren <hallgren@chalmers.se> | 2010-04-09 13:51:34 +0000 |
|---|---|---|
| committer | hallgren <hallgren@chalmers.se> | 2010-04-09 13:51:34 +0000 |
| commit | e7073c1575f39a27eee725d1218cf8b304871e98 (patch) | |
| tree | 10c7db93ccb5342c09113d48f8f0a7fdf5de24f8 /src/runtime | |
| parent | 0138e6bba1d593fcdf5417dc8596c63757585796 (diff) | |
Adding the Minibar files to the darcs repository.
Diffstat (limited to 'src/runtime')
| -rw-r--r-- | src/runtime/javascript/minibar/about.html | 70 | ||||
| -rw-r--r-- | src/runtime/javascript/minibar/minibar.css | 37 | ||||
| -rw-r--r-- | src/runtime/javascript/minibar/minibar.html | 29 | ||||
| -rw-r--r-- | src/runtime/javascript/minibar/minibar.js | 222 | ||||
| -rw-r--r-- | src/runtime/javascript/minibar/saldotest.html | 23 | ||||
| -rw-r--r-- | src/runtime/javascript/minibar/saldotest.js | 240 | ||||
| -rw-r--r-- | src/runtime/javascript/minibar/support.js | 157 |
7 files changed, 778 insertions, 0 deletions
diff --git a/src/runtime/javascript/minibar/about.html b/src/runtime/javascript/minibar/about.html new file mode 100644 index 000000000..ceb18daf1 --- /dev/null +++ b/src/runtime/javascript/minibar/about.html @@ -0,0 +1,70 @@ +<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> +<html> <head> +<title>About Minibar</title> +<link rel=stylesheet type="text/css" href="minibar.css"> +</head> + +<body> +<h1>About Minibar</h1> + +<a href="minibar.html">Minibar</a> is an alternative implementation of the +<a href="http://www.grammaticalframework.org:41296/fridge/">Fridge Poetry web app</a>. +It doesn't do everything the original Fridge Poetry does (e.g. drag-and-drop is missing), +so I refer to it as a minibar rather than a full refrigerator :-) + +<p> +Some implementation details: + +<ul class=space> + <li>It is implemented directly in JavaScipt. It does not use Google Web Toolkit or any big JavaScript libraries. + <li>It has been tested and found to work in the following browsers: + <ul> + <li>On the Mac: Firefox 3.5 & 3.6, Safari 4.0, Opera 10.10 and + Google Chrome 4.0.249.49. + <li>On Linux: Firefox 3.0.18 & 3.5, Opera 10.10. + <li>On the Android Dev Phone: Android Mobile Safari 3.0.4 & 3.1.2 + and Android Opera Mini 4.2. + </ul> + It does not seem work in Internet Explorer 7 + (there are both styling and scripting issues). + <li>The implementation consist of two JavaScript files: + <a href="minibar.js">minibar.js</a> (186 lines) + and <a href="support.js">support.js</a> (147 lines). + The latter is also used in a small web app based on the + <a href="http://spraakbanken.gu.se/sal/ws/">SALDO web services</a>. + <li>To access the GF web service, it uses the + <a href="http://en.wikipedia.org/wiki/JSON#JSONP">JSONP method</a> + mentioned in the GF + web services paper, which allows the web app to be hosted on a different server + from the GF web service. (To demonstrate this, I put the Minibar demo on + www.cs.chalmers.se, while the GF server that it calls is on + www.grammaticalframework.org.) + <li>As an experiment, it does no use the <code>grammars.xml</code> file, + but instead calls a little CGI script, + <a href="http://www.grammaticalframework.org:41296/grammars/grammars.cgi.txt">grammars.cgi</a> + which lists the .pgf in the directory, in JSONP format. (Note: if you want to install + this on your own computer, + <ul> + <li>if you click on the link, + the CGI script will be downloaded as <code>grammars.cgi.txt</code>, + but it should be called <code>grammars.cgi</code> and stored on the server + in the same directory as the grammar files. + <li>for CGI scripts to work with lighttpd, <code>"mod_cgi"</code> needs to be included + in the definition of <code>server.modules</code> in the + <code>lighttpd.conf</code> file.) + </ul> + <li>[Added 2010-02-16] There is a button for generating random sentences. + <li>[Added 2010-02-23] All translations are shown, not just the first one, if there are + multiple parses. + <li>[Added 2010-02-25] Next to each translation, there is now a little tree icon that + you can click on to see a drawing of an abstract syntax tree or a parse tree. If you click + on a drawing it collapses back into a tree icon. +</ul> + +<hr> +<address> +<a href="http://www.cs.chalmers.se/~hallgren/">TH</a> +<img src="http://www.altocumulus.org/~hallgren/online.cgi?icon" alt=""></address> +</address> +<!-- hhmts start --> Last modified: Thu Mar 25 15:06:22 CET 2010 <!-- hhmts end --> +</body> </html> diff --git a/src/runtime/javascript/minibar/minibar.css b/src/runtime/javascript/minibar/minibar.css new file mode 100644 index 000000000..17d7350c9 --- /dev/null +++ b/src/runtime/javascript/minibar/minibar.css @@ -0,0 +1,37 @@ +body { + background: #ccc url("http://www.grammaticalframework.org:41296/fridge/se.chalmers.cs.gf.gwt.FridgeApp/brushed-metal.png"); +} + +h1, h2, h3, small, th { font-family: sans-serif; } + +th, td { vertical-align: baseline; text-align: left; } + +div#surface { + min-height: 3ex; + margin: 5px; + padding: 5px; + border: 3px dashed #e0e0e0; +} + +div#words { + min-height: 3ex; + margin: 5px; + padding: 6px; + border: 3px solid #e0e0e0; +} + +div.word, span.word, div#words div { + display: inline-block; + font-family: sans-serif; + background-color: white; + border: 1px solid black; + padding: 3px; + margin: 3px; +} + +.invalid { color: red; } + +div.modtime { float: right; } +.modtime { color: #444; white-space: nowrap; } + +ul.space>li { margin-top: 0.5ex; } diff --git a/src/runtime/javascript/minibar/minibar.html b/src/runtime/javascript/minibar/minibar.html new file mode 100644 index 000000000..246a68214 --- /dev/null +++ b/src/runtime/javascript/minibar/minibar.html @@ -0,0 +1,29 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> <head> +<title>Minibar</title> +<link rel=stylesheet type="text/css" href="minibar.css"> +<script type="text/JavaScript" src="support.js"></script> +<script type="text/JavaScript" src="minibar.js"></script> +</head> + +<body onload="start_minibar()"> +<h1>Minibar</h1> +<div id=minibar> +</div> +<hr> + +<small> +[<a href="about.html">About Minibar</a> +| <a href="http://www.grammaticalframework.org:41296/fridge/">Original Fridge Poetry</a> +& <a href="http://www.grammaticalframework.org:41296/translate/">Translator</a>] +</small> +<small class=modtime> +HTML <!-- hhmts start --> Last modified: Tue Feb 23 20:25:50 CET 2010 <!-- hhmts end --> +</small> +<address> +<a href="http://www.cs.chalmers.se/~hallgren/">TH</a> +<img src="http://www.altocumulus.org/~hallgren/online.cgi?icon" alt=""></address> + +</body> + +</html> diff --git a/src/runtime/javascript/minibar/minibar.js b/src/runtime/javascript/minibar/minibar.js new file mode 100644 index 000000000..39d741bbd --- /dev/null +++ b/src/runtime/javascript/minibar/minibar.js @@ -0,0 +1,222 @@ + +var server="http://www.grammaticalframework.org:41296" +//var server="http://tournesol.cs.chalmers.se:41296"; +//var server="http://localhost:41296"; +var grammars_url=server+"/grammars/"; +var current_grammar_url=grammars_url+"Foods.pgf"; + +var tree_icon=server+"/translate/se.chalmers.cs.gf.gwt.TranslateApp/tree-btn.png"; + +function start_minibar() { + var minibar=element("minibar"); + minibar.appendChild(div_id("menubar")); + minibar.appendChild(div_id("surface")); + minibar.appendChild(div_id("words")); + minibar.appendChild(div_id("translations")); + jsonp(grammars_url+"grammars.cgi",""); // calls show_grammarlist +} + +function show_grammarlist(grammars) { + var menu=empty("select"); + for(var i=0;i<grammars.length;i++) { + var opt=empty("option"); + opt.setAttribute("value",grammars[i]); + opt.innerHTML=grammars[i]; + menu.appendChild(opt); + } + menu.setAttribute("onchange","new_grammar(this)"); + var menubar=element("menubar"); + menubar.innerHTML="Grammar: "; + menubar.appendChild(menu); + menubar.appendChild(text(" Input language: ")); + menubar.appendChild(empty_id("select","language_menu")); + menubar.appendChild(button("Clear","clear_all()")); + menubar.appendChild(button("⌫","delete_last()")); + menubar.appendChild(button("Random","generate_random()")); + select_grammar(grammars[0]); +} + +function new_grammar(menu) { + select_grammar(menu.options[menu.selectedIndex].value); +} + +function select_grammar(grammar_name) { + current_grammar_url=grammars_url+grammar_name; + jsonp(current_grammar_url,"show_languages"); +} + +function show_languages(grammar) { + var r=""; + var lang=grammar.languages; + var menu=element("language_menu"); + menu.setAttribute("onchange","new_language(this)"); + menu.grammar=grammar; + menu.innerHTML=""; + for(var i=0; i<lang.length; i++) { + if(lang[i].canParse) { + var opt=empty("option"); + opt.setAttribute("value",""+i); + opt.innerHTML=lang[i].name; + menu.appendChild(opt); + } + } + new_language(menu); +} + +function new_language(menu) { + var ix=menu.options[menu.selectedIndex].value; + var langname=menu.grammar.languages[ix].name; + menu.current={from: langname, input: ""}; + clear_all(); +} + +function clear_all1() { + var menu=element("language_menu"); + menu.current.input=""; + menu.previous=null; + element("surface").innerHTML=""; + element("translations").innerHTML=""; + return menu; +} + +function clear_all() { + get_completions(clear_all1()); +} + +function delete_last() { + var menu=element("language_menu"); + if(menu.previous) { + menu.current.input=menu.previous.input; + menu.previous=menu.previous.previous; + var s=element("surface"); + s.removeChild(s.lastChild); + element("translations").innerHTML=""; + get_completions(menu); + } +} + +function generate_random() { + jsonp(current_grammar_url+"?command=random&random="+Math.random(),"lin_random"); + +} + +function lin_random(abs) { + var menu=element("language_menu"); + var lang=menu.current.from; + jsonp(current_grammar_url+"?command=linearize&tree="+encodeURIComponent(abs[0].tree) + +"&to="+lang, + "show_random") + +} + +function show_random(random) { + var menu=clear_all1(); + var words=random[0].text.split(" "); + for(var i=0;i<words.length;i++) + add_word1(menu,words[i]+" "); + element("words").innerHTML="..."; + get_completions(menu); +} + +function get_completions(menu) { + var c=menu.current; + jsonp(current_grammar_url + +"?command=complete" + +"&from="+encodeURIComponent(c.from) + +"&input="+encodeURIComponent(c.input), + "show_completions"); +} + +function word(s) { + var w=div_class("word",text(s)); + w.setAttribute("onclick",'add_word("'+s+'")'); + return w; +} + +function add_word1(menu,s) { + menu.previous={ input: menu.current.input, previous: menu.previous }; + menu.current.input+=s; + element("surface").appendChild(span_class("word",text(s))); +} + +function add_word(s) { + var menu=element("language_menu"); + add_word1(menu,s); + element("words").innerHTML="..."; + get_completions(menu); +} + +function show_completions(completions) { + var box=element("words"); + var menu=element("language_menu"); + var prefixlen=menu.current.input.length; + var emptycnt=0; + box.innerHTML=""; + for(var i=0;i<completions.length;i++) { + var s=completions[i].text.substring(prefixlen); + if(s.length>0) box.appendChild(word(s)); + else emptycnt++; + } + if(emptycnt>0) + //setTimeout(function(){get_translations(menu);},200); + get_translations(menu); +} + +function get_translations(menu) { + jsonp(current_grammar_url + +"?command=translate" + +"&from="+encodeURIComponent(menu.current.from) + +"&input="+encodeURIComponent(menu.current.input), + "show_translations") +} + +function show_translations(translations) { + var trans=element("translations"); + var cnt=translations.length; + trans.innerHTML=""; + trans.appendChild(wrap("h3",text(cnt<1 ? "No translations?" : + cnt>1 ? ""+cnt+" translations:": + "One translation:"))); + for(p=0;p<cnt;p++) { + var t=translations[p]; + var lin=t.linearizations; + var tbody=empty("tbody"); + if(t.tree) + tbody.appendChild(tr([th(text("Abstract: ")), + tda([abstree_button(t.tree),text(" "+t.tree)])])); + for(var i=0;i<lin.length;i++) + tbody.appendChild(tr([th(text(lin[i].to+": ")), + tda([parsetree_button(t.tree,lin[i].to),text(lin[i].text)])])); + trans.appendChild(wrap("table",tbody)); + } +} + +function abstree_button(abs) { + var i=img(tree_icon); + i.setAttribute("onclick","toggle_img(this)"); + i.other=current_grammar_url+"?command=abstrtree&tree="+encodeURIComponent(abs); + return i; +} + +function parsetree_button(abs,lang) { + var i=img(tree_icon); + i.setAttribute("onclick","toggle_img(this)"); + i.other=current_grammar_url + +"?command=parsetree&from="+lang+"&tree="+encodeURIComponent(abs); + return i; +} + +function toggle_img(i) { + var tmp=i.src; + i.src=i.other; + i.other=tmp; +} + + +/* +se.chalmers.cs.gf.gwt.TranslateApp/align-btn.png + +GET /grammars/Foods.pgf?&command=abstrtree&tree=Pred+(This+Fish)+(Very+Fresh) +GET /grammars/Foods.pgf?&command=parsetree&tree=Pred+(This+Fish)+Expensive&from=FoodsAfr +GET /grammars/Foods.pgf?&command=alignment&tree=Pred+(This+Fish)+Expensive +*/ diff --git a/src/runtime/javascript/minibar/saldotest.html b/src/runtime/javascript/minibar/saldotest.html new file mode 100644 index 000000000..00856c4db --- /dev/null +++ b/src/runtime/javascript/minibar/saldotest.html @@ -0,0 +1,23 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> <head> +<title>Saldotest</title> +<link rel=stylesheet type="text/css" href="minibar.css"> +<script type="text/JavaScript" src="support.js"></script> +<script type="text/JavaScript" src="saldotest.js"></script> +</head> + +<body onload="start_saldotest()"> +<h1>En liten saldoleksak</h1> +<div id=saldotest> +</div> +<hr> +<small> +[Baserad på <a href="http://spraakbanken.gu.se/sal/ws/">SALDOs nättjänster</a>] +</small> +<small class=modtime> +HTML <!-- hhmts start --> Last modified: Tue Feb 23 20:30:14 CET 2010 <!-- hhmts end --> +</small> +<address>TH <img src="http://www.altocumulus.org/~hallgren/online.cgi?icon" alt=""></address> +</body> + +</html> diff --git a/src/runtime/javascript/minibar/saldotest.js b/src/runtime/javascript/minibar/saldotest.js new file mode 100644 index 000000000..cc2cdd1b1 --- /dev/null +++ b/src/runtime/javascript/minibar/saldotest.js @@ -0,0 +1,240 @@ + +var Saldo_ws_url = "http://spraakbanken.gu.se/ws/saldo-ws/"; +//var Saldo_ff_url = Saldo_ws_url+"ff/json+remember_completions/"; +var Saldo_lid_url = Saldo_ws_url+"lid/json"; + +var ordlista=[]; +var current=""; + +function start_saldotest() { + appendChildren(element("saldotest"), + [button("Slumpa","random_word()"), + button("Rensa","clear_all()"), + button("⌫","delete_last()"), + button("Ordlista","show_ordlista()"), + button("Visa tänkbara drag","show_moves()"), + button("Gör ett drag","make_a_move()"), + button("Visa prefix","show_prefixes()"), + div_id("surface"), + div_id("words"), + div_id("translations")]) + clear_all(); +} + +function random_word() { + jsonp(Saldo_lid_url+"+show_random/rnd?"+Math.random()); +} + +function show_random(lid) { + var lex=lid.lex; + reset_all(lex.substring(0,lex.indexOf('.'))); +} + +function clear_all() { reset_all(""); } + +function reset_all(s) { + current=s; + element("surface").innerHTML=s; + element("translations").innerHTML=""; + get_completions(); +} + +function delete_last() { + var len=current.length; + if(len>0) { + current=current.substring(0,len-1); + var s=element("surface"); + s.innerHTML=current; + element("translations").innerHTML=""; + get_completions(); + } +} + +function with_completions(s,cont) { + var c=ordlista[s]; + if(c && c.a) cont(c); + else { + //if(c) alert("c already has fields"+field_names(c)); + ordlista[s]={put: function(c) { ordlista[s]=c; cont(c); }}; + var url=Saldo_ws_url+"ff/json+ordlista[\""+s+"\"].put/"+encodeURIComponent(s); + jsonp(url,""); + } +} + +function get_completions() { + with_completions(current,show_completions); +} + +function word(s) { + var w=span_class("word",text(s)); + if(s==" ") w.innerHTML=" "; + w.setAttribute("onclick",'extend_current("'+s+'")'); + return w; +} + +function extend_current(s) { + current+=s; + element("words").innerHTML=""; + element("surface").innerHTML=current; + get_completions(); +} + +function show_completions(saldo_ff) { + var box=element("words"); + box.innerHTML=""; + //var c=saldo_ff.c.split(""); + var c=filter(allowed,saldo_ff.c); + sort(c); + for(var i=0;i<c.length;i++) { + var s=c[i]; + if(s!='-') + box.appendChild(word(s)); + } + show_translations(saldo_ff.a); +} + +function allowed(c) { + switch(c) { + case 'å': + case 'ä': + case 'ö': + case 'é': + case 'ü': + return true; + default: + return 'a'<=c && c<='z'; + } +} + +function ignore(msd) { + switch(msd) { + case "c": + case "ci": + case "cm": + case "seg": + case "sms": + return true; + default: + return false; + } +} + +function count_wordforms(a) { + var cnt=0; + for(var i=0;i<a.length;i++) + if(!ignore(a[i].msd)) cnt++; + return cnt; +} + +function pad(s) { + return s.length>0 ? " "+s : ""; +} + +function show_translations(a) { + var tr=element("translations"); + tr.innerHTML=""; + //if(!a) alert("a undefined in show_translations"); + if(count_wordforms(a)<1) { + tr.appendChild(p(text(a.length<1 ? "Detta är inte en giltig ordform" + : "Denna form förekommer bara i sammansättningar"))); + element("surface").setAttribute("class","invalid"); + } + else { + element("surface").setAttribute("class","valid"); + for(var i=0;i<a.length;i++) + if(!ignore(a[i].msd)) + tr.appendChild(p(text(a[i].gf+" ("+a[i].pos+pad(a[i].is)+", "+a[i].msd+")"))); + } +} + +function show_ordlista() { + var trans=element("translations"); + trans.innerHTML="Följande ord har slagits upp: "; + var apnd=function(el) { trans.appendChild(el) }; + for(var i in ordlista) { + apnd(empty("br")); + apnd(span_class(ordlista[i].a.length<1 ? "invalid" : "valid",text(" "+i))); + apnd(text(": "+(ordlista[i].ok!=null ? ordlista[i].ok.length : "?") + +"/"+(ordlista[i].allowed!=null ? ordlista[i].allowed.length : "?"))); + } +} + +function extend_ordlista(s,cs,cont) { + if(cs.length<1) cont(); + else { + var c=cs[0]; + var cs2=cs.substring(1); + with_completions(s+c,function(o){extend_ordlista(s,cs2,cont)}); + } +} + +function known_possible_moves(s,cont) { + var c=implode(sort(filter(allowed,ordlista[s].c))); + ordlista[s].allowed=c; + extend_ordlista(s,c,function() { + var ok=""; + for(var i=0;i<c.length;i++) { + var next=s+c[i]; + var ff=ordlista[next]; + //if(!ff.a) alert(show_props(ff,"ff")); + if(next.length<2 || count_wordforms(ff.a)<1) ok+=c[i]; + } + ordlista[s].ok=ok; + cont(ok); + } + ); +} + +function unknown_possible_moves(s,cont) { + with_completions(s,function(c){known_possible_moves(s,cont);}); +} + +function currently_possible_moves(cont) { + known_possible_moves(current,cont); +} + +function show_moves() { + var trans=element("translations"); + trans.innerHTML="Letar efter möjliga drag"; + currently_possible_moves(function(ok) { + trans.innerHTML="Tänkbara drag: "+ok; + winning_moves(trans,ok); + }); +} + +function winning_moves(trans,ok) { + var ws=map(function(c){return current+c;},ok); + mapc(unknown_possible_moves,ws,function(oks){ + var winning=""; + for(i=0;i<oks.length;i++) + if(oks[i].length<1) winning+=ok[i]; + trans.innerHTML+="<br>Vinnande drag: "+winning; + }); +} + +function make_a_move() { + currently_possible_moves(function(ok) { + if(ok.length<1) element("translations").innerHTML="Hittade inga möjliga drag!"; + else { + var i=Math.floor(Math.random()*ok.length); + extend_current(ok[i]); + } + } + ); +} + +function show_prefixes_of(trans,s) { + if(s.length>0) { + var p=s.substr(0,s.length-1); + with_completions(p,function(c) { + if(count_wordforms(c.a)>0) trans.innerHTML+="<br>"+p; + show_prefixes_of(trans,p); + }); + } +} + +function show_prefixes() { + var trans=element("translations"); + trans.innerHTML="Prefix av "+current+":"; + show_prefixes_of(trans,current); +} diff --git a/src/runtime/javascript/minibar/support.js b/src/runtime/javascript/minibar/support.js new file mode 100644 index 000000000..15ccc38d0 --- /dev/null +++ b/src/runtime/javascript/minibar/support.js @@ -0,0 +1,157 @@ +function element(id) { + return document.getElementById(id); +} + +// Inspired by the function jsonp from +// http://www.west-wind.com/Weblog/posts/107136.aspx +// See also http://niryariv.wordpress.com/2009/05/05/jsonp-quickly/ +// http://en.wikipedia.org/wiki/JSON#JSONP +function jsonp(url,callback) +{ + if (url.indexOf("?") > -1) + url += "&jsonp=" + else + url += "?jsonp=" + url += callback + "&"; + //url += new Date().getTime().toString(); // prevent caching + + var script = empty("script"); + script.setAttribute("src",url); + script.setAttribute("type","text/javascript"); + document.body.appendChild(script); +} + +/* --- HTML construction ---------------------------------------------------- */ +function text(s) { return document.createTextNode(s); } + +function empty(tag,name,value) { + var el=document.createElement(tag); + if(name && value) el.setAttribute(name,value); + return el; +} + +function empty_id(tag,id) { return empty(tag,"id",id); } +function empty_class(tag,cls) { return empty(tag,"class",cls); } + +function div_id(id) { return empty_id("div",id); } + +function wrap(tag,contents) { + var el=empty(tag); + el.appendChild(contents); + return el; +} + +function wrap_class(tag,cls,contents) { + var el=empty_class(tag,cls); + if(contents) el.appendChild(contents); + return el; +} + +function span_class(cls,contents) { return wrap_class("span",cls,contents); } +function div_class(cls,contents) { return wrap_class("div",cls,contents); } + +function p(contents) { return wrap("p",contents); } +function dt(contents) { return wrap("dt",contents); } + +function th(contents) { return wrap("th",contents); } +function td(contents) { return wrap("td",contents); } + +function tr(cells) { + var tr=empty("tr"); + for(var i=0;i<cells.length;i++) + tr.appendChild(cells[i]); + return tr; +} + +function button(label,action) { + var el=empty("input"); + el.setAttribute("type","button"); + el.setAttribute("value",label); + el.setAttribute("onclick",action); + return el; +} + +function appendChildren(el,cs) { + for(var i=0;i<cs.length;i++) + el.appendChild(cs[i]); + return el; +} + +function tda(cs) { return appendChildren(empty("td"),cs); } + +function img(src) { return empty("img","src",src); } + +/* --- Debug ---------------------------------------------------------------- */ + +function show_props(obj, objName) { + var result = ""; + for (var i in obj) { + result += objName + "." + i + " = " + obj[i] + "<br>"; + } + return result; +} + +function field_names(obj) { + var result = ""; + for (var i in obj) { + result += " " + i; + } + return result; +} + +/* --- Data manipulation ---------------------------------------------------- */ +function swap(a,i,j) { // Note: this doesn't work on strings. + var tmp=a[i]; + a[i]=a[j]; + a[j]=tmp; + return a; +} + +function sort(a) { // Note: this doesn't work on strings. + for(var i=0;i<a.length-1;i++) { + var min=i; + for(var j=i+1;j<a.length;j++) + if(a[j]<a[min]) min=j; + if(min!=i) swap(a,i,min); + } + return a; +} + +function filter(p,xs) { + var ys=[]; + for(var i=0;i<xs.length;i++) + if(p(xs[i])) ys[ys.length]=xs[i]; + return ys; +} + +function implode(cs) { + /* + var s=""; + for(var i=0;i<cs.length;i++) + s+=cs[i]; + return s; + */ + return cs.join(""); +} +/* +function all(p,xs) { + for(var i=0;i<xs.length;i++) + if(!p(xs[i])) return false; + return true; +} +*/ + +function map(f,xs) { + var ys=[]; + for(var i=0;i<xs.length;i++) ys[i]=f(xs[i]); + return ys; +} + +function mapc_from(f,xs,i,ys,cont) { + if(i<xs.length) + f(xs[i],function(y){ys[i]=y;mapc_from(f,xs,i+1,ys,cont)}); + else + cont(ys); +} + +function mapc(f,xs,cont) { mapc_from(f,xs,0,[],cont); } |
