Franck Pommereau

first HTMLL simulator

...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
3 import sys, os 3 import sys, os
4 from distutils.core import setup 4 from distutils.core import setup
5 5
6 -def doc_files() : 6 +def doc_files () :
7 import os, os.path 7 import os, os.path
8 result = {} 8 result = {}
9 for root, dirs, files in os.walk("doc") : 9 for root, dirs, files in os.walk("doc") :
...@@ -15,6 +15,15 @@ def doc_files() : ...@@ -15,6 +15,15 @@ def doc_files() :
15 result[target_dir].append(os.path.join(root, name)) 15 result[target_dir].append(os.path.join(root, name))
16 return list(result.items()) 16 return list(result.items())
17 17
18 +def abcd_resources () :
19 + collected = ["*.txt", "*.html", "*.css", "*.js", "*.png", "*.jpg"]
20 + import glob, os.path
21 + result = []
22 + for pattern in collected :
23 + for path in glob.glob("snakes/utils/abcd/resources/" + pattern) :
24 + result.append(os.path.join("resources", os.path.basename(path)))
25 + return result
26 +
18 try : 27 try :
19 long_description=open("README").read() 28 long_description=open("README").read()
20 except : 29 except :
...@@ -56,5 +65,6 @@ if __name__ == "__main__" : ...@@ -56,5 +65,6 @@ if __name__ == "__main__" :
56 "snakes.utils.abcd", 65 "snakes.utils.abcd",
57 "snakes.utils.ctlstar", 66 "snakes.utils.ctlstar",
58 ], 67 ],
68 + package_data={"snakes.utils.abcd": abcd_resources()},
59 data_files=doc_files() + emacs, 69 data_files=doc_files() + emacs,
60 ) 70 )
......
...@@ -906,15 +906,11 @@ class Expression (ArcAnnotation) : ...@@ -906,15 +906,11 @@ class Expression (ArcAnnotation) :
906 return Token(True) 906 return Token(True)
907 else : 907 else :
908 env = binding._dict 908 env = binding._dict
909 - # just to allow a cleaner implementation of let 909 + env["__binding__"] = binding._dict
910 - env["__binding__"] = env
911 - env["__globals__"] = self.globals
912 try : 910 try :
913 return Token(self.globals(self._expr, env)) 911 return Token(self.globals(self._expr, env))
914 finally : 912 finally :
915 - # cleanup what was added above
916 del env["__binding__"] 913 del env["__binding__"]
917 - del env["__globals__"]
918 def __call__ (self, binding) : 914 def __call__ (self, binding) :
919 """Returns the value from `bind` (but not encapsulated in a 915 """Returns the value from `bind` (but not encapsulated in a
920 `Token`). 916 `Token`).
......
...@@ -47,7 +47,7 @@ False ...@@ -47,7 +47,7 @@ False
47 automatically loaded) 47 automatically loaded)
48 """ 48 """
49 49
50 -import os, os.path, subprocess, collections 50 +import os, os.path, subprocess, collections, codecs
51 import snakes.plugins 51 import snakes.plugins
52 from snakes.plugins.clusters import Cluster 52 from snakes.plugins.clusters import Cluster
53 from snakes.compat import * 53 from snakes.compat import *
...@@ -78,7 +78,7 @@ class Graph (Cluster) : ...@@ -78,7 +78,7 @@ class Graph (Cluster) :
78 else : 78 else :
79 tag = "%s " % tag 79 tag = "%s " % tag
80 return (["%s[" % tag, 80 return (["%s[" % tag,
81 - ["%s=%s" % (key, self.escape(str(val))) 81 + ["%s=%s" % (key, self.escape(unicode(val)))
82 for key, val in attr.items()], 82 for key, val in attr.items()],
83 "];"]) 83 "];"])
84 def _dot (self) : 84 def _dot (self) :
...@@ -97,7 +97,7 @@ class Graph (Cluster) : ...@@ -97,7 +97,7 @@ class Graph (Cluster) :
97 return lines 97 return lines
98 def _dot_text (self, lines, indent=0) : 98 def _dot_text (self, lines, indent=0) :
99 for l in lines : 99 for l in lines :
100 - if isinstance(l, str) : 100 + if isinstance(l, (str, unicode)) :
101 yield " "*indent*2 + l 101 yield " "*indent*2 + l
102 else : 102 else :
103 for x in self._dot_text(l, indent+1) : 103 for x in self._dot_text(l, indent+1) :
...@@ -105,6 +105,7 @@ class Graph (Cluster) : ...@@ -105,6 +105,7 @@ class Graph (Cluster) :
105 def dot (self) : 105 def dot (self) :
106 self.done = set() 106 self.done = set()
107 return "\n".join(self._dot_text(["digraph {", 107 return "\n".join(self._dot_text(["digraph {",
108 + 'charset="UTF-8"',
108 ['node [label="N",' 109 ['node [label="N",'
109 ' fillcolor="#FFFFFF",' 110 ' fillcolor="#FFFFFF",'
110 ' fontcolor="#000000",' 111 ' fontcolor="#000000",'
...@@ -115,13 +116,15 @@ class Graph (Cluster) : ...@@ -115,13 +116,15 @@ class Graph (Cluster) :
115 self._dot(), 116 self._dot(),
116 "}"])) 117 "}"]))
117 def escape (self, text) : 118 def escape (self, text) :
118 - return '"%s"' % text.replace('"', r'\"') 119 + if text.startswith("<") and text.endswith(">") :
120 + return text
121 + else :
122 + return '"%s"' % text.replace('"', r'\"')
119 def render (self, filename, engine="dot", debug=False) : 123 def render (self, filename, engine="dot", debug=False) :
120 if engine not in ("dot", "neato", "twopi", "circo", "fdp") : 124 if engine not in ("dot", "neato", "twopi", "circo", "fdp") :
121 raise ValueError("unknown GraphViz engine %r" % engine) 125 raise ValueError("unknown GraphViz engine %r" % engine)
122 - outfile = open(filename + ".dot", "w") 126 + with codecs.open(filename + ".dot", "w", "utf-8") as outfile :
123 - outfile.write(self.dot()) 127 + outfile.write(self.dot())
124 - outfile.close()
125 if debug : 128 if debug :
126 dot = subprocess.Popen([engine, "-T" + filename.rsplit(".", 1)[-1], 129 dot = subprocess.Popen([engine, "-T" + filename.rsplit(".", 1)[-1],
127 "-o" + filename, outfile.name], 130 "-o" + filename, outfile.name],
...@@ -226,11 +229,10 @@ def extend (module) : ...@@ -226,11 +229,10 @@ def extend (module) :
226 self._copy_edges(nodemap, g, arc_attr) 229 self._copy_edges(nodemap, g, arc_attr)
227 if graph_attr : 230 if graph_attr :
228 graph_attr(self, g.attr) 231 graph_attr(self, g.attr)
229 - if filename is None : 232 + if filename is not None :
230 - g.nodemap = nodemap
231 - return g
232 - else :
233 g.render(filename, engine, debug) 233 g.render(filename, engine, debug)
234 + g.nodemap = nodemap
235 + return g
234 def _copy (self, nodemap, sub, cluster_attr, place_attr, trans_attr) : 236 def _copy (self, nodemap, sub, cluster_attr, place_attr, trans_attr) :
235 attr = dict(style="invis") 237 attr = dict(style="invis")
236 if cluster_attr : 238 if cluster_attr :
...@@ -249,6 +251,8 @@ def extend (module) : ...@@ -249,6 +251,8 @@ def extend (module) :
249 label="%s\\n%s" % (node.name, str(node.guard))) 251 label="%s\\n%s" % (node.name, str(node.guard)))
250 if trans_attr : 252 if trans_attr :
251 trans_attr(node, attr) 253 trans_attr(node, attr)
254 + attr["tooltip"] = node.name
255 + attr["id"] = nodemap[name]
252 graph.add_node(nodemap[name], attr) 256 graph.add_node(nodemap[name], attr)
253 for child in sub.children() : 257 for child in sub.children() :
254 graph.add_child(self._copy(nodemap, child, cluster_attr, 258 graph.add_child(self._copy(nodemap, child, cluster_attr,
......
...@@ -67,9 +67,11 @@ def unlet (expr, *names) : ...@@ -67,9 +67,11 @@ def unlet (expr, *names) :
67 return unparse(new), drop.calls 67 return unparse(new), drop.calls
68 68
69 class MakeLet (object) : 69 class MakeLet (object) :
70 + def __init__ (self, globals) :
71 + self.globals = globals
70 def match (self, match, binding) : 72 def match (self, match, binding) :
71 env = dict(binding) 73 env = dict(binding)
72 - env.update(env["__globals__"]) 74 + env.update(iter(self.globals))
73 exec("", env) 75 exec("", env)
74 old = set(env) 76 old = set(env)
75 exec(match, env) 77 exec(match, env)
...@@ -93,5 +95,5 @@ def extend (module) : ...@@ -93,5 +95,5 @@ def extend (module) :
93 class PetriNet (module.PetriNet) : 95 class PetriNet (module.PetriNet) :
94 def __init__ (self, name, **args) : 96 def __init__ (self, name, **args) :
95 module.PetriNet.__init__(self, name, **args) 97 module.PetriNet.__init__(self, name, **args)
96 - self.globals["let"] = MakeLet() 98 + self.globals["let"] = MakeLet(self.globals)
97 return PetriNet, unlet 99 return PetriNet, unlet
......
...@@ -272,9 +272,6 @@ def extend (module) : ...@@ -272,9 +272,6 @@ def extend (module) :
272 else : 272 else :
273 guard = guard & snk.Expression("newpids(%s)" 273 guard = guard & snk.Expression("newpids(%s)"
274 % ", ".join(assign)) 274 % ", ".join(assign))
275 - for pid in self.pids.killed :
276 - pidcount = vars.fresh(add=True, base="next_%s" % pid)
277 - self.pids.next[pid] = pidcount
278 snk.Transition.__init__(self, name, guard, **args) 275 snk.Transition.__init__(self, name, guard, **args)
279 def vars (self) : 276 def vars (self) :
280 return self.pids.vars() | snk.Transition.vars(self) 277 return self.pids.vars() | snk.Transition.vars(self)
...@@ -306,10 +303,6 @@ def extend (module) : ...@@ -306,10 +303,6 @@ def extend (module) :
306 prod[child] = snk.Tuple([snk.Variable(child), 303 prod[child] = snk.Tuple([snk.Variable(child),
307 snk.Value(0)]) 304 snk.Value(0)])
308 for pid in trans.pids.killed : 305 for pid in trans.pids.killed :
309 - if pid not in trans.pids.spawned :
310 - pidcount = trans.pids.next[pid]
311 - cons[pid] = snk.Tuple([snk.Variable(pid),
312 - snk.Variable(pidcount)])
313 prod.pop(pid, None) 306 prod.pop(pid, None)
314 if len(cons) > 1 : 307 if len(cons) > 1 :
315 self.add_input(self.nextpids, trans.name, 308 self.add_input(self.nextpids, trans.name,
...@@ -320,7 +313,7 @@ def extend (module) : ...@@ -320,7 +313,7 @@ def extend (module) :
320 if len(prod) > 1 : 313 if len(prod) > 1 :
321 self.add_output(self.nextpids, trans.name, 314 self.add_output(self.nextpids, trans.name,
322 snk.MultiArc(prod.values())) 315 snk.MultiArc(prod.values()))
323 - elif len(prod) == 1 : 316 + elif len(cons) == 1 :
324 self.add_output(self.nextpids, trans.name, 317 self.add_output(self.nextpids, trans.name,
325 iter(prod.values()).next()) 318 iter(prod.values()).next())
326 return PetriNet, Transition, Pid, ("tPid", tPid), ("tNextPid", tNextPid) 319 return PetriNet, Transition, Pid, ("tPid", tPid), ("tNextPid", tNextPid)
......
...@@ -432,7 +432,24 @@ class Builder (object) : ...@@ -432,7 +432,24 @@ class Builder (object) :
432 self.instances.add(name) 432 self.instances.add(name)
433 path = self.path + [name] 433 path = self.path + [name]
434 builder = self.__class__(self.snk, path, self) 434 builder = self.__class__(self.snk, path, self)
435 - return builder.build(spec) 435 + net = builder.build(spec)
436 + src = (node.st.source(),
437 + node.st.srow, node.st.scol,
438 + node.st.erow, node.st.ecol)
439 + for trans in net.transition() :
440 + try :
441 + lbl = trans.label("instances")
442 + trans.label(instances=[src] + lbl)
443 + except KeyError :
444 + trans.label(instances=[src])
445 + for place in net.place() :
446 + if place.status == self.snk.Status(None) :
447 + try :
448 + lbl = place.label("instances")
449 + place.label(instances=[src] + lbl)
450 + except KeyError :
451 + place.label(instances=[src])
452 + return net
436 # control flow operations 453 # control flow operations
437 def build_Sequence (self, node) : 454 def build_Sequence (self, node) :
438 return self.snk.PetriNet.__and__ 455 return self.snk.PetriNet.__and__
......
This diff is collapsed. Click to expand it.
1 -import sys, optparse, os.path 1 +import sys, optparse, os.path, webbrowser
2 import pdb, traceback 2 import pdb, traceback
3 import snakes.plugins 3 import snakes.plugins
4 from snakes.utils.abcd.build import Builder 4 from snakes.utils.abcd.build import Builder
...@@ -7,6 +7,7 @@ from snakes.lang.pgen import ParseError ...@@ -7,6 +7,7 @@ from snakes.lang.pgen import ParseError
7 from snakes.utils.abcd import CompilationError, DeclarationError 7 from snakes.utils.abcd import CompilationError, DeclarationError
8 from snakes.utils.abcd.simul import Simulator 8 from snakes.utils.abcd.simul import Simulator
9 from snakes.utils.abcd.checker import Checker 9 from snakes.utils.abcd.checker import Checker
10 +from snakes.utils.abcd.html import build as html
10 11
11 ## 12 ##
12 ## error messages 13 ## error messages
...@@ -21,10 +22,16 @@ ERR_COMPILE = 6 ...@@ -21,10 +22,16 @@ ERR_COMPILE = 6
21 ERR_OUTPUT = 7 22 ERR_OUTPUT = 7
22 ERR_BUG = 255 23 ERR_BUG = 255
23 24
25 +def log (message) :
26 + sys.stdout.write("abcd: %s\n" % message.strip())
27 + sys.stdout.flush()
28 +
24 def err (message) : 29 def err (message) :
25 sys.stderr.write("abcd: %s\n" % message.strip()) 30 sys.stderr.write("abcd: %s\n" % message.strip())
31 + sys.stderr.flush()
26 32
27 def die (code, message=None) : 33 def die (code, message=None) :
34 + global options
28 if message : 35 if message :
29 err(message) 36 err(message)
30 if options.debug : 37 if options.debug :
...@@ -33,6 +40,7 @@ def die (code, message=None) : ...@@ -33,6 +40,7 @@ def die (code, message=None) :
33 sys.exit(code) 40 sys.exit(code)
34 41
35 def bug () : 42 def bug () :
43 + global options
36 sys.stderr.write(""" 44 sys.stderr.write("""
37 ******************************************************************** 45 ********************************************************************
38 *** An unexpected error ocurred. Please report this bug to *** 46 *** An unexpected error ocurred. Please report this bug to ***
...@@ -79,12 +87,19 @@ opt.add_option("--debug", ...@@ -79,12 +87,19 @@ opt.add_option("--debug",
79 opt.add_option("-s", "--simul", 87 opt.add_option("-s", "--simul",
80 dest="simul", action="store_true", default=False, 88 dest="simul", action="store_true", default=False,
81 help="launch interactive code simulator") 89 help="launch interactive code simulator")
90 +opt.add_option("--headless",
91 + dest="headless", action="store_true", default=False,
92 + help="headless code simulator (don't start browser)")
93 +opt.add_option("-H", "--html",
94 + dest="html", action="store", default=None,
95 + help="save net as HTML",
96 + metavar="OUTFILE")
82 opt.add_option("--check", 97 opt.add_option("--check",
83 dest="check", action="store_true", default=False, 98 dest="check", action="store_true", default=False,
84 help="check assertions") 99 help="check assertions")
85 100
86 def getopts (args) : 101 def getopts (args) :
87 - global options, abcd 102 + global options, abcd, tmp
88 (options, args) = opt.parse_args(args) 103 (options, args) = opt.parse_args(args)
89 plugins = [] 104 plugins = []
90 for p in options.plugins : 105 for p in options.plugins :
...@@ -98,6 +113,8 @@ def getopts (args) : ...@@ -98,6 +113,8 @@ def getopts (args) :
98 if gvopt and "gv" not in plugins : 113 if gvopt and "gv" not in plugins :
99 plugins.append("gv") 114 plugins.append("gv")
100 break 115 break
116 + if (options.html or options.simul) and "gv" not in plugins :
117 + plugins.append("gv")
101 options.plugins = plugins 118 options.plugins = plugins
102 if len(args) < 1 : 119 if len(args) < 1 :
103 err("no input file provided") 120 err("no input file provided")
...@@ -112,6 +129,10 @@ def getopts (args) : ...@@ -112,6 +129,10 @@ def getopts (args) :
112 err("input file also used as output (--pnml)") 129 err("input file also used as output (--pnml)")
113 opt.print_help() 130 opt.print_help()
114 die(ERR_ARG) 131 die(ERR_ARG)
132 + if options.html == abcd :
133 + err("input file also used as output (--html)")
134 + opt.print_help()
135 + die(ERR_ARG)
115 for engine in gv_engines : 136 for engine in gv_engines :
116 if getattr(options, "gv%s" % engine) == abcd : 137 if getattr(options, "gv%s" % engine) == abcd :
117 err("input file also used as output (--%s)" % engine) 138 err("input file also used as output (--%s)" % engine)
...@@ -129,7 +150,7 @@ def place_attr (place, attr) : ...@@ -129,7 +150,7 @@ def place_attr (place, attr) :
129 elif place.status == snk.internal : 150 elif place.status == snk.internal :
130 pass 151 pass
131 elif place.status == snk.exit : 152 elif place.status == snk.exit :
132 - attr["fillcolor"] = "yellow" 153 + attr["fillcolor"] = "orange"
133 else : 154 else :
134 attr["fillcolor"] = "lightblue" 155 attr["fillcolor"] = "lightblue"
135 # fix shape 156 # fix shape
...@@ -142,9 +163,9 @@ def place_attr (place, attr) : ...@@ -142,9 +163,9 @@ def place_attr (place, attr) :
142 if count == 0 : 163 if count == 0 :
143 marking = " " 164 marking = " "
144 elif count == 1 : 165 elif count == 1 :
145 - marking = "@" 166 + marking = "&#8226;"
146 else : 167 else :
147 - marking = "%s@" % count 168 + marking = "%s&#8226;" % count
148 else : 169 else :
149 marking = str(place.tokens) 170 marking = str(place.tokens)
150 # node label 171 # node label
...@@ -167,12 +188,13 @@ def arc_attr (label, attr) : ...@@ -167,12 +188,13 @@ def arc_attr (label, attr) :
167 attr["arrowhead"] = "box" 188 attr["arrowhead"] = "box"
168 attr["label"] = " %s " % label._annotation 189 attr["label"] = " %s " % label._annotation
169 190
170 -def draw (net, engine, target) : 191 +
192 +def draw (net, target, engine="dot") :
171 try : 193 try :
172 - net.draw(target, engine=engine, 194 + return net.draw(target, engine=engine,
173 - place_attr=place_attr, 195 + place_attr=place_attr,
174 - trans_attr=trans_attr, 196 + trans_attr=trans_attr,
175 - arc_attr=arc_attr) 197 + arc_attr=arc_attr)
176 except : 198 except :
177 die(ERR_OUTPUT, str(sys.exc_info()[1])) 199 die(ERR_OUTPUT, str(sys.exc_info()[1]))
178 200
...@@ -193,7 +215,7 @@ def save_pnml (net, target) : ...@@ -193,7 +215,7 @@ def save_pnml (net, target) :
193 ## 215 ##
194 216
195 def main (args=sys.argv[1:], src=None) : 217 def main (args=sys.argv[1:], src=None) :
196 - global snk 218 + global options, snk
197 # get options 219 # get options
198 try: 220 try:
199 if src is None : 221 if src is None :
...@@ -232,7 +254,7 @@ def main (args=sys.argv[1:], src=None) : ...@@ -232,7 +254,7 @@ def main (args=sys.argv[1:], src=None) :
232 build = Builder(snk) 254 build = Builder(snk)
233 try : 255 try :
234 net = build.build(node) 256 net = build.build(node)
235 - net.label(srcfile=abcd) 257 + net.label(srcfile=abcd, snakes=snk)
236 except (CompilationError, DeclarationError) : 258 except (CompilationError, DeclarationError) :
237 die(ERR_COMPILE, str(sys.exc_info()[1])) 259 die(ERR_COMPILE, str(sys.exc_info()[1]))
238 except : 260 except :
...@@ -243,12 +265,24 @@ def main (args=sys.argv[1:], src=None) : ...@@ -243,12 +265,24 @@ def main (args=sys.argv[1:], src=None) :
243 for engine in gv_engines : 265 for engine in gv_engines :
244 target = getattr(options, "gv%s" % engine) 266 target = getattr(options, "gv%s" % engine)
245 if target : 267 if target :
246 - draw(net, engine, target) 268 + draw(net, target, engine)
269 + if options.html :
270 + try :
271 + html(abcd, node, net, draw(net, None), options.html)
272 + except :
273 + bug()
247 trace, lineno = [], None 274 trace, lineno = [], None
248 if options.check : 275 if options.check :
249 lineno, trace = Checker(net).run() 276 lineno, trace = Checker(net).run()
250 if options.simul : 277 if options.simul :
251 - Simulator(snk, source, net, trace, lineno).run() 278 + try :
279 + simul = Simulator(abcd, node, net, draw(net, None))
280 + except :
281 + bug()
282 + simul.start()
283 + if not options.headless :
284 + webbrowser.open(simul.url)
285 + simul.wait()
252 elif trace : 286 elif trace :
253 if lineno is None : 287 if lineno is None :
254 print("unsafe execution:") 288 print("unsafe execution:")
......
1 +<div class="about">
2 + <p><span class="title">ABCD simulator is part of the SNAKES
3 + toolkit</span><br/> (C) 2014 Franck Pommereau</p>
4 + <p><a href="http://www.ibisc.univ-evry.fr/~fpommereau/SNAKES"
5 + target="_blank">SNAKES homepage</a></p>
6 +</div>
This diff is collapsed. Click to expand it.
1 +import snakes
2 +from snakes.utils.simul.httpd import *
3 +from snakes.utils.simul.html import H
4 +import multiprocessing, time, sys, json, os.path, signal, inspect, glob
5 +import operator
6 +
7 +class StateSpace (dict) :
8 + def __init__ (self, net) :
9 + self.net = net
10 + self.current = self.add(net.get_marking())
11 + def get (self) :
12 + return self[self.current]
13 + def add (self, marking) :
14 + if marking in self :
15 + return self[marking].num
16 + else :
17 + marking.num = len(self) / 2
18 + self[marking] = self[marking.num] = marking
19 + self.setmodes(marking.num)
20 + return marking.num
21 + def setmodes (self, state) :
22 + marking = self[state]
23 + self.net.set_marking(marking)
24 + marking.modes = []
25 + for trans in self.net.transition() :
26 + for mode in trans.modes() :
27 + marking.modes.append((trans, mode))
28 + def succ (self, state, mode) :
29 + marking = self[state]
30 + trans, binding = marking.modes[mode]
31 + self.net.set_marking(marking)
32 + trans.fire(binding)
33 + self.current = self.add(self.net.get_marking())
34 + return self.current
35 + def modes (self, state) :
36 + return self[state].modes
37 +
38 +def log (message) :
39 + sys.stderr.write("[simulator] %s\n" % message.strip())
40 + sys.stderr.flush()
41 +
42 +shutdown = multiprocessing.Event()
43 +ping = multiprocessing.Event()
44 +
45 +class Server (multiprocessing.Process) :
46 + def __init__ (self, httpd) :
47 + multiprocessing.Process.__init__(self)
48 + self.httpd = httpd
49 + def run (self) :
50 + try :
51 + self.httpd.serve_forever()
52 + except KeyboardInterrupt :
53 + pass
54 + finally :
55 + shutdown.set()
56 +
57 +class WatchDog (multiprocessing.Process) :
58 + def __init__ (self, timeout=30) :
59 + multiprocessing.Process.__init__(self)
60 + self.timeout = timeout
61 + def run (self) :
62 + try :
63 + while True :
64 + if ping.wait(self.timeout) :
65 + ping.clear()
66 + else :
67 + log("client not active - %s\n"
68 + % time.strftime("%d/%b/%Y %H:%M:%S"))
69 + break
70 + except KeyboardInterrupt :
71 + pass
72 + finally :
73 + shutdown.set()
74 +
75 +class BaseHTTPSimulator (Node) :
76 + def __init__ (self, net, port=8000, resources=[]) :
77 + self.res = {}
78 + for cls in reversed(inspect.getmro(self.__class__)[:-2]) :
79 + path = os.path.dirname(inspect.getsourcefile(cls))
80 + for pattern in resources + ["resources/*.js",
81 + "resources/*.css",
82 + "resources/*.html",
83 + "resources/alive.txt"] :
84 + for res in glob.glob(os.path.join(path, pattern)) :
85 + with open(res) as infile :
86 + self.res[os.path.basename(res)] = infile.read()
87 + Node.__init__(self, r=ResourceNode(self.res))
88 + # create HTTP server
89 + self.port = port
90 + while True :
91 + try :
92 + httpd = HTTPServer(('', self.port), self)
93 + except Exception as err :
94 + self.port += 1
95 + else :
96 + break
97 + self.server = Server(httpd)
98 + self.watchdog = WatchDog()
99 + # init data
100 + self.url = "http://127.0.0.1:%s/%s/" % (port, httpd.key)
101 + self._alive = self.res["alive.txt"].splitlines()
102 + self._ping = 0
103 + self.states = StateSpace(net)
104 + def start (self) :
105 + log("starting at %r" % self.url)
106 + shutdown.clear()
107 + ping.clear()
108 + self.server.start()
109 + self.watchdog.start()
110 + def wait (self) :
111 + try :
112 + shutdown.wait()
113 + log("preparing to shut down...")
114 + time.sleep(2)
115 + except KeyboardInterrupt :
116 + shutdown.set()
117 + log("shuting down...")
118 + sig = getattr(signal, "CTRL_C_EVENT",
119 + getattr(signal, "SIGTERM", None))
120 + if sig is not None :
121 + if self.server.pid :
122 + os.kill(self.server.pid, sig)
123 + if self.watchdog.pid :
124 + os.kill(self.watchdog.pid, sig)
125 + log("bye!")
126 + def getstate (self, state) :
127 + marking = self.states[state]
128 + places = ["%s = %s" % (H.span(place.name, class_="place"),
129 + H.span(marking(place.name), class_="token"))
130 + for place in sorted(self.states.net.place(),
131 + key=operator.attrgetter("name"))]
132 + modes = ["%s : %s" % (H.span(trans.name, class_="trans"),
133 + H.span(binding, class_="binding"))
134 + for trans, binding in marking.modes]
135 + return {"id" : state,
136 + "states" : [{"do" : "sethtml",
137 + "select" : "#net",
138 + "html" : H.i(self.states.net)},
139 + {"do" : "settext",
140 + "select" : "#state",
141 + "text" : state},
142 + {"do" : "setlist",
143 + "select" : "#marking",
144 + "items" : places},
145 + ],
146 + "modes" : [{"select" : "#modes",
147 + "items" : modes},
148 + ],
149 + }
150 + def init_index (self) :
151 + return {"res" : "%s/r" % self.url,
152 + "url" : self.url,
153 + "key" : self.server.httpd.key,
154 + "host" : "127.0.0.1",
155 + "port" : self.port,
156 + "about" : self.init_about(),
157 + "model" : self.init_model()}
158 + def init_model (self) :
159 + return self.res["model.html"]
160 + def init_about (self) :
161 + return self.res["about.html"]
162 + @http("text/html")
163 + def __call__ (self) :
164 + return self.res["index.html"] % self.init_index()
165 + def init_ui (self) :
166 + argv = H.code(" ".join(sys.argv))
167 + version = (H.ul(H.li(H.b("Python: "),
168 + H.br.join(sys.version.splitlines())),
169 + H.li(H.b("SNAKES: "), snakes.version)))
170 + return [{"label" : "Versions",
171 + "id" : "ui-version",
172 + "href" : "#",
173 + "script" : "dialog(%r)" % version},
174 + {"label" : "Argv",
175 + "id" : "ui-argv",
176 + "href" : "#",
177 + "script" : "dialog(%r)" % argv}]
178 + def init_help (self) :
179 + return {"#trace": "the states and transitions explored so far",
180 + "#model" : "the model being simulated",
181 + "#alive .ui #ui-quit" : "stop the simulator (server side)",
182 + "#alive .ui #ui-help" : "show this help",
183 + "#alive .ui #ui-about" : "show information about the simulator"}
184 + @http("application/json", state=int)
185 + def init (self, state=-1) :
186 + if state < 0 :
187 + state = self.states.current
188 + return {"ui" : self.init_ui(),
189 + "state" : self.getstate(state),
190 + "help" : self.init_help()}
191 + @http("application/json", state=int, mode=int)
192 + def succ (self, state, mode) :
193 + state = self.states.succ(state, mode)
194 + return self.getstate(state)
195 + @http("text/plain")
196 + def ping (self) :
197 + ping.set()
198 + alive = self._alive[self._ping % len(self._alive)]
199 + self._ping += 1
200 + return alive
201 + @http("text/plain")
202 + def quit (self) :
203 + shutdown.set()
204 + return "Bye!"
205 +
206 +if __name__ == "__main__" :
207 + import snakes.nets, webbrowser
208 + net = snakes.nets.loads(sys.argv[1])
209 + simul = BaseHTTPSimulator(net)
210 + simul.start()
211 + webbrowser.open(simul.url)
212 + simul.wait()
1 +import functools
2 +import json as JSON
3 +
4 +def _tag (name) :
5 + return name.lower().strip("_")
6 +
7 +class Tag (object) :
8 + default = {"a" : {"href" : "#"}}
9 + noclose = set([None, "br"])
10 + def __init__ (self, name, *children, **attr) :
11 + if name is not None :
12 + self.name = name.lower()
13 + else :
14 + self.name = None
15 + self.attr = dict(self._cleanup(attr))
16 + self.children = list(children)
17 + def _cleanup (self, attr) :
18 + for key, value in attr.items() :
19 + yield _tag(key), value
20 + def __call__ (self, *children, **attr) :
21 + self.children.extend(children)
22 + self.attr.update(self._cleanup(attr))
23 + return self
24 + def add (self, *children) :
25 + self.children.extend(children)
26 + return self
27 + def join (self, children) :
28 + if self.name not in self.noclose :
29 + raise ValueError("cannot join with tag %r" % self.name)
30 + lst = [children[0]]
31 + for c in children[1:] :
32 + lst.extend([self, c])
33 + return self.__class__(None, *lst)
34 + def __setitem__ (self, key, value) :
35 + self(**{_tag(key): value})
36 + def __delitem__ (self, key) :
37 + self.attr.pop(_tag(key), None)
38 + def __contains__ (self, key) :
39 + return _tag(key) in self.attr
40 + def __str__ (self) :
41 + attr = self.attr.copy()
42 + for key, value in self.default.get(self.name, {}).items() :
43 + if key not in attr :
44 + attr[key] = value
45 + if self.name is None :
46 + return "".join(str(c) for c in self.children)
47 + elif attr :
48 + ret = "<%s %s>%s" % (
49 + self.name,
50 + " ".join("%s=%r" % a for a in attr.items()),
51 + "".join(str(c) for c in self.children))
52 + else :
53 + ret = "<%s>%s" % (
54 + self.name,
55 + "".join(str(c) for c in self.children))
56 + if self.children or self.name not in self.noclose :
57 + return ret + "</%s>" % self.name
58 + else :
59 + return ret[:-1] + "/>"
60 + def __repr__ (self) :
61 + return repr(str(self))
62 +
63 +class Factory (object) :
64 + def __getattr__ (self, name) :
65 + return Tag(_tag(name))
66 +
67 +H = Factory()
68 +
69 +class JSONEncoder(JSON.JSONEncoder):
70 + def default(self, obj):
71 + if isinstance(obj, Tag):
72 + return str(obj)
73 + else :
74 + return JSON.JSONEncoder.default(self, obj)
75 +
76 +json = JSONEncoder().encode
1 +import sys, os.path, httplib, cgi, urlparse, functools, mimetypes
2 +import os, signal, traceback, random, base64, inspect
3 +import BaseHTTPServer
4 +from snakes.utils.simul.html import json
5 +
6 +##
7 +##
8 +##
9 +
10 +class HTTPError (Exception) :
11 + def __init__ (self, code, reason=None, debug=None, headers={}) :
12 + self.answer = httplib.responses[code]
13 + if reason is None :
14 + message = self.answer
15 + else :
16 + message = "%s (%s)" % (self.answer, reason)
17 + Exception.__init__(self, message)
18 + self.code = code
19 + self.reason = reason
20 + self.debug = debug
21 + self.headers = headers
22 +
23 +##
24 +##
25 +##
26 +
27 +encoders = {"application/json" : json,
28 + "text/plain" : str,
29 + "text/html" : str,
30 + }
31 +
32 +def http (content_type=None, **types) :
33 + def decorator (method) :
34 + @functools.wraps(method)
35 + def wrapper (*larg, **karg) :
36 + try :
37 + args = inspect.getcallargs(method, *larg, **karg)
38 + for a, t in types.items() :
39 + if a in args :
40 + args[a] = t(args[a])
41 + except :
42 + raise HTTPError(httplib.BAD_REQUEST, "invalid arguments")
43 + try :
44 + if content_type is None :
45 + return method(**args)
46 + else :
47 + encode = encoders.get(content_type, str)
48 + return content_type, encode(method(**args))
49 + except HTTPError :
50 + raise
51 + except :
52 + raise HTTPError(httplib.INTERNAL_SERVER_ERROR,
53 + debug=sys.exc_info())
54 + return wrapper
55 + return decorator
56 +
57 +class Node (object) :
58 + def __init__ (self, **children) :
59 + for child, node in children.items() :
60 + setattr(self, child, node)
61 + def __getitem__ (self, path) :
62 + path = path.strip("/")
63 + if "/" in path :
64 + head, tail = path.split("/", 1)
65 + child = getattr(self, head, None)
66 + if isinstance(child, Node) :
67 + return child[tail]
68 + else :
69 + raise KeyError(tail)
70 + elif path == "" and hasattr(self, "__call__") :
71 + return self.__call__
72 + elif hasattr(self, path) :
73 + return getattr(self, path)
74 + else :
75 + raise KeyError(path)
76 +
77 +class DirNode (Node) :
78 + def __init__ (self, path) :
79 + self.root = os.path.realpath(path)
80 + def __getitem__ (self, path) :
81 + path = os.path.join(self.root, path.lstrip("./"))
82 + if not os.path.isfile(path) :
83 + raise HTTPError(httplib.NOT_FOUND)
84 + ct = mimetypes.guess_type(path)[0] or "application/octet-stream"
85 + @http(ct)
86 + def handler () :
87 + return open(path).read()
88 + return handler
89 +
90 +class ResourceNode (Node) :
91 + def __init__ (self, data) :
92 + self.data = data
93 + self.ct = dict((path, mimetypes.guess_type(path)[0]
94 + or "application/octet-stream")
95 + for path in self.data)
96 + def __getitem__ (self, path) :
97 + if path in self.data :
98 + @http(self.ct[path])
99 + def handler () :
100 + return self.data[path]
101 + return handler
102 + else :
103 + raise HTTPError(httplib.NOT_FOUND)
104 +
105 +##
106 +##
107 +##
108 +
109 +class HTTPRequestHandler (BaseHTTPServer.BaseHTTPRequestHandler) :
110 + def do_GET (self) :
111 + try :
112 + try :
113 + url = urlparse.urlparse(self.path)
114 + except :
115 + raise HTTPError(httplib.BAD_REQUEST, "invalid URL")
116 + try :
117 + handler = self.server[url.path]
118 + except KeyError :
119 + raise HTTPError(httplib.NOT_FOUND)
120 + try :
121 + query = dict(cgi.parse_qsl(url.query))
122 + # jQuery may add _ in query for cache control, let's drop it
123 + query.pop("_", None)
124 + except :
125 + raise HTTPError(httplib.BAD_REQUEST, "invalid query")
126 + content_type, data = handler(**query)
127 + self.send_response(httplib.OK)
128 + self.send_header("Content-type", content_type)
129 + self.send_header("Content-length", len(data))
130 + self.end_headers()
131 + self.wfile.write(data)
132 + except HTTPError :
133 + c, v, t = sys.exc_info()
134 + self.send_response(v.code)
135 + self.send_header("Content-type", "text/html")
136 + for hname, hdata in v.headers.iteritems() :
137 + self.send_header(hname, hdata)
138 + self.end_headers()
139 + self.wfile.write("<html><title>%s</title></head>"
140 + "<body><p>%s</p></body>" % (v.answer, v.message))
141 + if v.code == 500 :
142 + traceback.print_exception(*v.debug)
143 +
144 +class HTTPServer (BaseHTTPServer.HTTPServer):
145 + def __init__ (self, server_address, root):
146 + BaseHTTPServer.HTTPServer.__init__(self, server_address,
147 + HTTPRequestHandler)
148 + self.root = root
149 + self.key = "".join(base64.b64encode(
150 + "".join(chr(random.getrandbits(8)) for i in range(15)),
151 + "-_").split())
152 + def __getitem__ (self, path) :
153 + try :
154 + key, path = path.lstrip("/").split("/", 1)
155 + except :
156 + raise HTTPError(httplib.FORBIDDEN)
157 + if key != self.key :
158 + raise HTTPError(httplib.FORBIDDEN)
159 + return self.root[path]
160 +
161 +##
162 +##
163 +##
164 +
165 +if __name__ == '__main__':
166 + class HelloNode (Node) :
167 + @http("text/plain")
168 + def hello (self, first, last) :
169 + return "Hello %s %s!" % (first.capitalize(), last.capitalize())
170 + try :
171 + httpd = HTTPServer(('', 1234), HelloNode(r=DirNode(".")))
172 + httpd.serve_forever()
173 + except KeyboardInterrupt :
174 + print "\rGoobye"
1 +<div class="about">
2 + <div class="title">SNAKES simulator toolkit</div>
3 + <div class="subtitle">(C) 2014 Franck Pommereau</div>
4 + <p><a href="http://www.ibisc.univ-evry.fr/~fpommereau/SNAKES"
5 + target="_blank">SNAKES homepage</a></p>
6 +</div>
1 +Well, you can tell by the way I use my walk,
2 +I'm a woman's man: no time to talk.
3 +Music loud and women warm, I've been kicked around
4 +Since I was born.
5 +And now it's all right. it's ok.
6 +And you may look the other way.
7 +We can try to understand
8 +The new york times effect on man.
9 +Whether you're a brother or whether you're a mother,
10 +You're stayin alive, stayin alive.
11 +Feel the city breakin and everybody shakin,
12 +And were stayin alive, stayin alive.
13 +Ah, ha, ha, ha, stayin alive, stayin alive.
14 +Ah, ha, ha, ha, stayin alive.
15 +Well now, I get low and I get high,
16 +And if I can't get either, I really try.
17 +Got the wings of heaven on my shoes.
18 +I'm a dancin man and I just can't lose.
19 +You know it's all right.its ok.
20 +I'll live to see another day.
21 +We can try to understand
22 +The new york times effect on man.
23 +Whether you're a brother or whether you're a mother,
24 +You're stayin alive, stayin alive.
25 +Feel the city breakin and everybody shakin,
26 +And were stayin alive, stayin alive.
27 +Ah, ha, ha, ha, stayin alive, stayin alive.
28 +Ah, ha, ha, ha, stayin alive.
29 +Life goin nowhere.somebody help me.
30 +Somebody help me, yeah.
31 +Life goin nowhere.somebody help me.
32 +Somebody help me, yeah. stayin alive.
33 +Well, you can tell by the way I use my walk,
34 +I'm a woman's man: no time to talk.
35 +Music loud and women warm,
36 +I've been kicked around since I was born.
37 +And now it's all right. it's ok.
38 +And you may look the other way.
39 +We can try to understand
40 +The new york times effect on man.
41 +Whether you're a brother or whether you're a mother,
42 +You're stayin alive, stayin alive.
43 +Feel the city breakin and everybody shakin,
44 +And were stayin alive, stayin alive.
45 +Ah, ha, ha, ha, stayin alive, stayin alive.
46 +Ah, ha, ha, ha, stayin alive.
47 +Life goin nowhere.somebody help me.
48 +Somebody help me, yeah.
49 +Life goin nowhere.somebody help me, yeah.
50 +I'm stayin alive.
1 +<html>
2 + <head>
3 + <script type="text/javascript">
4 + var server = {key : "%(key)s",
5 + url : "%(url)s",
6 + host : "%(host)s",
7 + port : "%(port)s"};
8 + </script>
9 + <script type="text/javascript" src="r/jquery.min.js"></script>
10 + <script type="text/javascript" src="r/jquery.periodic.js"></script>
11 + <script type="text/javascript" src="r/simulator.js"></script>
12 + <link type="text/css" href="r/simulator.css" rel="stylesheet"/>
13 + <link type="text/css" href="r/model.css" rel="stylesheet"/>
14 + <link type="text/css" href="r/trace.css" rel="stylesheet"/>
15 + <link type="text/css" href="r/about.css" rel="stylesheet"/>
16 + </head>
17 + <body>
18 + <div id="alive">
19 + <ul class="ui">
20 + <li><a id="ui-reset" href="#">Reset simulation</a></li>
21 + <li><a id="ui-quit" href="#">Stop server</a></li>
22 + <li><a id="ui-help" href="#">Help</a></li>
23 + <li><a id="ui-about" href="#">About</a></li>
24 + </ul>
25 + <span class="ping">Starting...</span>
26 + </div>
27 + <div id="model">%(model)s</div>
28 + <div id="trace"></div>
29 + <div id="about">%(about)s</div>
30 + </body>
31 +</html>
This diff is collapsed. Click to expand it.
1 +/*!
2 + * jQuery periodic plugin
3 + *
4 + * Copyright 2010, Tom Anderson
5 + * Dual licensed under the MIT or GPL Version 2 licenses.
6 + *
7 + */
8 +
9 +jQuery.periodic = function (options, callback) {
10 +
11 + // if the first argument is a function then assume the options aren't being passed
12 + if (jQuery.isFunction(options)) {
13 + callback = options;
14 + options = {};
15 + }
16 +
17 + // Merge passed settings with default values
18 + var settings = jQuery.extend({}, jQuery.periodic.defaults, {
19 + ajax_complete : ajaxComplete,
20 + increment : increment,
21 + reset : reset,
22 + cancel : cancel
23 + }, options);
24 +
25 + // bookkeeping variables
26 + settings.cur_period = settings.period;
27 + settings.tid = false;
28 + var prev_ajax_response = '';
29 +
30 + run();
31 +
32 + // return settings so user can tweak them externally
33 + return settings;
34 +
35 + // run (or restart if already running) the looping construct
36 + function run() {
37 + // clear/stop existing timer (multiple calls to run() won't result in multiple timers)
38 + cancel();
39 + // let it rip!
40 + settings.tid = setTimeout(function() {
41 + // set the context (this) for the callback to the settings object
42 + callback.call(settings);
43 +
44 + // compute the next value for cur_period
45 + increment();
46 +
47 + // queue up the next run
48 + if(settings.tid)
49 + run();
50 + }, settings.cur_period);
51 + }
52 +
53 + // utility function for use with ajax calls
54 + function ajaxComplete(xhr, status) {
55 + if (status === 'success' && prev_ajax_response !== xhr.responseText) {
56 + // reset the period whenever the response changes
57 + prev_ajax_response = xhr.responseText;
58 + reset();
59 + }
60 + }
61 +
62 + // compute the next delay
63 + function increment() {
64 + settings.cur_period *= settings.decay;
65 + if (settings.cur_period < settings.period) {
66 + // don't let it drop below the minimum
67 + reset();
68 + } else if (settings.cur_period > settings.max_period) {
69 + settings.cur_period = settings.max_period;
70 + if (settings.on_max !== undefined) {
71 + // call the user-supplied callback if we reach max_period
72 + settings.on_max.call(settings);
73 + }
74 + }
75 + }
76 +
77 + function reset() {
78 + settings.cur_period = settings.period;
79 + // restart with the new timeout
80 + run();
81 + }
82 +
83 + function cancel() {
84 + clearTimeout(settings.tid);
85 + settings.tid = null;
86 + }
87 +
88 + // other functions we might want to implement
89 + function pause() {}
90 + function resume() {}
91 + function log() {}
92 +};
93 +
94 +jQuery.periodic.defaults = {
95 + period : 4000, // 4 sec.
96 + max_period : 1800000, // 30 min.
97 + decay : 1.5, // time period multiplier
98 + on_max : undefined // called if max_period is reached
99 +};
...\ No newline at end of file ...\ No newline at end of file
1 +#model h1 {
2 + display: block;
3 + text-align: center;
4 +}
...\ No newline at end of file ...\ No newline at end of file
1 +<ul>
2 +<li><b>Net:</b> <span id="net"></span></li>
3 +<li><b>State:</b> <span id="state"></span></li>
4 +<li><b>Marking:</b> <ul id="marking"></ul></li>
5 +<li><b>Modes:</b> <ul id="modes"></ul></li>
6 +</ul>
1 +body {
2 + font-family: sans-serif;
3 +}
4 +
5 +#alive {
6 + border: solid 1px #AAA;
7 + border-radius: 5px;
8 + padding: 5px 10px;
9 + margin: 5px;
10 + background-color: #DDD;
11 + overflow:auto;
12 +}
13 +
14 +#alive .ui {
15 + display: inline;
16 + list-style: none;
17 + margin: 0px;
18 + padding: 0px;
19 +}
20 +
21 +#alive .ui li {
22 + display: inline;
23 + border: solid 1px #AAA;
24 + padding: 5px 10px;
25 + margin: 0px 3px;
26 + background-color: #EEE;
27 +}
28 +
29 +#alive .ui a {
30 + text-decoration: none;
31 + color: #333;
32 +}
33 +
34 +#alive .ui li:hover {
35 + background-color: #FFF;
36 +}
37 +
38 +#alive .ui a:hover {
39 + color: #A33;
40 +}
41 +
42 +#alive .ping {
43 + color: #DDD;
44 + float: right;
45 +}
46 +
47 +#model {
48 + border: solid 1px #AAA;
49 + border-radius: 5px;
50 + padding: 5px 10px;
51 + margin: 5px;
52 + background-color: #EEE;
53 + overflow:auto;
54 +}
55 +
56 +#trace {
57 + border: solid 1px #AAA;
58 + border-radius: 5px;
59 + padding: 5px 10px;
60 + margin: 5px;
61 + background-color: #EEE;
62 + overflow:auto;
63 +}
64 +
65 +#about {
66 + display: none;
67 +}
68 +
69 +#dialog {
70 + display: none;
71 + position: fixed;
72 + z-index: 2;
73 + top: 10%;
74 + left: 20%;
75 + width: 60%;
76 + border: solid 2px #AAA;
77 + border-radius: 5px;
78 + padding: 20px;
79 + background-color: #FFF;
80 + overflow:auto;
81 +}
82 +
83 +#dialog-bg {
84 + display: none;
85 + position: fixed;
86 + z-index: 1;
87 + top: 0px;
88 + left: 0px;
89 + width: 100%;
90 + height: 100%;
91 + background-color: #000;
92 + margin: 0px;
93 +}
94 +
95 +#dialog-close {
96 + display: inline;
97 + float: right;
98 + border: solid 1px #AAA;
99 + padding: 5px 10px;
100 + margin: 0px 3px;
101 + background-color: #EEE;
102 + text-decoration: none;
103 + color: #333;
104 +}
105 +
106 +#dialog-close:hover {
107 + background-color: #FFF;
108 + color: #A33;
109 +}
110 +
111 +.dialog p {
112 + margin: 10px 20px 0px 20px;
113 +}
114 +
115 +.dialog .title {
116 + margin: 0px 20px 5px 20px;
117 + font-weight: bold;
118 + text-align: center;
119 +}
120 +
121 +.dialog .subtitle {
122 + margin: 0px 20px 5px 20px;
123 + text-align: center;
124 +}
...\ No newline at end of file ...\ No newline at end of file
1 +function addcss (css) {
2 + $("head").append("<style type='text/css'>" + css + "</style>");
3 +}
4 +
5 +function addjs (js) {
6 + $("head").append("<script type='text/javascript'>" + js + "</script>");
7 +}
8 +
9 +function dialog (content) {
10 + $("#dialog").html(content);
11 + $("#dialog").append("<a href='#' id='dialog-close'>close</a>");
12 + $("#dialog-close").click(function() {
13 + $("#dialog-bg").hide();
14 + $("#dialog").hide();
15 + });
16 + $("#dialog").fadeTo(50, 1);
17 + $("#dialog-bg").fadeTo(50, 0.5);
18 +}
19 +
20 +var update = {
21 + settext : function (action) {
22 + $(action.select).text(action.text);
23 + },
24 + sethtml : function (action) {
25 + $(action.select).html(action.html);
26 + },
27 + clear : function (action) {
28 + $(action.select).html("");
29 + },
30 + setlist : function (action) {
31 + ul = $(action.select);
32 + ul.html("");
33 + $.each(action.items, function (num, item) {
34 + ul.append("<li>" + item + "</li>");
35 + });
36 + }
37 +}
38 +
39 +function setstate (state) {
40 + $.each(state.states, function (num, item) {
41 + update[item.do](item);
42 + });
43 + $.each(state.modes, function (num, action) {
44 + ul = $(action.select);
45 + ul.html("");
46 + $.each(action.items, function (pos, item) {
47 + ul.append("<li><a href='#' data-mode='" + state.id + ":"
48 + + pos + "''>" + item + "</a></li>");
49 + a = ul.children().last().children().first();
50 + a.click(function () {
51 + next = $(this).attr("data-mode").split(":");
52 + text = $(this).text();
53 + $("#trace").append("<div class='trace'><div class='state'>"
54 + + state.id + "</div><div class='mode'>"
55 + + text + "</div></div>");
56 + $.get("succ", {state: next[0], mode: next[1]},
57 + function (newstate) {
58 + setstate(newstate);
59 + });
60 + });
61 + });
62 + });
63 +}
64 +
65 +$(document).ready(function() {
66 + /*
67 + * ping server every 10 seconds
68 + */
69 + $("#alive .ping").text("Stayin alive!");
70 + $.periodic({period: 10000, decay:1, max_period: 10000}, function() {
71 + $.get("ping", function(data) {
72 + $("#alive .ping").text(data);
73 + });
74 + });
75 + /*
76 + * setup UI and model
77 + */
78 + $.get("init", function(init) {
79 + /* bind reset button */
80 + $("#ui-reset").click(function() {
81 + $.get("init", {state: 0}, function(data) {
82 + setstate(data.state);
83 + $("#trace").html("");
84 + });
85 + });
86 + /* bind quit button */
87 + $("#ui-quit").click(function() {
88 + $.get("quit", function(data) {
89 + $("#alive .ui").html("").text(data);
90 + });
91 + });
92 + /* dialogs */
93 + $("body").append("<div id='dialog'>"
94 + + "</div><div id='dialog-bg'></div>");
95 + /* build about */
96 + $("#about").children().addClass("dialog");
97 + $("#ui-about").click(function() {
98 + dialog($("#about").html());
99 + });
100 + /* extend menu */
101 + if (init.ui != undefined) {
102 + ui = $("#alive .ui");
103 + /* TODO: fix spacing between these buttons */
104 + $.each(init.ui, function(num, menu) {
105 + ui.append("<li><a id='" + menu.id
106 + + "'href='" + menu.href + "'>"
107 + + menu.label + "</a></li>");
108 + if (menu.script != undefined) {
109 + ui.children().last().click(function() {
110 + eval(menu.script);
111 + });
112 + }
113 + });
114 + }
115 + /* build help */
116 + if (init.help != undefined) {
117 + $.each(init.help, function(key, text) {
118 + /* TODO: create help dic or whatever needed */
119 + });
120 + $("#ui-help").click(function() {
121 + /* TODO: show/hide tooltips for help */
122 + });
123 + } else {
124 + $("#ui-help").remove();
125 + }
126 + /* setup initial state */
127 + setstate(init.state);
128 + });
129 +});
...\ No newline at end of file ...\ No newline at end of file
1 +#trace h1 {
2 + display: block;
3 + text-align: center;
4 +}
...\ No newline at end of file ...\ No newline at end of file