Ticket #1321: trac_1321-sagenb_graphed.patch

File trac_1321-sagenb_graphed.patch, 193.5 KB (added by mpatel, 12 years ago)

Rado's graph editor. Apply this patch to the sagenb repo. Apply this patch only.

  • new file sagenb/data/graph_editor/graph_editor.html

    # HG changeset patch
    # User Mitesh Patel <qed777@gmail.com>
    # Date 1259033161 28800
    # Node ID 8b5d3cffe0b711a3008e548ec4823f9dd9c4af7d
    # Parent  96dc9920ce447ee8d235e0faa0301d0ad2349155
    #1321/sagenb: A graph editor by Radoslav Kirov
    
    diff --git a/sagenb/data/graph_editor/graph_editor.html b/sagenb/data/graph_editor/graph_editor.html
    new file mode 100644
    - +  
     1<html>
     2  <head>
     3    <title>Graph Editor</title>
     4    <style type="text/css">
     5      body {
     6          font-size: 10pt;
     7      }
     8      canvas {
     9          border: 1px solid;
     10          height: 350px;
     11          width: 350px;
     12          margin: 20px;
     13          float: left;
     14      }
     15      tr.live_slider {
     16          height: 1.75em;
     17      }
     18      div.slider {
     19          width : 150px;
     20      }
     21      #help {
     22          display: hidden;
     23      }
     24      h3 {
     25          color: #aa0;
     26          margin: 10px;
     27      }
     28    </style> 
     29    <script type="text/javascript" src="/javascript/jquery/jquery-1.3.2.min.js"></script>
     30    <link rel="stylesheet" href="/javascript/jqueryui/css/sage/jquery-ui-1.7.2.custom.css" />
     31    <script type="text/javascript" src="/javascript/jqueryui/js/jquery-ui-1.7.2.custom.min.js"></script>
     32    <script type="text/javascript" src="/javascript/graph_editor/processing.editor.min.js"></script>
     33    <script type="text/javascript" src="/javascript/graph_editor/graph_editor.js"></script>
     34  </head>
     35  <body>
     36    <canvas id="canvas"></canvas>
     37    <table>
     38      <tbody>
     39        <tr>
     40          <td>
     41            live:
     42          </td>
     43          <td>
     44            <input type="checkbox" id="live" value="true" />
     45          </td>
     46        </tr>
     47        <tr>
     48          <td>
     49            variable name:
     50          </td>
     51          <td>
     52            <input type="text" id="graph_name" size="20" />
     53          </td>
     54        </tr>
     55        <tr class="live_slider">
     56          <td>
     57            strength:
     58          </td>
     59          <td>
     60            <input type="hidden" id="val_edge" name="val_edge" value="50" />
     61            <div class="slider" id="slider_edge"></div>
     62          </td>
     63        </tr>
     64        <tr class="live_slider">
     65          <td>
     66            length:
     67          </td>
     68          <td>
     69            <input type="hidden" id="val_fixed_length" name="val_fixed_length" value="100" />
     70            <div class="slider" id="slider_fixed_length"></div>
     71          </td>
     72        </tr>
     73      </tbody>
     74    </table>
     75    <input type="button" id="help_button" value="help">
     76    <ul id="help">
     77      <li><h3>move vertex</h3>Vertices are draggable.
     78      <li><h3>create vertex</h3>Click on empty space not too close to existing vertices.
     79      <li><h3>select a vertex</h3>Click on existing vertex.
     80      <li><h3>create/erase edge</h3>Select the first vertex. Click on another vertex (different than the selected one) to turn on/off (toggle) the edge between them.
     81      <li><h3>keep the selected vertex</h3>Hold 'SHIFT' to perserve the selected vertex after creating/erasing an edge.
     82      <li><h3>delete vertex</h3>Double click on vertex or drag to the edge for the frame (be careful, there is no UNDO yet!).
     83    </ul>
     84  </body>
     85</html>
  • new file sagenb/data/graph_editor/graph_editor.js

    diff --git a/sagenb/data/graph_editor/graph_editor.js b/sagenb/data/graph_editor/graph_editor.js
    new file mode 100644
    - +  
     1/*global $, document, p: true, Processing, top, window */
     2/*jslint white: false, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, strict: true, newcap: true, immed: true */
     3"use strict";
     4var edge_list = [], nodes = [], NODES, EDGES, SIZE, NEW_RADIUS,
     5    DOUBLECLICK, LIVE, SPRING, FIXED_LENGTH,
     6    selected_node, dragged_node, dragging_flag, last_click_time,
     7    initial_x, initial_y
     8
     9var edges = [], num_vertices = null, pos = null;
     10
     11NODES = 10;
     12EDGES = 20;
     13SIZE = 350;
     14NEW_RADIUS = 20;
     15DOUBLECLICK = 250;
     16LIVE = false;
     17SPRING = 0.999;
     18FIXED_LENGTH = 100.0;
     19
     20function rand(a, b) {
     21    return a + Math.floor(Math.random() * (b - a));
     22}
     23
     24function Node(x, y) {
     25    this.x = x;
     26    this.y = y;
     27    this.size = 7;
     28}
     29
     30Node.prototype.display = function () {
     31    p.stroke(0);
     32    if (this.selected) {
     33        p.fill(255, 0, 0);
     34        p.ellipse(this.x, this.y, this.size, this.size);
     35    } else {
     36        p.fill(0);
     37        p.ellipse(this.x, this.y, this.size, this.size);
     38    }
     39};
     40
     41Node.prototype.distance_to = function (x, y) {
     42    return Math.sqrt(Math.pow((x - this.x), 2) + Math.pow((y - this.y), 2));
     43};
     44
     45Node.prototype.is_hit = function (x, y) {
     46    return Math.abs(x - this.x) < this.size &&
     47        Math.abs(y - this.y) < this.size;
     48};
     49
     50function Edge(node1, node2) {
     51    this.node1 = node1;
     52    this.node2 = node2;
     53}
     54
     55Edge.prototype.shrink = function () {
     56    var d, gx, gy, mx, my;
     57
     58    mx = (this.node1.x + this.node2.x) / 2;
     59    my = (this.node1.y + this.node2.y) / 2;
     60
     61    if (this.node1 !== dragged_node) {
     62        d = this.node1.distance_to(mx, my);
     63        gx = mx + (this.node1.x - mx) / d * FIXED_LENGTH / 2;
     64        gy = my + (this.node1.y - my) / d * FIXED_LENGTH / 2;
     65        this.node1.x = gx + (this.node1.x - gx) * SPRING;
     66        this.node1.y = gy + (this.node1.y - gy) * SPRING;
     67    }
     68    if (this.node2 !== dragged_node) {
     69        d = this.node2.distance_to(mx, my);
     70        gx = mx + (this.node2.x - mx) / d * FIXED_LENGTH / 2;
     71        gy = my + (this.node2.y - my) / d * FIXED_LENGTH / 2;
     72        this.node2.x = gx + (this.node2.x - gx) * SPRING;
     73        this.node2.y = gy + (this.node2.y - gy) * SPRING;
     74    }
     75};
     76
     77Edge.prototype.display = function () {
     78    if (this.node1.x > SIZE || this.node1.y > SIZE ||
     79        this.node1.x < 0 || this.node1.y < 0 ||
     80        this.node2.x > SIZE || this.node2.y > SIZE ||
     81        this.node2.x < 0 || this.node2.y < 0) {
     82        p.stroke(255, 0, 0);
     83    } else {
     84        if (this.node1.selected || this.node2.selected) {
     85            p.stroke(0, 0, 200);
     86        } else {
     87            p.stroke(0);
     88        }
     89    }
     90    p.line(this.node1.x, this.node1.y, this.node2.x, this.node2.y);
     91};
     92
     93function add_node(node) {
     94    if (nodes.indexOf(node) === -1) {
     95        nodes.push(node);
     96    }
     97}
     98
     99function remove_node(node) {
     100    var edge, i, index;
     101    for (i = edge_list.length - 1; i > -1; i -= 1) {
     102        edge = edge_list[i];
     103        if (edge.node1 === node || edge.node2 === node) {
     104            edge_list.splice(i, 1);
     105        }
     106    }
     107    index = nodes.indexOf(node);
     108    if (index !== -1) {
     109        nodes.splice(index, 1);
     110    }
     111}
     112
     113function add_edge_between_nodes(node1, node2) {
     114    if (node1 === node2) {
     115        // Only simple graphs are implemented so far.
     116        return;
     117    }
     118    edge_list.push(new Edge(node1, node2));
     119    if (nodes.indexOf(node1) === -1) {
     120        nodes.add(node1);
     121    }
     122    if (nodes.indexOf(node2) === -1) {
     123        nodes.add(node2);
     124    }
     125}
     126
     127function toggle_edge(node1, node2) {
     128    var edge, existing = false, i, new_edge;
     129    if (node1 === node2) {
     130        // Only simple graphs are implemented so far.
     131        return;
     132    }
     133    new_edge = new Edge(node1, node2);
     134    for (i = edge_list.length - 1; i > -1; i -= 1) {
     135        edge = edge_list[i];
     136        if ((edge.node1 === new_edge.node1 && edge.node2 === new_edge.node2) ||
     137            (edge.node1 === new_edge.node2 && edge.node2 === new_edge.node1)) {
     138            existing = true;
     139            break;
     140        }
     141    }
     142    if (existing) {
     143        edge_list.splice(i, 1);
     144    } else {
     145        edge_list.push(new_edge);
     146    }
     147}
     148
     149function set_graph() {
     150    var i, n1, n2;
     151
     152    if (!pos) {
     153        for (i = 0; i < NODES; i += 1) {
     154            add_node(new Node(rand(0, SIZE), rand(0, SIZE)));
     155        }
     156        for (i = 0; i < EDGES; i += 1) {
     157            n1 = rand(0, NODES);
     158            n2 = rand(0, NODES);
     159            add_edge_between_nodes(nodes[n1], nodes[n2]);
     160        }
     161    }
     162    for (i = 0; i < num_vertices; i += 1) {
     163        if (pos) {
     164            add_node(new Node(pos[i][0] * 8 * SIZE / 10 + SIZE / 10,
     165                              pos[i][1] * 8 * SIZE / 10 + SIZE / 10));
     166        } else {
     167            add_node(new Node(rand(0, SIZE), rand(0, SIZE)));
     168        }
     169    }
     170    for (i = 0; i < edges.length; i += 1) {
     171        add_edge_between_nodes(nodes[edges[i][0]], nodes[edges[i][1]]);
     172    }
     173    p.draw();
     174}
     175
     176function display_graph() {
     177    var i;
     178    for (i = 0; i < edge_list.length; i += 1) {
     179        edge_list[i].display();
     180        if (LIVE) {
     181            edge_list[i].shrink();
     182        }
     183    }
     184    for (i = 0; i < nodes.length; i += 1) {
     185        nodes[i].display();
     186    }
     187}
     188
     189function setup() {
     190    p.size(SIZE, SIZE);
     191    set_graph();
     192    p.rectMode(p.RADIUS);
     193    p.ellipseMode(p.RADIUS);
     194    p.noLoop();
     195}
     196
     197function update_sliders() {
     198    SPRING = (1 - 1e-2) + 1e-4 * (100 - $('#val_edge').val());
     199    FIXED_LENGTH = $('#val_fixed_length').val();
     200}
     201
     202function draw() {
     203    update_sliders();
     204    p.background(255);
     205    display_graph();
     206}
     207
     208function toggle_live() {
     209    if (LIVE) {
     210        LIVE = false;
     211        p.noLoop();
     212    } else {
     213        LIVE = true;
     214        p.loop();
     215    }
     216}
     217
     218function mousePressed() {
     219    var clicked_node, closest_distance, i, new_distance;
     220    if (!LIVE) {
     221        p.loop();
     222    }
     223    for (i = 0; i < nodes.length; i += 1) {
     224        if (nodes[i].is_hit(p.mouseX, p.mouseY)) {
     225            clicked_node = nodes[i];
     226            break;
     227        }
     228    }
     229    if (!clicked_node) {
     230        closest_distance = SIZE;
     231        for (i = 0; i < nodes.length; i += 1) {
     232            new_distance = nodes[i].distance_to(p.mouseX, p.mouseY);
     233            if (new_distance < closest_distance) {
     234                closest_distance = new_distance;
     235            }
     236        }
     237        if (closest_distance > NEW_RADIUS) {
     238            add_node(new Node(p.mouseX, p.mouseY));
     239        }
     240        return;
     241    } else {
     242        dragged_node = clicked_node;
     243        initial_x = dragged_node.x;
     244        initial_y = dragged_node.y;
     245    }
     246}
     247
     248function mouseDragged() {
     249    if (dragged_node) {
     250        dragging_flag = true;
     251        dragged_node.x = p.mouseX;
     252        dragged_node.y = p.mouseY;
     253    }
     254}
     255
     256function mouseReleased() {
     257    if (dragged_node) {
     258        if (dragging_flag) {
     259            dragging_flag = false;
     260            if (dragged_node.x > SIZE || dragged_node.y > SIZE ||
     261                dragged_node.x < 0 || dragged_node.y < 0) {
     262                remove_node(dragged_node);
     263                if (selected_node === dragged_node) {
     264                    selected_node = false;
     265                }
     266                dragged_node = false;
     267            }
     268        } else {
     269            if (p.millis() - last_click_time < DOUBLECLICK) {
     270                remove_node(dragged_node);
     271                if (selected_node === dragged_node) {
     272                    selected_node = false;
     273                }
     274            } else if (selected_node) {
     275                toggle_edge(selected_node, dragged_node);
     276                if (!p.keyPressed) {
     277                    selected_node.selected = false;
     278                    selected_node = false;
     279                } else {
     280                    if (selected_node === dragged_node) {
     281                        selected_node.selected = false;
     282                        selected_node = false;
     283                    }
     284                }
     285            } else {
     286                selected_node = dragged_node;
     287                selected_node.selected = true;
     288            }
     289        }
     290        dragged_node = false;
     291        last_click_time = p.millis();
     292        p.redraw();
     293    }
     294    if (!LIVE) {
     295        p.noLoop();
     296    }
     297}
     298
     299function mouse_out() {
     300    if (dragged_node) {
     301        dragged_node.x = initial_x;
     302        dragged_node.y = initial_y;
     303        dragged_node = false;
     304    }
     305}
     306
     307function positions_dict() {
     308    var i, out;
     309    out = "{";
     310    for (i = 0; i < nodes.length; i += 1) {
     311        out += i + ":[" + nodes[i].x + "," + (SIZE - nodes[i].y) + "],";
     312    }
     313    return out.substring(0, out.length - 1) + "}";
     314}
     315
     316function adjacency_lists_dict() {
     317    var edge, empty, i, j, node, out;
     318    out = "{";
     319    for (i = 0; i < nodes.length; i += 1) {
     320        out += i + ":[";
     321        node = nodes[i];
     322        empty = true;
     323        for (j = 0; j < edge_list.length; j += 1) {
     324            edge = edge_list[j];
     325            if (edge.node1 === node) {
     326                if (!empty) {
     327                    out += ",";
     328                }
     329                empty = false;
     330                out += nodes.indexOf(edge.node2);
     331            }
     332            if (edge.node2 === node) {
     333                if (!empty) {
     334                    out+=",";
     335                }
     336                empty = false;
     337                out += nodes.indexOf(edge.node1);
     338            }
     339        }
     340        out += "],";
     341    }
     342    return out.substring(0, out.length - 1) + "}";
     343}
     344
     345function update_sage() {
     346    return [adjacency_lists_dict(), positions_dict(), $('#graph_name').val()];
     347}
     348
     349
     350$(document).ready(function () {
     351    var cell_id, cell_outer, loc;
     352
     353    // Retrieve graph data and name from parent document.
     354    loc = window.location.href;
     355    cell_id = parseInt(loc.slice(loc.search('cell_id=') + 8), 10);
     356    cell_outer = $('#cell_outer_' + cell_id, top.document);
     357    eval($('#graph_data_' + cell_id, cell_outer).val());
     358    $('#graph_name').val($('#graph_name_' + cell_id, cell_outer).val());
     359
     360    // Set up processing.js.
     361    p = Processing($('#canvas')[0], '');
     362    p.setup = setup;
     363    p.draw = draw;
     364    p.mouseDragged = mouseDragged;
     365    p.mousePressed = mousePressed;
     366    p.mouseReleased = mouseReleased;
     367    p.init();
     368
     369    $('#help').hide();
     370
     371    $('#help_button').click(function () {
     372        $('#help').toggle();
     373    });
     374
     375    $('#live').click(function() {
     376        toggle_live();
     377    });
     378
     379    $('#slider_edge').slider({
     380        min: 0,
     381        max: 100,
     382        value: 50,
     383        slide: function(event, ui) {
     384            $('#val_edge').val(ui.value);
     385        }
     386    });
     387
     388    $('#slider_fixed_length').slider({
     389        min: 0,
     390        max: 200,
     391        value: 100,
     392        slide: function(event, ui) {
     393            $('#val_fixed_length').val(ui.value);
     394        }
     395    });
     396});
  • new file sagenb/data/graph_editor/processing.editor.js

    diff --git a/sagenb/data/graph_editor/processing.editor.js b/sagenb/data/graph_editor/processing.editor.js
    new file mode 100644
    - +  
     1(function() {
     2  this.Processing = function Processing(aElement, aCode) {
     3    if (typeof aElement == "string") aElement = document.getElementById(aElement);
     4    var p = buildProcessing(aElement);
     5    if (aCode) p.init(aCode);
     6    return p;
     7  };
     8
     9  function log() {
     10    try {
     11      console.log.apply(console, arguments);
     12    } catch(e) {
     13      try {
     14        opera.postError.apply(opera, arguments);
     15      } catch(e) {}
     16    }
     17  }
     18  var parse = Processing.parse = function parse(aCode, p) {
     19    aCode = aCode.replace(/\/\/ .*\n/g, "\n");
     20    aCode = aCode.replace(/([^\s])%([^\s])/g, "$1 % $2");
     21    aCode = aCode.replace(/(?:static )?(\w+ )(\w+)\s*(\([^\)]*\)\s*{)/g, function(all, type, name, args) {
     22      if (name == "if" || name == "for" || name == "while") {
     23        return all;
     24      } else {
     25        return "Processing." + name + " = function " + name + args;
     26      }
     27    });
     28    aCode = aCode.replace(/\.length\(\)/g, ".length");
     29    aCode = aCode.replace(/([\(,]\s*)(\w+)((?:\[\])+| )\s*(\w+\s*[\),])/g, "$1$4");
     30    aCode = aCode.replace(/([\(,]\s*)(\w+)((?:\[\])+| )\s*(\w+\s*[\),])/g, "$1$4");
     31    aCode = aCode.replace(/new (\w+)((?:\[([^\]]*)\])+)/g, function(all, name, args) {
     32      return "new ArrayList(" + args.slice(1, -1).split("][").join(", ") + ")";
     33    });
     34    aCode = aCode.replace(/(?:static )?\w+\[\]\s*(\w+)\[?\]?\s*=\s*{.*?};/g, function(all) {
     35      return all.replace(/{/g, "[").replace(/}/g, "]");
     36    });
     37    var intFloat = /(\n\s*(?:int|float)(?:\[\])?(?:\s*|[^\(]*?,\s*))([a-z]\w*)(;|,)/i;
     38    while (intFloat.test(aCode)) {
     39      aCode = aCode.replace(new RegExp(intFloat), function(all, type, name, sep) {
     40        return type + " " + name + " = 0" + sep;
     41      });
     42    }
     43    aCode = aCode.replace(/(?:static )?(\w+)((?:\[\])+| ) *(\w+)\[?\]?(\s*[=,;])/g, function(all, type, arr, name, sep) {
     44      if (type == "return") return all;
     45      else return "var " + name + sep;
     46    });
     47    aCode = aCode.replace(/=\s*{((.|\s)*?)};/g, function(all, data) {
     48      return "= [" + data.replace(/{/g, "[").replace(/}/g, "]") + "]";
     49    });
     50    aCode = aCode.replace(/static\s*{((.|\n)*?)}/g, function(all, init) {
     51      return init;
     52    });
     53    aCode = aCode.replace(/super\(/g, "superMethod(");
     54    var classes = ["int", "float", "boolean", "string"];
     55
     56    function ClassReplace(all, name, extend, vars, last) {
     57      classes.push(name);
     58      var static = "";
     59      vars = vars.replace(/final\s+var\s+(\w+\s*=\s*.*?;)/g, function(all, set) {
     60        static += " " + name + "." + set;
     61        return "";
     62      });
     63      return "function " + name + "() {with(this){\n  " + (extend ? "var __self=this;function superMethod(){extendClass(__self,arguments," + extend + ");}\n" : "") + vars.replace(/,\s?/g, ";\n  this.").replace(/\b(var |final |public )+\s*/g, "this.").replace(/this.(\w+);/g, "this.$1 = null;") + (extend ? "extendClass(this, " + extend + ");\n" : "") + "<CLASS " + name + " " + static + ">" + (typeof last == "string" ? last : name + "(");
     64    }
     65    var matchClasses = /(?:public |abstract |static )*class (\w+)\s*(?:extends\s*(\w+)\s*)?{\s*((?:.|\n)*?)\b\1\s*\(/g;
     66    var matchNoCon = /(?:public |abstract |static )*class (\w+)\s*(?:extends\s*(\w+)\s*)?{\s*((?:.|\n)*?)(Processing)/g;
     67    aCode = aCode.replace(matchClasses, ClassReplace);
     68    aCode = aCode.replace(matchNoCon, ClassReplace);
     69    var matchClass = /<CLASS (\w+) (.*?)>/,
     70      m;
     71    while ((m = aCode.match(matchClass))) {
     72      var left = RegExp.leftContext,
     73        allRest = RegExp.rightContext,
     74        rest = nextBrace(allRest),
     75        className = m[1],
     76        staticVars = m[2] || "";
     77      allRest = allRest.slice(rest.length + 1);
     78      rest = rest.replace(new RegExp("\\b" + className + "\\(([^\\)]*?)\\)\\s*{", "g"), function(all, args) {
     79        args = args.split(/,\s*?/);
     80        if (args[0].match(/^\s*$/)) args.shift();
     81        var fn = "if ( arguments.length == " + args.length + " ) {\n";
     82        for (var i = 0; i < args.length; i++) {
     83          fn += "    var " + args[i] + " = arguments[" + i + "];\n";
     84        }
     85        return fn;
     86      });
     87      rest = rest.replace(/(?:public )?Processing.\w+ = function (\w+)\((.*?)\)/g, function(all, name, args) {
     88        return "ADDMETHOD(this, '" + name + "', function(" + args + ")";
     89      });
     90      var matchMethod = /ADDMETHOD([\s\S]*?{)/,
     91        mc;
     92      var methods = "";
     93      while ((mc = rest.match(matchMethod))) {
     94        var prev = RegExp.leftContext,
     95          allNext = RegExp.rightContext,
     96          next = nextBrace(allNext);
     97        methods += "addMethod" + mc[1] + next + "});"
     98        rest = prev + allNext.slice(next.length + 1);
     99      }
     100      rest = methods + rest;
     101      aCode = left + rest + "\n}}" + staticVars + allRest;
     102    }
     103    aCode = aCode.replace(/Processing.\w+ = function addMethod/g, "addMethod");
     104
     105    function nextBrace(right) {
     106      var rest = right;
     107      var position = 0;
     108      var leftCount = 1,
     109        rightCount = 0;
     110      while (leftCount != rightCount) {
     111        var nextLeft = rest.indexOf("{");
     112        var nextRight = rest.indexOf("}");
     113        if (nextLeft < nextRight && nextLeft != -1) {
     114          leftCount++;
     115          rest = rest.slice(nextLeft + 1);
     116          position += nextLeft + 1;
     117        } else {
     118          rightCount++;
     119          rest = rest.slice(nextRight + 1);
     120          position += nextRight + 1;
     121        }
     122      }
     123      return right.slice(0, position - 1);
     124    }
     125    aCode = aCode.replace(/\(int\)/g, "0|");
     126    aCode = aCode.replace(new RegExp("\\((" + classes.join("|") + ")(\\[\\])?\\)", "g"), "");
     127    aCode = aCode.replace(/(\d+)f/g, "$1");
     128    aCode = aCode.replace(/('[a-zA-Z0-9]')/g, "$1.charCodeAt(0)");
     129    aCode = aCode.replace(/#([a-f0-9]{6})/ig, function(m, hex) {
     130      var num = toNumbers(hex);
     131      return "color(" + num[0] + "," + num[1] + "," + num[2] + ")";
     132    });
     133
     134    function toNumbers(str) {
     135      var ret = [];
     136      str.replace(/(..)/g, function(str) {
     137        ret.push(parseInt(str, 16));
     138      });
     139      return ret;
     140    }
     141    return aCode;
     142  };
     143
     144  function buildProcessing(curElement) {
     145    var p = {};
     146    p.PI = Math.PI;
     147    p.TWO_PI = 2 * p.PI;
     148    p.HALF_PI = p.PI / 2;
     149    p.P3D = 3;
     150    p.CORNER = 0;
     151    p.RADIUS = 1;
     152    p.CENTER_RADIUS = 1;
     153    p.CENTER = 2;
     154    p.POLYGON = 2;
     155    p.QUADS = 5;
     156    p.TRIANGLES = 6;
     157    p.POINTS = 7;
     158    p.LINES = 8;
     159    p.TRIANGLE_STRIP = 9;
     160    p.TRIANGLE_FAN = 4;
     161    p.QUAD_STRIP = 3;
     162    p.CORNERS = 10;
     163    p.CLOSE = true;
     164    p.RGB = 1;
     165    p.HSB = 2;
     166    p.CENTER = 88888880;
     167    p.CODED = 88888888;
     168    p.UP = 88888870;
     169    p.RIGHT = 88888871;
     170    p.DOWN = 88888872;
     171    p.LEFT = 88888869;
     172    p.codedKeys = [69, 70, 71, 72];
     173    var curContext = curElement.getContext("2d");
     174    var doFill = true;
     175    var doStroke = true;
     176    var loopStarted = false;
     177    var hasBackground = false;
     178    var doLoop = true;
     179    var looping = 0;
     180    var curRectMode = p.CORNER;
     181    var curEllipseMode = p.CENTER;
     182    var inSetup = false;
     183    var inDraw = false;
     184    var curBackground = "rgba(204,204,204,1)";
     185    var curFrameRate = 1000;
     186    var curShape = p.POLYGON;
     187    var curShapeCount = 0;
     188    var curvePoints = [];
     189    var curTightness = 0;
     190    var opacityRange = 255;
     191    var redRange = 255;
     192    var greenRange = 255;
     193    var blueRange = 255;
     194    var pathOpen = false;
     195    var mousePressed = false;
     196    var keyPressed = false;
     197    var firstX, firstY, secondX, secondY, prevX, prevY;
     198    var curColorMode = p.RGB;
     199    var curTint = -1;
     200    var curTextSize = 12;
     201    var curTextFont = "Arial";
     202    var getLoaded = false;
     203    var start = (new Date).getTime();
     204    p.pmouseX = 0;
     205    p.pmouseY = 0;
     206    p.mouseX = 0;
     207    p.mouseY = 0;
     208    p.mouseButton = 0;
     209    p.mouseDragged = undefined;
     210    p.mouseMoved = undefined;
     211    p.mousePressed = undefined;
     212    p.mouseReleased = undefined;
     213    p.keyPressed = undefined;
     214    p.keyReleased = undefined;
     215    p.draw = undefined;
     216    p.setup = undefined;
     217    p.width = curElement.width - 0;
     218    p.height = curElement.height - 0;
     219    p.frameCount = 0;
     220    p.ajax = function(url) {
     221      if (window.XMLHttpRequest) {
     222        AJAX = new XMLHttpRequest();
     223      } else {
     224        AJAX = new ActiveXObject("Microsoft.XMLHTTP");
     225      }
     226      if (AJAX) {
     227        AJAX.open("GET", url, false);
     228        AJAX.send(null);
     229        return AJAX.responseText;
     230      } else {
     231        return false;
     232      }
     233    }
     234    p.loadStrings = function loadStrings(url) {
     235      return p.ajax(url).split("\n");
     236    };
     237    p.color = function color(aValue1, aValue2, aValue3, aValue4) {
     238      var aColor = "";
     239      if (arguments.length == 3) {
     240        aColor = p.color(aValue1, aValue2, aValue3, opacityRange);
     241      } else if (arguments.length == 4) {
     242        var a = aValue4 / opacityRange;
     243        a = isNaN(a) ? 1 : a;
     244        if (curColorMode == p.HSB) {
     245          var rgb = HSBtoRGB(aValue1, aValue2, aValue3);
     246          var r = rgb[0],
     247            g = rgb[1],
     248            b = rgb[2];
     249        } else {
     250          var r = getColor(aValue1, redRange);
     251          var g = getColor(aValue2, greenRange);
     252          var b = getColor(aValue3, blueRange);
     253        }
     254        aColor = "rgba(" + r + "," + g + "," + b + "," + a + ")";
     255      } else if (typeof aValue1 == "string") {
     256        aColor = aValue1;
     257        if (arguments.length == 2) {
     258          var c = aColor.split(",");
     259          c[3] = (aValue2 / opacityRange) + ")";
     260          aColor = c.join(",");
     261        }
     262      } else if (arguments.length == 2) {
     263        aColor = p.color(aValue1, aValue1, aValue1, aValue2);
     264      } else if (typeof aValue1 == "number") {
     265        aColor = p.color(aValue1, aValue1, aValue1, opacityRange);
     266      } else {
     267        aColor = p.color(redRange, greenRange, blueRange, opacityRange);
     268      }
     269
     270      function HSBtoRGB(h, s, b) {
     271        h = (h / redRange) * 100;
     272        s = (s / greenRange) * 100;
     273        b = (b / blueRange) * 100;
     274        if (s == 0) {
     275          return [b, b, b];
     276        } else {
     277          var hue = h % 360;
     278          var f = hue % 60;
     279          var br = Math.round(b / 100 * 255);
     280          var p = Math.round((b * (100 - s)) / 10000 * 255);
     281          var q = Math.round((b * (6000 - s * f)) / 600000 * 255);
     282          var t = Math.round((b * (6000 - s * (60 - f))) / 600000 * 255);
     283          switch (Math.floor(hue / 60)) {
     284          case 0:
     285            return [br, t, p];
     286          case 1:
     287            return [q, br, p];
     288          case 2:
     289            return [p, br, t];
     290          case 3:
     291            return [p, q, br];
     292          case 4:
     293            return [t, p, br];
     294          case 5:
     295            return [br, p, q];
     296          }
     297        }
     298      }
     299
     300      function getColor(aValue, range) {
     301        return Math.round(255 * (aValue / range));
     302      }
     303      return aColor;
     304    }
     305    p.red = function(aColor) {
     306      return parseInt(verifyChannel(aColor).slice(5));
     307    };
     308    p.green = function(aColor) {
     309      return parseInt(verifyChannel(aColor).split(",")[1]);
     310    };
     311    p.blue = function(aColor) {
     312      return parseInt(verifyChannel(aColor).split(",")[2]);
     313    };
     314    p.alpha = function(aColor) {
     315      return parseInt(parseFloat(verifyChannel(aColor).split(",")[3]) * 255);
     316    };
     317
     318    function verifyChannel(aColor) {
     319      if (aColor.constructor == Array) {
     320        return aColor;
     321      } else {
     322        return p.color(aColor);
     323      }
     324    }
     325    p.lerpColor = function lerpColor(c1, c2, amt) {
     326      var colors1 = p.color(c1).split(",");
     327      var r1 = parseInt(colors1[0].split("(")[1]);
     328      var g1 = parseInt(colors1[1]);
     329      var b1 = parseInt(colors1[2]);
     330      var a1 = parseFloat(colors1[3].split(")")[0]);
     331      var colors2 = p.color(c2).split(",");
     332      var r2 = parseInt(colors2[0].split("(")[1]);
     333      var g2 = parseInt(colors2[1]);
     334      var b2 = parseInt(colors2[2]);
     335      var a2 = parseFloat(colors2[3].split(")")[0]);
     336      var r = parseInt(p.lerp(r1, r2, amt));
     337      var g = parseInt(p.lerp(g1, g2, amt));
     338      var b = parseInt(p.lerp(b1, b2, amt));
     339      var a = parseFloat(p.lerp(a1, a2, amt));
     340      aColor = "rgba(" + r + "," + g + "," + b + "," + a + ")";
     341      return aColor;
     342    }
     343    p.nf = function(num, pad) {
     344      var str = "" + num;
     345      while (pad - str.length) str = "0" + str;
     346      return str;
     347    };
     348    p.AniSprite = function(prefix, frames) {
     349      this.images = [];
     350      this.pos = 0;
     351      for (var i = 0; i < frames; i++) {
     352        this.images.push(prefix + p.nf(i, ("" + frames).length) + ".gif");
     353      }
     354      this.display = function(x, y) {
     355        p.image(this.images[this.pos], x, y);
     356        if (++this.pos >= frames) this.pos = 0;
     357      };
     358      this.getWidth = function() {
     359        return getImage(this.images[0]).width;
     360      };
     361      this.getHeight = function() {
     362        return getImage(this.images[0]).height;
     363      };
     364    };
     365
     366    function buildImageObject(obj) {
     367      var pixels = obj.data;
     368      var data = p.createImage(obj.width, obj.height);
     369      if (data.__defineGetter__ && data.__lookupGetter__ && !data.__lookupGetter__("pixels")) {
     370        var pixelsDone;
     371        data.__defineGetter__("pixels", function() {
     372          if (pixelsDone) return pixelsDone;
     373          pixelsDone = [];
     374          for (var i = 0; i < pixels.length; i += 4) {
     375            pixelsDone.push(p.color(pixels[i], pixels[i + 1], pixels[i + 2], pixels[i + 3]));
     376          }
     377          return pixelsDone;
     378        });
     379      } else {
     380        data.pixels = [];
     381        for (var i = 0; i < pixels.length; i += 4) {
     382          data.pixels.push(p.color(pixels[i], pixels[i + 1], pixels[i + 2], pixels[i + 3]));
     383        }
     384      }
     385      return data;
     386    }
     387    p.createImage = function createImage(w, h, mode) {
     388      var data = {};
     389      data.width = w;
     390      data.height = h;
     391      data.data = [];
     392      if (curContext.createImageData) {
     393        data = curContext.createImageData(w, h);
     394      }
     395      data.pixels = new Array(w * h);
     396      data.get = function(x, y) {
     397        return this.pixels[w * y + x];
     398      };
     399      data._mask = null;
     400      data.mask = function(img) {
     401        this._mask = img;
     402      };
     403      data.loadPixels = function() {};
     404      data.updatePixels = function() {};
     405      return data;
     406    };
     407    p.createGraphics = function createGraphics(w, h) {
     408      var canvas = document.createElement("canvas");
     409      var ret = buildProcessing(canvas);
     410      ret.size(w, h);
     411      ret.canvas = canvas;
     412      return ret;
     413    };
     414    p.beginDraw = function beginDraw() {};
     415    p.endDraw = function endDraw() {};
     416    p.tint = function tint(rgb, a) {
     417      curTint = a;
     418    };
     419
     420    function getImage(img) {
     421      if (typeof img == "string") {
     422        return document.getElementById(img);
     423      }
     424      if (img.img || img.canvas) {
     425        return img.img || img.canvas;
     426      }
     427      for (var i = 0, l = img.pixels.length; i < l; i++) {
     428        var pos = i * 4;
     429        var c = (img.pixels[i] || "rgba(0,0,0,1)").slice(5, -1).split(",");
     430        img.data[pos] = parseInt(c[0]);
     431        img.data[pos + 1] = parseInt(c[1]);
     432        img.data[pos + 2] = parseInt(c[2]);
     433        img.data[pos + 3] = parseFloat(c[3]) * 100;
     434      }
     435      var canvas = document.createElement("canvas") canvas.width = img.width;
     436      canvas.height = img.height;
     437      var context = canvas.getContext("2d");
     438      context.putImageData(img, 0, 0);
     439      img.canvas = canvas;
     440      return canvas;
     441    }
     442    p.image = function image(img, x, y, w, h) {
     443      x = x || 0;
     444      y = y || 0;
     445      var obj = getImage(img);
     446      if (curTint >= 0) {
     447        var oldAlpha = curContext.globalAlpha;
     448        curContext.globalAlpha = curTint / opacityRange;
     449      }
     450      if (arguments.length == 3) {
     451        curContext.drawImage(obj, x, y);
     452      } else {
     453        curContext.drawImage(obj, x, y, w, h);
     454      }
     455      if (curTint >= 0) {
     456        curContext.globalAlpha = oldAlpha;
     457      }
     458      if (img._mask) {
     459        var oldComposite = curContext.globalCompositeOperation;
     460        curContext.globalCompositeOperation = "darker";
     461        p.image(img._mask, x, y);
     462        curContext.globalCompositeOperation = oldComposite;
     463      }
     464    };
     465    p.exit = function exit() {
     466      clearInterval(looping);
     467    };
     468    p.save = function save(file) {};
     469    p.loadImage = function loadImage(file) {
     470      var img = document.getElementById(file);
     471      if (!img) return;
     472      var h = img.height,
     473        w = img.width;
     474      var canvas = document.createElement("canvas");
     475      canvas.width = w;
     476      canvas.height = h;
     477      var context = canvas.getContext("2d");
     478      context.drawImage(img, 0, 0);
     479      var data = buildImageObject(context.getImageData(0, 0, w, h));
     480      data.img = img;
     481      return data;
     482    };
     483    p.loadFont = function loadFont(name) {
     484      return {
     485        name: name,
     486        width: function(str) {
     487          if (curContext.mozMeasureText) return curContext.mozMeasureText(typeof str == "number" ? String.fromCharCode(str) : str) / curTextSize;
     488          else return 0;
     489        }
     490      };
     491    };
     492    p.textFont = function textFont(name, size) {
     493      curTextFont = name;
     494      p.textSize(size);
     495    };
     496    p.textSize = function textSize(size) {
     497      if (size) {
     498        curTextSize = size;
     499      }
     500    };
     501    p.textAlign = function textAlign() {};
     502    p.text = function text(str, x, y) {
     503      if (str && curContext.mozDrawText) {
     504        curContext.save();
     505        curContext.mozTextStyle = curTextSize + "px " + curTextFont.name;
     506        curContext.translate(x, y);
     507        curContext.mozDrawText(typeof str == "number" ? String.fromCharCode(str) : str);
     508        curContext.restore();
     509      }
     510    };
     511    p.print = function print(output) {
     512      alert(output);
     513    }
     514    p.println = p.print;
     515    p.char = function char(key) {
     516      return key;
     517    };
     518    p.map = function map(value, istart, istop, ostart, ostop) {
     519      return ostart + (ostop - ostart) * ((value - istart) / (istop - istart));
     520    };
     521    String.prototype.replaceAll = function(re, replace) {
     522      return this.replace(new RegExp(re, "g"), replace);
     523    };
     524    p.Point = function Point(x, y) {
     525      this.x = x;
     526      this.y = y;
     527      this.copy = function() {
     528        return new Point(x, y);
     529      }
     530    };
     531    p.Random = function() {
     532      var haveNextNextGaussian = false;
     533      var nextNextGaussian;
     534      this.nextGaussian = function() {
     535        if (haveNextNextGaussian) {
     536          haveNextNextGaussian = false;
     537          return nextNextGaussian;
     538        } else {
     539          var v1, v2, s;
     540          do {
     541            v1 = 2 * p.random(1) - 1;
     542            v2 = 2 * p.random(1) - 1;
     543            s = v1 * v1 + v2 * v2;
     544          } while (s >= 1 || s == 0);
     545          var multiplier = Math.sqrt(-2 * Math.log(s) / s);
     546          nextNextGaussian = v2 * multiplier;
     547          haveNextNextGaussian = true;
     548          return v1 * multiplier;
     549        }
     550      };
     551    };
     552    p.ArrayList = function ArrayList(size, size2, size3) {
     553      var array = new Array(0 | size);
     554      if (size2) {
     555        for (var i = 0; i < size; i++) {
     556          array[i] = [];
     557          for (var j = 0; j < size2; j++) {
     558            var a = array[i][j] = size3 ? new Array(size3) : 0;
     559            for (var k = 0; k < size3; k++) {
     560              a[k] = 0;
     561            }
     562          }
     563        }
     564      } else {
     565        for (var i = 0; i < size; i++) {
     566          array[i] = 0;
     567        }
     568      }
     569      array.size = function() {
     570        return this.length;
     571      };
     572      array.get = function(i) {
     573        return this[i];
     574      };
     575      array.remove = function(i) {
     576        return this.splice(i, 1);
     577      };
     578      array.add = function(item) {
     579        return this.push(item);
     580      };
     581      array.clone = function() {
     582        var a = new ArrayList(size);
     583        for (var i = 0; i < size; i++) {
     584          a[i] = this[i];
     585        }
     586        return a;
     587      };
     588      array.isEmpty = function() {
     589        return !this.length;
     590      };
     591      array.clear = function() {
     592        this.length = 0;
     593      };
     594      return array;
     595    };
     596    p.colorMode = function colorMode(mode, range1, range2, range3, range4) {
     597      curColorMode = mode;
     598      if (arguments.length >= 4) {
     599        redRange = range1;
     600        greenRange = range2;
     601        blueRange = range3;
     602      }
     603      if (arguments.length == 5) {
     604        opacityRange = range4;
     605      }
     606      if (arguments.length == 2) {
     607        p.colorMode(mode, range1, range1, range1, range1);
     608      }
     609    };
     610    p.beginShape = function beginShape(type) {
     611      curShape = type;
     612      curShapeCount = 0;
     613      curvePoints = [];
     614    };
     615    p.endShape = function endShape(close) {
     616      if (curShapeCount != 0) {
     617        if (close || doFill) curContext.lineTo(firstX, firstY);
     618        if (doFill) curContext.fill();
     619        if (doStroke) curContext.stroke();
     620        curContext.closePath();
     621        curShapeCount = 0;
     622        pathOpen = false;
     623      }
     624      if (pathOpen) {
     625        if (doFill) curContext.fill();
     626        if (doStroke) curContext.stroke();
     627        curContext.closePath();
     628        curShapeCount = 0;
     629        pathOpen = false;
     630      }
     631    };
     632    p.vertex = function vertex(x, y, x2, y2, x3, y3) {
     633      if (curShapeCount == 0 && curShape != p.POINTS) {
     634        pathOpen = true;
     635        curContext.beginPath();
     636        curContext.moveTo(x, y);
     637        firstX = x;
     638        firstY = y;
     639      } else {
     640        if (curShape == p.POINTS) {
     641          p.point(x, y);
     642        } else if (arguments.length == 2) {
     643          if (curShape != p.QUAD_STRIP || curShapeCount != 2) curContext.lineTo(x, y);
     644          if (curShape == p.TRIANGLE_STRIP) {
     645            if (curShapeCount == 2) {
     646              p.endShape(p.CLOSE);
     647              pathOpen = true;
     648              curContext.beginPath();
     649              curContext.moveTo(prevX, prevY);
     650              curContext.lineTo(x, y);
     651              curShapeCount = 1;
     652            }
     653            firstX = prevX;
     654            firstY = prevY;
     655          }
     656          if (curShape == p.TRIANGLE_FAN && curShapeCount == 2) {
     657            p.endShape(p.CLOSE);
     658            pathOpen = true;
     659            curContext.beginPath();
     660            curContext.moveTo(firstX, firstY);
     661            curContext.lineTo(x, y);
     662            curShapeCount = 1;
     663          }
     664          if (curShape == p.QUAD_STRIP && curShapeCount == 3) {
     665            curContext.lineTo(prevX, prevY);
     666            p.endShape(p.CLOSE);
     667            pathOpen = true;
     668            curContext.beginPath();
     669            curContext.moveTo(prevX, prevY);
     670            curContext.lineTo(x, y);
     671            curShapeCount = 1;
     672          }
     673          if (curShape == p.QUAD_STRIP) {
     674            firstX = secondX;
     675            firstY = secondY;
     676            secondX = prevX;
     677            secondY = prevY;
     678          }
     679        } else if (arguments.length == 4) {
     680          if (curShapeCount > 1) {
     681            curContext.moveTo(prevX, prevY);
     682            curContext.quadraticCurveTo(firstX, firstY, x, y);
     683            curShapeCount = 1;
     684          }
     685        } else if (arguments.length == 6) {
     686          curContext.bezierCurveTo(x, y, x2, y2, x3, y3);
     687        }
     688      }
     689      prevX = x;
     690      prevY = y;
     691      curShapeCount++;
     692      if (curShape == p.LINES && curShapeCount == 2 || (curShape == p.TRIANGLES) && curShapeCount == 3 || (curShape == p.QUADS) && curShapeCount == 4) {
     693        p.endShape(p.CLOSE);
     694      }
     695    };
     696    p.curveVertex = function(x, y, x2, y2) {
     697      if (curvePoints.length < 3) {
     698        curvePoints.push([x, y]);
     699      } else {
     700        var b = [],
     701          s = 1 - curTightness;
     702        curvePoints.push([x, y]);
     703        b[0] = [curvePoints[1][0], curvePoints[1][1]];
     704        b[1] = [curvePoints[1][0] + (s * curvePoints[2][0] - s * curvePoints[0][0]) / 6, curvePoints[1][1] + (s * curvePoints[2][1] - s * curvePoints[0][1]) / 6];
     705        b[2] = [curvePoints[2][0] + (s * curvePoints[1][0] - s * curvePoints[3][0]) / 6, curvePoints[2][1] + (s * curvePoints[1][1] - s * curvePoints[3][1]) / 6];
     706        b[3] = [curvePoints[2][0], curvePoints[2][1]];
     707        if (!pathOpen) {
     708          p.vertex(b[0][0], b[0][1]);
     709        } else {
     710          curShapeCount = 1;
     711        }
     712        p.vertex(b[1][0], b[1][1], b[2][0], b[2][1], b[3][0], b[3][1]);
     713        curvePoints.shift();
     714      }
     715    };
     716    p.curveTightness = function(tightness) {
     717      curTightness = tightness;
     718    };
     719    p.bezierVertex = p.vertex;
     720    p.rectMode = function rectMode(aRectMode) {
     721      curRectMode = aRectMode;
     722    };
     723    p.imageMode = function() {};
     724    p.ellipseMode = function ellipseMode(aEllipseMode) {
     725      curEllipseMode = aEllipseMode;
     726    };
     727    p.dist = function dist(x1, y1, x2, y2) {
     728      return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
     729    };
     730    p.year = function year() {
     731      return (new Date).getYear() + 1900;
     732    };
     733    p.month = function month() {
     734      return (new Date).getMonth();
     735    };
     736    p.day = function day() {
     737      return (new Date).getDay();
     738    };
     739    p.hour = function hour() {
     740      return (new Date).getHours();
     741    };
     742    p.minute = function minute() {
     743      return (new Date).getMinutes();
     744    };
     745    p.second = function second() {
     746      return (new Date).getSeconds();
     747    };
     748    p.millis = function millis() {
     749      return (new Date).getTime() - start;
     750    };
     751    p.ortho = function ortho() {};
     752    p.translate = function translate(x, y) {
     753      curContext.translate(x, y);
     754    };
     755    p.scale = function scale(x, y) {
     756      curContext.scale(x, y || x);
     757    };
     758    p.rotate = function rotate(aAngle) {
     759      curContext.rotate(aAngle);
     760    };
     761    p.pushMatrix = function pushMatrix() {
     762      curContext.save();
     763    };
     764    p.popMatrix = function popMatrix() {
     765      curContext.restore();
     766    };
     767    p.redraw = function redraw() {
     768      if (hasBackground) {
     769        p.background();
     770      }
     771      p.frameCount++;
     772      inDraw = true;
     773      p.pushMatrix();
     774      p.draw();
     775      p.popMatrix();
     776      inDraw = false;
     777    };
     778    p.loop = function loop() {
     779      if (loopStarted) return;
     780      looping = setInterval(function() {
     781        try {
     782          if (!p.paused) {
     783            p.redraw();
     784          }
     785        } catch(e) {
     786          clearInterval(looping);
     787          throw e;
     788        }
     789      },
     790      1000 / curFrameRate);
     791      loopStarted = true;
     792    };
     793    p.frameRate = function frameRate(aRate) {
     794      curFrameRate = aRate;
     795    };
     796    p.background = function background(img) {
     797      if (arguments.length) {
     798        if (img && img.img) {
     799          curBackground = img;
     800        } else {
     801          curBackground = p.color.apply(this, arguments);
     802        }
     803      }
     804      if (curBackground.img) {
     805        p.image(curBackground, 0, 0);
     806      } else {
     807        var oldFill = curContext.fillStyle;
     808        curContext.fillStyle = curBackground + "";
     809        curContext.fillRect(0, 0, p.width, p.height);
     810        curContext.fillStyle = oldFill;
     811      }
     812    };
     813    p.clear = function clear(x, y, width, height) {
     814      arguments.length == 0 ? curContext.clearRect(0, 0, p.width, p.height) : curContext.clearRect(x, y, width, height);
     815    }
     816    p.str = function str(aNumber) {
     817      return aNumber + '';
     818    }
     819    p.sq = function sq(aNumber) {
     820      return aNumber * aNumber;
     821    };
     822    p.sqrt = function sqrt(aNumber) {
     823      return Math.sqrt(aNumber);
     824    };
     825    p.ngsqrt = function ngsqrt(aNumber) {
     826      if (aNumber <= 0) {
     827        return Math.sqrt(-aNumber);
     828      } else {
     829        return Math.sqrt(aNumber);
     830      }
     831    };
     832    p.int = function int(aNumber) {
     833      return Math.floor(aNumber);
     834    };
     835    p.min = function min(aNumber, aNumber2) {
     836      return Math.min(aNumber, aNumber2);
     837    };
     838    p.max = function max(aNumber, aNumber2) {
     839      return Math.max(aNumber, aNumber2);
     840    };
     841    p.ceil = function ceil(aNumber) {
     842      return Math.ceil(aNumber);
     843    };
     844    p.round = function round(aNumber) {
     845      return Math.round(aNumber);
     846    };
     847    p.norm = function norm(aNumber, low, high) {
     848      var range = high - low;
     849      return ((1 / range) * aNumber) - ((1 / range) * low);
     850    };
     851    p.lerp = function lerp(value1, value2, amt) {
     852      var range = value2 - value1;
     853      return (range * amt) + value1;
     854    }
     855    p.floor = function floor(aNumber) {
     856      return Math.floor(aNumber);
     857    };
     858    p.float = function float(aNumber) {
     859      return parseFloat(aNumber);
     860    };
     861    p.byte = function byte(aNumber) {
     862      return aNumber || 0;
     863    };
     864    p.random = function random(aMin, aMax) {
     865      return arguments.length == 2 ? aMin + (Math.random() * (aMax - aMin)) : Math.random() * aMin;
     866    };
     867    p.noise = function(x, y, z) {
     868      return arguments.length >= 2 ? PerlinNoise_2D(x, y) : PerlinNoise_2D(x, x);
     869    };
     870
     871    function Noise(x, y) {
     872      var n = x + y * 57;
     873      n = (n << 13) ^ n;
     874      return Math.abs(1.0 - (((n * ((n * n * 15731) + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0));
     875    };
     876
     877    function SmoothedNoise(x, y) {
     878      var corners = (Noise(x - 1, y - 1) + Noise(x + 1, y - 1) + Noise(x - 1, y + 1) + Noise(x + 1, y + 1)) / 16;
     879      var sides = (Noise(x - 1, y) + Noise(x + 1, y) + Noise(x, y - 1) + Noise(x, y + 1)) / 8;
     880      var center = Noise(x, y) / 4;
     881      return corners + sides + center;
     882    };
     883
     884    function InterpolatedNoise(x, y) {
     885      var integer_X = Math.floor(x);
     886      var fractional_X = x - integer_X;
     887      var integer_Y = Math.floor(y);
     888      var fractional_Y = y - integer_Y;
     889      var v1 = SmoothedNoise(integer_X, integer_Y);
     890      var v2 = SmoothedNoise(integer_X + 1, integer_Y);
     891      var v3 = SmoothedNoise(integer_X, integer_Y + 1);
     892      var v4 = SmoothedNoise(integer_X + 1, integer_Y + 1);
     893      var i1 = Interpolate(v1, v2, fractional_X);
     894      var i2 = Interpolate(v3, v4, fractional_X);
     895      return Interpolate(i1, i2, fractional_Y);
     896    }
     897
     898    function PerlinNoise_2D(x, y) {
     899      var total = 0;
     900      var p = 0.25;
     901      var n = 3;
     902      for (var i = 0; i <= n; i++) {
     903        var frequency = Math.pow(2, i);
     904        var amplitude = Math.pow(p, i);
     905        total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude;
     906      }
     907      return total;
     908    }
     909
     910    function Interpolate(a, b, x) {
     911      var ft = x * p.PI;
     912      var f = (1 - p.cos(ft)) * .5;
     913      return a * (1 - f) + b * f;
     914    }
     915    p.abs = function abs(aNumber) {
     916      return Math.abs(aNumber);
     917    };
     918    p.cos = function cos(aNumber) {
     919      return Math.cos(aNumber);
     920    };
     921    p.sin = function sin(aNumber) {
     922      return Math.sin(aNumber);
     923    };
     924    p.pow = function pow(aNumber, aExponent) {
     925      return Math.pow(aNumber, aExponent);
     926    };
     927    p.constrain = function constrain(aNumber, aMin, aMax) {
     928      return Math.min(Math.max(aNumber, aMin), aMax);
     929    };
     930    p.sqrt = function sqrt(aNumber) {
     931      return Math.sqrt(aNumber);
     932    };
     933    p.atan2 = function atan2(aNumber, aNumber2) {
     934      return Math.atan2(aNumber, aNumber2);
     935    };
     936    p.radians = function radians(aAngle) {
     937      return (aAngle / 180) * p.PI;
     938    };
     939    p.degrees = function degrees(aAngle) {
     940      aAngle = (aAngle * 180) / p.PI;
     941      if (aAngle < 0) {
     942        aAngle = 360 + aAngle
     943      }
     944      return aAngle;
     945    };
     946    p.size = function size(aWidth, aHeight) {
     947      var fillStyle = curContext.fillStyle;
     948      var strokeStyle = curContext.strokeStyle;
     949      curElement.width = p.width = aWidth;
     950      curElement.height = p.height = aHeight;
     951      curContext.fillStyle = fillStyle;
     952      curContext.strokeStyle = strokeStyle;
     953    };
     954    p.noStroke = function noStroke() {
     955      doStroke = false;
     956    };
     957    p.noFill = function noFill() {
     958      doFill = false;
     959    };
     960    p.smooth = function smooth() {};
     961    p.noSmooth = function noSmooth() {};
     962    p.noLoop = function noLoop() {
     963      clearInterval(looping);
     964      loopStarted = false;
     965      doLoop = false;
     966    };
     967    p.fill = function fill() {
     968      doFill = true;
     969      curContext.fillStyle = p.color.apply(this, arguments);
     970    };
     971    p.stroke = function stroke() {
     972      doStroke = true;
     973      curContext.strokeStyle = p.color.apply(this, arguments);
     974    };
     975    p.strokeWeight = function strokeWeight(w) {
     976      curContext.lineWidth = w;
     977    };
     978    p.point = function point(x, y) {
     979      var oldFill = curContext.fillStyle;
     980      curContext.fillStyle = curContext.strokeStyle;
     981      curContext.fillRect(Math.round(x), Math.round(y), 1, 1);
     982      curContext.fillStyle = oldFill;
     983    };
     984    p.get = function get(x, y) {
     985      if (arguments.length == 0) {
     986        var c = p.createGraphics(p.width, p.height);
     987        c.image(curContext, 0, 0);
     988        return c;
     989      }
     990      if (!getLoaded) {
     991        getLoaded = buildImageObject(curContext.getImageData(0, 0, p.width, p.height));
     992      }
     993      return getLoaded.get(x, y);
     994    };
     995    p.set = function set(x, y, obj) {
     996      if (obj && obj.img) {
     997        p.image(obj, x, y);
     998      } else {
     999        var oldFill = curContext.fillStyle;
     1000        var color = obj;
     1001        curContext.fillStyle = color;
     1002        curContext.fillRect(Math.round(x), Math.round(y), 1, 1);
     1003        curContext.fillStyle = oldFill;
     1004      }
     1005    };
     1006    p.arc = function arc(x, y, width, height, start, stop) {
     1007      if (width <= 0) return;
     1008      if (curEllipseMode == p.CORNER) {
     1009        x += width / 2;
     1010        y += height / 2;
     1011      }
     1012      curContext.moveTo(x, y);
     1013      curContext.beginPath();
     1014      curContext.arc(x, y, curEllipseMode == p.CENTER_RADIUS ? width : width / 2, start, stop, false);
     1015      if (doStroke) curContext.stroke();
     1016      curContext.lineTo(x, y);
     1017      if (doFill) curContext.fill();
     1018      curContext.closePath();
     1019    };
     1020    p.line = function line(x1, y1, x2, y2) {
     1021      curContext.lineCap = "round";
     1022      curContext.beginPath();
     1023      curContext.moveTo(x1 || 0, y1 || 0);
     1024      curContext.lineTo(x2 || 0, y2 || 0);
     1025      curContext.stroke();
     1026      curContext.closePath();
     1027    };
     1028    p.bezier = function bezier(x1, y1, x2, y2, x3, y3, x4, y4) {
     1029      curContext.lineCap = "butt";
     1030      curContext.beginPath();
     1031      curContext.moveTo(x1, y1);
     1032      curContext.bezierCurveTo(x2, y2, x3, y3, x4, y4);
     1033      curContext.stroke();
     1034      curContext.closePath();
     1035    };
     1036    p.triangle = function triangle(x1, y1, x2, y2, x3, y3) {
     1037      p.beginShape();
     1038      p.vertex(x1, y1);
     1039      p.vertex(x2, y2);
     1040      p.vertex(x3, y3);
     1041      p.endShape();
     1042    };
     1043    p.quad = function quad(x1, y1, x2, y2, x3, y3, x4, y4) {
     1044      curContext.lineCap = "square";
     1045      p.beginShape();
     1046      p.vertex(x1, y1);
     1047      p.vertex(x2, y2);
     1048      p.vertex(x3, y3);
     1049      p.vertex(x4, y4);
     1050      p.endShape();
     1051    };
     1052    p.rect = function rect(x, y, width, height) {
     1053      if (width == 0 && height == 0) return;
     1054      curContext.beginPath();
     1055      var offsetStart = 0;
     1056      var offsetEnd = 0;
     1057      if (curRectMode == p.CORNERS) {
     1058        width -= x;
     1059        height -= y;
     1060      }
     1061      if (curRectMode == p.RADIUS) {
     1062        width *= 2;
     1063        height *= 2;
     1064      }
     1065      if (curRectMode == p.CENTER || curRectMode == p.RADIUS) {
     1066        x -= width / 2;
     1067        y -= height / 2;
     1068      }
     1069      curContext.rect(Math.round(x) - offsetStart, Math.round(y) - offsetStart, Math.round(width) + offsetEnd, Math.round(height) + offsetEnd);
     1070      if (doFill) curContext.fill();
     1071      if (doStroke) curContext.stroke();
     1072      curContext.closePath();
     1073    };
     1074    p.ellipse = function ellipse(x, y, width, height) {
     1075      x = x || 0;
     1076      y = y || 0;
     1077      if (width <= 0 && height <= 0) return;
     1078      curContext.beginPath();
     1079      if (curEllipseMode == p.RADIUS) {
     1080        width *= 2;
     1081        height *= 2;
     1082      }
     1083      var offsetStart = 0;
     1084      if (width == height) {
     1085        curContext.arc(x - offsetStart, y - offsetStart, width / 2, 0, Math.PI * 2, false);
     1086      } else {
     1087        var w = width / 2;
     1088        var h = height / 2;
     1089        var C = 0.5522847498307933;
     1090        var c_x = C * w;
     1091        var c_y = C * h;
     1092        curContext.moveTo(x + w, y);
     1093        curContext.bezierCurveTo(x + w, y - c_y, x + c_x, y - h, x, y - h);
     1094        curContext.bezierCurveTo(x - c_x, y - h, x - w, y - c_y, x - w, y);
     1095        curContext.bezierCurveTo(x - w, y + c_y, x - c_x, y + h, x, y + h);
     1096        curContext.bezierCurveTo(x + c_x, y + h, x + w, y + c_y, x + w, y);
     1097      }
     1098      if (doFill) curContext.fill();
     1099      if (doStroke) curContext.stroke();
     1100      curContext.closePath();
     1101    };
     1102    p.link = function(href, target) {
     1103      window.location = href;
     1104    };
     1105    p.loadPixels = function() {
     1106      p.pixels = buildImageObject(curContext.getImageData(0, 0, p.width, p.height)).pixels;
     1107    };
     1108    p.updatePixels = function() {
     1109      var colors = /(\d+),(\d+),(\d+),(\d+)/;
     1110      var pixels = {};
     1111      pixels.width = p.width;
     1112      pixels.height = p.height;
     1113      pixels.data = [];
     1114      if (curContext.createImageData) {
     1115        pixels = curContext.createImageData(p.width, p.height);
     1116      }
     1117      var data = pixels.data;
     1118      var pos = 0;
     1119      for (var i = 0, l = p.pixels.length; i < l; i++) {
     1120        var c = (p.pixels[i] || "rgba(0,0,0,1)").match(colors);
     1121        data[pos] = parseInt(c[1]);
     1122        data[pos + 1] = parseInt(c[2]);
     1123        data[pos + 2] = parseInt(c[3]);
     1124        data[pos + 3] = parseFloat(c[4]) * 255;
     1125        pos += 4;
     1126      }
     1127      curContext.putImageData(pixels, 0, 0);
     1128    };
     1129    p.extendClass = function extendClass(obj, args, fn) {
     1130      if (arguments.length == 3) {
     1131        fn.apply(obj, args);
     1132      } else {
     1133        args.call(obj);
     1134      }
     1135    };
     1136    p.addMethod = function addMethod(object, name, fn) {
     1137      if (object[name]) {
     1138        var args = fn.length;
     1139        var oldfn = object[name];
     1140        object[name] = function() {
     1141          if (arguments.length == args) return fn.apply(this, arguments);
     1142          else return oldfn.apply(this, arguments);
     1143        };
     1144      } else {
     1145        object[name] = fn;
     1146      }
     1147    };
     1148    p.init = function init(code) {
     1149      p.stroke(0);
     1150      p.fill(255);
     1151      curContext.translate(0.5, 0.5);
     1152      if (code) {
     1153        (function(Processing) {
     1154          with(p) {
     1155            eval(parse(code, p));
     1156          }
     1157        })(p);
     1158      }
     1159      if (p.setup) {
     1160        inSetup = true;
     1161        p.setup();
     1162      }
     1163      inSetup = false;
     1164      if (p.draw) {
     1165        if (!doLoop) {
     1166          p.redraw();
     1167        } else {
     1168          p.loop();
     1169        }
     1170      }
     1171      attach(document, "mousemove", function(e) {
     1172        var scrollX = window.scrollX != null ? window.scrollX : window.pageXOffset;
     1173        var scrollY = window.scrollY != null ? window.scrollY : window.pageYOffset;
     1174        p.pmouseX = p.mouseX;
     1175        p.pmouseY = p.mouseY;
     1176        p.mouseX = e.clientX - curElement.offsetLeft + scrollX;
     1177        p.mouseY = e.clientY - curElement.offsetTop + scrollY;
     1178        if (p.mouseMoved) {
     1179          p.mouseMoved();
     1180        }
     1181        if (mousePressed && p.mouseDragged) {
     1182          p.mouseDragged();
     1183        }
     1184      });
     1185      attach(curElement, "mousedown", function(e) {
     1186        mousePressed = true;
     1187        switch (e.which) {
     1188        case 1:
     1189          p.mouseButton = p.LEFT;
     1190          break;
     1191        case 2:
     1192          p.mouseButton = p.CENTER;
     1193          break;
     1194        case 3:
     1195          p.mouseButton = p.RIGHT;
     1196          break;
     1197        }
     1198        if (typeof p.mousePressed == "function") {
     1199          p.mousePressed();
     1200        } else {
     1201          p.mousePressed = true;
     1202        }
     1203      });
     1204      attach(curElement, "contextmenu", function(e) {
     1205        e.preventDefault();
     1206        e.stopPropagation();
     1207      });
     1208      attach(document, "mouseup", function(e) {
     1209        mousePressed = false;
     1210        if (typeof p.mousePressed != "function") {
     1211          p.mousePressed = false;
     1212        }
     1213        if (p.mouseReleased) {
     1214          p.mouseReleased();
     1215        }
     1216      });
     1217      attach(document, "keydown", function(e) {
     1218        keyPressed = true;
     1219        p.key = e.keyCode + 32;
     1220        var i;
     1221        for (i = 0; i < p.codedKeys.length; i++) {
     1222          if (p.key == p.codedKeys[i]) {
     1223            switch (p.key) {
     1224            case 70:
     1225              p.keyCode = p.UP;
     1226              break;
     1227            case 71:
     1228              p.keyCode = p.RIGHT;
     1229              break;
     1230            case 72:
     1231              p.keyCode = p.DOWN;
     1232              break;
     1233            case 69:
     1234              p.keyCode = p.LEFT;
     1235              break;
     1236            }
     1237            p.key = p.CODED;
     1238          }
     1239        }
     1240        if (e.shiftKey) {
     1241          p.key = String.fromCharCode(p.key).toUpperCase().charCodeAt(0);
     1242        }
     1243        if (typeof p.keyPressed == "function") {
     1244          p.keyPressed();
     1245        } else {
     1246          p.keyPressed = true;
     1247        }
     1248      });
     1249      attach(document, "keyup", function(e) {
     1250        keyPressed = false;
     1251        if (typeof p.keyPressed != "function") {
     1252          p.keyPressed = false;
     1253        }
     1254        if (p.keyReleased) {
     1255          p.keyReleased();
     1256        }
     1257      });
     1258
     1259      function attach(elem, type, fn) {
     1260        if (elem.addEventListener) elem.addEventListener(type, fn, false);
     1261        else elem.attachEvent("on" + type, fn);
     1262      }
     1263    };
     1264    return p;
     1265  }
     1266})();
  • new file sagenb/data/graph_editor/processing.editor.min.js

    diff --git a/sagenb/data/graph_editor/processing.editor.min.js b/sagenb/data/graph_editor/processing.editor.min.js
    new file mode 100644
    - +  
     1(function(){this.Processing=function Processing(aElement,aCode){if(typeof aElement=="string")
     2aElement=document.getElementById(aElement);var p=buildProcessing(aElement);if(aCode)
     3p.init(aCode);return p;};function log(){try{console.log.apply(console,arguments);}catch(e){try{opera.postError.apply(opera,arguments);}catch(e){}}}
     4var parse=Processing.parse=function parse(aCode,p){aCode=aCode.replace(/\/\/ .*\n/g,"\n");aCode=aCode.replace(/([^\s])%([^\s])/g,"$1 % $2");aCode=aCode.replace(/(?:static )?(\w+ )(\w+)\s*(\([^\)]*\)\s*{)/g,function(all,type,name,args){if(name=="if"||name=="for"||name=="while"){return all;}else{return"Processing."+name+" = function "+name+args;}});aCode=aCode.replace(/\.length\(\)/g,".length");aCode=aCode.replace(/([\(,]\s*)(\w+)((?:\[\])+| )\s*(\w+\s*[\),])/g,"$1$4");aCode=aCode.replace(/([\(,]\s*)(\w+)((?:\[\])+| )\s*(\w+\s*[\),])/g,"$1$4");aCode=aCode.replace(/new (\w+)((?:\[([^\]]*)\])+)/g,function(all,name,args){return"new ArrayList("+args.slice(1,-1).split("][").join(", ")+")";});aCode=aCode.replace(/(?:static )?\w+\[\]\s*(\w+)\[?\]?\s*=\s*{.*?};/g,function(all){return all.replace(/{/g,"[").replace(/}/g,"]");});var intFloat=/(\n\s*(?:int|float)(?:\[\])?(?:\s*|[^\(]*?,\s*))([a-z]\w*)(;|,)/i;while(intFloat.test(aCode)){aCode=aCode.replace(new RegExp(intFloat),function(all,type,name,sep){return type+" "+name+" = 0"+sep;});}
     5aCode=aCode.replace(/(?:static )?(\w+)((?:\[\])+| ) *(\w+)\[?\]?(\s*[=,;])/g,function(all,type,arr,name,sep){if(type=="return")
     6return all;else
     7return"var "+name+sep;});aCode=aCode.replace(/=\s*{((.|\s)*?)};/g,function(all,data){return"= ["+data.replace(/{/g,"[").replace(/}/g,"]")+"]";});aCode=aCode.replace(/static\s*{((.|\n)*?)}/g,function(all,init){return init;});aCode=aCode.replace(/super\(/g,"superMethod(");var classes=["int","float","boolean","string"];function ClassReplace(all,name,extend,vars,last){classes.push(name);var static="";vars=vars.replace(/final\s+var\s+(\w+\s*=\s*.*?;)/g,function(all,set){static+=" "+name+"."+set;return"";});return"function "+name+"() {with(this){\n  "+
     8(extend?"var __self=this;function superMethod(){extendClass(__self,arguments,"+extend+");}\n":"")+
     9vars.replace(/,\s?/g,";\n  this.").replace(/\b(var |final |public )+\s*/g,"this.").replace(/this.(\w+);/g,"this.$1 = null;")+
     10(extend?"extendClass(this, "+extend+");\n":"")+"<CLASS "+name+" "+static+">"+(typeof last=="string"?last:name+"(");}
     11var matchClasses=/(?:public |abstract |static )*class (\w+)\s*(?:extends\s*(\w+)\s*)?{\s*((?:.|\n)*?)\b\1\s*\(/g;var matchNoCon=/(?:public |abstract |static )*class (\w+)\s*(?:extends\s*(\w+)\s*)?{\s*((?:.|\n)*?)(Processing)/g;aCode=aCode.replace(matchClasses,ClassReplace);aCode=aCode.replace(matchNoCon,ClassReplace);var matchClass=/<CLASS (\w+) (.*?)>/,m;while((m=aCode.match(matchClass))){var left=RegExp.leftContext,allRest=RegExp.rightContext,rest=nextBrace(allRest),className=m[1],staticVars=m[2]||"";allRest=allRest.slice(rest.length+1);rest=rest.replace(new RegExp("\\b"+className+"\\(([^\\)]*?)\\)\\s*{","g"),function(all,args){args=args.split(/,\s*?/);if(args[0].match(/^\s*$/))
     12args.shift();var fn="if ( arguments.length == "+args.length+" ) {\n";for(var i=0;i<args.length;i++){fn+="    var "+args[i]+" = arguments["+i+"];\n";}
     13return fn;});rest=rest.replace(/(?:public )?Processing.\w+ = function (\w+)\((.*?)\)/g,function(all,name,args){return"ADDMETHOD(this, '"+name+"', function("+args+")";});var matchMethod=/ADDMETHOD([\s\S]*?{)/,mc;var methods="";while((mc=rest.match(matchMethod))){var prev=RegExp.leftContext,allNext=RegExp.rightContext,next=nextBrace(allNext);methods+="addMethod"+mc[1]+next+"});"
     14rest=prev+allNext.slice(next.length+1);}
     15rest=methods+rest;aCode=left+rest+"\n}}"+staticVars+allRest;}
     16aCode=aCode.replace(/Processing.\w+ = function addMethod/g,"addMethod");function nextBrace(right){var rest=right;var position=0;var leftCount=1,rightCount=0;while(leftCount!=rightCount){var nextLeft=rest.indexOf("{");var nextRight=rest.indexOf("}");if(nextLeft<nextRight&&nextLeft!=-1){leftCount++;rest=rest.slice(nextLeft+1);position+=nextLeft+1;}else{rightCount++;rest=rest.slice(nextRight+1);position+=nextRight+1;}}
     17return right.slice(0,position-1);}
     18aCode=aCode.replace(/\(int\)/g,"0|");aCode=aCode.replace(new RegExp("\\(("+classes.join("|")+")(\\[\\])?\\)","g"),"");aCode=aCode.replace(/(\d+)f/g,"$1");aCode=aCode.replace(/('[a-zA-Z0-9]')/g,"$1.charCodeAt(0)");aCode=aCode.replace(/#([a-f0-9]{6})/ig,function(m,hex){var num=toNumbers(hex);return"color("+num[0]+","+num[1]+","+num[2]+")";});function toNumbers(str){var ret=[];str.replace(/(..)/g,function(str){ret.push(parseInt(str,16));});return ret;}
     19return aCode;};function buildProcessing(curElement){var p={};p.PI=Math.PI;p.TWO_PI=2*p.PI;p.HALF_PI=p.PI/2;p.P3D=3;p.CORNER=0;p.RADIUS=1;p.CENTER_RADIUS=1;p.CENTER=2;p.POLYGON=2;p.QUADS=5;p.TRIANGLES=6;p.POINTS=7;p.LINES=8;p.TRIANGLE_STRIP=9;p.TRIANGLE_FAN=4;p.QUAD_STRIP=3;p.CORNERS=10;p.CLOSE=true;p.RGB=1;p.HSB=2;p.CENTER=88888880;p.CODED=88888888;p.UP=88888870;p.RIGHT=88888871;p.DOWN=88888872;p.LEFT=88888869;p.codedKeys=[69,70,71,72];var curContext=curElement.getContext("2d");var doFill=true;var doStroke=true;var loopStarted=false;var hasBackground=false;var doLoop=true;var looping=0;var curRectMode=p.CORNER;var curEllipseMode=p.CENTER;var inSetup=false;var inDraw=false;var curBackground="rgba(204,204,204,1)";var curFrameRate=1000;var curShape=p.POLYGON;var curShapeCount=0;var curvePoints=[];var curTightness=0;var opacityRange=255;var redRange=255;var greenRange=255;var blueRange=255;var pathOpen=false;var mousePressed=false;var keyPressed=false;var firstX,firstY,secondX,secondY,prevX,prevY;var curColorMode=p.RGB;var curTint=-1;var curTextSize=12;var curTextFont="Arial";var getLoaded=false;var start=(new Date).getTime();p.pmouseX=0;p.pmouseY=0;p.mouseX=0;p.mouseY=0;p.mouseButton=0;p.mouseDragged=undefined;p.mouseMoved=undefined;p.mousePressed=undefined;p.mouseReleased=undefined;p.keyPressed=undefined;p.keyReleased=undefined;p.draw=undefined;p.setup=undefined;p.width=curElement.width-0;p.height=curElement.height-0;p.frameCount=0;p.ajax=function(url){if(window.XMLHttpRequest){AJAX=new XMLHttpRequest();}
     20else{AJAX=new ActiveXObject("Microsoft.XMLHTTP");}
     21if(AJAX){AJAX.open("GET",url,false);AJAX.send(null);return AJAX.responseText;}else{return false;}}
     22p.loadStrings=function loadStrings(url){return p.ajax(url).split("\n");};p.color=function color(aValue1,aValue2,aValue3,aValue4){var aColor="";if(arguments.length==3){aColor=p.color(aValue1,aValue2,aValue3,opacityRange);}else if(arguments.length==4){var a=aValue4/opacityRange;a=isNaN(a)?1:a;if(curColorMode==p.HSB){var rgb=HSBtoRGB(aValue1,aValue2,aValue3);var r=rgb[0],g=rgb[1],b=rgb[2];}else{var r=getColor(aValue1,redRange);var g=getColor(aValue2,greenRange);var b=getColor(aValue3,blueRange);}
     23aColor="rgba("+r+","+g+","+b+","+a+")";}else if(typeof aValue1=="string"){aColor=aValue1;if(arguments.length==2){var c=aColor.split(",");c[3]=(aValue2/opacityRange)+")";aColor=c.join(",");}}else if(arguments.length==2){aColor=p.color(aValue1,aValue1,aValue1,aValue2);}else if(typeof aValue1=="number"){aColor=p.color(aValue1,aValue1,aValue1,opacityRange);}else{aColor=p.color(redRange,greenRange,blueRange,opacityRange);}
     24function HSBtoRGB(h,s,b){h=(h/redRange)*100;s=(s/greenRange)*100;b=(b/blueRange)*100;if(s==0){return[b,b,b];}else{var hue=h%360;var f=hue%60;var br=Math.round(b/100*255);var p=Math.round((b*(100-s))/10000*255);var q=Math.round((b*(6000-s*f))/600000*255);var t=Math.round((b*(6000-s*(60-f)))/600000*255);switch(Math.floor(hue/60)){case 0:return[br,t,p];case 1:return[q,br,p];case 2:return[p,br,t];case 3:return[p,q,br];case 4:return[t,p,br];case 5:return[br,p,q];}}}
     25function getColor(aValue,range){return Math.round(255*(aValue/range));}
     26return aColor;}
     27p.red=function(aColor){return parseInt(verifyChannel(aColor).slice(5));};p.green=function(aColor){return parseInt(verifyChannel(aColor).split(",")[1]);};p.blue=function(aColor){return parseInt(verifyChannel(aColor).split(",")[2]);};p.alpha=function(aColor){return parseInt(parseFloat(verifyChannel(aColor).split(",")[3])*255);};function verifyChannel(aColor){if(aColor.constructor==Array){return aColor;}else{return p.color(aColor);}}
     28p.lerpColor=function lerpColor(c1,c2,amt){var colors1=p.color(c1).split(",");var r1=parseInt(colors1[0].split("(")[1]);var g1=parseInt(colors1[1]);var b1=parseInt(colors1[2]);var a1=parseFloat(colors1[3].split(")")[0]);var colors2=p.color(c2).split(",");var r2=parseInt(colors2[0].split("(")[1]);var g2=parseInt(colors2[1]);var b2=parseInt(colors2[2]);var a2=parseFloat(colors2[3].split(")")[0]);var r=parseInt(p.lerp(r1,r2,amt));var g=parseInt(p.lerp(g1,g2,amt));var b=parseInt(p.lerp(b1,b2,amt));var a=parseFloat(p.lerp(a1,a2,amt));aColor="rgba("+r+","+g+","+b+","+a+")";return aColor;}
     29p.nf=function(num,pad){var str=""+num;while(pad-str.length)
     30str="0"+str;return str;};p.AniSprite=function(prefix,frames){this.images=[];this.pos=0;for(var i=0;i<frames;i++){this.images.push(prefix+p.nf(i,(""+frames).length)+".gif");}
     31this.display=function(x,y){p.image(this.images[this.pos],x,y);if(++this.pos>=frames)
     32this.pos=0;};this.getWidth=function(){return getImage(this.images[0]).width;};this.getHeight=function(){return getImage(this.images[0]).height;};};function buildImageObject(obj){var pixels=obj.data;var data=p.createImage(obj.width,obj.height);if(data.__defineGetter__&&data.__lookupGetter__&&!data.__lookupGetter__("pixels")){var pixelsDone;data.__defineGetter__("pixels",function(){if(pixelsDone)
     33return pixelsDone;pixelsDone=[];for(var i=0;i<pixels.length;i+=4){pixelsDone.push(p.color(pixels[i],pixels[i+1],pixels[i+2],pixels[i+3]));}
     34return pixelsDone;});}else{data.pixels=[];for(var i=0;i<pixels.length;i+=4){data.pixels.push(p.color(pixels[i],pixels[i+1],pixels[i+2],pixels[i+3]));}}
     35return data;}
     36p.createImage=function createImage(w,h,mode){var data={};data.width=w;data.height=h;data.data=[];if(curContext.createImageData){data=curContext.createImageData(w,h);}
     37data.pixels=new Array(w*h);data.get=function(x,y){return this.pixels[w*y+x];};data._mask=null;data.mask=function(img){this._mask=img;};data.loadPixels=function(){};data.updatePixels=function(){};return data;};p.createGraphics=function createGraphics(w,h){var canvas=document.createElement("canvas");var ret=buildProcessing(canvas);ret.size(w,h);ret.canvas=canvas;return ret;};p.beginDraw=function beginDraw(){};p.endDraw=function endDraw(){};p.tint=function tint(rgb,a){curTint=a;};function getImage(img){if(typeof img=="string"){return document.getElementById(img);}
     38if(img.img||img.canvas){return img.img||img.canvas;}
     39for(var i=0,l=img.pixels.length;i<l;i++){var pos=i*4;var c=(img.pixels[i]||"rgba(0,0,0,1)").slice(5,-1).split(",");img.data[pos]=parseInt(c[0]);img.data[pos+1]=parseInt(c[1]);img.data[pos+2]=parseInt(c[2]);img.data[pos+3]=parseFloat(c[3])*100;}
     40var canvas=document.createElement("canvas")
     41canvas.width=img.width;canvas.height=img.height;var context=canvas.getContext("2d");context.putImageData(img,0,0);img.canvas=canvas;return canvas;}
     42p.image=function image(img,x,y,w,h){x=x||0;y=y||0;var obj=getImage(img);if(curTint>=0){var oldAlpha=curContext.globalAlpha;curContext.globalAlpha=curTint/opacityRange;}
     43if(arguments.length==3){curContext.drawImage(obj,x,y);}else{curContext.drawImage(obj,x,y,w,h);}
     44if(curTint>=0){curContext.globalAlpha=oldAlpha;}
     45if(img._mask){var oldComposite=curContext.globalCompositeOperation;curContext.globalCompositeOperation="darker";p.image(img._mask,x,y);curContext.globalCompositeOperation=oldComposite;}};p.exit=function exit(){clearInterval(looping);};p.save=function save(file){};p.loadImage=function loadImage(file){var img=document.getElementById(file);if(!img)
     46return;var h=img.height,w=img.width;var canvas=document.createElement("canvas");canvas.width=w;canvas.height=h;var context=canvas.getContext("2d");context.drawImage(img,0,0);var data=buildImageObject(context.getImageData(0,0,w,h));data.img=img;return data;};p.loadFont=function loadFont(name){return{name:name,width:function(str){if(curContext.mozMeasureText)
     47return curContext.mozMeasureText(typeof str=="number"?String.fromCharCode(str):str)/curTextSize;else
     48return 0;}};};p.textFont=function textFont(name,size){curTextFont=name;p.textSize(size);};p.textSize=function textSize(size){if(size){curTextSize=size;}};p.textAlign=function textAlign(){};p.text=function text(str,x,y){if(str&&curContext.mozDrawText){curContext.save();curContext.mozTextStyle=curTextSize+"px "+curTextFont.name;curContext.translate(x,y);curContext.mozDrawText(typeof str=="number"?String.fromCharCode(str):str);curContext.restore();}};p.print=function print(output){alert(output);}
     49p.println=p.print;p.char=function char(key){return key;};p.map=function map(value,istart,istop,ostart,ostop){return ostart+(ostop-ostart)*((value-istart)/(istop-istart));};String.prototype.replaceAll=function(re,replace){return this.replace(new RegExp(re,"g"),replace);};p.Point=function Point(x,y){this.x=x;this.y=y;this.copy=function(){return new Point(x,y);}};p.Random=function(){var haveNextNextGaussian=false;var nextNextGaussian;this.nextGaussian=function(){if(haveNextNextGaussian){haveNextNextGaussian=false;return nextNextGaussian;}else{var v1,v2,s;do{v1=2*p.random(1)-1;v2=2*p.random(1)-1;s=v1*v1+v2*v2;}while(s>=1||s==0);var multiplier=Math.sqrt(-2*Math.log(s)/s);nextNextGaussian=v2*multiplier;haveNextNextGaussian=true;return v1*multiplier;}};};p.ArrayList=function ArrayList(size,size2,size3){var array=new Array(0|size);if(size2){for(var i=0;i<size;i++){array[i]=[];for(var j=0;j<size2;j++){var a=array[i][j]=size3?new Array(size3):0;for(var k=0;k<size3;k++){a[k]=0;}}}}else{for(var i=0;i<size;i++){array[i]=0;}}
     50array.size=function(){return this.length;};array.get=function(i){return this[i];};array.remove=function(i){return this.splice(i,1);};array.add=function(item){return this.push(item);};array.clone=function(){var a=new ArrayList(size);for(var i=0;i<size;i++){a[i]=this[i];}
     51return a;};array.isEmpty=function(){return!this.length;};array.clear=function(){this.length=0;};return array;};p.colorMode=function colorMode(mode,range1,range2,range3,range4){curColorMode=mode;if(arguments.length>=4){redRange=range1;greenRange=range2;blueRange=range3;}
     52if(arguments.length==5){opacityRange=range4;}
     53if(arguments.length==2){p.colorMode(mode,range1,range1,range1,range1);}};p.beginShape=function beginShape(type){curShape=type;curShapeCount=0;curvePoints=[];};p.endShape=function endShape(close){if(curShapeCount!=0){if(close||doFill)
     54curContext.lineTo(firstX,firstY);if(doFill)
     55curContext.fill();if(doStroke)
     56curContext.stroke();curContext.closePath();curShapeCount=0;pathOpen=false;}
     57if(pathOpen){if(doFill)
     58curContext.fill();if(doStroke)
     59curContext.stroke();curContext.closePath();curShapeCount=0;pathOpen=false;}};p.vertex=function vertex(x,y,x2,y2,x3,y3){if(curShapeCount==0&&curShape!=p.POINTS){pathOpen=true;curContext.beginPath();curContext.moveTo(x,y);firstX=x;firstY=y;}else{if(curShape==p.POINTS){p.point(x,y);}else if(arguments.length==2){if(curShape!=p.QUAD_STRIP||curShapeCount!=2)
     60curContext.lineTo(x,y);if(curShape==p.TRIANGLE_STRIP){if(curShapeCount==2){p.endShape(p.CLOSE);pathOpen=true;curContext.beginPath();curContext.moveTo(prevX,prevY);curContext.lineTo(x,y);curShapeCount=1;}
     61firstX=prevX;firstY=prevY;}
     62if(curShape==p.TRIANGLE_FAN&&curShapeCount==2){p.endShape(p.CLOSE);pathOpen=true;curContext.beginPath();curContext.moveTo(firstX,firstY);curContext.lineTo(x,y);curShapeCount=1;}
     63if(curShape==p.QUAD_STRIP&&curShapeCount==3){curContext.lineTo(prevX,prevY);p.endShape(p.CLOSE);pathOpen=true;curContext.beginPath();curContext.moveTo(prevX,prevY);curContext.lineTo(x,y);curShapeCount=1;}
     64if(curShape==p.QUAD_STRIP){firstX=secondX;firstY=secondY;secondX=prevX;secondY=prevY;}}else if(arguments.length==4){if(curShapeCount>1){curContext.moveTo(prevX,prevY);curContext.quadraticCurveTo(firstX,firstY,x,y);curShapeCount=1;}}else if(arguments.length==6){curContext.bezierCurveTo(x,y,x2,y2,x3,y3);}}
     65prevX=x;prevY=y;curShapeCount++;if(curShape==p.LINES&&curShapeCount==2||(curShape==p.TRIANGLES)&&curShapeCount==3||(curShape==p.QUADS)&&curShapeCount==4){p.endShape(p.CLOSE);}};p.curveVertex=function(x,y,x2,y2){if(curvePoints.length<3){curvePoints.push([x,y]);}else{var b=[],s=1-curTightness;curvePoints.push([x,y]);b[0]=[curvePoints[1][0],curvePoints[1][1]];b[1]=[curvePoints[1][0]+(s*curvePoints[2][0]-s*curvePoints[0][0])/6,curvePoints[1][1]+(s*curvePoints[2][1]-s*curvePoints[0][1])/6];b[2]=[curvePoints[2][0]+(s*curvePoints[1][0]-s*curvePoints[3][0])/6,curvePoints[2][1]+(s*curvePoints[1][1]-s*curvePoints[3][1])/6];b[3]=[curvePoints[2][0],curvePoints[2][1]];if(!pathOpen){p.vertex(b[0][0],b[0][1]);}else{curShapeCount=1;}
     66p.vertex(b[1][0],b[1][1],b[2][0],b[2][1],b[3][0],b[3][1]);curvePoints.shift();}};p.curveTightness=function(tightness){curTightness=tightness;};p.bezierVertex=p.vertex;p.rectMode=function rectMode(aRectMode){curRectMode=aRectMode;};p.imageMode=function(){};p.ellipseMode=function ellipseMode(aEllipseMode){curEllipseMode=aEllipseMode;};p.dist=function dist(x1,y1,x2,y2){return Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2));};p.year=function year(){return(new Date).getYear()+1900;};p.month=function month(){return(new Date).getMonth();};p.day=function day(){return(new Date).getDay();};p.hour=function hour(){return(new Date).getHours();};p.minute=function minute(){return(new Date).getMinutes();};p.second=function second(){return(new Date).getSeconds();};p.millis=function millis(){return(new Date).getTime()-start;};p.ortho=function ortho(){};p.translate=function translate(x,y){curContext.translate(x,y);};p.scale=function scale(x,y){curContext.scale(x,y||x);};p.rotate=function rotate(aAngle){curContext.rotate(aAngle);};p.pushMatrix=function pushMatrix(){curContext.save();};p.popMatrix=function popMatrix(){curContext.restore();};p.redraw=function redraw(){if(hasBackground){p.background();}
     67p.frameCount++;inDraw=true;p.pushMatrix();p.draw();p.popMatrix();inDraw=false;};p.loop=function loop(){if(loopStarted)
     68return;looping=setInterval(function(){try{if(!p.paused){p.redraw();}}
     69catch(e){clearInterval(looping);throw e;}},1000/curFrameRate);loopStarted=true;};p.frameRate=function frameRate(aRate){curFrameRate=aRate;};p.background=function background(img){if(arguments.length){if(img&&img.img){curBackground=img;}else{curBackground=p.color.apply(this,arguments);}}
     70if(curBackground.img){p.image(curBackground,0,0);}else{var oldFill=curContext.fillStyle;curContext.fillStyle=curBackground+"";curContext.fillRect(0,0,p.width,p.height);curContext.fillStyle=oldFill;}};p.clear=function clear(x,y,width,height){arguments.length==0?curContext.clearRect(0,0,p.width,p.height):curContext.clearRect(x,y,width,height);}
     71p.str=function str(aNumber){return aNumber+'';}
     72p.sq=function sq(aNumber){return aNumber*aNumber;};p.sqrt=function sqrt(aNumber){return Math.sqrt(aNumber);};p.ngsqrt=function ngsqrt(aNumber){if(aNumber<=0){return Math.sqrt(-aNumber);}else{return Math.sqrt(aNumber);}};p.int=function int(aNumber){return Math.floor(aNumber);};p.min=function min(aNumber,aNumber2){return Math.min(aNumber,aNumber2);};p.max=function max(aNumber,aNumber2){return Math.max(aNumber,aNumber2);};p.ceil=function ceil(aNumber){return Math.ceil(aNumber);};p.round=function round(aNumber){return Math.round(aNumber);};p.norm=function norm(aNumber,low,high){var range=high-low;return((1/range)*aNumber)-((1/range)*low);};p.lerp=function lerp(value1,value2,amt){var range=value2-value1;return(range*amt)+value1;}
     73p.floor=function floor(aNumber){return Math.floor(aNumber);};p.float=function float(aNumber){return parseFloat(aNumber);};p.byte=function byte(aNumber){return aNumber||0;};p.random=function random(aMin,aMax){return arguments.length==2?aMin+(Math.random()*(aMax-aMin)):Math.random()*aMin;};p.noise=function(x,y,z){return arguments.length>=2?PerlinNoise_2D(x,y):PerlinNoise_2D(x,x);};function Noise(x,y){var n=x+y*57;n=(n<<13)^n;return Math.abs(1.0-(((n*((n*n*15731)+789221)+1376312589)&0x7fffffff)/1073741824.0));};function SmoothedNoise(x,y){var corners=(Noise(x-1,y-1)+Noise(x+1,y-1)+Noise(x-1,y+1)+Noise(x+1,y+1))/16;var sides=(Noise(x-1,y)+Noise(x+1,y)+Noise(x,y-1)+Noise(x,y+1))/8;var center=Noise(x,y)/4;return corners+sides+center;};function InterpolatedNoise(x,y){var integer_X=Math.floor(x);var fractional_X=x-integer_X;var integer_Y=Math.floor(y);var fractional_Y=y-integer_Y;var v1=SmoothedNoise(integer_X,integer_Y);var v2=SmoothedNoise(integer_X+1,integer_Y);var v3=SmoothedNoise(integer_X,integer_Y+1);var v4=SmoothedNoise(integer_X+1,integer_Y+1);var i1=Interpolate(v1,v2,fractional_X);var i2=Interpolate(v3,v4,fractional_X);return Interpolate(i1,i2,fractional_Y);}
     74function PerlinNoise_2D(x,y){var total=0;var p=0.25;var n=3;for(var i=0;i<=n;i++){var frequency=Math.pow(2,i);var amplitude=Math.pow(p,i);total=total+InterpolatedNoise(x*frequency,y*frequency)*amplitude;}
     75return total;}
     76function Interpolate(a,b,x){var ft=x*p.PI;var f=(1-p.cos(ft))*.5;return a*(1-f)+b*f;}
     77p.abs=function abs(aNumber){return Math.abs(aNumber);};p.cos=function cos(aNumber){return Math.cos(aNumber);};p.sin=function sin(aNumber){return Math.sin(aNumber);};p.pow=function pow(aNumber,aExponent){return Math.pow(aNumber,aExponent);};p.constrain=function constrain(aNumber,aMin,aMax){return Math.min(Math.max(aNumber,aMin),aMax);};p.sqrt=function sqrt(aNumber){return Math.sqrt(aNumber);};p.atan2=function atan2(aNumber,aNumber2){return Math.atan2(aNumber,aNumber2);};p.radians=function radians(aAngle){return(aAngle/180)*p.PI;};p.degrees=function degrees(aAngle){aAngle=(aAngle*180)/p.PI;if(aAngle<0){aAngle=360+aAngle}
     78return aAngle;};p.size=function size(aWidth,aHeight){var fillStyle=curContext.fillStyle;var strokeStyle=curContext.strokeStyle;curElement.width=p.width=aWidth;curElement.height=p.height=aHeight;curContext.fillStyle=fillStyle;curContext.strokeStyle=strokeStyle;};p.noStroke=function noStroke(){doStroke=false;};p.noFill=function noFill(){doFill=false;};p.smooth=function smooth(){};p.noSmooth=function noSmooth(){};p.noLoop=function noLoop(){clearInterval(looping);loopStarted=false;doLoop=false;};p.fill=function fill(){doFill=true;curContext.fillStyle=p.color.apply(this,arguments);};p.stroke=function stroke(){doStroke=true;curContext.strokeStyle=p.color.apply(this,arguments);};p.strokeWeight=function strokeWeight(w){curContext.lineWidth=w;};p.point=function point(x,y){var oldFill=curContext.fillStyle;curContext.fillStyle=curContext.strokeStyle;curContext.fillRect(Math.round(x),Math.round(y),1,1);curContext.fillStyle=oldFill;};p.get=function get(x,y){if(arguments.length==0){var c=p.createGraphics(p.width,p.height);c.image(curContext,0,0);return c;}
     79if(!getLoaded){getLoaded=buildImageObject(curContext.getImageData(0,0,p.width,p.height));}
     80return getLoaded.get(x,y);};p.set=function set(x,y,obj){if(obj&&obj.img){p.image(obj,x,y);}else{var oldFill=curContext.fillStyle;var color=obj;curContext.fillStyle=color;curContext.fillRect(Math.round(x),Math.round(y),1,1);curContext.fillStyle=oldFill;}};p.arc=function arc(x,y,width,height,start,stop){if(width<=0)
     81return;if(curEllipseMode==p.CORNER){x+=width/2;y+=height/2;}
     82curContext.moveTo(x,y);curContext.beginPath();curContext.arc(x,y,curEllipseMode==p.CENTER_RADIUS?width:width/2,start,stop,false);if(doStroke)
     83curContext.stroke();curContext.lineTo(x,y);if(doFill)
     84curContext.fill();curContext.closePath();};p.line=function line(x1,y1,x2,y2){curContext.lineCap="round";curContext.beginPath();curContext.moveTo(x1||0,y1||0);curContext.lineTo(x2||0,y2||0);curContext.stroke();curContext.closePath();};p.bezier=function bezier(x1,y1,x2,y2,x3,y3,x4,y4){curContext.lineCap="butt";curContext.beginPath();curContext.moveTo(x1,y1);curContext.bezierCurveTo(x2,y2,x3,y3,x4,y4);curContext.stroke();curContext.closePath();};p.triangle=function triangle(x1,y1,x2,y2,x3,y3){p.beginShape();p.vertex(x1,y1);p.vertex(x2,y2);p.vertex(x3,y3);p.endShape();};p.quad=function quad(x1,y1,x2,y2,x3,y3,x4,y4){curContext.lineCap="square";p.beginShape();p.vertex(x1,y1);p.vertex(x2,y2);p.vertex(x3,y3);p.vertex(x4,y4);p.endShape();};p.rect=function rect(x,y,width,height){if(width==0&&height==0)
     85return;curContext.beginPath();var offsetStart=0;var offsetEnd=0;if(curRectMode==p.CORNERS){width-=x;height-=y;}
     86if(curRectMode==p.RADIUS){width*=2;height*=2;}
     87if(curRectMode==p.CENTER||curRectMode==p.RADIUS){x-=width/2;y-=height/2;}
     88curContext.rect(Math.round(x)-offsetStart,Math.round(y)-offsetStart,Math.round(width)+offsetEnd,Math.round(height)+offsetEnd);if(doFill)
     89curContext.fill();if(doStroke)
     90curContext.stroke();curContext.closePath();};p.ellipse=function ellipse(x,y,width,height){x=x||0;y=y||0;if(width<=0&&height<=0)
     91return;curContext.beginPath();if(curEllipseMode==p.RADIUS){width*=2;height*=2;}
     92var offsetStart=0;if(width==height){curContext.arc(x-offsetStart,y-offsetStart,width/2,0,Math.PI*2,false);}else{var w=width/2;var h=height/2;var C=0.5522847498307933;var c_x=C*w;var c_y=C*h;curContext.moveTo(x+w,y);curContext.bezierCurveTo(x+w,y-c_y,x+c_x,y-h,x,y-h);curContext.bezierCurveTo(x-c_x,y-h,x-w,y-c_y,x-w,y);curContext.bezierCurveTo(x-w,y+c_y,x-c_x,y+h,x,y+h);curContext.bezierCurveTo(x+c_x,y+h,x+w,y+c_y,x+w,y);}
     93if(doFill)
     94curContext.fill();if(doStroke)
     95curContext.stroke();curContext.closePath();};p.link=function(href,target){window.location=href;};p.loadPixels=function(){p.pixels=buildImageObject(curContext.getImageData(0,0,p.width,p.height)).pixels;};p.updatePixels=function(){var colors=/(\d+),(\d+),(\d+),(\d+)/;var pixels={};pixels.width=p.width;pixels.height=p.height;pixels.data=[];if(curContext.createImageData){pixels=curContext.createImageData(p.width,p.height);}
     96var data=pixels.data;var pos=0;for(var i=0,l=p.pixels.length;i<l;i++){var c=(p.pixels[i]||"rgba(0,0,0,1)").match(colors);data[pos]=parseInt(c[1]);data[pos+1]=parseInt(c[2]);data[pos+2]=parseInt(c[3]);data[pos+3]=parseFloat(c[4])*255;pos+=4;}
     97curContext.putImageData(pixels,0,0);};p.extendClass=function extendClass(obj,args,fn){if(arguments.length==3){fn.apply(obj,args);}else{args.call(obj);}};p.addMethod=function addMethod(object,name,fn){if(object[name]){var args=fn.length;var oldfn=object[name];object[name]=function(){if(arguments.length==args)
     98return fn.apply(this,arguments);else
     99return oldfn.apply(this,arguments);};}else{object[name]=fn;}};p.init=function init(code){p.stroke(0);p.fill(255);curContext.translate(0.5,0.5);if(code){(function(Processing){with(p){eval(parse(code,p));}})(p);}
     100if(p.setup){inSetup=true;p.setup();}
     101inSetup=false;if(p.draw){if(!doLoop){p.redraw();}else{p.loop();}}
     102attach(document,"mousemove",function(e){var scrollX=window.scrollX!=null?window.scrollX:window.pageXOffset;var scrollY=window.scrollY!=null?window.scrollY:window.pageYOffset;p.pmouseX=p.mouseX;p.pmouseY=p.mouseY;p.mouseX=e.clientX-curElement.offsetLeft+scrollX;p.mouseY=e.clientY-curElement.offsetTop+scrollY;if(p.mouseMoved){p.mouseMoved();}
     103if(mousePressed&&p.mouseDragged){p.mouseDragged();}});attach(curElement,"mousedown",function(e){mousePressed=true;switch(e.which){case 1:p.mouseButton=p.LEFT;break;case 2:p.mouseButton=p.CENTER;break;case 3:p.mouseButton=p.RIGHT;break;}
     104if(typeof p.mousePressed=="function"){p.mousePressed();}else{p.mousePressed=true;}});attach(curElement,"contextmenu",function(e){e.preventDefault();e.stopPropagation();});attach(document,"mouseup",function(e){mousePressed=false;if(typeof p.mousePressed!="function"){p.mousePressed=false;}
     105if(p.mouseReleased){p.mouseReleased();}});attach(document,"keydown",function(e){keyPressed=true;p.key=e.keyCode+32;var i;for(i=0;i<p.codedKeys.length;i++){if(p.key==p.codedKeys[i]){switch(p.key){case 70:p.keyCode=p.UP;break;case 71:p.keyCode=p.RIGHT;break;case 72:p.keyCode=p.DOWN;break;case 69:p.keyCode=p.LEFT;break;}
     106p.key=p.CODED;}}
     107if(e.shiftKey){p.key=String.fromCharCode(p.key).toUpperCase().charCodeAt(0);}
     108if(typeof p.keyPressed=="function"){p.keyPressed();}else{p.keyPressed=true;}});attach(document,"keyup",function(e){keyPressed=false;if(typeof p.keyPressed!="function"){p.keyPressed=false;}
     109if(p.keyReleased){p.keyReleased();}});function attach(elem,type,fn){if(elem.addEventListener)
     110elem.addEventListener(type,fn,false);else
     111elem.attachEvent("on"+type,fn);}};return p;}})();
  • new file sagenb/data/graph_editor/processing.js

    diff --git a/sagenb/data/graph_editor/processing.js b/sagenb/data/graph_editor/processing.js
    new file mode 100644
    - +  
     1/*
     2
     3  P R O C E S S I N G - 0 . 0 . J S
     4  a port of the Processing visualization language
     5 
     6  License       : MIT
     7  Developer     : John Resig: http://ejohn.org
     8  Web Site      : http://processingjs.org 
     9  Java Version  : http://processing.org
     10  Github Repo.  : http://github.com/jeresig/processing-js
     11  Bug Tracking  : http://processing-js.lighthouseapp.com
     12  Mozilla POW!  : http://wiki.Mozilla.org/Education/Projects/ProcessingForTheWeb
     13  Maintained by : Seneca: http://zenit.senecac.on.ca/wiki/index.php/Processing.js
     14                  Hyper-Metrix: http://hyper-metrix.com/#Processing
     15
     16*/
     17
     18
     19(function(){
     20 
     21
     22  // Attach Processing to the window
     23  this.Processing = function Processing( aElement, aCode ){
     24
     25    // Get the DOM element if string was passed
     26    if( typeof aElement == "string" ){
     27      aElement = document.getElementById( aElement );
     28    }
     29     
     30    // Build an Processing functions and env. vars into 'p' 
     31    var p = buildProcessing( aElement ); 
     32
     33    // Send aCode Processing syntax to be converted to JavaScript
     34    if( aCode ){ p.init( aCode ); }
     35   
     36    return p;
     37   
     38  };
     39   
     40  // IE Unfriendly AJAX Method
     41  var ajax=function( url ){
     42    var AJAX;
     43    if( AJAX = new XMLHttpRequest() ){
     44      AJAX.open( "GET", url, false );
     45      AJAX.send( null );
     46      return AJAX.responseText;
     47    }else{
     48      return false;
     49    }
     50  };
     51 
     52  // Automatic Initialization Method
     53  var init = function(){
     54   
     55    var canvas  = document.getElementsByTagName( 'canvas' ),
     56        datasrc = undefined;
     57
     58    for( var i = 0; l = i < canvas.length; i++ ){
     59      if( datasrc = canvas[ i ].getAttribute( 'datasrc' ) ){
     60        Processing( canvas[ i ], ajax( datasrc ) );
     61      }
     62    }
     63   
     64  };
     65 
     66  addEventListener( 'DOMContentLoaded', function(){ init(); }, false );
     67 
     68  // Parse Processing (Java-like) syntax to JavaScript syntax with Regex
     69  var parse = Processing.parse = function parse( aCode, p ){
     70
     71    // Remove end-of-line comments
     72    aCode = aCode.replace( /\/\/ .*\n/g, "\n" );
     73
     74    // Weird parsing errors with %
     75    aCode = aCode.replace( /([^\s])%([^\s])/g, "$1 % $2" );
     76   
     77    // Simple convert a function-like thing to function
     78    aCode = aCode.replace( /(?:static )?(\w+ )(\w+)\s*(\([^\)]*\)\s*{)/g, function( all, type, name, args ){
     79      if ( name == "if" || name == "for" || name == "while" ) {
     80        return all;
     81      } else {
     82        return "Processing." + name + " = function " + name + args;
     83      }
     84    });
     85     
     86    // Attach import() to p{} bypassing JS command, allowing for extrernal library loading
     87    aCode = aCode.replace( /import \(|import\(/g, "p.Import(" );
     88   
     89    // Force .length() to be .length
     90    aCode = aCode.replace( /\.length\(\)/g, ".length" );
     91
     92    // foo( int foo, float bar )
     93    aCode = aCode.replace( /([\(,]\s*)(\w+)((?:\[\])+| )\s*(\w+\s*[\),])/g, "$1$4" );
     94    aCode = aCode.replace( /([\(,]\s*)(\w+)((?:\[\])+| )\s*(\w+\s*[\),])/g, "$1$4" );
     95
     96    // float[] foo = new float[5];
     97    aCode = aCode.replace( /new (\w+)((?:\[([^\]]*)\])+)/g, function( all, name, args ){
     98      return "new ArrayList(" + args.slice(1,-1).split("][").join(", ") + ")";
     99    });
     100   
     101    // What does this do?
     102    aCode = aCode.replace( /(?:static )?\w+\[\]\s*(\w+)\[?\]?\s*=\s*{.*?};/g, function( all ){
     103      return all.replace( /{/g, "[").replace(/}/g, "]" );
     104    });
     105
     106    // int|float foo;
     107    var intFloat = /(\n\s*(?:int|float)(?:\[\])?(?:\s*|[^\(]*?,\s*))([a-z]\w*)(;|,)/i;
     108    while( intFloat.test(aCode) ){
     109      aCode = aCode.replace( new RegExp( intFloat ), function( all, type, name, sep ){
     110        return type + " " + name + " = 0" + sep;
     111      });
     112    }
     113
     114    // float foo = 5;
     115    aCode = aCode.replace( /(?:static )?(\w+)((?:\[\])+| ) *(\w+)\[?\]?(\s*[=,;])/g, function( all, type, arr, name, sep ){
     116      if ( type == "return" )
     117        return all;
     118      else
     119        return "var " + name + sep;
     120    });
     121
     122    // Fix Array[] foo = {...} to [...]
     123    aCode = aCode.replace( /=\s*{((.|\s)*?)};/g, function(all,data){
     124      return "= [" + data.replace(/{/g, "[").replace(/}/g, "]") + "]";
     125    });
     126   
     127    // super() is a reserved word
     128    aCode = aCode.replace( /super\(/g, "superMethod(" );
     129
     130    var classes = [ "int", "float", "boolean", "string" ];
     131
     132    function ClassReplace( all, name, extend, vars, last ){
     133     
     134      classes.push( name );
     135
     136      var static = "";
     137
     138      vars = vars.replace( /final\s+var\s+(\w+\s*=\s*.*?;)/g, function( all, set ){
     139        static += " " + name + "." + set;
     140        return "";
     141      });
     142
     143      // Move arguments up from constructor and wrap contents with
     144      // a with(this), and unwrap constructor
     145      return "function " + name + "() {with(this){\n  " +
     146        ( extend ? "var __self=this;function superMethod(){extendClass(__self,arguments," + extend + ");}\n" : "" ) +
     147        // Replace var foo = 0; with this.foo = 0;
     148        // and force var foo; to become this.foo = null;
     149        vars
     150          .replace( /,\s?/g, ";\n  this." )
     151          .replace( /\b(var |final |public )+\s*/g, "this." )
     152          .replace( /\b(var |final |public )+\s*/g, "this." )
     153          .replace( /this.(\w+);/g, "this.$1 = null;" ) +
     154          ( extend ? "extendClass(this, " + extend + ");\n" : "" ) +
     155          "<CLASS " + name + " " + static + ">" + ( typeof last == "string" ? last : name + "(" );
     156      }
     157
     158      var matchClasses = /(?:public |abstract |static )*class (\w+)\s*(?:extends\s*(\w+)\s*)?{\s*((?:.|\n)*?)\b\1\s*\(/g;
     159      var matchNoCon = /(?:public |abstract |static )*class (\w+)\s*(?:extends\s*(\w+)\s*)?{\s*((?:.|\n)*?)(Processing)/g;
     160     
     161      aCode = aCode.replace( matchClasses, ClassReplace );
     162      aCode = aCode.replace( matchNoCon, ClassReplace );
     163
     164      var matchClass = /<CLASS (\w+) (.*?)>/, m;
     165     
     166      while ( ( m = aCode.match( matchClass ) ) ){
     167       
     168        var left        = RegExp.leftContext,
     169            allRest     = RegExp.rightContext,
     170            rest        = nextBrace( allRest ),
     171            className   = m[ 1 ],
     172            staticVars  = m[ 2 ] || "";
     173         
     174        allRest = allRest.slice( rest.length + 1 );
     175
     176        rest = rest.replace( new RegExp("\\b" + className + "\\(([^\\)]*?)\\)\\s*{", "g"), function( all, args ){
     177          args = args.split( /,\s*?/ );
     178         
     179          if( args[ 0 ].match( /^\s*$/ ) ){
     180            args.shift();
     181          }
     182         
     183          var fn = "if ( arguments.length == " + args.length + " ) {\n";
     184           
     185          for ( var i = 0; i < args.length; i++ ) {
     186            fn += "    var " + args[ i ] + " = arguments["+ i +"];\n";
     187          }
     188           
     189          return fn;
     190        });
     191       
     192        // Fix class method names
     193        // this.collide = function() { ... }
     194        // and add closing } for with(this) ...
     195        rest = rest.replace( /(?:public )?Processing.\w+ = function (\w+)\((.*?)\)/g, function( all, name, args ){
     196          return "ADDMETHOD(this, '" + name + "', function(" + args + ")";
     197        });
     198       
     199        var matchMethod = /ADDMETHOD([\s\S]*?{)/, mc;
     200        var methods = "";
     201       
     202        while ( ( mc = rest.match( matchMethod ) ) ){
     203          var prev    = RegExp.leftContext,
     204              allNext = RegExp.rightContext,
     205              next    = nextBrace(allNext);
     206
     207          methods += "addMethod" + mc[ 1 ] + next + "});";
     208         
     209          rest = prev + allNext.slice( next.length + 1 );
     210        }
     211
     212        rest = methods + rest;
     213       
     214        aCode = left + rest + "\n}}" + staticVars + allRest;
     215      }
     216
     217      // Do some tidying up, where necessary
     218      aCode = aCode.replace( /Processing.\w+ = function addMethod/g, "addMethod" );
     219     
     220      function nextBrace( right ) {
     221
     222        var rest      = right,
     223            position  = 0,
     224            leftCount = 1,
     225            rightCount = 0;
     226       
     227        while( leftCount != rightCount ) {
     228       
     229        var nextLeft  = rest.indexOf( "{" ),
     230            nextRight = rest.indexOf( "}" );
     231       
     232        if( nextLeft < nextRight && nextLeft != - 1 ) {
     233
     234          leftCount++;
     235          rest = rest.slice( nextLeft + 1 );
     236          position += nextLeft + 1;
     237
     238        }else{
     239
     240          rightCount++;
     241          rest = rest.slice( nextRight + 1 );
     242          position += nextRight + 1;
     243
     244        }
     245       
     246      }
     247       
     248      return right.slice( 0, position - 1 );
     249    }
     250
     251    // Handle (int) Casting
     252    aCode = aCode.replace( /\(int\)/g, "0|" );
     253
     254    // Remove Casting
     255    aCode = aCode.replace( new RegExp("\\((" + classes.join("|") + ")(\\[\\])?\\)", "g"), "" );
     256   
     257    // Convert 3.0f to just 3.0
     258    aCode = aCode.replace( /(\d+)f[^a-zA-Z0-9]/g, "$1" );
     259
     260    // Force numbers to exist //
     261    //aCode = aCode.replace(/([^.])(\w+)\s*\+=/g, "$1$2 = ($2||0) +");
     262
     263//!  // Force characters-as-bytes to work --> Ping: Andor
     264    aCode = aCode.replace(/('[a-zA-Z0-9]')/g, "$1.charCodeAt(0)");
     265
     266    // Convert #aaaaaa into color
     267    aCode = aCode.replace(/#([a-f0-9]{6})/ig, function(m, hex){
     268      var num = toNumbers(hex);
     269      return "DefaultColor(" + num[0] + "," + num[1] + "," + num[2] + ")";
     270    });
     271
     272    function toNumbers( str ){
     273      var ret = [];
     274     
     275      str.replace( /(..)/g, function( str ){
     276        ret.push( parseInt( str, 16 ) );
     277      });
     278     
     279      return ret;
     280    }
     281
     282    return aCode;
     283
     284  };
     285
     286
     287  // Attach Processing functions to 'p'
     288  function buildProcessing( curElement ){
     289             
     290    // Create the 'p' object
     291    var p = {};
     292   
     293    // Set Processing defaults / environment variables
     294    p.name            = 'Processing.js Instance';
     295    p.PI              = Math.PI;
     296    p.TWO_PI          = 2 * p.PI;
     297    p.HALF_PI         = p.PI / 2;
     298    p.P3D             = 3;
     299    p.CORNER          = 0;
     300    p.RADIUS          = 1;
     301    p.CENTER_RADIUS   = 1;
     302    p.CENTER          = 2;
     303    p.POLYGON         = 2;
     304    p.QUADS           = 5;
     305    p.TRIANGLES       = 6;
     306    p.POINTS          = 7;
     307    p.LINES           = 8;
     308    p.TRIANGLE_STRIP  = 9;
     309    p.TRIANGLE_FAN    = 4;
     310    p.QUAD_STRIP      = 3;
     311    p.CORNERS         = 10;
     312    p.CLOSE           = true;
     313    p.RGB             = 1;
     314    p.HSB             = 2; 
     315
     316    // KeyCode table 
     317    p.CENTER  = 88888880;
     318    p.CODED   = 88888888;
     319    p.UP      = 88888870;
     320    p.RIGHT   = 88888871;
     321    p.DOWN    = 88888872;
     322    p.LEFT    = 88888869;
     323   
     324//! // Description required...
     325    p.codedKeys = [ 69, 70, 71, 72  ];
     326
     327    // "Private" variables used to maintain state
     328    var curContext      = curElement.getContext( "2d" ),
     329        doFill          = true,
     330        doStroke        = true,
     331        loopStarted     = false,
     332        hasBackground   = false,
     333        doLoop          = true,
     334        looping         = 0,
     335        curRectMode     = p.CORNER,
     336        curEllipseMode  = p.CENTER,
     337        inSetup         = false,
     338        inDraw          = false,
     339        curBackground   = "rgba( 204, 204, 204, 1 )",
     340        curFrameRate    = 1000,
     341        curMsPerFrame   = 1,
     342        curShape        = p.POLYGON,
     343        curShapeCount   = 0,
     344        curvePoints     = [],
     345        curTightness    = 0,
     346        opacityRange    = 255,
     347        redRange        = 255,
     348        greenRange      = 255,
     349        blueRange       = 255,
     350        pathOpen        = false,
     351        mousePressed    = false,
     352        keyPressed      = false,
     353        curColorMode    = p.RGB;
     354        curTint         = - 1,
     355        curTextSize     = 12,
     356        curTextFont     = "Arial",
     357        getLoaded       = false,
     358        start           = ( new Date ).getTime();
     359
     360    var firstX,
     361        firstY,
     362        secondX,
     363        secondY,
     364        prevX,
     365        prevY;
     366   
     367    // Store a line for println(), print() handline
     368    p.ln = "";
     369   
     370    // Glyph path storage for textFonts
     371    p.glyphTable = {};
     372   
     373    // Global vars for tracking mouse position
     374    p.pmouseX     = 0;
     375    p.pmouseY     = 0;
     376    p.mouseX      = 0;
     377    p.mouseY      = 0;
     378    p.mouseButton = 0;
     379    p.mouseDown   = false;
     380
     381    // Undefined event handlers to be replaced by user when needed
     382    p.mouseClicked = undefined;
     383    p.mouseDragged = undefined;
     384    p.mouseMoved = undefined;
     385    p.mousePressed = undefined;
     386    p.mouseReleased = undefined;
     387    p.keyPressed = undefined;
     388    p.keyReleased = undefined;
     389    p.draw = undefined;
     390    p.setup = undefined;
     391
     392    // The height/width of the canvas
     393    p.width  = curElement.width  - 0;
     394    p.height = curElement.height - 0;
     395
     396    // The current animation frame
     397    p.frameCount = 0;           
     398   
     399   
     400
     401    ////////////////////////////////////////////////////////////////////////////
     402    // Array handling
     403    ////////////////////////////////////////////////////////////////////////////
     404
     405    p.shorten = function( ary ){
     406   
     407      var newary = new Array();
     408
     409      // copy array into new array
     410      var len = ary.length;     
     411      for( var i = 0; i < len; i++ ){
     412        newary[ i ] = ary[ i ];
     413      }
     414
     415      newary.pop();
     416
     417      return newary;
     418    }
     419
     420 
     421    p.expand = function( ary, newSize ){
     422
     423      var newary = new Array();
     424     
     425      var len = ary.length
     426      for( var i = 0; i < len; i++ ){
     427          newary[ i ] = ary[ i ];
     428      }
     429     
     430      if( arguments.length == 1 ){
     431       
     432        // double size of array
     433        newary.length *= 2;
     434       
     435      }else if( arguments.length == 2 ){
     436       
     437        // size is newSize
     438        newary.length = newSize;
     439       
     440      }
     441     
     442      return newary;
     443    }
     444
     445
     446
     447    p.ArrayList = function ArrayList( size, size2, size3 ){
     448   
     449      var array = new Array( 0 | size );
     450     
     451      if( size2 ){
     452       
     453        for( var i = 0; i < size; i++ ){
     454         
     455          array[ i ] = [];
     456
     457          for( var j = 0; j < size2; j++ ){
     458            var a = array[ i ][ j ] = size3 ? new Array( size3 ) : 0 ; 
     459            for( var k = 0; k < size3; k++ ){ a[ k ] = 0; }
     460          }
     461         
     462        }
     463       
     464      }else{
     465       
     466        for( var i = 0; i < size; i++ ){ array[ i ] = 0; }       
     467      }
     468     
     469      array.get     = function( i    ){ return this[ i ];           };
     470      array.add     = function( item ){ return this.push( item );   };
     471      array.size    = function(      ){ return this.length;         };     
     472      array.clear   = function(      ){ this.length = 0;            };
     473      array.remove  = function( i    ){ return this.splice( i, 1 ); };
     474      array.isEmpty = function(      ){ return !this.length;        };
     475      array.clone   = function(      ){
     476                                        var a = new ArrayList( size );
     477                                        for( var i = 0; i < size; i++ ){
     478                                          a[ i ] = this[ i ];
     479                                        }
     480                                        return a;
     481                                      };
     482     
     483      return array;
     484    };
     485
     486
     487
     488    ////////////////////////////////////////////////////////////////////////////
     489    // Color functions
     490    ////////////////////////////////////////////////////////////////////////////
     491
     492    // In case I ever need to do HSV conversion:
     493    // http://srufaculty.sru.edu/david.dailey/javascript/js/5rml.js
     494    p.color = function color( aValue1, aValue2, aValue3, aValue4 ) {
     495      var aColor = "";
     496     
     497      if ( arguments.length == 3 ) {
     498     
     499        aColor = p.color( aValue1, aValue2, aValue3, opacityRange );
     500      } else if ( arguments.length == 4 ) {
     501        var a = aValue4 / opacityRange;
     502        a = isNaN(a) ? 1 : a;
     503
     504        if ( curColorMode == p.HSB ) {
     505          var rgb = HSBtoRGB(aValue1, aValue2, aValue3);
     506          var r = rgb[0], g = rgb[1], b = rgb[2];
     507        } else {
     508          var r = getColor(aValue1, redRange);
     509          var g = getColor(aValue2, greenRange);
     510          var b = getColor(aValue3, blueRange);
     511        }
     512
     513        aColor = "rgba(" + r + "," + g + "," + b + "," + a + ")";
     514      } else if ( typeof aValue1 == "string" ) {
     515        aColor = aValue1;
     516
     517        if ( arguments.length == 2 ) {
     518          var c = aColor.split(",");
     519          c[3] = (aValue2 / opacityRange) + ")";
     520          aColor = c.join(",");
     521        }
     522      } else if ( arguments.length == 2 ) {
     523        aColor = p.color( aValue1, aValue1, aValue1, aValue2 );
     524      } else if ( typeof aValue1 == "number" && aValue1 < 256 && aValue1 >= 0) {
     525        aColor = p.color( aValue1, aValue1, aValue1, opacityRange );
     526      } else if ( typeof aValue1 == "number" ) {
     527        var intcolor = 0;
     528        if( aValue1 < 0 ){
     529          intcolor = 4294967296 - ( aValue1 * -1 );
     530        }else{
     531          intcolor = aValue1;
     532        }
     533        var ac = Math.floor((intcolor % 4294967296) / 16777216);
     534        var rc = Math.floor((intcolor % 16777216) / 65536);
     535        var gc = Math.floor((intcolor % 65536) / 256);
     536        var bc = intcolor % 256;
     537         
     538        aColor = p.color( rc, gc, bc, ac );
     539      } else {
     540        aColor = p.color( redRange, greenRange, blueRange, opacityRange );
     541      }
     542
     543      // HSB conversion function from Mootools, MIT Licensed
     544      function HSBtoRGB(h, s, b) {
     545        h = (h / redRange) * 360;
     546        s = (s / greenRange) * 100;
     547        b = (b / blueRange) * 100;
     548        var br = Math.round(b / 100 * 255);
     549        if (s == 0){
     550          return [br, br, br];
     551        } else {
     552          var hue = h % 360;
     553          var f = hue % 60;
     554          var p = Math.round((b * (100 - s)) / 10000 * 255);
     555          var q = Math.round((b * (6000 - s * f)) / 600000 * 255);
     556          var t = Math.round((b * (6000 - s * (60 - f))) / 600000 * 255);
     557          switch (Math.floor(hue / 60)){
     558            case 0: return [br, t, p];
     559            case 1: return [q, br, p];
     560            case 2: return [p, br, t];
     561            case 3: return [p, q, br];
     562            case 4: return [t, p, br];
     563            case 5: return [br, p, q];
     564          }
     565        }
     566      }
     567   
     568      function getColor( aValue, range ) {
     569        return Math.round(255 * (aValue / range));
     570      }
     571     
     572      return aColor;
     573    }
     574   
     575    p.red   = function( aColor ){ return parseInt( verifyChannel( aColor ).slice( 5 ) ); };
     576    p.green = function( aColor ){ return parseInt( verifyChannel( aColor ).split( "," )[ 1 ] ); };
     577    p.blue  = function( aColor ){ return parseInt( verifyChannel( aColor ).split( "," )[ 2 ] ); };
     578    p.alpha = function( aColor ){ return parseInt( parseFloat( verifyChannel( aColor ).split( "," )[ 3 ] ) * 255 ); };
     579
     580    function verifyChannel( aColor ){
     581      if( aColor.constructor == Array ){   
     582        return aColor;
     583      } else {
     584        return p.color( aColor );
     585      }
     586    }
     587   
     588    p.lerpColor = function lerpColor( c1, c2, amt ){
     589       
     590      // Get RGBA values for Color 1 to floats
     591      var colors1 = p.color( c1 ).split( "," );
     592      var r1 =   parseInt( colors1[ 0 ].split( "(" )[ 1 ] );
     593      var g1 =   parseInt( colors1[ 1 ] );
     594      var b1 =   parseInt( colors1[ 2 ] );
     595      var a1 = parseFloat( colors1[ 3 ].split( ")" )[ 0 ] );
     596         
     597      // Get RGBA values for Color 2 to floats
     598      var colors2 = p.color( c2 ).split( "," );
     599      var r2 =   parseInt( colors2[ 0 ].split( "(" )[ 1 ] );
     600      var g2 =   parseInt( colors2[ 1 ] );
     601      var b2 =   parseInt( colors2[ 2 ] );
     602      var a2 = parseFloat( colors2[ 3 ].split( ")" )[ 0 ] );           
     603                       
     604      // Return lerp value for each channel, INT for color, Float for Alpha-range
     605      var r =   parseInt( p.lerp( r1, r2, amt ) );
     606      var g =   parseInt( p.lerp( g1, g2, amt ) );
     607      var b =   parseInt( p.lerp( b1, b2, amt ) );
     608      var a = parseFloat( p.lerp( a1, a2, amt ) );
     609     
     610      return aColor = "rgba("+ r +","+ g +","+ b +","+ a +")";
     611   
     612    }
     613
     614    // Forced default color mode for #aaaaaa style
     615    p.DefaultColor = function( aValue1, aValue2, aValue3 ){
     616      var tmpColorMode = curColorMode;
     617      curColorMode = p.RGB;
     618      var c = p.color(aValue1 / 255 * redRange, aValue2 / 255 * greenRange, aValue3 / 255 * blueRange );
     619      curColorMode = tmpColorMode;
     620      return c;
     621    }
     622   
     623    p.colorMode = function colorMode( mode, range1, range2, range3, range4 ){
     624      curColorMode = mode;
     625      if( arguments.length >= 4 ){ redRange     = range1; greenRange = range2; blueRange  = range3; }
     626      if( arguments.length == 5 ){ opacityRange = range4; }
     627      if( arguments.length == 2 ){ p.colorMode( mode, range1, range1, range1, range1 ); }   
     628    };
     629   
     630
     631    ////////////////////////////////////////////////////////////////////////////
     632    // Canvas-Matrix manipulation
     633    ////////////////////////////////////////////////////////////////////////////
     634
     635    p.translate   = function translate( x, y ){ curContext.translate( x, y );   };   
     636    p.scale       = function scale( x, y )    { curContext.scale( x, y || x );  };   
     637    p.rotate      = function rotate( aAngle ) { curContext.rotate( aAngle );    };   
     638    p.pushMatrix  = function pushMatrix()     { curContext.save();              };
     639    p.popMatrix   = function popMatrix()      { curContext.restore();           };
     640    p.ortho       = function ortho(){};
     641
     642
     643   
     644    ////////////////////////////////////////////////////////////////////////////
     645    //Time based functions
     646    ////////////////////////////////////////////////////////////////////////////
     647
     648    p.year    = function year()  { return ( new Date ).getYear() + 1900;   };
     649    p.month   = function month() { return ( new Date ).getMonth();         };
     650    p.day     = function day()   { return ( new Date ).getDay();           };
     651    p.hour    = function hour()  { return ( new Date ).getHours();         };
     652    p.minute  = function minute(){ return ( new Date ).getMinutes();       };
     653    p.second  = function second(){ return ( new Date ).getSeconds();       };
     654    p.millis  = function millis(){ return ( new Date ) .getTime() - start; };
     655   
     656    p.noLoop  = function noLoop(){ doLoop = false; };
     657         
     658    p.redraw = function redraw(){
     659      if( hasBackground ){ p.background(); }
     660      p.frameCount++;     
     661      inDraw = true;
     662      p.pushMatrix();
     663      p.draw();
     664      p.popMatrix();
     665      inDraw = false;     
     666    };
     667   
     668    p.loop = function loop(){
     669     
     670      if( loopStarted ){ return; }
     671     
     672      looping = setInterval( function(){
     673         
     674          try {
     675                      p.redraw();
     676              }
     677          catch( e ){
     678                      clearInterval( looping );
     679                      throw e;
     680                    }
     681      }, curMsPerFrame );
     682     
     683      loopStarted = true;
     684     
     685    };
     686   
     687    p.frameRate = function frameRate( aRate ){
     688      curFrameRate = aRate;
     689      curMsPerFrame = 1000 / curFrameRate;
     690    };
     691
     692    p.exit = function exit(){
     693      clearInterval( looping );
     694    };
     695   
     696   
     697   
     698    ////////////////////////////////////////////////////////////////////////////
     699    // MISC functions
     700    ////////////////////////////////////////////////////////////////////////////
     701    p.cursor = function(mode){ document.body.style.cursor=mode; }
     702    p.link = function( href, target ) { window.location = href; };
     703    p.beginDraw = function beginDraw(){};
     704    p.endDraw = function endDraw(){};
     705   
     706    p.ajax = ajax;
     707   
     708    // Imports an external Processing.js library
     709    p.Import = function Import( lib ){
     710      eval( p.ajax( lib ) );
     711    }
     712
     713   
     714
     715    ////////////////////////////////////////////////////////////////////////////
     716    // String functions
     717    ////////////////////////////////////////////////////////////////////////////
     718
     719    p.nfs = function( num, left, right){
     720      var str;
     721      // array handling
     722      if (typeof num == "object"){
     723        str = new Array();
     724        len = num.length;
     725        for(var i=0; i < len; i++){
     726          str[i] = p.nfs(num[i], left, right);
     727        }
     728      }
     729      else if (arguments.length == 3){
     730        var negative = false;
     731        if (num < 0)
     732          negative = true;
     733         
     734        str = "" + Math.abs(num);
     735        var digits = ("" + Math.floor(Math.abs(num))).length;
     736        var count = left - digits;
     737        while (count > 0){
     738          str = "0" + str;
     739          count--;
     740        }
     741        // get the number of decimal places, if none will be -1
     742        var decimals = ("" + Math.abs(num)).length - digits - 1;
     743        if (decimals == -1 && right > 0)
     744          str = str + ".";
     745        if (decimals != -1)
     746          count = right - decimals;
     747        else if (decimals == -1 && right > 0){
     748          count = right;
     749        }
     750        else
     751          count = 0;
     752        while (count > 0){
     753          str = str + "0";
     754          count--;
     755        }
     756        str = (negative ? "-" : " ") + str;
     757      }
     758      else if (arguments.length == 2){
     759        str = p.nfs(num, left, 0);
     760      }
     761      return str;
     762    }
     763   
     764   
     765    p.unhex = function( str ){
     766        var value = 0,
     767            multiplier = 1,
     768            num = 0;
     769       
     770        var len = str.length - 1;
     771        for (var i = len ; i >= 0; i--){
     772            try{
     773                switch(str[i]){
     774                    case "0": num = 0; break;
     775                    case "1": num = 1; break;
     776                    case "2": num = 2; break;
     777                    case "3": num = 3; break;
     778                    case "4": num = 4; break;
     779                    case "5": num = 5; break;
     780                    case "6": num = 6; break;
     781                    case "7": num = 7; break;
     782                    case "8": num = 8; break;
     783                    case "9": num = 9; break;
     784                    case "A":
     785                    case "a": num = 10; break;
     786                    case "B":
     787                    case "b": num = 11; break;
     788                    case "C":
     789                    case "c": num = 12; break;
     790                    case "D":
     791                    case "d": num = 13; break;
     792                    case "E":
     793                    case "e": num = 14; break;
     794                    case "F":
     795                    case "f": num = 15; break;
     796                    default:return 0; break;
     797                }
     798                value += num * multiplier;
     799                multiplier *= 16;
     800            }catch(e){;}
     801            // correct for int overflow java expectation
     802            if (value > 2147483647)
     803            {
     804                value -= 4294967296;
     805            } 
     806        }
     807        return value;
     808      }
     809
     810
     811    // Load a file or URL into strings     
     812    p.loadStrings = function loadStrings( url ){
     813      return p.ajax( url ).split( "\n" );             
     814    };
     815
     816    p.nf = function( num, pad ){
     817      var str = "" + num;
     818      while ( pad - str.length ){
     819        str = "0" + str;
     820      }
     821      return str;
     822    };
     823
     824    String.prototype.replaceAll = function( re, replace ){
     825      return this.replace( new RegExp( re, "g" ), replace );
     826    };
     827       
     828    // Returns a line to lnPrinted() for user handling
     829    p.lnPrinted = function lnPrinted(){};
     830    p.printed   = function printed()  {}; 
     831   
     832    // Event to send output to user control function print()/println()
     833    p.println = function println(){
     834     
     835      // Not working on Safari :( find work around!
     836      if( arguments.callee.caller ){
     837     
     838        var Caller = arguments.callee.caller.name.toString();
     839       
     840        if( arguments.length > 1 ){
     841
     842          Caller != "print"        ?
     843            p.ln  = arguments      :
     844            p.ln  = arguments[ 0 ] ;
     845
     846        }else{
     847
     848            p.ln  = arguments[ 0 ] ;
     849        }
     850       
     851        //Returns a line to lnPrinted() for user error handling/debugging
     852        Caller == "print"          ?       
     853          p.printed( arguments )   :
     854          p.lnPrinted()            ;
     855       
     856      }
     857     
     858    };   
     859
     860    // Converts a number to a string
     861    p.str = function str( aNumber ){ return aNumber+''; }   
     862   
     863    p.print = function print(){ p.println(arguments[ 0 ] ) };
     864   
     865    p.char = function char( key ){ return key; };
     866   
     867   
     868   
     869    ////////////////////////////////////////////////////////////////////////////
     870    // Math functions
     871    ////////////////////////////////////////////////////////////////////////////
     872   
     873    p.sq      = function sq     ( aNumber             ){ return aNumber * aNumber;                       };
     874    p.sqrt    = function sqrt   ( aNumber             ){ return Math.sqrt( aNumber );                    };
     875    p.int     = function int    ( aNumber             ){ return Math.floor( aNumber );                   };
     876    p.min     = function min    ( aNumber, aNumber2   ){ return Math.min( aNumber, aNumber2 );           };
     877    p.max     = function max    ( aNumber, aNumber2   ){ return Math.max( aNumber, aNumber2 );           };
     878    p.floor   = function floor  ( aNumber             ){ return Math.floor( aNumber );                   };
     879    p.float   = function float  ( aNumber             ){ return parseFloat( aNumber );                   };
     880    p.ceil    = function ceil   ( aNumber             ){ return Math.ceil( aNumber );                    };   
     881    p.round   = function round  ( aNumber             ){ return Math.round( aNumber );                   };
     882    p.lerp    = function lerp   ( value1, value2, amt ){ return ( ( value2 - value1 ) * amt ) + value1;  };
     883    p.abs    = function abs     ( aNumber             ){ return Math.abs( aNumber );                     };
     884    p.cos     = function cos    ( aNumber             ){ return Math.cos( aNumber );                     };
     885    p.sin     = function sin    ( aNumber             ){ return Math.sin( aNumber );                     };
     886    p.pow     = function pow    ( aNumber, aExponent  ){ return Math.pow( aNumber, aExponent );          };
     887    p.sqrt    = function sqrt   ( aNumber             ){ return Math.sqrt( aNumber );                    };
     888    p.atan2   = function atan2  ( aNumber, aNumber2   ){ return Math.atan2( aNumber, aNumber2 );         };
     889    p.radians = function radians( aAngle              ){ return ( aAngle / 180 ) * p.PI;                 };
     890
     891    p.dist = function dist( x1, y1, x2, y2 ){
     892      return Math.sqrt( Math.pow( x2 - x1, 2 ) + Math.pow( y2 - y1, 2 ) );
     893    };
     894
     895    p.map = function map( value, istart, istop, ostart, ostop ){
     896      return ostart + ( ostop - ostart ) * ( ( value - istart ) / ( istop - istart ) );
     897    };
     898
     899    p.Random = function(){
     900
     901      var haveNextNextGaussian = false,
     902          nextNextGaussian;
     903
     904      this.nextGaussian = function(){
     905       
     906        if( haveNextNextGaussian ){
     907       
     908          haveNextNextGaussian = false;
     909          return nextNextGaussian;
     910       
     911        }else{
     912         
     913          var v1, v2, s;
     914          do{
     915              v1 = 2 * p.random( 1 ) - 1;   // between -1.0 and 1.0
     916              v2 = 2 * p.random( 1 ) - 1;   // between -1.0 and 1.0
     917              s = v1 * v1 + v2 * v2;
     918          }
     919          while( s >= 1 || s == 0 );
     920         
     921          var multiplier = Math.sqrt( - 2 * Math.log( s ) / s );
     922          nextNextGaussian = v2 * multiplier;
     923          haveNextNextGaussian = true;
     924
     925          return v1 * multiplier;
     926       
     927        }
     928       
     929      };
     930     
     931    };
     932
     933//! This can't be right... right?
     934    p.byte     = function byte( aNumber               ){ return aNumber || 0;                           };
     935
     936    p.norm     = function norm( aNumber, low, high   ){
     937      var range = high-low;
     938      return ( ( 1 / range ) * aNumber ) - ( ( 1 / range ) * low );
     939    };       
     940   
     941    p.random = function random( aMin, aMax ) {
     942      return arguments.length == 2                   ?
     943        aMin + ( Math.random() * ( aMax - aMin ) )  :
     944        Math.random() * aMin                        ;
     945    };
     946
     947    // From: http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
     948    p.noise = function( x, y, z ){
     949      return arguments.length >= 2  ?
     950        PerlinNoise_2D( x, y, z )    :
     951        PerlinNoise_3D( x, x, z )    ;
     952    };
     953
     954    function Noise( x, y ){
     955      var n = x + y * 57;
     956      n = ( n << 13 ) ^ n;
     957      return Math.abs( 1.0 - ( ( ( n * ( ( n * n * 15731 ) + 789221 ) + 1376312589 ) & 0x7fffffff ) / 1073741824.0 ) );
     958    };
     959
     960    function SmoothedNoise( x, y ){
     961      var corners = ( Noise( x - 1, y - 1 ) + Noise( x + 1, y - 1 ) + Noise( x - 1, y + 1 ) + Noise( x + 1, y + 1 ) ) / 16,
     962          sides   = ( Noise( x - 1, y ) + Noise( x + 1, y ) + Noise( x, y - 1 ) + Noise( x, y + 1 ) ) / 8,
     963          center  = Noise( x, y ) / 4;
     964      return corners + sides + center;
     965    };
     966
     967    function InterpolatedNoise( x, y ){
     968
     969      var integer_X    = Math.floor( x );
     970      var fractional_X = x - integer_X;
     971
     972      var integer_Y    = Math.floor( y );
     973      var fractional_Y = y - integer_Y;
     974
     975      var v1 = SmoothedNoise( integer_X,     integer_Y     ),
     976          v2 = SmoothedNoise( integer_X + 1, integer_Y     ),
     977          v3 = SmoothedNoise( integer_X,     integer_Y + 1 ),
     978          v4 = SmoothedNoise( integer_X + 1, integer_Y + 1 );
     979
     980      var i1 = Interpolate( v1, v2, fractional_X ),
     981          i2 = Interpolate( v3, v4, fractional_X );
     982
     983      return Interpolate( i1, i2, fractional_Y );
     984     
     985    }
     986
     987
     988    function PerlinNoise_2D( x, y ){
     989
     990        var total = 0,
     991            p     = 0.25,
     992            n     = 3;
     993
     994        for( var i = 0; i <= n; i++ ){
     995          var frequency = Math.pow( 2, i );
     996          var amplitude = Math.pow( p, i );
     997          total += InterpolatedNoise( x * frequency, y * frequency ) * amplitude;
     998        }
     999
     1000        return total;
     1001    }
     1002
     1003    function Interpolate( a, b, x ){
     1004      var ft   = x * p.PI;
     1005      var f   = (1 - Math.cos( ft ) ) * .5;
     1006      return  a * ( 1 - f ) + b * f;
     1007    }
     1008   
     1009    p.constrain = function constrain( aNumber, aMin, aMax ){
     1010      return Math.min( Math.max( aNumber, aMin ), aMax );
     1011    };
     1012         
     1013    p.degrees = function degrees( aAngle ){
     1014      aAngle = ( aAngle * 180 ) / p.PI; 
     1015      if (aAngle < 0) {aAngle = 360 + aAngle}   
     1016      return aAngle;
     1017    };
     1018   
     1019    p.size = function size( aWidth, aHeight ){   
     1020      var fillStyle = curContext.fillStyle,
     1021          strokeStyle = curContext.strokeStyle;
     1022
     1023      curElement.width = p.width = aWidth;
     1024      curElement.height = p.height = aHeight;
     1025
     1026      curContext.fillStyle = fillStyle;
     1027      curContext.strokeStyle = strokeStyle;
     1028    };
     1029   
     1030
     1031   
     1032    ////////////////////////////////////////////////////////////////////////////
     1033    // Style functions
     1034    ////////////////////////////////////////////////////////////////////////////
     1035   
     1036    p.noStroke   = function noStroke()  { doStroke = false; };   
     1037    p.noFill     = function noFill()    { doFill = false;   };
     1038    p.smooth     = function smooth()    {};
     1039    p.noSmooth   = function noSmooth()  {};       
     1040   
     1041    p.fill = function fill(){
     1042      doFill = true;
     1043      curContext.fillStyle = p.color.apply( this, arguments );   
     1044    };
     1045   
     1046    p.stroke = function stroke(){
     1047      doStroke = true;
     1048      curContext.strokeStyle = p.color.apply( this, arguments );
     1049    };
     1050
     1051    p.strokeWeight = function strokeWeight( w ){
     1052      curContext.lineWidth = w;
     1053    };
     1054
     1055       
     1056       
     1057    ////////////////////////////////////////////////////////////////////////////
     1058    // Vector drawing functions
     1059    ////////////////////////////////////////////////////////////////////////////
     1060
     1061    p.Point = function Point( x, y ){
     1062      this.x = x;
     1063      this.y = y;
     1064      this.copy = function(){
     1065        return new Point( x, y );
     1066      }
     1067    };
     1068   
     1069    p.point = function point( x, y ){
     1070      var oldFill = curContext.fillStyle;
     1071      curContext.fillStyle = curContext.strokeStyle;
     1072      curContext.fillRect( Math.round( x ), Math.round( y ), 1, 1 );
     1073      curContext.fillStyle = oldFill;
     1074    };
     1075   
     1076    p.beginShape = function beginShape( type ){
     1077      curShape = type;
     1078      curShapeCount = 0;
     1079      curvePoints = [];
     1080    };
     1081   
     1082    p.endShape = function endShape( close ){
     1083     
     1084      if( curShapeCount != 0 ){
     1085       
     1086        if( close || doFill ){ curContext.lineTo( firstX, firstY ); }
     1087        if( doFill          ){ curContext.fill();                   }         
     1088        if( doStroke        ){ curContext.stroke();                 }
     1089     
     1090        curContext.closePath();
     1091        curShapeCount = 0;
     1092        pathOpen = false;
     1093       
     1094      }
     1095
     1096      if( pathOpen ){
     1097       
     1098        if ( doFill   ){ curContext.fill();   }
     1099        if ( doStroke ){ curContext.stroke(); }
     1100
     1101        curContext.closePath();
     1102        curShapeCount = 0;
     1103        pathOpen = false;
     1104       
     1105      }
     1106     
     1107    };
     1108   
     1109    p.vertex = function vertex( x, y, x2, y2, x3, y3 ){   
     1110     
     1111      if( curShapeCount == 0 && curShape != p.POINTS ){
     1112
     1113        pathOpen = true;
     1114        curContext.beginPath();
     1115        curContext.moveTo( x, y );
     1116        firstX = x;
     1117        firstY = y;
     1118
     1119      }else{
     1120
     1121        if( curShape == p.POINTS ){
     1122
     1123          p.point( x, y );
     1124
     1125        }else if( arguments.length == 2 ){
     1126         
     1127          if( curShape != p.QUAD_STRIP || curShapeCount != 2 ){
     1128
     1129            curContext.lineTo( x, y );
     1130
     1131          }
     1132         
     1133          if( curShape == p.TRIANGLE_STRIP ){
     1134           
     1135            if( curShapeCount == 2 ){
     1136             
     1137              // finish shape
     1138              p.endShape( p.CLOSE );
     1139              pathOpen = true;
     1140              curContext.beginPath();
     1141             
     1142              // redraw last line to start next shape
     1143              curContext.moveTo( prevX, prevY );
     1144              curContext.lineTo( x, y );
     1145              curShapeCount = 1;
     1146             
     1147            }
     1148           
     1149            firstX = prevX;
     1150            firstY = prevY;
     1151         
     1152          }
     1153
     1154          if( curShape == p.TRIANGLE_FAN && curShapeCount == 2 ){
     1155           
     1156            // finish shape
     1157            p.endShape( p.CLOSE) ;
     1158            pathOpen = true;
     1159            curContext.beginPath();
     1160       
     1161            // redraw last line to start next shape
     1162            curContext.moveTo( firstX, firstY );
     1163            curContext.lineTo( x, y );
     1164            curShapeCount = 1;
     1165         
     1166          }
     1167     
     1168          if( curShape == p.QUAD_STRIP && curShapeCount == 3 ){
     1169           
     1170            // finish shape
     1171            curContext.lineTo( prevX, prevY );
     1172            p.endShape(p.CLOSE);
     1173            pathOpen = true;
     1174            curContext.beginPath();
     1175     
     1176            // redraw lines to start next shape
     1177            curContext.moveTo( prevX, prevY );
     1178            curContext.lineTo( x, y );
     1179            curShapeCount = 1;
     1180         
     1181          }
     1182
     1183          if( curShape == p.QUAD_STRIP ){
     1184           
     1185            firstX  = secondX;
     1186            firstY  = secondY;
     1187            secondX = prevX;
     1188            secondY = prevY;
     1189           
     1190          }
     1191       
     1192        }else if( arguments.length == 4 ){
     1193       
     1194          if( curShapeCount > 1 ){
     1195           
     1196            curContext.moveTo( prevX, prevY );
     1197            curContext.quadraticCurveTo( firstX, firstY, x, y );
     1198            curShapeCount = 1;
     1199         
     1200          }
     1201       
     1202        }else if( arguments.length == 6 ){
     1203         
     1204          curContext.bezierCurveTo( x, y, x2, y2, x3, y3 );
     1205
     1206        }
     1207      }
     1208
     1209      prevX = x;
     1210      prevY = y;
     1211      curShapeCount ++;
     1212     
     1213      if(   curShape == p.LINES && curShapeCount == 2       ||
     1214          ( curShape == p.TRIANGLES ) && curShapeCount == 3 ||
     1215          ( curShape == p.QUADS     ) && curShapeCount == 4
     1216        ){
     1217          p.endShape( p.CLOSE );
     1218        }
     1219   
     1220    };
     1221
     1222    p.curveVertex = function( x, y, x2, y2 ){
     1223     
     1224      if( curvePoints.length < 3 ){
     1225       
     1226        curvePoints.push( [ x, y ] );
     1227     
     1228      }else{
     1229     
     1230        var b = [], s = 1 - curTightness;
     1231
     1232        /*
     1233         * Matrix to convert from Catmull-Rom to cubic Bezier
     1234         * where t = curTightness
     1235         * |0         1          0         0       |
     1236         * |(t-1)/6   1          (1-t)/6   0       |
     1237         * |0         (1-t)/6    1         (t-1)/6 |
     1238         * |0         0          0         0       |
     1239         */
     1240
     1241        curvePoints.push( [ x, y ] );
     1242
     1243        b[ 0 ] = [ curvePoints[ 1 ][ 0 ], curvePoints[ 1 ][ 1 ] ];
     1244        b[ 1 ] = [ curvePoints[ 1 ][ 0 ] + ( s * curvePoints[ 2 ][ 0 ] - s * curvePoints[ 0 ][ 0 ] ) / 6, curvePoints[ 1 ][ 1 ] + ( s * curvePoints[ 2 ][ 1 ] - s * curvePoints[ 0 ][ 1 ] ) / 6 ];
     1245        b[ 2 ] = [ curvePoints[ 2 ][ 0 ] + ( s * curvePoints[ 1 ][ 0 ] - s * curvePoints[ 3 ][ 0 ] ) / 6, curvePoints[ 2 ][ 1 ] + ( s * curvePoints[ 1 ][ 1 ] - s * curvePoints[ 3 ][ 1 ] ) / 6 ];
     1246        b[ 3 ] = [ curvePoints[ 2 ][ 0 ], curvePoints[ 2 ][ 1 ] ];
     1247
     1248        if( !pathOpen ){
     1249          p.vertex( b[ 0 ][ 0 ], b[ 0 ][ 1 ] );
     1250        }else{
     1251          curShapeCount = 1;
     1252        }
     1253
     1254        p.vertex(
     1255          b[ 1 ][ 0 ],
     1256          b[ 1 ][ 1 ],
     1257          b[ 2 ][ 0 ],
     1258          b[ 2 ][ 1 ],
     1259          b[ 3 ][ 0 ],
     1260          b[ 3 ][ 1 ]
     1261        );
     1262       
     1263        curvePoints.shift();     
     1264      }
     1265   
     1266    };
     1267
     1268    p.curveTightness = function( tightness ){ curTightness = tightness; };
     1269
     1270    p.bezierVertex = p.vertex;   
     1271   
     1272    p.rectMode     = function rectMode( aRectMode ){ curRectMode = aRectMode; };
     1273    p.imageMode   = function (){};   
     1274    p.ellipseMode = function ellipseMode( aEllipseMode ) { curEllipseMode = aEllipseMode; };       
     1275   
     1276    p.arc = function arc( x, y, width, height, start, stop ){
     1277
     1278      if( width <= 0 ){ return; }
     1279
     1280      if( curEllipseMode == p.CORNER ){
     1281       x += width / 2;
     1282       y += height / 2;
     1283      }
     1284     
     1285      curContext.moveTo( x, y );
     1286      curContext.beginPath();   
     1287      curContext.arc( x, y, curEllipseMode == p.CENTER_RADIUS ? width : width/2, start, stop, false );
     1288
     1289      if( doStroke ){ curContext.stroke(); }
     1290      curContext.lineTo( x, y );
     1291
     1292      if( doFill ){ curContext.fill(); }
     1293      curContext.closePath();
     1294     
     1295    };
     1296   
     1297    p.line = function line( x1, y1, x2, y2 ){
     1298      curContext.lineCap = "round";
     1299      curContext.beginPath();   
     1300      curContext.moveTo( x1 || 0, y1 || 0 );
     1301      curContext.lineTo( x2 || 0, y2 || 0 );     
     1302      curContext.stroke();     
     1303      curContext.closePath();
     1304    };
     1305
     1306    p.bezier = function bezier( x1, y1, x2, y2, x3, y3, x4, y4 ){
     1307      curContext.lineCap = "butt";
     1308      curContext.beginPath();   
     1309      curContext.moveTo( x1, y1 );
     1310      curContext.bezierCurveTo( x2, y2, x3, y3, x4, y4 );     
     1311      curContext.stroke();     
     1312      curContext.closePath();
     1313    };
     1314
     1315    p.triangle = function triangle( x1, y1, x2, y2, x3, y3 ){
     1316      p.beginShape();
     1317      p.vertex( x1, y1 );
     1318      p.vertex( x2, y2 );
     1319      p.vertex( x3, y3 );
     1320      p.endShape();
     1321    };
     1322
     1323    p.quad = function quad( x1, y1, x2, y2, x3, y3, x4, y4 ){
     1324      curContext.lineCap = "square";
     1325      p.beginShape();
     1326      p.vertex( x1, y1 );
     1327      p.vertex( x2, y2 );
     1328      p.vertex( x3, y3 );
     1329      p.vertex( x4, y4 );
     1330      p.endShape();
     1331    };
     1332   
     1333    p.rect = function rect( x, y, width, height ){
     1334
     1335      if( !( width + height ) ){ return; }
     1336
     1337      curContext.beginPath();
     1338     
     1339      var offsetStart = 0;
     1340      var offsetEnd = 0;
     1341
     1342      if( curRectMode == p.CORNERS ){
     1343        width -= x;
     1344        height -= y;
     1345      }
     1346     
     1347      if( curRectMode == p.RADIUS ){
     1348        width *= 2;
     1349        height *= 2;
     1350      }
     1351     
     1352      if( curRectMode == p.CENTER || curRectMode == p.RADIUS ){
     1353        x -= width / 2;
     1354        y -= height / 2;
     1355      }
     1356   
     1357      curContext.rect(
     1358        Math.round( x ) - offsetStart,
     1359        Math.round( y ) - offsetStart,
     1360        Math.round( width ) + offsetEnd,
     1361        Math.round( height ) + offsetEnd
     1362      );
     1363       
     1364      if( doFill     ){ curContext.fill();   }       
     1365      if( doStroke   ){  curContext.stroke() };
     1366     
     1367      curContext.closePath();
     1368     
     1369    };
     1370   
     1371    p.ellipse = function ellipse( x, y, width, height ){
     1372
     1373      x = x || 0;
     1374      y = y || 0;
     1375
     1376      if( width <= 0 && height <= 0 ){ return; }
     1377
     1378      curContext.beginPath();
     1379     
     1380      if( curEllipseMode == p.RADIUS ){
     1381        width *= 2;
     1382        height *= 2;
     1383      }     
     1384     
     1385      var offsetStart = 0;
     1386     
     1387      // Shortcut for drawing a circle
     1388      if( width == height ){
     1389     
     1390        curContext.arc( x - offsetStart, y - offsetStart, width / 2, 0, p.TWO_PI, false );
     1391     
     1392      }else{
     1393     
     1394        var w = width/2,
     1395            h = height/2,
     1396            C = 0.5522847498307933;
     1397        var c_x = C * w,
     1398            c_y = C * h;
     1399
     1400//!      Do we still need this? I hope the Canvas arc() more capable by now?
     1401        curContext.moveTo( x + w, y );
     1402        curContext.bezierCurveTo( x+w    ,   y-c_y  ,   x+c_x  ,   y-h   ,   x    ,   y-h  );
     1403        curContext.bezierCurveTo( x-c_x  ,   y-h    ,   x-w    ,   y-c_y ,   x-w  ,   y    );
     1404        curContext.bezierCurveTo( x-w    ,   y+c_y  ,   x-c_x  ,   y+h, x,   y+h           );
     1405        curContext.bezierCurveTo( x+c_x  ,   y+h    ,   x+w    ,   y+c_y ,   x+w  ,   y    );
     1406     
     1407      }
     1408   
     1409      if( doFill    ){ curContext.fill();   }
     1410      if( doStroke  ){ curContext.stroke(); }
     1411     
     1412      curContext.closePath();
     1413     
     1414    };
     1415
     1416
     1417
     1418    ////////////////////////////////////////////////////////////////////////////
     1419    // Raster drawing functions
     1420    ////////////////////////////////////////////////////////////////////////////
     1421
     1422    p.save = function save( file ){};
     1423
     1424    // Loads an image for display. Type is unused. Callback is fired on load.
     1425    p.loadImage = function loadImage( file, type, callback ){
     1426     
     1427      var img = document.createElement( 'img' );
     1428      img.src = file;
     1429     
     1430      img.onload = function(){
     1431       
     1432        var h = this.height,
     1433            w = this.width;
     1434       
     1435        var canvas = document.createElement( "canvas" );
     1436        canvas.width = w;
     1437        canvas.height = h;
     1438        var context = canvas.getContext( "2d" );
     1439     
     1440        context.drawImage( this, 0, 0 );
     1441        this.data = buildImageObject( context.getImageData( 0, 0, w, h ) );
     1442        this.data.img = img;
     1443
     1444        callback?callback():0;
     1445       
     1446      }
     1447     
     1448      return img;
     1449         
     1450    };
     1451   
     1452    // Gets a single pixel or block of pixels from the current Canvas Context
     1453    p.get = function get( x, y ){
     1454     
     1455      if( !arguments.length ){
     1456        var c = p.createGraphics( p.width, p.height );
     1457        c.image( curContext, 0, 0 );
     1458        return c;
     1459      }
     1460
     1461      if( !getLoaded ){
     1462        getLoaded = buildImageObject( curContext.getImageData( 0, 0, p.width, p.height ) );
     1463      }
     1464
     1465      return getLoaded.get( x, y );
     1466     
     1467    };
     1468
     1469    // Creates a new Processing instance and passes it back for... processing
     1470    p.createGraphics = function createGraphics( w, h ){
     1471 
     1472      var canvas = document.createElement( "canvas" );
     1473      var ret = buildProcessing( canvas );
     1474      ret.size( w, h );
     1475      ret.canvas = canvas;
     1476      return ret;
     1477 
     1478    };
     1479
     1480    // Paints a pixel array into the canvas
     1481    p.set = function set( x, y, obj ){
     1482     
     1483      if( obj && obj.img ){
     1484       
     1485        p.image( obj, x, y );
     1486       
     1487      }else{
     1488     
     1489        var oldFill = curContext.fillStyle,
     1490            color   = obj;
     1491           
     1492        curContext.fillStyle = color;
     1493        curContext.fillRect( Math.round( x ), Math.round( y ), 1, 1 );
     1494        curContext.fillStyle = oldFill;
     1495       
     1496      }
     1497     
     1498    };
     1499
     1500    // Gets a 1-Dimensional pixel array from Canvas
     1501    p.loadPixels = function(){
     1502      p.pixels = buildImageObject( curContext.getImageData(0, 0, p.width, p.height) ).pixels;
     1503    };
     1504
     1505    // Draws a 1-Dimensional pixel array to Canvas
     1506    p.updatePixels = function() {
     1507   
     1508      var colors = /(\d+),(\d+),(\d+),(\d+)/,
     1509          pixels = {};
     1510         
     1511      pixels.width   = p.width;
     1512      pixels.height = p.height;
     1513      pixels.data   = [];
     1514
     1515      if( curContext.createImageData ){
     1516        pixels = curContext.createImageData( p.width, p.height );
     1517      }
     1518
     1519      var data   = pixels.data,
     1520          pos   = 0;
     1521
     1522      for( var i = 0, l = p.pixels.length; i < l; i++ ){
     1523
     1524        var c = ( p.pixels[i] || "rgba(0,0,0,1)" ).match( colors );
     1525
     1526        data[ pos + 0 ] =   parseInt( c[ 1 ] );
     1527        data[ pos + 1 ] =   parseInt( c[ 2 ] );
     1528        data[ pos + 2 ] =   parseInt( c[ 3 ] );
     1529        data[ pos + 3 ] = parseFloat( c[ 4 ] ) * 255;
     1530
     1531        pos += 4;
     1532       
     1533      }
     1534
     1535      curContext.putImageData( pixels, 0, 0 );
     1536     
     1537    };
     1538
     1539    // Draw an image or a color to the background
     1540    p.background = function background( img ) {
     1541     
     1542       if( arguments.length ){
     1543       
     1544        if( img.data && img.data.img ){
     1545          curBackground = img.data;
     1546        }else{
     1547          curBackground = p.color.apply( this, arguments );
     1548        }
     1549       
     1550      }
     1551
     1552      if( curBackground.img ){
     1553     
     1554        p.image( img, 0, 0 );
     1555       
     1556      }else{
     1557
     1558        var oldFill = curContext.fillStyle;
     1559        curContext.fillStyle = curBackground + "";
     1560        curContext.fillRect( 0, 0, p.width, p.height );
     1561        curContext.fillStyle = oldFill;
     1562
     1563      }
     1564     
     1565    };   
     1566   
     1567    p.AniSprite = function( prefix, frames ){
     1568      this.images = [];
     1569      this.pos = 0;
     1570
     1571      for( var i = 0; i < frames; i++ ){
     1572        this.images.push( prefix + p.nf( i, ( "" + frames ).length ) + ".gif" );
     1573      }
     1574
     1575      this.display = function( x, y ){
     1576        p.image_old( this.images[ this.pos ], x, y );
     1577
     1578        if( ++this.pos >= frames ){
     1579          this.pos = 0;
     1580        }
     1581      };
     1582
     1583      this.getWidth   = function(){ return getImage_old( this.images[ 0 ] ).width;  };
     1584      this.getHeight  = function(){ return getImage_old( this.images[ 0 ] ).height; };
     1585    };
     1586
     1587    function buildImageObject( obj ){
     1588 
     1589      var pixels = obj.data;
     1590      var data = p.createImage( obj.width, obj.height );
     1591
     1592      if( data.__defineGetter__ && data.__lookupGetter__ && !data.__lookupGetter__( "pixels" ) ){
     1593       
     1594        var pixelsDone;
     1595       
     1596        data.__defineGetter__( "pixels", function(){
     1597         
     1598          if( pixelsDone ){
     1599            return pixelsDone;
     1600          }
     1601          pixelsDone = [];
     1602
     1603          for( var i = 0; i < pixels.length; i += 4 ){
     1604            pixelsDone.push(
     1605              p.color(
     1606                pixels[ i ],
     1607                pixels[ i + 1 ],
     1608                pixels[ i + 2 ],
     1609                pixels[ i + 3 ])
     1610              );
     1611          }
     1612
     1613          return pixelsDone;
     1614       
     1615        });
     1616       
     1617      }else{
     1618       
     1619        data.pixels = [];
     1620
     1621        for ( var i = 0; i < pixels.length; i += 4 ){
     1622          data.pixels.push( p.color(
     1623            pixels[ i ],
     1624            pixels[ i + 1 ],
     1625            pixels[ i + 2 ],
     1626            pixels[ i + 3 ]
     1627          ));
     1628        }
     1629     
     1630      }
     1631
     1632      return data;
     1633    }
     1634
     1635    p.createImage = function createImage( w, h, mode ){
     1636           
     1637      var data    = {};
     1638      data.width  = w;
     1639      data.height = h;
     1640      data.data   = [];
     1641
     1642      if( curContext.createImageData ) {
     1643        data = curContext.createImageData( w, h );
     1644      }
     1645
     1646      data.pixels = new Array( w * h );
     1647     
     1648      data.get = function( x, y ){
     1649        return this.pixels[ w * y + x ];
     1650      };
     1651     
     1652      data._mask = null;
     1653     
     1654      data.mask = function( img ){
     1655        this._mask = img;
     1656      };
     1657     
     1658      data.loadPixels = function(){};
     1659      data.updatePixels = function(){};
     1660
     1661      return data;
     1662     
     1663    };
     1664
     1665    function getImage( img ){
     1666     
     1667      if( typeof img == "string" ){
     1668        return document.getElementById( img );
     1669      }
     1670
     1671      if( img.img ){
     1672     
     1673        return img.img;
     1674       
     1675      }else if( img.getContext || img.canvas ){
     1676
     1677        img.pixels = img.getContext( '2d' ).createImageData( img.width, img.height );
     1678      }
     1679
     1680      for( var i = 0, l = img.pixels.length; i < l; i++ ){
     1681       
     1682        var pos = i * 4;
     1683        var c = ( img.pixels[ i ] || "rgba(0,0,0,1)" ).slice( 5, - 1 ).split( "," );
     1684       
     1685        img.data[ pos + 0 ] =   parseInt( c[ 0 ] );
     1686        img.data[ pos + 1 ] =   parseInt( c[ 1 ] );
     1687        img.data[ pos + 2 ] =   parseInt( c[ 2 ] );
     1688        img.data[ pos + 3 ] = parseFloat( c[ 3 ] ) * 100;
     1689     
     1690      }
     1691
     1692      var canvas = document.createElement( "canvas" );
     1693      canvas.width = img.width;
     1694      canvas.height = img.height;
     1695     
     1696      var context = canvas.getContext( "2d" );
     1697      context.putImageData( img.pixels, 0, 0 );
     1698
     1699      img.canvas = canvas;
     1700
     1701      return img;
     1702    }
     1703
     1704    // Depreciating "getImage_old" from PJS - currently here to support AniSprite
     1705    function getImage_old( img ){
     1706      if( typeof img == "string" ){
     1707        return document.getElementById( img );
     1708      }
     1709      if( img.img || img.canvas ){
     1710        return img.img || img.canvas;
     1711      }
     1712      for( var i = 0, l = img.pixels.length; i < l; i++ ){       
     1713        var pos = i * 4;
     1714        var c = ( img.pixels[ i ] || "rgba(0,0,0,1)" ).slice( 5, - 1 ).split( "," );       
     1715        img.data[ pos + 0 ] = parseInt( c[ 0 ] );
     1716        img.data[ pos + 1 ] = parseInt( c[ 1 ] );
     1717        img.data[ pos + 2 ] = parseInt( c[ 2 ] );
     1718        img.data[ pos + 3 ] = parseFloat( c[ 3 ] ) * 100;     
     1719      }
     1720      var canvas = document.createElement( "canvas" );
     1721      canvas.width = img.width;
     1722      canvas.height = img.height;     
     1723      var context = canvas.getContext( "2d" );
     1724      context.putImageData( img, 0, 0 );
     1725      img.canvas = canvas;
     1726      return canvas;
     1727    }
     1728    // Depreciating "getImage_old" from PJS - currently here to support AniSprite
     1729    p.image_old=function image_old(img,x,y,w,h){
     1730      x = x || 0;
     1731      y = y || 0;
     1732      var obj = getImage( img );
     1733      if( curTint >= 0 ){
     1734        var oldAlpha = curContext.globalAlpha;
     1735        curContext.globalAlpha = curTint / opacityRange;
     1736      }
     1737      if( arguments.length == 3 ){
     1738        curContext.drawImage( obj, x, y );
     1739      }else{
     1740        curContext.drawImage( obj, x, y, w, h );
     1741      }
     1742      if( curTint >= 0 ){
     1743        curContext.globalAlpha = oldAlpha;
     1744      }
     1745      if( img._mask ){
     1746        var oldComposite = curContext.globalCompositeOperation;
     1747        curContext.globalCompositeOperation = "darker";
     1748        p.image( img._mask, x, y );
     1749        curContext.globalCompositeOperation = oldComposite;
     1750      }     
     1751    };
     1752
     1753    // Draws an image to the Canvas
     1754    p.image = function image( img, x, y, w, h ){
     1755     
     1756      if( img.data || img.canvas ){
     1757
     1758        x = x || 0;
     1759        y = y || 0;
     1760
     1761        var obj = getImage( img.data || img.canvas );
     1762
     1763        if( curTint >= 0 ){
     1764          var oldAlpha = curContext.globalAlpha;
     1765          curContext.globalAlpha = curTint / opacityRange;
     1766        }
     1767
     1768        if( arguments.length == 3 ){
     1769          curContext.drawImage( obj, x, y );
     1770        }else{
     1771          curContext.drawImage( obj, x, y, w, h );
     1772        }
     1773
     1774        if( curTint >= 0 ){
     1775          curContext.globalAlpha = oldAlpha;
     1776        }
     1777
     1778        if( img._mask ){
     1779          var oldComposite = curContext.globalCompositeOperation;
     1780          curContext.globalCompositeOperation = "darker";
     1781          p.image( img._mask, x, y );
     1782          curContext.globalCompositeOperation = oldComposite;
     1783        }
     1784     
     1785      }
     1786     
     1787      if( typeof img == 'string' ){
     1788       
     1789      }
     1790     
     1791    };   
     1792   
     1793    // Clears hole in the Canvas or the whole Canvas
     1794    p.clear = function clear ( x, y, width, height ) {   
     1795      if( arguments.length == 0 ){
     1796        curContext.clearRect( x, y, width, height );
     1797      }else{
     1798        curContext.clearRect( 0, 0, p.width, p.height );
     1799      }
     1800    }
     1801
     1802    p.tint = function tint( rgb, a ){
     1803      curTint = a;
     1804    };
     1805
     1806
     1807
     1808    ////////////////////////////////////////////////////////////////////////////
     1809    // Font handling
     1810    ////////////////////////////////////////////////////////////////////////////
     1811   
     1812    // Loads a font from an SVG or Canvas API
     1813    p.loadFont = function loadFont( name ){
     1814     
     1815      if( name.indexOf( ".svg" ) == - 1 ){
     1816
     1817        return {
     1818          name: name,
     1819          width: function( str ){
     1820            if( curContext.mozMeasureText ){
     1821              return curContext.mozMeasureText(
     1822                typeof str == "number" ?
     1823                  String.fromCharCode( str ) :
     1824                  str
     1825              ) / curTextSize;
     1826            }else{
     1827              return 0;
     1828            }
     1829          }
     1830        };
     1831       
     1832      }else{
     1833       
     1834        // If the font is a glyph, calculate by SVG table     
     1835        var font = p.loadGlyphs( name );
     1836
     1837        return {
     1838          name          : name,
     1839          glyph         : true,
     1840          units_per_em  : font.units_per_em,
     1841          horiz_adv_x   : 1 / font.units_per_em * font.horiz_adv_x,
     1842          ascent        : font.ascent,
     1843          descent       : font.descent,
     1844          width         :
     1845            function( str ){
     1846              var width = 0;
     1847              var len   = str.length;
     1848              for( var i = 0; i < len; i++ ){                         
     1849                try{ width += parseFloat( p.glyphLook( p.glyphTable[ name ], str[ i ] ).horiz_adv_x ); }
     1850                catch( e ){ ; }
     1851              }
     1852              return width / p.glyphTable[ name ].units_per_em;
     1853            }
     1854        }
     1855       
     1856      }
     1857   
     1858    };
     1859
     1860    // Sets a 'current font' for use
     1861    p.textFont = function textFont( name, size ){
     1862      curTextFont = name;
     1863      p.textSize( size );
     1864    };
     1865
     1866    // Sets the font size
     1867    p.textSize = function textSize( size ){
     1868//!   Was this meant to return textSize value if no arguments were passed?
     1869      if( size ){
     1870        curTextSize = size;
     1871      }
     1872    };
     1873
     1874    p.textAlign = function textAlign(){};
     1875
     1876    // A lookup table for characters that can not be referenced by Object
     1877    p.glyphLook = function glyphLook( font, chr ){
     1878
     1879      try{
     1880        switch( chr ){
     1881          case "1"  : return font[ "one"          ]; break;
     1882          case "2"  : return font[ "two"          ]; break;
     1883          case "3"  : return font[ "three"        ]; break;
     1884          case "4"  : return font[ "four"         ]; break;
     1885          case "5"  : return font[ "five"         ]; break;
     1886          case "6"  : return font[ "six"          ]; break;
     1887          case "7"  : return font[ "seven"        ]; break;
     1888          case "8"  : return font[ "eight"        ]; break;
     1889          case "9"  : return font[ "nine"         ]; break;
     1890          case "0"  : return font[ "zero"         ]; break;
     1891          case " "  : return font[ "space"        ]; break;
     1892          case "$"  : return font[ "dollar"       ]; break;
     1893          case "!"  : return font[ "exclam"       ]; break;
     1894          case '"'  : return font[ "quotedbl"     ]; break;
     1895          case "#"  : return font[ "numbersign"   ]; break;
     1896          case "%"  : return font[ "percent"      ]; break;
     1897          case "&"  : return font[ "ampersand"    ]; break;
     1898          case "'"  : return font[ "quotesingle"  ]; break;
     1899          case "("  : return font[ "parenleft"    ]; break;
     1900          case ")"  : return font[ "parenright"   ]; break;
     1901          case "*"  : return font[ "asterisk"     ]; break;
     1902          case "+"  : return font[ "plus"         ]; break;
     1903          case ","  : return font[ "comma"        ]; break;
     1904          case "-"  : return font[ "hyphen"       ]; break;
     1905          case "."  : return font[ "period"       ]; break;
     1906          case "/"  : return font[ "slash"        ]; break;
     1907          case "_"  : return font[ "underscore"   ]; break;
     1908          case ":"  : return font[ "colon"        ]; break;
     1909          case ";"  : return font[ "semicolon"    ]; break;
     1910          case "<"  : return font[ "less"         ]; break;
     1911          case "="  : return font[ "equal"        ]; break;
     1912          case ">"  : return font[ "greater"      ]; break;
     1913          case "?"  : return font[ "question"     ]; break;
     1914          case "@"  : return font[ "at"           ]; break;
     1915          case "["  : return font[ "bracketleft"  ]; break;
     1916          case "\\" : return font[ "backslash"    ]; break;
     1917          case "]"  : return font[ "bracketright" ]; break;
     1918          case "^"  : return font[ "asciicircum"  ]; break;
     1919          case "`"  : return font[ "grave"        ]; break;
     1920          case "{"  : return font[ "braceleft"    ]; break;
     1921          case "|"  : return font[ "bar"          ]; break;
     1922          case "}"  : return font[ "braceright"   ]; break;
     1923          case "~"  : return font[ "asciitilde"   ]; break;
     1924          // If the character is not 'special', access it by object reference
     1925          default   : return font[ chr            ]; break;
     1926        }
     1927      }catch( e ){ ; }
     1928   
     1929    }
     1930   
     1931    // Print some text to the Canvas
     1932    p.text = function text( str, x, y ){
     1933     
     1934      // If the font is a standard Canvas font...
     1935      if( !curTextFont.glyph ){
     1936     
     1937        if( str && curContext.mozDrawText ){
     1938
     1939          curContext.save();
     1940          curContext.mozTextStyle = curTextSize + "px " + curTextFont.name;
     1941          curContext.translate( x, y );
     1942          curContext.mozDrawText(
     1943            typeof str == "number" ?
     1944            String.fromCharCode( str ) :
     1945            str ) ;
     1946          curContext.restore();
     1947
     1948        }
     1949       
     1950      }else{
     1951       
     1952        // If the font is a Batik SVG font...
     1953        var font = p.glyphTable[ curTextFont.name ];
     1954        curContext.save();
     1955        curContext.translate( x, y + curTextSize );
     1956       
     1957        var upem      = font[ "units_per_em" ],
     1958            newScale = 1 / upem * curTextSize;
     1959       
     1960        curContext.scale( newScale, newScale );
     1961       
     1962        var len = str.length;
     1963       
     1964        for(var i = 0; i < len; i++ ){
     1965          // Test character against glyph table
     1966          try{ p.glyphLook( font, str[ i ] ).draw(); }
     1967          catch( e ){ ; }
     1968        }
     1969       
     1970        curContext.restore();
     1971      }
     1972     
     1973    };
     1974   
     1975    // Load Batik SVG Fonts and parse to pre-def objects for quick rendering
     1976    p.loadGlyphs = function loadGlyph( url ){
     1977       
     1978        // Load and parse Batik SVG font as XML into a Processing Glyph object
     1979        var loadXML = function loadXML(){
     1980       
     1981          try{
     1982                      var xmlDoc = new ActiveXObject( "Microsoft.XMLDOM" );
     1983          }
     1984          catch( e ){
     1985                      try{
     1986                            xmlDoc=document.implementation.createDocument( "", "", null );
     1987                      }
     1988                      catch( e ){
     1989                            p.println( e.message );
     1990                            return;
     1991                      }
     1992          };
     1993         
     1994          try{
     1995                      xmlDoc.async = false;
     1996                      xmlDoc.load( url );
     1997                      parse( xmlDoc.getElementsByTagName( "svg" )[ 0 ] );
     1998          }
     1999          catch( e ){
     2000                      // Google Chrome, Safari etc.
     2001                      try{
     2002                            p.println( e.message );
     2003                            var xmlhttp = new window.XMLHttpRequest();
     2004                            xmlhttp.open( "GET", url, false );
     2005                            xmlhttp.send( null );
     2006                            parse( xmlhttp.responseXML.documentElement );
     2007                      }
     2008                      catch( e ){ ; }
     2009          }
     2010        };
     2011       
     2012        // Return arrays of SVG commands and coords
     2013        var regex = function regex( needle, hay ){
     2014         
     2015          var regexp  = new RegExp( needle, "g" ),
     2016              results = [],
     2017              i       = 0;
     2018             
     2019          while( results[ i ] = regexp.exec( hay ) ){ i++; }
     2020          return results;
     2021       
     2022        }
     2023
     2024        // Parse SVG font-file into block of Canvas commands
     2025        var parse = function parse( svg ){
     2026         
     2027          // Store font attributes
     2028          var font = svg.getElementsByTagName( "font" );
     2029          p.glyphTable[ url ][ "horiz_adv_x"  ] = font[ 0 ].getAttribute( "horiz-adv-x" );     
     2030         
     2031          var font_face = svg.getElementsByTagName( "font-face" )[ 0 ];                 
     2032          p.glyphTable[ url ][ "units_per_em" ] = parseFloat( font_face.getAttribute( "units-per-em") );
     2033          p.glyphTable[ url ][ "ascent"       ] = parseFloat( font_face.getAttribute( "ascent"      ) );
     2034          p.glyphTable[ url ][ "descent"      ] = parseFloat( font_face.getAttribute( "descent"     ) );         
     2035         
     2036          var getXY = "[0-9\-]+",
     2037              glyph = svg.getElementsByTagName( "glyph" ),
     2038              len   = glyph.length;
     2039
     2040          // Loop through each glyph in the SVG
     2041          for( var i = 0; i < len; i++ ){
     2042           
     2043            // Store attributes for this glyph
     2044            var unicode = glyph[ i ].getAttribute( "unicode" );
     2045            var name = glyph[ i ].getAttribute( "glyph-name" );
     2046            var horiz_adv_x = glyph[ i ].getAttribute( "horiz-adv-x" );
     2047            if( horiz_adv_x == null ){ var horiz_adv_x = p.glyphTable[ url ][ 'horiz_adv_x' ]; }
     2048           
     2049            var buildPath = function buildPath( d ){
     2050             
     2051              var c = regex( "[A-Za-z][0-9\- ]+|Z", d );                                                   
     2052             
     2053              // Begin storing path object
     2054              var path = "var path={draw:function(){curContext.beginPath();curContext.save();";
     2055             
     2056              var x       = 0,
     2057                  y       = 0,
     2058                  cx      = 0,
     2059                  cy      = 0,
     2060                  nx      = 0,
     2061                  ny      = 0,
     2062                  d       = 0,
     2063                  a       = 0,
     2064                  lastCom = "",
     2065                  lenC    = c.length - 1;
     2066             
     2067              // Loop through SVG commands translating to canvas eqivs functions in path object
     2068              for( var j = 0; j < lenC; j++ ){
     2069               
     2070                var com = c[ j ][ 0 ],
     2071                    xy   = regex( getXY, com );
     2072       
     2073                switch( com[ 0 ] ){
     2074               
     2075                  case "M": //curContext.moveTo(x,-y);
     2076                    x = parseFloat( xy[ 0 ][ 0 ] );
     2077                    y = parseFloat( xy[ 1 ][ 0 ] );             
     2078//!                 Brackets needed on (-y)?
     2079                    path += "curContext.moveTo("+ x +","+ (-y) +");";
     2080                    break;
     2081
     2082                  case "L": //curContext.lineTo(x,-y);
     2083                    x = parseFloat( xy[ 0 ][ 0 ] );
     2084                    y = parseFloat( xy[ 1 ][ 0 ] );
     2085                    path += "curContext.lineTo("+ x +","+ (-y) +");";
     2086                    break;
     2087
     2088                  case "H"://curContext.lineTo(x,-y)
     2089                    x = parseFloat( xy[ 0 ][ 0 ] );
     2090                    path += "curContext.lineTo("+ x +","+ (-y) +");";
     2091                    break;
     2092
     2093                  case "V"://curContext.lineTo(x,-y);
     2094                    y = parseFloat( xy[ 0 ][ 0 ] );             
     2095                    path += "curContext.lineTo("+ x +","+ (-y) +");";
     2096                    break;
     2097
     2098                  case "T"://curContext.quadraticCurveTo(cx,-cy,nx,-ny);
     2099                    nx = parseFloat( xy[ 0 ][ 0 ] );
     2100                    ny = parseFloat( xy[ 1 ][ 0 ] );
     2101
     2102                    if( lastCom == "Q" || lastCom == "T" ){
     2103
     2104                      d = Math.sqrt( Math.pow( x - cx, 2 ) + Math.pow( cy - y, 2 ) );
     2105                      a = Math.PI+Math.atan2( cx - x, cy - y );
     2106                      cx = x + ( Math.sin( a ) * ( d ) );
     2107                      cy = y + ( Math.cos( a ) * ( d ) );
     2108
     2109                    }else{
     2110                      cx = x;
     2111                      cy = y;
     2112                    }
     2113                   
     2114                    path += "curContext.quadraticCurveTo("+ cx +","+ (-cy) +","+ nx +","+ (-ny) +");";
     2115                    x = nx;
     2116                    y = ny;
     2117                    break;
     2118                     
     2119                  case "Q"://curContext.quadraticCurveTo(cx,-cy,nx,-ny);
     2120                    cx = parseFloat( xy[ 0 ][ 0 ] );
     2121                    cy = parseFloat( xy[ 1 ][ 0 ] );
     2122                    nx = parseFloat( xy[ 2 ][ 0 ] );
     2123                    ny = parseFloat( xy[ 3 ][ 0 ] );
     2124                    path += "curContext.quadraticCurveTo("+ cx +","+ (-cy) +","+ nx +","+ (-ny) +");";             
     2125                    x = nx;
     2126                    y = ny;
     2127                    break;
     2128
     2129                  case "Z"://curContext.closePath();
     2130                    path += "curContext.closePath();";
     2131                    break;
     2132
     2133                }
     2134
     2135                lastCom = com[ 0 ];
     2136
     2137              }
     2138
     2139              path += "doStroke?curContext.stroke():0;";
     2140              path += "doFill?curContext.fill():0;";
     2141              path += "curContext.restore();";
     2142              path += "curContext.translate("+ horiz_adv_x  +",0);";           
     2143              path += "}}";
     2144
     2145              return path;
     2146
     2147            }
     2148                     
     2149            var d = glyph[ i ].getAttribute( "d" );
     2150           
     2151            // Split path commands in glpyh
     2152            if( d !== undefined ){
     2153           
     2154              var path = buildPath( d );
     2155              eval( path );
     2156             
     2157              // Store glyph data to table object
     2158              p.glyphTable[ url ][ name ] = {
     2159                name        : name,
     2160                unicode     : unicode,
     2161                horiz_adv_x : horiz_adv_x,
     2162                draw        : path.draw
     2163              }
     2164
     2165            }
     2166         
     2167          } // finished adding glyphs to table
     2168         
     2169        }
     2170       
     2171        // Create a new object in glyphTable to store this font
     2172        p.glyphTable[ url ] = {};
     2173       
     2174        // Begin loading the Batik SVG font...
     2175        loadXML( url );
     2176       
     2177        // Return the loaded font for attribute grabbing
     2178        return p.glyphTable[ url ];
     2179    }
     2180
     2181
     2182
     2183    ////////////////////////////////////////////////////////////////////////////
     2184    // Class methods
     2185    ////////////////////////////////////////////////////////////////////////////
     2186   
     2187    p.extendClass = function extendClass( obj, args, fn ){
     2188      if( arguments.length == 3 ){
     2189        fn.apply( obj, args );
     2190      }else{
     2191        args.call( obj );
     2192      }
     2193    };
     2194
     2195    p.addMethod = function addMethod( object, name, fn ){
     2196
     2197      if( object[ name ] ){
     2198     
     2199        var args   = fn.length,
     2200            oldfn = object[ name ];
     2201       
     2202        object[ name ] = function(){
     2203         
     2204          if( arguments.length == args ){
     2205
     2206            return fn.apply( this, arguments );
     2207
     2208          }else{
     2209
     2210            return oldfn.apply( this, arguments );
     2211
     2212          }
     2213       
     2214        };
     2215     
     2216      }else{
     2217     
     2218        object[ name ] = fn;
     2219     
     2220      }
     2221   
     2222    };
     2223   
     2224   
     2225
     2226    ////////////////////////////////////////////////////////////////////////////
     2227    // Set up environment
     2228    ////////////////////////////////////////////////////////////////////////////
     2229   
     2230    p.init = function init(code){
     2231
     2232      p.stroke( 0 );
     2233      p.fill( 255 );
     2234   
     2235      // Canvas has trouble rendering single pixel stuff on whole-pixel
     2236      // counts, so we slightly offset it (this is super lame).
     2237     
     2238      curContext.translate( 0.5, 0.5 );   
     2239         
     2240      // The fun bit!
     2241      if( code ){
     2242        (function( Processing ){
     2243          with ( p ){
     2244            eval(parse(code, p));
     2245          }
     2246        })( p );
     2247      }
     2248   
     2249      if( p.setup ){
     2250        inSetup = true;
     2251        p.setup();
     2252      }
     2253     
     2254      inSetup = false;
     2255     
     2256      if( p.draw ){
     2257        if( !doLoop ){
     2258          p.redraw();
     2259        } else {
     2260          p.loop();
     2261        }
     2262      }
     2263     
     2264
     2265      //////////////////////////////////////////////////////////////////////////
     2266      // Event handling
     2267      //////////////////////////////////////////////////////////////////////////
     2268     
     2269      attach( curElement, "mousemove"  , function(e){
     2270     
     2271        var scrollX = window.scrollX != null ? window.scrollX : window.pageXOffset;
     2272        var scrollY = window.scrollY != null ? window.scrollY : window.pageYOffset;           
     2273     
     2274        p.pmouseX = p.mouseX;
     2275        p.pmouseY = p.mouseY;
     2276        p.mouseX   = e.clientX - curElement.offsetLeft + scrollX;
     2277        p.mouseY   = e.clientY - curElement.offsetTop + scrollY;   
     2278
     2279        if( p.mouseMoved ){ p.mouseMoved(); }
     2280        if( mousePressed && p.mouseDragged ){ p.mouseDragged(); }
     2281       
     2282      });
     2283     
     2284      attach( curElement, "mouseout" , function( e ){ p.cursor("auto"); });     
     2285     
     2286      attach( curElement, "mousedown", function( e ){     
     2287        mousePressed = true;     
     2288        switch(e.which){
     2289          case 1: p.mouseButton = p.LEFT; break;
     2290          case 2: p.mouseButton = p.CENTER; break;
     2291          case 3: p.mouseButton = p.RIGHT; break;
     2292        }       
     2293        p.mouseDown = true;       
     2294        if( typeof p.mousePressed == "function" ){ p.mousePressed(); }
     2295        else{ p.mousePressed = true; }
     2296      });
     2297
     2298      attach( curElement, "contextmenu", function( e ){
     2299        e.preventDefault();
     2300        e.stopPropagation();
     2301      });
     2302
     2303      attach( curElement, "mouseup", function( e ){
     2304        mousePressed = false;
     2305        if( p.mouseClicked ){ p.mouseClicked(); }       
     2306        if( typeof p.mousePressed != "function" ){ p.mousePressed = false; }
     2307        if( p.mouseReleased ){ p.mouseReleased(); }
     2308      });
     2309
     2310      attach( document, "keydown", function( e ){
     2311        keyPressed = true;
     2312        p.key = e.keyCode + 32;               
     2313        var i, len = p.codedKeys.length;       
     2314        for( i=0; i < len; i++ ){
     2315            if( p.key == p.codedKeys[ i ] ){
     2316              switch(p.key){
     2317              case 70: p.keyCode = p.UP        ; break;
     2318              case 71: p.keyCode = p.RIGHT    ; break;
     2319              case 72: p.keyCode = p.DOWN      ; break;
     2320              case 69: p.keyCode = p.LEFT      ; break;
     2321              }
     2322              p.key=p.CODED;
     2323            }
     2324        }
     2325        if( e.shiftKey ){ p.key = String.fromCharCode(p.key).toUpperCase().charCodeAt( 0 ); }
     2326        if( typeof p.keyPressed == "function" ){ p.keyPressed(); }
     2327        else{ p.keyPressed = true; }
     2328      });
     2329
     2330      attach( document, "keyup", function( e ){
     2331        keyPressed = false;
     2332        if( typeof p.keyPressed != "function" ){ p.keyPressed = false; }
     2333        if( p.keyReleased ){ p.keyReleased(); }
     2334      });
     2335
     2336      function attach(elem, type, fn) {
     2337        if( elem.addEventListener ){ elem.addEventListener( type, fn, false ); }
     2338        else{ elem.attachEvent( "on" + type, fn ); }
     2339      }
     2340
     2341    };
     2342
     2343    return p;
     2344   
     2345  }
     2346
     2347})();
  • new file sagenb/data/graph_editor/processing.min.js

    diff --git a/sagenb/data/graph_editor/processing.min.js b/sagenb/data/graph_editor/processing.min.js
    new file mode 100644
    - +  
     1(function(){this.Processing=function Processing(aElement,aCode){if(typeof aElement=="string"){aElement=document.getElementById(aElement);}
     2var p=buildProcessing(aElement);if(aCode){p.init(aCode);}
     3return p;};var ajax=function(url){var AJAX;if(AJAX=new XMLHttpRequest()){AJAX.open("GET",url,false);AJAX.send(null);return AJAX.responseText;}else{return false;}};var init=function(){var canvas=document.getElementsByTagName('canvas'),datasrc=undefined;for(var i=0;l=i<canvas.length;i++){if(datasrc=canvas[i].getAttribute('datasrc')){Processing(canvas[i],ajax(datasrc));}}};addEventListener('DOMContentLoaded',function(){init();},false);var parse=Processing.parse=function parse(aCode,p){aCode=aCode.replace(/\/\/ .*\n/g,"\n");aCode=aCode.replace(/([^\s])%([^\s])/g,"$1 % $2");aCode=aCode.replace(/(?:static )?(\w+ )(\w+)\s*(\([^\)]*\)\s*{)/g,function(all,type,name,args){if(name=="if"||name=="for"||name=="while"){return all;}else{return"Processing."+name+" = function "+name+args;}});aCode=aCode.replace(/import \(|import\(/g,"p.Import(");aCode=aCode.replace(/\.length\(\)/g,".length");aCode=aCode.replace(/([\(,]\s*)(\w+)((?:\[\])+| )\s*(\w+\s*[\),])/g,"$1$4");aCode=aCode.replace(/([\(,]\s*)(\w+)((?:\[\])+| )\s*(\w+\s*[\),])/g,"$1$4");aCode=aCode.replace(/new (\w+)((?:\[([^\]]*)\])+)/g,function(all,name,args){return"new ArrayList("+args.slice(1,-1).split("][").join(", ")+")";});aCode=aCode.replace(/(?:static )?\w+\[\]\s*(\w+)\[?\]?\s*=\s*{.*?};/g,function(all){return all.replace(/{/g,"[").replace(/}/g,"]");});var intFloat=/(\n\s*(?:int|float)(?:\[\])?(?:\s*|[^\(]*?,\s*))([a-z]\w*)(;|,)/i;while(intFloat.test(aCode)){aCode=aCode.replace(new RegExp(intFloat),function(all,type,name,sep){return type+" "+name+" = 0"+sep;});}
     4aCode=aCode.replace(/(?:static )?(\w+)((?:\[\])+| ) *(\w+)\[?\]?(\s*[=,;])/g,function(all,type,arr,name,sep){if(type=="return")
     5return all;else
     6return"var "+name+sep;});aCode=aCode.replace(/=\s*{((.|\s)*?)};/g,function(all,data){return"= ["+data.replace(/{/g,"[").replace(/}/g,"]")+"]";});aCode=aCode.replace(/super\(/g,"superMethod(");var classes=["int","float","boolean","string"];function ClassReplace(all,name,extend,vars,last){classes.push(name);var static="";vars=vars.replace(/final\s+var\s+(\w+\s*=\s*.*?;)/g,function(all,set){static+=" "+name+"."+set;return"";});return"function "+name+"() {with(this){\n  "+
     7(extend?"var __self=this;function superMethod(){extendClass(__self,arguments,"+extend+");}\n":"")+
     8vars.replace(/,\s?/g,";\n  this.").replace(/\b(var |final |public )+\s*/g,"this.").replace(/\b(var |final |public )+\s*/g,"this.").replace(/this.(\w+);/g,"this.$1 = null;")+
     9(extend?"extendClass(this, "+extend+");\n":"")+"<CLASS "+name+" "+static+">"+(typeof last=="string"?last:name+"(");}
     10var matchClasses=/(?:public |abstract |static )*class (\w+)\s*(?:extends\s*(\w+)\s*)?{\s*((?:.|\n)*?)\b\1\s*\(/g;var matchNoCon=/(?:public |abstract |static )*class (\w+)\s*(?:extends\s*(\w+)\s*)?{\s*((?:.|\n)*?)(Processing)/g;aCode=aCode.replace(matchClasses,ClassReplace);aCode=aCode.replace(matchNoCon,ClassReplace);var matchClass=/<CLASS (\w+) (.*?)>/,m;while((m=aCode.match(matchClass))){var left=RegExp.leftContext,allRest=RegExp.rightContext,rest=nextBrace(allRest),className=m[1],staticVars=m[2]||"";allRest=allRest.slice(rest.length+1);rest=rest.replace(new RegExp("\\b"+className+"\\(([^\\)]*?)\\)\\s*{","g"),function(all,args){args=args.split(/,\s*?/);if(args[0].match(/^\s*$/)){args.shift();}
     11var fn="if ( arguments.length == "+args.length+" ) {\n";for(var i=0;i<args.length;i++){fn+="    var "+args[i]+" = arguments["+i+"];\n";}
     12return fn;});rest=rest.replace(/(?:public )?Processing.\w+ = function (\w+)\((.*?)\)/g,function(all,name,args){return"ADDMETHOD(this, '"+name+"', function("+args+")";});var matchMethod=/ADDMETHOD([\s\S]*?{)/,mc;var methods="";while((mc=rest.match(matchMethod))){var prev=RegExp.leftContext,allNext=RegExp.rightContext,next=nextBrace(allNext);methods+="addMethod"+mc[1]+next+"});";rest=prev+allNext.slice(next.length+1);}
     13rest=methods+rest;aCode=left+rest+"\n}}"+staticVars+allRest;}
     14aCode=aCode.replace(/Processing.\w+ = function addMethod/g,"addMethod");function nextBrace(right){var rest=right,position=0,leftCount=1,rightCount=0;while(leftCount!=rightCount){var nextLeft=rest.indexOf("{"),nextRight=rest.indexOf("}");if(nextLeft<nextRight&&nextLeft!=-1){leftCount++;rest=rest.slice(nextLeft+1);position+=nextLeft+1;}else{rightCount++;rest=rest.slice(nextRight+1);position+=nextRight+1;}}
     15return right.slice(0,position-1);}
     16aCode=aCode.replace(/\(int\)/g,"0|");aCode=aCode.replace(new RegExp("\\(("+classes.join("|")+")(\\[\\])?\\)","g"),"");aCode=aCode.replace(/(\d+)f[^a-zA-Z0-9]/g,"$1");aCode=aCode.replace(/('[a-zA-Z0-9]')/g,"$1.charCodeAt(0)");aCode=aCode.replace(/#([a-f0-9]{6})/ig,function(m,hex){var num=toNumbers(hex);return"DefaultColor("+num[0]+","+num[1]+","+num[2]+")";});function toNumbers(str){var ret=[];str.replace(/(..)/g,function(str){ret.push(parseInt(str,16));});return ret;}
     17return aCode;};function buildProcessing(curElement){var p={};p.name='Processing.js Instance';p.PI=Math.PI;p.TWO_PI=2*p.PI;p.HALF_PI=p.PI/2;p.P3D=3;p.CORNER=0;p.RADIUS=1;p.CENTER_RADIUS=1;p.CENTER=2;p.POLYGON=2;p.QUADS=5;p.TRIANGLES=6;p.POINTS=7;p.LINES=8;p.TRIANGLE_STRIP=9;p.TRIANGLE_FAN=4;p.QUAD_STRIP=3;p.CORNERS=10;p.CLOSE=true;p.RGB=1;p.HSB=2;p.CENTER=88888880;p.CODED=88888888;p.UP=88888870;p.RIGHT=88888871;p.DOWN=88888872;p.LEFT=88888869;p.codedKeys=[69,70,71,72];var curContext=curElement.getContext("2d"),doFill=true,doStroke=true,loopStarted=false,hasBackground=false,doLoop=true,looping=0,curRectMode=p.CORNER,curEllipseMode=p.CENTER,inSetup=false,inDraw=false,curBackground="rgba( 204, 204, 204, 1 )",curFrameRate=1000,curMsPerFrame=1,curShape=p.POLYGON,curShapeCount=0,curvePoints=[],curTightness=0,opacityRange=255,redRange=255,greenRange=255,blueRange=255,pathOpen=false,mousePressed=false,keyPressed=false,curColorMode=p.RGB;curTint=-1,curTextSize=12,curTextFont="Arial",getLoaded=false,start=(new Date).getTime();var firstX,firstY,secondX,secondY,prevX,prevY;p.ln="";p.glyphTable={};p.pmouseX=0;p.pmouseY=0;p.mouseX=0;p.mouseY=0;p.mouseButton=0;p.mouseDown=false;p.mouseClicked=undefined;p.mouseDragged=undefined;p.mouseMoved=undefined;p.mousePressed=undefined;p.mouseReleased=undefined;p.keyPressed=undefined;p.keyReleased=undefined;p.draw=undefined;p.setup=undefined;p.width=curElement.width-0;p.height=curElement.height-0;p.frameCount=0;p.ArrayList=function ArrayList(size,size2,size3){var array=new Array(0|size);if(size2){for(var i=0;i<size;i++){array[i]=[];for(var j=0;j<size2;j++){var a=array[i][j]=size3?new Array(size3):0;for(var k=0;k<size3;k++){a[k]=0;}}}}else{for(var i=0;i<size;i++){array[i]=0;}}
     18array.get=function(i){return this[i];};array.add=function(item){return this.push(item);};array.size=function(){return this.length;};array.clear=function(){this.length=0;};array.remove=function(i){return this.splice(i,1);};array.isEmpty=function(){return!this.length;};array.clone=function(){var a=new ArrayList(size);for(var i=0;i<size;i++){a[i]=this[i];}
     19return a;};return array;};p.color=function color(aValue1,aValue2,aValue3,aValue4){var aColor="";if(arguments.length==3){aColor=p.color(aValue1,aValue2,aValue3,opacityRange);}else if(arguments.length==4){var a=aValue4/opacityRange;a=isNaN(a)?1:a;if(curColorMode==p.HSB){var rgb=HSBtoRGB(aValue1,aValue2,aValue3)
     20r=rgb[0],g=rgb[1],b=rgb[2];}else{var r=getColor(aValue1,redRange);var g=getColor(aValue2,greenRange);var b=getColor(aValue3,blueRange);}
     21aColor="rgba("+r+","+g+","+b+","+a+")";}else if(typeof aValue1=="string"){aColor=aValue1;if(arguments.length==2){var c=aColor.split(",");c[3]=(aValue2/opacityRange)+")";aColor=c.join(",");}}else if(arguments.length==2){aColor=p.color(aValue1,aValue1,aValue1,aValue2);}else if(typeof aValue1=="number"){aColor=p.color(aValue1,aValue1,aValue1,opacityRange);}else{aColor=p.color(redRange,greenRange,blueRange,opacityRange);}
     22function HSBtoRGB(h,s,b){h=(h/redRange)*360;s=(s/greenRange)*100;b=(b/blueRange)*100;var br=Math.round(b/100*255);if(s==0){return[br,br,br];}else{var hue=h%360;var f=hue%60;var p=Math.round((b*(100-s))/10000*255);var q=Math.round((b*(6000-s*f))/600000*255);var t=Math.round((b*(6000-s*(60-f)))/600000*255);switch(Math.floor(hue/60)){case 0:return[br,t,p];case 1:return[q,br,p];case 2:return[p,br,t];case 3:return[p,q,br];case 4:return[t,p,br];case 5:return[br,p,q];}}}
     23function getColor(aValue,range){return Math.round(255*(aValue/range));}
     24return aColor;}
     25p.red=function(aColor){return parseInt(verifyChannel(aColor).slice(5));};p.green=function(aColor){return parseInt(verifyChannel(aColor).split(",")[1]);};p.blue=function(aColor){return parseInt(verifyChannel(aColor).split(",")[2]);};p.alpha=function(aColor){return parseInt(parseFloat(verifyChannel(aColor).split(",")[3])*255);};function verifyChannel(aColor){if(aColor.constructor==Array){return aColor;}else{return p.color(aColor);}}
     26p.lerpColor=function lerpColor(c1,c2,amt){var colors1=p.color(c1).split(",");var r1=parseInt(colors1[0].split("(")[1]);var g1=parseInt(colors1[1]);var b1=parseInt(colors1[2]);var a1=parseFloat(colors1[3].split(")")[0]);var colors2=p.color(c2).split(",");var r2=parseInt(colors2[0].split("(")[1]);var g2=parseInt(colors2[1]);var b2=parseInt(colors2[2]);var a2=parseFloat(colors2[3].split(")")[0]);var r=parseInt(p.lerp(r1,r2,amt));var g=parseInt(p.lerp(g1,g2,amt));var b=parseInt(p.lerp(b1,b2,amt));var a=parseFloat(p.lerp(a1,a2,amt));return aColor="rgba("+r+","+g+","+b+","+a+")";}
     27p.DefaultColor=function(aValue1,aValue2,aValue3){var tmpColorMode=curColorMode;curColorMode=p.RGB;var c=p.color(aValue1/255*redRange,aValue2/255*greenRange,aValue3/255*blueRange);curColorMode=tmpColorMode;return c;}
     28p.colorMode=function colorMode(mode,range1,range2,range3,range4){curColorMode=mode;if(arguments.length>=4){redRange=range1;greenRange=range2;blueRange=range3;}
     29if(arguments.length==5){opacityRange=range4;}
     30if(arguments.length==2){p.colorMode(mode,range1,range1,range1,range1);}};p.translate=function translate(x,y){curContext.translate(x,y);};p.scale=function scale(x,y){curContext.scale(x,y||x);};p.rotate=function rotate(aAngle){curContext.rotate(aAngle);};p.pushMatrix=function pushMatrix(){curContext.save();};p.popMatrix=function popMatrix(){curContext.restore();};p.ortho=function ortho(){};p.year=function year(){return(new Date).getYear()+1900;};p.month=function month(){return(new Date).getMonth();};p.day=function day(){return(new Date).getDay();};p.hour=function hour(){return(new Date).getHours();};p.minute=function minute(){return(new Date).getMinutes();};p.second=function second(){return(new Date).getSeconds();};p.millis=function millis(){return(new Date).getTime()-start;};p.noLoop=function noLoop(){doLoop=false;};p.redraw=function redraw(){if(hasBackground){p.background();}
     31p.frameCount++;inDraw=true;p.pushMatrix();p.draw();p.popMatrix();inDraw=false;};p.loop=function loop(){if(loopStarted){return;}
     32looping=setInterval(function(){try{p.redraw();}
     33catch(e){clearInterval(looping);throw e;}},curMsPerFrame);loopStarted=true;};p.frameRate=function frameRate(aRate){curFrameRate=aRate;curMsPerFrame=1000/curFrameRate;};p.exit=function exit(){clearInterval(looping);};p.cursor=function(mode){document.body.style.cursor=mode;}
     34p.link=function(href,target){window.location=href;};p.beginDraw=function beginDraw(){};p.endDraw=function endDraw(){};p.ajax=ajax;p.Import=function Import(lib){eval(p.ajax(lib));}
     35p.loadStrings=function loadStrings(url){return p.ajax(url).split("\n");};p.nf=function(num,pad){var str=""+num;while(pad-str.length){str="0"+str;}
     36return str;};String.prototype.replaceAll=function(re,replace){return this.replace(new RegExp(re,"g"),replace);};p.lnPrinted=function lnPrinted(){};p.printed=function printed(){};p.println=function println(){if(arguments.callee.caller){var Caller=arguments.callee.caller.name.toString();if(arguments.length>1){Caller!="print"?p.ln=arguments:p.ln=arguments[0];}else{p.ln=arguments[0];}
     37Caller=="print"?p.printed(arguments):p.lnPrinted();}};p.str=function str(aNumber){return aNumber+'';}
     38p.print=function print(){p.println(arguments[0])};p.char=function char(key){return key;};p.sq=function sq(aNumber){return aNumber*aNumber;};p.sqrt=function sqrt(aNumber){return Math.sqrt(aNumber);};p.int=function int(aNumber){return Math.floor(aNumber);};p.min=function min(aNumber,aNumber2){return Math.min(aNumber,aNumber2);};p.max=function max(aNumber,aNumber2){return Math.max(aNumber,aNumber2);};p.floor=function floor(aNumber){return Math.floor(aNumber);};p.float=function float(aNumber){return parseFloat(aNumber);};p.ceil=function ceil(aNumber){return Math.ceil(aNumber);};p.round=function round(aNumber){return Math.round(aNumber);};p.lerp=function lerp(value1,value2,amt){return((value2-value1)*amt)+value1;};p.abs=function abs(aNumber){return Math.abs(aNumber);};p.cos=function cos(aNumber){return Math.cos(aNumber);};p.sin=function sin(aNumber){return Math.sin(aNumber);};p.pow=function pow(aNumber,aExponent){return Math.pow(aNumber,aExponent);};p.sqrt=function sqrt(aNumber){return Math.sqrt(aNumber);};p.atan2=function atan2(aNumber,aNumber2){return Math.atan2(aNumber,aNumber2);};p.radians=function radians(aAngle){return(aAngle/180)*p.PI;};p.dist=function dist(x1,y1,x2,y2){return Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2));};p.map=function map(value,istart,istop,ostart,ostop){return ostart+(ostop-ostart)*((value-istart)/(istop-istart));};p.Random=function(){var haveNextNextGaussian=false,nextNextGaussian;this.nextGaussian=function(){if(haveNextNextGaussian){haveNextNextGaussian=false;return nextNextGaussian;}else{var v1,v2,s;do{v1=2*p.random(1)-1;v2=2*p.random(1)-1;s=v1*v1+v2*v2;}
     39while(s>=1||s==0);var multiplier=Math.sqrt(-2*Math.log(s)/s);nextNextGaussian=v2*multiplier;haveNextNextGaussian=true;return v1*multiplier;}};};p.byte=function byte(aNumber){return aNumber||0;};p.norm=function norm(aNumber,low,high){var range=high-low;return((1/range)*aNumber)-((1/range)*low);};p.random=function random(aMin,aMax){return arguments.length==2?aMin+(Math.random()*(aMax-aMin)):Math.random()*aMin;};p.noise=function(x,y,z){return arguments.length>=2?PerlinNoise_2D(x,y,z):PerlinNoise_3D(x,x,z);};function Noise(x,y){var n=x+y*57;n=(n<<13)^n;return Math.abs(1.0-(((n*((n*n*15731)+789221)+1376312589)&0x7fffffff)/1073741824.0));};function SmoothedNoise(x,y){var corners=(Noise(x-1,y-1)+Noise(x+1,y-1)+Noise(x-1,y+1)+Noise(x+1,y+1))/16,sides=(Noise(x-1,y)+Noise(x+1,y)+Noise(x,y-1)+Noise(x,y+1))/8,center=Noise(x,y)/4;return corners+sides+center;};function InterpolatedNoise(x,y){var integer_X=Math.floor(x);var fractional_X=x-integer_X;var integer_Y=Math.floor(y);var fractional_Y=y-integer_Y;var v1=SmoothedNoise(integer_X,integer_Y),v2=SmoothedNoise(integer_X+1,integer_Y),v3=SmoothedNoise(integer_X,integer_Y+1),v4=SmoothedNoise(integer_X+1,integer_Y+1);var i1=Interpolate(v1,v2,fractional_X),i2=Interpolate(v3,v4,fractional_X);return Interpolate(i1,i2,fractional_Y);}
     40function PerlinNoise_2D(x,y){var total=0,p=0.25,n=3;for(var i=0;i<=n;i++){var frequency=Math.pow(2,i);var amplitude=Math.pow(p,i);total+=InterpolatedNoise(x*frequency,y*frequency)*amplitude;}
     41return total;}
     42function Interpolate(a,b,x){var ft=x*p.PI;var f=(1-Math.cos(ft))*.5;return a*(1-f)+b*f;}
     43p.constrain=function constrain(aNumber,aMin,aMax){return Math.min(Math.max(aNumber,aMin),aMax);};p.degrees=function degrees(aAngle){aAngle=(aAngle*180)/p.PI;if(aAngle<0){aAngle=360+aAngle}
     44return aAngle;};p.size=function size(aWidth,aHeight){var fillStyle=curContext.fillStyle,strokeStyle=curContext.strokeStyle;curElement.width=p.width=aWidth;curElement.height=p.height=aHeight;curContext.fillStyle=fillStyle;curContext.strokeStyle=strokeStyle;};p.noStroke=function noStroke(){doStroke=false;};p.noFill=function noFill(){doFill=false;};p.smooth=function smooth(){};p.noSmooth=function noSmooth(){};p.fill=function fill(){doFill=true;curContext.fillStyle=p.color.apply(this,arguments);};p.stroke=function stroke(){doStroke=true;curContext.strokeStyle=p.color.apply(this,arguments);};p.strokeWeight=function strokeWeight(w){curContext.lineWidth=w;};p.Point=function Point(x,y){this.x=x;this.y=y;this.copy=function(){return new Point(x,y);}};p.point=function point(x,y){var oldFill=curContext.fillStyle;curContext.fillStyle=curContext.strokeStyle;curContext.fillRect(Math.round(x),Math.round(y),1,1);curContext.fillStyle=oldFill;};p.beginShape=function beginShape(type){curShape=type;curShapeCount=0;curvePoints=[];};p.endShape=function endShape(close){if(curShapeCount!=0){if(close||doFill){curContext.lineTo(firstX,firstY);}
     45if(doFill){curContext.fill();}
     46if(doStroke){curContext.stroke();}
     47curContext.closePath();curShapeCount=0;pathOpen=false;}
     48if(pathOpen){if(doFill){curContext.fill();}
     49if(doStroke){curContext.stroke();}
     50curContext.closePath();curShapeCount=0;pathOpen=false;}};p.vertex=function vertex(x,y,x2,y2,x3,y3){if(curShapeCount==0&&curShape!=p.POINTS){pathOpen=true;curContext.beginPath();curContext.moveTo(x,y);firstX=x;firstY=y;}else{if(curShape==p.POINTS){p.point(x,y);}else if(arguments.length==2){if(curShape!=p.QUAD_STRIP||curShapeCount!=2){curContext.lineTo(x,y);}
     51if(curShape==p.TRIANGLE_STRIP){if(curShapeCount==2){p.endShape(p.CLOSE);pathOpen=true;curContext.beginPath();curContext.moveTo(prevX,prevY);curContext.lineTo(x,y);curShapeCount=1;}
     52firstX=prevX;firstY=prevY;}
     53if(curShape==p.TRIANGLE_FAN&&curShapeCount==2){p.endShape(p.CLOSE);pathOpen=true;curContext.beginPath();curContext.moveTo(firstX,firstY);curContext.lineTo(x,y);curShapeCount=1;}
     54if(curShape==p.QUAD_STRIP&&curShapeCount==3){curContext.lineTo(prevX,prevY);p.endShape(p.CLOSE);pathOpen=true;curContext.beginPath();curContext.moveTo(prevX,prevY);curContext.lineTo(x,y);curShapeCount=1;}
     55if(curShape==p.QUAD_STRIP){firstX=secondX;firstY=secondY;secondX=prevX;secondY=prevY;}}else if(arguments.length==4){if(curShapeCount>1){curContext.moveTo(prevX,prevY);curContext.quadraticCurveTo(firstX,firstY,x,y);curShapeCount=1;}}else if(arguments.length==6){curContext.bezierCurveTo(x,y,x2,y2,x3,y3);}}
     56prevX=x;prevY=y;curShapeCount++;if(curShape==p.LINES&&curShapeCount==2||(curShape==p.TRIANGLES)&&curShapeCount==3||(curShape==p.QUADS)&&curShapeCount==4){p.endShape(p.CLOSE);}};p.curveVertex=function(x,y,x2,y2){if(curvePoints.length<3){curvePoints.push([x,y]);}else{var b=[],s=1-curTightness;curvePoints.push([x,y]);b[0]=[curvePoints[1][0],curvePoints[1][1]];b[1]=[curvePoints[1][0]+(s*curvePoints[2][0]-s*curvePoints[0][0])/6,curvePoints[1][1]+(s*curvePoints[2][1]-s*curvePoints[0][1])/6];b[2]=[curvePoints[2][0]+(s*curvePoints[1][0]-s*curvePoints[3][0])/6,curvePoints[2][1]+(s*curvePoints[1][1]-s*curvePoints[3][1])/6];b[3]=[curvePoints[2][0],curvePoints[2][1]];if(!pathOpen){p.vertex(b[0][0],b[0][1]);}else{curShapeCount=1;}
     57p.vertex(b[1][0],b[1][1],b[2][0],b[2][1],b[3][0],b[3][1]);curvePoints.shift();}};p.curveTightness=function(tightness){curTightness=tightness;};p.bezierVertex=p.vertex;p.rectMode=function rectMode(aRectMode){curRectMode=aRectMode;};p.imageMode=function(){};p.ellipseMode=function ellipseMode(aEllipseMode){curEllipseMode=aEllipseMode;};p.arc=function arc(x,y,width,height,start,stop){if(width<=0){return;}
     58if(curEllipseMode==p.CORNER){x+=width/2;y+=height/2;}
     59curContext.moveTo(x,y);curContext.beginPath();curContext.arc(x,y,curEllipseMode==p.CENTER_RADIUS?width:width/2,start,stop,false);if(doStroke){curContext.stroke();}
     60curContext.lineTo(x,y);if(doFill){curContext.fill();}
     61curContext.closePath();};p.line=function line(x1,y1,x2,y2){curContext.lineCap="round";curContext.beginPath();curContext.moveTo(x1||0,y1||0);curContext.lineTo(x2||0,y2||0);curContext.stroke();curContext.closePath();};p.bezier=function bezier(x1,y1,x2,y2,x3,y3,x4,y4){curContext.lineCap="butt";curContext.beginPath();curContext.moveTo(x1,y1);curContext.bezierCurveTo(x2,y2,x3,y3,x4,y4);curContext.stroke();curContext.closePath();};p.triangle=function triangle(x1,y1,x2,y2,x3,y3){p.beginShape();p.vertex(x1,y1);p.vertex(x2,y2);p.vertex(x3,y3);p.endShape();};p.quad=function quad(x1,y1,x2,y2,x3,y3,x4,y4){curContext.lineCap="square";p.beginShape();p.vertex(x1,y1);p.vertex(x2,y2);p.vertex(x3,y3);p.vertex(x4,y4);p.endShape();};p.rect=function rect(x,y,width,height){if(!(width+height)){return;}
     62curContext.beginPath();var offsetStart=0;var offsetEnd=0;if(curRectMode==p.CORNERS){width-=x;height-=y;}
     63if(curRectMode==p.RADIUS){width*=2;height*=2;}
     64if(curRectMode==p.CENTER||curRectMode==p.RADIUS){x-=width/2;y-=height/2;}
     65curContext.rect(Math.round(x)-offsetStart,Math.round(y)-offsetStart,Math.round(width)+offsetEnd,Math.round(height)+offsetEnd);if(doFill){curContext.fill();}
     66if(doStroke){curContext.stroke()};curContext.closePath();};p.ellipse=function ellipse(x,y,width,height){x=x||0;y=y||0;if(width<=0&&height<=0){return;}
     67curContext.beginPath();if(curEllipseMode==p.RADIUS){width*=2;height*=2;}
     68var offsetStart=0;if(width==height){curContext.arc(x-offsetStart,y-offsetStart,width/2,0,p.TWO_PI,false);}else{var w=width/2,h=height/2,C=0.5522847498307933;var c_x=C*w,c_y=C*h;curContext.moveTo(x+w,y);curContext.bezierCurveTo(x+w,y-c_y,x+c_x,y-h,x,y-h);curContext.bezierCurveTo(x-c_x,y-h,x-w,y-c_y,x-w,y);curContext.bezierCurveTo(x-w,y+c_y,x-c_x,y+h,x,y+h);curContext.bezierCurveTo(x+c_x,y+h,x+w,y+c_y,x+w,y);}
     69if(doFill){curContext.fill();}
     70if(doStroke){curContext.stroke();}
     71curContext.closePath();};p.save=function save(file){};p.loadImage=function loadImage(file,type,callback){var img=document.createElement('img');img.src=file;img.onload=function(){var h=this.height,w=this.width;var canvas=document.createElement("canvas");canvas.width=w;canvas.height=h;var context=canvas.getContext("2d");context.drawImage(this,0,0);this.data=buildImageObject(context.getImageData(0,0,w,h));this.data.img=img;callback?callback():0;}
     72return img;};p.get=function get(x,y){if(!arguments.length){var c=p.createGraphics(p.width,p.height);c.image(curContext,0,0);return c;}
     73if(!getLoaded){getLoaded=buildImageObject(curContext.getImageData(0,0,p.width,p.height));}
     74return getLoaded.get(x,y);};p.createGraphics=function createGraphics(w,h){var canvas=document.createElement("canvas");var ret=buildProcessing(canvas);ret.size(w,h);ret.canvas=canvas;return ret;};p.set=function set(x,y,obj){if(obj&&obj.img){p.image(obj,x,y);}else{var oldFill=curContext.fillStyle,color=obj;curContext.fillStyle=color;curContext.fillRect(Math.round(x),Math.round(y),1,1);curContext.fillStyle=oldFill;}};p.loadPixels=function(){p.pixels=buildImageObject(curContext.getImageData(0,0,p.width,p.height)).pixels;};p.updatePixels=function(){var colors=/(\d+),(\d+),(\d+),(\d+)/,pixels={};pixels.width=p.width;pixels.height=p.height;pixels.data=[];if(curContext.createImageData){pixels=curContext.createImageData(p.width,p.height);}
     75var data=pixels.data,pos=0;for(var i=0,l=p.pixels.length;i<l;i++){var c=(p.pixels[i]||"rgba(0,0,0,1)").match(colors);data[pos+0]=parseInt(c[1]);data[pos+1]=parseInt(c[2]);data[pos+2]=parseInt(c[3]);data[pos+3]=parseFloat(c[4])*255;pos+=4;}
     76curContext.putImageData(pixels,0,0);};p.background=function background(img){if(arguments.length){if(img.data&&img.data.img){curBackground=img.data;}else{curBackground=p.color.apply(this,arguments);}}
     77if(curBackground.img){p.image(img,0,0);}else{var oldFill=curContext.fillStyle;curContext.fillStyle=curBackground+"";curContext.fillRect(0,0,p.width,p.height);curContext.fillStyle=oldFill;}};p.AniSprite=function(prefix,frames){this.images=[];this.pos=0;for(var i=0;i<frames;i++){this.images.push(prefix+p.nf(i,(""+frames).length)+".gif");}
     78this.display=function(x,y){p.image_old(this.images[this.pos],x,y);if(++this.pos>=frames){this.pos=0;}};this.getWidth=function(){return getImage_old(this.images[0]).width;};this.getHeight=function(){return getImage_old(this.images[0]).height;};};function buildImageObject(obj){var pixels=obj.data;var data=p.createImage(obj.width,obj.height);if(data.__defineGetter__&&data.__lookupGetter__&&!data.__lookupGetter__("pixels")){var pixelsDone;data.__defineGetter__("pixels",function(){if(pixelsDone){return pixelsDone;}
     79pixelsDone=[];for(var i=0;i<pixels.length;i+=4){pixelsDone.push(p.color(pixels[i],pixels[i+1],pixels[i+2],pixels[i+3]));}
     80return pixelsDone;});}else{data.pixels=[];for(var i=0;i<pixels.length;i+=4){data.pixels.push(p.color(pixels[i],pixels[i+1],pixels[i+2],pixels[i+3]));}}
     81return data;}
     82p.createImage=function createImage(w,h,mode){var data={};data.width=w;data.height=h;data.data=[];if(curContext.createImageData){data=curContext.createImageData(w,h);}
     83data.pixels=new Array(w*h);data.get=function(x,y){return this.pixels[w*y+x];};data._mask=null;data.mask=function(img){this._mask=img;};data.loadPixels=function(){};data.updatePixels=function(){};return data;};function getImage(img){if(typeof img=="string"){return document.getElementById(img);}
     84if(img.img){return img.img;}else if(img.getContext||img.canvas){img.pixels=img.getContext('2d').createImageData(img.width,img.height);}
     85for(var i=0,l=img.pixels.length;i<l;i++){var pos=i*4;var c=(img.pixels[i]||"rgba(0,0,0,1)").slice(5,-1).split(",");img.data[pos+0]=parseInt(c[0]);img.data[pos+1]=parseInt(c[1]);img.data[pos+2]=parseInt(c[2]);img.data[pos+3]=parseFloat(c[3])*100;}
     86var canvas=document.createElement("canvas");canvas.width=img.width;canvas.height=img.height;var context=canvas.getContext("2d");context.putImageData(img.pixels,0,0);img.canvas=canvas;return img;}
     87function getImage_old(img){if(typeof img=="string"){return document.getElementById(img);}
     88if(img.img||img.canvas){return img.img||img.canvas;}
     89for(var i=0,l=img.pixels.length;i<l;i++){var pos=i*4;var c=(img.pixels[i]||"rgba(0,0,0,1)").slice(5,-1).split(",");img.data[pos+0]=parseInt(c[0]);img.data[pos+1]=parseInt(c[1]);img.data[pos+2]=parseInt(c[2]);img.data[pos+3]=parseFloat(c[3])*100;}
     90var canvas=document.createElement("canvas");canvas.width=img.width;canvas.height=img.height;var context=canvas.getContext("2d");context.putImageData(img,0,0);img.canvas=canvas;return canvas;}
     91p.image_old=function image_old(img,x,y,w,h){x=x||0;y=y||0;var obj=getImage(img);if(curTint>=0){var oldAlpha=curContext.globalAlpha;curContext.globalAlpha=curTint/opacityRange;}
     92if(arguments.length==3){curContext.drawImage(obj,x,y);}else{curContext.drawImage(obj,x,y,w,h);}
     93if(curTint>=0){curContext.globalAlpha=oldAlpha;}
     94if(img._mask){var oldComposite=curContext.globalCompositeOperation;curContext.globalCompositeOperation="darker";p.image(img._mask,x,y);curContext.globalCompositeOperation=oldComposite;}};p.image=function image(img,x,y,w,h){if(img.data||img.canvas){x=x||0;y=y||0;var obj=getImage(img.data||img.canvas);if(curTint>=0){var oldAlpha=curContext.globalAlpha;curContext.globalAlpha=curTint/opacityRange;}
     95if(arguments.length==3){curContext.drawImage(obj,x,y);}else{curContext.drawImage(obj,x,y,w,h);}
     96if(curTint>=0){curContext.globalAlpha=oldAlpha;}
     97if(img._mask){var oldComposite=curContext.globalCompositeOperation;curContext.globalCompositeOperation="darker";p.image(img._mask,x,y);curContext.globalCompositeOperation=oldComposite;}}
     98if(typeof img=='string'){}};p.clear=function clear(x,y,width,height){if(arguments.length==0){curContext.clearRect(x,y,width,height);}else{curContext.clearRect(0,0,p.width,p.height);}}
     99p.tint=function tint(rgb,a){curTint=a;};p.loadFont=function loadFont(name){if(name.indexOf(".svg")==-1){return{name:name,width:function(str){if(curContext.mozMeasureText){return curContext.mozMeasureText(typeof str=="number"?String.fromCharCode(str):str)/curTextSize;}else{return 0;}}};}else{var font=p.loadGlyphs(name);return{name:name,glyph:true,units_per_em:font.units_per_em,horiz_adv_x:1/font.units_per_em*font.horiz_adv_x,ascent:font.ascent,descent:font.descent,width:function(str){var width=0;var len=str.length;for(var i=0;i<len;i++){try{width+=parseFloat(p.glyphLook(p.glyphTable[name],str[i]).horiz_adv_x);}
     100catch(e){;}}
     101return width/p.glyphTable[name].units_per_em;}}}};p.textFont=function textFont(name,size){curTextFont=name;p.textSize(size);};p.textSize=function textSize(size){if(size){curTextSize=size;}};p.textAlign=function textAlign(){};p.glyphLook=function glyphLook(font,chr){try{switch(chr){case"1":return font["one"];break;case"2":return font["two"];break;case"3":return font["three"];break;case"4":return font["four"];break;case"5":return font["five"];break;case"6":return font["six"];break;case"7":return font["seven"];break;case"8":return font["eight"];break;case"9":return font["nine"];break;case"0":return font["zero"];break;case" ":return font["space"];break;case"$":return font["dollar"];break;case"!":return font["exclam"];break;case'"':return font["quotedbl"];break;case"#":return font["numbersign"];break;case"%":return font["percent"];break;case"&":return font["ampersand"];break;case"'":return font["quotesingle"];break;case"(":return font["parenleft"];break;case")":return font["parenright"];break;case"*":return font["asterisk"];break;case"+":return font["plus"];break;case",":return font["comma"];break;case"-":return font["hyphen"];break;case".":return font["period"];break;case"/":return font["slash"];break;case"_":return font["underscore"];break;case":":return font["colon"];break;case";":return font["semicolon"];break;case"<":return font["less"];break;case"=":return font["equal"];break;case">":return font["greater"];break;case"?":return font["question"];break;case"@":return font["at"];break;case"[":return font["bracketleft"];break;case"\\":return font["backslash"];break;case"]":return font["bracketright"];break;case"^":return font["asciicircum"];break;case"`":return font["grave"];break;case"{":return font["braceleft"];break;case"|":return font["bar"];break;case"}":return font["braceright"];break;case"~":return font["asciitilde"];break;default:return font[chr];break;}}catch(e){;}}
     102p.text=function text(str,x,y){if(!curTextFont.glyph){if(str&&curContext.mozDrawText){curContext.save();curContext.mozTextStyle=curTextSize+"px "+curTextFont.name;curContext.translate(x,y);curContext.mozDrawText(typeof str=="number"?String.fromCharCode(str):str);curContext.restore();}}else{var font=p.glyphTable[curTextFont.name];curContext.save();curContext.translate(x,y+curTextSize);var upem=font["units_per_em"],newScale=1/upem*curTextSize;curContext.scale(newScale,newScale);var len=str.length;for(var i=0;i<len;i++){try{p.glyphLook(font,str[i]).draw();}
     103catch(e){;}}
     104curContext.restore();}};p.loadGlyphs=function loadGlyph(url){var loadXML=function loadXML(){try{var xmlDoc=new ActiveXObject("Microsoft.XMLDOM");}
     105catch(e){try{xmlDoc=document.implementation.createDocument("","",null);}
     106catch(e){p.println(e.message);return;}};try{xmlDoc.async=false;xmlDoc.load(url);parse(xmlDoc.getElementsByTagName("svg")[0]);}
     107catch(e){try{p.println(e.message);var xmlhttp=new window.XMLHttpRequest();xmlhttp.open("GET",url,false);xmlhttp.send(null);parse(xmlhttp.responseXML.documentElement);}
     108catch(e){;}}};var regex=function regex(needle,hay){var regexp=new RegExp(needle,"g"),results=[],i=0;while(results[i]=regexp.exec(hay)){i++;}
     109return results;}
     110var parse=function parse(svg){var font=svg.getElementsByTagName("font");p.glyphTable[url]["horiz_adv_x"]=font[0].getAttribute("horiz-adv-x");var font_face=svg.getElementsByTagName("font-face")[0];p.glyphTable[url]["units_per_em"]=parseFloat(font_face.getAttribute("units-per-em"));p.glyphTable[url]["ascent"]=parseFloat(font_face.getAttribute("ascent"));p.glyphTable[url]["descent"]=parseFloat(font_face.getAttribute("descent"));var getXY="[0-9\-]+",glyph=svg.getElementsByTagName("glyph"),len=glyph.length;for(var i=0;i<len;i++){var unicode=glyph[i].getAttribute("unicode");var name=glyph[i].getAttribute("glyph-name");var horiz_adv_x=glyph[i].getAttribute("horiz-adv-x");if(horiz_adv_x==null){var horiz_adv_x=p.glyphTable[url]['horiz_adv_x'];}
     111var buildPath=function buildPath(d){var c=regex("[A-Za-z][0-9\- ]+|Z",d);var path="var path={draw:function(){curContext.beginPath();curContext.save();";var x=0,y=0,cx=0,cy=0,nx=0,ny=0,d=0,a=0,lastCom="",lenC=c.length-1;for(var j=0;j<lenC;j++){var com=c[j][0],xy=regex(getXY,com);switch(com[0]){case"M":x=parseFloat(xy[0][0]);y=parseFloat(xy[1][0]);path+="curContext.moveTo("+x+","+(-y)+");";break;case"L":x=parseFloat(xy[0][0]);y=parseFloat(xy[1][0]);path+="curContext.lineTo("+x+","+(-y)+");";break;case"H":x=parseFloat(xy[0][0]);path+="curContext.lineTo("+x+","+(-y)+");";break;case"V":y=parseFloat(xy[0][0]);path+="curContext.lineTo("+x+","+(-y)+");";break;case"T":nx=parseFloat(xy[0][0]);ny=parseFloat(xy[1][0]);if(lastCom=="Q"||lastCom=="T"){d=Math.sqrt(Math.pow(x-cx,2)+Math.pow(cy-y,2));a=Math.PI+Math.atan2(cx-x,cy-y);cx=x+(Math.sin(a)*(d));cy=y+(Math.cos(a)*(d));}else{cx=x;cy=y;}
     112path+="curContext.quadraticCurveTo("+cx+","+(-cy)+","+nx+","+(-ny)+");";x=nx;y=ny;break;case"Q":cx=parseFloat(xy[0][0]);cy=parseFloat(xy[1][0]);nx=parseFloat(xy[2][0]);ny=parseFloat(xy[3][0]);path+="curContext.quadraticCurveTo("+cx+","+(-cy)+","+nx+","+(-ny)+");";x=nx;y=ny;break;case"Z":path+="curContext.closePath();";break;}
     113lastCom=com[0];}
     114path+="doStroke?curContext.stroke():0;";path+="doFill?curContext.fill():0;";path+="curContext.restore();";path+="curContext.translate("+horiz_adv_x+",0);";path+="}}";return path;}
     115var d=glyph[i].getAttribute("d");if(d!==undefined){var path=buildPath(d);eval(path);p.glyphTable[url][name]={name:name,unicode:unicode,horiz_adv_x:horiz_adv_x,draw:path.draw}}}}
     116p.glyphTable[url]={};loadXML(url);return p.glyphTable[url];}
     117p.extendClass=function extendClass(obj,args,fn){if(arguments.length==3){fn.apply(obj,args);}else{args.call(obj);}};p.addMethod=function addMethod(object,name,fn){if(object[name]){var args=fn.length,oldfn=object[name];object[name]=function(){if(arguments.length==args){return fn.apply(this,arguments);}else{return oldfn.apply(this,arguments);}};}else{object[name]=fn;}};p.init=function init(code){p.stroke(0);p.fill(255);curContext.translate(0.5,0.5);if(code){(function(Processing){with(p){eval(parse(code,p));}})(p);}
     118if(p.setup){inSetup=true;p.setup();}
     119inSetup=false;if(p.draw){if(!doLoop){p.redraw();}else{p.loop();}}
     120attach(curElement,"mousemove",function(e){var scrollX=window.scrollX!=null?window.scrollX:window.pageXOffset;var scrollY=window.scrollY!=null?window.scrollY:window.pageYOffset;p.pmouseX=p.mouseX;p.pmouseY=p.mouseY;p.mouseX=e.clientX-curElement.offsetLeft+scrollX;p.mouseY=e.clientY-curElement.offsetTop+scrollY;if(p.mouseMoved){p.mouseMoved();}
     121if(mousePressed&&p.mouseDragged){p.mouseDragged();}});attach(curElement,"mouseout",function(e){p.cursor("auto");});attach(curElement,"mousedown",function(e){mousePressed=true;switch(e.which){case 1:p.mouseButton=p.LEFT;break;case 2:p.mouseButton=p.CENTER;break;case 3:p.mouseButton=p.RIGHT;break;}
     122p.mouseDown=true;if(typeof p.mousePressed=="function"){p.mousePressed();}
     123else{p.mousePressed=true;}});attach(curElement,"contextmenu",function(e){e.preventDefault();e.stopPropagation();});attach(curElement,"mouseup",function(e){mousePressed=false;if(p.mouseClicked){p.mouseClicked();}
     124if(typeof p.mousePressed!="function"){p.mousePressed=false;}
     125if(p.mouseReleased){p.mouseReleased();}});attach(document,"keydown",function(e){keyPressed=true;p.key=e.keyCode+32;var i,len=p.codedKeys.length;for(i=0;i<len;i++){if(p.key==p.codedKeys[i]){switch(p.key){case 70:p.keyCode=p.UP;break;case 71:p.keyCode=p.RIGHT;break;case 72:p.keyCode=p.DOWN;break;case 69:p.keyCode=p.LEFT;break;}
     126p.key=p.CODED;}}
     127if(e.shiftKey){p.key=String.fromCharCode(p.key).toUpperCase().charCodeAt(0);}
     128if(typeof p.keyPressed=="function"){p.keyPressed();}
     129else{p.keyPressed=true;}});attach(document,"keyup",function(e){keyPressed=false;if(typeof p.keyPressed!="function"){p.keyPressed=false;}
     130if(p.keyReleased){p.keyReleased();}});function attach(elem,type,fn){if(elem.addEventListener){elem.addEventListener(type,fn,false);}
     131else{elem.attachEvent("on"+type,fn);}}};return p;}})();
  • sagenb/data/sage/js/notebook_lib.js

    diff --git a/sagenb/data/sage/js/notebook_lib.js b/sagenb/data/sage/js/notebook_lib.js
    a b function cell_delete_callback(status, re 
    21712171    }
    21722172}
    21732173
     2174function cell_delete_output(id) {
     2175    /*
     2176    Ask the server to delete the output of a cell.
     2177
     2178    INPUT:
     2179        id -- an integer
     2180    */
     2181    if (active_cell_list.indexOf(id) != -1) {
     2182        // Deleting a running cell causes evaluation to be interrupted.
     2183        // In most cases this avoids potentially tons of confusion.
     2184        async_request(worksheet_command('interrupt'));
     2185    }
     2186    async_request(worksheet_command('delete_cell_output'),
     2187                  cell_delete_output_callback, {id: id});
     2188}
     2189
     2190function cell_delete_output_callback(status, response_text) {
     2191    /*
     2192    Callback for after the server deletes a cell's output.  This
     2193    function removes the cell's output from the DOM.
     2194
     2195    INPUT:
     2196        status -- string ('success' or 'failure')
     2197        response_text -- [command]SEP[id]
     2198               command -- string ('delete_output')
     2199               id -- id of cell whose output is deleted.
     2200    */
     2201    var id;
     2202    if (status !== 'success') {
     2203        // Do not delete output, for some reason.
     2204        return;
     2205    }
     2206    id = response_text.split(SEP)[1];
     2207
     2208    // Delete the output.
     2209    get_element('cell_output_' + id).innerHTML = "";
     2210    get_element('cell_output_nowrap_' + id).innerHTML = "";
     2211    get_element('cell_output_html_' + id).innerHTML = "";
     2212
     2213    // Set the cell to not evaluated.
     2214    cell_set_not_evaluated(id);
     2215}
     2216
     2217
    21742218function debug_input_key_event(e) {
    21752219    /*
    21762220    Handle an input key even when we're in debug mode.
  • sagenb/notebook/twist.py

    diff --git a/sagenb/notebook/twist.py b/sagenb/notebook/twist.py
    a b class Worksheet_delete_cell(WorksheetRes 
    11241124            s = encode_list(['delete', id, prev_id, W.cell_id_list()])
    11251125        return HTMLResponse(stream = s)
    11261126
     1127##############################################################################
     1128# The delete cell output command: /home/worksheet/delete_cell_output?id=number
     1129##############################################################################
     1130class Worksheet_delete_cell_output(WorksheetResource, resource.PostableResource):
     1131    """
     1132    Deletes a cell's output.
     1133    """
     1134    def render(self, ctx):
     1135        id = self.id(ctx)
     1136        self.worksheet.get_cell_with_id(id).delete_output()
     1137        return HTMLResponse(stream = encode_list(['delete_output', id]))
     1138
    11271139
    11281140############################
    11291141# Get the latest update on output appearing