A Denitive System For The Browser University of Warwick Dissertation Report Author:

advertisement
University of Warwick
Dissertation Report
A Denitive System For The Browser
Author:
Timothy
Monks
Supervisor:
0622387
Dr. Steve
Russ
Keywords: JavaScript, Denitive Notations, Modelling, Web Browser, HTML5,
Compiler, Dependency, EDEN
September 15, 2011
Abstract
Interactive modelling through denitions has been a successful way of Thinking with
the computer in the Empirical Modelling Research group and with a wider community through spreadsheet packages. This project is an attempt to bring generalised
modelling to the browser using the browser-side scripting technology, JavaScript.
The report gives a technical description of the maintainer for state with denitions
and a translator for a language (EDEN), which allows for ecient maintenance of
such a system.
1
Contents
1 Introduction
6
1.1
Report structure
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
1.2
Acknowledgements
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
1.3
Motivation for Denitive Systems . . . . . . . . . . . . . . . . . . . .
7
1.3.1
Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
1.3.2
Denitive Notations
. . . . . . . . . . . . . . . . . . . . . . .
8
. . . . . . . . . . . . . . . . . . . . . . . . . . .
9
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
1.4
What is JavaScript?
1.5
Why JavaScript?
2 Related Work
12
2.1
TkEden
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2
The EDEN notation
2.3
WebEden
2.4
. . . . . . . . . . . . . . . . . . . . . . . . . . .
12
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
JavaScript Data Binding APIs . . . . . . . . . . . . . . . . . . . . . .
14
3 Aims and Initial Design
3.1
3.2
12
16
Design Thoughts for a Maintainer for State with Denitions
. . . . .
16
. . . . . . . . . . . . . .
16
. . . . . . . . . . . . . . . .
19
. . . . . . . . . . . . . . .
20
3.2.1
Preliminary Work: A JSON DSL for Denitions . . . . . . . .
20
3.2.2
Preliminary Work: Denition Maintainer . . . . . . . . . . . .
21
3.2.3
Change of Approach:
3.1.1
Support for Interactive Development
3.1.2
Associating Denitions and State
Design Thoughts for a Denitive Notation
Representation
Using JavaScript as an Intermediate
. . . . . . . . . . . . . . . . . . . . . . . . . .
21
3.3
Design Thoughts for an End User Interface - JsEden
. . . . . . . . .
23
3.4
Overview of Underlying Structure . . . . . . . . . . . . . . . . . . . .
23
2
4 Description of maintainer.js
25
4.1
Observables
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2
Symbol Table
4.3
Dealing with Observables that have yet to be dened
. . . . . . . . .
26
4.4
Denitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
29
4.5
Denition Maintenance . . . . . . . . . . . . . . . . . . . . . . . . . .
30
4.6
Simple JavaScript Agents
. . . . . . . . . . . . . . . . . . . . . . . .
30
4.7
Querying State
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
4.8
Mutation of observables
. . . . . . . . . . . . . . . . . . . . . . . . .
34
4.9
Note about Determining Dependencies Dynamically . . . . . . . . . .
34
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5 EDEN Translation Scheme
25
26
35
5.1
Number, Character and String Data Types . . . . . . . . . . . . . . .
35
5.2
Observables
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
5.3
Arithmetic, String and Boolean Logic Expressions . . . . . . . . . . .
36
5.4
Dierences Between EDEN and JavaScript's Built In Operators
. . .
36
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
37
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
38
5.4.1
5.5
Lists
Pointers
5.5.1
List Indexing
. . . . . . . . . . . . . . . . . . . . . . . . . . .
38
5.5.2
List modication statements . . . . . . . . . . . . . . . . . . .
39
5.6
Denitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
39
5.7
Extracting Denitions in EDEN Form for Formula Inspection
. . . .
39
5.8
Functions
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
40
5.9
Function Arguments
. . . . . . . . . . . . . . . . . . . . . . . . . . .
40
5.10 Function Argument Aliases . . . . . . . . . . . . . . . . . . . . . . . .
42
5.11 Function Local Variables . . . . . . . . . . . . . . . . . . . . . . . . .
43
5.12 Triggered Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
44
5.13 Control Flow
44
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.14 Verbatim JavaScript Sections
. . . . . . . . . . . . . . . . . . . . . .
45
5.15 Methodology for Developing the Translator . . . . . . . . . . . . . . .
45
3
6 Example Applications
47
6.1
JsEden Prototype . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
47
6.2
General Approach to Developing Visualisations with JsEden Models .
47
6.3
Example JsEden Model With A Simple Box Visualisation . . . . . . .
49
6.4
Embedding Formulas Into an HTML Document
50
. . . . . . . . . . . .
7 Project Management
52
7.1
Timeline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
52
7.2
Methodology
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
52
7.3
Other commitments . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53
7.4
Version Control and Backups
. . . . . . . . . . . . . . . . . . . . . .
53
7.5
Tools
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
7.6
Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
7.7
Legal, social, ethical and professional issues . . . . . . . . . . . . . . .
55
8 Conclusions
56
8.1
Success of targetting EDEN
. . . . . . . . . . . . . . . . . . . . . . .
56
8.2
Potential outside of EDEN . . . . . . . . . . . . . . . . . . . . . . . .
57
9 Further Work
58
9.1
More Model Development
. . . . . . . . . . . . . . . . . . . . . . . .
9.2
Implement Cyclic Dependency Checking
. . . . . . . . . . . . . . . .
58
9.3
Possibilities outside the browser . . . . . . . . . . . . . . . . . . . . .
58
9.4
Collaborative modelling and interaction with already existing tools
.
59
9.5
Modelling with hierarchical structures . . . . . . . . . . . . . . . . . .
59
9.6
Support for other notations
. . . . . . . . . . . . . . . . . . . . . . .
60
9.7
Improved JsEden UI
. . . . . . . . . . . . . . . . . . . . . . . . . . .
60
9.8
Improved Error Reporting for EDEN Code . . . . . . . . . . . . . . .
61
9.9
Persistency for the developed models in JsEden
61
4
. . . . . . . . . . . .
58
10 Appendices
64
10.1 Build Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
64
10.2 Test Cases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
64
10.3 Glossary of Technical Terms . . . . . . . . . . . . . . . . . . . . . . .
65
List of Figures
2.1
Screenshot of WebEden . . . . . . . . . . . . . . . . . . . . . . . . . .
14
3.1
Activity for a JavaScript VM over time . . . . . . . . . . . . . . . . .
17
3.2
Activity for a TkEden VM over time
18
3.3
An overview of how EDEN code is used with the JavaScript maintainer 24
4.1
Illustration of objects sharing a common operation via a prototype
object
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
26
4.2
Example of the Structure used to represent an observable . . . . . . .
27
4.3
Illustration of the symbol table used in the maintainer
. . . . . . . .
28
4.4
Illustration of notication of change to a dependent symbol . . . . . .
31
4.5
An example of agent observation
32
4.6
Illustration of scheduling a triggered action through
5.1
Screenshot of the grammar testing and development environment
6.1
Prototype JsEden Interface
6.2
A simple visualisation using a square
. . . . . . . . . . . . . . . . . .
50
6.3
Web page with embedded formulas that reect the maintainer.js state
51
. . . . . . . . . . . . . . . . . . . .
setTimeout
. .
33
. .
46
. . . . . . . . . . . . . . . . . . . . . . .
47
5
1
Introduction
1.1 Report structure
The project undertaken was to implement an interpreter for denitive notations that
would run in a modern browser.
This report is meant to provide a grounding so
that the reader may understand the project's topic and motivation, as well as documentation and analysis of the project itself. The report covers some rather technical
aspects of the implementation as well as possible future uses for the project and also
some higher level discussion on the topics of denitive notations and modelling. The
structure for the report is:
•
Introduction:
The rst section is intended to outline the problem and
provide a proper context to the rest of the text of the report. It will introduce
denitive notations as a tool for model building and software development as
well as the JavaScript platform.
•
Related work:
This section goes into some deeper analysis of already exist-
ing denitive systems and related libraries and frameworks that already exist
for JavaScript.
Particular attention is paid to how the current JavaScript
approaches dier from the interactive modelling approach usually associated
with denitive scripts.
•
Project Aims and Initial Design:
This section outlines the project aims
as well as the design process for the system to be built.
•
Description of maintainer.js:
This section is an in detail description of
the mechanics for the maintainer for state through denitions, including the
API for the maintainer, the underlying structures used and the state caching
system.
•
Project Management:
This section outlines the time line for the project,
as well as the tools used and any issues encountered.
•
Conclusions:
This section is a retrospective on the work done, including an
analysis of the success of the project.
•
Further Work:
This section covers potential extensions to the work done in
this project.
6
1.2 Acknowledgements
The work done in this project is my own. However, there are many people I would
like to thank for helping me get through this project, which has been technically
and more so personally dicult for me at times. While there are too many people
to thank individually, here is a summary:
•
The project supervisor Steve Russ and also Meurig Beynon, both of whom
oered much inspiration through their interest in my work, as well as great
support in something I personally nd dicult - writing up.
•
My girlfriend, Jess, who is far better at reminding me to nish things than my
own quiet conscience.
•
My family, for support and perspectives from their own experiences with similar problems in the past and for allowing me to have somewhere to live.
•
The sta at the department of computer science for giving me the chance to
complete this project and my degree.
•
Far too many students from the department of computer science and the computing society for reminding me that people are interested in what I do and
do interesting things with computers, and for having more faith in me than I
do!
1.3 Motivation for Denitive Systems
This section provides a small discussion on models leading to the motivations for
using computers and denitive systems for model construction.
1.3.1 Models
A model is a construction that helps humans reason about the world. For example,
understanding the combination of quantities can be helped via the combination
of symbols and sets of rules (logic, or mathematics), or using a physical device
like an abacus. In either case there is some external experience from the referent
phenomenon (the thing we are interested in understanding) that we can somehow
use to make conclusions about the referent.
7
As well as helping us reason about things, models also help us communicate about
the world. This can depend on the representation used for the modelling, some are
more convenient for communication than others.
History has seen the development of increasingly complex models (mostly mathematical systems, as opposed to increasingly complex abacuses), which have allowed
humans to reason about dicult things like the spread of infectious disease and next
week's weather. The development of computers has allowed us to solve the complex
equations involved in these models in very short periods of time, thus, computers
are an important part of understanding complex systems.
1.3.2 Denitive Notations
A denitive notation is somewhat like a programming language, it is a tool to craft
a source of experience which utilises computer hardware. One might use either tool
to model a familiar real world phenomena (e.g. a simulation of a ball falling into
a uid), or go the other way, and create something that is unfamiliar (e.g. reverse
the gravitational eect on the ball).
The key feature for a denitive notation is the presence of denitive statements,
which take the form:
definitive statement ::= symbol “is” formula
These statements dene a particular observable in terms of a formula which may
contain other observables.
In order to build a model using these sorts of denitions, a maintainer is needed
that ensures that the model can never be observed in a state that is unfaithful to
the current set of denitions. This job is very amenable to formal reasoning, so a
computer program is appropriate for carrying this out.
Modelling through denitions is already quite popular in spreadsheet packages.
While similar to programming languages in that they can have imperative parts
for performing algorithms, they generally are found in tools which give a much more
interactive experience in which the model state is much more tangible and immediately modiable. The experience is much more like using a multimedia tool like
PhotoShop, where your actions have much more observable consequences, as opposed to a program where there is a complex relation between your modication to
the program and the behaviour of the program.
8
1.4 What is JavaScript?
This short section is intended to clear up what JavaScript is and provide enough understanding of the features of JavaScript such that the implementation of a denitive
system can be explained later.
JavaScript is a technology which allows for much more dynamic content in a web
page than would be possible from just rendering HTML. Though the name is very
similar to the programming language Java, the language itself is in fact very distinct
except for the fact that both of them have similar syntax to the C programming
language. Apart from this it has the following distinguishing features:
•
Dynamically typed
•
Duck typing
•
First class functions
•
Object Oriented through use of object prototypes
Generally JavaScript is run via a virtual machine, through direct interpretation and
more recently through clever JIT (Just In Time) compilation techniques. The use of
these techniques has turned JavaScript into a much more powerful tool in modern
browsers than it had been previously, especially when compared to alternative technologies such as Flash, Java or SilverLight which have run on sophisticated VMs for
quite some time.
JavaScript is embeddable directly in web pages simply by using HTML
<script>
tags. It does not require any plugins to be installed by the end user of the webpage,
just that they have a browser which supports JavaScript (and have not explicitly
disabled it), which includes the vast majority of browsers today. To make this a bit
clearer, here is a simple example of embedding some JavaScript that changes the
content of a webpage every second:
<html>
<head>
<script type="text/javascript">
var counter = 0;
window.onload = function() {
setInterval(function() {
counter++;
document.body.innerHTML = counter;
9
}, 1000);
};
</script>
</head>
<body>
</body>
</html>
The key things to notice in the listing are:
•
The script is embedded directly in the web page
•
The use of `function()' allows for writing function values, which in turn
allows for the use of higher order functions such as
setInterval
• setInterval takes a procedure to run and an interval, in milliseconds, which
is how frequently the passed procedure should be called.
•
It is possible to easily manipulate the DOM (Document Object Model) of a
document.body.innerHTML
<body> section of the page
webpage from JavaScript, e.g. assignment to
allows mutation of the content in the
1.5 Why JavaScript?
There are several other technologies that allow for development of rich web applications. The other notable technologies are:
•
Adobe Flash
•
Java Applets
•
Microsoft Silverlight
JavaScript was chosen over these for a few reasons:
•
Superior cross platform support. Flash will not run on iOS devices (iPhone,
iPad) for example, and has poor support under GNU/Linux.
run on iOS devices.
Java will not
Silverlight has some support for platforms other than
Microsoft Windows through a free implementation of the .NET runtime called
Mono, but is not ocially supported.
10
•
No plugins required. JavaScript applications work out of the box with any
modern browser. There is no need to manually download any plugins, which
lowers the level for entry for applications written in JavaScript.
•
Event based programming model.
JavaScript allows you to dene handlers
which execute whenever some event happens. These handlers are eectively
observing agents.
•
JavaScript can interact well with webpages. One interesting aspect that might
be explored is using a lightweight JavaScript maintainer to demonstrate the
ideas of dependency in an informational webpage.
•
Simple toolchain.
All that is needed to modify an application written in
JavaScript is a text editor. Refreshing the browser will allow you to use the
updated application.
This could prove valuable for lowering the barrier of
entry for new developers.
11
2
Related Work
This project is mostly a practical one, so while there is limited relevant literature
(except in maybe the ecient implementation of compilers, which will be relevant
later on), it is important to examine already existing systems which use denitive
notations as these were the context in which the design decisions during the project
were made.
2.1 TkEden
TkEden is a tool developed at the University of Warwick which allows for interactive model construction using denitive notations. The name TkEden reects the
underlying interpreter for denitive notations called EDEN, and the toolkit used for
the user interface, Tk. It has a very large history of use by students in the University, leading to a large archive of models which are free to obtain and use. The core
concepts in TkEden are:
•
Observables - all of the model state is captured through named values called
observables
•
Dependency - Observables can be dened in terms of each other, and then
kept consistent by the maintainer
•
Agency - Agency is what causes change in the model state, and can happen
by human intervention or by triggered actions which act as simple machine
based agents watching for changes in particular observables
2.2 The EDEN notation
The TkEden tool infact supports several notations for use in dierent contexts.
The main notation (which most of the other notations are in fact translated to) is
called EDEN. The notation acts as an imperative interface to the underlying engine,
which allows for manipulation of the various observables, dependencies and agency
in a model.
Each statement is like a single interaction with the model state. Some interactions
rene the dependencies that the model adheres to, while others are a direct manipulation of the model state. Others have no interaction with the model state at all,
but cause some side eects somewhere else, e.g. an arithmetic expression with no
12
assignment to an observable will have no eect to the model or an expression which
calls the writeln function to log something to the TkEden console.
The syntax has a similar style to C, as well as supporting imperative style programming (e.g. assignment, loops and other ow control).
Denitions in EDEN take the form:
observable is formula;
Where a formula is some expression, syntactically similar to an expression you might
see in any C like programming language. There is a reasonably accurate documentation of the grammar available from [Beynon(2006)].
2.3 WebEden
WebEden is a tool which allows for modelling with denitions in the browser.
It
was created by Richard Myers as a 3rd year project at the University of Warwick.
The architecture combines a Flash frontend connected up to a modied instance of
TkEden. The important parts of the architecture are:
•
The Flash frontend is all about managing input and presenting a nice interface,
and pushing interactions to the backend via an XML protocol.
•
The interpretation of EDEN code (and code in other notations) and the dependency maintenance all happens on the modied instance of TkEden, which
then communicates any changes back to the UI.
While WebEden was an excellent 3rd year project, and does allow for modelling
through denitions through a remote interface to TkEden, there are some benets
in moving away from the architecture that it uses:
•
Analogue interactions are laggy - Since WebEden relies on transmitting user
interactions over a wire to be processed, and then receiving a response to that,
change triggered by mouse motion seems a lot less continuous than it usually
would.
•
Expensive to scale - WebEden requires a single instance of TkEden for each
user using WebEden. If the maintainer and interpreter existed locally, scaling
would be a lot simpler.
13
Figure 2.1: Screenshot of WebEden
http://www2.warwick.ac.uk/fac/sci/dcs
/research/em/software/webeden/)
(taken from
•
Architecture overly complex - WebEden had sophisticated load balancing and
authentication systems in place. These are denitely important in WebEden,
unfortunately at the University of Warwick these seemed to be problematic,
leading to users having problems in connecting to instances of TkEden hosted
in the department of computer science. This could possibly be xed with the
proper knowledge of WebEden and some negotation with the department, but
it could be avoided entirely if we removed the reliance on a remote dependency
engine an interpreter.
2.4 JavaScript Data Binding APIs
There are a few libraries that already exist for JavaScript which support something
resembling modelling with denitions.
They use a technique called data binding
to tackle a particular concern - updating some visual representation of data from
an underlying model whenever change occurs to the model.
This is analogous to
triggered actions in EDEN, however, these systems generally have no concern for
maintaining state such that a set of denitions is always faithful. Some frameworks
of interest are:
•
backbone.js
14
•
Knockout
•
SproutCore
Data bindings can also be found in other environments such as Adobe FLEX or
when using Key-Value Observation with Objective C.
15
3
Aims and Initial Design
This section provides both an outline of the key aims and objectives as well as a
more granular break down of sub-aims and sub-objectives, so that it is clear what
is trying to be achieved in the following sections.
The overall aim of the project is to attempt to prototype a system for interactive
modelling with denitions, that works in the browser. The main objectives for the
project are:
•
Build a system that maintains state through denitions that runs in modern
web browsers
•
Develop support for a denitive notation for the system
•
Explore possible applications of both
3.1 Design Thoughts for a Maintainer for State with Denitions
3.1.1 Support for Interactive Development
Modelling with denitions is an interactive process where the model is rened
through continuous observation and action.
This is a discussion of how the cho-
sen platform, JavaScript, can allow such a work ow.
A JavaScript engine executes in a single thread, and is asleep most of the time. In
order for computation to happen, some event must trigger it rst. Some examples
of events are a timer nishing, user interaction or receiving an HTTP response. The
timeline in Figure 3.1 illustrates this, where the shaded areas correspond to activity
in the machine.
This is similar to the activity of TkEden's virtual machine. Until agency spontaneously renes the state, the machine can stay asleep. The important thing is that
the TkEden virtual machine ensures that before the state can be observed again,
no observables have associated values which are inconsistent with their denitions.
Figure 3.2 shows how the activity of the TkEden VM can be construed as similar
to the JavaScript one.
Further to this, the TkEden virtual machine needs to notify triggered actions of any
state that was modied by the last spontaneous update. These then execute in some
undened order (but notably not in parallel).
16
activity
time
page
load
user
interaction
user
interaction
Figure 3.1: Activity for a JavaScript VM over time
17
dealing with dependency maintenance and
queueing triggered actions
time
script
loaded
agency
agency
Figure 3.2: Activity for a TkEden VM over time
18
Now, looking at the similarity between the operation of the TkEden VM and the
JavaScript VM, it seems that the JavaScript VM is already a good platform for
interactive development in the style that TkEden supports. The JavaScript process
carries a persistent state with it, and indeed it is very possible to interact with
that state interactively and observe it change. The key dierence is that there is no
notion of a denition attached to a variable, variables only take values. The crux of
the work is to provide some structure for associating denitions with observables, as
before this is done there is really no concept of maintaining the values of observables
based on denitions. It is also desirable to manage the `values' and `denitions' of
observables eciently, i.e. whenever possible, avoid re-computation of the `value' of
an observable based on some denition, though that is more of an implementation
detail than a conceptual problem.
3.1.2 Associating Denitions and State
A simple way to work around the problem of variables not having both a value and
a denition is to make the value stored in a variable model an observable, by using
an aggregate which contains the denition for the observable as well some computed
value for it. JavaScript supports aggregate types as collections of key value pairs,
called Objects. An example of an observable modelled with an object is:
{
value: 2,
definition: function(context) { return 2; }
}
Alternatively it may be preferable to store all the observable values and all the
observable denitions in separate data structures.
There are no hooks in JavaScript for when a variable changes. However, if we always
ensure that updates to state happen through calls to particular functions, we can
ensure that the implementation of these functions guarantees that it is impossible
to observe inconsistent state, as well as notifying any machine agents of changes in
state.
To summarise:
•
JavaScript's execution model already a great match for TkEden's interactive
development
19
•
The JavaScript process carries with it a persistent state which can be interactively modied and observed
•
JavaScript variables have no concept of a denition like TkEden observables,
so some way of modelling this needs to be in place
•
JavaScript doesn't provide hooks for mutation of it's state, however if we
ensure that we use particular functions for all change, we can ensure these
changes come with indivisible changes of dependent observables
3.2 Design Thoughts for a Denitive Notation
3.2.1 Preliminary Work: A JSON DSL for Denitions
Before deciding to carry out this work as a dissertation project, a previous denition
maintainer was developed based around it's own JSON based DSL for specifying
denitions. JSON was used for several reasons:
•
JSON is small in amount of syntax and number of concepts to learn, compared
to something like XML
•
JSON is easy to work with in JavaScript since it maps to JavaScript data
structures directly
•
Allows for the possibility of transmitting denitions between processes, e.g.
for working with denitions in a collaborative setting like dtkeden.
In this system, formulas were represented by a list of JSON Objects, where Objects
represented symbols and operators in the language.
Each Object's meaning was
determined by a particular eld called `type'. An example of a formula would be:
[
{
‘type’: ‘Symbol’,
‘value’: ‘add’
},
{
‘type’: ‘Symbol’,
‘value’: ‘a’
20
}, {
‘type’: ‘Number’,
‘value’: 1
}
]
This structure, when evaluated using a hand written evaluator, would eectively
be equivalent to computing the expression `a + 1' where a is an observable in the
environment that is being maintained.
Further to this a parser for a LISP like dialect was developed, in order to make it
easier to specify formulas for denitions using simple prex notation for functions.
Again this parser was hand written due to the simplicity of the language.
The
previous denition could be written using this language like so:
(add a 1)
The language was developed to the point of supporting lambda (function) expressions and hence the denition of named functions via dening a symbol to be a
lambda expression was possible.
3.2.2 Preliminary Work: Denition Maintainer
As well as having some way of representing denitions, a maintainer also had to be
developed to ensure that observables could be associated with a denition and that
any observables were always faithful to the denitions stored in the system.
The
pattern used for denition re-evaluation is the same as the nal maintainer and in
fact the nal maintainer evolved from the code initially developed at this stage.
3.2.3 Change of Approach: Using JavaScript as an Intermediate Representation
Shortly after starting to develop the previously described system, I discovered CoffeeScript [Ashkenas(2011)] which translates a DSL directly to JavaScript (with the
aim of just providing some syntactic sugar around common JavaScript idioms or
pitfalls), and decided that the approach of translating EDEN to JavaScript was an
interesting idea.
21
The key dierence is that instead of developing a custom data structure that represents a denition (the list structure described in the previous section), the system
would just use native JavaScript functions since they are already the perfect abstraction for a computation, which is essentially what evaluating a denition is.
For example, using a JavaScript function to represent the expression used to demonstrate the JSON powered DSL would result in something like the following:
function() {
return observables.a + 1;
}
Once some JavaScript has been generated, it is possible to dynamically evaluate it
using the builtin
eval
function.
This approach has several advantages over the previously investigated one:
•
No need to design an intermediate representation (IR) capable of representing
enough for EDEN denitions.
Plus, JavaScript is already a great choice of
target language for the EDEN notation, as it is so similar syntactically.
•
No need to develop interpreter for the IR, just use the JavaScript interpreter
(which is also much more ecient in certain cases as it performs Just In Time
compilation [Google(2000)])
As well as this, there would be the benet of the ability to reuse previous models
developed using TkEden, for both learning how direct use in a fully compatible
environment or just as a source of illustrative examples for how to use the EDEN
language.
After this decision, the project had two clear, reasonably independent goals:
1. Develop a maintainer for state with associated functions acting as denitions.
2. Develop a translator for EDEN to JavaScript, relying on methods provided by
the maintainer to interact with some set of observables.
22
3.3 Design Thoughts for an End User Interface - JsEden
Further to the technical work to be done, it would be good to have an interface
that can be used for entering EDEN code interactively and observing the results.
This environment would be called JsEden to reect the targetting of EDEN, and
the underlying implementation using JavaScript. Ideally the interface would look
similar to TkEden, which has quite good facilities for inspecting the current model
state and denitions.
3.4 Overview of Underlying Structure
What follows is an overview of how the individual parts of the JsEden environment
all relate to each other:
The important things to note are:
•
Observables dened using formulas are modelled using some JavaScript data
type
•
Updates to the state happen through function calls, which allows us to intercept them and maintain dependencies eciently, as well as triggering machine
agents Triggered actions
Figure 3.3 shows how the EDEN to JavaScript translator and maintainer.js are
related.
The key things to note are:
•
The EDEN to JavaScript translator is written in JavaScript itself and available
as a function which takes EDEN code as a String and returns JavaScript code
as a String.
•
The JavaScript code is then input into the eval procedure, which runs the code
given to it in the same context as it's callsite. This can cause updates in any
state accessible, most notably it can cause updates via the maintainer.js APIs.
23
other
JavaScript
state
EDEN code
EDEN to
JavaScript
translator
maintainer.js
state
the generated
JavaScript can have
side effects
JavaScript
code
implemented as a JavaScript
function
HTML DOM
state
JavaScript
evaluator
implemented as a builtin function
of JavaScript
Figure 3.3: An overview of how EDEN code is used with the JavaScript maintainer
24
4
Description of maintainer.js
This section gives a more detailed description of the workings of the JavaScript
maintainer, called maintainer.js in this project.
At the start of this project, a small library was developed in order to perform
maintenance of a set of observables, possibly dened in terms of each other, as well
as agent interactions within the world of observables.
This section describes the
underlying workings of the library as a reference for those interested in using it or
creating any sort of derivative work.
This section also goes on to describe other
possible solutions for dependency maintenance and weigh up how much the design
of the chosen solution was inuenced by the desire to support the modelling activity
through the EDEN notation.
The main topics of concern for the library are:
•
How are observables modelled
•
How are observable denitions (formulas) represented
•
How are observables stored and accessed by name
•
How symbols can depend upon, or observe, other symbols
•
How is indivisible dependency implemented eciently
4.1 Observables
Observables should allow for the association of a name with a value as well as a
denition. This was implemented using a JavaScript Object, which is essentially a
key value store as hinted at earlier.
As well as being a key value store, JavaScript objects can come with a prototype
object which is checked in the case where a requested key has no associated value.
This makes it easy to attach common functionality to each Object intended to model
an observable: let them share the same prototype and attach common functionality
to the prototype (see Figure 4.1 for an illustration). In the code developed during
this project, the observables were described as symbols, and they all share the same
Symbol prototype. The following JavaScript code demonstrates how functionality
is tacked on to the Object used as a prototype:
Symbol.prototype.value = function() { ... }
25
The prototype has
common functionality
attached to it
Symbol
Symbol Prototype
Symbol
Symbol
Figure 4.1: Illustration of objects sharing a common operation via a prototype object
Each symbol stores its current value, and its denition. Further to this, it stores
important information such as the symbols that rely on it in their denitions, the
agents that are observing it and also the symbols it relies on and observes.
This
information is used in the cacheing system for observable state. Figure 4.2 illustrates
the structure of the
Symbol type, which just stores this information in various elds.
4.2 Symbol Table
Observables are stored in a symbol table, which maps string identiers to
values.
This allows us to query and modify symbols using a name.
Symbol
This is im-
plemented in a straight forward manner, using an Object where the keys are the
observable names and the values are the Symbols, and is shown in Figure 4.3.
4.3 Dealing with Observables that have yet to be dened
In TkEden it is possible to dene an observable in terms of some other observable
name that currently has had no value or denition associated with it. The API for
26
Symbol
Value
2
Definition
function(c) {
return c.lookup('x') + 1
};
Subscribers
[ ]
Subscribees
[ "x" ]
Observers
[ ]
Figure 4.2: Example of the Structure used to represent an observable
27
Symbol Table
Symbol
Value
Definition
2
function(c) {
return c.lookup('x') + 1
};
y
Subscribers
[ ]
Subscribees
[ "x" ]
Observers
[ ]
x
Figure 4.3: Illustration of the symbol table used in the maintainer
28
the maintainer.js symbol table has been designed to deal with this case. In order to
fetch an observable to query its value or modify it, a call must be made using the
lookup
method. This allows us to check whether the requested symbol has been
observed or dened before: if this is not the case, a new
Symbol
is created for it
and returned. This can then be modied or queried, and will have its initial value
as
undefined.
4.4 Denitions
Denitions are simply represented using a function.
In JavaScript, functions are
values so this makes it simple for dynamic storage of `denitions' by simply storing
a JavaScript function. The convention currently used in the maintainer is that the
rst argument to the function is a symbol table of observables, and the return value
of a function is the `value' of the observable given the current system state. A simple
example of a denition represented this way is:
function(context) {
return context.lookup(’a’).value() + 1;
}
This function, when evaluated, returns 1 greater than the current value of the `a'
observable (assuming the observable `a' has some numeric value currently, else the
result will be an erroneous value).
Any
Symbol
comes with a method to associate a denition with it:
Symbol.prototype.define
Unfortunately functions in JavaScript are not like mathematical functions, they
are not guaranteed side eect free nor are they guaranteed to satisfy referential
transparency (they could rely on some external state for their result), which means
when using the `native' JavaScript interface it is up to the modeller to ensure they
use pure functions for their denitions or they may get some unpredictable (and
unrepeatable) results. This problem can be addressed with an appropriate domain
specic language, however the one implemented later (the EDEN denitive notation)
does not enforce this constraint.
29
4.5 Denition Maintenance
Now that there is a structure which maps all the observables to a function that
can be treated as a `denition' by evaluating it, it is already possible to have a
system where observation of an observable results in a value that is faithful to it's
formula. The most naive solution is to simply evaluate the function used to represent
it's formula on each attempt to inspect it.
However, this is obviously a lot more
wasteful than what can be achieved, also it makes it impossible to implement EDEN
style triggered actions which only trigger when an observable changes, which will be
implemented later.
Therefore, the maintainer attempts to trigger re-evaluation only when necessary.
It does this through a combination of a simple cache mechanism for the results of
formulas, and by allowing the (manual) specication of observables that are relied
upon in a particular formula. These are called dependencies for the formula, and
any change to them should invalidate any cached value for the result of that formula.
An example of using the raw JavaScript api is:
context.lookup(‘a’).define(function(context) {
return context.lookup(‘b’) + 1;
}).subscribe([‘b’]);
The call to
is changed.
subscribe
is what sets up the notications for when some symbol
All this does is request that the symbols subscribed to inform this
symbol of any changes, so it can then mark itself as having an invalidated cached
value (whether or not this is always true is dicult to say). An illustration of this
notication can be seen in Figure 4.4.
4.6 Simple JavaScript Agents
Each Symbol comes with methods for `observing' other symbols.
Currently, the
method for watching other symbols relies on the symbol table structure, as symbols
to observe are specied by a name in String form. This decision works ne in an
EDEN style setting, where every observable exists in a symbol table and is looked
up via a string, however it might have been preferable to observe symbols specied
by a direct reference to the symbol.
30
B is notified that it is no longer up to
date
B is A + 1
A
B is defined in terms of A
Spontaneous change in the value of A
A = 2;
Figure 4.4: Illustration of notication of change to a dependent symbol
31
watchA must inform any
observables it was previously
observing that it is no longer
observing them
watchA asks A to
schedule a call to
watchA when A
changes
A
watchA
watchA
remembers that
it is watching A
watchA spontaneously
starts watching A
Figure 4.5: An example of agent observation
It is actually possible for any symbol to observe other symbols, but it only really
makes sense to do so when the observer is some callable value (i.e. some JavaScript
function), because when the observed symbols are changed, a call to the value is
scheduled.
An example of how to do observation:
context.lookup(“watchA”).assign(function() {
alert(“A changed!”);
}).observe([“A”]);
Here, an action is stored under the name `watchA' and is set to trigger whenever
the observable named A changes. The way it does this is by requesting that the A
symbol schedules a call to it whenever its value is changed. Figure 4.5 illustrates the
interaction between the various symbols involved when one symbol is set to observe
another.
The dierence for notifying an observing symbol vs. notifying a dependent symbol is
that the notication to an observer is deferred until all of the dependencies have been
32
JavaScript VM
A call to watchA is scheduled for when
this transition has completed
A
watchA
watchA is observing A
Spontaneous change in the value of A
A = 2;
Figure 4.6: Illustration of scheduling a triggered action through
dealt with.
setTimeout
This is handled using the built in JavaScript function
setTimeout,
which allows you to ask the virtual machine to schedule a call to a given function
after a given timeout (or if no time is given, as soon as it gets a turn). This deferred
notication is illustrated in Figure 4.6.
4.7 Querying State
Each
Symbol
has a method for querying its current state (which is dened in the
shared prototype object). The method is:
Symbol.prototype.value
This method is quite simple - it checks whether the
Symbol
is up to date (each
symbol stores a ag to mark whether they have a faithful cached value), if it is, then
it just returns the cached value, otherwise it triggers a re-evaluation of its denition.
This has subtle but important connotations - if an observable is never inspected, and
it is dened through some formula (as opposed to having a value directly assigned
33
to it), but never has its state queried, it will never have its formula evaluated even if
its formula is dened in terms of symbols that are changing frequently. This should
do well in avoiding evaluating formulas too frequently.
4.8 Mutation of observables
As discussed previously, the trick for maintaining values by dependency is to ensure
that mutation of the managed state happens through an agreed interface. In this
case, each Symbol can be modied using helper methods:
• Symbol.prototype.assign
• Symbol.prototype.mutate
The implementation of these methods noties any dependent symbols, schedules
calls to of an update and removes any attached denition.
4.9 Note about Determining Dependencies Dynamically
Again, some care needs to be taken by the programmer about specication of which
symbols to watch. The approach to improving this situation implemented later is
to use a DSL which, when parsed, establishes the symbols used in the formula and
implicitly sets up subscriptions for you.
However, there is an alternative approach that has not been explored during this
project. Instead of determining dependent symbols at denition time, it could be
possible to have automatic deduction of the symbols to watch for cache invalidation
at denition evaluation time.
In this system, the context passed as the symbol
table would keep track of what symbols were looked up during the evaluation, and
implicitly subscribe the observable to these symbols (and only these symbols) when
the evaluation completed. This would have the benet of allowing the JavaScript
api to do automatic dependency detection, however it may be costly performance
wise, since in this system, whenever the formula is re-evaluated, it has to potentially
resetup dependencies.
34
5
EDEN Translation Scheme
This section attempts to document the various EDEN forms are translated to
JavaScript code while providing similar (unfortunately not always identical) meaning.
The aim is to provide a clearer guide than the code used for generating the
translator (which is basically a formal grammar with semantic actions), by using a
plain English description of the translation rules and examples. As well as illustrating the translation scheme, this section includes potential problems arising from the
translation itself.
5.1 Number, Character and String Data Types
The `primitive' EDEN data types include integers, oating point numbers, characters
and strings.
These were mapped directly to the closest corresponding JavaScript
data type.
JavaScript has less granular primitive types than EDEN. There is no true integer
data type - all numbers are stored using a 64bit oating point representation, though
there are some guarantees on operations that occur on values that t perfectly into
an integer representation[ECMA()].
JavaScript does however still have matching
notations for values with and without a fractional part, so number literals were
translated verbatim.
Further to this, there is no true `character' datatype in JavaScript, there are only
strings.
Strings however are sucient for representing a single character, just by
having a string of length 1, so all character literals are translated to string literals.
5.2 Observables
An observable in EDEN is denoted using letters, underscores and numbers.
A reference to an observable in EDEN source is translated to a call to the lookup
method on the object that eectively represents the EDEN symbol table from the
maintainer library. For example, a simple reference to an observable:
a
Is translated to:
context.lookup(‘a’)
35
How this is then used is dependent on the context in which the observable is in.
Essentially, the result of
context.lookup
(a
Symbol)
models an lvalue in the
EDEN notation. An lvalue is basically a location where something can be stored, and
so supports an assignment operation (for storing data) and also retrieving the data
stored there for use in more complex computations. The result of context.lookup is
Symbol.prototype.value
method (for retrieving the stored value) and Symbol.prototype.assign method
an object that supports these requirements through the
(for updating a stored value).
5.3 Arithmetic, String and Boolean Logic Expressions
EDEN supports a number of expressions for performing computations. Firstly there
are arithmetic expressions which can use various inx or prex operators, but also
there are expressions for comparison between numbers, boolean logic, and string
operations. Fortunately these are all very common within most programming languages, so there were operators in JavaScript that almost directly corresponded to
the EDEN ones. The translation scheme maps each operator to a native JavaScript
one where it can. For example:
a + b;
is translated to:
context.lookup(’a’).value() + context.lookup(’b’).value()
5.4 Dierences Between EDEN and JavaScript's Built In Operators
While these operators all seem close to the EDEN counterparts there are some dierences in their behaviour. Firstly, the addition operator in JavaScript is overloaded
so that it can deal with numbers and strings. In the string case, it performs concatenation of the operands, whereas in EDEN attempting to `add' strings is caught
at run time and reported as an error to the user.
“hello” + “world”;
type clash: number type required (got string)
while executing string near line 1, char 18:
36
To make matters even more confusing, JavaScript's type system allows for implicit
conversions of data types for operands in an expression. In particular, the `addition'
of a number and a string results in a string, where the number operand is coerced
to a string representation before concatenation:
2 + “world”
Another example where a dierence in behaviour is observed is with division.
In
EDEN, the division operator, when applied to integers, computes the result of integer
division of its operands.
However, since in JavaScript there is no dierentiation
between integer types and oating point types - all numbers have a oating point
representation. This means that in cases where the result of division has a remainder,
dierent results are seen from the EDEN expression to the JavaScript expression:
3 / 2 == 1 ## this holds in EDEN
3 / 2 == 1.5 // this holds in JavaScript
5.4.1 Pointers
EDEN supports referring to observables indirectly through what are called pointers.
In a sense pointers are `rst class lvalues', in that they allow some value representation of a location that can be passed around and manipulated.
In EDEN, the & symbol is used prexed to an observable to mean `location of '. Take
this as an example of storing a pointer to one observable in another observable:
x = 2;
ptr_x = &x;
Fortunately, objects created from the Symbol prototype eectively are rst class
lvalues, so we can store references to them in the observable symbol table or any
other lvalue we want:
context.lookup(‘x’).assign(2);
context.lookup(‘ptr_x’).assign(context.lookup(‘x’));
Accessing the location stored is done by using the * symbol prex to a pointer value.
The result of that expression is then a valid lvalue - so can be assigned to or used
to retrieve a value for a computation. E.g.
37
*ptr_x = 2;
y = *ptr_x + 1;
Would be translated to
context.lookup(‘ptr_x’).value().assign(2);
context.lookup(‘y’).assign(context.lookup(‘ptr_x’).value() + 1);
5.5 Lists
An example EDEN list literal:
[1, 2, 3]
Is simply translated to a JavaScript list literal:
[1, 2, 3]
5.5.1 List Indexing
In EDEN, it is possible to index an lvalue to retrieve another lvalue. This can then
be used to update and retrieve sections of EDEN list structures.
An important
property of these derived lvalues is that updates to the data stored for their location
expires their `parent' lvalue. For example:
list1 = [1,2,3];
list2 is list1;
writeln(list2); ## list2 == [1,2,3]
list1[1] = 5;
After the nal statement is executed, list2 needs to be notied that one of the terms
it depends on has changed.
The way this was modelled on the JavaScript side was by creating something that
had the same interface as Symbol, but with slight modications so that it would
update its parent symbol.
context.lookup(’list1’).get(1 - 1)
It was also necessary to adjust for the fact that EDEN uses 1-indexed arrays,
JavaScript uses 0 indexed arrays. This was dealt with by just substituting whatever
was used as the index with - 1.
38
5.5.2 List modication statements
JavaScript lists come with several methods that work well as substitutions for the
various list related statements in EDEN. The Symbol prototype supports a mutate
method - essentially a generalised version of
Symbol.prototype.assign - that
allows an update of a stored value directly using a given modication function.
Consider the following sample which inserts:
insert list, 1, 9000;
This is translated to:
context.lookup(‘x’).mutate(function(s) {
s.cached_value.splice(0, 0, 9000);
});
5.6 Denitions
It was important here to extract what the dependencies for the formula were so that
they could be watched for changes. This was implemented essentially by having a
boolean ag that represented whether the parser was looking at tokens that were in
a denition. Whenever an observable was encountered, the ag was checked to see
whether to make note of the observable (by adding it to a set).
The boolean ag was set to true when an `IS' token was seen by the parser, and set
to false when the the statement terminator was seen. This relied on the particular
parser algorithm used, which reads tokens from left to right, so will always see the
`IS' token before seeing all the observables in the denition.
5.7 Extracting Denitions in EDEN Form for Formula Inspection
In the TkEden environment it is possible to query observables for their formula
using a query statement, for example:
x is y + 20;
?x;
39
The query statement causes the following output:
x is y + 20; /* current value of x is @ */
x ~> []; /* x last changed by input */
So, this caused the need for associating each observable with a string which stored
the denition in EDEN notation. This was simply implemented by guring out the
span of the denition while parsing it, followed by extracting a substring from the
raw text being parsed.
The string was associated with the observable simply by adding a new property to
the Symbol object used to represent it (remembering that objects in JavaScript are
basically just associative arrays that can be extended at any time).
5.8 Functions
Dening a named function with the maintainer library is as simple as dening any
other observable, since functions are values in JavaScript. So some EDEN code like:
func blank { }
Is translated to:
context.lookup(‘blank’).define(function() {
return function() { };
});
Note that the denition actually evaluates to a function value.
This is the value
that will be looked up and called when the function is called.
5.9 Function Arguments
EDEN functions have access to a list of parameters in their body. Any symbol of
the form $N (where N is a number) refers to the Nth argument passed to an EDEN
function. For example, a simple square function can be implemented as follows:
func square { return $1 * $1; }
40
In JavaScript, the arguments keyword refers to a list like structure containing the
arguments passed in a function invocation, so is essentially synonymous to $ in
EDEN. Translating references to $ in EDEN to references to arguments in JavaScript
is a good start:
return arguments[0] * arguments[0];
However, in EDEN it is possible to perform assignment on the arguments list, that
is, $ is in fact an lvalue. Consider the following function:
func test {
$[1] = 1;
writeln(“$[1] = “ // str($[1]));
}
In test, the value of the rst argument is overridden with the number 1, and then
printed. As a testcase:
test(9000);
Running this causes the output $1 = 1, showing that the argument has been
successfully overridden. The implications of this are that we need references to $
to be translated to some Symbol, which is what models an EDEN lvalue in the
JavaScript system. Two steps were made:
1) Every translated function also comes with a line converting the arguments array
to a Symbol so that it could support `assignment' in our system, for example, the
blank function in section 5.8 would be translated to:
context.lookup(’blank’).define(function() {
return function() {
var args = new Symbol(asJavaScriptArray(arguments))
};
})
There is one small thing to notice: The arguments keyword doesn't actually refer
to a full-edged JavaScript array (in that it doesn't support the methods dened
in the Array prototype object). Since the translation scheme relies on EDEN lists
being translated to JavaScript arrays,
Array.prototype
asJavaScriptArray
methods to the arguments structure.
41
is used to add the
2) References to $ are now translated to references to the local variable `args', this
local can then be treated similarly to any other lvalue.
For example, assignment
looks much like it did with assignment to observables:
args.assign(10);
Or in order to assign to a particular position in the arguments:
args.get(0).assign(10);
5.10 Function Argument Aliases
EDEN has a syntactic sugar for referring to function arguments by a name instead of
just by position. These are declared at the start of a function using a para statement,
like so:
func square {
para number;
return number * number;
}
In the current translator, these para statements are not really translated to JavaScript
code. Instead, the parser just makes note of the para aliases at the start of the function, and if it encounters any of those aliases later in the function body, it translates
those references to the corresponding argument position for the alias.
The above
code would be translated to:
context.lookup(‘square’).define(function(context) {
return function() {
return args.value(0) * args.value(0);
};
});
42
5.11 Function Local Variables
EDEN supports `auto' variables which are scoped to within a function denition.
JavaScript also supports declaring function local variables through use of the var
keyword, so a corresponding function local was created in the generated JavaScript
code for each function local. For example:
func sumToN {
para n;
auto i, sum;
sum = 0;
for (i = 1; i < n; i = i + 1) {
sum = sum + i;
}
}
Is translated to:
function() {
var local_i = new Symbol();
for (
local_i.assign(1);
local_i.value() < args.get(0).value();
local_i.assign(local_i.value() + 1)
) {
local_sum.assign(local_sum.value() + 1);
}
}
One nice property of function local variables with this implementation is that they
don't require performing a hashing operation in order to retrieve a location for
storing and retrieving values like regular observables currently do.
This could be
important for making certain types of computations more ecient (e.g. any computations where a single location is updated or read lots of times).
43
5.12 Triggered Actions
Triggered actions are modelled on the JavaScript side in the same way as EDEN
functions, by just dening an observable as some function value that can later be
called. For example:
proc WatchA : A {
writeln(“a changed”);
}
Is translated to:
context.lookup(’WatchA’).define(function(context) {
return function() {
context.lookup("writeln").value()("a changed");
};
}).observe(["a"]);
5.13 Control Flow
This was the most straight forward part of the translator to implement, since the
JavaScript control structures resemble the EDEN ones very closely. The structures
EDEN supports are:
•
If statements
•
Switch statements
•
While loops
•
C style for loops
•
Break/Continue
All these are almost directly transferable to JavaScript. For example, a for loop in
EDEN looks like:
for (i = 1; i <= 10; ++i) { ## code ... }
Would be translated to the following JavaScript:
44
for (
context.lookup(‘i’).assign(1);
context.lookup(‘i’).value() <= 10;
context.lookup(‘i’).assign(context.lookup(‘i’).value() + 1)
) {
// code ...
}
The only dierence is in how the value of
i
is retrieved.
5.14 Verbatim JavaScript Sections
An extension was made to the EDEN syntax which allows for marking sections of
code to be translated to JavaScript with no modications. In order to mark such
a section, the code needs to be surrounded with `${{` and `}}$'. The intention of
this feature was to allow for the creation of agents that updated some state in a
visualisation, e.g. some HTML elements in a page. Take this example of an agent
which alerts:
proc WatchA : A { ${{ alert(“A changed!”) }}$; }
This generates the following JavaScript:
context.lookup(’WatchA’).define(function(context) {
return function() {
alert("A changed!");
};
}).observe(["A"]);
5.15 Methodology for Developing the Translator
The Jison parser generator was used to create the program that translated EDEN
source into JavaScript source. Since Jison itself is written in JavaScript, it was simple
to develop the grammar le in the web browser and interactively test translating
and evaluating examples. The interface used in this process is shown in Figure 5.1.
45
Translator Grammar
Generate Translator
Test Input/Output
Figure 5.1: Screenshot of the grammar testing and development environment
46
Figure 6.1: Prototype JsEden Interface
6
Example Applications
6.1 JsEden Prototype
A prototype interface for what JsEden might look like was developed using a combination of maintainer.js, the EDEN translator and some simple HTML/JavaScript
for the user interface. The nal interface is shown in Figure 6.1.
The features it includes are:
1. An interpreter for EDEN statements
2. Simple error reporting
3. A naive visual symbol table, allowing for in place modication of model state
6.2 General Approach to Developing Visualisations with JsEden
Models
Usually it is desirable to develop some visual representation of what is trying to be
modelled. These can be implemented using triggered actions that update some state
47
in the webpage that JsEden runs in, whenever certain parts of the underlying model
state change. However, before developing a model that uses any sort of visualisation,
some care needs to be taken to ensure that any required preconditions in the state
used for the visualisation have been fullled (for example, initialising some graphics
system, adding some element to an HTML page which will then be drawn within).
In a TkEden model, all the visualisation state is described in a denitive notation.
Of course, not all the state for a DoNaLD picture is explicitly described (things
like the algorithms used to draw lines, all the state of the tcl/tk toolkit used),
however, due to the engineering of TkEden, any `external' state required for the
correct visualisation is guaranteed to be initialised on TkEden starting up.
In the JsEden environment, there is currently no state setup on startup for line
drawings. Furthermore, there is no ability to use the DoNaLD notation to describe
line drawings. However, DoNaLD is not too important as it is simply some sugar
around already understood EDEN statements. This can be veried by using TkEden, which allows for inspection of translated DoNaLD denitions. For example the
following donald code:
line myLine
myLine = [{0, 0}, {100, 100}]
Results in the following EDEN being generated:
_ is [ OPENSHAPE, &_myLine ];
_myLine is line(cart(0, 0), cart(100, 100));
A_myLine = "";
proc P_myLine : _myLine, A_myLine, DoNaLD {
plot_line(DoNaLD, &_myLine, &A_myLine);
}
Here what has happened is that the line `declaration' is essentially a macro which
generates a denition for an agent which is responsible for updating the external
visualisation state.
What we can do in the JsEden environment is to use raw JavaScript to setup what is
needed before constructing a visualisation. Subsection 6.3 demonstrates an example
of doing this by wrapping some JavaScript in EDEN functions, which construct and
manipulate an HTML canvas element (which is for general puprose line drawing).
48
6.3 Example JsEden Model With A Simple Box Visualisation
The following listing shows an EDEN script which uses HTML canvas for drawing a
box. Any changes to the
boxX, boxY, boxW or boxH observables causes an update
in the visualisation. This example is available for testing as a sample in the grammar
development page (along with a few others).
##
## HTML canvas utilities
##
## sets up some necessary "external" state
proc setupCanvas { ${{
$(’body’).append(’<canvas id="c" width="400" height="400"></canvas>’);
}}$; }
proc clearCanvas { ${{
var c = $(’#c’).get(0);
c.width = c.width;
}}$; }
proc drawBox { ${{
var c = $(’#c’).get(0).getContext(’2d’);
c.fillRect(arguments[0], arguments[1], arguments[2], arguments[3]);
}}$; }
setupCanvas();
##
## example agent that draws a box based on some observables
##
proc boxDrawer : boxX,boxY,boxW,boxH {
clearCanvas();
drawBox(boxX, boxY, boxW, boxH);
}
boxX
boxY
boxW
boxH
=
=
=
=
0;
0;
20;
30;
The result is shown in Figure 6.2.
49
Figure 6.2: A simple visualisation using a square
6.4 Embedding Formulas Into an HTML Document
The idea in this example is that a user could enter a formula inlined in some HTML
markup like so:
<formula>x + 1</formula>
And this tag would have its contents replaced with the contents of the given expression. Here was the markup used in this example:
<h1>dependency demo</h1>
<p>the current value of x + 1 is <formula>x + 1</formula></p>
<p>the current value of x + 2 is <formula>x + 2</formula></p>
<p>feel free to modify x here: <input type="text" id="xInput"/></p>
Figure 6.3 shows the resulting webpage.
The way this was implemented was quite simple. Once the page has nished loading,
some JavaScript executes which scans the page for
following for each:
50
formula
tags, and creates the
Figure 6.3: Web page with embedded formulas that reect the maintainer.js state
•
An observable (called
formulaElementN,
where N corresponds to the Nth
formula tag) which is dened using the expression inside (interpreted as EDEN).
•
An agent is created which watches this observable for changes, and propogates
the change to the HTML.
This example can be found in the project source distribution as
51
document-maintainer.html.
7
Pro ject Management
This section gives an overview of when the work required for this project happened,
as well as what approach was taken to managing the work involved. As well as this,
it gives a rough idea of other issues related to getting the project done, such as the
tools used to do so and any external events that might have aected the work.
7.1 Timeline
The MSc Computer Science and Applications course for which this project was carried out for started at the beginning of October 2010. Students are required to select
a supervisor and project by the end of the rst term, as well as submit a specication for their project idea including analysis and background detail. Professor Steve
Russ kindly agreed to supervise for this project.
The way this project has turned out is not very close to the original plans made
during this rst term. The project supervisor has stayed the same, and the overall
eld of modelling with denitive scripts has stayed the same, but the original focus
was on a currently existing tool called Cadence[Pope(2011)].
In some respects the project had similar ideas in mind - Cadence (and the main
denitive notation used to interface with it, DASM) while interesting from both a
modelling perspective and a software development perspective, is currently a little
bit lacking in accessibility as both the complex underlying maintainer and the notation itself are somewhat undocumented through literature and examples. In the end
this is one of the main motivations of JsEden - to create something very accessible
to the user and the developer, via the use of web technologies to allow it to work
across platform with no setup as well as oering a robust development stack.
This is a project that I have had in my head for a while, so it is dicult to document all the time spent towards it.
However, it is denitely true that the bulk
of the work developing the maintainer and the translator happened in a few weeks
during February/May. The report documenting this was written much later, during
July/August/September.
7.2 Methodology
The methodology for the work done for this project was quite straightforward. The
requirements for the project did not really change during the course of it, it was
52
simply a case of attempting to achieve goals in order and assessing while the process
was continuing.
There were a few cases where the maintainer being developed
parallel to the translator would need to be modied to make the translator neater.
Testing was carried out during the development of the parser to attempt to prevent
regressions from occurring, as new features of the EDEN language were implemented, test cases were created for them.
The test cases currently in place have
been documented in section 10.2.
7.3 Other commitments
While working on this project I have also been involved in some part time work
doing software development (also involving JavaScript and rich interfaces).
This
work started in early March and has varied in the amount of time committed per
week - ranging from 3 hours to 30.
As a result of this there has been a section of my time and eort that could not go
to this project, however since all my other modules were completed last year, I feel I
have managed to dedicate a decent time to both projects and have no regrets about
my decision to do both.
7.4 Version Control and Backups
Throughout the project the git version control system was used for managing the
codebase. This is an advanced system for storing snapshots of your codebase which
in git are called commits. This system proved useful in several ways:
•
Easy tracking of current changes to the project by generating a `di ' which
shows all edits/additions/removals from the last stored snapshot.
This was
useful for both guring out what elements had changed when something was
behaving in an unexpected way, and also for remembering what I was doing
the previous day.
•
Reverting the codebase back to a previous snapshot in the case of a problem.
•
A log of all the snapshots including both a di and a message from the author
to describe the changes introduced between that commit and the previous one.
•
Simple (and ecient) synchronization of the codebase including the entire
commit history to remote locations, making for eective backups.
53
•
Branching o from a particular stored state so that it was possible to work on
multiple trains of thought if I wanted to switch between features that would
required large changes to the codebase, as well as semi-automated merging of
codebase states.
7.5 Tools
The toolchain for the software development process was quite simple.
The key
elements of it were:
VIM[Moolenaar(2011)] which is a simple programmer's text editor, available for
various platforms including Windows, GNU/Linux and Mac OSX.
For testing, various browsers were used as there are occasional subtle dierences
in their behaviour (usually in situations where the DOM/JavaScript specication
aren't specic). The browsers tested in were:
•
Google Chrome
•
Safari
•
Firefox
•
Internet Explorer 8
•
Mobile Safari (for iPhone)
Further to this the Firebug extension for Firefox browser was useful during the development process. It is an extension that provides sophisticated debugging facilities
for JavaScript development including an interactive console, inspection of JavaScript
data structures and reporting of JavaScript errors with the ability to jump to the
problematic location in the code. This proved invaluable for both debugging problems and for experimentation with both JsEden and the core maintainer library.
7.6 Libraries
Several JavaScript libraries were used to aid the development of JsEden:
•
jison - http://zaach.github.com/jison/docs/ - a parser generator used to develop the translator for EDEN to JavaScript
54
•
jQuery - http://jquery.com/ - a general purpose DOM manipulation library
used in the UI
•
jQuery UI - http://jqueryui.com/ - a jQuery plugin that adds some common
UI widgets
•
Douglas Crockford's implementation of JSON parsing/serialisation in JavaScript
- http://www.json.org/js.html - for browsers which don't have the JSON object implemented natively
•
jsbeautier - http://jsbeautier.org/ - a script to tidy up JavaScript whitespace/indentation, to format the outputted JavaScript from the translator for
easier inspection
7.7 Legal, social, ethical and professional issues
Generally this project did not touch on many legal, social, ethical and professional
issues.
The main things to consider (for any software product) were related to
licensing of the code written itself and any libraries used in it's development.
The code written by the author includes a copyright notice as well as a notication
that it is all licensed under the MIT Licence[OSI()], which is a very permissive
license in that it only requires a copy of the license is provided with the code or any
derivative work.
The other code used is all library code, all of which are licensed under a permissive
license:
•
jQuery - MIT
•
jQuery UI - MIT
•
jison - MIT
•
Douglas Crockford's json2.js - Public Domain
•
jsbeautier - Public Domain
55
8
Conclusions
8.1 Success of targetting EDEN
The JsEden prototype could be a great asset to the Empirical Modelling community.
The EDEN translator developed to help reuse EM models is reasonably comprehensive but still needs more testing, as well as `builtin' functions being ported over (in
some cases this is just including functions written in EDEN in the JsEden environment). While it oers something similar to WebEden, the architecture is much
simpler and the ability for responsive interactions is far greater.
As for the other tools available for interactive modelling, it potentially oers a clean
break from TkEden which has become stale.
The codebase is large and over the
years has been patched by many people without too much code review to keep it
manageable. This makes it far less accessible for new developers than the JsEden
architecture which only requires a very small amount of code written outside of
denitive scripts.
The following is a small summary of some of the advantages of JsEden over TkEden
and WebEden:
•
JavaScript is more accessible than C (which the TkEden VM is written in), as it
already has high level language features such as automated garbage collection,
resizable data structures and rst class functions. This is particularly relevant
as EDEN is mostly of interest in the University of Warwick department of
computer science - where there is basically no ecosystem for C developers.
•
The JsEden Codebase is (currently) much smaller than the TkEden one. The
JavaScript maintainer is less than 350 source lines of code, the translator is
about 500. The EDEN virtual machine and language interpreter alone are over
10,000 lines of code. While this might not be a particularly accurate measure
of code complexity, the scale of the dierence here should illustrate there is
certainly a signicant delta.
•
Easily extensible by embedding JavaScript code into EDEN code to hook into
rich browser APIs. This means that it is much easier to extend or modify the
tool within the tool itself.
•
Guaranteed to work for a very long time as JavaScript is too widespread to be
deprecated any time soon.
56
•
Simple architecture making it trivial to deploy or migrate. No need for clever
load balancing or authentication beyond dealing with HTTP trac to get the
requisite JavaScript les.
•
Much easier to scale than WebEden, which required an instance of TkEden
somewhere serverside for each instance of WebEden.
•
JIT compilation for denitions, whereas in TkEden, the result of a denition
is computed using the hand written interpreter.
•
Competition in JavaScript engines drives development to improve performance.
Saying this, obviously a lot of work still needs to be done for this platform to act
as a substitute for TkEden, which has had numerous features implemented over the
years.
8.2 Potential outside of EDEN
While the EDEN language provides a great DSL that makes the use of dependency
a lot less error prone, the JavaScript API oers a lot more exibility in what sorts
of things can be connected together. The main problem is that EDEN can't quite
understand everything that exists in the JavaScript world, though this might be
dealt with by making some minor extensions to the EDEN syntax.
JavaScript already has an event based programming model, which allows for easy updates of visualisations in the event of changing data, so the real gains of maintainer.js
would be seen in easier maintenance of program invariants through dependency.
57
9
Further Work
This section documents some ideas for interesting extensions on the work done in
this project.
9.1 More Model Development
In order for a tool to be useful it has to be used. The maintainer is already in a state
where models can be developed interactively, however without constructing larger
scale models it is dicult to assess how successfully it can be applied.
9.2 Implement Cyclic Dependency Checking
Currently maintainer.js does not check for attempts to create cyclic dependencies
between symbols. This can cause an innite loop when expiring a symbol's cached
value. This could be implemented quite simply by adding some code to the symbol
subscription method to check for cycles before commiting the change.
9.3 Possibilities outside the browser
While JavaScript is mostly executed in a browser environment, it is also possible to
execute it in a less strictly controlled environment (mostly this is used for serverside
web programs).
One example of such an environment is called Node.js, which combines Google's
v8 JavaScript engine with libraries for enabling it for general purpose programming
outside of the browser. One benet of running the maintainer via Node.js instead
of a browser based environment is the simplicity of interfacing it with other computer artifacts, for example using its simple Foreign Function Interface (FFI) to
provide action to C apis[Branson()] or by using other inter process communication
like named pipes or sockets.
This could open up possibilities of using more so-
phisticated graphics engines or interacting with other tools or peripherals. Node.js
is targeted at communicating systems which could allow it to shine as a sort of
glue with the ability for maintenance via denitions, not unlike some of the uses
of Cadence.
Another environment for using JavaScript outside of the browser is Rhino, which is
a JavaScript engine that runs on the Java Virtual Machine (JVM). The JVM has
58
recently gained improved support for dynamically typed languages (mostly due to
a rising popularity in the implementation of the Ruby language for the JVM, which
is dynamically typed)[Oracle()]. JavaScript run through Rhino has access to Java
APIs available on the system, so this could open up some interesting possibilities
for interacting with already existing Java programs or user interfaces from triggered
actions.
9.4 Collaborative modelling and interaction with already existing tools
There are possibilities for remote communication between instances of JsEden in either the browser setting or one of the headless settings. The communication methods
available in the browser are:
•
Comet
•
EventSource
•
WebSockets
Sadly all of these models follow a client-server model, where the browser is always
a client.
In other words, there is no possibility for peer to peer communication
between browsers (at least when using JavaScript, it may be possible with Flash
or Java which has more capability to elevate based on user specied permissions).
This means there would always be the requirement for a high bandwidth machine
that has to proxy the communications between browsers.
Things are easier outside of a browser setting, where JavaScript is less limited as the
program is trusted in this environment. Node.js has great support for networking
over TCP or UDP, so could be used along with the JavaScript maintainer to produce
a collaborative modelling environment.
It may also be possible to have collaboration between a JsEden based environment
and already existing modelling tools such as dtkeden (distributed TkEden) or Cadence which already have well dened protocols for distributed formula maintenance.
9.5 Modelling with hierarchical structures
Many programming languages allow for modelling problems using objects, which
are essentially a way of modelling ownership of certain state (as well as sometimes
enforcing where changes to such state can come from).
59
JavaScript already supports object oriented modelling, however the project has
mostly ignored the possibility of using such ownership relationships in the dependency enabled environment.
Notably, this is topical in the Empirical Modelling
community of late due to the more recently developed Cadence tool, which is heavily focused on hierarchical graph structures for its state.
These sorts of structures should also be usable in a way similar to `collections' used
in JavaScript data binding oriented frameworks, which allow for setting triggered
actions that watch for elements being added or removed to the collection. Currently
JsEden (and TkEden) make it dicult to create triggered actions that watch for the
introduction of (or removal of ) new symbols before acting.
This capability could
be particularly useful is for the creation an ecient visualisations of a collection
which can vary in size dynamically. One example of a scenario like this is the visual
symbol table' which shows the denitions for all the observables currently dened.
9.6 Support for other notations
The vast majority of the interesting models developed using TkEden use some kind
of graphical interface. This was generally developed using a separate notation for
graphics, such DoNaLD, SCOUT or the gel notation. While the use of multiple notations might not be the best approach for dealing with multiple concerns available,
the support for these notations would help support the reuse of the EM archive
projects.
In scripts written for TkEden it is possible to switch what notation is being used
using a directive such as:
%donald
It would be quite simple to add support for multiple notations by creating a higher
level translator which dispatches translation o to a separate translator function for
the currently active notation, and switches which translator to dispatch to whenever
a
%donald
style comment is seen.
9.7 Improved JsEden UI
Some more work on the UI could make the modelling process more accessible and
raise the perceived quality of the software. Improved support for code editing - there
60
are a few JavaScript/HTML editors that could be used instead of just an HTML
<textarea>
for code editing. These would allow for syntax highlighting and even
syntax error highlighting. An example of a library that already supports better code
editing is CodeMirror[Haverbeke()].
9.8 Improved Error Reporting for EDEN Code
Currently the error reporting for the EDEN interface to the JavaScript maintainer
is limited to syntax errors, however it is also possible for there to be run time errors
in the JavaScript generated by the EDEN translator. JavaScript will already report
these errors to the browser's error window, but in this form they don't aid the use
of the EDEN environment as much as they might for the following reasons: They
make little sense in the context of EDEN as they actually refer to the generated
JavaScript code. Since the errors occured in dynamically generated and evaluated
code, they have no source attachment to point to.
It may be possible to deal with this by using the attached denitions of functions,
however guring out how line numbers correlate between the generated JavaScript
and the original EDEN source will be challenging.
9.9 Persistency for the developed models in JsEden
The prototype JsEden environment does not store any of the work done between
page loads. There are several useful features that could come from work to implement this:
•
Inspecting history of interactions for educational reasons
•
Collaboration, by transmitting the model to other people
•
Taking breaks from working on a model
•
Returning to a previous model state, possibly storing multiple branches of
models developed from some particular state
In order to persist models, the system could either:
1. Store a snapshot of the current model state
2. Store a history of all the interactions during the model development.
61
Both approaches are interesting and have their own considerations for implementation and use cases.
The rst approach is ideal for restoring a model to a previous state quickly. It does
rely on the current state being completely serialisable to something like a string in
some way, which is ne if the model state is completely representable in terms of
some denitive notation.
The ability for sections of script to be translated verbatim to JavaScript in the
EDEN like language of JsEden introduces problems here, as the model can become
reliant on some `external state' which is not seen as a simple observable in the
JsEden environment. It is quite easy for this to happen when dealing with function
values which rely on some state which is in their closure (this is a common idiom
for encapsulating state for event callbacks in JavaScript) but not accessible as an
observable. Another possibility is that some JavaScript code relies on the state of
the HTML page which it has access to. This sort of situation makes it impossible
to take a faithful `snapshot' of the model, as there is no way to enumerate all of this
state.
The second approach is necessary if users wish to gain insight into the interactions
performed in the model development, but really it is impossible to capture all
interactions - trying to capture all interactions (which potentially includes all mouse
interaction) would be unreasonable, so it would be limited to capturing interactions
through the EDEN interface. This would mean that in order to restore a model, it
really is necessary to be able to enumerate all the model state as observables.
It is also important to consider where exactly information about model development
should be stored. The possible solutions are:
1. Store everything locally using new HTML5 APIs
2. Store things on a remote machine by using POST or REST requests to some
server side app
Option 1 has the benet of requiring no server side application in order to implement persisting developed models. It also allows the user to do model development
without the need for an Internet connection. The local storage APIs introduced in
HTML5 are reported to work in most modern browsers [Grove()], and due to the
introspective nature of JavaScript, it is possible to do feature detection and fall back
on some 3rd party system for persisting data on the client side (for example Google
Gears[Google()]).
62
As for Option 2, one good example of how to do this is jsddle.net.
This is a system that allows you to develop web applications within the browser,
and store them persistently on their servers. You are they given a url which you
can use to return to that particular version of the webapp. The format is always
http://jsddle.net/<unique-id>/<revision-id>
63
10
Appendices
10.1 Build Instructions
HTML/JavaScript applications generally only need a JavaScript enabled browser
in order to run.
The architecture for the JsEden environment is currently quite
simplistic, and in order to host your own instance of it, all that is required is to
extract the source distribution and open eden.html in a browser. Making it public
is simply a case of putting it somewhere being served up by a webserver.
If you're using a machine in the department of computer science at Warwick University, you can run (this will also work on most GNU/Linux or OSX machines):
curl "http://trmonks.me.uk/gitw/?p=js-dependency.git;a=snapshot;h=refs/heads/\
master;sf=tgz" | tar xzvf
The grammar development and testing environment is test.html, the prototype
JsEden interface is eden.html.
10.2 Test Cases
Some testcases were created for the translator during it's development. The tests
are all in js/tests.js in the JsEden distribution, here is a summary of what is tested
for currently:
1. Lookup results in a symbol
2. Assignment sets the correct value
3. Increment results in a value 1 greater
4. += op works
5. The value after formula denition is correct
6. Function denition stores a function in the symbol table
7. Procedure denition stores a function in the symbol table
8. Triggered action denition stores a function in the symbol table
9. Triggered action denition observes a requested symbol
10. Function calls work Return statement from a function works
64
11. Function parameters work
12. Parameter aliases work
13. Nested strings work
14. Multiline strings work
15. Multiple function denitions with locals works
16. Underscores in observable names works
17. Autos work in a function denition
18. Autos work in a procedure denition
19. Autos protect the outside scope
20. Single quoting a character works
21. Empty quotes won't parse
22. Single quoting an escaped quote character works
23. Lists are 1 indexed
24. .get(i) returns an accessor with index i
25. .get() returns an lvalue
10.3 Glossary of Technical Terms
Closure - The closure of a function is the set of all things in its scope.
XML - A standardised markup for representing arbitrary data, along with some
schema.
JSON - JavaScript Object Notation.
This is a simple string representation of
JavaScript objects for communication.
DOM - Document Object Model.
This is a JavaScript object representation of
HTML documents to allow for simple manipulation (without parsing HTML)
DSL - Domain Specic Language
EDSL - Embedded Domain Specic Language. This usually refers to a system of
values in an already existing programming language that resemble a DSL, often with
help from the type system to enforce language rules.
VM - Virtual Machine
65
References
[Ashkenas(2011)] Jeremy Ashkenas.
URL
The coeescript project page, August 2011.
http://jashkenas.github.com/coffee-script/.
[Beynon(2006)] Meurig Beynon. Syntax summary for eden, November 2006. URL
http://www2.warwick.ac.uk/fac/sci/dcs/research/em/software/eden
/langref/summary/.
[Branson()] Rick
Branson.
A
node
tutorial.
URL
https://github.com/rbranson/node-ffi/wiki/Node-FFI-Tutorial.
[ECMA()] ECMA.
The
ecmascript
language
specication.
URL
http://www.ecma-international.org/publications
/files/ECMA-ST/Ecma-262.pdf.
[Google()] Google.
The
google
gears
project
page.
URL
http://gears.google.com/.
[Google(2000)] Google.
The
v8
project
page,
January
2000.
URL
http://code.google.com/p/v8/.
[Grove()] Ryan
client-side
Grove.
Yahoo!
storage
to
improve
search
user
pad:
Using
experience.
URL
http://wonko.com/post/search-pad-browser-storage.
[Haverbeke()] Marijn
Haverbeke.
The
codemirror
project
page.
URL
http://codemirror.net/.
[Moolenaar(2011)] Bram Moolenaar.
The vim project page, April 2011.
URL
http://www.vim.org/.
[Oracle()] Oracle.
TM platform.
java
Jsr
292,
URL
supporting
dynamically
typed
languages
on
the
http://jcp.org/en/jsr/detail?id=292.
[OSI()] OSI. The mit software license. URL
[Pope(2011)] Nicholas Pope.
http://www.vim.org/.
The cadence project page,
August 2011.
URL
http://www2.warwick.ac.uk/fac/sci/dcs/research/em/software/cadence/.
66
Download