Franck Pommereau

full ABCD simulator

...@@ -14,6 +14,8 @@ from snakes.utils.simul.html import json ...@@ -14,6 +14,8 @@ from snakes.utils.simul.html import json
14 ## error messages 14 ## error messages
15 ## 15 ##
16 16
17 +options = None
18 +
17 ERR_ARG = 1 19 ERR_ARG = 1
18 ERR_OPT = 2 20 ERR_OPT = 2
19 ERR_IO = 3 21 ERR_IO = 3
...@@ -92,6 +94,10 @@ opt.add_option("--headless", ...@@ -92,6 +94,10 @@ opt.add_option("--headless",
92 dest="headless", action="store", default=None, 94 dest="headless", action="store", default=None,
93 help="headless code simulator, with saved parameters", 95 help="headless code simulator, with saved parameters",
94 metavar="JSONFILE") 96 metavar="JSONFILE")
97 +opt.add_option("--port",
98 + dest="port", action="store", default=8000, type=int,
99 + help="port on which the simulator server runs",
100 + metavar="PORT")
95 opt.add_option("-H", "--html", 101 opt.add_option("-H", "--html",
96 dest="html", action="store", default=None, 102 dest="html", action="store", default=None,
97 help="save net as HTML", 103 help="save net as HTML",
...@@ -292,7 +298,7 @@ def main (args=sys.argv[1:], src=None) : ...@@ -292,7 +298,7 @@ def main (args=sys.argv[1:], src=None) :
292 lineno, trace = Checker(net).run() 298 lineno, trace = Checker(net).run()
293 if options.simul : 299 if options.simul :
294 try : 300 try :
295 - simul = Simulator(node, net, draw(net, None)) 301 + simul = Simulator(node, net, draw(net, None), options.port)
296 except : 302 except :
297 bug() 303 bug()
298 simul.start() 304 simul.start()
......
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.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
1 +<!DOCTYPE html>
2 +<html>
3 + <head>
4 + <link type="text/css" href="r/css/bootstrap-theme.css" rel="stylesheet"/>
5 + <link type="text/css" href="r/css/bootstrap.css" rel="stylesheet"/>
6 + <link type="text/css" href="r/css/docs.css" rel="stylesheet"/>
7 + <link type="text/css" href="r/simulator.css" rel="stylesheet"/>
8 + <link type="text/css" href="r/model.css" rel="stylesheet"/>
9 + <script src="r/jquery.min.js"></script>
10 + <script src="r/js/bootstrap.min.js"></script>
11 + <script src="r/jquery.periodic.js"></script>
12 + <script src="r/js/bootstrap.file-input.js"></script>
13 + <script src="r/d3.min.js"></script>
14 + <script src="r/js/petri.js"></script>
15 + <script src="r/simulator.js"></script>
16 + </head>
17 + <style>
18 + path {
19 + stroke: steelblue;
20 + stroke-width: 2;
21 + fill: none;
22 + }
23 +
24 + line {
25 + stroke: black;
26 + }
27 +
28 + text {
29 + font-family: Arial;
30 + font-size: 9pt;
31 + }
32 +
33 + </style>
34 + <body>
35 +
36 + <header class="navbar navbar-static-top">
37 + <div class="container">
38 + <nav class="navbar navbar-default" role="navigation">
39 + <div class="container-fluid">
40 + <div class="navbar-header"><button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-6"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Simulation SNAKES</a></div>
41 + <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-6">
42 + <ul id="nav_sim" class="nav navbar-nav">
43 + <li><a href="#" id="ui-reset">Reset Simulation</a></li>
44 + <li><a href="#" id="ui-quit">Stop Simulation</a></li>
45 + <li><a href="#" id="ui-help">Help</a></li>
46 + </ul>
47 + </div>
48 + </div>
49 + </nav>
50 + </div>
51 + </header>
52 + <div class="container">
53 +
54 + %(model)s
55 +
56 + <div class="modal fade" id="about" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
57 + <div class="modal-dialog">
58 + <div class="modal-content">
59 + <div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
60 + <h4 class="modal-title" id="myModalLabel">Petri Net</h4>
61 + </div>
62 + <div class="modal-body">
63 + <p><span class="title">ABCD simulator is part of the SNAKES toolkit</span><br /> (C) 2014 Franck Pommereau</p>
64 + <p><a href="http://www.ibisc.univ-evry.fr/~fpommereau/SNAKES" target="_blank">SNAKES homepage</a></p>
65 + </div>
66 + <div class="modal-footer"><button type="button" class="btn btn-default" data-dismiss="modal">Close</button></div>
67 + </div>
68 + </div>
69 + </div>
70 +<script>
71 + $(document).ready(function(){
72 + $.simisc({
73 + "nav":{
74 + "about": {
75 + "text": "About",
76 + "attr": {
77 + "id":"ui-about",
78 + "data-toggle": "modal",
79 + "data-target": "#about"
80 + }
81 + },
82 + "net": {
83 + "text": "Petri Net",
84 + "attr": {
85 + "id":"ui-net",
86 + "data-toggle": "modal",
87 + "data-target": "#net"
88 + }
89 + }
90 + },
91 + "graph": {
92 + "activate": false
93 + }
94 + });
95 + });
96 +</script>
97 +</body>
98 +</html>
This diff could not be displayed because it is too large.
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 +$.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 +/*
2 + Bootstrap - File Input
3 + ======================
4 +
5 + This is meant to convert all file input tags into a set of elements that displays consistently in all browsers.
6 +
7 + Converts all
8 + <input type="file">
9 + into Bootstrap buttons
10 + <a class="btn">Browse</a>
11 +
12 +*/
13 +$(function() {
14 +
15 +$.fn.bootstrapFileInput = function() {
16 +
17 + this.each(function(i,elem){
18 +
19 + var $elem = $(elem);
20 +
21 + // Maybe some fields don't need to be standardized.
22 + if (typeof $elem.attr('data-bfi-disabled') != 'undefined') {
23 + return;
24 + }
25 +
26 + // Set the word to be displayed on the button
27 + var buttonWord = 'Browse';
28 +
29 + if (typeof $elem.attr('title') != 'undefined') {
30 + buttonWord = $elem.attr('title');
31 + }
32 +
33 + // Start by getting the HTML of the input element.
34 + // Thanks for the tip http://stackoverflow.com/a/1299069
35 + var input = $('<div>').append( $elem.eq(0).clone() ).html();
36 + var className = '';
37 +
38 + if (!!$elem.attr('class')) {
39 + className = ' ' + $elem.attr('class');
40 + }
41 +
42 + // Now we're going to replace that input field with a Bootstrap button.
43 + // The input will actually still be there, it will just be float above and transparent (done with the CSS).
44 + $elem.replaceWith('<a class="file-input-wrapper btn btn-default' + className + '">'+buttonWord+input+'</a>');
45 + })
46 +
47 + // After we have found all of the file inputs let's apply a listener for tracking the mouse movement.
48 + // This is important because the in order to give the illusion that this is a button in FF we actually need to move the button from the file input under the cursor. Ugh.
49 + .promise().done( function(){
50 +
51 + // As the cursor moves over our new Bootstrap button we need to adjust the position of the invisible file input Browse button to be under the cursor.
52 + // This gives us the pointer cursor that FF denies us
53 + $('.file-input-wrapper').mousemove(function(cursor) {
54 +
55 + var input, wrapper,
56 + wrapperX, wrapperY,
57 + inputWidth, inputHeight,
58 + cursorX, cursorY;
59 +
60 + // This wrapper element (the button surround this file input)
61 + wrapper = $(this);
62 + // The invisible file input element
63 + input = wrapper.find("input");
64 + // The left-most position of the wrapper
65 + wrapperX = wrapper.offset().left;
66 + // The top-most position of the wrapper
67 + wrapperY = wrapper.offset().top;
68 + // The with of the browsers input field
69 + inputWidth= input.width();
70 + // The height of the browsers input field
71 + inputHeight= input.height();
72 + //The position of the cursor in the wrapper
73 + cursorX = cursor.pageX;
74 + cursorY = cursor.pageY;
75 +
76 + //The positions we are to move the invisible file input
77 + // The 20 at the end is an arbitrary number of pixels that we can shift the input such that cursor is not pointing at the end of the Browse button but somewhere nearer the middle
78 + moveInputX = cursorX - wrapperX - inputWidth + 20;
79 + // Slides the invisible input Browse button to be positioned middle under the cursor
80 + moveInputY = cursorY- wrapperY - (inputHeight/2);
81 +
82 + // Apply the positioning styles to actually move the invisible file input
83 + input.css({
84 + left:moveInputX,
85 + top:moveInputY
86 + });
87 + });
88 +
89 + $('.file-input-wrapper input[type=file]').change(function(){
90 +
91 + var fileName;
92 + fileName = $(this).val();
93 +
94 + // Remove any previous file names
95 + $(this).parent().next('.file-input-name').remove();
96 + if (!!$(this).prop('files') && $(this).prop('files').length > 1) {
97 + fileName = $(this)[0].files.length+' files';
98 + //$(this).parent().after('<span class="file-input-name">'+$(this)[0].files.length+' files</span>');
99 + }
100 + else {
101 + // var fakepath = 'C:\\fakepath\\';
102 + // fileName = $(this).val().replace('C:\\fakepath\\','');
103 + fileName = fileName.substring(fileName.lastIndexOf('\\')+1,fileName.length);
104 + }
105 +
106 + $(this).parent().after('<span class="file-input-name">'+fileName+'</span>');
107 + });
108 +
109 + });
110 +
111 +};
112 +
113 +// Add the styles before the first stylesheet
114 +// This ensures they can be easily overridden with developer styles
115 +var cssHtml = '<style>'+
116 + '.file-input-wrapper { overflow: hidden; position: relative; cursor: pointer; z-index: 1; }'+
117 + '.file-input-wrapper input[type=file], .file-input-wrapper input[type=file]:focus, .file-input-wrapper input[type=file]:hover { position: absolute; top: 0; left: 0; cursor: pointer; opacity: 0; filter: alpha(opacity=0); z-index: 99; outline: 0; }'+
118 + '.file-input-name { margin-left: 8px; }'+
119 + '</style>';
120 +$('link[rel=stylesheet]').eq(0).before(cssHtml);
121 +
122 +});
...\ No newline at end of file ...\ No newline at end of file
This diff is collapsed. Click to expand it.
1 +$(document).ready(function(){
2 + $(".abcd .action, .abcd .instance").each(function(){
3 + var objet = this;
4 + $(".action, .instance").each(function(){
5 + if ($(this).attr("data-abcd") == "#" + $(objet).attr("id")){
6 + $(this).html($(objet).html());
7 + }
8 + });
9 + });
10 +
11 + $(".action, .instance, .buffer, .proto").mouseover(function(){
12 +
13 + $(this).addClass("highlight_simul");
14 + $($(this).attr("data-abcd")).addClass("highlight_simul");
15 + $($(this).attr("data-tree")).addClass("highlight_simul");
16 + $($(this).attr("data-net")).addClass("highlight_simul");
17 +
18 + }).mouseout(function(){
19 +
20 + $(this).removeClass("highlight_simul");
21 + $($(this).attr("data-abcd")).removeClass("highlight_simul");
22 + $($(this).attr("data-tree")).removeClass("highlight_simul");
23 + $($(this).attr("data-net")).removeClass("highlight_simul");
24 +
25 + });
26 +});
...\ No newline at end of file ...\ No newline at end of file
1 /* ABCD source code */ 1 /* ABCD source code */
2 2
3 -#model .abcd {
4 - border: solid 1px #DDD;
5 - border-radius: 5px;
6 - padding: 5px 10px;
7 - margin: 5px;
8 - background-color: #F4F4F4;
9 - overflow: auto;
10 - float: left;
11 -}
12 -
13 #model .abcd .comment { 3 #model .abcd .comment {
14 color: #888; 4 color: #888;
15 } 5 }
...@@ -58,22 +48,10 @@ ...@@ -58,22 +48,10 @@
58 background-color: #B6F8AE; 48 background-color: #B6F8AE;
59 } 49 }
60 50
61 -#model .abcd .highlight { 51 +#model .abcd .highlight_simul {
62 background-color: yellow; 52 background-color: yellow;
63 } 53 }
64 54
65 -/* Objects tree */
66 -
67 -#model .tree {
68 - border: solid 1px #DDD;
69 - border-radius: 5px;
70 - padding: 5px 10px;
71 - margin: 5px;
72 - background-color: #F4F4F4;
73 - overflow: auto;
74 - font-family: monospace;
75 - float: left;
76 -}
77 55
78 #model .tree .buffer .kw { 56 #model .tree .buffer .kw {
79 color: #800; 57 color: #800;
...@@ -127,20 +105,8 @@ ...@@ -127,20 +105,8 @@
127 background-color: #B6F8AE; 105 background-color: #B6F8AE;
128 } 106 }
129 107
130 -#model .tree .highlight { 108 +#model .tree .highlight_simul {
131 background-color: yellow; 109 background-color: yellow;
132 } 110 }
133 111
134 -/* Petri net picture */
135 -
136 -#model .petrinet {
137 - border: solid 1px #DDD;
138 - border-radius: 5px;
139 - padding: 5px 10px;
140 - margin: 5px;
141 - background-color: #FFF;
142 - overflow: auto;
143 - clear: both;
144 - display: none;
145 -}
146 112
......
1 -<h1><tt>%(filename)s</tt></h1> 1 +<div class="page-header">
2 -%(abcd)s 2 + <h1><tt>%(filename)s</tt> <small> powered by Franck</small></h1>
3 -%(tree)s 3 +</div>
4 -%(net)s 4 +<div class="row">
5 + <div class="col-md-3">
6 +
7 + <div class="row">
8 + <h3>Player</h3>
9 + <div id="player"></div>
10 + </div>
11 + </div>
12 +</div>
13 +<div id="model" class="row">
14 + <div class="col-md-6">
15 + <div class="row">
16 + <h3>ABCD</h3>
17 + <div class="abcd">%(abcd)s</div>
18 + </div>
19 +
20 + </div>
21 + <div class=col-md-6>
22 + <div class="row">
23 + <h3>Tree</h3>
24 + <div class="tree">%(tree)s</div>
25 + </div>
26 + </div>
27 +
28 + <div class="col-md-12">
29 + <div id="trace_zone"></div>
30 + </div>
31 +</div>
32 +
33 +<div class="modal fade" id="net" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
34 + <div class="modal-dialog" style="width:auto;">
35 + <div class="modal-content" style="overflow: scroll;">
36 + %(net)s
37 + </div>
38 + </div>
39 +</div>
...\ No newline at end of file ...\ No newline at end of file
......
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 + /* TODO: fix position when dialog has a horizontal scrollbar */
97 + display: block;
98 + float: right;
99 + border: solid 1px #AAA;
100 + padding: 5px 10px;
101 + margin: 0px 3px;
102 + background-color: #EEE;
103 + text-decoration: none;
104 + color: #333;
105 +}
106 +
107 +#dialog-close:hover {
108 + background-color: #FFF;
109 + color: #A33;
110 +}
111 +
112 +.dialog p {
113 + margin: 10px 20px 0px 20px;
114 +}
115 +
116 +.dialog .title {
117 + margin: 0px 20px 5px 20px;
118 + font-weight: bold;
119 + text-align: center;
120 +}
121 +
122 +.dialog .subtitle {
123 + margin: 0px 20px 5px 20px;
124 + text-align: center;
125 +}
...\ No newline at end of file ...\ No newline at end of file
This diff is collapsed. Click to expand it.
...@@ -78,9 +78,9 @@ class ABCDSimulator (BaseSimulator) : ...@@ -78,9 +78,9 @@ class ABCDSimulator (BaseSimulator) :
78 } 78 }
79 79
80 class Simulator (BaseHTTPSimulator) : 80 class Simulator (BaseHTTPSimulator) :
81 - def __init__ (self, node, net, gv) : 81 + def __init__ (self, node, net, gv, port) :
82 simul = ABCDSimulator(node, net, gv) 82 simul = ABCDSimulator(node, net, gv)
83 - BaseHTTPSimulator.__init__(self, net, simulator=simul) 83 + BaseHTTPSimulator.__init__(self, net, simulator=simul, port=port)
84 def init_model (self) : 84 def init_model (self) :
85 return self.res["model.html"] % self.simul.info 85 return self.res["model.html"] % self.simul.info
86 def init_ui (self) : 86 def init_ui (self) :
......
1 import snakes 1 import snakes
2 from snakes.utils.simul.httpd import * 2 from snakes.utils.simul.httpd import *
3 from snakes.utils.simul.html import H 3 from snakes.utils.simul.html import H
4 +from snakes.utils.simul import logger as log
4 import multiprocessing, time, sys, os.path, signal, inspect, glob 5 import multiprocessing, time, sys, os.path, signal, inspect, glob
5 import operator 6 import operator
6 7
...@@ -35,10 +36,6 @@ class StateSpace (dict) : ...@@ -35,10 +36,6 @@ class StateSpace (dict) :
35 def modes (self, state) : 36 def modes (self, state) :
36 return self[state].modes 37 return self[state].modes
37 38
38 -def log (message) :
39 - sys.stderr.write("[simulator] %s\n" % message.strip())
40 - sys.stderr.flush()
41 -
42 shutdown = multiprocessing.Event() 39 shutdown = multiprocessing.Event()
43 ping = multiprocessing.Event() 40 ping = multiprocessing.Event()
44 41
...@@ -64,8 +61,7 @@ class WatchDog (multiprocessing.Process) : ...@@ -64,8 +61,7 @@ class WatchDog (multiprocessing.Process) :
64 if ping.wait(self.timeout) : 61 if ping.wait(self.timeout) :
65 ping.clear() 62 ping.clear()
66 else : 63 else :
67 - log("client not active - %s\n" 64 + log.info("client has gone", "simul")
68 - % time.strftime("%d/%b/%Y %H:%M:%S"))
69 break 65 break
70 except KeyboardInterrupt : 66 except KeyboardInterrupt :
71 pass 67 pass
...@@ -138,14 +134,12 @@ class BaseHTTPSimulator (Node) : ...@@ -138,14 +134,12 @@ class BaseHTTPSimulator (Node) :
138 dirs = {} 134 dirs = {}
139 for cls in reversed(inspect.getmro(self.__class__)[:-2]) : 135 for cls in reversed(inspect.getmro(self.__class__)[:-2]) :
140 path = os.path.dirname(inspect.getsourcefile(cls)) 136 path = os.path.dirname(inspect.getsourcefile(cls))
141 - for pattern in respatt + ["resources/*.js", 137 + for pattern in respatt + ["resources/*/*.*",
142 - "resources/*.css", 138 + "resources/*.*"] :
143 - "resources/*.html",
144 - "resources/alive.txt"] :
145 for res in glob.glob(os.path.join(path, pattern)) : 139 for res in glob.glob(os.path.join(path, pattern)) :
146 if os.path.isfile(res) : 140 if os.path.isfile(res) :
147 with open(res) as infile : 141 with open(res) as infile :
148 - self.res[os.path.basename(res)] = infile.read() 142 + self.res[res[len(path + "resources/")+1:]] = infile.read()
149 elif os.path.isdir(res) : 143 elif os.path.isdir(res) :
150 dirs[os.path.basename(res)] = DirNode(res) 144 dirs[os.path.basename(res)] = DirNode(res)
151 else : 145 else :
...@@ -171,7 +165,7 @@ class BaseHTTPSimulator (Node) : ...@@ -171,7 +165,7 @@ class BaseHTTPSimulator (Node) :
171 else : 165 else :
172 self.simul = simulator 166 self.simul = simulator
173 def start (self) : 167 def start (self) :
174 - log("starting at %r" % self.url) 168 + log.info("starting at %r" % self.url, "simul")
175 shutdown.clear() 169 shutdown.clear()
176 ping.clear() 170 ping.clear()
177 self.server.start() 171 self.server.start()
...@@ -179,11 +173,11 @@ class BaseHTTPSimulator (Node) : ...@@ -179,11 +173,11 @@ class BaseHTTPSimulator (Node) :
179 def wait (self) : 173 def wait (self) :
180 try : 174 try :
181 shutdown.wait() 175 shutdown.wait()
182 - log("preparing to shut down...") 176 + log.info("preparing to shut down...", "simul")
183 time.sleep(2) 177 time.sleep(2)
184 except KeyboardInterrupt : 178 except KeyboardInterrupt :
185 shutdown.set() 179 shutdown.set()
186 - log("shuting down...") 180 + log.info("shuting down...", "simul")
187 sig = getattr(signal, "CTRL_C_EVENT", 181 sig = getattr(signal, "CTRL_C_EVENT",
188 getattr(signal, "SIGTERM", None)) 182 getattr(signal, "SIGTERM", None))
189 if sig is not None : 183 if sig is not None :
...@@ -191,7 +185,7 @@ class BaseHTTPSimulator (Node) : ...@@ -191,7 +185,7 @@ class BaseHTTPSimulator (Node) :
191 os.kill(self.server.pid, sig) 185 os.kill(self.server.pid, sig)
192 if self.watchdog.pid : 186 if self.watchdog.pid :
193 os.kill(self.watchdog.pid, sig) 187 os.kill(self.watchdog.pid, sig)
194 - log("bye!") 188 + log.info("bye!", "simul")
195 def init_index (self) : 189 def init_index (self) :
196 return {"res" : "%sr" % self.url, 190 return {"res" : "%sr" % self.url,
197 "url" : self.url, 191 "url" : self.url,
......
1 import sys, os.path, httplib, cgi, urlparse, functools, mimetypes 1 import sys, os.path, httplib, cgi, urlparse, functools, mimetypes
2 -import os, signal, traceback, random, base64, inspect 2 +import os, traceback, random, base64, inspect, math
3 import BaseHTTPServer 3 import BaseHTTPServer
4 +from snakes.utils.simul import logger as log
4 from snakes.utils.simul.html import json, utf8 5 from snakes.utils.simul.html import json, utf8
5 6
6 ## 7 ##
...@@ -156,6 +157,21 @@ class HTTPRequestHandler (BaseHTTPServer.BaseHTTPRequestHandler) : ...@@ -156,6 +157,21 @@ class HTTPRequestHandler (BaseHTTPServer.BaseHTTPRequestHandler) :
156 "<body><p>%s</p></body>" % (v.answer, v.message)) 157 "<body><p>%s</p></body>" % (v.answer, v.message))
157 if v.code == 500 : 158 if v.code == 500 :
158 traceback.print_exception(*v.debug) 159 traceback.print_exception(*v.debug)
160 + def log_request (self, code="-", size="-") :
161 + code = str(code or "-")
162 + method, path, version = self.requestline.split()
163 + if code[0] in "45" :
164 + logger = log.warn
165 + else :
166 + path = path.split("/", 2)[-1]
167 + if len(path) > 28 :
168 + path = "..." + path[-28:]
169 + logger = log.debug
170 + logger("%s %s => %s" % (method, path, code), "httpd")
171 + def log_message (self, format, *args) :
172 + log.info(format % args, "httpd")
173 + def log_error (self, format, *args) :
174 + log.error(format % args, "httpd")
159 175
160 class HTTPServer (BaseHTTPServer.HTTPServer): 176 class HTTPServer (BaseHTTPServer.HTTPServer):
161 def __init__ (self, server_address, root): 177 def __init__ (self, server_address, root):
......
1 +import sys, time, re
2 +
3 +##
4 +## borrowed from http://code.activestate.com/recipes/475116/
5 +##
6 +
7 +class TerminalController:
8 + """
9 + A class that can be used to portably generate formatted output to
10 + a terminal.
11 +
12 + `TerminalController` defines a set of instance variables whose
13 + values are initialized to the control sequence necessary to
14 + perform a given action. These can be simply included in normal
15 + output to the terminal:
16 +
17 + >>> term = TerminalController()
18 + >>> print 'This is '+term.GREEN+'green'+term.NORMAL
19 +
20 + Alternatively, the `render()` method can used, which replaces
21 + '${action}' with the string required to perform 'action':
22 +
23 + >>> term = TerminalController()
24 + >>> print term.render('This is ${GREEN}green${NORMAL}')
25 +
26 + If the terminal doesn't support a given action, then the value of
27 + the corresponding instance variable will be set to ''. As a
28 + result, the above code will still work on terminals that do not
29 + support color, except that their output will not be colored.
30 + Also, this means that you can test whether the terminal supports a
31 + given action by simply testing the truth value of the
32 + corresponding instance variable:
33 +
34 + >>> term = TerminalController()
35 + >>> if term.CLEAR_SCREEN:
36 + ... print 'This terminal supports clearning the screen.'
37 +
38 + Finally, if the width and height of the terminal are known, then
39 + they will be stored in the `COLS` and `LINES` attributes.
40 + """
41 + # Cursor movement:
42 + BOL = '' #: Move the cursor to the beginning of the line
43 + UP = '' #: Move the cursor up one line
44 + DOWN = '' #: Move the cursor down one line
45 + LEFT = '' #: Move the cursor left one char
46 + RIGHT = '' #: Move the cursor right one char
47 +
48 + # Deletion:
49 + CLEAR_SCREEN = '' #: Clear the screen and move to home position
50 + CLEAR_EOL = '' #: Clear to the end of the line.
51 + CLEAR_BOL = '' #: Clear to the beginning of the line.
52 + CLEAR_EOS = '' #: Clear to the end of the screen
53 +
54 + # Output modes:
55 + BOLD = '' #: Turn on bold mode
56 + BLINK = '' #: Turn on blink mode
57 + DIM = '' #: Turn on half-bright mode
58 + REVERSE = '' #: Turn on reverse-video mode
59 + NORMAL = '' #: Turn off all modes
60 +
61 + # Cursor display:
62 + HIDE_CURSOR = '' #: Make the cursor invisible
63 + SHOW_CURSOR = '' #: Make the cursor visible
64 +
65 + # Terminal size:
66 + COLS = None #: Width of the terminal (None for unknown)
67 + LINES = None #: Height of the terminal (None for unknown)
68 +
69 + # Foreground colors:
70 + BLACK = BLUE = GREEN = CYAN = RED = MAGENTA = YELLOW = WHITE = ''
71 +
72 + # Background colors:
73 + BG_BLACK = BG_BLUE = BG_GREEN = BG_CYAN = ''
74 + BG_RED = BG_MAGENTA = BG_YELLOW = BG_WHITE = ''
75 +
76 + _STRING_CAPABILITIES = """
77 + BOL=cr UP=cuu1 DOWN=cud1 LEFT=cub1 RIGHT=cuf1
78 + CLEAR_SCREEN=clear CLEAR_EOL=el CLEAR_BOL=el1 CLEAR_EOS=ed BOLD=bold
79 + BLINK=blink DIM=dim REVERSE=rev UNDERLINE=smul NORMAL=sgr0
80 + HIDE_CURSOR=cinvis SHOW_CURSOR=cnorm""".split()
81 + _COLORS = """BLACK BLUE GREEN CYAN RED MAGENTA YELLOW WHITE""".split()
82 + _ANSICOLORS = "BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE".split()
83 +
84 + def __init__(self, term_stream=sys.stdout):
85 + """
86 + Create a `TerminalController` and initialize its attributes
87 + with appropriate values for the current terminal.
88 + `term_stream` is the stream that will be used for terminal
89 + output; if this stream is not a tty, then the terminal is
90 + assumed to be a dumb terminal (i.e., have no capabilities).
91 + """
92 + # Curses isn't available on all platforms
93 + try: import curses
94 + except: return
95 +
96 + # If the stream isn't a tty, then assume it has no capabilities.
97 + if not term_stream.isatty(): return
98 +
99 + # Check the terminal type. If we fail, then assume that the
100 + # terminal has no capabilities.
101 + try: curses.setupterm()
102 + except: return
103 +
104 + # Look up numeric capabilities.
105 + self.COLS = curses.tigetnum('cols')
106 + self.LINES = curses.tigetnum('lines')
107 +
108 + # Look up string capabilities.
109 + for capability in self._STRING_CAPABILITIES:
110 + (attrib, cap_name) = capability.split('=')
111 + setattr(self, attrib, self._tigetstr(cap_name) or '')
112 +
113 + # Colors
114 + set_fg = self._tigetstr('setf')
115 + if set_fg:
116 + for i,color in zip(range(len(self._COLORS)), self._COLORS):
117 + setattr(self, color, curses.tparm(set_fg, i) or '')
118 + set_fg_ansi = self._tigetstr('setaf')
119 + if set_fg_ansi:
120 + for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
121 + setattr(self, color, curses.tparm(set_fg_ansi, i) or '')
122 + set_bg = self._tigetstr('setb')
123 + if set_bg:
124 + for i,color in zip(range(len(self._COLORS)), self._COLORS):
125 + setattr(self, 'BG_'+color, curses.tparm(set_bg, i) or '')
126 + set_bg_ansi = self._tigetstr('setab')
127 + if set_bg_ansi:
128 + for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
129 + setattr(self, 'BG_'+color, curses.tparm(set_bg_ansi, i) or '')
130 +
131 + def _tigetstr(self, cap_name):
132 + # String capabilities can include "delays" of the form "$<2>".
133 + # For any modern terminal, we should be able to just ignore
134 + # these, so strip them out.
135 + import curses
136 + cap = curses.tigetstr(cap_name) or ''
137 + return re.sub(r'\$<\d+>[/*]?', '', cap)
138 +
139 + def render(self, template):
140 + """
141 + Replace each $-substitutions in the given template string with
142 + the corresponding terminal control string (if it's defined) or
143 + '' (if it's not).
144 + """
145 + return re.sub(r'\$\$|\${\w+}', self._render_sub, template)
146 +
147 + def _render_sub(self, match):
148 + s = match.group()
149 + if s == '$$': return s
150 + else: return getattr(self, s[2:-1])
151 +
152 +##
153 +## functions
154 +##
155 +
156 +_level = {"debug": "MAGENTA",
157 + "info": "BLUE",
158 + "warn": "YELLOW",
159 + "error": "RED"}
160 +
161 +term = TerminalController()
162 +
163 +def log (level, message, header="", date=True, newline=True, clearline=True) :
164 + text = "%s%s[%s%s%s]${NORMAL} %s%s%s" % (
165 + "${BOL}" if clearline else "",
166 + "${%s}" % _level.get(level.lower(), "NORMAL"),
167 + time.strftime("%Y-%m-%d %H:%M:%S") if date else "",
168 + " - " if date and header else "",
169 + header,
170 + message,
171 + "${CLEAR_EOL}" if clearline else "",
172 + "\n" if newline else "")
173 + sys.stderr.write(term.render(text))
174 + sys.stderr.flush()
175 +
176 +def debug (message, header="") :
177 + log("debug", message, header, date=True, newline=False, clearline=True)
178 +
179 +def info (message, header="") :
180 + log("info", message, header, date=True, newline=True, clearline=True)
181 +
182 +def warn (message, header="") :
183 + log("warn", message, header, date=True, newline=True, clearline=True)
184 +
185 +def error (message, header="") :
186 + log("error", message, header, date=True, newline=True, clearline=True)