gameplan 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  site
2
- *.rb
2
+ *.rb
3
+ pkg
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Curry - Function currying
3
+ * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
4
+ * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)
5
+ * Date: 10/4/2008
6
+ *
7
+ * @author Ariel Flesler
8
+ * @version 1.0.1
9
+ */
10
+
11
+ function curry( fn ){
12
+ return function(){
13
+ var args = curry.args(arguments),
14
+ master = arguments.callee,
15
+ self = this;
16
+
17
+ return args.length >= fn.length ? fn.apply(self,args) : function(){
18
+ return master.apply( self, args.concat(curry.args(arguments)) );
19
+ };
20
+ };
21
+ };
22
+
23
+ curry.args = function( args ){
24
+ return Array.prototype.slice.call(args);
25
+ };
26
+
27
+ Function.prototype.curry = function(){
28
+ return curry(this);
29
+ };
@@ -0,0 +1,112 @@
1
+ var redraw;
2
+
3
+ window.onload = function() {
4
+ var width = 400;//$('#canvas').width();
5
+ var height = 300;//$('#canvas').height() - 100;
6
+
7
+ /* Showcase of the Bellman-Ford search algorithm finding shortest paths
8
+ from one point to every node */
9
+
10
+ /* We need to write a new node renderer function to display the computed
11
+ distance.
12
+ (the Raphael graph drawing implementation of Dracula can draw this shape,
13
+ please consult the RaphaelJS reference for details http://raphaeljs.com/) */
14
+ var render = function(r, n) {
15
+ frame = r.rect(n.point[0] - 30, n.point[1] - 13, 60, 44);
16
+ frame.attr({
17
+ 'fill': '#feb'/*, r : '12px'*/,
18
+ 'stroke-width' : (n.distance === 0 ? '3px' : '1px')
19
+ });
20
+ /* the Raphael set is obligatory, containing all you want to display */
21
+ var set = r.set()
22
+ .push(
23
+ frame,
24
+ /* custom objects go here */
25
+ r.text(n.point[0], n.point[1] + 10, (n.label || n.id)
26
+ + "\n(" + (n.distance === undefined ? 'Infinity' : n.distance) + ')')
27
+ );
28
+ return set;
29
+ };
30
+
31
+ var g = new Graph();
32
+
33
+ /* modify the edge creation to attach random weights */
34
+ g.edgeFactory.build = function(source, target) {
35
+ var e = jQuery.extend(true, {}, this.template);
36
+ e.source = source;
37
+ e.target = target;
38
+ e.style.label = e.weight = Math.floor(Math.random() * 10) + 1;
39
+ return e;
40
+ }
41
+
42
+ /* creating nodes and passing the new renderer function to overwrite the default one */
43
+ g.addNode('New York', { render : render }); // TODO add currying support for nicer code
44
+ g.addNode('Berlin' , { render : render });
45
+ g.addNode('Tel Aviv', { render : render });
46
+ g.addNode('Tokyo' , { render : render });
47
+ g.addNode('Roma' , { render : render });
48
+ g.addNode('Madrid' , { render : render });
49
+
50
+ /* connections */
51
+ g.addEdge("Tokyo" , "Tel Aviv");
52
+ /*, {weight:9, directed: true, stroke : "#bfa"}*/
53
+ // also supports directed graphs, but currently doesn't look that nice
54
+ g.addEdge("Tokyo" , "New York");
55
+ g.addEdge("Tokyo" , "Berlin");
56
+ g.addEdge("Tel Aviv", "Berlin");
57
+ g.addEdge("Tel Aviv", "New York");
58
+ g.addEdge("Tel Aviv", "Roma");
59
+ g.addEdge("Roma" , "New York");
60
+ g.addEdge("Berlin" , "New York");
61
+ g.addEdge("Madrid" , "New York");
62
+ g.addEdge("Madrid" , "Roma");
63
+ g.addEdge("Madrid" , "Tokyo");
64
+
65
+ /* random edge weights (our undirected graph is modelled as a bidirectional graph) */
66
+ /* for(e in g.edges)
67
+ if(g.edges[e].backedge != undefined) {
68
+ g.edges[e].weight = Math.floor(Math.random()*10) + 1;
69
+ g.edges[e].backedge.weight = g.edges[e].weight;
70
+ }
71
+ */
72
+ /* layout the graph using the Spring layout implementation */
73
+ var layouter = new Graph.Layout.Spring(g);
74
+
75
+ /* draw the graph using the RaphaelJS draw implementation */
76
+
77
+ /* calculating the shortest paths via Bellman Ford */
78
+ //bellman_ford(g, g.nodes["Berlin"]);
79
+
80
+ /* calculating the shortest paths via Dijkstra */
81
+ dijkstra(g, g.nodes["Berlin"]);
82
+
83
+ /* calculating the shortest paths via Floyd-Warshall */
84
+ //floyd_warshall(g, g.nodes['Berlin']);
85
+
86
+
87
+ /* colourising the shortest paths and setting labels */
88
+ for(e in g.edges) {
89
+ if(g.edges[e].target.predecessor === g.edges[e].source
90
+ || g.edges[e].source.predecessor === g.edges[e].target)
91
+ {
92
+ g.edges[e].style.stroke = '#bfa';
93
+ g.edges[e].style.fill = '#56f';
94
+ } else {
95
+ g.edges[e].style.stroke = '#aaa';
96
+ }
97
+ }
98
+
99
+ var renderer = new Graph.Renderer.Raphael('canvas', g, width, height);
100
+
101
+ redraw = function() {
102
+ layouter.layout();
103
+ renderer.draw();
104
+ };
105
+
106
+ /* var pos=0;
107
+ step = function(dir) {
108
+ pos+=dir;
109
+ var renderer = new Graph.Renderer.Raphael('canvas', g.snapshots[pos], width, height);
110
+ renderer.draw();
111
+ };*/
112
+ };
@@ -0,0 +1,616 @@
1
+ /*
2
+ * Various algorithms and data structures, licensed under the MIT-license.
3
+ * (c) 2010 by Johann Philipp Strathausen <strathausen@gmail.com>
4
+ * http://strathausen.eu
5
+ *
6
+ */
7
+
8
+
9
+
10
+ /*
11
+ Bellman-Ford
12
+
13
+ Path-finding algorithm, finds the shortest paths from one node to all nodes.
14
+
15
+
16
+ Complexity
17
+
18
+ O( |E| · |V| ), where E = edges and V = vertices (nodes)
19
+
20
+
21
+ Constraints
22
+
23
+ Can run on graphs with negative edge weights as long as they do not have
24
+ any negative weight cycles.
25
+
26
+ */
27
+ function bellman_ford(g, source) {
28
+ var i, l;
29
+
30
+ /* STEP 1: initialisation */
31
+ for(var n in g.nodes) {
32
+ g.nodes[n].distance = Infinity;
33
+ }
34
+ /* predecessors are implicitly zero */
35
+ source.distance = 0;
36
+
37
+ step("Initially, all distances are infinite and all predecessors are null.");
38
+
39
+ /* STEP 2: relax each edge (this is at the heart of Bellman-Ford) */
40
+ /* repeat this for the number of nodes minus one */
41
+ for(i = 1, l = g.nodes.length; i < l; i++)
42
+ /* for each edge */
43
+ for(var e in g.edges) {
44
+ var edge = g.edges[e];
45
+ if(edge.source.distance + edge.weight < edge.target.distance) {
46
+ step("Relax edge between " + edge.source.id + " and " + edge.target.id + ".");
47
+ edge.target.distance = edge.source.distance + edge.weight;
48
+ edge.target.predecessor = edge.source;
49
+ }
50
+ // Added by Jake Stothard (Needs to be tested)
51
+ //if(!edge.style.directed) {
52
+ //if(edge.target.distance + edge.weight < edge.source.distance) {
53
+ //g.snapShot("Relax edge between " + edge.target.id + " and " + edge.source.id + ".");
54
+ //edge.source.distance = edge.target.distance + edge.weight;
55
+ //edge.source.predecessor = edge.target;
56
+ //}
57
+ //}
58
+ }
59
+ step("Ready.");
60
+
61
+ /* STEP 3: TODO Check for negative cycles */
62
+ /* For now we assume here that the graph does not contain any negative
63
+ weights cycles. (this is left as an excercise to the reader[tm]) */
64
+ }
65
+
66
+
67
+
68
+ /*
69
+ Path-finding algorithm Dijkstra
70
+
71
+ - worst-case running time is O((|E| + |V|) · log |V| ) thus better than
72
+ Bellman-Ford for sparse graphs (with less edges), but cannot handle
73
+ negative edge weights
74
+ */
75
+ function dijkstra(g, source) {
76
+
77
+ /* initially, all distances are infinite and all predecessors are null */
78
+ for(var n in g.nodes)
79
+ g.nodes[n].distance = Infinity;
80
+ /* predecessors are implicitly null */
81
+
82
+ g.snapShot("Initially, all distances are infinite and all predecessors are null.");
83
+
84
+ source.distance = 0;
85
+ /* set of unoptimized nodes, sorted by their distance (but a Fibonacci heap
86
+ would be better) */
87
+ var q = new BinaryMinHeap(g.nodes, "distance");
88
+
89
+ /* pointer to the node in focus */
90
+ var node;
91
+
92
+ /* get the node with the smallest distance
93
+ as long as we have unoptimized nodes. q.min() can have O(log n). */
94
+ while(q.min() != undefined) {
95
+ /* remove the latest */
96
+ node = q.extractMin();
97
+ node.optimized = true;
98
+
99
+ /* no nodes accessible from this one, should not happen */
100
+ if(node.distance == Infinity)
101
+ throw "Orphaned node!";
102
+
103
+ /* for each neighbour of node */
104
+ for(e in node.edges) {
105
+ var other = (node == node.edges[e].target) ? node.edges[e].source : node.edges[e].target;
106
+
107
+ if(other.optimized)
108
+ continue;
109
+
110
+ /* look for an alternative route */
111
+ var alt = node.distance + node.edges[e].weight;
112
+
113
+ /* update distance and route if a better one has been found */
114
+ if (alt < other.distance) {
115
+
116
+ /* update distance of neighbour */
117
+ other.distance = alt;
118
+
119
+ /* update priority queue */
120
+ q.heapify();
121
+
122
+ /* update path */
123
+ other.predecessor = node;
124
+ g.snapShot("Enhancing node.")
125
+ }
126
+ }
127
+ }
128
+ }
129
+
130
+
131
+ /* All-Pairs-Shortest-Paths */
132
+ /* Runs at worst in O(|V|³) and at best in Omega(|V|³) :-)
133
+ complexity Sigma(|V|²) */
134
+ /* This implementation is not yet ready for general use, but works with the
135
+ Dracula graph library. */
136
+ function floyd_warshall(g, source) {
137
+
138
+ /* Step 1: initialising empty path matrix (second dimension is implicit) */
139
+ var path = [];
140
+ var next = [];
141
+ var n = g.nodes.length;
142
+
143
+ /* construct path matrix, initialize with Infinity */
144
+ for(j in g.nodes) {
145
+ path[j] = [];
146
+ next[j] = [];
147
+ for(i in g.nodes)
148
+ path[j][i] = j == i ? 0 : Infinity;
149
+ }
150
+
151
+ /* initialize path with edge weights */
152
+ for(e in g.edges)
153
+ path[g.edges[e].source.id][g.edges[e].target.id] = g.edges[e].weight;
154
+
155
+ /* Note: Usually, the initialisation is done by getting the edge weights
156
+ from a node matrix representation of the graph, not by iterating through
157
+ a list of edges as done here. */
158
+
159
+ /* Step 2: find best distances (the heart of Floyd-Warshall) */
160
+ for(k in g.nodes){
161
+ for(i in g.nodes) {
162
+ for(j in g.nodes)
163
+ if(path[i][j] > path[i][k] + path[k][j]) {
164
+ path[i][j] = path[i][k] + path[k][j];
165
+ /* Step 2.b: remember the path */
166
+ next[i][j] = k;
167
+ }
168
+ }
169
+ }
170
+
171
+ /* Step 3: Path reconstruction, get shortest path */
172
+ function getPath(i, j) {
173
+ if(path[i][j] == Infinity)
174
+ throw "There is no path.";
175
+ var intermediate = next[i][j];
176
+ if(intermediate == undefined)
177
+ return null;
178
+ else
179
+ return getPath(i, intermediate)
180
+ .concat([intermediate])
181
+ .concat(getPath(intermediate, j));
182
+ }
183
+
184
+ /* TODO use the knowledge, e.g. mark path in graph */
185
+ }
186
+
187
+ /*
188
+ Ford-Fulkerson
189
+
190
+ Max-Flow-Min-Cut Algorithm finding the maximum flow through a directed
191
+ graph from source to sink.
192
+
193
+
194
+ Complexity
195
+
196
+ O(E * max(f)), max(f) being the maximum flow
197
+
198
+
199
+ Description
200
+
201
+ As long as there is an open path through the residual graph, send the
202
+ minimum of the residual capacities on the path.
203
+
204
+
205
+ Constraints
206
+
207
+ The algorithm works only if all weights are integers. Otherwise it is
208
+ possible that the Ford–Fulkerson algorithm will not converge to the maximum
209
+ value.
210
+
211
+
212
+ Input
213
+
214
+ g - Graph object
215
+ s - Source ID
216
+ t - Target (sink) ID
217
+
218
+
219
+ Output
220
+
221
+ Maximum flow from Source s to Target t
222
+
223
+ */
224
+ /*
225
+ Edmonds-Karp
226
+
227
+ Max-Flow-Min-Cut Algorithm finding the maximum flow through a directed
228
+ graph from source to sink. An implementation of the Ford-Fulkerson
229
+ algorithm.
230
+
231
+
232
+ Complexity
233
+
234
+ O(|V|*|E|²)
235
+
236
+
237
+ Input
238
+
239
+ g - Graph object (with node and edge lists, capacity is a property of edge)
240
+ s - source ID
241
+ t - sink ID
242
+
243
+ */
244
+ function edmonds_karp(g, s, t) {
245
+
246
+ }
247
+
248
+ /*
249
+ A simple binary min-heap serving as a priority queue
250
+ - takes an array as the input, with elements having a key property
251
+ - elements will look like this:
252
+ {
253
+ key: "... key property ...",
254
+ value: "... element content ..."
255
+ }
256
+ - provides insert(), min(), extractMin() and heapify()
257
+ - example usage (e.g. via the Firebug or Chromium console):
258
+ var x = {foo: 20, hui: "bla"};
259
+ var a = new BinaryMinHeap([x,{foo:3},{foo:10},{foo:20},{foo:30},{foo:6},{foo:1},{foo:3}],"foo");
260
+ console.log(a.extractMin());
261
+ console.log(a.extractMin());
262
+ x.foo = 0; // update key
263
+ a.heapify(); // call this always after having a key updated
264
+ console.log(a.extractMin());
265
+ console.log(a.extractMin());
266
+ - can also be used on a simple array, like [9,7,8,5]
267
+ */
268
+ function BinaryMinHeap(array, key) {
269
+
270
+ /* Binary tree stored in an array, no need for a complicated data structure */
271
+ var tree = [];
272
+
273
+ var key = key || 'key';
274
+
275
+ /* Calculate the index of the parent or a child */
276
+ var parent = function(index) { return Math.floor((index - 1)/2); };
277
+ var right = function(index) { return 2 * index + 2; };
278
+ var left = function(index) { return 2 * index + 1; };
279
+
280
+ /* Helper function to swap elements with their parent
281
+ as long as the parent is bigger */
282
+ function bubble_up(i) {
283
+ var p = parent(i);
284
+ while((p >= 0) && (tree[i][key] < tree[p][key])) {
285
+ /* swap with parent */
286
+ tree[i] = tree.splice(p, 1, tree[i])[0];
287
+ /* go up one level */
288
+ i = p;
289
+ p = parent(i);
290
+ }
291
+ }
292
+
293
+ /* Helper function to swap elements with the smaller of their children
294
+ as long as there is one */
295
+ function bubble_down(i) {
296
+ var l = left(i);
297
+ var r = right(i);
298
+
299
+ /* as long as there are smaller children */
300
+ while(tree[l] && (tree[i][key] > tree[l][key]) || tree[r] && (tree[i][key] > tree[r][key])) {
301
+
302
+ /* find smaller child */
303
+ var child = tree[l] ? tree[r] ? tree[l][key] > tree[r][key] ? r : l : l : l;
304
+
305
+ /* swap with smaller child with current element */
306
+ tree[i] = tree.splice(child, 1, tree[i])[0];
307
+
308
+ /* go up one level */
309
+ i = child;
310
+ l = left(i);
311
+ r = right(i);
312
+ }
313
+ }
314
+
315
+ /* Insert a new element with respect to the heap property
316
+ 1. Insert the element at the end
317
+ 2. Bubble it up until it is smaller than its parent */
318
+ this.insert = function(element) {
319
+
320
+ /* make sure there's a key property */
321
+ (element[key] == undefined) && (element = {key:element});
322
+
323
+ /* insert element at the end */
324
+ tree.push(element);
325
+
326
+ /* bubble up the element */
327
+ bubble_up(tree.length - 1);
328
+ }
329
+
330
+ /* Only show us the minimum */
331
+ this.min = function() {
332
+ return tree.length == 1 ? undefined : tree[0];
333
+ }
334
+
335
+ /* Return and remove the minimum
336
+ 1. Take the root as the minimum that we are looking for
337
+ 2. Move the last element to the root (thereby deleting the root)
338
+ 3. Compare the new root with both of its children, swap it with the
339
+ smaller child and then check again from there (bubble down)
340
+ */
341
+ this.extractMin = function() {
342
+ var result = this.min();
343
+
344
+ /* move the last element to the root or empty the tree completely */
345
+ /* bubble down the new root if necessary */
346
+ (tree.length == 1) && (tree = []) || (tree[0] = tree.pop()) && bubble_down(0);
347
+
348
+ return result;
349
+ }
350
+
351
+ /* currently unused, TODO implement */
352
+ this.changeKey = function(index, key) {
353
+ throw "function not implemented";
354
+ }
355
+
356
+ this.heapify = function() {
357
+ for(var start = Math.floor((tree.length - 2) / 2); start >= 0; start--) {
358
+ bubble_down(start);
359
+ }
360
+ }
361
+
362
+ /* insert the input elements one by one only when we don't have a key property (TODO can be done more elegant) */
363
+ for(i in (array || []))
364
+ this.insert(array[i]);
365
+ }
366
+
367
+
368
+
369
+ /*
370
+ Quick Sort:
371
+ 1. Select some random value from the array, the median.
372
+ 2. Divide the array in three smaller arrays according to the elements
373
+ being less, equal or greater than the median.
374
+ 3. Recursively sort the array containg the elements less than the
375
+ median and the one containing elements greater than the median.
376
+ 4. Concatenate the three arrays (less, equal and greater).
377
+ 5. One or no element is always sorted.
378
+ TODO: This could be implemented more efficiently by using only one array object and several pointers.
379
+ */
380
+ function quickSort(arr) {
381
+ /* recursion anchor: one element is always sorted */
382
+ if(arr.length <= 1) return arr;
383
+ /* randomly selecting some value */
384
+ var median = arr[Math.floor(Math.random() * arr.length)];
385
+ var arr1 = [], arr2 = [], arr3 = [];
386
+ for(var i in arr) {
387
+ arr[i] < median && arr1.push(arr[i]);
388
+ arr[i] == median && arr2.push(arr[i]);
389
+ arr[i] > median && arr3.push(arr[i]);
390
+ }
391
+ /* recursive sorting and assembling final result */
392
+ return quickSort(arr1).concat(arr2).concat(quickSort(arr3));
393
+ }
394
+
395
+ /*
396
+ Selection Sort:
397
+ 1. Select the minimum and remove it from the array
398
+ 2. Sort the rest recursively
399
+ 3. Return the minimum plus the sorted rest
400
+ 4. An array with only one element is already sorted
401
+ */
402
+ function selectionSort(arr) {
403
+ /* recursion anchor: one element is always sorted */
404
+ if(arr.length == 1) return arr;
405
+ var minimum = Infinity;
406
+ var index;
407
+ for(var i in arr) {
408
+ if(arr[i] < minimum) {
409
+ minimum = arr[i];
410
+ index = i; /* remember the minimum index for later removal */
411
+ }
412
+ }
413
+ /* remove the minimum */
414
+ arr.splice(index, 1);
415
+ /* assemble result and sort recursively (could be easily done iteratively as well)*/
416
+ return [minimum].concat(selectionSort(arr));
417
+ }
418
+
419
+ /*
420
+ Merge Sort:
421
+ 1. Cut the array in half
422
+ 2. Sort each of them recursively
423
+ 3. Merge the two sorted arrays
424
+ 4. An array with only one element is considered sorted
425
+
426
+ */
427
+ function mergeSort(arr) {
428
+ /* merges two sorted arrays into one sorted array */
429
+ function merge(a, b) {
430
+ /* result set */
431
+ var c = [];
432
+ /* as long as there are elements in the arrays to be merged */
433
+ while(a.length > 0 || b.length > 0){
434
+ /* are there elements to be merged, if yes, compare them and merge */
435
+ var n = a.length > 0 && b.length > 0 ? a[0] < b[0] ? a.shift() : b.shift() : b.length > 0 ? b.shift() : a.length > 0 ? a.shift() : null;
436
+ /* always push the smaller one onto the result set */
437
+ n != null && c.push(n);
438
+ }
439
+ return c;
440
+ }
441
+ /* this mergeSort implementation cuts the array in half, wich should be fine with randomized arrays, but introduces the risk of a worst-case scenario */
442
+ median = Math.floor(arr.length / 2);
443
+ var part1 = arr.slice(0, median); /* for some reason it doesn't work if inserted directly in the return statement (tried so with firefox) */
444
+ var part2 = arr.slice(median - arr.length);
445
+ return arr.length <= 1 ? arr : merge(
446
+ mergeSort(part1), /* first half */
447
+ mergeSort(part2) /* second half */
448
+ );
449
+ }
450
+
451
+ /* Balanced Red-Black-Tree */
452
+ function RedBlackTree(arr) {
453
+
454
+ }
455
+
456
+ function BTree(arr) {
457
+
458
+ }
459
+
460
+ function NaryTree(n, arr) {
461
+
462
+ }
463
+
464
+ /**
465
+ * Knuth-Morris-Pratt string matching algorithm - finds a pattern in a text.
466
+ * FIXME: Doesn't work correctly yet.
467
+ */
468
+ function kmp(p, t) {
469
+
470
+ /**
471
+ * PREFIX, OVERLAP or FALIURE function for KMP. Computes how many iterations
472
+ * the algorithm can skip after a mismatch.
473
+ *
474
+ * @input p - pattern (string)
475
+ * @result array of skippable iterations
476
+ */
477
+ function prefix(p) {
478
+ /* pi contains the computed skip marks */
479
+ var pi = [0], k = 0;
480
+ for(q = 1; q < p.length; q++) {
481
+ while(k > 0 && (p.charAt(k) != p.charAt(q)))
482
+ k = pi[k-1];
483
+
484
+ (p.charAt(k) == p.charAt(q)) && k++;
485
+
486
+ pi[q] = k;
487
+ }
488
+ return pi;
489
+ }
490
+
491
+ /* The actual KMP algorithm starts here. */
492
+
493
+ var pi = prefix(p), q = 0, result = [];
494
+
495
+ for(var i = 0; i < t.length; i++) {
496
+ /* jump forward as long as the character doesn't match */
497
+ while((q > 0) && (p.charAt(q) != t.charAt(i)))
498
+ q = pi[q];
499
+
500
+ (p.charAt(q) == t.charAt(i)) && q++;
501
+
502
+ (q == p.length) && result.push(i - p.length) && (q = pi[q]);
503
+ }
504
+
505
+ return result;
506
+ }
507
+
508
+ /* step for algorithm visualisation */
509
+ function step(comment, funct) {
510
+ //wait for input
511
+ //display comment (before or after waiting)
512
+ // next.wait();
513
+ /* execute callback function */
514
+ funct();
515
+ }
516
+
517
+ /**
518
+ * Curry - Function currying
519
+ * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
520
+ * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)
521
+ * Date: 10/4/2008
522
+ *
523
+ * @author Ariel Flesler
524
+ * @version 1.0.1
525
+ */
526
+ function curry( fn ){
527
+ return function(){
528
+ var args = curry.args(arguments),
529
+ master = arguments.callee,
530
+ self = this;
531
+
532
+ return args.length >= fn.length ? fn.apply(self,args) : function(){
533
+ return master.apply( self, args.concat(curry.args(arguments)) );
534
+ };
535
+ };
536
+ };
537
+
538
+ curry.args = function( args ){
539
+ return Array.prototype.slice.call(args);
540
+ };
541
+
542
+ Function.prototype.curry = function(){
543
+ return curry(this);
544
+ };
545
+
546
+ /**
547
+ * Node ID Sort
548
+ *
549
+ * Sort a directed graph by the IDs useful for limited circumstances
550
+ * Assumes node.id is an integer. Might change later.
551
+ *
552
+ */
553
+ function nodeid_sort(g) {
554
+ var sorted_list = [];
555
+ for (n in g.nodes)
556
+ sorted_list.unshift(g.nodes[n]);
557
+ sorted_list.sort(function(a,b){ return a.id - b.id; })
558
+ return sorted_list;
559
+ }
560
+
561
+ /**
562
+ * Topological Sort
563
+ *
564
+ * Sort a directed graph based on incoming edges
565
+ *
566
+ * Coded by Jake Stothard
567
+ */
568
+ function topological_sort(g) {
569
+ //Mark nodes as "deleted" instead of actually deleting them
570
+ //That way we don't have to copy g
571
+
572
+ for(i in g.nodes)
573
+ g.nodes[i].deleted = false;
574
+
575
+ var ret = topological_sort_helper(g);
576
+
577
+ //Cleanup: Remove the deleted property
578
+ for(i in g.nodes)
579
+ delete g.nodes[i].deleted
580
+
581
+ return ret;
582
+ }
583
+ function topological_sort_helper(g) {
584
+ //Find node with no incoming edges
585
+ var node;
586
+ for(i in g.nodes) {
587
+ if(g.nodes[i].deleted)
588
+ continue; //Bad style, meh
589
+
590
+ var incoming = false;
591
+ for(j in g.nodes[i].edges) {
592
+ if(g.nodes[i].edges[j].target == g.nodes[i]
593
+ && g.nodes[i].edges[j].source.deleted == false) {
594
+ incoming = true;
595
+ break;
596
+ }
597
+ }
598
+ if(!incoming) {
599
+ node = g.nodes[i];
600
+ break;
601
+ }
602
+ }
603
+
604
+ // Either unsortable or done. Either way, GTFO
605
+ if(node == undefined)
606
+ return [];
607
+
608
+ //"Delete" node from g
609
+ node.deleted = true;
610
+
611
+ var tail = topological_sort_helper(g);
612
+
613
+ tail.unshift(node);
614
+
615
+ return tail;
616
+ }