Franck Pommereau

first HTMLL simulator

......@@ -3,7 +3,7 @@
import sys, os
from distutils.core import setup
def doc_files() :
def doc_files () :
import os, os.path
result = {}
for root, dirs, files in os.walk("doc") :
......@@ -15,6 +15,15 @@ def doc_files() :
result[target_dir].append(os.path.join(root, name))
return list(result.items())
def abcd_resources () :
collected = ["*.txt", "*.html", "*.css", "*.js", "*.png", "*.jpg"]
import glob, os.path
result = []
for pattern in collected :
for path in glob.glob("snakes/utils/abcd/resources/" + pattern) :
result.append(os.path.join("resources", os.path.basename(path)))
return result
try :
long_description=open("README").read()
except :
......@@ -56,5 +65,6 @@ if __name__ == "__main__" :
"snakes.utils.abcd",
"snakes.utils.ctlstar",
],
package_data={"snakes.utils.abcd": abcd_resources()},
data_files=doc_files() + emacs,
)
......
......@@ -906,15 +906,11 @@ class Expression (ArcAnnotation) :
return Token(True)
else :
env = binding._dict
# just to allow a cleaner implementation of let
env["__binding__"] = env
env["__globals__"] = self.globals
env["__binding__"] = binding._dict
try :
return Token(self.globals(self._expr, env))
finally :
# cleanup what was added above
del env["__binding__"]
del env["__globals__"]
def __call__ (self, binding) :
"""Returns the value from `bind` (but not encapsulated in a
`Token`).
......
......@@ -47,7 +47,7 @@ False
automatically loaded)
"""
import os, os.path, subprocess, collections
import os, os.path, subprocess, collections, codecs
import snakes.plugins
from snakes.plugins.clusters import Cluster
from snakes.compat import *
......@@ -78,7 +78,7 @@ class Graph (Cluster) :
else :
tag = "%s " % tag
return (["%s[" % tag,
["%s=%s" % (key, self.escape(str(val)))
["%s=%s" % (key, self.escape(unicode(val)))
for key, val in attr.items()],
"];"])
def _dot (self) :
......@@ -97,7 +97,7 @@ class Graph (Cluster) :
return lines
def _dot_text (self, lines, indent=0) :
for l in lines :
if isinstance(l, str) :
if isinstance(l, (str, unicode)) :
yield " "*indent*2 + l
else :
for x in self._dot_text(l, indent+1) :
......@@ -105,6 +105,7 @@ class Graph (Cluster) :
def dot (self) :
self.done = set()
return "\n".join(self._dot_text(["digraph {",
'charset="UTF-8"',
['node [label="N",'
' fillcolor="#FFFFFF",'
' fontcolor="#000000",'
......@@ -115,13 +116,15 @@ class Graph (Cluster) :
self._dot(),
"}"]))
def escape (self, text) :
return '"%s"' % text.replace('"', r'\"')
if text.startswith("<") and text.endswith(">") :
return text
else :
return '"%s"' % text.replace('"', r'\"')
def render (self, filename, engine="dot", debug=False) :
if engine not in ("dot", "neato", "twopi", "circo", "fdp") :
raise ValueError("unknown GraphViz engine %r" % engine)
outfile = open(filename + ".dot", "w")
outfile.write(self.dot())
outfile.close()
with codecs.open(filename + ".dot", "w", "utf-8") as outfile :
outfile.write(self.dot())
if debug :
dot = subprocess.Popen([engine, "-T" + filename.rsplit(".", 1)[-1],
"-o" + filename, outfile.name],
......@@ -226,11 +229,10 @@ def extend (module) :
self._copy_edges(nodemap, g, arc_attr)
if graph_attr :
graph_attr(self, g.attr)
if filename is None :
g.nodemap = nodemap
return g
else :
if filename is not None :
g.render(filename, engine, debug)
g.nodemap = nodemap
return g
def _copy (self, nodemap, sub, cluster_attr, place_attr, trans_attr) :
attr = dict(style="invis")
if cluster_attr :
......@@ -249,6 +251,8 @@ def extend (module) :
label="%s\\n%s" % (node.name, str(node.guard)))
if trans_attr :
trans_attr(node, attr)
attr["tooltip"] = node.name
attr["id"] = nodemap[name]
graph.add_node(nodemap[name], attr)
for child in sub.children() :
graph.add_child(self._copy(nodemap, child, cluster_attr,
......
......@@ -67,9 +67,11 @@ def unlet (expr, *names) :
return unparse(new), drop.calls
class MakeLet (object) :
def __init__ (self, globals) :
self.globals = globals
def match (self, match, binding) :
env = dict(binding)
env.update(env["__globals__"])
env.update(iter(self.globals))
exec("", env)
old = set(env)
exec(match, env)
......@@ -93,5 +95,5 @@ def extend (module) :
class PetriNet (module.PetriNet) :
def __init__ (self, name, **args) :
module.PetriNet.__init__(self, name, **args)
self.globals["let"] = MakeLet()
self.globals["let"] = MakeLet(self.globals)
return PetriNet, unlet
......
......@@ -272,9 +272,6 @@ def extend (module) :
else :
guard = guard & snk.Expression("newpids(%s)"
% ", ".join(assign))
for pid in self.pids.killed :
pidcount = vars.fresh(add=True, base="next_%s" % pid)
self.pids.next[pid] = pidcount
snk.Transition.__init__(self, name, guard, **args)
def vars (self) :
return self.pids.vars() | snk.Transition.vars(self)
......@@ -306,10 +303,6 @@ def extend (module) :
prod[child] = snk.Tuple([snk.Variable(child),
snk.Value(0)])
for pid in trans.pids.killed :
if pid not in trans.pids.spawned :
pidcount = trans.pids.next[pid]
cons[pid] = snk.Tuple([snk.Variable(pid),
snk.Variable(pidcount)])
prod.pop(pid, None)
if len(cons) > 1 :
self.add_input(self.nextpids, trans.name,
......@@ -320,7 +313,7 @@ def extend (module) :
if len(prod) > 1 :
self.add_output(self.nextpids, trans.name,
snk.MultiArc(prod.values()))
elif len(prod) == 1 :
elif len(cons) == 1 :
self.add_output(self.nextpids, trans.name,
iter(prod.values()).next())
return PetriNet, Transition, Pid, ("tPid", tPid), ("tNextPid", tNextPid)
......
......@@ -432,7 +432,24 @@ class Builder (object) :
self.instances.add(name)
path = self.path + [name]
builder = self.__class__(self.snk, path, self)
return builder.build(spec)
net = builder.build(spec)
src = (node.st.source(),
node.st.srow, node.st.scol,
node.st.erow, node.st.ecol)
for trans in net.transition() :
try :
lbl = trans.label("instances")
trans.label(instances=[src] + lbl)
except KeyError :
trans.label(instances=[src])
for place in net.place() :
if place.status == self.snk.Status(None) :
try :
lbl = place.label("instances")
place.label(instances=[src] + lbl)
except KeyError :
place.label(instances=[src])
return net
# control flow operations
def build_Sequence (self, node) :
return self.snk.PetriNet.__and__
......
This diff is collapsed. Click to expand it.
import sys, optparse, os.path
import sys, optparse, os.path, webbrowser
import pdb, traceback
import snakes.plugins
from snakes.utils.abcd.build import Builder
......@@ -7,6 +7,7 @@ from snakes.lang.pgen import ParseError
from snakes.utils.abcd import CompilationError, DeclarationError
from snakes.utils.abcd.simul import Simulator
from snakes.utils.abcd.checker import Checker
from snakes.utils.abcd.html import build as html
##
## error messages
......@@ -21,10 +22,16 @@ ERR_COMPILE = 6
ERR_OUTPUT = 7
ERR_BUG = 255
def log (message) :
sys.stdout.write("abcd: %s\n" % message.strip())
sys.stdout.flush()
def err (message) :
sys.stderr.write("abcd: %s\n" % message.strip())
sys.stderr.flush()
def die (code, message=None) :
global options
if message :
err(message)
if options.debug :
......@@ -33,6 +40,7 @@ def die (code, message=None) :
sys.exit(code)
def bug () :
global options
sys.stderr.write("""
********************************************************************
*** An unexpected error ocurred. Please report this bug to ***
......@@ -79,12 +87,19 @@ opt.add_option("--debug",
opt.add_option("-s", "--simul",
dest="simul", action="store_true", default=False,
help="launch interactive code simulator")
opt.add_option("--headless",
dest="headless", action="store_true", default=False,
help="headless code simulator (don't start browser)")
opt.add_option("-H", "--html",
dest="html", action="store", default=None,
help="save net as HTML",
metavar="OUTFILE")
opt.add_option("--check",
dest="check", action="store_true", default=False,
help="check assertions")
def getopts (args) :
global options, abcd
global options, abcd, tmp
(options, args) = opt.parse_args(args)
plugins = []
for p in options.plugins :
......@@ -98,6 +113,8 @@ def getopts (args) :
if gvopt and "gv" not in plugins :
plugins.append("gv")
break
if (options.html or options.simul) and "gv" not in plugins :
plugins.append("gv")
options.plugins = plugins
if len(args) < 1 :
err("no input file provided")
......@@ -112,6 +129,10 @@ def getopts (args) :
err("input file also used as output (--pnml)")
opt.print_help()
die(ERR_ARG)
if options.html == abcd :
err("input file also used as output (--html)")
opt.print_help()
die(ERR_ARG)
for engine in gv_engines :
if getattr(options, "gv%s" % engine) == abcd :
err("input file also used as output (--%s)" % engine)
......@@ -129,7 +150,7 @@ def place_attr (place, attr) :
elif place.status == snk.internal :
pass
elif place.status == snk.exit :
attr["fillcolor"] = "yellow"
attr["fillcolor"] = "orange"
else :
attr["fillcolor"] = "lightblue"
# fix shape
......@@ -142,9 +163,9 @@ def place_attr (place, attr) :
if count == 0 :
marking = " "
elif count == 1 :
marking = "@"
marking = "&#8226;"
else :
marking = "%s@" % count
marking = "%s&#8226;" % count
else :
marking = str(place.tokens)
# node label
......@@ -167,12 +188,13 @@ def arc_attr (label, attr) :
attr["arrowhead"] = "box"
attr["label"] = " %s " % label._annotation
def draw (net, engine, target) :
def draw (net, target, engine="dot") :
try :
net.draw(target, engine=engine,
place_attr=place_attr,
trans_attr=trans_attr,
arc_attr=arc_attr)
return net.draw(target, engine=engine,
place_attr=place_attr,
trans_attr=trans_attr,
arc_attr=arc_attr)
except :
die(ERR_OUTPUT, str(sys.exc_info()[1]))
......@@ -193,7 +215,7 @@ def save_pnml (net, target) :
##
def main (args=sys.argv[1:], src=None) :
global snk
global options, snk
# get options
try:
if src is None :
......@@ -232,7 +254,7 @@ def main (args=sys.argv[1:], src=None) :
build = Builder(snk)
try :
net = build.build(node)
net.label(srcfile=abcd)
net.label(srcfile=abcd, snakes=snk)
except (CompilationError, DeclarationError) :
die(ERR_COMPILE, str(sys.exc_info()[1]))
except :
......@@ -243,12 +265,24 @@ def main (args=sys.argv[1:], src=None) :
for engine in gv_engines :
target = getattr(options, "gv%s" % engine)
if target :
draw(net, engine, target)
draw(net, target, engine)
if options.html :
try :
html(abcd, node, net, draw(net, None), options.html)
except :
bug()
trace, lineno = [], None
if options.check :
lineno, trace = Checker(net).run()
if options.simul :
Simulator(snk, source, net, trace, lineno).run()
try :
simul = Simulator(abcd, node, net, draw(net, None))
except :
bug()
simul.start()
if not options.headless :
webbrowser.open(simul.url)
simul.wait()
elif trace :
if lineno is None :
print("unsafe execution:")
......
<div class="about">
<p><span class="title">ABCD simulator is part of the SNAKES
toolkit</span><br/> (C) 2014 Franck Pommereau</p>
<p><a href="http://www.ibisc.univ-evry.fr/~fpommereau/SNAKES"
target="_blank">SNAKES homepage</a></p>
</div>
This diff is collapsed. Click to expand it.
import snakes
from snakes.utils.simul.httpd import *
from snakes.utils.simul.html import H
import multiprocessing, time, sys, json, os.path, signal, inspect, glob
import operator
class StateSpace (dict) :
def __init__ (self, net) :
self.net = net
self.current = self.add(net.get_marking())
def get (self) :
return self[self.current]
def add (self, marking) :
if marking in self :
return self[marking].num
else :
marking.num = len(self) / 2
self[marking] = self[marking.num] = marking
self.setmodes(marking.num)
return marking.num
def setmodes (self, state) :
marking = self[state]
self.net.set_marking(marking)
marking.modes = []
for trans in self.net.transition() :
for mode in trans.modes() :
marking.modes.append((trans, mode))
def succ (self, state, mode) :
marking = self[state]
trans, binding = marking.modes[mode]
self.net.set_marking(marking)
trans.fire(binding)
self.current = self.add(self.net.get_marking())
return self.current
def modes (self, state) :
return self[state].modes
def log (message) :
sys.stderr.write("[simulator] %s\n" % message.strip())
sys.stderr.flush()
shutdown = multiprocessing.Event()
ping = multiprocessing.Event()
class Server (multiprocessing.Process) :
def __init__ (self, httpd) :
multiprocessing.Process.__init__(self)
self.httpd = httpd
def run (self) :
try :
self.httpd.serve_forever()
except KeyboardInterrupt :
pass
finally :
shutdown.set()
class WatchDog (multiprocessing.Process) :
def __init__ (self, timeout=30) :
multiprocessing.Process.__init__(self)
self.timeout = timeout
def run (self) :
try :
while True :
if ping.wait(self.timeout) :
ping.clear()
else :
log("client not active - %s\n"
% time.strftime("%d/%b/%Y %H:%M:%S"))
break
except KeyboardInterrupt :
pass
finally :
shutdown.set()
class BaseHTTPSimulator (Node) :
def __init__ (self, net, port=8000, resources=[]) :
self.res = {}
for cls in reversed(inspect.getmro(self.__class__)[:-2]) :
path = os.path.dirname(inspect.getsourcefile(cls))
for pattern in resources + ["resources/*.js",
"resources/*.css",
"resources/*.html",
"resources/alive.txt"] :
for res in glob.glob(os.path.join(path, pattern)) :
with open(res) as infile :
self.res[os.path.basename(res)] = infile.read()
Node.__init__(self, r=ResourceNode(self.res))
# create HTTP server
self.port = port
while True :
try :
httpd = HTTPServer(('', self.port), self)
except Exception as err :
self.port += 1
else :
break
self.server = Server(httpd)
self.watchdog = WatchDog()
# init data
self.url = "http://127.0.0.1:%s/%s/" % (port, httpd.key)
self._alive = self.res["alive.txt"].splitlines()
self._ping = 0
self.states = StateSpace(net)
def start (self) :
log("starting at %r" % self.url)
shutdown.clear()
ping.clear()
self.server.start()
self.watchdog.start()
def wait (self) :
try :
shutdown.wait()
log("preparing to shut down...")
time.sleep(2)
except KeyboardInterrupt :
shutdown.set()
log("shuting down...")
sig = getattr(signal, "CTRL_C_EVENT",
getattr(signal, "SIGTERM", None))
if sig is not None :
if self.server.pid :
os.kill(self.server.pid, sig)
if self.watchdog.pid :
os.kill(self.watchdog.pid, sig)
log("bye!")
def getstate (self, state) :
marking = self.states[state]
places = ["%s = %s" % (H.span(place.name, class_="place"),
H.span(marking(place.name), class_="token"))
for place in sorted(self.states.net.place(),
key=operator.attrgetter("name"))]
modes = ["%s : %s" % (H.span(trans.name, class_="trans"),
H.span(binding, class_="binding"))
for trans, binding in marking.modes]
return {"id" : state,
"states" : [{"do" : "sethtml",
"select" : "#net",
"html" : H.i(self.states.net)},
{"do" : "settext",
"select" : "#state",
"text" : state},
{"do" : "setlist",
"select" : "#marking",
"items" : places},
],
"modes" : [{"select" : "#modes",
"items" : modes},
],
}
def init_index (self) :
return {"res" : "%s/r" % self.url,
"url" : self.url,
"key" : self.server.httpd.key,
"host" : "127.0.0.1",
"port" : self.port,
"about" : self.init_about(),
"model" : self.init_model()}
def init_model (self) :
return self.res["model.html"]
def init_about (self) :
return self.res["about.html"]
@http("text/html")
def __call__ (self) :
return self.res["index.html"] % self.init_index()
def init_ui (self) :
argv = H.code(" ".join(sys.argv))
version = (H.ul(H.li(H.b("Python: "),
H.br.join(sys.version.splitlines())),
H.li(H.b("SNAKES: "), snakes.version)))
return [{"label" : "Versions",
"id" : "ui-version",
"href" : "#",
"script" : "dialog(%r)" % version},
{"label" : "Argv",
"id" : "ui-argv",
"href" : "#",
"script" : "dialog(%r)" % argv}]
def init_help (self) :
return {"#trace": "the states and transitions explored so far",
"#model" : "the model being simulated",
"#alive .ui #ui-quit" : "stop the simulator (server side)",
"#alive .ui #ui-help" : "show this help",
"#alive .ui #ui-about" : "show information about the simulator"}
@http("application/json", state=int)
def init (self, state=-1) :
if state < 0 :
state = self.states.current
return {"ui" : self.init_ui(),
"state" : self.getstate(state),
"help" : self.init_help()}
@http("application/json", state=int, mode=int)
def succ (self, state, mode) :
state = self.states.succ(state, mode)
return self.getstate(state)
@http("text/plain")
def ping (self) :
ping.set()
alive = self._alive[self._ping % len(self._alive)]
self._ping += 1
return alive
@http("text/plain")
def quit (self) :
shutdown.set()
return "Bye!"
if __name__ == "__main__" :
import snakes.nets, webbrowser
net = snakes.nets.loads(sys.argv[1])
simul = BaseHTTPSimulator(net)
simul.start()
webbrowser.open(simul.url)
simul.wait()
import functools
import json as JSON
def _tag (name) :
return name.lower().strip("_")
class Tag (object) :
default = {"a" : {"href" : "#"}}
noclose = set([None, "br"])
def __init__ (self, name, *children, **attr) :
if name is not None :
self.name = name.lower()
else :
self.name = None
self.attr = dict(self._cleanup(attr))
self.children = list(children)
def _cleanup (self, attr) :
for key, value in attr.items() :
yield _tag(key), value
def __call__ (self, *children, **attr) :
self.children.extend(children)
self.attr.update(self._cleanup(attr))
return self
def add (self, *children) :
self.children.extend(children)
return self
def join (self, children) :
if self.name not in self.noclose :
raise ValueError("cannot join with tag %r" % self.name)
lst = [children[0]]
for c in children[1:] :
lst.extend([self, c])
return self.__class__(None, *lst)
def __setitem__ (self, key, value) :
self(**{_tag(key): value})
def __delitem__ (self, key) :
self.attr.pop(_tag(key), None)
def __contains__ (self, key) :
return _tag(key) in self.attr
def __str__ (self) :
attr = self.attr.copy()
for key, value in self.default.get(self.name, {}).items() :
if key not in attr :
attr[key] = value
if self.name is None :
return "".join(str(c) for c in self.children)
elif attr :
ret = "<%s %s>%s" % (
self.name,
" ".join("%s=%r" % a for a in attr.items()),
"".join(str(c) for c in self.children))
else :
ret = "<%s>%s" % (
self.name,
"".join(str(c) for c in self.children))
if self.children or self.name not in self.noclose :
return ret + "</%s>" % self.name
else :
return ret[:-1] + "/>"
def __repr__ (self) :
return repr(str(self))
class Factory (object) :
def __getattr__ (self, name) :
return Tag(_tag(name))
H = Factory()
class JSONEncoder(JSON.JSONEncoder):
def default(self, obj):
if isinstance(obj, Tag):
return str(obj)
else :
return JSON.JSONEncoder.default(self, obj)
json = JSONEncoder().encode
import sys, os.path, httplib, cgi, urlparse, functools, mimetypes
import os, signal, traceback, random, base64, inspect
import BaseHTTPServer
from snakes.utils.simul.html import json
##
##
##
class HTTPError (Exception) :
def __init__ (self, code, reason=None, debug=None, headers={}) :
self.answer = httplib.responses[code]
if reason is None :
message = self.answer
else :
message = "%s (%s)" % (self.answer, reason)
Exception.__init__(self, message)
self.code = code
self.reason = reason
self.debug = debug
self.headers = headers
##
##
##
encoders = {"application/json" : json,
"text/plain" : str,
"text/html" : str,
}
def http (content_type=None, **types) :
def decorator (method) :
@functools.wraps(method)
def wrapper (*larg, **karg) :
try :
args = inspect.getcallargs(method, *larg, **karg)
for a, t in types.items() :
if a in args :
args[a] = t(args[a])
except :
raise HTTPError(httplib.BAD_REQUEST, "invalid arguments")
try :
if content_type is None :
return method(**args)
else :
encode = encoders.get(content_type, str)
return content_type, encode(method(**args))
except HTTPError :
raise
except :
raise HTTPError(httplib.INTERNAL_SERVER_ERROR,
debug=sys.exc_info())
return wrapper
return decorator
class Node (object) :
def __init__ (self, **children) :
for child, node in children.items() :
setattr(self, child, node)
def __getitem__ (self, path) :
path = path.strip("/")
if "/" in path :
head, tail = path.split("/", 1)
child = getattr(self, head, None)
if isinstance(child, Node) :
return child[tail]
else :
raise KeyError(tail)
elif path == "" and hasattr(self, "__call__") :
return self.__call__
elif hasattr(self, path) :
return getattr(self, path)
else :
raise KeyError(path)
class DirNode (Node) :
def __init__ (self, path) :
self.root = os.path.realpath(path)
def __getitem__ (self, path) :
path = os.path.join(self.root, path.lstrip("./"))
if not os.path.isfile(path) :
raise HTTPError(httplib.NOT_FOUND)
ct = mimetypes.guess_type(path)[0] or "application/octet-stream"
@http(ct)
def handler () :
return open(path).read()
return handler
class ResourceNode (Node) :
def __init__ (self, data) :
self.data = data
self.ct = dict((path, mimetypes.guess_type(path)[0]
or "application/octet-stream")
for path in self.data)
def __getitem__ (self, path) :
if path in self.data :
@http(self.ct[path])
def handler () :
return self.data[path]
return handler
else :
raise HTTPError(httplib.NOT_FOUND)
##
##
##
class HTTPRequestHandler (BaseHTTPServer.BaseHTTPRequestHandler) :
def do_GET (self) :
try :
try :
url = urlparse.urlparse(self.path)
except :
raise HTTPError(httplib.BAD_REQUEST, "invalid URL")
try :
handler = self.server[url.path]
except KeyError :
raise HTTPError(httplib.NOT_FOUND)
try :
query = dict(cgi.parse_qsl(url.query))
# jQuery may add _ in query for cache control, let's drop it
query.pop("_", None)
except :
raise HTTPError(httplib.BAD_REQUEST, "invalid query")
content_type, data = handler(**query)
self.send_response(httplib.OK)
self.send_header("Content-type", content_type)
self.send_header("Content-length", len(data))
self.end_headers()
self.wfile.write(data)
except HTTPError :
c, v, t = sys.exc_info()
self.send_response(v.code)
self.send_header("Content-type", "text/html")
for hname, hdata in v.headers.iteritems() :
self.send_header(hname, hdata)
self.end_headers()
self.wfile.write("<html><title>%s</title></head>"
"<body><p>%s</p></body>" % (v.answer, v.message))
if v.code == 500 :
traceback.print_exception(*v.debug)
class HTTPServer (BaseHTTPServer.HTTPServer):
def __init__ (self, server_address, root):
BaseHTTPServer.HTTPServer.__init__(self, server_address,
HTTPRequestHandler)
self.root = root
self.key = "".join(base64.b64encode(
"".join(chr(random.getrandbits(8)) for i in range(15)),
"-_").split())
def __getitem__ (self, path) :
try :
key, path = path.lstrip("/").split("/", 1)
except :
raise HTTPError(httplib.FORBIDDEN)
if key != self.key :
raise HTTPError(httplib.FORBIDDEN)
return self.root[path]
##
##
##
if __name__ == '__main__':
class HelloNode (Node) :
@http("text/plain")
def hello (self, first, last) :
return "Hello %s %s!" % (first.capitalize(), last.capitalize())
try :
httpd = HTTPServer(('', 1234), HelloNode(r=DirNode(".")))
httpd.serve_forever()
except KeyboardInterrupt :
print "\rGoobye"
<div class="about">
<div class="title">SNAKES simulator toolkit</div>
<div class="subtitle">(C) 2014 Franck Pommereau</div>
<p><a href="http://www.ibisc.univ-evry.fr/~fpommereau/SNAKES"
target="_blank">SNAKES homepage</a></p>
</div>
Well, you can tell by the way I use my walk,
I'm a woman's man: no time to talk.
Music loud and women warm, I've been kicked around
Since I was born.
And now it's all right. it's ok.
And you may look the other way.
We can try to understand
The new york times effect on man.
Whether you're a brother or whether you're a mother,
You're stayin alive, stayin alive.
Feel the city breakin and everybody shakin,
And were stayin alive, stayin alive.
Ah, ha, ha, ha, stayin alive, stayin alive.
Ah, ha, ha, ha, stayin alive.
Well now, I get low and I get high,
And if I can't get either, I really try.
Got the wings of heaven on my shoes.
I'm a dancin man and I just can't lose.
You know it's all right.its ok.
I'll live to see another day.
We can try to understand
The new york times effect on man.
Whether you're a brother or whether you're a mother,
You're stayin alive, stayin alive.
Feel the city breakin and everybody shakin,
And were stayin alive, stayin alive.
Ah, ha, ha, ha, stayin alive, stayin alive.
Ah, ha, ha, ha, stayin alive.
Life goin nowhere.somebody help me.
Somebody help me, yeah.
Life goin nowhere.somebody help me.
Somebody help me, yeah. stayin alive.
Well, you can tell by the way I use my walk,
I'm a woman's man: no time to talk.
Music loud and women warm,
I've been kicked around since I was born.
And now it's all right. it's ok.
And you may look the other way.
We can try to understand
The new york times effect on man.
Whether you're a brother or whether you're a mother,
You're stayin alive, stayin alive.
Feel the city breakin and everybody shakin,
And were stayin alive, stayin alive.
Ah, ha, ha, ha, stayin alive, stayin alive.
Ah, ha, ha, ha, stayin alive.
Life goin nowhere.somebody help me.
Somebody help me, yeah.
Life goin nowhere.somebody help me, yeah.
I'm stayin alive.
<html>
<head>
<script type="text/javascript">
var server = {key : "%(key)s",
url : "%(url)s",
host : "%(host)s",
port : "%(port)s"};
</script>
<script type="text/javascript" src="r/jquery.min.js"></script>
<script type="text/javascript" src="r/jquery.periodic.js"></script>
<script type="text/javascript" src="r/simulator.js"></script>
<link type="text/css" href="r/simulator.css" rel="stylesheet"/>
<link type="text/css" href="r/model.css" rel="stylesheet"/>
<link type="text/css" href="r/trace.css" rel="stylesheet"/>
<link type="text/css" href="r/about.css" rel="stylesheet"/>
</head>
<body>
<div id="alive">
<ul class="ui">
<li><a id="ui-reset" href="#">Reset simulation</a></li>
<li><a id="ui-quit" href="#">Stop server</a></li>
<li><a id="ui-help" href="#">Help</a></li>
<li><a id="ui-about" href="#">About</a></li>
</ul>
<span class="ping">Starting...</span>
</div>
<div id="model">%(model)s</div>
<div id="trace"></div>
<div id="about">%(about)s</div>
</body>
</html>
This diff is collapsed. Click to expand it.
/*!
* jQuery periodic plugin
*
* Copyright 2010, Tom Anderson
* Dual licensed under the MIT or GPL Version 2 licenses.
*
*/
jQuery.periodic = function (options, callback) {
// if the first argument is a function then assume the options aren't being passed
if (jQuery.isFunction(options)) {
callback = options;
options = {};
}
// Merge passed settings with default values
var settings = jQuery.extend({}, jQuery.periodic.defaults, {
ajax_complete : ajaxComplete,
increment : increment,
reset : reset,
cancel : cancel
}, options);
// bookkeeping variables
settings.cur_period = settings.period;
settings.tid = false;
var prev_ajax_response = '';
run();
// return settings so user can tweak them externally
return settings;
// run (or restart if already running) the looping construct
function run() {
// clear/stop existing timer (multiple calls to run() won't result in multiple timers)
cancel();
// let it rip!
settings.tid = setTimeout(function() {
// set the context (this) for the callback to the settings object
callback.call(settings);
// compute the next value for cur_period
increment();
// queue up the next run
if(settings.tid)
run();
}, settings.cur_period);
}
// utility function for use with ajax calls
function ajaxComplete(xhr, status) {
if (status === 'success' && prev_ajax_response !== xhr.responseText) {
// reset the period whenever the response changes
prev_ajax_response = xhr.responseText;
reset();
}
}
// compute the next delay
function increment() {
settings.cur_period *= settings.decay;
if (settings.cur_period < settings.period) {
// don't let it drop below the minimum
reset();
} else if (settings.cur_period > settings.max_period) {
settings.cur_period = settings.max_period;
if (settings.on_max !== undefined) {
// call the user-supplied callback if we reach max_period
settings.on_max.call(settings);
}
}
}
function reset() {
settings.cur_period = settings.period;
// restart with the new timeout
run();
}
function cancel() {
clearTimeout(settings.tid);
settings.tid = null;
}
// other functions we might want to implement
function pause() {}
function resume() {}
function log() {}
};
jQuery.periodic.defaults = {
period : 4000, // 4 sec.
max_period : 1800000, // 30 min.
decay : 1.5, // time period multiplier
on_max : undefined // called if max_period is reached
};
\ No newline at end of file
#model h1 {
display: block;
text-align: center;
}
\ No newline at end of file
<ul>
<li><b>Net:</b> <span id="net"></span></li>
<li><b>State:</b> <span id="state"></span></li>
<li><b>Marking:</b> <ul id="marking"></ul></li>
<li><b>Modes:</b> <ul id="modes"></ul></li>
</ul>
body {
font-family: sans-serif;
}
#alive {
border: solid 1px #AAA;
border-radius: 5px;
padding: 5px 10px;
margin: 5px;
background-color: #DDD;
overflow:auto;
}
#alive .ui {
display: inline;
list-style: none;
margin: 0px;
padding: 0px;
}
#alive .ui li {
display: inline;
border: solid 1px #AAA;
padding: 5px 10px;
margin: 0px 3px;
background-color: #EEE;
}
#alive .ui a {
text-decoration: none;
color: #333;
}
#alive .ui li:hover {
background-color: #FFF;
}
#alive .ui a:hover {
color: #A33;
}
#alive .ping {
color: #DDD;
float: right;
}
#model {
border: solid 1px #AAA;
border-radius: 5px;
padding: 5px 10px;
margin: 5px;
background-color: #EEE;
overflow:auto;
}
#trace {
border: solid 1px #AAA;
border-radius: 5px;
padding: 5px 10px;
margin: 5px;
background-color: #EEE;
overflow:auto;
}
#about {
display: none;
}
#dialog {
display: none;
position: fixed;
z-index: 2;
top: 10%;
left: 20%;
width: 60%;
border: solid 2px #AAA;
border-radius: 5px;
padding: 20px;
background-color: #FFF;
overflow:auto;
}
#dialog-bg {
display: none;
position: fixed;
z-index: 1;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
background-color: #000;
margin: 0px;
}
#dialog-close {
display: inline;
float: right;
border: solid 1px #AAA;
padding: 5px 10px;
margin: 0px 3px;
background-color: #EEE;
text-decoration: none;
color: #333;
}
#dialog-close:hover {
background-color: #FFF;
color: #A33;
}
.dialog p {
margin: 10px 20px 0px 20px;
}
.dialog .title {
margin: 0px 20px 5px 20px;
font-weight: bold;
text-align: center;
}
.dialog .subtitle {
margin: 0px 20px 5px 20px;
text-align: center;
}
\ No newline at end of file
function addcss (css) {
$("head").append("<style type='text/css'>" + css + "</style>");
}
function addjs (js) {
$("head").append("<script type='text/javascript'>" + js + "</script>");
}
function dialog (content) {
$("#dialog").html(content);
$("#dialog").append("<a href='#' id='dialog-close'>close</a>");
$("#dialog-close").click(function() {
$("#dialog-bg").hide();
$("#dialog").hide();
});
$("#dialog").fadeTo(50, 1);
$("#dialog-bg").fadeTo(50, 0.5);
}
var update = {
settext : function (action) {
$(action.select).text(action.text);
},
sethtml : function (action) {
$(action.select).html(action.html);
},
clear : function (action) {
$(action.select).html("");
},
setlist : function (action) {
ul = $(action.select);
ul.html("");
$.each(action.items, function (num, item) {
ul.append("<li>" + item + "</li>");
});
}
}
function setstate (state) {
$.each(state.states, function (num, item) {
update[item.do](item);
});
$.each(state.modes, function (num, action) {
ul = $(action.select);
ul.html("");
$.each(action.items, function (pos, item) {
ul.append("<li><a href='#' data-mode='" + state.id + ":"
+ pos + "''>" + item + "</a></li>");
a = ul.children().last().children().first();
a.click(function () {
next = $(this).attr("data-mode").split(":");
text = $(this).text();
$("#trace").append("<div class='trace'><div class='state'>"
+ state.id + "</div><div class='mode'>"
+ text + "</div></div>");
$.get("succ", {state: next[0], mode: next[1]},
function (newstate) {
setstate(newstate);
});
});
});
});
}
$(document).ready(function() {
/*
* ping server every 10 seconds
*/
$("#alive .ping").text("Stayin alive!");
$.periodic({period: 10000, decay:1, max_period: 10000}, function() {
$.get("ping", function(data) {
$("#alive .ping").text(data);
});
});
/*
* setup UI and model
*/
$.get("init", function(init) {
/* bind reset button */
$("#ui-reset").click(function() {
$.get("init", {state: 0}, function(data) {
setstate(data.state);
$("#trace").html("");
});
});
/* bind quit button */
$("#ui-quit").click(function() {
$.get("quit", function(data) {
$("#alive .ui").html("").text(data);
});
});
/* dialogs */
$("body").append("<div id='dialog'>"
+ "</div><div id='dialog-bg'></div>");
/* build about */
$("#about").children().addClass("dialog");
$("#ui-about").click(function() {
dialog($("#about").html());
});
/* extend menu */
if (init.ui != undefined) {
ui = $("#alive .ui");
/* TODO: fix spacing between these buttons */
$.each(init.ui, function(num, menu) {
ui.append("<li><a id='" + menu.id
+ "'href='" + menu.href + "'>"
+ menu.label + "</a></li>");
if (menu.script != undefined) {
ui.children().last().click(function() {
eval(menu.script);
});
}
});
}
/* build help */
if (init.help != undefined) {
$.each(init.help, function(key, text) {
/* TODO: create help dic or whatever needed */
});
$("#ui-help").click(function() {
/* TODO: show/hide tooltips for help */
});
} else {
$("#ui-help").remove();
}
/* setup initial state */
setstate(init.state);
});
});
\ No newline at end of file
#trace h1 {
display: block;
text-align: center;
}
\ No newline at end of file