1
0
forked from GitHub/gf-core

Improvements of "gf -server" mode and related setup

"gf -server" mode now contains everything needed to run the minibar and
the grammar editor (including example-based grammar writing).

The Setup.hs script installs the required files where gf -server can find them.
These files have been moved to a new directory: src/www.

The separate server program pgf-http is now obsolete.
This commit is contained in:
hallgren
2011-10-12 17:03:54 +00:00
parent 0aba45560d
commit 44d1a5a9f7
51 changed files with 118 additions and 20 deletions

View File

@@ -1,180 +0,0 @@
<!DOCTYPE html>
<html> <head>
<title>About Minibar</title>
<link rel=stylesheet type="text/css" href="minibar.css">
<meta charset="UTF-8">
</head>
<body>
<h1>About Minibar</h1>
<a href="minibar.html">Minibar</a> is an alternative implementation of the
<a href="http://www.grammaticalframework.org/">GF</a> web app
<a href="http://www.grammaticalframework.org:41296/fridge/">Fridge Poetry</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 &amp; 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).
There seems to be some rendering bugs in Chrome 5.0.342.9 β.
<li>The implementation consist of two JavaScript files:
<a href="minibar.js">minibar.js</a> and <a href="support.js">support.js</a>
The latter is also used in
<a href="http://spraakbanken.gu.se/swe/forskning/saldo/ordspel">a couple of
small web apps</a> 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 files 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.
<li>[Added 2010-04-09] Preparations to support different ways to access the
grammar: currently we access a PGF server via JSONP, but I would also like
to support AJAX, and local/downloaded JavaScript grammars.
<li>[Added 2010-04-19] A text entry field appears when you click in
the sentence area (with a dashed border). This allows you to enter words by
typing on the keyboard. As you start typing word magnets that don't match what
you are typing are removed. When only one magnet remains, you can press enter
to complete the word.
<li>[Added 2010-04-19] There is a menu for choosing the output language:
you can pick "All" to translate to all available languages, or pick one
particular language.
<li>[Added 2010-04-19] You can pass options to the function
<code>start_minibar</code> to customize the user interface. The default is
<code>{show_abstract:true,show_trees:true}</code> to show the abstract syntax
of parsed sentences, and to show icons that expand to syntax/parse trees next
each translation.
These features can be turned off by setting the fields to <code>false</code>.
<li>[Added 2010-04-30] The grammar menu is omitted if there is only one
grammar in the grammar list.
<li>[Added 2010-04-30] Fewer hardwired constants and new
<code>start_minibar</code> options (server, grammars_url, grammar_list,
show_grouped_translations, delete_button_text) to make
<code>minibar.js</code> more resuable.)
<li>[Added 2010-05-26] The magnets are now created with
<code>&lt;input type=button&gt;</code> tags to make them clickable in more
browsers.
<li>[Added 2010-05-26] The text entry field is now visible from the start,
and it is removed when no more words can be added to the sentence. When you
press enter, a word is added if there is only one magnet left,
<em>or</em> if what you have entered exactly matches one of the remaining
magnet.
<li>[Added 2010-05-28] Added a link to make it easy to try the same sentence in
<a href="http://translate.google.com">Google Translate</a>.This can be
turned off by passing the option <code>{try_google:false}</code> to
<code>start_minibar</code>.
<li>[Added 2010-06-02] Added support for Help and Feedback buttons, controlled
by the options <code>feedback_url</code> and <code>help_url</code> passed to
<code>start_minibar</code>.
<li>[Added 2010-06-02] New option: <code>default_source_language</code>.
<li>[Added 2010-09-10] Minibar now automatically uses
<a href="http://en.wikipedia.org/wiki/XMLHttpRequest">XHR</a>
instead of JSONP when possible (i.e. when the HTML document and the
PGF service are on the same server).
<li>[Added 2010-09-10] The default input language is now the user's preferred
language, if possible. This is implemented by consulting the
<code>userLanguage</code> field in the grammar info output by pgf-server.
<li>[Added 2010-10-27] Keyboard input and completion should now work much
more smoothly:
<ul>
<li>When you press space, the current word will be completed (if incomplete)
and a new magnet will be created. If there is more than one possible
completion, no magnet is created, but the common prefix of the possible
completions is added to the text box.
<li>Instead of asking the server for possible completions every time a new
letter is added to the curent word, minibar only ask for completions for
whole words and then filters the list locally when more letters are entered,
speeding things up when server responses are slow.
</ul>
<li>[Added 2010-10-27] Code restructuring:
<ul>
<li>The PGF server API has been moved to its own file:
<a href="pgf_online.js">pgf_online.js</a>. This
allows it to be reused in other applicaitons without importing the entire
minibar. It also allows minibar to be used with different server
interfaces. <a href="minibar.html">minibar.html</a> has been updated to
show how you use the new <a href="minibar.js">minibar.js</a> and
<a href="pgf_online.js">pgf_online.js</a>.
<li>The minibar code has been rewritten to avoid storing state information
in the document tree and accessing it by referring to named document
elements. The code now also avoids using string literals containing
the names of top-level functions to specify event handlers for buttons
and menus. (The code is no longer introspective, so &alpha; conversion
will not change its meaning.)
</ul>
<li>[Added 2010-11-09] Some new documentation:
<ul>
<li><a href="gf-web-api-examples.html">gf-web-api-examples.html</a>:
examples illustrating the PGF server API provided by
<a href="pgf_online.js">pgf_online.js</a>.
<li><a href="example.html">example.html</a>: a minimal example of a web
page that uses <a href="pgf_online.js">pgf_online.js</a> to talk to the
PGF server.
</ul>
<li>[Added 2011-03-03] Added a button to display word alignment.
<li>[Changed 2011-03-22] Don't force focus to the typed input field
after every word. On touch-based devices, the on-screen keyboard kept
popping up after every word, which was very annoying if you were
entering a sentence by tapping on the magnets.
<li>[Changed 2011-08-03] Moved the initialization code in minibar.html to
<a href="minibar_online.js">minibar_online.js</a>.
<li>[Changed 2011-08-08] For improved modularity and reusability,
two smaller objects have been factored out from the Minibar object:
Input and Translations. These have been placed in two separate files:
<a href="minibar_input.js">minibar_input.js</a> and
<a href="minibar_translations.js">minibar_translations.js</a>.
Some common auxiliary functions have also been moved to a separate file:
<a href="minibar_support.js">minibar_support.js</a>.
<li>[Added 2011-08-09] Added some <a href="minibar-api.html">Minibar API</a>
documentation.
<li>[Changed 2011-08-22] Quick fix to allow literals to be entered:
if you press Enter, the current word will be accepted, even if there are no
matching completions.
(You can now use names of people when constructing sentences in the Letter
grammar, for example.)
</ul>
<hr>
<small class=modtime>
<!-- hhmts start --> Last modified: Mon Aug 22 19:31:37 CEST 2011 <!-- 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>
</address>
</body> </html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -1,57 +0,0 @@
<!DOCTYPE html>
<html> <head>
<title>PGF online server example</title>
<style type="text/css">
body { background: #ddd; }
h1, h2, h3, small, th { font-family: sans-serif; }
div.modtime { float: right; }
.modtime { color: #666; white-space: nowrap; }
</style>
<script type="text/JavaScript" src="support.js"></script>
<script type="text/JavaScript" src="pgf_online.js"></script>
<script type="text/JavaScript">
var server_options={
grammars_url: "http://www.grammaticalframework.org/grammars/",
grammar_list: ["Foods.pgf"]
}
var pgf_server = pgf_online(server_options);
function call_server() {
pgf_server.parse({from:"FoodsEng",input:document.forms[0].input.value},
show_output)
}
function show_output(parsed) {
document.getElementById("output").innerHTML=parsed[0].trees[0]
}
</script>
</head>
<body>
<h1>PGF online server example</h1>
<form onsubmit="call_server(); return false">
Input:
<input name=input size=50 value="this cheese is expensive">
<input type=submit value=Parse>
<p>
Output:
<span id=output></span>
</form>
<h2>Documentation</h2>
<ul>
<li><a href="gf-web-api-examples.html">GF Web API examples</a>
</ul>
<hr>
<div class=modtime><small>
<!-- hhmts start --> Last modified: Wed Aug 3 16:52:51 CEST 2011 <!-- hhmts end -->
</small></div>
<address><a href="http://www.cse.chalmers.se/~hallgren/">TH</a></address>
</body> </html>

View File

@@ -1,44 +0,0 @@
#!/bin/bash
bin=bin
AUTOHEADER=no
. $bin/cgistart.sh
save_feedback() {
getquery
if [ -n "$feedback_path" ] &&
echo "t=$(date +%F+%T)&ip=$REMOTE_ADDR&$query&accept_language=$HTTP_ACCEPT_LANGUAGE&user_agent=$(echo -n $HTTP_USER_AGENT | plain2url)" >> "$feedback_path"
then
pagestart "Thank you!"
echo "Your feedback has been saved."
begin script type="text/javascript"
echo "setTimeout(function(){window.close()},4000);"
end
pageend
else
pagestart "Feedback error"
echo "Your feedback could not be saved. Sorry."
p
tag 'input type=button onclick="javascript:history.back()" value="&lt;- Go back"'
pageend
fi
}
view_feedback() {
charset="UTF-8"
pagestart "Collected Feedback"
begin pre class=feedbacklist
Reg show reverse drop color_depth,pixel_depth,outer_size,inner_size,available_screen_size from-url <"$PATH_TRANSLATED" | plain2html
end
pageend
}
case "$PATH_TRANSLATED" in
"") save_feedback ;;
*) view_feedback
esac

View File

@@ -1,48 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html> <head>
<title>Feedback</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>
<meta name = "viewport" content = "width = device-width">
</head>
<body onload="prefill_feedback_form()">
<h2><span id=grammar></span> Feedback</h2>
<form class=feedback name=feedback action="feedback.cgi" method="post">
<input type=hidden name="grammar">
<p>
<input type=hidden name="from"> <span class=field id=from>...</span> input:
<input type=hidden name="input"> <span class=field id=input>...</span>
<div id=translation_box>
<p><input type=hidden name="to"> <span class=field id="to">...</span> translation:
<input type=hidden name="translation"> <span class=field id=translation>...</span>
<p><label accesskey="S">Suggest a better translation:
<textarea rows=3 name="improvement"></textarea></label>
</div>
<p><label accesskey="C">Comments:
<br><textarea rows=5 name="comment"></textarea></label>
<p>
<input type=submit value="Submit Feedback">
<input type=button value="Cancel" onclick="window.close()">
<input type=hidden name="inner_size">
<input type=hidden name="outer_size">
<input type=hidden name="screen_size">
<input type=hidden name="available_screen_size">
<input type=hidden name="color_depth">
<input type=hidden name="pixel_depth">
</form>
</body>
</html>

View File

@@ -1,151 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>GF web services API examples</title>
<meta charset="UTF-8">
<style type="text/css">
body { background: #ddd; }
h1, h2, h3, small, th { font-family: sans-serif; }
dt { background: #cef; }
dt.js { background: white; margin-bottom: 1ex; }
dt.js em { color: #36f; }
dd { background: #ffc; margin-top: 1ex; margin-bottom: 1ex; }
dl.apiexamples>dt, dl.apiexamples>dd { font-family: monospace; }
dl.apiexamples>dd { white-space: pre; }
div.modtime { float: right; }
.modtime { color: #666; white-space: nowrap; }
@media projection {
div.intro { display: none; }
body {
font-size: 150%;
}
h2 { page-break-before: always; }
dl.apiexamples dd {
page-break-after: always;
/*border-style: none;*/
}
}
</style>
<body>
<h1>GF web services API examples</h1>
GF can be used interactively from the GF Shell. Some of the functionality
availiable in the GF shell is also available via the GF web services API.
<p>
The
<a href="http://code.google.com/p/grammatical-framework/wiki/GFWebServiceAPI">GF
Web Service API page</a> describes the calls supported by the GF web service
API. Below, we illustrate these calls by examples, and also show
how to make these calls from JavaScript using the API defined in
<a href="pgf_online.js"><code>pgf_online.js</code></a>.
<p>
<strong>Note</strong> that <code>pgf_online.js</code> was initially developed
with one particular web application in mind (the minibar), so the server API was
incomplete. It was simplified and generalized in August 2011 to support the
full API.
<dl>
<dt class=js>These boxes show what the calls look like in the JavaScript
API defined in <code>pgf_online.js</code>.
<dt>These boxes show the corresponding URLs sent to the PGF server.
<dd>These boxes show the JSON (JavaScript data structures) returned by the PGF
server. This will be passed to the callback function supplied in the
call.
</dl>
<h2>Initialization</h2>
<dl class=apiexamples>
<dt class=js>
<em>// Select which server and grammars to use:</em>
<br>var server_options = {
<br>&nbsp;&nbsp;grammars_url: "http://www.grammaticalframework.org/grammars/",
<br>&nbsp;&nbsp;grammar_list: ["Foods.pgf"] <em>// It's ok to skip this</em>
<br>}
<br>var server = pgf_online(server_options);
</dl>
<h2>Examples</h2>
<dl class=apiexamples>
<dt class=js> <em>// Get the list of available grammars</em>
<br>server.get_grammarlist(callback)
<dt>http://localhost:41296/grammars/grammars.cgi
<dd>["Foods.pgf","Phrasebook.pgf"]
<dt class=js> <em>// Select which grammar to use</em>
<br>server.switch_grammar("Foods.pgf")
<dt class=js><em>// Get list of concrete languages and other grammar info</em>
<br>server.grammar_info(callback)
<dt>http://localhost:41296/grammars/Foods.pgf
<dd>{"name":"Foods",
"userLanguage":"FoodsEng",
"categories":["Comment","Float","Int","Item","Kind","Quality","String"],
"functions":["Boring","Cheese","Delicious","Expensive","Fish","Fresh",
"Italian","Mod","Pizza","Pred","That","These","This","Those","Very",
"Warm","Wine"],
"languages":[{"name":"FoodsBul","languageCode":""},
{"name":"FoodsEng","languageCode":"en-US"},
{"name":"FoodsFin","languageCode":""},
{"name":"FoodsSwe","languageCode":"sv-SE"},
...]
}
<dt class=js><em>// Get a random syntax tree</em>
<br>server.get_random({},callback)
<dt>http://localhost:41296/grammars/Foods.pgf?command=random
<dd>[{"tree":"Pred (That Pizza) (Very Boring)"}]
<dt class=js><em>// Linearize a syntax tree</em>
<br>server.linearize({tree:"Pred (That Pizza) (Very Boring)",to:"FoodsEng"},callback)
<dt>http://localhost:41296/grammars/Foods.pgf?command=linearize&tree=Pred+(That+Pizza)+(Very+Boring)&to=FoodsEng
<dd>[{"to":"FoodsEng","text":"that pizza is very boring"}]
<dt class=js>server.linearize({tree:"Pred (That Pizza) (Very Boring)"},callback)
<dt>http://localhost:41296/grammars/Foods.pgf?command=linearize&tree=Pred+(That+Pizza)+(Very+Boring)
<dd>[{"to":"FoodsBul","text":"онази пица е много еднообразна"},
{"to":"FoodsEng","text":"that pizza is very boring"},
{"to":"FoodsFin","text":"tuo pizza on erittäin tylsä"},
{"to":"FoodsSwe","text":"den där pizzan är mycket tråkig"},
...
]
<dt class=js><em>// Parse a string</em>
<br>server.parse({from:"FoodsEng",input:"that pizza is very boring"},callback)
<dt>http://localhost:41296/grammars/Foods.pgf?command=parse&input=that+pizza+is+very+boring&from=FoodsEng
<dd>[{"from":"FoodsEng",
"brackets":{"cat":"Comment","fid":10,"index":0,"children":[{"cat":"Item","fid":7,"index":0,"children":[{"token":"that"},{"cat":"Kind","fid":6,"index":0,"children":[{"token":"pizza"}]}]},{"token":"is"},{"cat":"Quality","fid":9,"index":0,"children":[{"token":"very"},{"cat":"Quality","fid":8,"index":0,"children":[{"token":"boring"}]}]}]},
"trees":["Pred (That Pizza) (Very Boring)"]}]
<dt class=js><em>// Translate to all available languages</em>
<br>server.translate({from:"FoodsEng",input:"that pizza is very boring"},callback)
<dd>...
<dt class=js><em>// Translate to one language</em>
<br>server.translate({input:"that pizza is very boring", from:"FoodsEng", to:"FoodsSwe"}, callback)
<dt>http://localhost:41296/grammars/Foods.pgf?command=translate&input=that+pizza+is+very+boring&from=FoodsEng&to=FoodsSwe
<dd>[{"from":"FoodsEng",
"brackets":{"cat":"Comment","fid":10,"index":0,"children":[{"cat":"Item","fid":7,"index":0,"children":[{"token":"that"},{"cat":"Kind","fid":6,"index":0,"children":[{"token":"pizza"}]}]},{"token":"is"},{"cat":"Quality","fid":9,"index":0,"children":[{"token":"very"},{"cat":"Quality","fid":8,"index":0,"children":[{"token":"boring"}]}]}]},
"translations":
[{"tree":"Pred (That Pizza) (Very Boring)",
"linearizations":
[{"to":"FoodsSwe",
"text":"den där pizzan är mycket tråkig"}]}]}]
<dt class=js><em>// Get completions (what words could come next)</em>
<br>server.complete({from:"FoodsEng",input:"that pizza is very "},callback)
<dt>http://localhost:41296/grammars/Foods.pgf?command=complete&input=that+pizza+is+very+&from=FoodsEng
<dd>[{"from":"FoodsEng",
"brackets":{"cat":"_","fid":0,"index":0,"children":[{"cat":"Item","fid":7,"index":0,"children":[{"token":"that"},{"cat":"Kind","fid":6,"index":0,"children":[{"token":"pizza"}]}]},{"token":"is"},{"token":"very"}]},
"completions":["boring","delicious","expensive","fresh","Italian","very","warm"],
"text":""}]
</dl>
<hr>
<div class=modtime><small>
<!-- hhmts start --> Last modified: Sun Aug 21 10:52:43 CEST 2011 <!-- hhmts end -->
</small></div>
<address><a href="http://www.cse.chalmers.se/~hallgren/">TH</a></address>

View File

@@ -1,235 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>GF web services API examples</title>
<meta charset="UTF-8">
<style type="text/css">
body { background: #eee; }
h1, h2, h3, small, th { font-family: sans-serif; }
th { text-align: left; }
h1,h2 { border-bottom: 2px solid black }
dt { background: #cef; }
code { background: #ffc; }
dt.js { background: white; margin-bottom: 1ex; }
dt.js em { color: #36f; }
dd { background: #ffc; margin-top: 1ex; margin-bottom: 1ex; }
dl.apiexamples>dt, dl.apiexamples>dd { font-family: monospace; }
dl.apiexamples>dd { white-space: pre; }
table.border { border-collapse: collapse; margin-top: 1ex; margin-bottom: 1ex; }
table.border td, table.border th { border: 1px solid black; background: #fcfcfc; }
div.modtime { float: right; }
.modtime { color: #666; white-space: nowrap; }
</style>
<body>
<h1>Minibar API</h1>
The Minibar web app consists of the following objects:
<ul>
<li><a href="#Minibar">Minibar</a>
<li><a href="#Input">Input</a>
<li><a href="#Translations">Translations</a>
</ul>
They are described below.
<h2 id=Minibar>The Minibar object</h2>
<p>
This object implements the complete Minibar web app. It is defined in
<a href="minibar.js">minibar.js</a>. It also uses the <code>Input</code>
and <code>Translations</code> objects described below, and some auxiliary
functions defined in <a href="minibar_support.js">minibar_support.js</a>
and <a href="support.js">support.js</a>, so to use it in an
HTML file, you would normally include at least the following:
<blockquote><pre>
&lt;script type="text/JavaScript" src="minibar.js">&lt;/script>
&lt;script type="text/JavaScript" src="minibar_input.js">&lt;/script>
&lt;script type="text/JavaScript" src="minibar_translations.js">&lt;/script>
&lt;script type="text/JavaScript" src="minibar_support.js">&lt;/script>
&lt;script type="text/JavaScript" src="support.js">&lt;/script>
</pre></blockquote>
<p>
For an example, see <a href="minibar.html">minibar.html</a>.
<h3>Constructor</h3>
<code>var minibar=new Minibar(server,options,target)</code>
<ul>
<li><code>server</code> is the PGF service object.
<li><code>options</code> is an object where the following properties
can be set to override various default options:
<table class=border>
<tr><th>Option<th>Default<th>Description
<tr><td>show_abstract<td>false<td rowspan=3>See Translations,
not used directly by Minibar
<tr><td>show_trees<td>false
<tr><td>show_grouped_translations<td>true
<tr><td>delete_button_text<td>"⌫"<td rowspan=3>See Input,
not used directly by Minibar
<tr><td>default_source_language<td>null
<tr><td>random_button<td>true
<tr><td>try_google<td>true<td>Include a button to try the current
sentence in Google Translate
<tr><td>feedback_url<td>null<td>Include a button to open a feedback
form. The HTTP server must be configured to handle form submissions
for this to work.
<tr><td>help_url<td>null<td>Include a button to open a help text.
</table>
<li><code>target</code> is the <code>id</code> of the HTML element inside
which the minibar user interface is created. It can be omitted if
the <code>id</code> is <code>minibar</code>. The HTML document should
contain something like this:
<blockquote><code>&lt;div id="minibar">&lt;/div></code></blockquote>
</ul>
<h3>Methods</h3>
There are several internal methods, but since this is a self-contained
web app, there is usually no need to call any methods from outside.
<h2 id=Input>The Input object</h2>
This object handles user input. Text can be entered by typing or by clicking
on the "refrigerator magnets".
<p>
It is defined in
<a href="minibar_input.js">minibar_input.js</a>.
It also uses some auxiliary functions defined
in <a href="minibar_support.js">minibar_support.js</a>
and <a href="support.js">support.js</a>, so to use it in an
HTML file, you would normally include at least the following:
<blockquote><pre>
&lt;script type="text/JavaScript" src="minibar_input.js">&lt;/script>
&lt;script type="text/JavaScript" src="minibar_support.js">&lt;/script>
&lt;script type="text/JavaScript" src="support.js">&lt;/script>
</pre></blockquote>
<h3>Constructor</h3>
<code>var input=new Input(server,translations,options)</code>
<ul>
<li><code>server</code> is the PGF service object
<li><code>options</code> is an object where the following properties
can be set to override various default options:
<table class=border>
<tr><th>Option<th>Default<th>Description
<tr><td>delete_button_text<td>"⌫"<td>the label for the button that deletes the last word
<tr><td>default_source_language<td>null<td>the concrete language to
use for input in case the user's browers doesn't supply a suitable
default. If none is provided the first language in alphabetical
order will be used.
<tr><td>random_button<td>true<td>include a button to generate a
random sentence
</table>
<li><code>translations</code> is the object that is notified when the input
has changed. In the minibar, this is the object that display translations, but
other apps might of course use the entered text for other purposes.
The following methods will be called:
<ul>
<li><code>translations.clear()</code> is called when there no entered
text.
<li><code>translations.translateFrom({from:<var>conc</var>,input:<var>string</var>})</code>
is called when the user has entered some text. The <code>from</code>
property is the name of the concrete syntax and the <code>input</code>
property is the entered text.
</ul>
</ul>
<h3>Properties and user interface</h3>
The <code>input</code> object created by the <code>Input</code> constructor
contains two field that the caller should add to the user interface:
<ul>
<li><code>input.main</code> is the main user interface where the current
input and the refrigerator magnets are displayed.
<li><code>input.menus</code> contains the menu for selecting input language,
and buttons for deleting the last word, clearing the input and generating
a random sentence (if enabled in the options)
</ul>
<h3>Methods</h3>
<ul>
<li><code>input.change_grammar(grammar_info)</code> should be called
after a different grammar is selected in the <code>server</code> object. It
will clear away old input and magnets, and update the input language menu
with the languages available in the new grammar.
</ul>
<h2 id=Translations>The Translations object</h2>
This object display translations. It is defined in
<a href="minibar_translations.js">minibar_translations.js</a>.
It also uses some auxiliary functions defined
in <a href="minibar_support.js">minibar_support.js</a>
and <a href="support.js">support.js</a>, so to use it in an
HTML file, you would normally include at least the following:
<blockquote><pre>
&lt;script type="text/JavaScript" src="minibar_input.js">&lt;/script>
&lt;script type="text/JavaScript" src="minibar_support.js">&lt;/script>
&lt;script type="text/JavaScript" src="support.js">&lt;/script>
</pre></blockquote>
<h3>Constructor</h3>
<code>var translations=new Translations(server,options)</code>
<ul>
<li><code>server</code> is the PGF service object.
<li><p><code>options</code> is an object where the following properties
can be set to override various default options:
<table class=border>
<tr><th>Option<th>Default<th>Description
<tr><td>show_abstract<td>false<td>show the abstract syntax in addition
to the concrete syntax for the translations
<tr><td>show_trees<td>false<td>add buttons to display syntax trees
next to translations.
<tr><td>show_grouped_translations<td>true<td>in case there are
multiple translations, group them by concrete language
</table>
</ul>
<h3>Properties and user interface</h3>
The <code>translations</code> object created by the
<code>Translations</code> constructor contains two field that the caller
should add to the user interface:
<ul>
<li><code>input.main</code> is the main user interface where the current
translations are displayed.
<li><code>input.menus</code> contains the menu for selecting target language.
</ul>
<h3>Methods</h3>
<ul>
<li><code>translations.change_grammar(grammar_info)</code> should be called
after a different grammar is selected in the <code>server</code> object. It
will clear away old translations and update the target language menu
with the languages available in the new grammar.
</ul>
<hr>
<div class=modtime>
<small class=modtime>
HTML <!-- hhmts start --> Last modified: Sun Aug 21 19:11:35 CEST 2011 <!-- hhmts end -->
</small>
</div>
<address>
<a href="Http://www.cse.chalmers.se/~hallgren/">TH</a>
</address>

View File

@@ -1,53 +0,0 @@
body {
background: #ccc url("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, div#words input[type=button] {
display: inline-block;
font-family: sans-serif;
font-size: 100%;
background-color: white;
border: 1px solid black;
padding: 3px;
margin: 3px;
}
.invalid { color: red; }
div.modtime { float: right; }
.modtime { color: #666; white-space: nowrap; }
ul.space>li { margin-top: 0.75ex; }
div#saldospel input[type=button] { font-size: 100%; }
div#saldospel input.correct { color: green; }
div#saldospel input.incorrect { color: red; }
#surface input[type=text] { width: 5em; }
.feedback textarea { width: 95%; }
span.field { background-color: #eee; }
pre.feedbacklist { background: white }
img.button { padding: 1px; }

View File

@@ -1,41 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Minibar</title>
<link rel=stylesheet type="text/css" href="minibar.css">
<meta name = "viewport" content = "width = device-width">
<meta charset="UTF-8">
</head>
<body>
<h2>Minibar online</h2>
<div id=minibar></div>
<noscript>This page doesn't works unless JavaScript is enabled.</noscript>
<hr>
<small>
[<a href="about.html">About Minibar</a>
| <a href="http://www.grammaticalframework.org:41296/fridge/">Original Fridge Poetry</a>
&amp; <a href="http://www.grammaticalframework.org:41296/translate/">Translator</a>]
</small>
<small class=modtime>
HTML <!-- hhmts start --> Last modified: Mon Aug 8 18:04:22 CEST 2011 <!-- hhmts end -->
</small>
<address>
<a href="http://www.cse.chalmers.se/~hallgren/">TH</a>
<img src="http://www.altocumulus.org/~hallgren/online.cgi?icon" alt=""></address>
<script type="text/JavaScript" src="support.js"></script>
<script type="text/JavaScript" src="minibar.js"></script>
<script type="text/JavaScript" src="minibar_input.js"></script>
<script type="text/JavaScript" src="minibar_translations.js"></script>
<script type="text/JavaScript" src="minibar_support.js"></script>
<script type="text/JavaScript" src="pgf_online.js"></script>
<script type="text/javascript" src="minibar_online.js"></script>
</body>
</html>

View File

@@ -1,176 +0,0 @@
/* minibar.js
needs: minibar_support.js, minibar_input.js, minibar_translations.js, support.js
*/
/*
// This is essentially what happens when you call start_minibar:
if(server.grammar_list) grammars=server.grammar_list;
else grammars=server.get_grammarlist();
show_grammarlist(grammars)
select_grammar(grammars[0])
grammar_info=server.get_languages()
show_languages(grammar_info)
new_language()
complete_output=get_completions()
show_completions(complete_output)
*/
// For backward compatibility:
function start_minibar(server,opts,target) {
if(target) opts.target=target;
return new Minibar(server,opts);
}
/* --- Main Minibar object -------------------------------------------------- */
function Minibar(server,opts) {
// Contructor, typically called when the HTML document is loaded
/* --- Configuration ---------------------------------------------------- */
// default values for options:
this.options={
target: "minibar",
try_google: true,
feedback_url: null,
help_url: null
}
// Apply supplied options
if(opts) for(var o in opts) this.options[o]=opts[o];
/* --- Creating the components of the minibar --------------------------- */
this.translations=new Translations(server,this.options)
this.input=new Input(server,this.translations,this.options)
/* --- Creating user interface elements --------------------------------- */
this.menubar=empty("div");
this.extra=div_id("extra");
this.minibar=element(this.options.target);
this.minibar.innerHTML="";
with(this) {
appendChildren(menubar,[input.menus,translations.menus,input.buttons])
appendChildren(minibar,[menubar,input.main,translations.main,extra]);
append_extra_buttons(extra,options);
}
/* --- Minibar client state initialisation ------------------------------ */
this.grammar=null;
this.server=server;
/* --- Main program, this gets things going ----------------------------- */
with(this) {
if(server.grammar_list) show_grammarlist(server.grammar_list);
else server.get_grammarlist(bind(show_grammarlist,this));
}
}
Minibar.prototype.show_grammarlist=function(grammars) {
this.grammar_menu=empty_id("select","grammar_menu");
with(this) {
if(grammars.length>1) {
function opt(g) { return option(g,g); }
appendChildren(grammar_menu,map(opt,grammars));
grammar_menu.onchange=
bind(function() { select_grammar(grammar_menu.value); },this);
insertFirst(menubar,grammar_menu);
insertFirst(menubar,text("Grammar: "));
}
if(options.help_url)
menubar.appendChild(button("Help",bind(open_help,this)));
select_grammar(grammars[0]);
}
}
Minibar.prototype.select_grammar=function(grammar_name) {
var t=this;
//debug("select_grammar ");
function change_grammar() {
t.server.grammar_info(bind(t.change_grammar,t));
}
t.server.switch_grammar(grammar_name,change_grammar);
}
Minibar.prototype.change_grammar=function(grammar_info) {
var t=this;
with(t) {
//debug("show_languages ");
grammar=grammar_info;
input.change_grammar(grammar)
translations.change_grammar(grammar)
}
}
Minibar.prototype.append_extra_buttons=function(extra,options) {
with(this) {
if(options.try_google)
extra.appendChild(button("Try Google Translate",bind(try_google,this)));
if(options.feedback_url)
appendChildren(extra,[text(" "),button("Feedback",bind(open_feedback,this))]);
}
}
Minibar.prototype.try_google=function() {
with(this) {
var to=translations.target_lang();
var s=input.current.input;
if(input.surface.typed) s+=input.surface.typed.value;
var url="http://translate.google.com/?sl="
+langpart(input.current.from,grammar.name);
if(to!="All") url+="&tl="+to;
url+="&q="+encodeURIComponent(s);
window.open(url);
}
}
Minibar.prototype.open_help=function() {
with(this) open_popup(options.help_url,"help");
}
Minibar.prototype.open_feedback=function() {
with(this) {
// make the minibar state easily accessible from the feedback page:
minibar.state={grammar:grammar,current:input.current,
to:translations.to_menu.value,
translations:translations.translations};
open_popup(options.feedback_url,'feedback');
}
}
// This function is called from feedback.html
function prefill_feedback_form() {
var state=opener_element("minibar").state;
var trans=state.translations;
var gn=state.grammar.name
var to=langpart(state.to,gn);
var form=document.forms.namedItem("feedback");
setField(form,"grammar",gn);
setField(form,"from",langpart(state.current.from,gn));
setField(form,"input",state.current.input);
setField(form,"to",to);
if(to=="All") element("translation_box").style.display="none";
else setField(form,"translation",trans.single_translation.join(" / "));
// Browser info:
form["inner_size"].value=window.innerWidth+"×"+window.innerHeight;
form["outer_size"].value=window.outerWidth+"×"+window.outerHeight;
form["screen_size"].value=screen.width+"×"+screen.height;
form["available_screen_size"].value=screen.availWidth+"×"+screen.availHeight;
form["color_depth"].value=screen.colorDepth;
form["pixel_depth"].value=screen.pixelDepth;
window.focus();
}
/*
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
*/

View File

@@ -1,277 +0,0 @@
/* --- Input object --------------------------------------------------------- */
function Input(server,translations,opts) { // Input object constructor
this.server=server;
this.translations=translations;
// Default values for options:
this.options={
delete_button_text: "⌫",
default_source_language: null,
random_button: true,
}
// Apply supplied options
if(opts) for(var o in opts) this.options[o]=opts[o];
// User interface elements
this.main=empty("div");
this.menus=empty("span");
this.buttons=empty("span");
this.surface=div_id("surface");
this.words=div_id("words");
this.from_menu=empty("select");
with(this) {
appendChildren(main,[surface,words]);
appendChildren(menus,[text(" From: "),from_menu])
appendChildren(buttons,
[button(options.delete_button_text,bind(delete_last,this),"H"),
button("Clear",bind(clear_all,this),"L")]);
if(options.random_button)
buttons.appendChild(button("Random",bind(generate_random,this),"R"));
}
/* --- Input client state initialization --- */
this.current={from: null, input: ""};
this.previous=null;
this.from_menu.onchange=bind(this.change_language,this);
}
Input.prototype.change_grammar=function (grammar) {
update_language_menu(this.from_menu,grammar);
set_initial_language(this.options,this.from_menu,grammar);
this.change_language();
}
Input.prototype.change_language=function () {
this.current.from=this.from_menu.value;
this.clear_all();
}
Input.prototype.clear_all1=function() {
with(this) {
remove_typed_input();
current.input="";
previous=null;
surface.innerHTML="";
translations.clear();
}
}
Input.prototype.clear_all=function() {
with(this) {
clear_all1();
get_completions();
}
}
Input.prototype.get_completions=function() {
with(this) {
//debug("get_completions ");
words.innerHTML="...";
server.complete({from:current.from,input:current.input},
bind(show_completions,this));
}
}
Input.prototype.show_completions=function(complete_output) {
with(this) {
//debug("show_completions ");
var completions=complete_output[0].completions;
var emptycnt=add_completions(completions)
if(true/*emptycnt>0*/) translations.translateFrom(current);
else translations.clear();
if(surface.typed && emptycnt==completions.length) {
if(surface.typed.value=="") remove_typed_input();
}
else add_typed_input();
}
}
Input.prototype.add_completions=function(completions) {
with(this) {
if(words.timeout) clearTimeout(words.timeout),words.timeout=null;
words.innerHTML="";
words.completions=completions;
words.word=[];
var t=surface.typed ? surface.typed.value : "";
var emptycnt=0;
for(var i=0;i<completions.length;i++) {
var s=completions[i];
if(s.length>0) {
var w=word(s);
words.appendChild(w);
words.word[i]=w;
}
else emptycnt++;
}
filter_completions(t,true);
return emptycnt;
}
}
Input.prototype.filter_completions=function(t,dim) {
with(this) {
if(words.timeout) clearTimeout(words.timeout),words.timeout=null;
words.filtered=t;
//if(dim) debug('filter "'+t+'"');
var w=words.word;
words.count=0;
var dimmed=0;
var prefix=""; // longest common prefix, for completion
for(var i=0;i<w.length;i++) {
var s=words.completions[i];
var keep=hasPrefix(s,t);
if(keep) {
if(words.count==0) prefix=s;
else prefix=(commonPrefix(prefix,s));
words.count++;
}
if(dim) {
w[i].style.opacity= keep ? "1" : "0.5";
if(keep) w[i].style.display="inline";
else dimmed++;
}
else
w[i].style.display=keep ? "inline" : "none";
}
words.theword=prefix;
if(dimmed>0)
words.timeout=setTimeout(function(){ filter_completions(t,false)},1000);
}
}
Input.prototype.add_typed_input=function() {
with(this) {
if(!surface.typed) {
var inp=empty("input","type","text");
inp.value="";
inp.setAttribute("accesskey","t");
inp.style.width="10em";
inp.onkeyup=bind(complete_typed,this);
surface.appendChild(inp);
surface.typed=inp;
inp.focus();
}
}
}
Input.prototype.remove_typed_input=function() {
with(this) {
if(surface.typed) {
surface.typed.parentNode.removeChild(surface.typed);
surface.typed=null;
}
}
}
Input.prototype.complete_typed=function(event) {
with(this) {
//element("debug").innerHTML=show_props(event,"event");
var inp=surface.typed;
//debug('"'+inp.value+'"');
var s=inp.value;
var ws=s.split(" ");
if(ws.length>1 || event.keyCode==13) {
if(ws[0]!=words.filtered) filter_completions(ws[0],true);
if(words.count==1) add_word(words.theword);
else if(event.keyCode==13) add_word(ws[0]) // for literals
else if(elem(ws[0],words.completions)) add_word(ws[0]);
else if(words.theword.length>ws[0].length) inp.value=words.theword;
}
else if(s!=words.filtered) filter_completions(s,true)
}
}
Input.prototype.generate_random=function() {
var t=this;
function show_random(random) {
t.clear_all1();
t.add_words(random[0].text);
}
function lin_random(abs) {
t.server.linearize({tree:abs[0].tree,to:t.current.from},show_random);
}
t.server.get_random({},lin_random);
}
Input.prototype.add_words=function(s) {
with(this) {
var ws=s.split(" ");
for(var i=0;i<ws.length;i++)
add_word1(ws[i]+" ");
get_completions();
}
}
Input.prototype.word=function(s) {
var t=this;
function click_word() {
if(t.surface.typed) t.surface.typed.value="";
t.add_word(s);
}
return button(s,click_word);
}
Input.prototype.add_word=function(s) {
with(this) {
add_word1(s+" ");
if(surface.typed) {
var s2;
if(hasPrefix(s2=surface.typed.value,s)) {
s2=s2.substr(s.length);
while(s2.length>0 && s2[0]==" ") s2=s2.substr(1);
surface.typed.value=s2;
}
else surface.typed.value="";
}
get_completions();
}
}
Input.prototype.add_word1=function(s) {
with(this) {
previous={ input: current.input, previous: previous };
current.input+=s;
var w=span_class("word",text(s));
if(surface.typed) surface.insertBefore(w,surface.typed);
else surface.appendChild(w);
}
}
Input.prototype.delete_last=function() {
with(this) {
if(surface.typed && surface.typed.value!="")
surface.typed.value="";
else if(previous) {
current.input=previous.input;
previous=previous.previous;
if(surface.typed) {
surface.removeChild(surface.typed.previousSibling);
surface.typed.focus();
}
else surface.removeChild(surface.lastChild);
translations.clear();
get_completions();
}
}
}
/* --- Auxiliary functions -------------------------------------------------- */
function set_initial_language(options,menu,grammar) {
if(grammar.userLanguage) menu.value=grammar.userLanguage;
else if(options.default_source_language) {
for(var i=0;i<menu.options.length;i++) {
var o=menu.options[i].value;
var l=langpart(o,grammar.name);
if(l==options.default_source_language) menu.value=o;
}
}
}

View File

@@ -1,25 +0,0 @@
// minibar_demo.js, assumes that minibar.js and pgf_online.js have been loaded.
var online_options={
//grammars_url: "http://www.grammaticalframework.org/grammars/",
//grammars_url: "http://tournesol.cs.chalmers.se:41296/grammars/",
//grammars_url: "http://localhost:41296/grammars/",
//grammar_list: ["Foods.pgf"], // leave undefined to get list from server
}
if(/^\?\/tmp\//.test(location.search)) {
online_options.grammars_url=location.search.substr(1);
}
var server=pgf_online(online_options);
var minibar_options= {
show_abstract: true,
show_trees: true,
show_grouped_translations: false,
default_source_language: "Eng",
//feedback_url: "feedback.html",
try_google: true
}
var minibar=new Minibar(server,minibar_options);

View File

@@ -1,46 +0,0 @@
/* --- Auxiliary functions -------------------------------------------------- */
function langpart(conc,abs) { // langpart("FoodsEng","Foods") == "Eng"
return hasPrefix(conc,abs) ? conc.substr(abs.length) : conc;
}
function update_language_menu(menu,grammar) {
// Replace the options in the menu with the languages in the grammar
var lang=grammar.languages;
menu.innerHTML="";
for(var i=0; i<lang.length; i++) {
var ln=lang[i].name;
if(!hasPrefix(ln,"Disamb")) {
var lp=langpart(ln,grammar.name);
menu.appendChild(option(lp,ln));
}
}
}
function button_img(url,action) {
var i=img(url);
i.setAttribute("class","button");
i.setAttribute("onclick",action);
return i;
}
function toggle_img(i) {
var tmp=i.src;
i.src=i.other;
i.other=tmp;
}
function setField(form,name,value) {
form[name].value=value;
var el=element(name);
if(el) el.innerHTML=value;
}
function open_popup(url,target) {
var w=window.open(url,target,'toolbar=no,location=no,status=no,menubar=no');
w.focus();
}
function opener_element(id) { with(window.opener) return element(id); }

View File

@@ -1,162 +0,0 @@
/* --- Translations object -------------------------------------------------- */
var tree_icon="tree-btn.png";
var alignment_icon="align-btn.png";
function Translations(server,opts) {
this.server=server;
// Default values for options:
this.options={
show_abstract: false,
show_trees: false,
show_grouped_translations: true,
}
// Apply supplied options
if(opts) for(var o in opts) this.options[o]=opts[o];
this.main=empty("div");
this.menus=empty("span");
this.to_menu=empty_id("select","to_menu");
appendChildren(this.menus,[text(" To: "), this.to_menu])
this.to_menu.onchange=bind(this.get_translations,this);
}
Translations.prototype.change_grammar=function(grammar) {
this.grammar=grammar;
update_language_menu(this.to_menu,grammar);
insertFirst(this.to_menu,option("All","All"));
this.to_menu.value="All";
}
Translations.prototype.clear=function() {
this.main.innerHTML="";
}
Translations.prototype.translateFrom=function(current) {
this.current=current;
this.get_translations();
}
Translations.prototype.get_translations=function() {
with(this) {
var c=current;
if(options.show_grouped_translations)
server.translategroup({from:c.from,input:c.input},
bind(show_groupedtranslations,this));
else
server.translate({from:c.from,input:c.input},
bind(show_translations,this));
}
}
Translations.prototype.tdt=function(tree_btn,txt) {
with(this) {
return options.show_trees ? tda([tree_btn,txt]) : td(txt);
}
}
Translations.prototype.target_lang=function() {
with(this) return langpart(to_menu.value,grammar.name);
}
Translations.prototype.show_translations=function(translationResults) {
with(this) {
var trans=main;
//var to=target_lang(); // wrong
var to=to_menu.value;
var cnt=translationResults.length;
//trans.translations=translations;
trans.single_translation=[];
trans.innerHTML="";
/*
trans.appendChild(wrap("h3",text(cnt<1 ? "No translations?" :
cnt>1 ? ""+cnt+" translations:":
"One translation:")));
*/
for(p=0;p<cnt;p++) {
var tra=translationResults[p];
if (tra.translations != null) {
for (q = 0; q < tra.translations.length; q++) {
var t = tra.translations[q];
var lin=t.linearizations;
var tbody=empty("tbody");
if(options.show_abstract && t.tree)
tbody.appendChild(
tr([th(text("Abstract: ")),
tdt(node("span",{},[abstree_button(t.tree),
alignment_button(t.tree)]),
text(" "+t.tree))]));
for(var i=0;i<lin.length;i++) {
if(lin[i].to==to)
trans.single_translation.push(lin[i].text);
if(to=="All" || lin[i].to==to)
tbody.appendChild(tr([th(text(langpart(lin[i].to,grammar.name)+": ")),
tdt(parsetree_button(t.tree,lin[i].to),
text(lin[i].text))]));
}
trans.appendChild(wrap("table",tbody));
}
}
else if(tra.typeErrors) {
var errs=tra.typeErrors;
for(var i=0;i<errs.length;i++)
trans.appendChild(wrap("pre",text(errs[i].msg)))
}
}
}
}
Translations.prototype.show_groupedtranslations=function(translationsResult) {
with(this) {
var trans=main;
var to=target_lang();
//var to=to_menu.value // wrong
var cnt=translationsResult.length;
//trans.translations=translationsResult;
trans.single_translation=[];
trans.innerHTML="";
for(p=0;p<cnt;p++) {
var t=translationsResult[p];
if(to=="All" || t.to==to) {
var lin=t.linearizations;
var tbody=empty("tbody");
if(to=="All") tbody.appendChild(tr([th(text(t.to+":"))]));
for(var i=0;i<lin.length;i++) {
if(to!="All") trans.single_translation[i]=lin[i].text;
tbody.appendChild(tr([td(text(lin[i].text))]));
if (lin.length > 1) tbody.appendChild(tr([td(text(lin[i].tree))]));
}
trans.appendChild(wrap("table",tbody));
}
}
}
}
function abstree_button(abs) {
var i=button_img(tree_icon,"toggle_img(this)");
i.title="Click to display abstract syntax tree"
i.other=server.current_grammar_url+"?command=abstrtree&tree="+encodeURIComponent(abs);
return i;
}
function alignment_button(abs) {
var i=button_img(alignment_icon,"toggle_img(this)");
i.title="Click to display word alignment"
i.other=server.current_grammar_url+"?command=alignment&tree="+encodeURIComponent(abs);
return i;
}
function parsetree_button(abs,lang) {
var i=button_img(tree_icon,"toggle_img(this)");
i.title="Click to display parse tree"
i.other=server.current_grammar_url
+"?command=parsetree&from="+lang+"&tree="+encodeURIComponent(abs);
return i;
}

View File

@@ -1,96 +0,0 @@
// Assumes that Services.js has been loaded
function pgf_offline(options) {
var server = {
// State variables (private):
grammars_url: "",
grammar_list: ["Foods.pgf"],
current_grammar_url: null,
pgf : null,
// Methods:
switch_grammar: function(grammar_url,cont) {
//debug("switch_grammar ");
var new_grammar_url=this.grammars_url+grammar_url;
var self=this;
var update_pgf=function(pgfbinary) {
debug("Got "+new_grammar_url+", length="
+pgfbinary.length+", parsing... ");
self.pgf = {v: Services_decodePGF.v({v:pgfbinary}) }
//debug("done")
self.current_grammar_url=new_grammar_url;
cont();
}
ajax_http_get_binary(new_grammar_url,update_pgf);
},
get_grammarlist: function(cont) { cont([this.grammar_list]); },
get_languages: function(cont) {
cont(fromJSValue(Services_grammar.v(this.pgf)))
},
grammar_info: function(cont) {
cont(fromJSValue(Services_grammar.v(this.pgf)))
},
get_random: function(cont) {
alert("Random generation not supported yet in the offline version");
},
linearize: function(args,cont) {
cont(fromJSValue(Services_linearize.v(this.pgf)(v(args.tree))(v(args.to))));
},
complete: function(args,cont) {
cont(fromJSValue(Services_complete.v(this.pgf)(v(args.from))(v(args.input))));
},
parse: function(args,cont) {
cont(fromJSValue(Services_parse.v(this.pgf)(v(args.from))(v(args.input))));
},
translate: function(args,cont) {
cont(fromJSValue(Services_translate.v(this.pgf)(v(args.from))(v(args.input))));
},
translategroup: function(args,cont) {
cont(fromJSValue(Services_translategroup.v(this.pgf)(v(args.from))(v(args.input))));
}
};
for(var o in options) server[o]=options[o];
return server;
};
// See https://developer.mozilla.org/En/XMLHttpRequest/Using_XMLHttpRequest
function ajax_http_get_binary(url,callback) {
var http=GetXmlHttpObject()
if (http==null) {
alert ("Browser does not support HTTP Request")
return
}
var statechange=function() {
if (http.readyState==4 || http.readyState=="complete") {
if(http.status==200) {
var buffer=http.mozResponseArrayBuffer;
if(buffer) callback(bufferToString(buffer)) // Gecko 2 (Firefox 4)
else callback(http.responseText); // other browsers
}
else alert("Request for "+url+" failed: "
+http.status+" "+http.statusText);
}
}
http.onreadystatechange=statechange;
http.open("GET",url,true);
http.overrideMimeType('text/plain; charset=x-user-defined');
http.send(null);
//dump("http get "+url+"\n")
return http;
}
function bufferToString(buffer) {
// This function converts to the current representation of ByteString,
// but it would be better to use binary buffers for ByteStrings as well.
debug("bufferToString");
var u=new Uint8Array(buffer);
var a=new Array(u.length);
for(var i=0;i<u.length;i++)
a[i]=String.fromCharCode(u[i]);
return a.join("");
}

View File

@@ -1,52 +0,0 @@
/* --- Grammar access object ------------------------------------------------ */
function pgf_online(options) {
var server = {
// State variables (private):
grammars_url: "/grammars/",
grammar_list: null,
current_grammar_url: null,
// Methods:
switch_grammar: function(grammar_url,cont) {
this.current_grammar_url=this.grammars_url+grammar_url;
if(cont) cont();
},
get_grammarlist: function(cont) {
http_get_json(this.grammars_url+"grammars.cgi",cont);
},
pgf_call: function(cmd,args,cont) {
var url=this.current_grammar_url+"?command="+cmd+encodeArgs(args)
http_get_json(url,cont);
},
get_languages: function(cont) { this.pgf_call("grammar",{},cont); },
grammar_info: function(cont) { this.pgf_call("grammar",{},cont); },
get_random: function(args,cont) { // cat, limit
args.random=Math.random(); // side effect!!
this.pgf_call("random",args,cont);
},
linearize: function(args,cont) { // tree, to
this.pgf_call("linearize",args,cont);
},
complete: function(args,cont) { // from, input, cat, limit
this.pgf_call("complete",args,cont);
},
parse: function(args,cont) { // from, input, cat
this.pgf_call("parse",args,cont);
},
translate: function(args,cont) { // from, input, cat, to
this.pgf_call("translate",args,cont);
},
translategroup: function(args,cont) { // from, input, cat, to
this.pgf_call("translategroup",args,cont);
}
};
for(var o in options) server[o]=options[o];
if(server.grammar_list && server.grammar_list.length>0)
server.switch_grammar(server.grammar_list[0]);
return server;
}

View File

@@ -1,56 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Phrasebook</title>
<link rel=stylesheet type="text/css" href="minibar.css">
<meta charset="UTF-8">
<meta name = "viewport" content = "width = device-width">
</head>
<body>
<div id=minibar></div>
<hr>
<small>
Powered by <a href="http://www.grammaticalframework.org/">GF</a>,
see <a href="http://www.grammaticalframework.org/examples/phrasebook/doc-phrasebook.html">doc</a>.
</small>
<script type="text/JavaScript" src="support.js"></script>
<script type="text/JavaScript" src="minibar.js"></script>
<script type="text/JavaScript" src="minibar_input.js"></script>
<script type="text/JavaScript" src="minibar_translations.js"></script>
<script type="text/JavaScript" src="minibar_support.js"></script>
<script type="text/JavaScript" src="pgf_online.js"></script>
<script type="text/JavaScript">
var online_options={
// grammars_url: "http://www.grammaticalframework.org/grammars/",
//grammars_url: "http://tournesol.cs.chalmers.se:41296/grammars",
//grammars_url: "http://localhost:41296/grammars/",
grammar_list: ["Phrasebook.pgf"] // leave undefined to get list from server
}
var server=pgf_online(online_options);
var phrasebook_options={
delete_button_text: "Del",
help_url: "http://www.grammaticalframework.org/examples/phrasebook/help-phrasebook.html",
feedback_url: "feedback.html",
default_source_language: "Eng"
}
start_minibar(server,phrasebook_options)
</script>
</body>
</html>

View File

@@ -1,30 +0,0 @@
<!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>
<meta name = "viewport" content = "width = device-width">
</head>
<body onload="start_saldotest();start_saldospel()">
<h2>Vilket ord ska bort?</h2>
<div id=saldospel>
</div>
<h2>Hel- och halvspöke</h2>
<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: Thu May 27 14:02:42 CEST 2010 <!-- hhmts end -->
</small>
<address>TH <img src="http://www.altocumulus.org/~hallgren/online.cgi?icon" alt=""></address>
</body>
</html>

View File

@@ -1,340 +0,0 @@
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";
function saldo_ws(fn,fmt,arg,cont_name) {
jsonp(Saldo_ws_url+fn+"/"+fmt+(cont_name ? "+"+cont_name : "")+"/"+arg,"");
}
function saldo_json(fn,arg,cont_name) { saldo_ws(fn,"json",arg,cont_name); }
function saldo_lid(arg,cont_name) { saldo_json("lid",arg,cont_name); }
function saldo_lid_rnd(cont_name) { saldo_lid("rnd?"+Math.random(),cont_name); }
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")])
var style0="min-height: 3ex; margin: 5px; padding: 5px;";
element("surface").setAttribute("style",style0+"border: 3px dashed #e0e0e0;");
element("words").setAttribute("style",style0+"border: 3px solid #e0e0e0;");
clear_all();
}
function random_word() {
saldo_lid_rnd("show_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="&nbsp;";
//w.setAttribute("onclick",'extend_current("'+s+'")');
//return w;
return button(s,'extend_current("'+s+'")');
}
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';
}
}
// ordklasser: mxc sxc (förekommer bara som prefix),
// *h (förekommer bara som suffix)
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);
}
/* -------------------------------------------------------------------------- */
var spel={ antal_ord: 4, // antal närbesläktade ord att visa
antal_korrekta_svar: 0,
antal_felaktiga_svar: 0
};
function start_saldospel() {
spel.hylla=div_id("hylla");
spel.status=div_id("status");
//element("saldospel").innerHTML="<span id=score></span>";
appendChildren(element("saldospel"),
[spel.hylla,spel.status,
p(text("")),
button("Nya ord","spel0()"),
text(" "),
wrap("b",span_id("score"))]);
spel.score=element("score");
show_score();
spel0();
}
function spel0() { // Välj ord 1
saldo_lid_rnd("spel1");
}
function spel1(lid) { // Slå upp md1 för ord 1
spel.lid=lid;
saldo_json("md1",lid.lex,"spel2");
}
function spel2(md1) { // Kontrollera att det finns minst 4 ord i md1 för ord1
if(md1.length<spel.antal_ord) spel0();
else {
spel.md1=md1;
spel3();
}
}
function spel3() { // Välj ord 2
saldo_lid_rnd("spel4");
}
function spel4(lid) { // Slå upp md1 för ord 2
spel.lid2=lid;
saldo_json("md1",lid.lex,"spel5");
}
function spel5(md1) { // Kontrollera att ord 1 och ord 2 inte har något gemensamt
var ordlista1=map(wf,spel.md1);
var ord2=wf(spel.lid2.lex);
var ordlista2=map(wf,md1).concat(ord2);
if(overlaps(ordlista1,ordlista2)) spel3();
else spel6(ordlista1,ord2);
}
function spel6(ordlista1,ord2) {
spel.ord2=ord2;
var pos=Math.floor(Math.random()*spel.antal_ord);
var ordlista=shuffle(shuffle(ordlista1).slice(0,spel.antal_ord).concat(ord2));
spel.hylla.innerHTML="";
var lista=empty_class("div","space");
for(var i=0;i<ordlista.length;i++)
lista.appendChild((button(ordlista[i],"spel7(this)")));
spel.hylla.appendChild(lista);
}
function spel7(btn) {
btn.disabled=true;
var ok=btn.value==spel.ord2;
//btn.setAttribute("class",ok ? "correct" : "incorrect");
btn.setAttribute("style",ok ? "color: green" : "color: red");
if(ok) spel.antal_korrekta_svar++; else spel.antal_felaktiga_svar++;
show_score();
if(ok) spel0();
}
function show_score() {
spel.score.innerHTML=""+spel.antal_korrekta_svar+" rätt, "
+spel.antal_felaktiga_svar+" fel";
}
function wf(ord) { // word form, wf("band..1") == "band"
return ord.split(".",1)[0].split("_").join(" ");
}

View File

@@ -1,300 +0,0 @@
/* --- Accessing document elements ------------------------------------------ */
function element(id) {
return document.getElementById(id);
}
/* --- JavaScript tricks ---------------------------------------------------- */
// To be able to use object methods that refer to "this" as callbacks
// See section 3.3 of https://github.com/spencertipping/js-in-ten-minutes/raw/master/js-in-ten-minutes.pdf
function bind(f, this_value) {
return function () {return f.apply (this_value, arguments)};
};
/* --- JSONP ---------------------------------------------------------------- */
// 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);
}
var json = {next:0};
// Like jsonp, but instead of passing the name of the callback function, you
// pass the callback function directly, making it possible to use anonymous
// functions.
function jsonpf(url,callback)
{
var name="callback"+(json.next++);
json[name]=function(x) { delete json[name]; callback(x); }
jsonp(url,"json."+name);
}
/* --- AJAX ----------------------------------------------------------------- */
function GetXmlHttpObject(handler)
{
var objXMLHttp=null
if (window.XMLHttpRequest)
{
// See http://www.w3.org/TR/XMLHttpRequest/
// https://developer.mozilla.org/en/xmlhttprequest
objXMLHttp=new XMLHttpRequest()
}
else if (window.ActiveXObject)
{
objXMLHttp=new ActiveXObject("Microsoft.XMLHTTP")
}
return objXMLHttp
}
function ajax_http(method,url,body,callback,errorcallback) {
var http=GetXmlHttpObject()
if (!http) {
var errortext="Browser does not support HTTP Request";
if(errorcallback) errorcallback(errortext,500)
else alert(errortext)
}
else {
var statechange=function() {
if (http.readyState==4 || http.readyState=="complete") {
if(http.status<300) callback(http.responseText,http.status);
else if(errorcallback) errorcallback(http.responseText,http.status);
else alert("Request for "+url+" failed: "
+http.status+" "+http.statusText);
}
}
http.onreadystatechange=statechange;
http.open(method,url,true)
http.send(body)
}
return http
}
function ajax_http_get(url,callback,errorcallback) {
ajax_http("GET",url,null,callback,errorcallback)
}
function ajax_http_post(url,formdata,callback,errorcallback) {
ajax_http("POST",url,formdata,callback,errorcallback)
// See https://developer.mozilla.org/En/XMLHttpRequest/Using_XMLHttpRequest#Using_FormData_objects
}
// JSON via AJAX
function ajax_http_get_json(url,cont) {
ajax_http_get(url,function(txt) { cont(eval("("+txt+")")); });
}
function sameOrigin(url) {
var a=empty("a");
a.href=url; // converts to an absolute URL
return hasPrefix(a.href,location.protocol+"//"+location.host+"/");
}
// Use AJAX when possible, fallback to JSONP
function http_get_json(url,cont) {
if(sameOrigin(url)) ajax_http_get_json(url,cont);
else jsonpf(url,cont);
}
/* --- URL construction ----------------------------------------------------- */
function encodeArgs(args) {
var q=""
for(var arg in args)
if(args[arg]!=undefined)
q+="&"+arg+"="+encodeURIComponent(args[arg]);
return q;
}
/* --- HTML construction ---------------------------------------------------- */
function text(s) { return document.createTextNode(s); }
function node(tag,as,ds) {
var n=document.createElement(tag);
for(var a in as) n.setAttribute(a,as[a]);
for(var i in ds) n.appendChild(ds[i]);
return n;
}
function empty(tag,name,value) {
var el=node(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 span_id(id) { return empty_id("span",id); }
function wrap(tag,contents) { return node(tag,{},[contents]); }
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 li(contents) { return wrap("li",contents); }
function th(contents) { return wrap("th",contents); }
function td(contents) { return wrap("td",contents); }
function tr(cells) { return node("tr",{},cells); }
function button(label,action,key) {
var el=node("input",{"type":"button","value":label},[]);
if(typeof action=="string") el.setAttribute("onclick",action);
else el.onclick=action;
if(key) el.setAttribute("accesskey",key);
return el;
}
function option(label,value) {
return node("option",{"value":value},[text(label)]);
}
function appendChildren(el,ds) {
for(var i in ds) el.appendChild(ds[i]);
return el;
}
function insertFirst(parent,child) {
parent.insertBefore(child,parent.firstChild);
}
function tda(cs) { return node("td",{},cs); }
function img(src) { return empty("img","src",src); }
/* --- Debug ---------------------------------------------------------------- */
function debug(s) {
var d=element("debug");
if(d) d.appendChild(text(s+"\n"))
}
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) {
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Array/sort
return a.sort();
/* // 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) { // array of strings to string
/*
var s="";
for(var i=0;i<cs.length;i++)
s+=cs[i];
return s;
*/
return cs.join("");
}
function hasPrefix(s,pre) { return s.substr(0,pre.length)==pre; }
function commonPrefix(s1,s2) {
for(var i=0;i<s1.length && i<s2.length && s1[i]==s2[i];i++);
return s1.substr(0,i);
}
/*
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;
}
// map in continuation passing style
function mapc(f,xs,cont) { mapc_from(f,xs,0,[],cont); }
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 overlaps(as,bs) {
for(var i=0;i<as.length;i++)
if(elem(as[i],bs)) return true;
return false;
}
function elem(a,as) {
for(var i=0;i<as.length;i++)
if(a==as[i]) return true;
return false;
}
function shuffle(a) {
for(i=0;i<a.length;i++) swap(a,i,Math.floor(Math.random()*a.length))
return a;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 B