summaryrefslogtreecommitdiff
path: root/node_modules/webworker-threads
diff options
context:
space:
mode:
authoryo mama <pepper@scannerjammer.com>2015-04-04 01:00:59 -0700
committeryo mama <pepper@scannerjammer.com>2015-04-04 01:00:59 -0700
commitc7c22e3db1c826bcfb2bc66651ec480aae0d4ae0 (patch)
tree8546df448afef40d3814d2581f4dacff7cebb87f /node_modules/webworker-threads
Diffstat (limited to 'node_modules/webworker-threads')
-rw-r--r--node_modules/webworker-threads/.npmignore3
-rw-r--r--node_modules/webworker-threads/AUTHORS5
-rw-r--r--node_modules/webworker-threads/CHANGES.md73
-rw-r--r--node_modules/webworker-threads/LICENSE40
-rw-r--r--node_modules/webworker-threads/README.md465
-rw-r--r--node_modules/webworker-threads/TODO.md6
-rw-r--r--node_modules/webworker-threads/benchmark/b00_fibonacci_server_no_threads.js27
-rw-r--r--node_modules/webworker-threads/benchmark/b01_fibonacci_server_threads.js42
-rw-r--r--node_modules/webworker-threads/benchmark/b02_fibonacci_server_threads_pool.js36
-rw-r--r--node_modules/webworker-threads/benchmark/b03_fibonacci_server_clustered.js39
-rw-r--r--node_modules/webworker-threads/benchmark/b04_only_quick.js14
-rw-r--r--node_modules/webworker-threads/benchmark/doubles.c637
-rw-r--r--node_modules/webworker-threads/benchmark/pi.c155
-rwxr-xr-xnode_modules/webworker-threads/benchmark/pi.js50
-rwxr-xr-xnode_modules/webworker-threads/benchmark/pi.rb39
-rw-r--r--node_modules/webworker-threads/benchmark/pi_precompiled.js50
-rw-r--r--node_modules/webworker-threads/binding.gyp17
-rw-r--r--node_modules/webworker-threads/build/Makefile332
-rw-r--r--node_modules/webworker-threads/build/Release/.deps/Release/WebWorkerThreads.node.d1
-rw-r--r--node_modules/webworker-threads/build/Release/.deps/Release/obj.target/WebWorkerThreads.node.d1
-rw-r--r--node_modules/webworker-threads/build/Release/.deps/Release/obj.target/WebWorkerThreads/src/WebWorkerThreads.o.d41
-rwxr-xr-xnode_modules/webworker-threads/build/Release/WebWorkerThreads.nodebin0 -> 92361 bytes
-rw-r--r--node_modules/webworker-threads/build/Release/linker.lock0
-rwxr-xr-xnode_modules/webworker-threads/build/Release/obj.target/WebWorkerThreads.nodebin0 -> 92361 bytes
-rw-r--r--node_modules/webworker-threads/build/Release/obj.target/WebWorkerThreads/src/WebWorkerThreads.obin0 -> 111912 bytes
-rw-r--r--node_modules/webworker-threads/build/WebWorkerThreads.target.mk128
-rw-r--r--node_modules/webworker-threads/build/binding.Makefile6
-rw-r--r--node_modules/webworker-threads/build/config.gypi114
-rwxr-xr-xnode_modules/webworker-threads/deps/minifier/bin/minifybin0 -> 13488 bytes
-rw-r--r--node_modules/webworker-threads/deps/minifier/src/minify.c432
-rwxr-xr-xnode_modules/webworker-threads/deps/minifier/src/testbin0 -> 8736 bytes
-rw-r--r--node_modules/webworker-threads/deps/minifier/src/test.include.c14
-rw-r--r--node_modules/webworker-threads/deps/minifier/src/test_minifier.c8
-rw-r--r--node_modules/webworker-threads/examples/demo.js31
-rw-r--r--node_modules/webworker-threads/examples/ex01_basic.js63
-rw-r--r--node_modules/webworker-threads/examples/ex01_basic.md94
-rw-r--r--node_modules/webworker-threads/examples/ex02_events.js54
-rw-r--r--node_modules/webworker-threads/examples/ex02_events.md73
-rw-r--r--node_modules/webworker-threads/examples/ex03_ping_pong.js57
-rw-r--r--node_modules/webworker-threads/examples/ex03_ping_pong.md80
-rw-r--r--node_modules/webworker-threads/examples/ex04_main.js40
-rw-r--r--node_modules/webworker-threads/examples/ex04_main.md51
-rw-r--r--node_modules/webworker-threads/examples/ex04_worker.js15
-rw-r--r--node_modules/webworker-threads/examples/ex04_worker.md18
-rw-r--r--node_modules/webworker-threads/examples/ex05_pool.js52
-rw-r--r--node_modules/webworker-threads/examples/ex05_pool.md63
-rw-r--r--node_modules/webworker-threads/examples/ex06_complex.js39
-rw-r--r--node_modules/webworker-threads/examples/ex06_jason.js42
-rw-r--r--node_modules/webworker-threads/examples/ex06_jason.md61
-rwxr-xr-xnode_modules/webworker-threads/examples/fiveThreads.ls15
-rwxr-xr-xnode_modules/webworker-threads/examples/multiThreadEvented.ls15
-rw-r--r--node_modules/webworker-threads/examples/quickIntro_blocking.js13
-rw-r--r--node_modules/webworker-threads/examples/quickIntro_evented_childThreadCode.js7
-rw-r--r--node_modules/webworker-threads/examples/quickIntro_fiveThreads.js21
-rw-r--r--node_modules/webworker-threads/examples/quickIntro_loop.js4
-rw-r--r--node_modules/webworker-threads/examples/quickIntro_multiThread.js16
-rw-r--r--node_modules/webworker-threads/examples/quickIntro_multiThreadEvented.js30
-rw-r--r--node_modules/webworker-threads/examples/quickIntro_oneThread.js17
-rw-r--r--node_modules/webworker-threads/examples/quickIntro_oneThreadEvented.js18
-rw-r--r--node_modules/webworker-threads/package.json70
-rwxr-xr-xnode_modules/webworker-threads/package.ls41
-rw-r--r--node_modules/webworker-threads/src/WebWorkerThreads.cc955
-rw-r--r--node_modules/webworker-threads/src/bson.cc1016
-rw-r--r--node_modules/webworker-threads/src/bson.h277
-rw-r--r--node_modules/webworker-threads/src/createPool.js169
-rw-r--r--node_modules/webworker-threads/src/createPool.js.c1
-rw-r--r--node_modules/webworker-threads/src/createPool.ls107
-rw-r--r--node_modules/webworker-threads/src/events.js53
-rw-r--r--node_modules/webworker-threads/src/events.js.c1
-rw-r--r--node_modules/webworker-threads/src/events.ls29
-rw-r--r--node_modules/webworker-threads/src/jslib.cc177
-rw-r--r--node_modules/webworker-threads/src/load.js19
-rw-r--r--node_modules/webworker-threads/src/load.js.c1
-rw-r--r--node_modules/webworker-threads/src/load.ls9
-rw-r--r--node_modules/webworker-threads/src/queues_a_gogo.cc160
-rw-r--r--node_modules/webworker-threads/src/thread_nextTick.js29
-rw-r--r--node_modules/webworker-threads/src/thread_nextTick.js.c1
-rw-r--r--node_modules/webworker-threads/src/thread_nextTick.ls19
-rw-r--r--node_modules/webworker-threads/src/worker.js46
-rw-r--r--node_modules/webworker-threads/src/worker.js.c1
-rw-r--r--node_modules/webworker-threads/src/worker.ls18
-rwxr-xr-xnode_modules/webworker-threads/test.ls18
-rw-r--r--node_modules/webworker-threads/test/ab.js96
-rw-r--r--node_modules/webworker-threads/test/test00_run_once_and_destroy.js27
-rw-r--r--node_modules/webworker-threads/test/test01_loop_as_fast_as_possible.js84
-rw-r--r--node_modules/webworker-threads/test/test02_loop_as_fast_as_possible.js32
-rw-r--r--node_modules/webworker-threads/test/test03_infiniteLoopFunction.js32
-rw-r--r--node_modules/webworker-threads/test/test04_gc_versus_not_gc.js44
-rw-r--r--node_modules/webworker-threads/test/test05_debugLeaksNoCallbacks.js32
-rw-r--r--node_modules/webworker-threads/test/test06_throw_from_the_thread.js12
-rw-r--r--node_modules/webworker-threads/test/test07_sigkill.js24
-rw-r--r--node_modules/webworker-threads/test/test08_sigkill_leaks.js30
-rw-r--r--node_modules/webworker-threads/test/test09_throw_from_the_callback.js15
-rw-r--r--node_modules/webworker-threads/test/test10_node_nextTick_speed.js35
-rw-r--r--node_modules/webworker-threads/test/test11_multi_callbacks.js38
-rw-r--r--node_modules/webworker-threads/test/test12_precompiled_vs_normal.js42
-rw-r--r--node_modules/webworker-threads/test/test13_thread_nextTick_speed.js31
-rw-r--r--node_modules/webworker-threads/test/test14_emit_once.js20
-rw-r--r--node_modules/webworker-threads/test/test15_emit_ping_pong.js31
-rw-r--r--node_modules/webworker-threads/test/test16_syntax_error_in_the_thread.js13
-rw-r--r--node_modules/webworker-threads/test/test17_pool_pi.js67
-rw-r--r--node_modules/webworker-threads/test/test18_pool_any_as_fast_as_possible.js47
-rw-r--r--node_modules/webworker-threads/test/test19_pool_emit_any_all.js37
-rw-r--r--node_modules/webworker-threads/test/test20_removeAllListeners.js23
-rw-r--r--node_modules/webworker-threads/test/test21_emit_ping_pong_big_string.js32
-rw-r--r--node_modules/webworker-threads/test/test22_create_destroy_loop.js25
-rw-r--r--node_modules/webworker-threads/test/test23_create_destroy_loop.js25
-rw-r--r--node_modules/webworker-threads/test/test24_puts.js17
-rw-r--r--node_modules/webworker-threads/test/test25_delete_puts.js23
-rw-r--r--node_modules/webworker-threads/test/test26_puts_with_many_args.js18
-rw-r--r--node_modules/webworker-threads/test/test27_puts_event_loop.js14
-rw-r--r--node_modules/webworker-threads/test/test28_puts_nextTick_loop.js14
-rw-r--r--node_modules/webworker-threads/test/test29_puts_callback_loop.js14
113 files changed, 7975 insertions, 0 deletions
diff --git a/node_modules/webworker-threads/.npmignore b/node_modules/webworker-threads/.npmignore
new file mode 100644
index 0000000..54f9e46
--- /dev/null
+++ b/node_modules/webworker-threads/.npmignore
@@ -0,0 +1,3 @@
+threads_a_gogo.node
+build
+.lock-wscript
diff --git a/node_modules/webworker-threads/AUTHORS b/node_modules/webworker-threads/AUTHORS
new file mode 100644
index 0000000..4c44003
--- /dev/null
+++ b/node_modules/webworker-threads/AUTHORS
@@ -0,0 +1,5 @@
+//Threads_a_gogo AUTHORS
+
+2011-11-06 Jorge Chamorro Bieling <jorge@jorgechamorro.com>
+2011-11-25 Juan Falgueras Cano <juan.falgueras@gmail.com>
+2012-01-26 Bruno Jouhier <bjouhier@gmail.com>
diff --git a/node_modules/webworker-threads/CHANGES.md b/node_modules/webworker-threads/CHANGES.md
new file mode 100644
index 0000000..c956a56
--- /dev/null
+++ b/node_modules/webworker-threads/CHANGES.md
@@ -0,0 +1,73 @@
+## 0.4.6
+
+### Bug Fixes
+
+* Compatibility with Node.js 0.10.
+
+## 0.4.5
+
+### Bug Fixes
+
+* new Worker("filename.js") was broken on OS X. (@dfellis)
+
+## 0.4.3
+
+### Bug Fixes
+
+* Fix Linux compilation issue introduced in 0.4.1. (@dfellis)
+
+* `importScripts` now checks if the files have been read entirely,
+ instead of (potentially) evaluating part of the file in case
+ of filesystem failure.
+
+## 0.4.2
+
+### Global Worker API
+
+* Set `onmessage = function(event) { ... }` directly now works
+ as specced. (Previously it required `self.onmessage = ...`.)
+
+## 0.4.1
+
+### Global Worker API
+
+* Add `importScripts` for loading on-disk files.
+
+* Add `console.log` and `console.error` from thread.js.
+
+## 0.4.0
+
+* Support for Windows with Node.js 0.9.3+.
+
+## 0.3.2
+
+* Fix BSON building on SunOS.
+
+## 0.3.1
+
+* Switch to BSON instead of JSON for message serialization.
+
+ Note that neither one supports circular structures or
+ native buffer objects yet.
+
+## 0.3.0
+
+* Require Node.js 0.8.
+
+## 0.2.3
+
+* Add SunOS to supported OSs; tested on Linux.
+
+## 0.2.2
+
+* Allow an empty `new Worker()` constructor.
+
+* Update API documentation in README.
+
+## 0.2.1
+
+* Allow any JSON-serializable structures in postMessage/onmessage.
+
+## 0.2.0
+
+* Initial release.
diff --git a/node_modules/webworker-threads/LICENSE b/node_modules/webworker-threads/LICENSE
new file mode 100644
index 0000000..8ae0385
--- /dev/null
+++ b/node_modules/webworker-threads/LICENSE
@@ -0,0 +1,40 @@
+# CC0 1.0 Universal
+
+To the extent possible under law, 唐鳳 has waived all copyright
+and related or neighboring rights to webworker-threads.
+
+This work is published from Taiwan.
+
+http://creativecommons.org/publicdomain/zero/1.0
+
+# This module includes src/bson.cc and src/bson.h, under the Apache License v2.0:
+
+https://github.com/mongodb/js-bson/
+
+Copyright by Christian Amor Kvalheim and other contributors.
+
+# This module includes src/jslib.cc, under the MIT license:
+
+https://github.com/rob333/thread.js
+
+Copyright(C) 2012 by RobertL
+
+# This module is based on Threads_a_gogo, under the MIT license:
+
+https://github.com/xk/node-threads-a-gogo/blob/2665efb9d1d3cc0934ac2f5b6265b37a684d2e07/package.json#L24
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+====
+
+Copyright 2011 Proyectos Equis Ka, s.l., Jorge Chamorro Bieling and other
+contributors. See the AUTHORS file. All rights reserved.
+
+====
+
+This license applies to all parts of Threads_a_gogo that are not externally
+maintained libraries.
diff --git a/node_modules/webworker-threads/README.md b/node_modules/webworker-threads/README.md
new file mode 100644
index 0000000..f46aef4
--- /dev/null
+++ b/node_modules/webworker-threads/README.md
@@ -0,0 +1,465 @@
+# WebWorker Threads
+
+This is based on @xk (jorgechamorro)'s [Threads A GoGo for Node.js](https://github.com/audreyt/node-threads-a-gogo), but with an API conforming to the [Web Worker standard](http://www.w3.org/TR/workers/).
+
+This module provides an asynchronous, evented and/or continuation passing style API for moving blocking/longish CPU-bound tasks out of Node's event loop to JavaScript threads that run in parallel in the background and that use all the available CPU cores automatically; all from within a single Node process.
+
+This module requires Node.js 0.8.0+.
+
+On Unix (including Linux and OS X), this module requires a working node-gyp toolchain, which in turn requires make and C/C++.
+For example, on OS X, you could install XCode from Apple, and then use it to install the command line tools (under Preferences -> Downloads).
+
+On Windows, this module requires Node.js 0.9.3+ and a working [node-gyp toolchain](http://dailyjs.com/2012/05/17/windows-and-node-3/).
+
+## Installing the module
+
+With [npm](http://npmjs.org/):
+
+ npm install webworker-threads
+
+Sample usage (adapted from [MDN](https://developer.mozilla.org/en-US/docs/DOM/Using_web_workers#Passing_data)):
+
+```js
+var Worker = require('webworker-threads').Worker;
+// var w = new Worker('worker.js'); // Standard API
+
+// You may also pass in a function:
+var worker = new Worker(function(){
+ postMessage("I'm working before postMessage('ali').");
+ onmessage = function(event) {
+ postMessage('Hi ' + event.data);
+ self.close();
+ };
+});
+worker.onmessage = function(event) {
+ console.log("Worker said : " + event.data);
+};
+worker.postMessage('ali');
+```
+
+A more involved example in [LiveScript](http://livescript.net/) syntax, with five threads:
+
+```coffee
+{ Worker } = require \webworker-threads
+
+for til 5 => (new Worker ->
+ fibo = (n) -> if n > 1 then fibo(n - 1) + fibo(n - 2) else 1
+ @onmessage = ({ data }) -> postMessage fibo data
+)
+ ..onmessage = ({ data }) ->
+ console.log "[#{ @thread.id }] #data"
+ @postMessage Math.ceil Math.random! * 30
+ ..postMessage Math.ceil Math.random! * 30
+
+do spin = -> process.nextTick spin
+```
+
+## Introduction
+
+After the initialization phase of a Node program, whose purpose is to setup listeners and callbacks to be executed in response to events, the next phase, the proper execution of the program, is orchestrated by the event loop whose duty is to [juggle events, listeners and callbacks quickly and without any hiccups nor interruptions that would ruin its performance](http://youtube.com/v/D0uA_NOb0PE?autoplay=1)
+
+Both the event loop and said listeners and callbacks run sequentially in a single thread of execution, Node's main thread. If any of them ever blocks, nothing else will happen for the duration of the block: no more events will be handled, no more callbacks nor listeners nor timeouts nor nextTick()ed functions will have the chance to run and do their job, because they won't be called by the blocked event loop, and the program will turn sluggish at best, or appear to be frozen and dead at worst.
+
+### What is WebWorker-Threads
+
+`webworker-threads` provides an asynchronous API for CPU-bound tasks that's missing in Node.js:
+
+``` javascript
+var Worker = require('webworker-threads').Worker;
+require('http').createServer(function (req,res) {
+ var fibo = new Worker(function() {
+ function fibo (n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+ }
+ onmessage = function (event) {
+ postMessage(fibo(event.data));
+ }
+ });
+ fibo.onmessage = function (event) {
+ res.end('fib(40) = ' + event.data);
+ };
+ fibo.postMessage(40);
+}).listen(port);
+```
+
+And it won't block the event loop because for each request, the `fibo` worker will run in parallel in a separate background thread.
+
+## API
+
+### Module API
+``` javascript
+var Threads= require('webworker-threads');
+```
+##### .Worker
+`new Threads.Worker( [ file | function ] )` returns a Worker object.
+##### .create()
+`Threads.create( /* no arguments */ )` returns a thread object.
+##### .createPool( numThreads )
+`Threads.createPool( numberOfThreads )` returns a threadPool object.
+
+---
+### Web Worker API
+``` javascript
+var worker= new Threads.Worker('worker.js');
+var worker= new Threads.Worker(function(){ ... });
+var worker= new Threads.Worker();
+```
+##### .postMessage( data )
+`worker.postMessage({ x: 1, y: 2 })` sends a data structure into the worker. The worker can receive it using the `onmessage` handler.
+##### .onmessage
+`worker.onmessage = function (event) { console.log(event.data) };` receives data from the worker's `postMessage` calls.
+##### .terminate()
+`worker.terminate()` terminates the worker thread.
+##### .addEventListener( type, cb )
+`worker.addEventListener('message', callback)` is equivalent to setting `worker.onmesssage = callback`.
+##### .dispatchEvent( event )
+Currently unimplemented.
+##### .removeEventListener( type )
+Currently unimplemented.
+##### .thread
+Returns the underlying `thread` object; see the next section for details.
+Note that this attribute is implementation-specific, and not part of W3C Web Worker API.
+
+---
+### Thread API
+``` javascript
+var thread= Threads.create();
+```
+##### .id
+`thread.id` is a sequential thread serial number.
+##### .load( absolutePath [, cb] )
+`thread.load( absolutePath [, cb] )` reads the file at `absolutePath` and `thread.eval(fileContents, cb)`.
+##### .eval( program [, cb])
+`thread.eval( program [, cb])` converts `program.toString()` and eval()s it in the thread's global context, and (if provided) returns the completion value to `cb(err, completionValue)`.
+##### .on( eventType, listener )
+`thread.on( eventType, listener )` registers the listener `listener(data)` for any events of `eventType` that the thread `thread` may emit.
+##### .once( eventType, listener )
+`thread.once( eventType, listener )` is like `thread.on()`, but the listener will only be called once.
+##### .removeAllListeners( [eventType] )
+`thread.removeAllListeners( [eventType] )` deletes all listeners for all eventTypes. If `eventType` is provided, deletes all listeners only for the event type `eventType`.
+##### .emit( eventType, eventData [, eventData ... ] )
+`thread.emit( eventType, eventData [, eventData ... ] )` emits an event of `eventType` with `eventData` inside the thread `thread`. All its arguments are .toString()ed.
+##### .destroy( /* no arguments */ )
+`thread.destroy( /* no arguments */ )` destroys the thread.
+
+---
+### Thread pool API
+``` javascript
+threadPool= Threads.createPool( numberOfThreads );
+```
+##### .load( absolutePath [, cb] )
+`threadPool.load( absolutePath [, cb] )` runs `thread.load( absolutePath [, cb] )` in all the pool's threads.
+##### .any.eval( program, cb )
+`threadPool.any.eval( program, cb )` is like `thread.eval()`, but in any of the pool's threads.
+##### .any.emit( eventType, eventData [, eventData ... ] )
+`threadPool.any.emit( eventType, eventData [, eventData ... ] )` is like `thread.emit()`, but in any of the pool's threads.
+##### .all.eval( program, cb )
+`threadPool.all.eval( program, cb )` is like `thread.eval()`, but in all the pool's threads.
+##### .all.emit( eventType, eventData [, eventData ... ] )
+`threadPool.all.emit( eventType, eventData [, eventData ... ] )` is like `thread.emit()`, but in all the pool's threads.
+##### .on( eventType, listener )
+`threadPool.on( eventType, listener )` is like `thread.on()`, registers listeners for events from any of the threads in the pool.
+##### .totalThreads()
+`threadPool.totalThreads()` returns the number of threads in this pool: as supplied in `.createPool( number )`
+##### .idleThreads()
+`threadPool.idleThreads()` returns the number of threads in this pool that are currently idle (sleeping)
+##### .pendingJobs()
+`threadPool.pendingJobs()` returns the number of jobs pending.
+##### .destroy( [ rudely ] )
+`threadPool.destroy( [ rudely ] )` waits until `pendingJobs()` is zero and then destroys the pool. If `rudely` is truthy, then it doesn't wait for `pendingJobs === 0`.
+
+---
+### Global Web Worker API
+
+Inside every Worker instance from webworker-threads, there's a global `self` object with these properties:
+
+##### .postMessage( data )
+`postMessage({ x: 1, y: 2 })` sends a data structure back to the main thread.
+##### .onmessage
+`onmessage = function (event) { ... }` receives data from the main thread's `.postMessage` calls.
+##### .close()
+`close()` stops the current thread.
+##### .addEventListener( type, cb )
+`addEventListener('message', callback)` is equivalent to setting `self.onmesssage = callback`.
+##### .dispatchEvent( event )
+`dispatchEvent({ type: 'message', data: data })` is the same as `self.postMessage(data)`.
+##### .removeEventListener( type )
+Currently unimplemented.
+##### .importScripts( file [, file...] )
+`importScripts('a.js', 'b.js')` loads one or more files from the disk and `eval()` them in the worker's instance scope.
+##### .thread
+The underlying `thread` object; see the next section for details.
+Note that this attribute is implementation-specific, and not part of W3C Web Worker API.
+
+---
+### Global Thread API
+
+Inside every thread .create()d by webworker-threads, there's a global `thread` object with these properties:
+##### .id
+`thread.id` is the serial number of this thread
+##### .on( eventType, listener )
+`thread.on( eventType, listener )` is just like `thread.on()` above.
+##### .once( eventType, listener )
+`thread.once( eventType, listener )` is just like `thread.once()` above.
+##### .emit( eventType, eventData [, eventData ... ] )
+`thread.emit( eventType, eventData [, eventData ... ] )` is just like `thread.emit()` above.
+##### .removeAllListeners( [eventType] )
+`thread.removeAllListeners( [eventType] )` is just like `thread.removeAllListeners()` above.
+##### .nextTick( function )
+`thread.nextTick( function )` is like `process.nextTick()`, but much faster.
+
+---
+### Global Helper API
+
+Inside every thread .create()d by webworker-threads, there are some helpers:
+
+##### console.log(arg1 [, arg2 ...])
+Same as `console.log` on the main process.
+
+##### console.error(arg1 [, arg2 ...])
+Same as `console.log`, except it prints to stderr.
+
+##### puts(arg1 [, arg2 ...])
+`puts(arg1 [, arg2 ...])` converts .toString()s and prints its arguments to stdout.
+
+-----------
+WIP WIP WIP
+-----------
+Note that everything below this line is under construction and subject to change.
+-----------
+
+## Examples
+
+**A.-** Here's a program that makes Node's event loop spin freely and as fast as possible: it simply prints a dot to the console in each turn:
+
+ cat examples/quickIntro_loop.js
+
+``` javascript
+(function spinForever () {
+ process.nextTick(spinForever);
+})();
+```
+
+**B.-** Here's another program that adds to the one above a fibonacci(35) call in each turn, a CPU-bound task that takes quite a while to complete and that blocks the event loop making it spin slowly and clumsily. The point is simply to show that you can't put a job like that in the event loop because Node will stop performing properly when its event loop can't spin fast and freely due to a callback/listener/nextTick()ed function that's blocking.
+
+ cat examples/quickIntro_blocking.js
+
+``` javascript
+function fibo (n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+
+(function fiboLoop () {
+ process.stdout.write(fibo(35).toString());
+ process.nextTick(fiboLoop);
+})();
+
+(function spinForever () {
+ process.nextTick(spinForever);
+})();
+```
+
+**C.-** The program below uses `webworker-threads` to run the fibonacci(35) calls in a background thread, so Node's event loop isn't blocked at all and can spin freely again at full speed:
+
+ cat examples/quickIntro_oneThread.js
+
+``` javascript
+function fibo (n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+
+function cb (err, data) {
+ process.stdout.write(data);
+ this.eval('fibo(35)', cb);
+}
+
+var thread= require('webworker-threads').create();
+
+thread.eval(fibo).eval('fibo(35)', cb);
+
+(function spinForever () {
+ process.nextTick(spinForever);
+})();
+```
+
+**D.-** This example is almost identical to the one above, only that it creates 5 threads instead of one, each running a fibonacci(35) in parallel and in parallel too with Node's event loop that keeps spinning happily at full speed in its own thread:
+
+ cat examples/quickIntro_fiveThreads.js
+
+``` javascript
+function fibo (n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+
+function cb (err, data) {
+ process.stdout.write(" ["+ this.id+ "]"+ data);
+ this.eval('fibo(35)', cb);
+}
+
+var Threads= require('webworker-threads');
+
+Threads.create().eval(fibo).eval('fibo(35)', cb);
+Threads.create().eval(fibo).eval('fibo(35)', cb);
+Threads.create().eval(fibo).eval('fibo(35)', cb);
+Threads.create().eval(fibo).eval('fibo(35)', cb);
+Threads.create().eval(fibo).eval('fibo(35)', cb);
+
+(function spinForever () {
+ process.nextTick(spinForever);
+})();
+```
+
+**E.-** The next one asks `webworker-threads` to create a pool of 10 background threads, instead of creating them manually one by one:
+
+ cat examples/multiThread.js
+
+``` javascript
+function fibo (n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+
+var numThreads= 10;
+var threadPool= require('webworker-threads').createPool(numThreads).all.eval(fibo);
+
+threadPool.all.eval('fibo(35)', function cb (err, data) {
+ process.stdout.write(" ["+ this.id+ "]"+ data);
+ this.eval('fibo(35)', cb);
+});
+
+(function spinForever () {
+ process.nextTick(spinForever);
+})();
+```
+
+**F.-** This is a demo of the `webworker-threads` eventEmitter API, using one thread:
+
+ cat examples/quickIntro_oneThreadEvented.js
+
+``` javascript
+var thread= require('webworker-threads').create();
+thread.load(__dirname + '/quickIntro_evented_childThreadCode.js');
+
+/*
+ This is the code that's .load()ed into the child/background thread:
+
+ function fibo (n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+ }
+
+ thread.on('giveMeTheFibo', function onGiveMeTheFibo (data) {
+ this.emit('theFiboIs', fibo(+data)); //Emits 'theFiboIs' in the parent/main thread.
+ });
+
+*/
+
+//Emit 'giveMeTheFibo' in the child/background thread.
+thread.emit('giveMeTheFibo', 35);
+
+//Listener for the 'theFiboIs' events emitted by the child/background thread.
+thread.on('theFiboIs', function cb (data) {
+ process.stdout.write(data);
+ this.emit('giveMeTheFibo', 35);
+});
+
+(function spinForever () {
+ process.nextTick(spinForever);
+})();
+```
+
+**G.-** This is a demo of the `webworker-threads` eventEmitter API, using a pool of threads:
+
+ cat examples/quickIntro_multiThreadEvented.js
+
+``` javascript
+var numThreads= 10;
+var threadPool= require('webworker-threads').createPool(numThreads);
+threadPool.load(__dirname + '/quickIntro_evented_childThreadCode.js');
+
+/*
+ This is the code that's .load()ed into the child/background threads:
+
+ function fibo (n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+ }
+
+ thread.on('giveMeTheFibo', function onGiveMeTheFibo (data) {
+ this.emit('theFiboIs', fibo(+data)); //Emits 'theFiboIs' in the parent/main thread.
+ });
+
+*/
+
+//Emit 'giveMeTheFibo' in all the child/background threads.
+threadPool.all.emit('giveMeTheFibo', 35);
+
+//Listener for the 'theFiboIs' events emitted by the child/background threads.
+threadPool.on('theFiboIs', function cb (data) {
+ process.stdout.write(" ["+ this.id+ "]"+ data);
+ this.emit('giveMeTheFibo', 35);
+});
+
+(function spinForever () {
+ process.nextTick(spinForever);
+})();
+```
+
+## More examples
+
+The `examples` directory contains a few more examples:
+
+* [ex01_basic](https://github.com/xk/node-threads-a-gogo/blob/master/examples/ex01_basic.md): Running a simple function in a thread.
+* [ex02_events](https://github.com/xk/node-threads-a-gogo/blob/master/examples/ex02_events.md): Sending events from a worker thread.
+* [ex03_ping_pong](https://github.com/xk/node-threads-a-gogo/blob/master/examples/ex03_ping_pong.md): Sending events both ways between the main thread and a worker thread.
+* [ex04_main](https://github.com/xk/node-threads-a-gogo/blob/master/examples/ex04_main.md): Loading the worker code from a file.
+* [ex05_pool](https://github.com/xk/node-threads-a-gogo/blob/master/examples/ex05_pool.md): Using the thread pool.
+* [ex06_jason](https://github.com/xk/node-threads-a-gogo/blob/master/examples/ex06_jason.md): Passing complex objects to threads.
+
+## Rationale
+
+[Node.js](http://nodejs.org) is the most awesome, cute and super-sexy piece of free, open source software.
+
+Its event loop can spin as fast and smooth as a turbo, and roughly speaking, **the faster it spins, the more power it delivers**. That's why [@ryah](http://twitter.com/ryah) took great care to ensure that no -possibly slow- I/O operations could ever block it: a pool of background threads (thanks to [Marc Lehmann's libeio library](http://software.schmorp.de/pkg/libeio.html)) handle any blocking I/O calls in the background, in parallel.
+
+In Node it's verboten to write a server like this:
+
+``` javascript
+http.createServer(function (req,res) {
+ res.end( fs.readFileSync(path) );
+}).listen(port);
+```
+Because synchronous I/O calls **block the turbo**, and without proper boost, Node.js begins to stutter and behaves clumsily. To avoid it there's the asynchronous version of `.readFile()`, in continuation passing style, that takes a callback:
+
+``` javascript
+fs.readfile(path, function cb (err, data) { /* ... */ });
+```
+
+It's cool, we love it (*), and there's hundreds of ad hoc built-in functions like this in Node to help us deal with almost any variety of possibly slow, blocking I/O.
+
+### But what's with longish, CPU-bound tasks?
+
+How do you avoid blocking the event loop, when the task at hand isn't I/O bound, and lasts more than a few fractions of a millisecond?
+
+``` javascript
+http.createServer(function cb (req,res) {
+ res.end( fibonacci(40) );
+}).listen(port);
+```
+
+You simply can't, because there's no way... well, there wasn't before `webworker-threads`.
+
+### Why Threads
+
+Threads (kernel threads) are very interesting creatures. They provide:
+
+1.- Parallelism: All the threads run in parallel. On a single core processor, the CPU is switched rapidly back and forth among the threads providing the illusion that the threads are running in parallel, albeit on a slower CPU than the real one. With 10 compute-bound threads in a process, the threads would appear to be running in parallel, each one on a CPU with 1/10th the speed of the real CPU. On a multi-core processor, threads are truly running in parallel, and get time-sliced when the number of threads exceed the number of cores. So with 12 compute bound threads on a quad-core processor each thread will appear to run at 1/3rd of the nominal core speed.
+
+2.- Fairness: No thread is more important than another, cores and CPU slices are fairly distributed among threads by the OS scheduler.
+
+3.- Threads fully exploit all the available CPU resources in your system. On a loaded system running many tasks in many threads, the more cores there are, the faster the threads will complete. Automatically.
+
+4.- The threads of a process share exactly the same address space, that of the process they belong to. Every thread can access every memory address within the process' address space. This is a very appropriate setup when the threads are actually part of the same job and are actively and closely cooperating with each other. Passing a reference to a chunk of data via a pointer is many orders of magnitude faster than transferring a copy of the data via IPC.
+
+### Why not multiple processes.
+
+The "can't block the event loop" problem is inherent to Node's evented model. No matter how many Node processes you have running as a [Node-cluster](http://blog.nodejs.org/2011/10/04/an-easy-way-to-build-scalable-network-programs/), it won't solve its issues with CPU-bound tasks.
+
+Launch a cluster of N Nodes running the example B (`quickIntro_blocking.js`) above, and all you'll get is N -instead of one- Nodes with their event loops blocked and showing a sluggish performance.
diff --git a/node_modules/webworker-threads/TODO.md b/node_modules/webworker-threads/TODO.md
new file mode 100644
index 0000000..0e01a20
--- /dev/null
+++ b/node_modules/webworker-threads/TODO.md
@@ -0,0 +1,6 @@
+* Worker API
+ * `setTimeout` / `clearTimeout` / `setInterval` / `clearInterval`
+ Forwarding to the default implementation (in NativeModule TimerWrap).
+ * `onerror` handler
+ Catch runtime errors; also addEventListener 'error'.
+ * `dispatchEvent`?
diff --git a/node_modules/webworker-threads/benchmark/b00_fibonacci_server_no_threads.js b/node_modules/webworker-threads/benchmark/b00_fibonacci_server_no_threads.js
new file mode 100644
index 0000000..74c74fc
--- /dev/null
+++ b/node_modules/webworker-threads/benchmark/b00_fibonacci_server_no_threads.js
@@ -0,0 +1,27 @@
+
+
+function fib (n) {
+ return (n < 2) ? 1 : fib(n-2)+ fib(n-1);
+}
+
+var i= 0;
+var n= 35;
+function ƒ (req, res) {
+ if ((++i) % 10) {
+ res.end(" QUICK");
+ process.stdout.write(" QUICK");
+ }
+ else {
+ var txt= ' '+ fib(n);
+ res.end(txt);
+ process.stdout.write(txt);
+ }
+}
+
+
+var port= +process.argv[2] || 1234;
+var http= require('http');
+http.globalAgent.maxSockets= 8192+2048;
+http.createServer(ƒ).listen(port);
+console.log('Fibonacci server (NO THREADS) running @port: '+ port);
+
diff --git a/node_modules/webworker-threads/benchmark/b01_fibonacci_server_threads.js b/node_modules/webworker-threads/benchmark/b01_fibonacci_server_threads.js
new file mode 100644
index 0000000..dbedc87
--- /dev/null
+++ b/node_modules/webworker-threads/benchmark/b01_fibonacci_server_threads.js
@@ -0,0 +1,42 @@
+
+
+function fib (n) {
+ return (n < 2) ? 1 : fib(n-2)+ fib(n-1);
+}
+
+//We're going to use n threads
+var numThreads= +process.argv[3] || 1;
+console.log("Using "+ numThreads+ " threads");
+
+var threads= [];
+var round_robin= 0;
+var t= require('threads_a_gogo');
+while (numThreads--) {
+ threads.push(t.create().eval(fib));
+}
+
+var i= 0;
+var n= 35;
+function ƒ (req, res) {
+ if ((++i) % 10) {
+ res.end(" QUICK");
+ process.stdout.write(" QUICK");
+ }
+ else {
+ round_robin= (++round_robin) % threads.length;
+ threads[round_robin].eval('fib('+ n+ ')', function cb (err, data) {
+ if (err) throw err;
+ var txt= ' '+ data;
+ res.end(txt);
+ process.stdout.write(txt);
+ });
+ }
+}
+
+
+var port= +process.argv[2] || 1234;
+var http= require('http');
+http.globalAgent.maxSockets= 8192+2048;
+http.createServer(ƒ).listen(port);
+console.log('Fibonacci server (WITH THREADS) running @port: '+ port);
+
diff --git a/node_modules/webworker-threads/benchmark/b02_fibonacci_server_threads_pool.js b/node_modules/webworker-threads/benchmark/b02_fibonacci_server_threads_pool.js
new file mode 100644
index 0000000..7b2eef5
--- /dev/null
+++ b/node_modules/webworker-threads/benchmark/b02_fibonacci_server_threads_pool.js
@@ -0,0 +1,36 @@
+
+
+function fib (n) {
+ return (n < 2) ? 1 : fib(n-2)+ fib(n-1);
+}
+
+//We're going to use n threads
+var numThreads= +process.argv[3] || 1;
+console.log("Using a POOL of "+ numThreads+ " threads");
+
+var pool= require('threads_a_gogo').createPool(numThreads).all.eval(fib);
+
+var i= 0;
+var n= 35;
+function ƒ (req, res) {
+ if ((++i) % 10) {
+ res.end(" QUICK");
+ process.stdout.write(" QUICK");
+ }
+ else {
+ pool.any.eval('fib('+ n+ ')', function cb (err, data) {
+ if (err) throw err;
+ var txt= ' '+ data;
+ res.end(txt);
+ process.stdout.write(txt);
+ });
+ }
+}
+
+
+var port= +process.argv[2] || 1234;
+var http= require('http');
+http.globalAgent.maxSockets= 8192+2048;
+http.createServer(ƒ).listen(port);
+console.log('Fibonacci server (WITH A THREAD POOL) running @port: '+ port);
+
diff --git a/node_modules/webworker-threads/benchmark/b03_fibonacci_server_clustered.js b/node_modules/webworker-threads/benchmark/b03_fibonacci_server_clustered.js
new file mode 100644
index 0000000..d6609b9
--- /dev/null
+++ b/node_modules/webworker-threads/benchmark/b03_fibonacci_server_clustered.js
@@ -0,0 +1,39 @@
+
+
+function fib (n) {
+ return (n < 2) ? 1 : fib(n-2)+ fib(n-1);
+}
+
+var i= 0;
+var n= 35;
+function ƒ (req, res) {
+ if ((++i) % 10) {
+ res.end(" QUICK");
+ process.stdout.write(" QUICK");
+ }
+ else {
+ var txt= ' '+ fib(n);
+ res.end(txt);
+ process.stdout.write(txt);
+ }
+}
+
+var cluster = require('cluster');
+if (cluster.isMaster) {
+ require('http').globalAgent.maxSockets= 8192+2048;
+ var numCPUs = process.argv[3] || 1;
+ for (var i = 0; i < numCPUs; i++) {
+ cluster.fork();
+ }
+
+ cluster.on('death', function(worker) {
+ console.log('worker ' + worker.pid + ' died');
+ });
+} else {
+ var port= + process.argv[2] || 1234;
+ var http= require('http');
+ http.globalAgent.maxSockets= 8192+2048;
+ http.createServer(ƒ).listen(port);
+ console.log('Fibonacci server (CLUSTERED) listening: ' + port);
+}
+
diff --git a/node_modules/webworker-threads/benchmark/b04_only_quick.js b/node_modules/webworker-threads/benchmark/b04_only_quick.js
new file mode 100644
index 0000000..105ebb2
--- /dev/null
+++ b/node_modules/webworker-threads/benchmark/b04_only_quick.js
@@ -0,0 +1,14 @@
+
+
+function ƒ (req, res) {
+ res.end(" QUICK");
+ process.stdout.write(" QUICK");
+}
+
+
+var port= +process.argv[2] || 1234;
+var http= require('http');
+http.globalAgent.maxSockets= 8192+2048;
+http.createServer(ƒ).listen(port);
+console.log('Fibonacci server (NO THREADS) running @port: '+ port);
+
diff --git a/node_modules/webworker-threads/benchmark/doubles.c b/node_modules/webworker-threads/benchmark/doubles.c
new file mode 100644
index 0000000..3210a51
--- /dev/null
+++ b/node_modules/webworker-threads/benchmark/doubles.c
@@ -0,0 +1,637 @@
+/*
+ simple thread/process benchmark
+
+ Copyright (C) Andrew Tridgell <tridge@samba.org> 2003
+
+ Released under the GNU GPL version 2 or later
+*/
+
+/*
+ this program is designed to test the relative performance of threads/processes
+ for operations typically performed by fileserving applications.
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <dirent.h>
+
+#ifndef NO_THREADS
+#include <pthread.h>
+#endif
+
+/* this contains per-task data */
+static struct {
+ char *dname;
+ char *fname;
+} *id_data;
+
+/* these pipes are used for synchronised startup of the tasks */
+static struct barrier {
+ int fd1[2];
+ int fd2[2];
+} barriers[2];
+
+/* setup a barrier */
+static void barrier_setup(struct barrier *b)
+{
+ if (pipe(b->fd1) != 0 || pipe(b->fd2) != 0) {
+ fprintf(stderr,"Barrier setup failed\n");
+ exit(1);
+ }
+}
+
+/* cleanup the barrier pipes */
+static void barrier_cleanup(struct barrier *b)
+{
+ close(b->fd1[0]);
+ close(b->fd1[1]);
+ close(b->fd2[0]);
+ close(b->fd2[1]);
+}
+
+/* wait for the parent to signal startup */
+static void barrier_wait(struct barrier *b)
+{
+ char c = 0;
+
+ if (write(b->fd1[1], &c, 1) != 1 ||
+ read(b->fd2[0], &c, 1) != 1) {
+ fprintf(stderr, "Barrier wait failed\n");
+ exit(1);
+ }
+}
+
+/* synchronise children. Return the amount of time since the last
+ barrier */
+static double barrier_parent(struct barrier *b, int nprocs)
+{
+ char *s = calloc(nprocs, 1);
+ int i, nwritten=0;
+ char c = 0;
+ double t;
+ static struct timeval tp1;
+ struct timeval tp2;
+
+ for (i=0;i<nprocs;i++) {
+ while (read(b->fd1[0], &c, 1) != 1) ;
+ }
+
+ /* putting the timer here prevents problems with the parent getting
+ rescheduled after the write */
+ gettimeofday(&tp2,NULL);
+ t = (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) -
+ (tp1.tv_sec + (tp1.tv_usec*1.0e-6));
+ gettimeofday(&tp1,NULL);
+
+ while (nwritten != nprocs) {
+ int n = write(b->fd2[1], s, nprocs-nwritten);
+ if (n <= 0) {
+ fprintf(stderr, "Barrier parent failed\n");
+ exit(1);
+ }
+ nwritten += n;
+ }
+ free(s);
+ return t;
+}
+
+#ifndef NO_THREADS
+/*
+ create a thread with initial function fn(private)
+*/
+static pthread_t thread_start(void *(*fn)(int), int id)
+{
+ pthread_t thread_id;
+ pthread_attr_t thread_attr;
+ int rc;
+ typedef void *(*thread_fn_t)(void *);
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setdetachstate(&thread_attr, 0);
+ rc = pthread_create(&thread_id, &thread_attr, (thread_fn_t)fn, (void *)(intptr_t)id);
+ pthread_attr_destroy(&thread_attr);
+
+ if (rc != 0) {
+ fprintf(stderr,"Thread create failed for id %d\n", id);
+ exit(1);
+ }
+
+ return thread_id;
+}
+
+/* wait for a thread to exit */
+static int thread_join(pthread_t id)
+{
+ return pthread_join(id, NULL);
+}
+#endif
+
+
+/*
+ create a process with initial function fn(private)
+*/
+static pid_t proc_start(void *(*fn)(int), int id)
+{
+ pid_t pid;
+
+ pid = fork();
+ if (pid == (pid_t)-1) {
+ fprintf(stderr,"Fork failed for id %d\n", id);
+ return pid;
+ }
+ if (pid == 0) {
+ fn(id);
+ exit(0);
+ }
+ return pid;
+}
+
+/* wait for a process to exit */
+static int proc_join(pid_t id)
+{
+ if (waitpid(id, NULL, 0) != id) {
+ return -1;
+ }
+ return 0;
+}
+
+#ifndef NO_THREADS
+/* run a function under a set of threads */
+static double run_threads(int nthreads, void *(*fn)(int ))
+{
+ int i;
+ pthread_t *ids = calloc(sizeof(*ids), nthreads);
+ double t;
+
+ barrier_setup(&barriers[0]);
+ barrier_setup(&barriers[1]);
+
+ for (i=0;i<nthreads;i++) {
+ ids[i] = thread_start(fn, i);
+ }
+
+ barrier_parent(&barriers[0], nthreads);
+ t = barrier_parent(&barriers[1], nthreads);
+
+ for (i=0;i<nthreads;i++) {
+ int rc;
+ rc = thread_join(ids[i]);
+ if (rc != 0) {
+ fprintf(stderr, "Thread %d failed : %s\n", i, strerror(errno));
+ exit(1);
+ }
+ }
+
+ barrier_cleanup(&barriers[0]);
+ barrier_cleanup(&barriers[1]);
+
+ free(ids);
+
+ return t;
+}
+#endif
+
+/* run a function under a set of processes */
+static double run_processes(int nprocs, void *(*fn)(int ))
+{
+ int i;
+ pid_t *ids = calloc(sizeof(*ids), nprocs);
+ double t;
+
+ barrier_setup(&barriers[0]);
+ barrier_setup(&barriers[1]);
+
+ for (i=0;i<nprocs;i++) {
+ ids[i] = proc_start(fn, i);
+ if (ids[i] == (pid_t)-1) {
+ for (i--;i>=0;i--) {
+ kill(ids[i], SIGTERM);
+ }
+ exit(1);
+ }
+ }
+
+ barrier_parent(&barriers[0], nprocs);
+ t = barrier_parent(&barriers[1], nprocs);
+
+ for (i=0;i<nprocs;i++) {
+ int rc;
+ rc = proc_join(ids[i]);
+ if (rc != 0) {
+ fprintf(stderr, "Process %d failed : %s\n", i, strerror(errno));
+ exit(1);
+ }
+ }
+
+ barrier_cleanup(&barriers[0]);
+ barrier_cleanup(&barriers[1]);
+
+ free(ids);
+
+ return t;
+}
+
+
+
+/***********************************************************************
+ a simple malloc speed test using a wide variety of malloc sizes
+************************************************************************/
+static void *test_malloc(int id)
+{
+#define NMALLOCS 200
+ int i, j;
+ void *ptrs[NMALLOCS];
+
+ barrier_wait(&barriers[0]);
+
+ for (j=0;j<500;j++) {
+ for (i=1;i<NMALLOCS;i++) {
+ ptrs[i] = malloc(i*128);
+ if (!ptrs[i]) {
+ printf("malloc(%d) failed!\n", i);
+ exit(1);
+ }
+ }
+ for (i=1;i<NMALLOCS;i++) {
+ free(ptrs[i]);
+ }
+ }
+
+ barrier_wait(&barriers[1]);
+ return NULL;
+}
+
+/***********************************************************************
+ a simple setreuid speed test
+************************************************************************/
+static void *test_setreuid(int id)
+{
+ int i;
+ void *ptrs[NMALLOCS];
+
+ barrier_wait(&barriers[0]);
+ if (getuid() != 0) {
+ if (id == 0) {
+ printf("Skipping setreuid test for non-root user\n");
+ }
+ barrier_wait(&barriers[1]);
+ return NULL;
+ }
+
+
+ for (i=0;i<2000;i++) {
+ if (setreuid(-1, 1) != 0 ||
+ setreuid(-1, 0) != 0) {
+ printf("setreuid failed: %s\n", strerror(errno));
+ barrier_wait(&barriers[1]);
+ return NULL;
+ }
+ }
+
+ barrier_wait(&barriers[1]);
+ return NULL;
+}
+
+
+/***********************************************************************
+ simple read/write testing using /dev/null and /dev/zero
+************************************************************************/
+static void *test_readwrite(int id)
+{
+ int i;
+ int fd_in, fd_out;
+ /* we use less than 1 page to prevent page table games */
+ char buf[32];
+
+ barrier_wait(&barriers[0]);
+
+ fd_in = open("/dev/zero", O_RDONLY);
+ fd_out = open("/dev/null", O_WRONLY);
+ if (fd_in == -1 || fd_out == -1) {
+ fprintf(stderr,"Failed to open /dev/zero or /dev/null\n");
+ exit(1);
+ }
+
+ for (i=0;i<100000;i++) {
+ if (read(fd_in, buf, sizeof(buf)) != sizeof(buf) ||
+ write(fd_out, buf, sizeof(buf)) != sizeof(buf)) {
+ fprintf(stderr,"IO failed at loop %d\n", i);
+ exit(1);
+ }
+ }
+
+ close(fd_in);
+ close(fd_out);
+
+ barrier_wait(&barriers[1]);
+
+ return NULL;
+}
+
+
+/***********************************************************************
+test stat() operations
+************************************************************************/
+static void *test_stat(int id)
+{
+ int i;
+
+ barrier_wait(&barriers[0]);
+
+ for (i=0;i<30000;i++) {
+ struct stat st;
+ if (stat(id_data[id].dname, &st) != 0) goto failed;
+ if (stat(id_data[id].fname, &st) == 0) goto failed;
+ }
+
+ barrier_wait(&barriers[1]);
+
+ return NULL;
+
+failed:
+ fprintf(stderr,"stat failed\n");
+ exit(1);
+}
+
+/***********************************************************************
+test fstat() operations
+************************************************************************/
+static void *test_fstat(int id)
+{
+ int i, fd;
+
+ barrier_wait(&barriers[0]);
+
+ fd = open(id_data[id].fname, O_RDWR|O_CREAT, 0600);
+ if (fd == -1) goto failed;
+
+ for (i=0;i<1000000;i++) {
+ struct stat st;
+ if (fstat(fd, &st) != 0) goto failed;
+ }
+
+ close(fd);
+ unlink(id_data[id].fname);
+
+ barrier_wait(&barriers[1]);
+
+ return NULL;
+
+failed:
+ fprintf(stderr,"fstat failed\n");
+ exit(1);
+}
+
+/***********************************************************************
+test directory operations
+************************************************************************/
+static void *test_dir(int id)
+{
+ int i;
+
+ barrier_wait(&barriers[0]);
+
+ for (i=0;i<2000;i++) {
+ DIR *d = opendir(id_data[id].dname);
+ if (!d) goto failed;
+ while (readdir(d)) {} ;
+ closedir(d);
+ }
+
+ barrier_wait(&barriers[1]);
+ return NULL;
+
+failed:
+ fprintf(stderr,"dir failed\n");
+ exit(1);
+}
+
+/***********************************************************************
+test directory operations
+************************************************************************/
+static void *test_dirsingle(int id)
+{
+ int i;
+
+ barrier_wait(&barriers[0]);
+
+ for (i=0;i<2000;i++) {
+ DIR *d = opendir(".");
+ if (!d) goto failed;
+ while (readdir(d)) {} ;
+ closedir(d);
+ }
+
+ barrier_wait(&barriers[1]);
+ return NULL;
+
+failed:
+ fprintf(stderr,"dirsingle failed\n");
+ exit(1);
+}
+
+
+/***********************************************************************
+test create/unlink operations
+************************************************************************/
+static void *test_create(int id)
+{
+ int i;
+
+ barrier_wait(&barriers[0]);
+
+ for (i=0;i<3000;i++) {
+ int fd;
+ fd = open(id_data[id].fname, O_CREAT|O_TRUNC|O_RDWR, 0666);
+ if (fd == -1) goto failed;
+ if (open(id_data[id].fname, O_CREAT|O_TRUNC|O_RDWR|O_EXCL, 0666) != -1) goto failed;
+ close(fd);
+ if (unlink(id_data[id].fname) != 0) goto failed;
+ }
+
+ barrier_wait(&barriers[1]);
+ return NULL;
+
+failed:
+ fprintf(stderr,"create failed\n");
+ exit(1);
+}
+
+
+/***********************************************************************
+test fcntl lock operations
+************************************************************************/
+static void *test_lock(int id)
+{
+ int i;
+ int fd;
+
+ barrier_wait(&barriers[0]);
+
+ fd = open(id_data[id].fname, O_CREAT|O_RDWR, 0666);
+ if (fd == -1) goto failed;
+ unlink(id_data[id].fname);
+
+ for (i=0;i<20000;i++) {
+ struct flock lock;
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = (id*100) + (i%100);
+ lock.l_len = 1;
+ lock.l_pid = 0;
+
+ if (fcntl(fd,F_SETLK,&lock) != 0) goto failed;
+
+ lock.l_type = F_UNLCK;
+
+ if (fcntl(fd,F_SETLK,&lock) != 0) goto failed;
+ }
+
+ close(fd);
+
+ barrier_wait(&barriers[1]);
+ return NULL;
+
+failed:
+ fprintf(stderr,"lock failed\n");
+ exit(1);
+}
+
+/***********************************************************************
+do nothing!
+************************************************************************/
+static void *test_noop(int id)
+{
+ barrier_wait(&barriers[0]);
+ barrier_wait(&barriers[1]);
+ return NULL;
+}
+
+
+/*
+ show the average and range of a set of results
+*/
+static void show_result(const char *name, double *t, int nrepeats)
+{
+ double mint, maxt, total;
+ int i;
+ total = mint = maxt = t[0];
+ for (i=1;i<nrepeats;i++) {
+ if (t[i] < mint) mint = t[i];
+ if (t[i] > maxt) maxt = t[i];
+ total += t[i];
+ }
+ printf("%s %5.2f +/- %.2f seconds\n", name, total/nrepeats, (maxt-mint)/2);
+}
+
+
+/* lock a byte range in a open file */
+int main(int argc, char *argv[])
+{
+ int nprocs, i;
+ char *tname = "ALL";
+#define NREPEATS 10
+ struct {
+ const char *name;
+ void *(*fn)(int );
+ } tests[] = {
+ {"noop", test_noop},
+ {"malloc", test_malloc},
+ {"setreuid", test_setreuid},
+ {"readwrite", test_readwrite},
+ {"stat", test_stat},
+ {"fstat", test_fstat},
+ {"dir", test_dir},
+ {"dirsingle", test_dirsingle},
+ {"create", test_create},
+ {"lock", test_lock},
+ {NULL, NULL}
+ };
+
+ if (argc <= 1) {
+ printf("thread_perf NPROCS\n");
+ exit(1);
+ }
+
+ nprocs = atoi(argv[1]);
+
+ if (argc > 2) {
+ tname = argv[2];
+ }
+
+ id_data = calloc(nprocs, sizeof(*id_data));
+ if (!id_data) {
+ exit(1);
+ }
+
+#ifndef NO_THREADS
+ printf("NOTE! for accurate process results please compile with -DNO_THREADS and don't link to -lpthread\n\n");
+#endif
+
+ for (i=0;i<nprocs;i++) {
+ char s[30];
+ sprintf(s, "testd_%d", i);
+ id_data[i].dname = strdup(s);
+
+ sprintf(s, "%s/test.dat", id_data[i].dname);
+ id_data[i].fname = strdup(s);
+
+ rmdir(id_data[i].dname);
+ if (mkdir(id_data[i].dname, 0777) != 0) {
+ fprintf(stderr, "Failed to create %s\n", id_data[i].dname);
+ exit(1);
+ }
+
+ unlink(id_data[i].fname);
+ }
+
+ for (i=0;tests[i].name;i++) {
+ double t_threads[NREPEATS];
+ double t_processes[NREPEATS];
+ int j;
+
+ if (strcasecmp(tname, "ALL") && strcasecmp(tests[i].name, tname)) {
+ continue;
+ }
+
+ printf("Running test '%s' with %d tasks\n", tests[i].name, nprocs);
+
+ for (j=0;j<NREPEATS;j++) {
+#ifndef NO_THREADS
+ t_threads[j] = run_threads(nprocs, tests[i].fn);
+#endif
+ t_processes[j] = run_processes(nprocs, tests[i].fn);
+ }
+#ifndef NO_THREADS
+ show_result("Threads ", t_threads, NREPEATS);
+#endif
+ show_result("Processes", t_processes, NREPEATS);
+
+ printf("\n");
+ fflush(stdout);
+ }
+
+ for (i=0;i<nprocs;i++) {
+ if (rmdir(id_data[i].dname) != 0) {
+ fprintf(stderr, "Failed to delete %s\n", id_data[i].dname);
+ exit(1);
+ }
+ }
+
+ for (i=0;i<nprocs;i++) {
+ free(id_data[i].dname);
+ free(id_data[i].fname);
+ }
+ free(id_data);
+
+ return 0;
+} \ No newline at end of file
diff --git a/node_modules/webworker-threads/benchmark/pi.c b/node_modules/webworker-threads/benchmark/pi.c
new file mode 100644
index 0000000..601fe49
--- /dev/null
+++ b/node_modules/webworker-threads/benchmark/pi.c
@@ -0,0 +1,155 @@
+/*
+
+To run this:
+$ gcc pi.c -pthread -o pi
+./pi
+
+*/
+
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/uio.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/signal.h>
+#include <sys/wait.h>
+
+#define kPI 5e7
+
+typedef struct {
+ int id;
+ pid_t pid;
+ pthread_t thread;
+} threadData;
+
+
+
+
+struct timeval t0;
+void timer_start () {
+ gettimeofday(&t0, NULL);
+}
+
+double timer_end () {
+ struct timeval t1;
+ gettimeofday(&t1, NULL);
+ return (double) (((double)t1.tv_sec)+ ((double)t1.tv_usec*1.0e-6))- (((double)t0.tv_sec)+ ((double)t0.tv_usec*1.0e-6));
+}
+
+
+
+
+double pi (double n) {
+ double pi= 0;
+ double num= 4;
+ double den= 1;
+ int plus= 1;
+
+ while (den < n) {
+ if (plus) {
+ pi+= num/den;
+ plus= 0;
+ }
+ else {
+ pi-= num/den;
+ plus= 1;
+ }
+ den+= 2;
+ }
+ return pi;
+}
+
+
+
+
+void* thread_proc (void* arg) {
+ fprintf(stdout, "%.16f -> TID[%d]\n", pi(kPI), ((threadData*) arg)->id);
+ return NULL;
+}
+
+
+
+
+int main (int argc, char *argv[]) {
+
+ double tThreads= 0, tProcs= 0;
+ int numThreads= (argc > 1) ? atoi(argv[1]): 33;
+ threadData* threads= (threadData*) malloc(numThreads* sizeof(threadData));
+
+
+
+ // USING PROCESSES
+
+ fprintf(stdout, "\n**** Using %d processes\n", numThreads);
+
+ timer_start();
+
+ {
+ pid_t pid;
+ int i= numThreads;
+ while (i--) {
+ threads[i].id= numThreads- i;
+ threads[i].pid= pid= fork();
+ if (!pid) {
+ //child
+ fprintf(stdout, "%.16f -> PID[%d]\n", pi(kPI), threads[i].id);
+ exit(0);
+ }
+ else if (pid < 0) {
+ fprintf(stdout, "**** Error: fork(): -1\n");
+ while (++i < numThreads) {
+ kill(threads[i].pid, SIGKILL);
+ }
+ exit(-1);
+ }
+ }
+
+ i= numThreads;
+ while (i--) {
+ waitpid(WAIT_ANY, NULL, 0);
+ }
+ }
+
+ tProcs= timer_end();
+
+
+
+
+ // USING THREADS
+
+ fprintf(stdout, "\n**** Using %d threads\n", numThreads);
+
+ timer_start();
+
+ {
+ int i= numThreads;
+ while (i--) {
+ threads[i].id= numThreads- i;
+ pthread_create(&threads[i].thread, NULL, thread_proc, &threads[i]);
+ }
+
+ i= numThreads;
+ while (i--) {
+ pthread_join(threads[i].thread, NULL);
+ }
+ }
+
+ tThreads= timer_end();
+
+
+ fprintf(stdout, "\n*** Procesos:\n");
+ fprintf(stdout, "Tiempo total (ms) -> %.0f\n", tProcs*1e3);
+ fprintf(stdout, "Procesos por segundo -> %.1f\n", (double)(numThreads/tProcs));
+ fprintf(stdout, "Total de procesos ejecutadas -> %d\n", numThreads);
+
+ fprintf(stdout, "\n*** Threads:\n");
+ fprintf(stdout, "Tiempo total (ms) -> %.0f\n", tThreads*1e3);
+ fprintf(stdout, "Threads por segundo -> %.1f\n", (double)(numThreads/tThreads));
+ fprintf(stdout, "Total de threads ejecutadas -> %d\n", numThreads);
+
+ fprintf(stdout, "\nRatio t_Threads/t_Procesos -> %.4f\n", (double)(tThreads/tProcs));
+ free(threads);
+}
diff --git a/node_modules/webworker-threads/benchmark/pi.js b/node_modules/webworker-threads/benchmark/pi.js
new file mode 100755
index 0000000..fe30668
--- /dev/null
+++ b/node_modules/webworker-threads/benchmark/pi.js
@@ -0,0 +1,50 @@
+
+
+var Threads= require('threads_a_gogo');
+
+
+function cb (err, msg) {
+ this.destroy();
+ ++i;
+ process.stdout.write('\n'+ msg + ' -> '+ this.id);
+}
+
+function pi () {
+ var π= 0;
+ var num= 4;
+ var den= 1;
+ var plus= true;
+
+ while (den < 5e7) {
+ if (plus) {
+ π+= num/den;
+ plus= false;
+ }
+ else {
+ π-= num/den;
+ plus= true;
+ }
+ den+= 2;
+ }
+ return π;
+}
+
+
+var i= +process.argv[2] || 1;
+console.log('Using '+ i+ ' threads');
+
+
+var t= Date.now();
+while (i--) {
+ Threads.create().eval('('+ pi+ ')()', cb);
+}
+
+
+i= 0;
+process.on('exit', function () {
+ t= Date.now()- t;
+ var tps= (i*1e3/t).toFixed(1);
+ console.log('\nTiempo total (ms) -> '+ t);
+ console.log('Threads por segundo -> '+ tps);
+ console.log('Total de threads ejecutadas -> '+ i);
+});
diff --git a/node_modules/webworker-threads/benchmark/pi.rb b/node_modules/webworker-threads/benchmark/pi.rb
new file mode 100755
index 0000000..5f85965
--- /dev/null
+++ b/node_modules/webworker-threads/benchmark/pi.rb
@@ -0,0 +1,39 @@
+#!/usr/bin/env ruby
+
+def pi(i)
+ pi= 0
+ num= 4.0
+ den= 1
+ plus= true
+
+ while den < 5e7
+ if plus
+ pi+= num/den
+ plus= false
+ else
+ pi-= num/den
+ plus= true
+ end
+ den+= 2
+ end
+ puts "#{pi} -> #{i}"
+end
+
+threads=[]
+count=ARGV.shift || 1
+puts "Using #{count} threads"
+
+t= Time.new
+count.to_i.times do |i|
+ threads << Thread.new{pi(i)}
+end
+
+threads.each do |j|
+ j.join
+end
+
+t= (Time.new- t)* 1e3
+tps= Integer(count) * 1e3 / t
+puts "\nTiempo total (ms) -> %.0f" % t
+puts "Threads por segundo -> %.1f" % tps
+puts "Total de threads ejecutadas -> #{count}"
diff --git a/node_modules/webworker-threads/benchmark/pi_precompiled.js b/node_modules/webworker-threads/benchmark/pi_precompiled.js
new file mode 100644
index 0000000..7139ac1
--- /dev/null
+++ b/node_modules/webworker-threads/benchmark/pi_precompiled.js
@@ -0,0 +1,50 @@
+
+
+var Threads= require('threads_a_gogo');
+
+
+function cb (err, msg) {
+ this.destroy();
+ ++i;
+ process.stdout.write('\n'+ msg + ' -> '+ this.id);
+}
+
+function pi () {
+ var π= 0;
+ var num= 4;
+ var den= 1;
+ var plus= true;
+
+ while (den < 1e7) {
+ if (plus) {
+ π+= num/den;
+ plus= false;
+ }
+ else {
+ π-= num/den;
+ plus= true;
+ }
+ den+= 2;
+ }
+ return π;
+}
+
+
+var i= +process.argv[2] || 1;
+console.log('Using '+ i+ ' threads');
+
+var precompiled= Threads.preCompile('('+ pi+ ')()');
+var t= Date.now();
+while (i--) {
+ Threads.create().eval(precompiled, cb);
+}
+
+
+i= 0;
+process.on('exit', function () {
+ t= Date.now()- t;
+ var tps= (i*1e3/t).toFixed(1);
+ console.log('\nTiempo total (ms) -> '+ t);
+ console.log('Threads por segundo -> '+ tps);
+ console.log('Total de threads ejecutadas -> '+ i);
+});
diff --git a/node_modules/webworker-threads/binding.gyp b/node_modules/webworker-threads/binding.gyp
new file mode 100644
index 0000000..fcd23db
--- /dev/null
+++ b/node_modules/webworker-threads/binding.gyp
@@ -0,0 +1,17 @@
+{
+ 'targets': [
+ {
+ 'target_name': 'WebWorkerThreads',
+ 'sources': [ 'src/WebWorkerThreads.cc' ],
+ 'cflags!': [ '-fno-exceptions' ],
+ 'cflags_cc!': [ '-fno-exceptions' ],
+ 'conditions': [
+ ['OS=="mac"', {
+ 'xcode_settings': {
+ 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES'
+ }
+ }]
+ ]
+ }
+ ]
+}
diff --git a/node_modules/webworker-threads/build/Makefile b/node_modules/webworker-threads/build/Makefile
new file mode 100644
index 0000000..7f64210
--- /dev/null
+++ b/node_modules/webworker-threads/build/Makefile
@@ -0,0 +1,332 @@
+# We borrow heavily from the kernel build setup, though we are simpler since
+# we don't have Kconfig tweaking settings on us.
+
+# The implicit make rules have it looking for RCS files, among other things.
+# We instead explicitly write all the rules we care about.
+# It's even quicker (saves ~200ms) to pass -r on the command line.
+MAKEFLAGS=-r
+
+# The source directory tree.
+srcdir := ..
+abs_srcdir := $(abspath $(srcdir))
+
+# The name of the builddir.
+builddir_name ?= .
+
+# The V=1 flag on command line makes us verbosely print command lines.
+ifdef V
+ quiet=
+else
+ quiet=quiet_
+endif
+
+# Specify BUILDTYPE=Release on the command line for a release build.
+BUILDTYPE ?= Release
+
+# Directory all our build output goes into.
+# Note that this must be two directories beneath src/ for unit tests to pass,
+# as they reach into the src/ directory for data with relative paths.
+builddir ?= $(builddir_name)/$(BUILDTYPE)
+abs_builddir := $(abspath $(builddir))
+depsdir := $(builddir)/.deps
+
+# Object output directory.
+obj := $(builddir)/obj
+abs_obj := $(abspath $(obj))
+
+# We build up a list of every single one of the targets so we can slurp in the
+# generated dependency rule Makefiles in one pass.
+all_deps :=
+
+
+
+# C++ apps need to be linked with g++.
+#
+# Note: flock is used to seralize linking. Linking is a memory-intensive
+# process so running parallel links can often lead to thrashing. To disable
+# the serialization, override LINK via an envrionment variable as follows:
+#
+# export LINK=g++
+#
+# This will allow make to invoke N linker processes as specified in -jN.
+LINK ?= flock $(builddir)/linker.lock $(CXX.target)
+
+CC.target ?= $(CC)
+CFLAGS.target ?= $(CFLAGS)
+CXX.target ?= $(CXX)
+CXXFLAGS.target ?= $(CXXFLAGS)
+LINK.target ?= $(LINK)
+LDFLAGS.target ?= $(LDFLAGS)
+AR.target ?= $(AR)
+
+# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
+# to replicate this environment fallback in make as well.
+CC.host ?= gcc
+CFLAGS.host ?=
+CXX.host ?= g++
+CXXFLAGS.host ?=
+LINK.host ?= g++
+LDFLAGS.host ?=
+AR.host ?= ar
+
+# Define a dir function that can handle spaces.
+# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
+# "leading spaces cannot appear in the text of the first argument as written.
+# These characters can be put into the argument value by variable substitution."
+empty :=
+space := $(empty) $(empty)
+
+# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
+replace_spaces = $(subst $(space),?,$1)
+unreplace_spaces = $(subst ?,$(space),$1)
+dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
+
+# Flags to make gcc output dependency info. Note that you need to be
+# careful here to use the flags that ccache and distcc can understand.
+# We write to a dep file on the side first and then rename at the end
+# so we can't end up with a broken dep file.
+depfile = $(depsdir)/$(call replace_spaces,$@).d
+DEPFLAGS = -MMD -MF $(depfile).raw
+
+# We have to fixup the deps output in a few ways.
+# (1) the file output should mention the proper .o file.
+# ccache or distcc lose the path to the target, so we convert a rule of
+# the form:
+# foobar.o: DEP1 DEP2
+# into
+# path/to/foobar.o: DEP1 DEP2
+# (2) we want missing files not to cause us to fail to build.
+# We want to rewrite
+# foobar.o: DEP1 DEP2 \
+# DEP3
+# to
+# DEP1:
+# DEP2:
+# DEP3:
+# so if the files are missing, they're just considered phony rules.
+# We have to do some pretty insane escaping to get those backslashes
+# and dollar signs past make, the shell, and sed at the same time.
+# Doesn't work with spaces, but that's fine: .d files have spaces in
+# their names replaced with other characters.
+define fixup_dep
+# The depfile may not exist if the input file didn't have any #includes.
+touch $(depfile).raw
+# Fixup path as in (1).
+sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
+# Add extra rules as in (2).
+# We remove slashes and replace spaces with new lines;
+# remove blank lines;
+# delete the first line and append a colon to the remaining lines.
+sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
+ grep -v '^$$' |\
+ sed -e 1d -e 's|$$|:|' \
+ >> $(depfile)
+rm $(depfile).raw
+endef
+
+# Command definitions:
+# - cmd_foo is the actual command to run;
+# - quiet_cmd_foo is the brief-output summary of the command.
+
+quiet_cmd_cc = CC($(TOOLSET)) $@
+cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
+
+quiet_cmd_cxx = CXX($(TOOLSET)) $@
+cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
+
+quiet_cmd_touch = TOUCH $@
+cmd_touch = touch $@
+
+quiet_cmd_copy = COPY $@
+# send stderr to /dev/null to ignore messages when linking directories.
+cmd_copy = rm -rf "$@" && cp -af "$<" "$@"
+
+quiet_cmd_alink = AR($(TOOLSET)) $@
+cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
+
+quiet_cmd_alink_thin = AR($(TOOLSET)) $@
+cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^)
+
+# Due to circular dependencies between libraries :(, we wrap the
+# special "figure out circular dependencies" flags around the entire
+# input list during linking.
+quiet_cmd_link = LINK($(TOOLSET)) $@
+cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS)
+
+# We support two kinds of shared objects (.so):
+# 1) shared_library, which is just bundling together many dependent libraries
+# into a link line.
+# 2) loadable_module, which is generating a module intended for dlopen().
+#
+# They differ only slightly:
+# In the former case, we want to package all dependent code into the .so.
+# In the latter case, we want to package just the API exposed by the
+# outermost module.
+# This means shared_library uses --whole-archive, while loadable_module doesn't.
+# (Note that --whole-archive is incompatible with the --start-group used in
+# normal linking.)
+
+# Other shared-object link notes:
+# - Set SONAME to the library filename so our binaries don't reference
+# the local, absolute paths used on the link command-line.
+quiet_cmd_solink = SOLINK($(TOOLSET)) $@
+cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS)
+
+quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
+cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
+
+
+# Define an escape_quotes function to escape single quotes.
+# This allows us to handle quotes properly as long as we always use
+# use single quotes and escape_quotes.
+escape_quotes = $(subst ','\'',$(1))
+# This comment is here just to include a ' to unconfuse syntax highlighting.
+# Define an escape_vars function to escape '$' variable syntax.
+# This allows us to read/write command lines with shell variables (e.g.
+# $LD_LIBRARY_PATH), without triggering make substitution.
+escape_vars = $(subst $$,$$$$,$(1))
+# Helper that expands to a shell command to echo a string exactly as it is in
+# make. This uses printf instead of echo because printf's behaviour with respect
+# to escape sequences is more portable than echo's across different shells
+# (e.g., dash, bash).
+exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
+
+# Helper to compare the command we're about to run against the command
+# we logged the last time we ran the command. Produces an empty
+# string (false) when the commands match.
+# Tricky point: Make has no string-equality test function.
+# The kernel uses the following, but it seems like it would have false
+# positives, where one string reordered its arguments.
+# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
+# $(filter-out $(cmd_$@), $(cmd_$(1))))
+# We instead substitute each for the empty string into the other, and
+# say they're equal if both substitutions produce the empty string.
+# .d files contain ? instead of spaces, take that into account.
+command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
+ $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
+
+# Helper that is non-empty when a prerequisite changes.
+# Normally make does this implicitly, but we force rules to always run
+# so we can check their command lines.
+# $? -- new prerequisites
+# $| -- order-only dependencies
+prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
+
+# Helper that executes all postbuilds until one fails.
+define do_postbuilds
+ @E=0;\
+ for p in $(POSTBUILDS); do\
+ eval $$p;\
+ E=$$?;\
+ if [ $$E -ne 0 ]; then\
+ break;\
+ fi;\
+ done;\
+ if [ $$E -ne 0 ]; then\
+ rm -rf "$@";\
+ exit $$E;\
+ fi
+endef
+
+# do_cmd: run a command via the above cmd_foo names, if necessary.
+# Should always run for a given target to handle command-line changes.
+# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
+# Third argument, if non-zero, makes it do POSTBUILDS processing.
+# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
+# spaces already and dirx strips the ? characters.
+define do_cmd
+$(if $(or $(command_changed),$(prereq_changed)),
+ @$(call exact_echo, $($(quiet)cmd_$(1)))
+ @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
+ $(if $(findstring flock,$(word 1,$(cmd_$1))),
+ @$(cmd_$(1))
+ @echo " $(quiet_cmd_$(1)): Finished",
+ @$(cmd_$(1))
+ )
+ @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
+ @$(if $(2),$(fixup_dep))
+ $(if $(and $(3), $(POSTBUILDS)),
+ $(call do_postbuilds)
+ )
+)
+endef
+
+# Declare the "all" target first so it is the default,
+# even though we don't have the deps yet.
+.PHONY: all
+all:
+
+# make looks for ways to re-generate included makefiles, but in our case, we
+# don't have a direct way. Explicitly telling make that it has nothing to do
+# for them makes it go faster.
+%.d: ;
+
+# Use FORCE_DO_CMD to force a target to run. Should be coupled with
+# do_cmd.
+.PHONY: FORCE_DO_CMD
+FORCE_DO_CMD:
+
+TOOLSET := target
+# Suffix rules, putting all outputs into $(obj).
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+# Try building from generated source, too.
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+
+ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
+ $(findstring $(join ^,$(prefix)),\
+ $(join ^,WebWorkerThreads.target.mk)))),)
+ include WebWorkerThreads.target.mk
+endif
+
+quiet_cmd_regen_makefile = ACTION Regenerating $@
+cmd_regen_makefile = /usr/libexec/openshift/cartridges/c9-0.1/root/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." -I/var/lib/stickshift/521199af5973ca01b600005b/app-root/data/587788/node_modules/webworker-threads/build/config.gypi -I/usr/libexec/openshift/cartridges/c9-0.1/root/lib/node_modules/npm/node_modules/node-gyp/addon.gypi -I/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15" "-Dmodule_root_dir=/var/lib/stickshift/521199af5973ca01b600005b/app-root/data/587788/node_modules/webworker-threads" binding.gyp
+Makefile: $(srcdir)/../../../../../../../openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/common.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp $(srcdir)/../../../../../../../../../usr/libexec/openshift/cartridges/c9-0.1/root/lib/node_modules/npm/node_modules/node-gyp/addon.gypi
+ $(call do_cmd,regen_makefile)
+
+# "all" is a concatenation of the "all" targets from all the included
+# sub-makefiles. This is just here to clarify.
+all:
+
+# Add in dependency-tracking rules. $(all_deps) is the list of every single
+# target in our tree. Only consider the ones with .d (dependency) info:
+d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
+ifneq ($(d_files),)
+ include $(d_files)
+endif
diff --git a/node_modules/webworker-threads/build/Release/.deps/Release/WebWorkerThreads.node.d b/node_modules/webworker-threads/build/Release/.deps/Release/WebWorkerThreads.node.d
new file mode 100644
index 0000000..beba378
--- /dev/null
+++ b/node_modules/webworker-threads/build/Release/.deps/Release/WebWorkerThreads.node.d
@@ -0,0 +1 @@
+cmd_Release/WebWorkerThreads.node := rm -rf "Release/WebWorkerThreads.node" && cp -af "Release/obj.target/WebWorkerThreads.node" "Release/WebWorkerThreads.node"
diff --git a/node_modules/webworker-threads/build/Release/.deps/Release/obj.target/WebWorkerThreads.node.d b/node_modules/webworker-threads/build/Release/.deps/Release/obj.target/WebWorkerThreads.node.d
new file mode 100644
index 0000000..1407ad7
--- /dev/null
+++ b/node_modules/webworker-threads/build/Release/.deps/Release/obj.target/WebWorkerThreads.node.d
@@ -0,0 +1 @@
+cmd_Release/obj.target/WebWorkerThreads.node := flock ./Release/linker.lock g++ -shared -pthread -rdynamic -m64 -Wl,-soname=WebWorkerThreads.node -o Release/obj.target/WebWorkerThreads.node -Wl,--start-group Release/obj.target/WebWorkerThreads/src/WebWorkerThreads.o -Wl,--end-group
diff --git a/node_modules/webworker-threads/build/Release/.deps/Release/obj.target/WebWorkerThreads/src/WebWorkerThreads.o.d b/node_modules/webworker-threads/build/Release/.deps/Release/obj.target/WebWorkerThreads/src/WebWorkerThreads.o.d
new file mode 100644
index 0000000..80bc675
--- /dev/null
+++ b/node_modules/webworker-threads/build/Release/.deps/Release/obj.target/WebWorkerThreads/src/WebWorkerThreads.o.d
@@ -0,0 +1,41 @@
+cmd_Release/obj.target/WebWorkerThreads/src/WebWorkerThreads.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DBUILDING_NODE_EXTENSION' -I/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/src -I/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/deps/uv/include -I/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/deps/v8/include -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-tree-sink -fno-rtti -MMD -MF ./Release/.deps/Release/obj.target/WebWorkerThreads/src/WebWorkerThreads.o.d.raw -c -o Release/obj.target/WebWorkerThreads/src/WebWorkerThreads.o ../src/WebWorkerThreads.cc
+Release/obj.target/WebWorkerThreads/src/WebWorkerThreads.o: \
+ ../src/WebWorkerThreads.cc \
+ /var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/deps/v8/include/v8.h \
+ /var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/deps/v8/include/v8stdint.h \
+ /var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/src/node.h \
+ /var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/deps/uv/include/uv.h \
+ /var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/deps/uv/include/uv-private/uv-unix.h \
+ /var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/deps/uv/include/uv-private/ngx-queue.h \
+ /var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/deps/uv/include/uv-private/uv-linux.h \
+ /var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/src/node_object_wrap.h \
+ /var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/src/node.h \
+ ../src/queues_a_gogo.cc ../src/bson.cc \
+ /var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/src/node_version.h \
+ /var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/src/node_buffer.h \
+ ../src/bson.h \
+ /var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/src/node_object_wrap.h \
+ ../src/jslib.cc ../src/events.js.c ../src/load.js.c \
+ ../src/createPool.js.c ../src/worker.js.c ../src/thread_nextTick.js.c
+../src/WebWorkerThreads.cc:
+/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/deps/v8/include/v8.h:
+/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/deps/v8/include/v8stdint.h:
+/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/src/node.h:
+/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/deps/uv/include/uv.h:
+/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/deps/uv/include/uv-private/uv-unix.h:
+/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/deps/uv/include/uv-private/ngx-queue.h:
+/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/deps/uv/include/uv-private/uv-linux.h:
+/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/src/node_object_wrap.h:
+/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/src/node.h:
+../src/queues_a_gogo.cc:
+../src/bson.cc:
+/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/src/node_version.h:
+/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/src/node_buffer.h:
+../src/bson.h:
+/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/src/node_object_wrap.h:
+../src/jslib.cc:
+../src/events.js.c:
+../src/load.js.c:
+../src/createPool.js.c:
+../src/worker.js.c:
+../src/thread_nextTick.js.c:
diff --git a/node_modules/webworker-threads/build/Release/WebWorkerThreads.node b/node_modules/webworker-threads/build/Release/WebWorkerThreads.node
new file mode 100755
index 0000000..efa129c
--- /dev/null
+++ b/node_modules/webworker-threads/build/Release/WebWorkerThreads.node
Binary files differ
diff --git a/node_modules/webworker-threads/build/Release/linker.lock b/node_modules/webworker-threads/build/Release/linker.lock
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/node_modules/webworker-threads/build/Release/linker.lock
diff --git a/node_modules/webworker-threads/build/Release/obj.target/WebWorkerThreads.node b/node_modules/webworker-threads/build/Release/obj.target/WebWorkerThreads.node
new file mode 100755
index 0000000..efa129c
--- /dev/null
+++ b/node_modules/webworker-threads/build/Release/obj.target/WebWorkerThreads.node
Binary files differ
diff --git a/node_modules/webworker-threads/build/Release/obj.target/WebWorkerThreads/src/WebWorkerThreads.o b/node_modules/webworker-threads/build/Release/obj.target/WebWorkerThreads/src/WebWorkerThreads.o
new file mode 100644
index 0000000..04e3f4c
--- /dev/null
+++ b/node_modules/webworker-threads/build/Release/obj.target/WebWorkerThreads/src/WebWorkerThreads.o
Binary files differ
diff --git a/node_modules/webworker-threads/build/WebWorkerThreads.target.mk b/node_modules/webworker-threads/build/WebWorkerThreads.target.mk
new file mode 100644
index 0000000..882c07e
--- /dev/null
+++ b/node_modules/webworker-threads/build/WebWorkerThreads.target.mk
@@ -0,0 +1,128 @@
+# This file is generated by gyp; do not edit.
+
+TOOLSET := target
+TARGET := WebWorkerThreads
+DEFS_Debug := \
+ '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DBUILDING_NODE_EXTENSION' \
+ '-DDEBUG' \
+ '-D_DEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Debug := \
+ -fPIC \
+ -Wall \
+ -Wextra \
+ -Wno-unused-parameter \
+ -pthread \
+ -m64 \
+ -g \
+ -O0
+
+# Flags passed to only C files.
+CFLAGS_C_Debug :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Debug := \
+ -fno-rtti
+
+INCS_Debug := \
+ -I/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/src \
+ -I/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/deps/uv/include \
+ -I/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/deps/v8/include
+
+DEFS_Release := \
+ '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DBUILDING_NODE_EXTENSION'
+
+# Flags passed to all source files.
+CFLAGS_Release := \
+ -fPIC \
+ -Wall \
+ -Wextra \
+ -Wno-unused-parameter \
+ -pthread \
+ -m64 \
+ -O2 \
+ -fno-strict-aliasing \
+ -fno-tree-vrp \
+ -fno-tree-sink
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release := \
+ -fno-rtti
+
+INCS_Release := \
+ -I/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/src \
+ -I/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/deps/uv/include \
+ -I/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15/deps/v8/include
+
+OBJS := \
+ $(obj).target/$(TARGET)/src/WebWorkerThreads.o
+
+# Add to the list of files we specially track dependencies for.
+all_deps += $(OBJS)
+
+# CFLAGS et al overrides must be target-local.
+# See "Target-specific Variable Values" in the GNU Make manual.
+$(OBJS): TOOLSET := $(TOOLSET)
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+
+# Suffix rules, putting all outputs into $(obj).
+
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+
+# Try building from generated source, too.
+
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+
+# End of this set of suffix rules
+### Rules for final target.
+LDFLAGS_Debug := \
+ -pthread \
+ -rdynamic \
+ -m64
+
+LDFLAGS_Release := \
+ -pthread \
+ -rdynamic \
+ -m64
+
+LIBS :=
+
+$(obj).target/WebWorkerThreads.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
+$(obj).target/WebWorkerThreads.node: LIBS := $(LIBS)
+$(obj).target/WebWorkerThreads.node: TOOLSET := $(TOOLSET)
+$(obj).target/WebWorkerThreads.node: $(OBJS) FORCE_DO_CMD
+ $(call do_cmd,solink_module)
+
+all_deps += $(obj).target/WebWorkerThreads.node
+# Add target alias
+.PHONY: WebWorkerThreads
+WebWorkerThreads: $(builddir)/WebWorkerThreads.node
+
+# Copy this to the executable output path.
+$(builddir)/WebWorkerThreads.node: TOOLSET := $(TOOLSET)
+$(builddir)/WebWorkerThreads.node: $(obj).target/WebWorkerThreads.node FORCE_DO_CMD
+ $(call do_cmd,copy)
+
+all_deps += $(builddir)/WebWorkerThreads.node
+# Short alias for building this executable.
+.PHONY: WebWorkerThreads.node
+WebWorkerThreads.node: $(obj).target/WebWorkerThreads.node $(builddir)/WebWorkerThreads.node
+
+# Add executable to "all" target.
+.PHONY: all
+all: $(builddir)/WebWorkerThreads.node
+
diff --git a/node_modules/webworker-threads/build/binding.Makefile b/node_modules/webworker-threads/build/binding.Makefile
new file mode 100644
index 0000000..50f7621
--- /dev/null
+++ b/node_modules/webworker-threads/build/binding.Makefile
@@ -0,0 +1,6 @@
+# This file is generated by gyp; do not edit.
+
+export builddir_name ?= build/./.
+.PHONY: all
+all:
+ $(MAKE) WebWorkerThreads
diff --git a/node_modules/webworker-threads/build/config.gypi b/node_modules/webworker-threads/build/config.gypi
new file mode 100644
index 0000000..64d8bc5
--- /dev/null
+++ b/node_modules/webworker-threads/build/config.gypi
@@ -0,0 +1,114 @@
+# Do not edit. File was generated by node-gyp's "configure" step
+{
+ "target_defaults": {
+ "cflags": [],
+ "default_configuration": "Release",
+ "defines": [],
+ "include_dirs": [],
+ "libraries": []
+ },
+ "variables": {
+ "clang": 0,
+ "gcc_version": 44,
+ "host_arch": "x64",
+ "node_install_npm": "true",
+ "node_prefix": "",
+ "node_shared_cares": "false",
+ "node_shared_http_parser": "false",
+ "node_shared_libuv": "false",
+ "node_shared_openssl": "false",
+ "node_shared_v8": "false",
+ "node_shared_zlib": "false",
+ "node_tag": "",
+ "node_unsafe_optimizations": 0,
+ "node_use_dtrace": "false",
+ "node_use_etw": "false",
+ "node_use_openssl": "true",
+ "node_use_perfctr": "false",
+ "node_use_systemtap": "false",
+ "python": "/var/lib/stickshift/5169307b5973cafe5600012f/app-root/data/.nix-profile/bin/python",
+ "target_arch": "x64",
+ "v8_enable_gdbjit": 0,
+ "v8_no_strict_aliasing": 1,
+ "v8_use_snapshot": "true",
+ "nodedir": "/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.node-gyp/0.10.15",
+ "copy_dev_lib": "true",
+ "standalone_static_library": 1,
+ "save_dev": "",
+ "viewer": "man",
+ "browser": "",
+ "rollback": "true",
+ "usage": "",
+ "globalignorefile": "/var/lib/stickshift/521199af5973ca01b600005b/app-root/data/etc/npmignore",
+ "shell": "/usr/bin/oo-trap-user",
+ "init_author_url": "",
+ "shrinkwrap": "true",
+ "parseable": "",
+ "userignorefile": "/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.npmignore",
+ "sign_git_tag": "",
+ "init_author_email": "",
+ "cache_max": "null",
+ "long": "",
+ "ignore": "",
+ "npat": "",
+ "fetch_retries": "2",
+ "registry": "https://registry.npmjs.org/",
+ "versions": "",
+ "message": "%s",
+ "globalconfig": "/var/lib/stickshift/521199af5973ca01b600005b/app-root/data/etc/npmrc",
+ "always_auth": "",
+ "cache_lock_retries": "10",
+ "proprietary_attribs": "true",
+ "fetch_retry_mintimeout": "10000",
+ "json": "",
+ "coverage": "",
+ "pre": "",
+ "https_proxy": "",
+ "engine_strict": "",
+ "description": "true",
+ "userconfig": "/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.npmrc",
+ "init_module": "/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.npm-init.js",
+ "npaturl": "http://npat.npmjs.org/",
+ "user": "6841",
+ "node_version": "v0.10.15",
+ "save": "",
+ "editor": "vi",
+ "tag": "latest",
+ "global": "",
+ "username": "",
+ "optional": "true",
+ "force": "",
+ "bin_links": "true",
+ "searchopts": "",
+ "depth": "null",
+ "searchsort": "name",
+ "rebuild_bundle": "true",
+ "yes": "",
+ "unicode": "true",
+ "fetch_retry_maxtimeout": "60000",
+ "strict_ssl": "true",
+ "group": "6841",
+ "fetch_retry_factor": "10",
+ "dev": "",
+ "version": "",
+ "cache_lock_stale": "60000",
+ "cache_min": "10",
+ "searchexclude": "",
+ "cache": "/var/lib/openshift/521199af5973ca01b600005b/app-root/data/.npm",
+ "color": "true",
+ "save_optional": "",
+ "user_agent": "node/v0.10.15 linux x64",
+ "cache_lock_wait": "10000",
+ "production": "",
+ "save_bundle": "",
+ "umask": "18",
+ "init_version": "0.0.0",
+ "init_author_name": "",
+ "git": "/var/lib/stickshift/521199af5973ca01b600005b/app-root/data/bin/git",
+ "unsafe_perm": "true",
+ "tmp": "/tmp/",
+ "onload_script": "",
+ "link": "",
+ "prefix": "/var/lib/stickshift/521199af5973ca01b600005b/app-root/data"
+ }
+}
diff --git a/node_modules/webworker-threads/deps/minifier/bin/minify b/node_modules/webworker-threads/deps/minifier/bin/minify
new file mode 100755
index 0000000..539d559
--- /dev/null
+++ b/node_modules/webworker-threads/deps/minifier/bin/minify
Binary files differ
diff --git a/node_modules/webworker-threads/deps/minifier/src/minify.c b/node_modules/webworker-threads/deps/minifier/src/minify.c
new file mode 100644
index 0000000..37fe385
--- /dev/null
+++ b/node_modules/webworker-threads/deps/minifier/src/minify.c
@@ -0,0 +1,432 @@
+/*
+
+2012-02-20 minify.c basado en jsmin.c, Jorge Chamorro Bieling, Proyectos Equis Ka, s.l.
+
+Minifica un .js, y lo convierte en una sentencia de C que fabrica una
+string de C debidamente acabada en \0, con el nombre que se haya pasado en arg[1],
+lista para ser guardada en un fichero del que se puede hacer un #include "fichero".
+
+
+*/
+
+/* jsmin.c
+2012-01-09
+
+Copyright (c) 2002 Douglas Crockford (www.crockford.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+static int theA;
+static int theB;
+static int theLookahead = EOF;
+static const char* hex= "0123456789abcdef";
+
+/*
+
+static int len;
+static int first;
+#define maxLen 80
+
+static void put_hex (int c) {
+ int lo= c & 0x000f;
+ int hi= (c & 0x00f0) >> 4;
+
+ if (first) {
+ first= 0;
+ fprintf(stdout, " 0x%c%c", hex[hi], hex[lo]);
+ len+= 6;
+ }
+ else {
+ len+= 6;
+ if (len > maxLen) {
+ len= 6;
+ fprintf(stdout, ",\n 0x%c%c", hex[hi], hex[lo]);
+ }
+ else {
+ fprintf(stdout, ", 0x%c%c", hex[hi], hex[lo]);
+ }
+ }
+}
+*/
+
+/*
+static void put_hex (int c) {
+ if (c < ' ') {
+ if (c == '\n') {
+ fprintf(stdout, "\\n");
+ }
+ else if (c == '\t') {
+ fprintf(stdout, "\\t");
+ }
+ else if (c == '\r') {
+ fprintf(stdout, "\\r");
+ }
+ else {
+ int lo= c & 0x000f;
+ int hi= (c & 0x00f0) >> 4;
+
+ fprintf(stdout, "\\x%c%c", hex[hi], hex[lo]);
+ }
+ }
+ else if ((c == '\\') || (c == '"')) {
+ fprintf(stdout, "\\%c", c);
+ }
+ else {
+ putc(c, stdout);
+ }
+}
+*/
+
+/*
+
+static void put_hex (int c) {
+ int lo, hi;
+
+ if (c == '\n') {
+ fprintf(stdout, "\\n");
+ lastCharWasHex= 0;
+ return;
+ }
+
+ if (c == '\r') {
+ fprintf(stdout, "\\r");
+ lastCharWasHex= 0;
+ return;
+ }
+
+ if (c == '\t') {
+ fprintf(stdout, "\\t");
+ lastCharWasHex= 0;
+ return;
+ }
+
+ if ( (c == '"') || (c == '\\') || (c < 32) || (c > 126) ) {
+ goto printHex;
+ }
+
+ if (lastCharWasHex && ( (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (c >= '0' && c <= '9') )) {
+ goto printHex;
+ }
+
+ putc(c, stdout);
+ lastCharWasHex= 0;
+ goto quit;
+
+ printHex:
+ lo= c & 0x000f;
+ hi= (c & 0x00f0) >> 4;
+ fprintf(stdout, "\\x%c%c", hex[hi], hex[lo]);
+ lastCharWasHex= 1;
+
+ quit:
+ return;
+}
+*/
+
+
+static void put_hex (int c) {
+ if (c == '\n') {
+ fputs("\\n", stdout);
+ }
+ else if (c == '\r') {
+ fputs("\\r", stdout);
+ }
+ else if (c == '\t') {
+ fputs("\\t", stdout);
+ }
+ else if (c == ' ') {
+ putc(c, stdout);
+ }
+ else {
+ int lo= c & 0x000f;
+ int hi= (c & 0x00f0) >> 4;
+ fprintf(stdout, "\\x%c%c", hex[hi], hex[lo]);
+ }
+}
+
+
+/* isAlphanum -- return true if the character is a letter, digit, underscore,
+dollar sign, or non-ASCII character.
+*/
+static int isAlphanum (int c) {
+ return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
+ (c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' ||
+ c > 126);
+}
+
+
+/* get -- return the next character from stdin. Watch out for lookahead. If
+the character is a control character, translate it to a space or
+linefeed.
+*/
+
+static int get() {
+ int c = theLookahead;
+ theLookahead = EOF;
+ if (c == EOF) {
+ c = getc(stdin);
+ }
+ if (c >= ' ' || c == '\n' || c == EOF) {
+ return c;
+ }
+ if (c == '\r') {
+ return '\n';
+ }
+ return ' ';
+}
+
+
+/* peek -- get the next character without getting it.
+*/
+
+static int peek () {
+ theLookahead = get();
+ return theLookahead;
+}
+
+
+/* next -- get the next character, excluding comments. peek() is used to see
+if a '/' is followed by a '/' or '*'.
+*/
+
+static int next () {
+ int c = get();
+ if (c == '/') {
+ switch (peek()) {
+ case '/':
+ for (;;) {
+ c = get();
+ if (c <= '\n') {
+ return c;
+ }
+ }
+ case '*':
+ get();
+ for (;;) {
+ switch (get()) {
+ case '*':
+ if (peek() == '/') {
+ get();
+ return ' ';
+ }
+ break;
+ case EOF:
+ fprintf(stderr, "Error: JSMIN Unterminated comment.\n");
+ exit(1);
+ }
+ }
+ default:
+ return c;
+ }
+ }
+ return c;
+}
+
+
+/* action -- do something! What you do is determined by the argument:
+1 Output A. Copy B to A. Get the next B.
+2 Copy B to A. Get the next B. (Delete A).
+3 Get the next B. (Delete B).
+action treats a string as a single character. Wow!
+action recognizes a regular expression if it is preceded by ( or , or =.
+*/
+
+static void action (int d) {
+ switch (d) {
+ case 1:
+ put_hex(theA);
+ case 2:
+ theA = theB;
+ if (theA == '\'' || theA == '"' || theA == '`') {
+ for (;;) {
+ put_hex(theA);
+ theA = get();
+ if (theA == theB) {
+ break;
+ }
+ if (theA == '\\') {
+ put_hex(theA);
+ theA = get();
+ }
+ if (theA == EOF) {
+ fprintf(stderr, "Error: JSMIN unterminated string literal.");
+ exit(1);
+ }
+ }
+ }
+ case 3:
+ theB = next();
+ if (theB == '/' && (theA == '(' || theA == ',' || theA == '=' ||
+ theA == ':' || theA == '[' || theA == '!' ||
+ theA == '&' || theA == '|' || theA == '?' ||
+ theA == '{' || theA == '}' || theA == ';' ||
+ theA == '\n')) {
+ put_hex(theA);
+ put_hex(theB);
+ for (;;) {
+ theA = get();
+ if (theA == '[') {
+ for (;;) {
+ put_hex(theA);
+ theA = get();
+ if (theA == ']') {
+ break;
+ }
+ if (theA == '\\') {
+ put_hex(theA);
+ theA = get();
+ }
+ if (theA == EOF) {
+ fprintf(stderr,
+ "Error: JSMIN unterminated set in Regular Expression literal.\n");
+ exit(1);
+ }
+ }
+ } else if (theA == '/') {
+ break;
+ } else if (theA =='\\') {
+ put_hex(theA);
+ theA = get();
+ }
+ if (theA == EOF) {
+ fprintf(stderr,
+ "Error: JSMIN unterminated Regular Expression literal.\n");
+ exit(1);
+ }
+ put_hex(theA);
+ }
+ theB = next();
+ }
+ }
+ }
+
+
+/* jsmin -- Copy the input to the output, deleting the characters which are
+insignificant to JavaScript. Comments will be removed. Tabs will be
+replaced with spaces. Carriage returns will be replaced with linefeeds.
+Most spaces and linefeeds will be removed.
+*/
+
+static void jsmin() {
+ if (peek() == 0xEF) {
+ get();
+ get();
+ get();
+ }
+ theA = '\n';
+ action(3);
+ while (theA != EOF) {
+ switch (theA) {
+ case ' ':
+ if (isAlphanum(theB)) {
+ action(1);
+ } else {
+ action(2);
+ }
+ break;
+ case '\n':
+ switch (theB) {
+ case '{':
+ case '[':
+ case '(':
+ case '+':
+ case '-':
+ action(1);
+ break;
+ case ' ':
+ action(3);
+ break;
+ default:
+ if (isAlphanum(theB)) {
+ action(1);
+ } else {
+ action(2);
+ }
+ }
+ break;
+ default:
+ switch (theB) {
+ case ' ':
+ if (isAlphanum(theA)) {
+ action(1);
+ break;
+ }
+ action(3);
+ break;
+ case '\n':
+ switch (theA) {
+ case '}':
+ case ']':
+ case ')':
+ case '+':
+ case '-':
+ case '"':
+ case '\'':
+ case '`':
+ action(1);
+ break;
+ default:
+ if (isAlphanum(theA)) {
+ action(1);
+ } else {
+ action(3);
+ }
+ }
+ break;
+ default:
+ action(1);
+ break;
+ }
+ }
+ }
+}
+
+
+/* main -- Output any command line arguments as comments
+and then minify the input.
+*/
+int main (int argc, char* argv[]) {
+ if (argv[1] == NULL) exit(1);
+ fprintf(stdout, "static const char* %s= \"", argv[1]);
+ /*
+ len= 0;
+ first= 1;
+ */
+ if (argv[2] == NULL) {
+ putchar('(');
+ jsmin();
+ puts(")\";");
+ }
+ else if (argv[3] == NULL) {
+ putchar('(');
+ jsmin();
+ puts(")()\";");
+ }
+ else {
+ jsmin();
+ puts("\";");
+ }
+ return 0;
+}
diff --git a/node_modules/webworker-threads/deps/minifier/src/test b/node_modules/webworker-threads/deps/minifier/src/test
new file mode 100755
index 0000000..78ffee7
--- /dev/null
+++ b/node_modules/webworker-threads/deps/minifier/src/test
Binary files differ
diff --git a/node_modules/webworker-threads/deps/minifier/src/test.include.c b/node_modules/webworker-threads/deps/minifier/src/test.include.c
new file mode 100644
index 0000000..b7c3506
--- /dev/null
+++ b/node_modules/webworker-threads/deps/minifier/src/test.include.c
@@ -0,0 +1,14 @@
+static const char* _test= "\n\x28\x66\x75\x6e\x63\x74\x69\x6f\x6e \x6c\x6f\x61\x64\x28\x70\x2c\x63\x62\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x68\x69\x73\x2e\x65\x76\x61\x6c\x28\x72\x65\x71\x75\x69\x72\x65\x28\x27\x66\x73\x27\x29\x2e\x72\x65\x61\x64\x46\x69\x6c\x65\x53\x79\x6e\x63\x28\x70\x29\x2c\x63\x62\x29\x3b\x7d\x29";
+
+/*
+static const char _test[]= {
+ 0x0a, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b,
+ 0x76, 0x61, 0x72, 0x20, 0x72, 0x66, 0x73, 0x3d, 0x72, 0x65, 0x71, 0x75, 0x69,
+ 0x72, 0x65, 0x28, 0x27, 0x66, 0x73, 0x27, 0x29, 0x2e, 0x72, 0x65, 0x61, 0x64,
+ 0x46, 0x69, 0x6c, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x3b, 0x72, 0x65, 0x74, 0x75,
+ 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c,
+ 0x6f, 0x61, 0x64, 0x28, 0x70, 0x61, 0x74, 0x68, 0x2c, 0x63, 0x62, 0x29, 0x7b,
+ 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x65,
+ 0x76, 0x61, 0x6c, 0x28, 0x72, 0x66, 0x73, 0x28, 0x70, 0x61, 0x74, 0x68, 0x29,
+ 0x2c, 0x63, 0x62, 0x29, 0x3b, 0x7d, 0x3b, 0x7d, 0x29, 0x28, 0x29, 0x00 };
+*/ \ No newline at end of file
diff --git a/node_modules/webworker-threads/deps/minifier/src/test_minifier.c b/node_modules/webworker-threads/deps/minifier/src/test_minifier.c
new file mode 100644
index 0000000..8be053b
--- /dev/null
+++ b/node_modules/webworker-threads/deps/minifier/src/test_minifier.c
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+int main (int argc, char* argv[]) {
+ #include "test.include.c"
+ printf("%s\n\n", _test);
+ return 0;
+} \ No newline at end of file
diff --git a/node_modules/webworker-threads/examples/demo.js b/node_modules/webworker-threads/examples/demo.js
new file mode 100644
index 0000000..63316ae
--- /dev/null
+++ b/node_modules/webworker-threads/examples/demo.js
@@ -0,0 +1,31 @@
+var http= require('http');
+
+function fibo (n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+
+function fast (req,res) {
+ process.stdout.write('·');
+ res.end("FAST");
+}
+
+function slow (req,res) {
+ process.stdout.write('•');
+ res.end("SLOW -> "+ fibo(40));
+}
+
+var numThreads= parseInt(process.argv[2], 10) || 5;
+console.log("Using "+ numThreads+ " threads.");
+var Worker= require('webworker-threads');
+var threadPool= Worker.createPool(numThreads).all.eval(fibo);
+
+function tagg (req,res) {
+ threadPool.any.eval('fibo(40)', function (err, data) {
+ process.stdout.write('❚');
+ res.end("TAGG -> "+ data); //Threads A GoGo
+ });
+}
+
+http.createServer(fast).listen(12345), console.log("fast @ localhost:12345");
+http.createServer(slow).listen(12346), console.log("slow @ localhost:12346");
+http.createServer(tagg).listen(12347), console.log("useThreads @ localhost:12347");
diff --git a/node_modules/webworker-threads/examples/ex01_basic.js b/node_modules/webworker-threads/examples/ex01_basic.js
new file mode 100644
index 0000000..e82cd9d
--- /dev/null
+++ b/node_modules/webworker-threads/examples/ex01_basic.js
@@ -0,0 +1,63 @@
+/// !example
+/// ## Running a simple function in a thread
+///
+/// This first example demonstrates how you can run an expensive computation in
+/// a worker thread and obtain its result.
+///
+/// First, we define the function that we want to execute in the worker thread:
+function fibo(n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+/// Then, we create a worker thread with the `Threads.create` call:
+var Threads = require('webworker-threads');
+var t = Threads.create();
+/// In the next step, we load the function into the worker thead.
+/// We get the function's source with `fibo.toString()` and we
+/// call `t.eval(source)` to evalutate it into the worker thread's context:
+t.eval(fibo);
+/// Now, we are ready to call this function.
+/// We use the `t.eval` function again, with two arguments this time.
+/// The first argument is the expression to evaluate.
+/// The second one is a callback that receives the result (or an error if there was one).
+t.eval('fibo(10)', function(err, result) {
+ if (err) throw err; // something abnormal
+ // print the result
+ console.log('fibo(10)=' + result);
+ // chain with next step
+ step2();
+});
+/// Let's call it again:
+function step2() {
+ t.eval('fibo(20)', function(err, result) {
+ if (err) throw err;
+ console.log('fibo(20)=' + result);
+ step3();
+ });
+}
+/// If the expression is invalid, we get an error through the callback
+function step3() {
+ // 'x' is not defined
+ t.eval('fibo(x)', function(err, result) {
+ console.log('error=' + err);
+ step4();
+ });
+}
+/// But the thread is still alive and ready to accept more calls:
+function step4() {
+ t.eval('fibo(15)', function(err, result) {
+ console.log('fibo(15)=' + result);
+ step5();
+ });
+}
+/// Once we are done, we destroy the thread:
+function step5() {
+ t.destroy();
+}
+/// ### Output
+///
+/// ```
+/// fibo(10)=89
+/// fibo(20)=10946
+/// error=Error: ReferenceError: x is not defined
+/// fibo(15)=987
+/// ``` \ No newline at end of file
diff --git a/node_modules/webworker-threads/examples/ex01_basic.md b/node_modules/webworker-threads/examples/ex01_basic.md
new file mode 100644
index 0000000..21ee60d
--- /dev/null
+++ b/node_modules/webworker-threads/examples/ex01_basic.md
@@ -0,0 +1,94 @@
+## Running a simple function in a thread
+
+This first example demonstrates how you can run an expensive computation in
+a worker thread and obtain its result.
+
+First, we define the function that we want to execute in the worker thread:
+
+``` javascript
+function fibo(n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+```
+
+Then, we create a worker thread with the `Threads.create` call:
+
+``` javascript
+var Threads = require('webworker-threads');
+var t = Threads.create();
+```
+
+In the next step, we load the function into the worker thead.
+We get the function's source with `fibo.toString()` and we
+call `t.eval(source)` to evalutate it into the worker thread's context:
+
+``` javascript
+t.eval(fibo);
+```
+
+Now, we are ready to call this function.
+We use the `t.eval` function again, with two arguments this time.
+The first argument is the expression to evaluate.
+The second one is a callback that receives the result (or an error if there was one).
+
+``` javascript
+t.eval('fibo(10)', function(err, result) {
+ if (err) throw err; // something abnormal
+ // print the result
+ console.log('fibo(10)=' + result);
+ // chain with next step
+ step2();
+});
+```
+
+Let's call it again:
+
+``` javascript
+function step2() {
+ t.eval('fibo(20)', function(err, result) {
+ if (err) throw err;
+ console.log('fibo(20)=' + result);
+ step3();
+ });
+}
+```
+
+If the expression is invalid, we get an error through the callback
+
+``` javascript
+function step3() {
+ // 'x' is not defined
+ t.eval('fibo(x)', function(err, result) {
+ console.log('error=' + err);
+ step4();
+ });
+}
+```
+
+But the thread is still alive and ready to accept more calls:
+
+``` javascript
+function step4() {
+ t.eval('fibo(15)', function(err, result) {
+ console.log('fibo(15)=' + result);
+ step5();
+ });
+}
+```
+
+Once we are done, we destroy the thread:
+
+``` javascript
+function step5() {
+ t.destroy();
+}
+```
+
+### Output
+
+```
+fibo(10)=89
+fibo(20)=10946
+error=Error: ReferenceError: x is not defined
+fibo(15)=987
+```
diff --git a/node_modules/webworker-threads/examples/ex02_events.js b/node_modules/webworker-threads/examples/ex02_events.js
new file mode 100644
index 0000000..6d6bfac
--- /dev/null
+++ b/node_modules/webworker-threads/examples/ex02_events.js
@@ -0,0 +1,54 @@
+/// !example
+/// ## Sending events from a worker thread
+///
+/// This second example demonstrates how we can use events to communicate from the worker
+/// thread to the main thread.
+///
+/// Like before, we create a thread and we define the fibonacci function:
+var Threads = require('webworker-threads');
+var t = Threads.create();
+
+function fibo(n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+/// Instead of running a single fibonacci computation in the worker thread, we are going to execute a function
+/// that computes all fibonacci numbers and emits a `data` event for every number it generates.
+///
+/// This function runs inside the worker thread so it does not see the `t` variable which belongs to the
+/// main thread. But **webworker-threads** sets up a global `thread` variable that the worker thread can use to
+/// send events to the main thread.
+///
+/// Here is our fibonacci generator:
+function generateFibos(max) {
+ for (var i = 1; i <= max; i++) {
+ thread.emit("data", i, fibo(i));
+ }
+}
+/// Note: this is obviously a very inefficient algorithm to generate the sequence of fibonacci numbers.
+///
+/// Inside the main thread, we set up an event listener for the `data` events emitted by the
+/// worker thread:
+t.on('data', function(n, result) {
+ console.log('fibo(' + n + ') = ' + result);
+})
+/// Now, we are ready to go. We load the two functions into the worker thread
+t.eval(fibo);
+t.eval(generateFibos);
+/// And we run the generator with a callback that will execute when the generator returns from its loop:
+t.eval("generateFibos(40)", function(err, result) {
+ if (err) throw err;
+ console.log("generator is done!");
+ t.destroy();
+});
+/// ### Output
+///
+/// ```
+/// fibo(1) = 1
+/// fibo(2) = 2
+/// fibo(3) = 3
+/// fibo(4) = 5
+/// ...
+/// fibo(39) = 102334155
+/// fibo(40) = 165580141
+/// generator is done!
+/// ``` \ No newline at end of file
diff --git a/node_modules/webworker-threads/examples/ex02_events.md b/node_modules/webworker-threads/examples/ex02_events.md
new file mode 100644
index 0000000..7819b17
--- /dev/null
+++ b/node_modules/webworker-threads/examples/ex02_events.md
@@ -0,0 +1,73 @@
+## Sending events from a worker thread
+
+This second example demonstrates how we can use events to communicate from the worker
+thread to the main thread.
+
+Like before, we create a thread and we define the fibonacci function:
+
+``` javascript
+var Threads = require('webworker-threads');
+var t = Threads.create();
+
+function fibo(n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+```
+
+Instead of running a single fibonacci computation in the worker thread, we are going to execute a function
+that computes all fibonacci numbers and emits a `data` event for every number it generates.
+
+This function runs inside the worker thread so it does not see the `t` variable which belongs to the
+main thread. But **webworker-threads** sets up a global `thread` variable that the worker thread can use to
+send events to the main thread.
+
+Here is our fibonacci generator:
+
+``` javascript
+function generateFibos(max) {
+ for (var i = 1; i <= max; i++) {
+ thread.emit("data", i, fibo(i));
+ }
+}
+```
+
+Note: this is obviously a very inefficient algorithm to generate the sequence of fibonacci numbers.
+
+Inside the main thread, we set up an event listener for the `data` events emitted by the
+worker thread:
+
+``` javascript
+t.on('data', function(n, result) {
+ console.log('fibo(' + n + ') = ' + result);
+})
+```
+
+Now, we are ready to go. We load the two functions into the worker thread
+
+``` javascript
+t.eval(fibo);
+t.eval(generateFibos);
+```
+
+And we run the generator with a callback that will execute when the generator returns from its loop:
+
+``` javascript
+t.eval("generateFibos(40)", function(err, result) {
+ if (err) throw err;
+ console.log("generator is done!");
+ t.destroy();
+});
+```
+
+### Output
+
+```
+fibo(1) = 1
+fibo(2) = 2
+fibo(3) = 3
+fibo(4) = 5
+...
+fibo(39) = 102334155
+fibo(40) = 165580141
+generator is done!
+```
diff --git a/node_modules/webworker-threads/examples/ex03_ping_pong.js b/node_modules/webworker-threads/examples/ex03_ping_pong.js
new file mode 100644
index 0000000..f2d7df4
--- /dev/null
+++ b/node_modules/webworker-threads/examples/ex03_ping_pong.js
@@ -0,0 +1,57 @@
+/// !example
+/// ## Sending events both ways between the main thread and a worker thread
+///
+/// This third example demonstrates how we can use events to communicate in both directions
+/// between main thread and worker thread.
+///
+/// Like before, we create a worker thread and we define the fibonacci function:
+var Threads = require('webworker-threads');
+var t = Threads.create();
+
+function fibo(n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+/// In the previous example we were running a loop that generates fibonacci numbers in the worker thread.
+/// This is fine if the generator produces the number at a slower rate than the main thread can consume them
+/// but it will hog memory if the main thread is too busy and cannot consume the data events fast enough.
+/// We can improve this by controlling the flow with events in both directions.
+///
+/// The `thread` global variable that **webworker-threads** predefines in every worker thread is also an `EventEmitter`.
+/// So we will use it to send events in the other direction, from the main thread to the worker thread.
+///
+/// Our modified generator does not use a loop any more. Instead, it generates numbers in response to `next` events
+/// sent from the main thread. Here is the new generator:
+function generateFibos() {
+ var i = 1;
+ thread.on('next', function() {
+ thread.emit('data', i, fibo(i));
+ i++;
+ });
+}
+/// From the main thread, we listen for the `data` events emitted by the worker thread.
+/// Every time we get a `data` event from the worker thread, we print the result and we `emit` a
+/// `next` event into the worker thread (stopping at 40):
+t.on('data', function(n, result) {
+ console.log('fibo(' + n + ') = ' + result);
+ if (n < 40) t.emit('next');
+ else console.log('bye!'), t.destroy();
+});
+/// We now have all we need for our little ping-pong game. We load the two functions into the thread:
+t.eval(fibo);
+t.eval(generateFibos);
+/// We start the generator in the worker thread:
+t.eval("generateFibos()");
+/// And we start the game by emitting the first `next` event:
+t.emit('next');
+/// ### Output
+///
+/// ```
+/// fibo(1) = 1
+/// fibo(2) = 2
+/// fibo(3) = 3
+/// fibo(4) = 5
+/// ...
+/// fibo(39) = 102334155
+/// fibo(40) = 165580141
+/// bye!
+/// ``` \ No newline at end of file
diff --git a/node_modules/webworker-threads/examples/ex03_ping_pong.md b/node_modules/webworker-threads/examples/ex03_ping_pong.md
new file mode 100644
index 0000000..826df60
--- /dev/null
+++ b/node_modules/webworker-threads/examples/ex03_ping_pong.md
@@ -0,0 +1,80 @@
+## Sending events both ways between the main thread and a worker thread
+
+This third example demonstrates how we can use events to communicate in both directions
+between main thread and worker thread.
+
+Like before, we create a worker thread and we define the fibonacci function:
+
+``` javascript
+var Threads = require('webworker-threads');
+var t = Threads.create();
+
+function fibo(n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+```
+
+In the previous example we were running a loop that generates fibonacci numbers in the worker thread.
+This is fine if the generator produces the number at a slower rate than the main thread can consume them
+but it will hog memory if the main thread is too busy and cannot consume the data events fast enough.
+We can improve this by controlling the flow with events in both directions.
+
+The `thread` global variable that **webworker-threads** predefines in every worker thread is also an `EventEmitter`.
+So we will use it to send events in the other direction, from the main thread to the worker thread.
+
+Our modified generator does not use a loop any more. Instead, it generates numbers in response to `next` events
+sent from the main thread. Here is the new generator:
+
+``` javascript
+function generateFibos() {
+ var i = 1;
+ thread.on('next', function() {
+ thread.emit('data', i, fibo(i));
+ i++;
+ });
+}
+```
+
+From the main thread, we listen for the `data` events emitted by the worker thread.
+Every time we get a `data` event from the worker thread, we print the result and we `emit` a
+`next` event into the worker thread (stopping at 40):
+
+``` javascript
+t.on('data', function(n, result) {
+ console.log('fibo(' + n + ') = ' + result);
+ if (n < 40) t.emit('next');
+ else console.log('bye!'), t.destroy();
+});
+```
+
+We now have all we need for our little ping-pong game. We load the two functions into the thread:
+
+``` javascript
+t.eval(fibo);
+t.eval(generateFibos);
+```
+
+We start the generator in the worker thread:
+
+``` javascript
+t.eval("generateFibos()");
+```
+
+And we start the game by emitting the first `next` event:
+
+``` javascript
+t.emit('next');
+```
+
+### Output
+
+```
+fibo(1) = 1
+fibo(2) = 2
+fibo(3) = 3
+fibo(4) = 5
+...
+fibo(39) = 102334155
+fibo(40) = 165580141
+bye!
+```
diff --git a/node_modules/webworker-threads/examples/ex04_main.js b/node_modules/webworker-threads/examples/ex04_main.js
new file mode 100644
index 0000000..be8ca7c
--- /dev/null
+++ b/node_modules/webworker-threads/examples/ex04_main.js
@@ -0,0 +1,40 @@
+/// !example
+/// ## Loading the worker code from a file (main side)
+///
+/// When writing code for threads we have both code that executes in the main thread and code that
+/// executes in worker threads. When the code is small, it may be handy to have all code in a single file
+/// but it is often clearer to split the code apart when the worker code starts to grow.
+///
+/// This example demonstrates how we can package the worker code in a separeate file and
+/// load it with `t.load`.
+///
+/// We are going to keep the same logic as in our previous 'ping pong' example, but just repackage
+/// it slightly differently.
+///
+/// In this file we keep only the ping (main) side:
+// Creating the worker thread
+var Threads = require('webworker-threads');
+var t = Threads.create();
+
+// Listening to 'data' events from the worker thread
+t.on('data', function(n, result) {
+ console.log('fibo(' + n + ') = ' + result);
+ if (n < 40) t.emit('next');
+ else console.log('bye!'), t.destroy();
+});
+/// At this point we load the worker code:
+t.load(__dirname + '/ex04_worker.js');
+/// And we start the game by emitting the first `next` event:
+t.emit('next');
+/// ### Output
+///
+/// ```
+/// fibo(1) = 1
+/// fibo(2) = 2
+/// fibo(3) = 3
+/// fibo(4) = 5
+/// ...
+/// fibo(39) = 102334155
+/// fibo(40) = 165580141
+/// bye!
+/// ``` \ No newline at end of file
diff --git a/node_modules/webworker-threads/examples/ex04_main.md b/node_modules/webworker-threads/examples/ex04_main.md
new file mode 100644
index 0000000..f341518
--- /dev/null
+++ b/node_modules/webworker-threads/examples/ex04_main.md
@@ -0,0 +1,51 @@
+## Loading the worker code from a file (main side)
+
+When writing code for threads we have both code that executes in the main thread and code that
+executes in worker threads. When the code is small, it may be handy to have all code in a single file
+but it is often clearer to split the code apart when the worker code starts to grow.
+
+This example demonstrates how we can package the worker code in a separeate file and
+load it with `t.load`.
+
+We are going to keep the same logic as in our previous 'ping pong' example, but just repackage
+it slightly differently.
+
+In this file we keep only the ping (main) side:
+
+``` javascript
+// Creating the worker thread
+var Threads = require('webworker-threads');
+var t = Threads.create();
+
+// Listening to 'data' events from the worker thread
+t.on('data', function(n, result) {
+ console.log('fibo(' + n + ') = ' + result);
+ if (n < 40) t.emit('next');
+ else console.log('bye!'), t.destroy();
+});
+```
+
+At this point we load the worker code:
+
+``` javascript
+t.load(__dirname + '/ex04_worker.js');
+```
+
+And we start the game by emitting the first `next` event:
+
+``` javascript
+t.emit('next');
+```
+
+### Output
+
+```
+fibo(1) = 1
+fibo(2) = 2
+fibo(3) = 3
+fibo(4) = 5
+...
+fibo(39) = 102334155
+fibo(40) = 165580141
+bye!
+```
diff --git a/node_modules/webworker-threads/examples/ex04_worker.js b/node_modules/webworker-threads/examples/ex04_worker.js
new file mode 100644
index 0000000..4a784e6
--- /dev/null
+++ b/node_modules/webworker-threads/examples/ex04_worker.js
@@ -0,0 +1,15 @@
+/// !example
+/// ## Loading the worker code from a file (worker side)
+///
+/// This file contains the pong (worker) side of our ping pong example.
+/// It is loaded by a `t.load` call in `ex4_main.js`.
+function fibo(n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+
+// returning the next fibonacci number when a 'next' event comes in:
+var i = 1;
+thread.on('next', function() {
+ thread.emit('data', i, fibo(i));
+ i++;
+}); \ No newline at end of file
diff --git a/node_modules/webworker-threads/examples/ex04_worker.md b/node_modules/webworker-threads/examples/ex04_worker.md
new file mode 100644
index 0000000..1304675
--- /dev/null
+++ b/node_modules/webworker-threads/examples/ex04_worker.md
@@ -0,0 +1,18 @@
+## Loading the worker code from a file (worker side)
+
+This file contains the pong (worker) side of our ping pong example.
+It is loaded by a `t.load` call in `ex4_main.js`.
+
+``` javascript
+function fibo(n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+
+// returning the next fibonacci number when a 'next' event comes in:
+var i = 1;
+thread.on('next', function() {
+ thread.emit('data', i, fibo(i));
+ i++;
+});
+```
+
diff --git a/node_modules/webworker-threads/examples/ex05_pool.js b/node_modules/webworker-threads/examples/ex05_pool.js
new file mode 100644
index 0000000..f9ce4d8
--- /dev/null
+++ b/node_modules/webworker-threads/examples/ex05_pool.js
@@ -0,0 +1,52 @@
+/// !example
+/// ## Using the thread pool
+///
+/// Our previous examples used a single worker thread, and thus only one processor core.
+/// If we want to take full advantage of multi-core processors, we need the ability to delegate
+/// expensive computations to a pool of theads. This example demonstrates the pool thread that comes
+/// bundled with Worker.
+///
+/// First, we create a pool
+var Threads = require('webworker-threads');
+var pool = Threads.createPool(3);
+///
+/// Then we load our fibonacci function in all the pool's threads:
+function fibo(n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+
+pool.all.eval(fibo);
+/// Now, we can get fibonacci numbers from our pool
+///
+/// We request them in reverse order, to show that longer computations (`fibo(40)`) run in
+/// parallel with shorter ones (`fibo(39)`, `fibo(38)`, ...). The results won't come out in strictly decreasing order.
+var remain = 11;
+for (var i = 40; i >= 30; i--) {
+ // extra closure to get proper scoping on 'i'
+ (function(i) {
+ // dispatch each request to the first available thread
+ pool.any.eval('fibo(' + i + ')', function(err, val) {
+ console.log('fibo(' + i + ')=' + i);
+ // destroy the pool when all results have been produced
+ if (--remain == 0) console.log('bye!'), pool.destroy();
+ });
+ })(i);
+}
+/// ### Typical (*) Output
+///
+/// (*) Execution is non-deterministic. So order may vary.
+///
+/// ```
+/// fibo(38)=38
+/// fibo(39)=39
+/// fibo(37)=37
+/// fibo(35)=35
+/// fibo(36)=36
+/// fibo(33)=33
+/// fibo(34)=34
+/// fibo(31)=31
+/// fibo(32)=32
+/// fibo(30)=30
+/// fibo(40)=40
+/// bye!
+/// ``` \ No newline at end of file
diff --git a/node_modules/webworker-threads/examples/ex05_pool.md b/node_modules/webworker-threads/examples/ex05_pool.md
new file mode 100644
index 0000000..528793f
--- /dev/null
+++ b/node_modules/webworker-threads/examples/ex05_pool.md
@@ -0,0 +1,63 @@
+## Using the thread pool
+
+Our previous examples used a single worker thread, and thus only one processor core.
+If we want to take full advantage of multi-core processors, we need the ability to delegate
+expensive computations to a pool of theads. This example demonstrates the pool thread that comes
+bundled with webworker-threads.
+
+First, we create a pool
+
+``` javascript
+var Threads = require('webworker-threads');
+var pool = Threads.createPool(3);
+```
+
+
+Then we load our fibonacci function in all the pool's threads:
+
+``` javascript
+function fibo(n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+
+pool.all.eval(fibo);
+```
+
+Now, we can get fibonacci numbers from our pool
+
+We request them in reverse order, to show that longer computations (`fibo(40)`) run in
+parallel with shorter ones (`fibo(39)`, `fibo(38)`, ...). The results won't come out in strictly decreasing order.
+
+``` javascript
+var remain = 11;
+for (var i = 40; i >= 30; i--) {
+ // extra closure to get proper scoping on 'i'
+ (function(i) {
+ // dispatch each request to the first available thread
+ pool.any.eval('fibo(' + i + ')', function(err, val) {
+ console.log('fibo(' + i + ')=' + i);
+ // destroy the pool when all results have been produced
+ if (--remain == 0) console.log('bye!'), pool.destroy();
+ });
+ })(i);
+}
+```
+
+### Typical (*) Output
+
+(*) Execution is non-deterministic. So order may vary.
+
+```
+fibo(38)=38
+fibo(39)=39
+fibo(37)=37
+fibo(35)=35
+fibo(36)=36
+fibo(33)=33
+fibo(34)=34
+fibo(31)=31
+fibo(32)=32
+fibo(30)=30
+fibo(40)=40
+bye!
+```
diff --git a/node_modules/webworker-threads/examples/ex06_complex.js b/node_modules/webworker-threads/examples/ex06_complex.js
new file mode 100644
index 0000000..d8d71b4
--- /dev/null
+++ b/node_modules/webworker-threads/examples/ex06_complex.js
@@ -0,0 +1,39 @@
+/// A very simple class for complex numbers
+
+function Complex (x, y) {
+ this.x = x;
+ this.y = y;
+ this.add= complex_add;
+ this.mul= complex_mul;
+ this.toString= complex_toString;
+}
+function complex_toString () {
+ return this.x + (this.y > 0 ? " + " + this.y + "i" : this.y < 0 ? " - " + -this.y + "i" : "");
+}
+function complex_add (c) {
+ return new Complex(this.x + c.x, this.y + c.y);
+}
+function complex_mul (c) {
+ return new Complex(this.x * c.x - this.y * c.y, this.x + c.y + this.y * c.x);
+}
+
+/// A class to represent a degree 2 polynomial equation with real coefficients.
+
+function Equation (a, b, c) {
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ this.toString= equation_toString;
+ this.solve= equation_solve;
+}
+function equation_toString () {
+ return this.a + "x^2 + " + this.b + "x + " + this.c
+}
+function equation_solve () {
+ var a = this.a, b = this.b, c = this.c
+ var det = b * b - 4 * a * c;
+ var sdet = Math.sqrt(Math.abs(det));
+ var _2a = 2 * a;
+ if (det >= 0) return [new Complex((-b - sdet) / _2a, 0), new Complex((-b + sdet) / _2a, 0)];
+ else return [new Complex(-b / _2a, -sdet / _2a), new Complex(-b / _2a, sdet / _2a)];
+} \ No newline at end of file
diff --git a/node_modules/webworker-threads/examples/ex06_jason.js b/node_modules/webworker-threads/examples/ex06_jason.js
new file mode 100644
index 0000000..94c9474
--- /dev/null
+++ b/node_modules/webworker-threads/examples/ex06_jason.js
@@ -0,0 +1,42 @@
+/// !example
+/// ## Passing complex objects to threads
+///
+/// In the previous examples, we have been using threads with very simple functions and
+/// we have been passing very simple values (integers) between threads.
+///
+/// This example shows how we can pass more complex data between threads.
+///
+/// It is important to understand that objects cannot be shared across threads.
+/// This does not prevent us from passing complex objects but we have to serialize them
+/// and pass them as strings.
+///
+/// If the objects are really simple, we can use JSON serialization but if they contain
+/// information that JSON discards, like methods, we should use the JASON serializer
+/// published on https://github.com/xk/JASON
+///
+/// In this example, we are going to use a thread to do computation with complex numbers.
+/// We use the Complex and Equation classes defined in the ex06_complex.js file.
+var Equation = require("./ex06_complex").Equation;
+/// As usual, we create a thread
+var t = require('webworker-threads').create();
+/// We require the JASON serializer
+var JASON = require("JASON");
+/// We load the JASON serializer and the solve function in our thread:
+t.eval("JASON= "+ JASON.stringify(JASON));
+t.load(__dirname + "/ex06_complex.js");
+/// Now we can pass a request to solve an equation to our thread.
+/// The expression is wrapped into a `JASON.stringify` call because we want the thread
+/// to stringify the solution object before returning it to the main thread
+/// The main thread calls `JASON.parse` to _de-stringify_ the solution.
+t.eval("JASON.stringify(new Equation(1, -4, 29).solve())", function(err, result) {
+ if (err) throw err;
+ var r = JASON.parse(result).join(', ');
+ console.log("\nsolution is:\n[" + r+ "]\n");
+ t.destroy();
+});
+/// ### Typical Output
+///
+/// ```
+/// solution is:
+/// [2 - 5i, 2 + 5i]
+/// ``` \ No newline at end of file
diff --git a/node_modules/webworker-threads/examples/ex06_jason.md b/node_modules/webworker-threads/examples/ex06_jason.md
new file mode 100644
index 0000000..000c3af
--- /dev/null
+++ b/node_modules/webworker-threads/examples/ex06_jason.md
@@ -0,0 +1,61 @@
+## Passing complex objects to threads
+
+In the previous examples, we have been using threads with very simple functions and
+we have been passing very simple values (integers) between threads.
+
+This example shows how we can pass more complex data between threads.
+
+It is important to understand that objects cannot be shared across threads.
+This does not prevent us from passing complex objects but we have to serialize them
+and pass them as strings.
+
+If the objects are really simple, we can use JSON serialization but if they contain
+information that JSON discards, like methods, we should use the JASON serializer
+published on https://github.com/xk/JASON
+
+In this example, we are going to use a thread to do computation with complex numbers.
+We use the Complex and Equation classes defined in the ex06_complex.js file.
+
+``` javascript
+var Equation = require("./ex06_complex").Equation;
+```
+
+As usual, we create a thread
+
+``` javascript
+var t = require('webworker-threads').create();
+```
+
+We require the JASON serializer
+
+``` javascript
+var JASON = require("JASON");
+```
+
+We load the JASON serializer and the solve function in our thread:
+
+``` javascript
+t.eval("JASON= "+ JASON.stringify(JASON));
+t.load(__dirname + "/ex06_complex.js")
+```
+
+Now we can pass a request to solve an equation to our thread.
+The expression is wrapped into a `JASON.stringify` call because we want the thread
+to stringify the solution object before returning it to the main thread
+The main thread calls `JASON.parse` to _de-stringify_ the solution.
+
+``` javascript
+t.eval("JASON.stringify(new Equation(1, -4, 29).solve())", function(err, result) {
+ if (err) throw err;
+ var r = JASON.parse(result).join(', ');
+ console.log("\nsolution is:\n[" + r+ "]\n");
+ t.destroy();
+});
+```
+
+### Typical Output
+
+```
+solution is:
+[2 - 5i, 2 + 5i]
+```
diff --git a/node_modules/webworker-threads/examples/fiveThreads.ls b/node_modules/webworker-threads/examples/fiveThreads.ls
new file mode 100755
index 0000000..9d8b324
--- /dev/null
+++ b/node_modules/webworker-threads/examples/fiveThreads.ls
@@ -0,0 +1,15 @@
+#!/usr/bin/env lsc
+# Same as multiThreadEvented.ls, but with 5 workers
+
+{ Worker } = require \webworker-threads
+
+for til 5 => (new Worker ->
+ fibo = (n) -> if n > 1 then fibo(n - 1) + fibo(n - 2) else 1
+ @onmessage = ({ data }) -> postMessage fibo data
+)
+ ..onmessage = ({ data }) ->
+ console.log "[#{ @thread.id }] #data"
+ @postMessage Math.ceil Math.random! * 30
+ ..postMessage Math.ceil Math.random! * 30
+
+do spin = -> process.nextTick spin
diff --git a/node_modules/webworker-threads/examples/multiThreadEvented.ls b/node_modules/webworker-threads/examples/multiThreadEvented.ls
new file mode 100755
index 0000000..982c1dd
--- /dev/null
+++ b/node_modules/webworker-threads/examples/multiThreadEvented.ls
@@ -0,0 +1,15 @@
+#!/usr/bin/env lsc
+# Minimal example for https://npmjs.org/package/webworker-threads
+
+{ Worker } = require \webworker-threads
+
+(new Worker ->
+ fibo = (n) -> if n > 1 then fibo(n - 1) + fibo(n - 2) else 1
+ @onmessage = ({ data }) -> postMessage fibo data
+)
+ ..onmessage = ({ data }) ->
+ console.log data
+ @postMessage Math.ceil Math.random! * 30
+ ..postMessage Math.ceil Math.random! * 30
+
+do spin = -> process.nextTick spin
diff --git a/node_modules/webworker-threads/examples/quickIntro_blocking.js b/node_modules/webworker-threads/examples/quickIntro_blocking.js
new file mode 100644
index 0000000..fedb97f
--- /dev/null
+++ b/node_modules/webworker-threads/examples/quickIntro_blocking.js
@@ -0,0 +1,13 @@
+function fibo (n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+
+(function fiboLoop () {
+ process.stdout.write(fibo(35).toString());
+ process.nextTick(fiboLoop);
+})();
+
+(function spinForever () {
+ process.stdout.write(".");
+ process.nextTick(spinForever);
+})();
diff --git a/node_modules/webworker-threads/examples/quickIntro_evented_childThreadCode.js b/node_modules/webworker-threads/examples/quickIntro_evented_childThreadCode.js
new file mode 100644
index 0000000..ba31205
--- /dev/null
+++ b/node_modules/webworker-threads/examples/quickIntro_evented_childThreadCode.js
@@ -0,0 +1,7 @@
+function fibo (n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+
+thread.on('giveMeTheFibo', function onGiveMeTheFibo (data) {
+ this.emit('theFiboIs', fibo(+data)); //Emits 'theFiboIs' in the parent/main thread.
+}); \ No newline at end of file
diff --git a/node_modules/webworker-threads/examples/quickIntro_fiveThreads.js b/node_modules/webworker-threads/examples/quickIntro_fiveThreads.js
new file mode 100644
index 0000000..1348a97
--- /dev/null
+++ b/node_modules/webworker-threads/examples/quickIntro_fiveThreads.js
@@ -0,0 +1,21 @@
+function fibo (n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+
+function cb (err, data) {
+ process.stdout.write(" ["+ this.id+ "]"+ data);
+ this.eval('fibo(35)', cb);
+}
+
+var Worker= require('webworker-threads');
+
+Worker.create().eval(fibo).eval('fibo(35)', cb);
+Worker.create().eval(fibo).eval('fibo(35)', cb);
+Worker.create().eval(fibo).eval('fibo(35)', cb);
+Worker.create().eval(fibo).eval('fibo(35)', cb);
+Worker.create().eval(fibo).eval('fibo(35)', cb);
+
+(function spinForever () {
+ process.stdout.write(".");
+ process.nextTick(spinForever);
+})();
diff --git a/node_modules/webworker-threads/examples/quickIntro_loop.js b/node_modules/webworker-threads/examples/quickIntro_loop.js
new file mode 100644
index 0000000..4d4212c
--- /dev/null
+++ b/node_modules/webworker-threads/examples/quickIntro_loop.js
@@ -0,0 +1,4 @@
+(function spinForever () {
+ process.stdout.write(".");
+ process.nextTick(spinForever);
+})();
diff --git a/node_modules/webworker-threads/examples/quickIntro_multiThread.js b/node_modules/webworker-threads/examples/quickIntro_multiThread.js
new file mode 100644
index 0000000..86e861e
--- /dev/null
+++ b/node_modules/webworker-threads/examples/quickIntro_multiThread.js
@@ -0,0 +1,16 @@
+function fibo (n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+
+var numThreads= 10;
+var threadPool= require('webworker-threads').createPool(numThreads).all.eval(fibo);
+
+threadPool.all.eval('fibo(35)', function cb (err, data) {
+ process.stdout.write(" ["+ this.id+ "]"+ data);
+ this.eval('fibo(35)', cb);
+});
+
+(function spinForever () {
+ process.stdout.write(".");
+ process.nextTick(spinForever);
+})();
diff --git a/node_modules/webworker-threads/examples/quickIntro_multiThreadEvented.js b/node_modules/webworker-threads/examples/quickIntro_multiThreadEvented.js
new file mode 100644
index 0000000..bd7f4c1
--- /dev/null
+++ b/node_modules/webworker-threads/examples/quickIntro_multiThreadEvented.js
@@ -0,0 +1,30 @@
+var numThreads= 10;
+var threadPool= require('webworker-threads').createPool(numThreads);
+threadPool.load(__dirname + '/quickIntro_evented_childThreadCode.js');
+
+/*
+ This is the code that's .load()ed into the child/background threads:
+
+ function fibo (n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+ }
+
+ thread.on('giveMeTheFibo', function onGiveMeTheFibo (data) {
+ this.emit('theFiboIs', fibo(+data)); //Emits 'theFiboIs' in the parent/main thread.
+ });
+
+*/
+
+//Emit 'giveMeTheFibo' in all the child/background threads.
+threadPool.all.emit('giveMeTheFibo', 35);
+
+//Listener for the 'theFiboIs' events emitted by the child/background thread.
+threadPool.on('theFiboIs', function cb (data) {
+ process.stdout.write(" ["+ this.id+ "]"+ data);
+ this.emit('giveMeTheFibo', 35);
+});
+
+(function spinForever () {
+ process.stdout.write(".");
+ process.nextTick(spinForever);
+})();
diff --git a/node_modules/webworker-threads/examples/quickIntro_oneThread.js b/node_modules/webworker-threads/examples/quickIntro_oneThread.js
new file mode 100644
index 0000000..82f342d
--- /dev/null
+++ b/node_modules/webworker-threads/examples/quickIntro_oneThread.js
@@ -0,0 +1,17 @@
+function fibo (n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+}
+
+function cb (err, data) {
+ process.stdout.write(data);
+ this.eval('fibo(35)', cb);
+}
+
+var thread= require('webworker-threads').create();
+
+thread.eval(fibo).eval('fibo(35)', cb);
+
+(function spinForever () {
+ process.stdout.write(".");
+ process.nextTick(spinForever);
+})();
diff --git a/node_modules/webworker-threads/examples/quickIntro_oneThreadEvented.js b/node_modules/webworker-threads/examples/quickIntro_oneThreadEvented.js
new file mode 100644
index 0000000..fed6f41
--- /dev/null
+++ b/node_modules/webworker-threads/examples/quickIntro_oneThreadEvented.js
@@ -0,0 +1,18 @@
+var Worker = require('webworker-threads').Worker;
+var w = new Worker(function(){
+ function fibo (n) {
+ return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
+ }
+ self.onmessage = function (event) {
+ self.postMessage( fibo( event.data ) );
+ };
+});
+w.postMessage(Math.ceil(Math.random()*30));
+w.onmessage = function cb (event) {
+ process.stdout.write(event.data);
+ w.postMessage(Math.ceil(Math.random()*30));
+};
+(function spinForever () {
+ process.stdout.write(".");
+ process.nextTick(spinForever);
+})();
diff --git a/node_modules/webworker-threads/package.json b/node_modules/webworker-threads/package.json
new file mode 100644
index 0000000..d792ca4
--- /dev/null
+++ b/node_modules/webworker-threads/package.json
@@ -0,0 +1,70 @@
+{
+ "name": "webworker-threads",
+ "version": "0.4.7",
+ "main": "build/Release/WebWorkerThreads.node",
+ "description": "Lightweight Web Worker API implementation with native threads",
+ "keywords": [
+ "threads",
+ "web worker",
+ "a gogo"
+ ],
+ "author": {
+ "name": "Audrey Tang",
+ "email": "audreyt@audreyt.org"
+ },
+ "homepage": "https://github.com/audreyt/node-webworker-threads",
+ "bugs": {
+ "url": "http://github.com/audreyt/node-webworker-threads/issues",
+ "email": "audreyt@audreyt.org"
+ },
+ "licenses": [
+ {
+ "type": "Apache License, Version 2.0",
+ "url": "http://www.apache.org/licenses/LICENSE-2.0"
+ },
+ {
+ "type": "MIT",
+ "url": "file:LICENSE"
+ }
+ ],
+ "repository": {
+ "type": "git",
+ "url": "http://github.com/audreyt/node-webworker-threads.git"
+ },
+ "scripts": {
+ "js": "env PATH=./node_modules/.bin:\"$PATH\" lsc -cj package.ls;\ngcc deps/minifier/src/minify.c -o deps/minifier/bin/minify;\nenv PATH=./node_modules/.bin:\"$PATH\" lsc -cbp src/worker.ls > src/worker.js;\n./deps/minifier/bin/minify kWorker_js < src/worker.js > src/worker.js.c;\nenv PATH=./node_modules/.bin:\"$PATH\" lsc -cbp src/events.ls > src/events.js;\n./deps/minifier/bin/minify kEvents_js < src/events.js > src/events.js.c;\nenv PATH=./node_modules/.bin:\"$PATH\" lsc -cbp src/createPool.ls > src/createPool.js;\n./deps/minifier/bin/minify kCreatePool_js < src/createPool.js > src/createPool.js.c;\nenv PATH=./node_modules/.bin:\"$PATH\" lsc -cbp src/thread_nextTick.ls > src/thread_nextTick.js;\n./deps/minifier/bin/minify kThread_nextTick_js 1 < src/thread_nextTick.js > src/thread_nextTick.js.c;\nenv PATH=./node_modules/.bin:\"$PATH\" lsc -cbp src/load.ls > src/load.js;\n./deps/minifier/bin/minify kLoad_js 1 1 < src/load.js > src/load.js.c;",
+ "install": "node-gyp rebuild"
+ },
+ "devDependencies": {
+ "LiveScript": "1.1.x"
+ },
+ "gypfile": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ },
+ "contributors": [
+ {
+ "name": "//Threads_a_gogo AUTHORS"
+ },
+ {
+ "name": "2011-11-06 Jorge Chamorro Bieling",
+ "email": "jorge@jorgechamorro.com"
+ },
+ {
+ "name": "2011-11-25 Juan Falgueras Cano",
+ "email": "juan.falgueras@gmail.com"
+ },
+ {
+ "name": "2012-01-26 Bruno Jouhier",
+ "email": "bjouhier@gmail.com"
+ }
+ ],
+ "readme": "# WebWorker Threads\n\nThis is based on @xk (jorgechamorro)'s [Threads A GoGo for Node.js](https://github.com/audreyt/node-threads-a-gogo), but with an API conforming to the [Web Worker standard](http://www.w3.org/TR/workers/).\n\nThis module provides an asynchronous, evented and/or continuation passing style API for moving blocking/longish CPU-bound tasks out of Node's event loop to JavaScript threads that run in parallel in the background and that use all the available CPU cores automatically; all from within a single Node process.\n\nThis module requires Node.js 0.8.0+.\n\nOn Unix (including Linux and OS X), this module requires a working node-gyp toolchain, which in turn requires make and C/C++.\nFor example, on OS X, you could install XCode from Apple, and then use it to install the command line tools (under Preferences -> Downloads).\n\nOn Windows, this module requires Node.js 0.9.3+ and a working [node-gyp toolchain](http://dailyjs.com/2012/05/17/windows-and-node-3/).\n\n## Installing the module\n\nWith [npm](http://npmjs.org/):\n\n npm install webworker-threads\n\nSample usage (adapted from [MDN](https://developer.mozilla.org/en-US/docs/DOM/Using_web_workers#Passing_data)):\n\n```js\nvar Worker = require('webworker-threads').Worker;\n// var w = new Worker('worker.js'); // Standard API\n\n// You may also pass in a function:\nvar worker = new Worker(function(){\n postMessage(\"I'm working before postMessage('ali').\");\n onmessage = function(event) {\n postMessage('Hi ' + event.data);\n self.close();\n };\n});\nworker.onmessage = function(event) {\n console.log(\"Worker said : \" + event.data);\n};\nworker.postMessage('ali');\n```\n\nA more involved example in [LiveScript](http://livescript.net/) syntax, with five threads:\n\n```coffee\n{ Worker } = require \\webworker-threads\n\nfor til 5 => (new Worker ->\n fibo = (n) -> if n > 1 then fibo(n - 1) + fibo(n - 2) else 1\n @onmessage = ({ data }) -> postMessage fibo data\n)\n ..onmessage = ({ data }) ->\n console.log \"[#{ @thread.id }] #data\"\n @postMessage Math.ceil Math.random! * 30\n ..postMessage Math.ceil Math.random! * 30\n\ndo spin = -> process.nextTick spin\n```\n\n## Introduction\n\nAfter the initialization phase of a Node program, whose purpose is to setup listeners and callbacks to be executed in response to events, the next phase, the proper execution of the program, is orchestrated by the event loop whose duty is to [juggle events, listeners and callbacks quickly and without any hiccups nor interruptions that would ruin its performance](http://youtube.com/v/D0uA_NOb0PE?autoplay=1)\n\nBoth the event loop and said listeners and callbacks run sequentially in a single thread of execution, Node's main thread. If any of them ever blocks, nothing else will happen for the duration of the block: no more events will be handled, no more callbacks nor listeners nor timeouts nor nextTick()ed functions will have the chance to run and do their job, because they won't be called by the blocked event loop, and the program will turn sluggish at best, or appear to be frozen and dead at worst.\n\n### What is WebWorker-Threads\n\n`webworker-threads` provides an asynchronous API for CPU-bound tasks that's missing in Node.js:\n\n``` javascript\nvar Worker = require('webworker-threads').Worker;\nrequire('http').createServer(function (req,res) {\n var fibo = new Worker(function() {\n function fibo (n) {\n return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;\n }\n onmessage = function (event) {\n postMessage(fibo(event.data));\n }\n });\n fibo.onmessage = function (event) {\n res.end('fib(40) = ' + event.data);\n };\n fibo.postMessage(40);\n}).listen(port);\n```\n\nAnd it won't block the event loop because for each request, the `fibo` worker will run in parallel in a separate background thread.\n\n## API\n\n### Module API\n``` javascript\nvar Threads= require('webworker-threads');\n```\n##### .Worker\n`new Threads.Worker( [ file | function ] )` returns a Worker object.\n##### .create()\n`Threads.create( /* no arguments */ )` returns a thread object.\n##### .createPool( numThreads )\n`Threads.createPool( numberOfThreads )` returns a threadPool object.\n\n---\n### Web Worker API\n``` javascript\nvar worker= new Threads.Worker('worker.js');\nvar worker= new Threads.Worker(function(){ ... });\nvar worker= new Threads.Worker();\n```\n##### .postMessage( data )\n`worker.postMessage({ x: 1, y: 2 })` sends a data structure into the worker. The worker can receive it using the `onmessage` handler.\n##### .onmessage\n`worker.onmessage = function (event) { console.log(event.data) };` receives data from the worker's `postMessage` calls.\n##### .terminate()\n`worker.terminate()` terminates the worker thread.\n##### .addEventListener( type, cb )\n`worker.addEventListener('message', callback)` is equivalent to setting `worker.onmesssage = callback`.\n##### .dispatchEvent( event )\nCurrently unimplemented.\n##### .removeEventListener( type )\nCurrently unimplemented.\n##### .thread\nReturns the underlying `thread` object; see the next section for details.\nNote that this attribute is implementation-specific, and not part of W3C Web Worker API.\n\n---\n### Thread API\n``` javascript\nvar thread= Threads.create();\n```\n##### .id\n`thread.id` is a sequential thread serial number.\n##### .load( absolutePath [, cb] )\n`thread.load( absolutePath [, cb] )` reads the file at `absolutePath` and `thread.eval(fileContents, cb)`.\n##### .eval( program [, cb])\n`thread.eval( program [, cb])` converts `program.toString()` and eval()s it in the thread's global context, and (if provided) returns the completion value to `cb(err, completionValue)`.\n##### .on( eventType, listener )\n`thread.on( eventType, listener )` registers the listener `listener(data)` for any events of `eventType` that the thread `thread` may emit.\n##### .once( eventType, listener )\n`thread.once( eventType, listener )` is like `thread.on()`, but the listener will only be called once.\n##### .removeAllListeners( [eventType] )\n`thread.removeAllListeners( [eventType] )` deletes all listeners for all eventTypes. If `eventType` is provided, deletes all listeners only for the event type `eventType`.\n##### .emit( eventType, eventData [, eventData ... ] )\n`thread.emit( eventType, eventData [, eventData ... ] )` emits an event of `eventType` with `eventData` inside the thread `thread`. All its arguments are .toString()ed.\n##### .destroy( /* no arguments */ )\n`thread.destroy( /* no arguments */ )` destroys the thread.\n\n---\n### Thread pool API\n``` javascript\nthreadPool= Threads.createPool( numberOfThreads );\n```\n##### .load( absolutePath [, cb] )\n`threadPool.load( absolutePath [, cb] )` runs `thread.load( absolutePath [, cb] )` in all the pool's threads.\n##### .any.eval( program, cb )\n`threadPool.any.eval( program, cb )` is like `thread.eval()`, but in any of the pool's threads.\n##### .any.emit( eventType, eventData [, eventData ... ] )\n`threadPool.any.emit( eventType, eventData [, eventData ... ] )` is like `thread.emit()`, but in any of the pool's threads.\n##### .all.eval( program, cb )\n`threadPool.all.eval( program, cb )` is like `thread.eval()`, but in all the pool's threads.\n##### .all.emit( eventType, eventData [, eventData ... ] )\n`threadPool.all.emit( eventType, eventData [, eventData ... ] )` is like `thread.emit()`, but in all the pool's threads.\n##### .on( eventType, listener )\n`threadPool.on( eventType, listener )` is like `thread.on()`, registers listeners for events from any of the threads in the pool.\n##### .totalThreads()\n`threadPool.totalThreads()` returns the number of threads in this pool: as supplied in `.createPool( number )`\n##### .idleThreads()\n`threadPool.idleThreads()` returns the number of threads in this pool that are currently idle (sleeping)\n##### .pendingJobs()\n`threadPool.pendingJobs()` returns the number of jobs pending.\n##### .destroy( [ rudely ] )\n`threadPool.destroy( [ rudely ] )` waits until `pendingJobs()` is zero and then destroys the pool. If `rudely` is truthy, then it doesn't wait for `pendingJobs === 0`.\n\n---\n### Global Web Worker API\n\nInside every Worker instance from webworker-threads, there's a global `self` object with these properties:\n\n##### .postMessage( data )\n`postMessage({ x: 1, y: 2 })` sends a data structure back to the main thread.\n##### .onmessage\n`onmessage = function (event) { ... }` receives data from the main thread's `.postMessage` calls.\n##### .close()\n`close()` stops the current thread.\n##### .addEventListener( type, cb )\n`addEventListener('message', callback)` is equivalent to setting `self.onmesssage = callback`.\n##### .dispatchEvent( event )\n`dispatchEvent({ type: 'message', data: data })` is the same as `self.postMessage(data)`.\n##### .removeEventListener( type )\nCurrently unimplemented.\n##### .importScripts( file [, file...] )\n`importScripts('a.js', 'b.js')` loads one or more files from the disk and `eval()` them in the worker's instance scope.\n##### .thread\nThe underlying `thread` object; see the next section for details.\nNote that this attribute is implementation-specific, and not part of W3C Web Worker API.\n\n---\n### Global Thread API\n\nInside every thread .create()d by webworker-threads, there's a global `thread` object with these properties:\n##### .id\n`thread.id` is the serial number of this thread\n##### .on( eventType, listener )\n`thread.on( eventType, listener )` is just like `thread.on()` above.\n##### .once( eventType, listener )\n`thread.once( eventType, listener )` is just like `thread.once()` above.\n##### .emit( eventType, eventData [, eventData ... ] )\n`thread.emit( eventType, eventData [, eventData ... ] )` is just like `thread.emit()` above.\n##### .removeAllListeners( [eventType] )\n`thread.removeAllListeners( [eventType] )` is just like `thread.removeAllListeners()` above.\n##### .nextTick( function )\n`thread.nextTick( function )` is like `process.nextTick()`, but much faster.\n\n---\n### Global Helper API\n\nInside every thread .create()d by webworker-threads, there are some helpers:\n\n##### console.log(arg1 [, arg2 ...])\nSame as `console.log` on the main process.\n\n##### console.error(arg1 [, arg2 ...])\nSame as `console.log`, except it prints to stderr.\n\n##### puts(arg1 [, arg2 ...])\n`puts(arg1 [, arg2 ...])` converts .toString()s and prints its arguments to stdout.\n\n-----------\nWIP WIP WIP\n-----------\nNote that everything below this line is under construction and subject to change.\n-----------\n\n## Examples\n\n**A.-** Here's a program that makes Node's event loop spin freely and as fast as possible: it simply prints a dot to the console in each turn:\n\n cat examples/quickIntro_loop.js\n \n``` javascript\n(function spinForever () {\n process.nextTick(spinForever);\n})();\n```\n\n**B.-** Here's another program that adds to the one above a fibonacci(35) call in each turn, a CPU-bound task that takes quite a while to complete and that blocks the event loop making it spin slowly and clumsily. The point is simply to show that you can't put a job like that in the event loop because Node will stop performing properly when its event loop can't spin fast and freely due to a callback/listener/nextTick()ed function that's blocking.\n\n cat examples/quickIntro_blocking.js\n\n``` javascript\nfunction fibo (n) {\n return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;\n}\n\n(function fiboLoop () {\n process.stdout.write(fibo(35).toString());\n process.nextTick(fiboLoop);\n})();\n\n(function spinForever () {\n process.nextTick(spinForever);\n})();\n```\n\n**C.-** The program below uses `webworker-threads` to run the fibonacci(35) calls in a background thread, so Node's event loop isn't blocked at all and can spin freely again at full speed:\n\n cat examples/quickIntro_oneThread.js\n \n``` javascript\nfunction fibo (n) {\n return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;\n}\n\nfunction cb (err, data) {\n process.stdout.write(data);\n this.eval('fibo(35)', cb);\n}\n\nvar thread= require('webworker-threads').create();\n\nthread.eval(fibo).eval('fibo(35)', cb);\n\n(function spinForever () {\n process.nextTick(spinForever);\n})();\n```\n\n**D.-** This example is almost identical to the one above, only that it creates 5 threads instead of one, each running a fibonacci(35) in parallel and in parallel too with Node's event loop that keeps spinning happily at full speed in its own thread:\n\n cat examples/quickIntro_fiveThreads.js\n \n``` javascript\nfunction fibo (n) {\n return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;\n}\n\nfunction cb (err, data) {\n process.stdout.write(\" [\"+ this.id+ \"]\"+ data);\n this.eval('fibo(35)', cb);\n}\n\nvar Threads= require('webworker-threads');\n\nThreads.create().eval(fibo).eval('fibo(35)', cb);\nThreads.create().eval(fibo).eval('fibo(35)', cb);\nThreads.create().eval(fibo).eval('fibo(35)', cb);\nThreads.create().eval(fibo).eval('fibo(35)', cb);\nThreads.create().eval(fibo).eval('fibo(35)', cb);\n\n(function spinForever () {\n process.nextTick(spinForever);\n})();\n```\n\n**E.-** The next one asks `webworker-threads` to create a pool of 10 background threads, instead of creating them manually one by one:\n\n cat examples/multiThread.js\n\n``` javascript\nfunction fibo (n) {\n return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;\n}\n\nvar numThreads= 10;\nvar threadPool= require('webworker-threads').createPool(numThreads).all.eval(fibo);\n\nthreadPool.all.eval('fibo(35)', function cb (err, data) {\n process.stdout.write(\" [\"+ this.id+ \"]\"+ data);\n this.eval('fibo(35)', cb);\n});\n\n(function spinForever () {\n process.nextTick(spinForever);\n})();\n```\n\n**F.-** This is a demo of the `webworker-threads` eventEmitter API, using one thread:\n\n cat examples/quickIntro_oneThreadEvented.js\n\n``` javascript\nvar thread= require('webworker-threads').create();\nthread.load(__dirname + '/quickIntro_evented_childThreadCode.js');\n\n/*\n This is the code that's .load()ed into the child/background thread:\n \n function fibo (n) {\n return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;\n }\n\n thread.on('giveMeTheFibo', function onGiveMeTheFibo (data) {\n this.emit('theFiboIs', fibo(+data)); //Emits 'theFiboIs' in the parent/main thread.\n });\n \n*/\n\n//Emit 'giveMeTheFibo' in the child/background thread.\nthread.emit('giveMeTheFibo', 35);\n\n//Listener for the 'theFiboIs' events emitted by the child/background thread.\nthread.on('theFiboIs', function cb (data) {\n process.stdout.write(data);\n this.emit('giveMeTheFibo', 35);\n});\n\n(function spinForever () {\n process.nextTick(spinForever);\n})();\n```\n\n**G.-** This is a demo of the `webworker-threads` eventEmitter API, using a pool of threads:\n\n cat examples/quickIntro_multiThreadEvented.js\n\n``` javascript\nvar numThreads= 10;\nvar threadPool= require('webworker-threads').createPool(numThreads);\nthreadPool.load(__dirname + '/quickIntro_evented_childThreadCode.js');\n\n/*\n This is the code that's .load()ed into the child/background threads:\n \n function fibo (n) {\n return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;\n }\n\n thread.on('giveMeTheFibo', function onGiveMeTheFibo (data) {\n this.emit('theFiboIs', fibo(+data)); //Emits 'theFiboIs' in the parent/main thread.\n });\n \n*/\n\n//Emit 'giveMeTheFibo' in all the child/background threads.\nthreadPool.all.emit('giveMeTheFibo', 35);\n\n//Listener for the 'theFiboIs' events emitted by the child/background threads.\nthreadPool.on('theFiboIs', function cb (data) {\n process.stdout.write(\" [\"+ this.id+ \"]\"+ data);\n this.emit('giveMeTheFibo', 35);\n});\n\n(function spinForever () {\n process.nextTick(spinForever);\n})();\n```\n\n## More examples\n\nThe `examples` directory contains a few more examples:\n\n* [ex01_basic](https://github.com/xk/node-threads-a-gogo/blob/master/examples/ex01_basic.md): Running a simple function in a thread.\n* [ex02_events](https://github.com/xk/node-threads-a-gogo/blob/master/examples/ex02_events.md): Sending events from a worker thread.\n* [ex03_ping_pong](https://github.com/xk/node-threads-a-gogo/blob/master/examples/ex03_ping_pong.md): Sending events both ways between the main thread and a worker thread.\n* [ex04_main](https://github.com/xk/node-threads-a-gogo/blob/master/examples/ex04_main.md): Loading the worker code from a file.\n* [ex05_pool](https://github.com/xk/node-threads-a-gogo/blob/master/examples/ex05_pool.md): Using the thread pool.\n* [ex06_jason](https://github.com/xk/node-threads-a-gogo/blob/master/examples/ex06_jason.md): Passing complex objects to threads.\n\n## Rationale\n\n[Node.js](http://nodejs.org) is the most awesome, cute and super-sexy piece of free, open source software.\n\nIts event loop can spin as fast and smooth as a turbo, and roughly speaking, **the faster it spins, the more power it delivers**. That's why [@ryah](http://twitter.com/ryah) took great care to ensure that no -possibly slow- I/O operations could ever block it: a pool of background threads (thanks to [Marc Lehmann's libeio library](http://software.schmorp.de/pkg/libeio.html)) handle any blocking I/O calls in the background, in parallel.\n\nIn Node it's verboten to write a server like this:\n\n``` javascript\nhttp.createServer(function (req,res) {\n res.end( fs.readFileSync(path) );\n}).listen(port);\n```\nBecause synchronous I/O calls **block the turbo**, and without proper boost, Node.js begins to stutter and behaves clumsily. To avoid it there's the asynchronous version of `.readFile()`, in continuation passing style, that takes a callback:\n\n``` javascript\nfs.readfile(path, function cb (err, data) { /* ... */ });\n```\n\nIt's cool, we love it (*), and there's hundreds of ad hoc built-in functions like this in Node to help us deal with almost any variety of possibly slow, blocking I/O.\n\n### But what's with longish, CPU-bound tasks?\n\nHow do you avoid blocking the event loop, when the task at hand isn't I/O bound, and lasts more than a few fractions of a millisecond?\n\n``` javascript\nhttp.createServer(function cb (req,res) {\n res.end( fibonacci(40) );\n}).listen(port);\n```\n\nYou simply can't, because there's no way... well, there wasn't before `webworker-threads`.\n\n### Why Threads\n\nThreads (kernel threads) are very interesting creatures. They provide:\n\n1.- Parallelism: All the threads run in parallel. On a single core processor, the CPU is switched rapidly back and forth among the threads providing the illusion that the threads are running in parallel, albeit on a slower CPU than the real one. With 10 compute-bound threads in a process, the threads would appear to be running in parallel, each one on a CPU with 1/10th the speed of the real CPU. On a multi-core processor, threads are truly running in parallel, and get time-sliced when the number of threads exceed the number of cores. So with 12 compute bound threads on a quad-core processor each thread will appear to run at 1/3rd of the nominal core speed.\n\n2.- Fairness: No thread is more important than another, cores and CPU slices are fairly distributed among threads by the OS scheduler.\n\n3.- Threads fully exploit all the available CPU resources in your system. On a loaded system running many tasks in many threads, the more cores there are, the faster the threads will complete. Automatically.\n\n4.- The threads of a process share exactly the same address space, that of the process they belong to. Every thread can access every memory address within the process' address space. This is a very appropriate setup when the threads are actually part of the same job and are actively and closely cooperating with each other. Passing a reference to a chunk of data via a pointer is many orders of magnitude faster than transferring a copy of the data via IPC.\n\n### Why not multiple processes.\n\nThe \"can't block the event loop\" problem is inherent to Node's evented model. No matter how many Node processes you have running as a [Node-cluster](http://blog.nodejs.org/2011/10/04/an-easy-way-to-build-scalable-network-programs/), it won't solve its issues with CPU-bound tasks.\n\nLaunch a cluster of N Nodes running the example B (`quickIntro_blocking.js`) above, and all you'll get is N -instead of one- Nodes with their event loops blocked and showing a sluggish performance.\n",
+ "readmeFilename": "README.md",
+ "_id": "webworker-threads@0.4.7",
+ "dist": {
+ "shasum": "be36d346b673b0ab80d5cbc3914fb234ecb136a3"
+ },
+ "_from": "webworker-threads@",
+ "_resolved": "https://registry.npmjs.org/webworker-threads/-/webworker-threads-0.4.7.tgz"
+}
diff --git a/node_modules/webworker-threads/package.ls b/node_modules/webworker-threads/package.ls
new file mode 100755
index 0000000..ca3e388
--- /dev/null
+++ b/node_modules/webworker-threads/package.ls
@@ -0,0 +1,41 @@
+#!/usr/bin/env lsc -cj
+name: \webworker-threads
+version: \0.4.7
+main: \build/Release/WebWorkerThreads.node
+description: 'Lightweight Web Worker API implementation with native threads'
+keywords: [ 'threads' 'web worker' 'a gogo' ]
+author:
+ name: 'Audrey Tang'
+ email: \audreyt@audreyt.org
+ twitter: \audreyt
+homepage: \https://github.com/audreyt/node-webworker-threads
+bugs:
+ url: \http://github.com/audreyt/node-webworker-threads/issues
+ email: \audreyt@audreyt.org
+licenses: [
+ { type: "Apache License, Version 2.0", url: "http://www.apache.org/licenses/LICENSE-2.0" }
+ { type: 'MIT', url: "file:LICENSE" }
+]
+repository:
+ type: \git
+ url: \http://github.com/audreyt/node-webworker-threads.git
+scripts:
+# prepublish: 'env PATH=./node_modules/.bin:"$PATH" lsc -cj package.ls'
+ js: """
+ env PATH=./node_modules/.bin:"$PATH" lsc -cj package.ls;
+ gcc deps/minifier/src/minify.c -o deps/minifier/bin/minify;
+ env PATH=./node_modules/.bin:"$PATH" lsc -cbp src/worker.ls > src/worker.js;
+ ./deps/minifier/bin/minify kWorker_js < src/worker.js > src/worker.js.c;
+ env PATH=./node_modules/.bin:"$PATH" lsc -cbp src/events.ls > src/events.js;
+ ./deps/minifier/bin/minify kEvents_js < src/events.js > src/events.js.c;
+ env PATH=./node_modules/.bin:"$PATH" lsc -cbp src/createPool.ls > src/createPool.js;
+ ./deps/minifier/bin/minify kCreatePool_js < src/createPool.js > src/createPool.js.c;
+ env PATH=./node_modules/.bin:"$PATH" lsc -cbp src/thread_nextTick.ls > src/thread_nextTick.js;
+ ./deps/minifier/bin/minify kThread_nextTick_js 1 < src/thread_nextTick.js > src/thread_nextTick.js.c;
+ env PATH=./node_modules/.bin:"$PATH" lsc -cbp src/load.ls > src/load.js;
+ ./deps/minifier/bin/minify kLoad_js 1 1 < src/load.js > src/load.js.c;
+ """
+dev-dependencies:
+ LiveScript: \1.1.x
+gypfile: true
+engines: { node: '>= 0.8.0' }
diff --git a/node_modules/webworker-threads/src/WebWorkerThreads.cc b/node_modules/webworker-threads/src/WebWorkerThreads.cc
new file mode 100644
index 0000000..7cf7746
--- /dev/null
+++ b/node_modules/webworker-threads/src/WebWorkerThreads.cc
@@ -0,0 +1,955 @@
+//2011-11 Proyectos Equis Ka, s.l., jorge@jorgechamorro.com
+//WebWorkerThreads.cc
+
+
+#include <v8.h>
+#include <node.h>
+#include <uv.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+
+#if defined(__unix__) || defined(__POSIX__) || defined(__APPLE__) || defined(_AIX)
+#define WWT_PTHREAD 1
+#include <pthread.h>
+#include <unistd.h>
+#ifndef uv_cond_t
+#define uv_cond_signal(x) pthread_cond_signal(x)
+#define uv_cond_init(x) pthread_cond_init(x, NULL)
+#define uv_cond_wait(x,y) pthread_cond_wait(x, y)
+typedef pthread_cond_t uv_cond_t;
+#endif
+#else
+#define pthread_setcancelstate(x,y) NULL
+#define pthread_setcanceltype(x,y) NULL
+#endif
+
+
+/*
+static int debug_threads= 0;
+static int debug_allocs= 0;
+*/
+
+#include "queues_a_gogo.cc"
+#include "bson.cc"
+#include "jslib.cc"
+
+//using namespace node;
+using namespace v8;
+
+static Persistent<String> id_symbol;
+static Persistent<ObjectTemplate> threadTemplate;
+static bool useLocker;
+
+static typeQueue* freeJobsQueue= NULL;
+static typeQueue* freeThreadsQueue= NULL;
+
+#define kThreadMagicCookie 0x99c0ffee
+typedef struct {
+ uv_async_t async_watcher; //MUST be the first one
+
+ long int id;
+ uv_thread_t thread;
+ volatile int sigkill;
+
+ typeQueue inQueue; //Jobs to run
+ typeQueue outQueue; //Jobs done
+
+ volatile int IDLE;
+ uv_cond_t IDLE_cv;
+ uv_mutex_t IDLE_mutex;
+
+ Isolate* isolate;
+ Persistent<Context> context;
+ Persistent<Object> JSObject;
+ Persistent<Object> threadJSObject;
+ Persistent<Object> dispatchEvents;
+
+ unsigned long threadMagicCookie;
+} typeThread;
+
+enum jobTypes {
+ kJobTypeEval,
+ kJobTypeEvent,
+ kJobTypeEventSerialized
+};
+
+typedef struct {
+ int jobType;
+ Persistent<Object> cb;
+ union {
+ struct {
+ int length;
+ String::Utf8Value* eventName;
+ String::Utf8Value** argumentos;
+ } typeEvent;
+ struct {
+ int length;
+ String::Utf8Value* eventName;
+ char* buffer;
+ size_t bufferSize;
+ } typeEventSerialized;
+ struct {
+ int error;
+ int tiene_callBack;
+ int useStringObject;
+ String::Utf8Value* resultado;
+ union {
+ char* scriptText_CharPtr;
+ String::Utf8Value* scriptText_StringObject;
+ };
+ } typeEval;
+ };
+} typeJob;
+
+/*
+
+cd deps/minifier/src
+gcc minify.c -o minify
+cat ../../../src/events.js | ./minify kEvents_js > ../../../src/kEvents_js
+cat ../../../src/load.js | ./minify kLoad_js > ../../../src/kLoad_js
+cat ../../../src/createPool.js | ./minify kCreatePool_js > ../../../src/kCreatePool_js
+cat ../../../src/worker.js | ./minify kWorker_js > ../../../src/kWorker_js
+cat ../../../src/thread_nextTick.js | ./minify kThread_nextTick_js > ../../../src/kThread_nextTick_js
+
+*/
+
+#include "events.js.c"
+#include "load.js.c"
+#include "createPool.js.c"
+#include "worker.js.c"
+#include "thread_nextTick.js.c"
+//#include "JASON.js.c"
+
+//node-waf configure uninstall distclean configure build install
+
+
+
+
+
+
+
+
+static typeQueueItem* nuJobQueueItem (void) {
+ typeQueueItem* qitem= queue_pull(freeJobsQueue);
+ if (!qitem) {
+ qitem= nuItem(kItemTypePointer, calloc(1, sizeof(typeJob)));
+ }
+ return qitem;
+}
+
+
+
+
+
+
+static typeThread* isAThread (Handle<Object> receiver) {
+ typeThread* thread;
+
+ if (receiver->IsObject()) {
+ if (receiver->InternalFieldCount() == 1) {
+ thread= (typeThread*) receiver->GetPointerFromInternalField(0);
+ if (thread && (thread->threadMagicCookie == kThreadMagicCookie)) {
+ return thread;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+
+
+
+
+static void pushToInQueue (typeQueueItem* qitem, typeThread* thread) {
+ uv_mutex_lock(&thread->IDLE_mutex);
+ queue_push(qitem, &thread->inQueue);
+ if (thread->IDLE) {
+ uv_cond_signal(&thread->IDLE_cv);
+ }
+ uv_mutex_unlock(&thread->IDLE_mutex);
+}
+
+
+
+
+
+
+static Handle<Value> Puts (const Arguments &args) {
+ //fprintf(stdout, "*** Puts BEGIN\n");
+
+ HandleScope scope;
+ int i= 0;
+ while (i < args.Length()) {
+ String::Utf8Value c_str(args[i]);
+ fputs(*c_str, stdout);
+ i++;
+ }
+ fflush(stdout);
+
+ //fprintf(stdout, "*** Puts END\n");
+ return Undefined();
+}
+
+static Handle<Value> Print (const Arguments &args) {
+ HandleScope scope;
+ int i= 0;
+ while (i < args.Length()) {
+ String::Utf8Value c_str(args[i]);
+ fputs(*c_str, stdout);
+ i++;
+ }
+ static char end = '\n';
+ fputs(&end, stdout);
+ fflush(stdout);
+
+ //fprintf(stdout, "*** Puts END\n");
+ return Undefined();
+}
+
+
+
+
+static void eventLoop (typeThread* thread);
+
+// A background thread
+#ifdef WWT_PTHREAD
+static void* aThread (void* arg) {
+#else
+static void aThread (void* arg) {
+#endif
+
+ int dummy;
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &dummy);
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &dummy);
+
+ typeThread* thread= (typeThread*) arg;
+ thread->isolate= Isolate::New();
+ thread->isolate->SetData(thread);
+
+ if (useLocker) {
+ //printf("**** USING LOCKER: YES\n");
+ v8::Locker myLocker(thread->isolate);
+ //v8::Isolate::Scope isolate_scope(thread->isolate);
+ eventLoop(thread);
+ }
+ else {
+ //printf("**** USING LOCKER: NO\n");
+ //v8::Isolate::Scope isolate_scope(thread->isolate);
+ eventLoop(thread);
+ }
+ thread->isolate->Exit();
+ thread->isolate->Dispose();
+
+ // wake up callback
+ if (!(thread->inQueue.length)) uv_async_send(&thread->async_watcher);
+#ifdef WWT_PTHREAD
+ return NULL;
+#endif
+}
+
+
+
+static Handle<Value> threadEmit (const Arguments &args);
+static Handle<Value> postMessage (const Arguments &args);
+static Handle<Value> postError (const Arguments &args);
+
+
+
+static void eventLoop (typeThread* thread) {
+ thread->isolate->Enter();
+ thread->context= Context::New();
+ thread->context->Enter();
+
+ {
+ HandleScope scope1;
+
+ Local<Object> global= thread->context->Global();
+
+ Handle<Object> fs_obj = Object::New();
+ JSObjFn(fs_obj, "readFileSync", readFileSync_);
+ global->Set(String::New("native_fs_"), fs_obj, attribute_ro_dd);
+
+ Handle<Object> console_obj = Object::New();
+ JSObjFn(console_obj, "log", console_log);
+ JSObjFn(console_obj, "error", console_error);
+ global->Set(String::New("console"), console_obj, attribute_ro_dd);
+
+ global->Set(String::NewSymbol("self"), global);
+ global->Set(String::NewSymbol("global"), global);
+
+ global->Set(String::NewSymbol("puts"), FunctionTemplate::New(Puts)->GetFunction());
+ global->Set(String::NewSymbol("print"), FunctionTemplate::New(Print)->GetFunction());
+
+ global->Set(String::NewSymbol("postMessage"), FunctionTemplate::New(postMessage)->GetFunction());
+ global->Set(String::NewSymbol("__postError"), FunctionTemplate::New(postError)->GetFunction());
+
+ Local<Object> threadObject= Object::New();
+ global->Set(String::NewSymbol("thread"), threadObject);
+
+ threadObject->Set(String::NewSymbol("id"), Number::New(thread->id));
+ threadObject->Set(String::NewSymbol("emit"), FunctionTemplate::New(threadEmit)->GetFunction());
+ Local<Object> dispatchEvents= Script::Compile(String::New(kEvents_js))->Run()->ToObject()->CallAsFunction(threadObject, 0, NULL)->ToObject();
+ Local<Object> dispatchNextTicks= Script::Compile(String::New(kThread_nextTick_js))->Run()->ToObject();
+ Local<Array> _ntq= (v8::Array*) *threadObject->Get(String::NewSymbol("_ntq"));
+
+ Script::Compile(String::New(kLoad_js))->Run();
+
+ double nextTickQueueLength= 0;
+ long int ctr= 0;
+
+ //SetFatalErrorHandler(FatalErrorCB);
+
+ while (!thread->sigkill) {
+ typeJob* job;
+ typeQueueItem* qitem;
+
+ {
+ HandleScope scope2;
+ TryCatch onError;
+ String::Utf8Value* str;
+ Local<String> source;
+ Local<Script> script;
+ Local<Value> resultado;
+
+
+ while ((qitem= queue_pull(&thread->inQueue))) {
+
+ job= (typeJob*) qitem->asPtr;
+
+ if ((++ctr) > 2e3) {
+ ctr= 0;
+ V8::IdleNotification();
+ }
+
+ if (job->jobType == kJobTypeEval) {
+ //Ejecutar un texto
+
+ if (job->typeEval.useStringObject) {
+ str= job->typeEval.scriptText_StringObject;
+ source= String::New(**str, (*str).length());
+ delete str;
+ }
+ else {
+ source= String::New(job->typeEval.scriptText_CharPtr);
+ free(job->typeEval.scriptText_CharPtr);
+ }
+
+ script= Script::New(source);
+
+ if (!onError.HasCaught()) resultado= script->Run();
+
+ if (job->typeEval.tiene_callBack) {
+ job->typeEval.error= onError.HasCaught() ? 1 : 0;
+ job->typeEval.resultado= new String::Utf8Value(job->typeEval.error ? onError.Exception() : resultado);
+ queue_push(qitem, &thread->outQueue);
+ // wake up callback
+ if (!(thread->inQueue.length)) uv_async_send(&thread->async_watcher);
+ }
+ else {
+ queue_push(qitem, freeJobsQueue);
+ }
+
+ if (onError.HasCaught()) onError.Reset();
+ }
+ else if (job->jobType == kJobTypeEvent) {
+ //Emitir evento.
+
+ Local<Value> args[2];
+ str= job->typeEvent.eventName;
+ args[0]= String::New(**str, (*str).length());
+ delete str;
+
+ Local<Array> array= Array::New(job->typeEvent.length);
+ args[1]= array;
+
+ int i= 0;
+ while (i < job->typeEvent.length) {
+ str= job->typeEvent.argumentos[i];
+ array->Set(i, String::New(**str, (*str).length()));
+ delete str;
+ i++;
+ }
+
+ free(job->typeEvent.argumentos);
+ queue_push(qitem, freeJobsQueue);
+ dispatchEvents->CallAsFunction(global, 2, args);
+ }
+ else if (job->jobType == kJobTypeEventSerialized) {
+ Local<Value> args[2];
+ str= job->typeEventSerialized.eventName;
+ args[0]= String::New(**str, (*str).length());
+ delete str;
+
+ int len = job->typeEventSerialized.length;
+ Local<Array> array= Array::New(len);
+ args[1]= array;
+
+ {
+ BSON *bson = new BSON();
+ char* data = job->typeEventSerialized.buffer;
+ size_t size = job->typeEventSerialized.bufferSize;
+ BSONDeserializer deserializer(bson, data, size);
+ Local<Object> result = deserializer.DeserializeDocument()->ToObject();
+ int i = 0; do { array->Set(i, result->Get(i)); } while (++i < len);
+ free(data);
+ }
+
+ queue_push(qitem, freeJobsQueue);
+ dispatchEvents->CallAsFunction(global, 2, args);
+ }
+ }
+
+ if (_ntq->Length()) {
+
+ if ((++ctr) > 2e3) {
+ ctr= 0;
+ V8::IdleNotification();
+ }
+
+ resultado= dispatchNextTicks->CallAsFunction(global, 0, NULL);
+ if (onError.HasCaught()) {
+ nextTickQueueLength= 1;
+ onError.Reset();
+ }
+ else {
+ nextTickQueueLength= resultado->NumberValue();
+ }
+ }
+ }
+
+ if (nextTickQueueLength || thread->inQueue.length) continue;
+ if (thread->sigkill) break;
+
+ uv_mutex_lock(&thread->IDLE_mutex);
+ if (!thread->inQueue.length) {
+ thread->IDLE= 1;
+ uv_cond_wait(&thread->IDLE_cv, &thread->IDLE_mutex);
+ thread->IDLE= 0;
+ }
+ uv_mutex_unlock(&thread->IDLE_mutex);
+ }
+ }
+
+ thread->context.Dispose();
+}
+
+
+
+
+
+
+static void destroyaThread (typeThread* thread) {
+
+ thread->sigkill= 0;
+ //TODO: hay que vaciar las colas y destruir los trabajos antes de ponerlas a NULL
+ thread->inQueue.first= thread->inQueue.last= NULL;
+ thread->outQueue.first= thread->outQueue.last= NULL;
+ thread->JSObject->SetPointerInInternalField(0, NULL);
+ thread->JSObject.Dispose();
+
+ uv_unref((uv_handle_t*)&thread->async_watcher);
+
+ if (freeThreadsQueue) {
+ queue_push(nuItem(kItemTypePointer, thread), freeThreadsQueue);
+ }
+ else {
+ free(thread);
+ }
+}
+
+
+
+
+
+
+// C callback that runs in the main nodejs thread. This is the one responsible for
+// calling the thread's JS callback.
+static void Callback (uv_async_t *watcher, int revents) {
+ typeThread* thread= (typeThread*) watcher;
+
+ if (thread->sigkill) {
+ destroyaThread(thread);
+ return;
+ }
+
+ HandleScope scope;
+ typeJob* job;
+ Local<Value> argv[2];
+ Local<Value> null= Local<Value>::New(Null());
+ typeQueueItem* qitem;
+ String::Utf8Value* str;
+
+ TryCatch onError;
+ while ((qitem= queue_pull(&thread->outQueue))) {
+ job= (typeJob*) qitem->asPtr;
+
+ if (job->jobType == kJobTypeEval) {
+
+ if (job->typeEval.tiene_callBack) {
+ str= job->typeEval.resultado;
+
+ if (job->typeEval.error) {
+ argv[0]= Exception::Error(String::New(**str, (*str).length()));
+ argv[1]= null;
+ } else {
+ argv[0]= null;
+ argv[1]= String::New(**str, (*str).length());
+ }
+ job->cb->CallAsFunction(thread->JSObject, 2, argv);
+ job->cb.Dispose();
+ job->typeEval.tiene_callBack= 0;
+
+ delete str;
+ job->typeEval.resultado= NULL;
+ }
+
+ queue_push(qitem, freeJobsQueue);
+
+ if (onError.HasCaught()) {
+ if (thread->outQueue.first) {
+ uv_async_send(&thread->async_watcher); // wake up callback again
+ }
+ node::FatalException(onError);
+ return;
+ }
+ }
+ else if (job->jobType == kJobTypeEvent) {
+
+ //fprintf(stdout, "*** Callback\n");
+
+ Local<Value> args[2];
+
+ str= job->typeEvent.eventName;
+ args[0]= String::New(**str, (*str).length());
+ delete str;
+
+ Local<Array> array= Array::New(job->typeEvent.length);
+ args[1]= array;
+
+ int i= 0;
+ while (i < job->typeEvent.length) {
+ str= job->typeEvent.argumentos[i];
+ array->Set(i, String::New(**str, (*str).length()));
+ delete str;
+ i++;
+ }
+
+ free(job->typeEvent.argumentos);
+ queue_push(qitem, freeJobsQueue);
+ thread->dispatchEvents->CallAsFunction(thread->JSObject, 2, args);
+ }
+ else if (job->jobType == kJobTypeEventSerialized) {
+ Local<Value> args[2];
+
+ str= job->typeEventSerialized.eventName;
+ args[0]= String::New(**str, (*str).length());
+ delete str;
+
+ int len = job->typeEventSerialized.length;
+ Local<Array> array= Array::New(len);
+ args[1]= array;
+
+ {
+ BSON *bson = new BSON();
+ char* data = job->typeEventSerialized.buffer;
+ size_t size = job->typeEventSerialized.bufferSize;
+ BSONDeserializer deserializer(bson, data, size);
+ Local<Object> result = deserializer.DeserializeDocument()->ToObject();
+ int i = 0; do { array->Set(i, result->Get(i)); } while (++i < len);
+ free(data);
+ }
+
+ queue_push(qitem, freeJobsQueue);
+ thread->dispatchEvents->CallAsFunction(thread->JSObject, 2, args);
+ }
+ }
+}
+
+
+
+
+
+
+// unconditionally destroys a thread by brute force.
+static Handle<Value> Destroy (const Arguments &args) {
+ HandleScope scope;
+ //TODO: Hay que comprobar que this en un objeto y que tiene hiddenRefTotypeThread_symbol y que no es nil
+ //TODO: Aquí habría que usar static void TerminateExecution(int thread_id);
+ //TODO: static void v8::V8::TerminateExecution ( Isolate * isolate= NULL ) [static]
+
+ typeThread* thread= isAThread(args.This());
+ if (!thread) {
+ return ThrowException(Exception::TypeError(String::New("thread.destroy(): the receiver must be a thread object")));
+ }
+
+ if (!thread->sigkill) {
+ //pthread_cancel(thread->thread);
+ thread->sigkill= 1;
+ uv_mutex_lock(&thread->IDLE_mutex);
+ if (thread->IDLE) {
+ uv_cond_signal(&thread->IDLE_cv);
+ }
+ uv_mutex_unlock(&thread->IDLE_mutex);
+ }
+
+ return Undefined();
+}
+
+
+
+
+
+
+// Eval: Pushes a job into the thread's ->inQueue.
+static Handle<Value> Eval (const Arguments &args) {
+ HandleScope scope;
+
+ if (!args.Length()) {
+ return ThrowException(Exception::TypeError(String::New("thread.eval(program [,callback]): missing arguments")));
+ }
+
+ typeThread* thread= isAThread(args.This());
+ if (!thread) {
+ return ThrowException(Exception::TypeError(String::New("thread.eval(): the receiver must be a thread object")));
+ }
+
+ typeQueueItem* qitem= nuJobQueueItem();
+ typeJob* job= (typeJob*) qitem->asPtr;
+
+ job->typeEval.tiene_callBack= ((args.Length() > 1) && (args[1]->IsFunction()));
+ if (job->typeEval.tiene_callBack) {
+ job->cb= Persistent<Object>::New(args[1]->ToObject());
+ }
+ job->typeEval.scriptText_StringObject= new String::Utf8Value(args[0]);
+ job->typeEval.useStringObject= 1;
+ job->jobType= kJobTypeEval;
+
+ pushToInQueue(qitem, thread);
+ return scope.Close(args.This());
+}
+
+
+
+
+
+static char* readFile (Handle<String> path) {
+ v8::String::Utf8Value c_str(path);
+ FILE* fp= fopen(*c_str, "rb");
+ if (!fp) {
+ fprintf(stderr, "Error opening the file %s\n", *c_str);
+ //@bruno: Shouldn't we throw, here ?
+ return NULL;
+ }
+ fseek(fp, 0, SEEK_END);
+ size_t len= ftell(fp);
+ rewind(fp); //fseek(fp, 0, SEEK_SET);
+ char *buf= (char*)malloc((len+1) * sizeof(char)); // +1 to get null terminated string
+ if (fread(buf, sizeof(char), len, fp) < len) {
+ fprintf(stderr, "Error reading the file %s\n", *c_str);
+ return NULL;
+ }
+ buf[len] = 0;
+ fclose(fp);
+ /*
+ printf("SOURCE:\n%s\n", buf);
+ fflush(stdout);
+ */
+ return buf;
+}
+
+
+
+
+
+
+// Load: Loads from file and passes to Eval
+static Handle<Value> Load (const Arguments &args) {
+ HandleScope scope;
+
+ if (!args.Length()) {
+ return ThrowException(Exception::TypeError(String::New("thread.load(filename [,callback]): missing arguments")));
+ }
+
+ typeThread* thread= isAThread(args.This());
+ if (!thread) {
+ return ThrowException(Exception::TypeError(String::New("thread.load(): the receiver must be a thread object")));
+ }
+
+ char* source= readFile(args[0]->ToString()); //@Bruno: here we don't know if the file was not found or if it was an empty file
+ if (!source) return scope.Close(args.This()); //@Bruno: even if source is empty, we should call the callback ?
+
+ typeQueueItem* qitem= nuJobQueueItem();
+ typeJob* job= (typeJob*) qitem->asPtr;
+
+ job->typeEval.tiene_callBack= ((args.Length() > 1) && (args[1]->IsFunction()));
+ if (job->typeEval.tiene_callBack) {
+ job->cb= Persistent<Object>::New(args[1]->ToObject());
+ }
+ job->typeEval.scriptText_CharPtr= source;
+ job->typeEval.useStringObject= 0;
+ job->jobType= kJobTypeEval;
+
+ pushToInQueue(qitem, thread);
+
+ return scope.Close(args.This());
+}
+
+
+
+
+
+
+static Handle<Value> processEmit (const Arguments &args) {
+ HandleScope scope;
+
+ //fprintf(stdout, "*** processEmit\n");
+
+ if (!args.Length()) return scope.Close(args.This());
+
+ typeThread* thread= isAThread(args.This());
+ if (!thread) {
+ return ThrowException(Exception::TypeError(String::New("thread.emit(): the receiver must be a thread object")));
+ }
+
+ typeQueueItem* qitem= nuJobQueueItem();
+ typeJob* job= (typeJob*) qitem->asPtr;
+
+ job->jobType= kJobTypeEvent;
+ job->typeEvent.length= args.Length()- 1;
+ job->typeEvent.eventName= new String::Utf8Value(args[0]);
+ job->typeEvent.argumentos= (v8::String::Utf8Value**) malloc(job->typeEvent.length* sizeof(void*));
+
+ int i= 1;
+ do {
+ job->typeEvent.argumentos[i-1]= new String::Utf8Value(args[i]);
+ } while (++i <= job->typeEvent.length);
+
+ pushToInQueue(qitem, thread);
+
+ return scope.Close(args.This());
+}
+
+static Handle<Value> processEmitSerialized (const Arguments &args) {
+ HandleScope scope;
+
+ //fprintf(stdout, "*** processEmit\n");
+ int len = args.Length();
+
+ if (!len) return scope.Close(args.This());
+
+ typeThread* thread= isAThread(args.This());
+ if (!thread) {
+ return ThrowException(Exception::TypeError(String::New("thread.emit(): the receiver must be a thread object")));
+ }
+
+ typeQueueItem* qitem= nuJobQueueItem();
+ typeJob* job= (typeJob*) qitem->asPtr;
+
+ job->jobType= kJobTypeEventSerialized;
+ job->typeEventSerialized.length= len-1;
+ job->typeEventSerialized.eventName= new String::Utf8Value(args[0]);
+ Local<Array> array= Array::New(len-1);
+ int i = 1; do { array->Set(i-1, args[i]); } while (++i < len);
+
+ {
+ char* buffer;
+ BSON *bson = new BSON();
+ size_t object_size;
+ Local<Object> object = bson->GetSerializeObject(array);
+ BSONSerializer<CountStream> counter(bson, false, false);
+ counter.SerializeDocument(object);
+ object_size = counter.GetSerializeSize();
+ buffer = (char *)malloc(object_size);
+ BSONSerializer<DataStream> data(bson, false, false, buffer);
+ data.SerializeDocument(object);
+ job->typeEventSerialized.buffer= buffer;
+ job->typeEventSerialized.bufferSize= object_size;
+ }
+
+ pushToInQueue(qitem, thread);
+
+ return scope.Close(args.This());
+}
+
+#define POST_EVENT(eventname) { \
+ HandleScope scope; \
+ int len = args.Length(); \
+ \
+ if (!len) return scope.Close(args.This()); \
+ \
+ typeThread* thread= (typeThread*) Isolate::GetCurrent()->GetData(); \
+ \
+ typeQueueItem* qitem= nuJobQueueItem(); \
+ typeJob* job= (typeJob*) qitem->asPtr; \
+ \
+ job->jobType= kJobTypeEventSerialized; \
+ job->typeEventSerialized.eventName= new String::Utf8Value(String::New(eventname)); \
+ job->typeEventSerialized.length= len; \
+ \
+ Local<Array> array= Array::New(len); \
+ int i = 0; do { array->Set(i, args[i]); } while (++i < len); \
+ \
+ { \
+ char* buffer; \
+ BSON *bson = new BSON(); \
+ size_t object_size; \
+ Local<Object> object = bson->GetSerializeObject(array); \
+ BSONSerializer<CountStream> counter(bson, false, false); \
+ counter.SerializeDocument(object); \
+ object_size = counter.GetSerializeSize(); \
+ buffer = (char *)malloc(object_size); \
+ BSONSerializer<DataStream> data(bson, false, false, buffer); \
+ data.SerializeDocument(object); \
+ job->typeEventSerialized.buffer= buffer; \
+ job->typeEventSerialized.bufferSize= object_size; \
+ } \
+ \
+ queue_push(qitem, &thread->outQueue); \
+ if (!(thread->inQueue.length)) uv_async_send(&thread->async_watcher); \
+ \
+ return scope.Close(args.This()); \
+}
+
+static Handle<Value> postMessage (const Arguments &args) {
+ POST_EVENT("message");
+}
+
+static Handle<Value> postError (const Arguments &args) {
+ POST_EVENT("error");
+}
+
+static Handle<Value> threadEmit (const Arguments &args) {
+ HandleScope scope;
+
+ //fprintf(stdout, "*** threadEmit\n");
+
+ if (!args.Length()) return scope.Close(args.This());
+
+ int i;
+ typeThread* thread= (typeThread*) Isolate::GetCurrent()->GetData();
+
+ typeQueueItem* qitem= nuJobQueueItem();
+ typeJob* job= (typeJob*) qitem->asPtr;
+
+ job->jobType= kJobTypeEvent;
+ job->typeEvent.length= args.Length()- 1;
+ job->typeEvent.eventName= new String::Utf8Value(args[0]);
+ job->typeEvent.argumentos= (v8::String::Utf8Value**) malloc(job->typeEvent.length* sizeof(void*));
+
+ i= 1;
+ do {
+ job->typeEvent.argumentos[i-1]= new String::Utf8Value(args[i]);
+ } while (++i <= job->typeEvent.length);
+
+ queue_push(qitem, &thread->outQueue);
+ if (!(thread->inQueue.length)) uv_async_send(&thread->async_watcher); // wake up callback
+
+ //fprintf(stdout, "*** threadEmit END\n");
+
+ return scope.Close(args.This());
+}
+
+
+
+
+
+
+
+
+// Creates and launches a new isolate in a new background thread.
+static Handle<Value> Create (const Arguments &args) {
+ HandleScope scope;
+
+ typeThread* thread;
+ typeQueueItem* qitem= NULL;
+ qitem= queue_pull(freeThreadsQueue);
+ if (qitem) {
+ thread= (typeThread*) qitem->asPtr;
+ destroyItem(qitem);
+ }
+ else {
+ thread= (typeThread*) calloc(1, sizeof(typeThread));
+ thread->threadMagicCookie= kThreadMagicCookie;
+ }
+
+ static long int threadsCtr= 0;
+ thread->id= threadsCtr++;
+
+ thread->JSObject= Persistent<Object>::New(threadTemplate->NewInstance());
+ thread->JSObject->Set(id_symbol, Integer::New(thread->id));
+ thread->JSObject->SetPointerInInternalField(0, thread);
+ Local<Value> dispatchEvents= Script::Compile(String::New(kEvents_js))->Run()->ToObject()->CallAsFunction(thread->JSObject, 0, NULL);
+ thread->dispatchEvents= Persistent<Object>::New(dispatchEvents->ToObject());
+
+ uv_async_init(uv_default_loop(), &thread->async_watcher, Callback);
+ uv_ref((uv_handle_t*)&thread->async_watcher);
+
+ uv_cond_init(&thread->IDLE_cv);
+ uv_mutex_init(&thread->IDLE_mutex);
+ uv_mutex_init(&thread->inQueue.queueLock);
+ uv_mutex_init(&thread->outQueue.queueLock);
+
+#ifdef WWT_PTHREAD
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ int err= pthread_create(&thread->thread, &attr, aThread, thread);
+ pthread_attr_destroy(&attr);
+#else
+ int err= uv_thread_create(&thread->thread, aThread, thread);
+#endif
+ if (err) {
+ //Ha habido un error no se ha arrancado esta thread
+ destroyaThread(thread);
+ return ThrowException(Exception::TypeError(String::New("create(): error in pthread_create()")));
+ }
+
+ V8::AdjustAmountOfExternalAllocatedMemory(sizeof(typeThread)); //OJO V8 con V mayúscula.
+ return scope.Close(thread->JSObject);
+}
+
+
+#if NODE_MODULE_VERSION >= 0x000B
+void Init (Handle<Object> target, Handle<Value> module) {
+#else
+void Init (Handle<Object> target) {
+#endif
+
+ initQueues();
+ freeThreadsQueue= nuQueue(-3);
+ freeJobsQueue= nuQueue(-4);
+
+ HandleScope scope;
+
+ useLocker= v8::Locker::IsActive();
+
+ target->Set(String::NewSymbol("create"), FunctionTemplate::New(Create)->GetFunction());
+ target->Set(String::NewSymbol("createPool"), Script::Compile(String::New(kCreatePool_js))->Run()->ToObject());
+ target->Set(String::NewSymbol("Worker"), Script::Compile(String::New(kWorker_js))->Run()->ToObject()->CallAsFunction(target, 0, NULL)->ToObject());
+ //target->Set(String::NewSymbol("JASON"), Script::Compile(String::New(kJASON_js))->Run()->ToObject());
+
+ id_symbol= Persistent<String>::New(String::NewSymbol("id"));
+
+ threadTemplate= Persistent<ObjectTemplate>::New(ObjectTemplate::New());
+ threadTemplate->SetInternalFieldCount(1);
+ threadTemplate->Set(id_symbol, Integer::New(0));
+ threadTemplate->Set(String::NewSymbol("eval"), FunctionTemplate::New(Eval));
+ threadTemplate->Set(String::NewSymbol("load"), FunctionTemplate::New(Load));
+ threadTemplate->Set(String::NewSymbol("emit"), FunctionTemplate::New(processEmit));
+ threadTemplate->Set(String::NewSymbol("emitSerialized"), FunctionTemplate::New(processEmitSerialized));
+ threadTemplate->Set(String::NewSymbol("destroy"), FunctionTemplate::New(Destroy));
+
+}
+
+
+
+
+NODE_MODULE(WebWorkerThreads, Init)
+
+/*
+gcc -E -I /Users/jorge/JAVASCRIPT/binarios/include/node -o /o.c /Users/jorge/JAVASCRIPT/threads_a_gogo/src/threads_a_gogo.cc && mate /o.c
+*/
diff --git a/node_modules/webworker-threads/src/bson.cc b/node_modules/webworker-threads/src/bson.cc
new file mode 100644
index 0000000..accf8da
--- /dev/null
+++ b/node_modules/webworker-threads/src/bson.cc
@@ -0,0 +1,1016 @@
+//===========================================================================
+
+#include <stdarg.h>
+#include <cstdlib>
+#include <cstring>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+#endif
+
+#include <v8.h>
+
+// this and the above block must be around the v8.h header otherwise
+// v8 is not happy
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <node.h>
+#include <node_version.h>
+#include <node_buffer.h>
+
+#include <cmath>
+#include <iostream>
+#include <limits>
+#include <vector>
+
+#include "bson.h"
+
+using namespace v8;
+using namespace node;
+
+//===========================================================================
+
+void DataStream::WriteObjectId(const Handle<Object>& object, const Handle<String>& key)
+{
+ uint16_t buffer[12];
+ object->Get(key)->ToString()->Write(buffer, 0, 12);
+ for(uint32_t i = 0; i < 12; ++i)
+ {
+ *p++ = (char) buffer[i];
+ }
+}
+
+void ThrowAllocatedStringException(size_t allocationSize, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ char* string = (char*) malloc(allocationSize);
+ vsprintf(string, format, args);
+ va_end(args);
+
+ throw string;
+}
+
+void DataStream::CheckKey(const Local<String>& keyName)
+{
+ size_t keyLength = keyName->Utf8Length();
+ if(keyLength == 0) return;
+
+ char* keyStringBuffer = (char*) alloca(keyLength+1);
+ keyName->WriteUtf8(keyStringBuffer);
+
+ if(keyStringBuffer[0] == '$')
+ {
+ ThrowAllocatedStringException(64+keyLength, "key %s must not start with '$'", keyStringBuffer);
+ }
+
+ if(strchr(keyStringBuffer, '.') != NULL)
+ {
+ ThrowAllocatedStringException(64+keyLength, "key %s must not contain '.'", keyStringBuffer);
+ }
+}
+
+template<typename T> void BSONSerializer<T>::SerializeDocument(const Handle<Value>& value)
+{
+ void* documentSize = this->BeginWriteSize();
+ Local<Object> object = bson->GetSerializeObject(value);
+
+ // Get the object property names
+ #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 6
+ Local<Array> propertyNames = object->GetPropertyNames();
+ #else
+ Local<Array> propertyNames = object->GetOwnPropertyNames();
+ #endif
+
+ // Length of the property
+ int propertyLength = propertyNames->Length();
+ for(int i = 0; i < propertyLength; ++i)
+ {
+ const Local<String>& propertyName = propertyNames->Get(i)->ToString();
+ if(checkKeys) this->CheckKey(propertyName);
+
+ const Local<Value>& propertyValue = object->Get(propertyName);
+
+ if(serializeFunctions || !propertyValue->IsFunction())
+ {
+ void* typeLocation = this->BeginWriteType();
+ this->WriteString(propertyName);
+ SerializeValue(typeLocation, propertyValue);
+ }
+ }
+
+ this->WriteByte(0);
+ this->CommitSize(documentSize);
+}
+
+template<typename T> void BSONSerializer<T>::SerializeArray(const Handle<Value>& value)
+{
+ void* documentSize = this->BeginWriteSize();
+
+ Local<Array> array = Local<Array>::Cast(value->ToObject());
+ uint32_t arrayLength = array->Length();
+
+ for(uint32_t i = 0; i < arrayLength; ++i)
+ {
+ void* typeLocation = this->BeginWriteType();
+ this->WriteUInt32String(i);
+ SerializeValue(typeLocation, array->Get(i));
+ }
+
+ this->WriteByte(0);
+ this->CommitSize(documentSize);
+}
+
+// This is templated so that we can use this function to both count the number of bytes, and to serialize those bytes.
+// The template approach eliminates almost all of the inspection of values unless they're required (eg. string lengths)
+// and ensures that there is always consistency between bytes counted and bytes written by design.
+template<typename T> void BSONSerializer<T>::SerializeValue(void* typeLocation, const Handle<Value>& value)
+{
+ if(value->IsNumber())
+ {
+ double doubleValue = value->NumberValue();
+ int intValue = (int) doubleValue;
+ if(intValue == doubleValue)
+ {
+ this->CommitType(typeLocation, BSON_TYPE_INT);
+ this->WriteInt32(intValue);
+ }
+ else
+ {
+ this->CommitType(typeLocation, BSON_TYPE_NUMBER);
+ this->WriteDouble(doubleValue);
+ }
+ }
+ else if(value->IsString())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_STRING);
+ this->WriteLengthPrefixedString(value->ToString());
+ }
+ else if(value->IsBoolean())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_BOOLEAN);
+ this->WriteBool(value);
+ }
+ else if(value->IsArray())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_ARRAY);
+ SerializeArray(value);
+ }
+ else if(value->IsDate())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_DATE);
+ this->WriteInt64(value);
+ }
+ else if(value->IsRegExp())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_REGEXP);
+ const Handle<RegExp>& regExp = Handle<RegExp>::Cast(value);
+
+ this->WriteString(regExp->GetSource());
+
+ int flags = regExp->GetFlags();
+ if(flags & RegExp::kGlobal) this->WriteByte('s');
+ if(flags & RegExp::kIgnoreCase) this->WriteByte('i');
+ if(flags & RegExp::kMultiline) this->WriteByte('m');
+ this->WriteByte(0);
+ }
+ else if(value->IsFunction())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_CODE);
+ this->WriteLengthPrefixedString(value->ToString());
+ }
+ else if(value->IsObject())
+ {
+ const Local<Object>& object = value->ToObject();
+ if(object->Has(bson->_bsontypeString))
+ {
+ const Local<String>& constructorString = object->GetConstructorName();
+ if(bson->longString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_LONG);
+ this->WriteInt32(object, bson->_longLowString);
+ this->WriteInt32(object, bson->_longHighString);
+ }
+ else if(bson->timestampString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_TIMESTAMP);
+ this->WriteInt32(object, bson->_longLowString);
+ this->WriteInt32(object, bson->_longHighString);
+ }
+ else if(bson->objectIDString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_OID);
+ this->WriteObjectId(object, bson->_objectIDidString);
+ }
+ else if(bson->binaryString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_BINARY);
+
+ uint32_t length = object->Get(bson->_binaryPositionString)->Uint32Value();
+ Local<Object> bufferObj = object->Get(bson->_binaryBufferString)->ToObject();
+
+ this->WriteInt32(length);
+ this->WriteByte(object, bson->_binarySubTypeString); // write subtype
+ this->WriteData(Buffer::Data(bufferObj), length);
+ }
+ else if(bson->doubleString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_NUMBER);
+ this->WriteDouble(object, bson->_doubleValueString);
+ }
+ else if(bson->symbolString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_SYMBOL);
+ this->WriteLengthPrefixedString(object->Get(bson->_symbolValueString)->ToString());
+ }
+ else if(bson->codeString->StrictEquals(constructorString))
+ {
+ const Local<String>& function = object->Get(bson->_codeCodeString)->ToString();
+ const Local<Object>& scope = object->Get(bson->_codeScopeString)->ToObject();
+
+ // For Node < 0.6.X use the GetPropertyNames
+ #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 6
+ uint32_t propertyNameLength = scope->GetPropertyNames()->Length();
+ #else
+ uint32_t propertyNameLength = scope->GetOwnPropertyNames()->Length();
+ #endif
+
+ if(propertyNameLength > 0)
+ {
+ this->CommitType(typeLocation, BSON_TYPE_CODE_W_SCOPE);
+ void* codeWidthScopeSize = this->BeginWriteSize();
+ this->WriteLengthPrefixedString(function->ToString());
+ SerializeDocument(scope);
+ this->CommitSize(codeWidthScopeSize);
+ }
+ else
+ {
+ this->CommitType(typeLocation, BSON_TYPE_CODE);
+ this->WriteLengthPrefixedString(function->ToString());
+ }
+ }
+ else if(bson->dbrefString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_OBJECT);
+
+ void* dbRefSize = this->BeginWriteSize();
+
+ void* refType = this->BeginWriteType();
+ this->WriteData("$ref", 5);
+ SerializeValue(refType, object->Get(bson->_dbRefNamespaceString));
+
+ void* idType = this->BeginWriteType();
+ this->WriteData("$id", 4);
+ SerializeValue(idType, object->Get(bson->_dbRefOidString));
+
+ const Local<Value>& refDbValue = object->Get(bson->_dbRefDbString);
+ if(!refDbValue->IsUndefined())
+ {
+ void* dbType = this->BeginWriteType();
+ this->WriteData("$db", 4);
+ SerializeValue(dbType, refDbValue);
+ }
+
+ this->WriteByte(0);
+ this->CommitSize(dbRefSize);
+ }
+ else if(bson->minKeyString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_MIN_KEY);
+ }
+ else if(bson->maxKeyString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_MAX_KEY);
+ }
+ }
+ else if(Buffer::HasInstance(value))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_BINARY);
+
+ #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
+ Buffer *buffer = ObjectWrap::Unwrap<Buffer>(value->ToObject());
+ uint32_t length = object->length();
+ #else
+ uint32_t length = Buffer::Length(value->ToObject());
+ #endif
+
+ this->WriteInt32(length);
+ this->WriteByte(0);
+ this->WriteData(Buffer::Data(value->ToObject()), length);
+ }
+ else
+ {
+ this->CommitType(typeLocation, BSON_TYPE_OBJECT);
+ SerializeDocument(value);
+ }
+ }
+ else if(value->IsNull() || value->IsUndefined())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_NULL);
+ }
+}
+
+// Data points to start of element list, length is length of entire document including '\0' but excluding initial size
+BSONDeserializer::BSONDeserializer(BSON* aBson, char* data, size_t length)
+: bson(aBson),
+ pStart(data),
+ p(data),
+ pEnd(data + length - 1)
+{
+ if(*pEnd != '\0') ThrowAllocatedStringException(64, "Missing end of document marker '\\0'");
+}
+
+BSONDeserializer::BSONDeserializer(BSONDeserializer& parentSerializer, size_t length)
+: bson(parentSerializer.bson),
+ pStart(parentSerializer.p),
+ p(parentSerializer.p),
+ pEnd(parentSerializer.p + length - 1)
+{
+ parentSerializer.p += length;
+ if(pEnd > parentSerializer.pEnd) ThrowAllocatedStringException(64, "Child document exceeds parent's bounds");
+ if(*pEnd != '\0') ThrowAllocatedStringException(64, "Missing end of document marker '\\0'");
+}
+
+Local<String> BSONDeserializer::ReadCString()
+{
+ char* start = p;
+ while(*p++) { }
+ return String::New(start, (int32_t) (p-start-1) );
+}
+
+int32_t BSONDeserializer::ReadRegexOptions()
+{
+ int32_t options = 0;
+ for(;;)
+ {
+ switch(*p++)
+ {
+ case '\0': return options;
+ case 's': options |= RegExp::kGlobal; break;
+ case 'i': options |= RegExp::kIgnoreCase; break;
+ case 'm': options |= RegExp::kMultiline; break;
+ }
+ }
+}
+
+uint32_t BSONDeserializer::ReadIntegerString()
+{
+ uint32_t value = 0;
+ while(*p)
+ {
+ if(*p < '0' || *p > '9') ThrowAllocatedStringException(64, "Invalid key for array");
+ value = value * 10 + *p++ - '0';
+ }
+ ++p;
+ return value;
+}
+
+Local<String> BSONDeserializer::ReadString()
+{
+ uint32_t length = ReadUInt32();
+ char* start = p;
+ p += length;
+ return String::New(start, length-1);
+}
+
+Local<String> BSONDeserializer::ReadObjectId()
+{
+ uint16_t objectId[12];
+ for(size_t i = 0; i < 12; ++i)
+ {
+ objectId[i] = *reinterpret_cast<unsigned char*>(p++);
+ }
+ return String::New(objectId, 12);
+}
+
+Handle<Value> BSONDeserializer::DeserializeDocument()
+{
+ uint32_t length = ReadUInt32();
+ if(length < 5) ThrowAllocatedStringException(64, "Bad BSON: Document is less than 5 bytes");
+
+ BSONDeserializer documentDeserializer(*this, length-4);
+ return documentDeserializer.DeserializeDocumentInternal();
+}
+
+Handle<Value> BSONDeserializer::DeserializeDocumentInternal()
+{
+ Local<Object> returnObject = Object::New();
+
+ while(HasMoreData())
+ {
+ BsonType type = (BsonType) ReadByte();
+ const Local<String>& name = ReadCString();
+ const Handle<Value>& value = DeserializeValue(type);
+ returnObject->ForceSet(name, value);
+ }
+ if(p != pEnd) ThrowAllocatedStringException(64, "Bad BSON Document: Serialize consumed unexpected number of bytes");
+
+ // From JavaScript:
+ // if(object['$id'] != null) object = new DBRef(object['$ref'], object['$id'], object['$db']);
+ if(returnObject->Has(bson->_dbRefIdRefString))
+ {
+ Local<Value> argv[] = { returnObject->Get(bson->_dbRefRefString), returnObject->Get(bson->_dbRefIdRefString), returnObject->Get(bson->_dbRefDbRefString) };
+ return bson->dbrefConstructor->NewInstance(3, argv);
+ }
+ else
+ {
+ return returnObject;
+ }
+}
+
+Handle<Value> BSONDeserializer::DeserializeArray()
+{
+ uint32_t length = ReadUInt32();
+ if(length < 5) ThrowAllocatedStringException(64, "Bad BSON: Array Document is less than 5 bytes");
+
+ BSONDeserializer documentDeserializer(*this, length-4);
+ return documentDeserializer.DeserializeArrayInternal();
+}
+
+Handle<Value> BSONDeserializer::DeserializeArrayInternal()
+{
+ Local<Array> returnArray = Array::New();
+
+ while(HasMoreData())
+ {
+ BsonType type = (BsonType) ReadByte();
+ uint32_t index = ReadIntegerString();
+ const Handle<Value>& value = DeserializeValue(type);
+ returnArray->Set(index, value);
+ }
+ if(p != pEnd) ThrowAllocatedStringException(64, "Bad BSON Array: Serialize consumed unexpected number of bytes");
+
+ return returnArray;
+}
+
+Handle<Value> BSONDeserializer::DeserializeValue(BsonType type)
+{
+ switch(type)
+ {
+ case BSON_TYPE_STRING:
+ return ReadString();
+
+ case BSON_TYPE_INT:
+ return Integer::New(ReadInt32());
+
+ case BSON_TYPE_NUMBER:
+ return Number::New(ReadDouble());
+
+ case BSON_TYPE_NULL:
+ return Null();
+
+ case BSON_TYPE_UNDEFINED:
+ return Undefined();
+
+ case BSON_TYPE_TIMESTAMP:
+ {
+ int32_t lowBits = ReadInt32();
+ int32_t highBits = ReadInt32();
+ Local<Value> argv[] = { Int32::New(lowBits), Int32::New(highBits) };
+ return bson->timestampConstructor->NewInstance(2, argv);
+ }
+
+ case BSON_TYPE_BOOLEAN:
+ return (ReadByte() != 0) ? True() : False();
+
+ case BSON_TYPE_REGEXP:
+ {
+ const Local<String>& regex = ReadCString();
+ int32_t options = ReadRegexOptions();
+ return RegExp::New(regex, (RegExp::Flags) options);
+ }
+
+ case BSON_TYPE_CODE:
+ {
+ const Local<Value>& code = ReadString();
+ const Local<Value>& scope = Object::New();
+ Local<Value> argv[] = { code, scope };
+ return bson->codeConstructor->NewInstance(2, argv);
+ }
+
+ case BSON_TYPE_CODE_W_SCOPE:
+ {
+ ReadUInt32();
+ const Local<Value>& code = ReadString();
+ const Handle<Value>& scope = DeserializeDocument();
+ Local<Value> argv[] = { code, scope->ToObject() };
+ return bson->codeConstructor->NewInstance(2, argv);
+ }
+
+ case BSON_TYPE_OID:
+ {
+ Local<Value> argv[] = { ReadObjectId() };
+ return bson->objectIDConstructor->NewInstance(1, argv);
+ }
+
+ case BSON_TYPE_BINARY:
+ {
+ uint32_t length = ReadUInt32();
+ uint32_t subType = ReadByte();
+ Buffer* buffer = Buffer::New(p, length);
+ p += length;
+
+ Handle<Value> argv[] = { buffer->handle_, Uint32::New(subType) };
+ return bson->binaryConstructor->NewInstance(2, argv);
+ }
+
+ case BSON_TYPE_LONG:
+ {
+ // Read 32 bit integers
+ int32_t lowBits = (int32_t) ReadInt32();
+ int32_t highBits = (int32_t) ReadInt32();
+
+ // If value is < 2^53 and >-2^53
+ if((highBits < 0x200000 || (highBits == 0x200000 && lowBits == 0)) && highBits >= -0x200000) {
+ // Adjust the pointer and read as 64 bit value
+ p -= 8;
+ // Read the 64 bit value
+ int64_t finalValue = (int64_t) ReadInt64();
+ return Number::New(finalValue);
+ }
+
+ Local<Value> argv[] = { Int32::New(lowBits), Int32::New(highBits) };
+ return bson->longConstructor->NewInstance(2, argv);
+ }
+
+ case BSON_TYPE_DATE:
+ return Date::New((double) ReadInt64());
+
+ case BSON_TYPE_ARRAY:
+ return DeserializeArray();
+
+ case BSON_TYPE_OBJECT:
+ return DeserializeDocument();
+
+ case BSON_TYPE_SYMBOL:
+ {
+ const Local<String>& string = ReadString();
+ Local<Value> argv[] = { string };
+ return bson->symbolConstructor->NewInstance(1, argv);
+ }
+
+ case BSON_TYPE_MIN_KEY:
+ return bson->minKeyConstructor->NewInstance();
+
+ case BSON_TYPE_MAX_KEY:
+ return bson->maxKeyConstructor->NewInstance();
+
+ default:
+ ThrowAllocatedStringException(64, "Unhandled BSON Type: %d", type);
+ }
+
+ return v8::Null();
+}
+
+
+static Handle<Value> VException(const char *msg)
+{
+ HandleScope scope;
+ return ThrowException(Exception::Error(String::New(msg)));
+}
+
+Persistent<FunctionTemplate> BSON::constructor_template;
+
+BSON::BSON() : ObjectWrap()
+{
+ // Setup pre-allocated comparision objects
+ _bsontypeString = Persistent<String>::New(String::New("_bsontype"));
+ _longLowString = Persistent<String>::New(String::New("low_"));
+ _longHighString = Persistent<String>::New(String::New("high_"));
+ _objectIDidString = Persistent<String>::New(String::New("id"));
+ _binaryPositionString = Persistent<String>::New(String::New("position"));
+ _binarySubTypeString = Persistent<String>::New(String::New("sub_type"));
+ _binaryBufferString = Persistent<String>::New(String::New("buffer"));
+ _doubleValueString = Persistent<String>::New(String::New("value"));
+ _symbolValueString = Persistent<String>::New(String::New("value"));
+ _dbRefRefString = Persistent<String>::New(String::New("$ref"));
+ _dbRefIdRefString = Persistent<String>::New(String::New("$id"));
+ _dbRefDbRefString = Persistent<String>::New(String::New("$db"));
+ _dbRefNamespaceString = Persistent<String>::New(String::New("namespace"));
+ _dbRefDbString = Persistent<String>::New(String::New("db"));
+ _dbRefOidString = Persistent<String>::New(String::New("oid"));
+ _codeCodeString = Persistent<String>::New(String::New("code"));
+ _codeScopeString = Persistent<String>::New(String::New("scope"));
+ _toBSONString = Persistent<String>::New(String::New("toBSON"));
+
+ longString = Persistent<String>::New(String::New("Long"));
+ objectIDString = Persistent<String>::New(String::New("ObjectID"));
+ binaryString = Persistent<String>::New(String::New("Binary"));
+ codeString = Persistent<String>::New(String::New("Code"));
+ dbrefString = Persistent<String>::New(String::New("DBRef"));
+ symbolString = Persistent<String>::New(String::New("Symbol"));
+ doubleString = Persistent<String>::New(String::New("Double"));
+ timestampString = Persistent<String>::New(String::New("Timestamp"));
+ minKeyString = Persistent<String>::New(String::New("MinKey"));
+ maxKeyString = Persistent<String>::New(String::New("MaxKey"));
+}
+
+void BSON::Initialize(v8::Handle<v8::Object> target)
+{
+ // Grab the scope of the call from Node
+ HandleScope scope;
+ // Define a new function template
+ Local<FunctionTemplate> t = FunctionTemplate::New(New);
+ constructor_template = Persistent<FunctionTemplate>::New(t);
+ constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
+ constructor_template->SetClassName(String::NewSymbol("BSON"));
+
+ // Instance methods
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "calculateObjectSize", CalculateObjectSize);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "serialize", BSONSerialize);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "serializeWithBufferAndIndex", SerializeWithBufferAndIndex);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "deserialize", BSONDeserialize);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "deserializeStream", BSONDeserializeStream);
+
+ target->ForceSet(String::NewSymbol("BSON"), constructor_template->GetFunction());
+}
+
+// Create a new instance of BSON and passing it the existing context
+Handle<Value> BSON::New(const Arguments &args)
+{
+ HandleScope scope;
+
+ // Check that we have an array
+ if(args.Length() == 1 && args[0]->IsArray())
+ {
+ // Cast the array to a local reference
+ Local<Array> array = Local<Array>::Cast(args[0]);
+
+ if(array->Length() > 0)
+ {
+ // Create a bson object instance and return it
+ BSON *bson = new BSON();
+
+ uint32_t foundClassesMask = 0;
+
+ // Iterate over all entries to save the instantiate funtions
+ for(uint32_t i = 0; i < array->Length(); i++)
+ {
+ // Let's get a reference to the function
+ Local<Function> func = Local<Function>::Cast(array->Get(i));
+ Local<String> functionName = func->GetName()->ToString();
+
+ // Save the functions making them persistant handles (they don't get collected)
+ if(functionName->StrictEquals(bson->longString))
+ {
+ bson->longConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 1;
+ }
+ else if(functionName->StrictEquals(bson->objectIDString))
+ {
+ bson->objectIDConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 2;
+ }
+ else if(functionName->StrictEquals(bson->binaryString))
+ {
+ bson->binaryConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 4;
+ }
+ else if(functionName->StrictEquals(bson->codeString))
+ {
+ bson->codeConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 8;
+ }
+ else if(functionName->StrictEquals(bson->dbrefString))
+ {
+ bson->dbrefConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 0x10;
+ }
+ else if(functionName->StrictEquals(bson->symbolString))
+ {
+ bson->symbolConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 0x20;
+ }
+ else if(functionName->StrictEquals(bson->doubleString))
+ {
+ bson->doubleConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 0x40;
+ }
+ else if(functionName->StrictEquals(bson->timestampString))
+ {
+ bson->timestampConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 0x80;
+ }
+ else if(functionName->StrictEquals(bson->minKeyString))
+ {
+ bson->minKeyConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 0x100;
+ }
+ else if(functionName->StrictEquals(bson->maxKeyString))
+ {
+ bson->maxKeyConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 0x200;
+ }
+ }
+
+ // Check if we have the right number of constructors otherwise throw an error
+ if(foundClassesMask != 0x3ff)
+ {
+ delete bson;
+ return VException("Missing function constructor for either [Long/ObjectID/Binary/Code/DbRef/Symbol/Double/Timestamp/MinKey/MaxKey]");
+ }
+ else
+ {
+ bson->Wrap(args.This());
+ return args.This();
+ }
+ }
+ else
+ {
+ return VException("No types passed in");
+ }
+ }
+ else
+ {
+ return VException("Argument passed in must be an array of types");
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------
+
+Handle<Value> BSON::BSONDeserialize(const Arguments &args)
+{
+ HandleScope scope;
+
+ // Ensure that we have an parameter
+ if(Buffer::HasInstance(args[0]) && args.Length() > 1) return VException("One argument required - buffer1.");
+ if(args[0]->IsString() && args.Length() > 1) return VException("One argument required - string1.");
+ // Throw an exception if the argument is not of type Buffer
+ if(!Buffer::HasInstance(args[0]) && !args[0]->IsString()) return VException("Argument must be a Buffer or String.");
+
+ // Define pointer to data
+ Local<Object> obj = args[0]->ToObject();
+
+ // Unpack the BSON parser instance
+ BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
+
+ // If we passed in a buffer, let's unpack it, otherwise let's unpack the string
+ if(Buffer::HasInstance(obj))
+ {
+#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
+ Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
+ char* data = buffer->data();
+ size_t length = buffer->length();
+#else
+ char* data = Buffer::Data(obj);
+ size_t length = Buffer::Length(obj);
+#endif
+
+ // Validate that we have at least 5 bytes
+ if(length < 5) return VException("corrupt bson message < 5 bytes long");
+
+ try
+ {
+ BSONDeserializer deserializer(bson, data, length);
+ return deserializer.DeserializeDocument();
+ }
+ catch(char* exception)
+ {
+ Handle<Value> error = VException(exception);
+ free(exception);
+ return error;
+ }
+
+ }
+ else
+ {
+ // The length of the data for this encoding
+ ssize_t len = DecodeBytes(args[0], BINARY);
+
+ // Validate that we have at least 5 bytes
+ if(len < 5) return VException("corrupt bson message < 5 bytes long");
+
+ // Let's define the buffer size
+ char* data = (char *)malloc(len);
+ DecodeWrite(data, len, args[0], BINARY);
+
+ try
+ {
+ BSONDeserializer deserializer(bson, data, len);
+ Handle<Value> result = deserializer.DeserializeDocument();
+ free(data);
+ return result;
+
+ }
+ catch(char* exception)
+ {
+ Handle<Value> error = VException(exception);
+ free(exception);
+ free(data);
+ return error;
+ }
+ }
+}
+
+Local<Object> BSON::GetSerializeObject(const Handle<Value>& argValue)
+{
+ Local<Object> object = argValue->ToObject();
+ if(object->Has(_toBSONString))
+ {
+ const Local<Value>& toBSON = object->Get(_toBSONString);
+ if(!toBSON->IsFunction()) ThrowAllocatedStringException(64, "toBSON is not a function");
+
+ Local<Value> result = Local<Function>::Cast(toBSON)->Call(object, 0, NULL);
+ if(!result->IsObject()) ThrowAllocatedStringException(64, "toBSON function did not return an object");
+ return result->ToObject();
+ }
+ else
+ {
+ return object;
+ }
+}
+
+Handle<Value> BSON::BSONSerialize(const Arguments &args)
+{
+ HandleScope scope;
+
+ if(args.Length() == 1 && !args[0]->IsObject()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]");
+ if(args.Length() == 2 && !args[0]->IsObject() && !args[1]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]");
+ if(args.Length() == 3 && !args[0]->IsObject() && !args[1]->IsBoolean() && !args[2]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]");
+ if(args.Length() == 4 && !args[0]->IsObject() && !args[1]->IsBoolean() && !args[2]->IsBoolean() && !args[3]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean] or [object, boolean, boolean, boolean]");
+ if(args.Length() > 4) return VException("One, two, tree or four arguments required - [object] or [object, boolean] or [object, boolean, boolean] or [object, boolean, boolean, boolean]");
+
+ // Unpack the BSON parser instance
+ BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
+
+ // Calculate the total size of the document in binary form to ensure we only allocate memory once
+ // With serialize function
+ bool serializeFunctions = (args.Length() >= 4) && args[3]->BooleanValue();
+
+ char *serialized_object = NULL;
+ size_t object_size;
+ try
+ {
+ Local<Object> object = bson->GetSerializeObject(args[0]);
+
+ BSONSerializer<CountStream> counter(bson, false, serializeFunctions);
+ counter.SerializeDocument(object);
+ object_size = counter.GetSerializeSize();
+
+ // Allocate the memory needed for the serialization
+ serialized_object = (char *)malloc(object_size);
+
+ // Check if we have a boolean value
+ bool checkKeys = args.Length() >= 3 && args[1]->IsBoolean() && args[1]->BooleanValue();
+ BSONSerializer<DataStream> data(bson, checkKeys, serializeFunctions, serialized_object);
+ data.SerializeDocument(object);
+ }
+ catch(char *err_msg)
+ {
+ free(serialized_object);
+ Handle<Value> error = VException(err_msg);
+ free(err_msg);
+ return error;
+ }
+
+ // If we have 3 arguments
+ if(args.Length() == 3 || args.Length() == 4)
+ {
+ Buffer *buffer = Buffer::New(serialized_object, object_size);
+ free(serialized_object);
+ return scope.Close(buffer->handle_);
+ }
+ else
+ {
+ Local<Value> bin_value = Encode(serialized_object, object_size, BINARY)->ToString();
+ free(serialized_object);
+ return bin_value;
+ }
+}
+
+Handle<Value> BSON::CalculateObjectSize(const Arguments &args)
+{
+ HandleScope scope;
+ // Ensure we have a valid object
+ if(args.Length() == 1 && !args[0]->IsObject()) return VException("One argument required - [object]");
+ if(args.Length() == 2 && !args[0]->IsObject() && !args[1]->IsBoolean()) return VException("Two arguments required - [object, boolean]");
+ if(args.Length() > 3) return VException("One or two arguments required - [object] or [object, boolean]");
+
+ // Unpack the BSON parser instance
+ BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
+ bool serializeFunctions = (args.Length() >= 2) && args[1]->BooleanValue();
+ BSONSerializer<CountStream> countSerializer(bson, false, serializeFunctions);
+ countSerializer.SerializeDocument(args[0]);
+
+ // Return the object size
+ return scope.Close(Uint32::New((uint32_t) countSerializer.GetSerializeSize()));
+}
+
+Handle<Value> BSON::SerializeWithBufferAndIndex(const Arguments &args)
+{
+ HandleScope scope;
+
+ //BSON.serializeWithBufferAndIndex = function serializeWithBufferAndIndex(object, ->, buffer, index) {
+ // Ensure we have the correct values
+ if(args.Length() > 5) return VException("Four or five parameters required [object, boolean, Buffer, int] or [object, boolean, Buffer, int, boolean]");
+ if(args.Length() == 4 && !args[0]->IsObject() && !args[1]->IsBoolean() && !Buffer::HasInstance(args[2]) && !args[3]->IsUint32()) return VException("Four parameters required [object, boolean, Buffer, int]");
+ if(args.Length() == 5 && !args[0]->IsObject() && !args[1]->IsBoolean() && !Buffer::HasInstance(args[2]) && !args[3]->IsUint32() && !args[4]->IsBoolean()) return VException("Four parameters required [object, boolean, Buffer, int, boolean]");
+
+ uint32_t index;
+ size_t object_size;
+
+ try
+ {
+ BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
+
+ Local<Object> obj = args[2]->ToObject();
+ char* data = Buffer::Data(obj);
+ size_t length = Buffer::Length(obj);
+
+ index = args[3]->Uint32Value();
+ bool checkKeys = args.Length() >= 4 && args[1]->IsBoolean() && args[1]->BooleanValue();
+ bool serializeFunctions = (args.Length() == 5) && args[4]->BooleanValue();
+
+ BSONSerializer<DataStream> dataSerializer(bson, checkKeys, serializeFunctions, data+index);
+ dataSerializer.SerializeDocument(bson->GetSerializeObject(args[0]));
+ object_size = dataSerializer.GetSerializeSize();
+
+ if(object_size + index > length) return VException("Serious error - overflowed buffer!!");
+ }
+ catch(char *exception)
+ {
+ Handle<Value> error = VException(exception);
+ free(exception);
+ return error;
+ }
+
+ return scope.Close(Uint32::New((uint32_t) (index + object_size - 1)));
+}
+
+Handle<Value> BSON::BSONDeserializeStream(const Arguments &args)
+{
+ HandleScope scope;
+
+ // At least 3 arguments required
+ if(args.Length() < 5) return VException("Arguments required (Buffer(data), Number(index in data), Number(number of documents to deserialize), Array(results), Number(index in the array), Object(optional))");
+
+ // If the number of argumets equals 3
+ if(args.Length() >= 5)
+ {
+ if(!Buffer::HasInstance(args[0])) return VException("First argument must be Buffer instance");
+ if(!args[1]->IsUint32()) return VException("Second argument must be a positive index number");
+ if(!args[2]->IsUint32()) return VException("Third argument must be a positive number of documents to deserialize");
+ if(!args[3]->IsArray()) return VException("Fourth argument must be an array the size of documents to deserialize");
+ if(!args[4]->IsUint32()) return VException("Sixth argument must be a positive index number");
+ }
+
+ // If we have 4 arguments
+ if(args.Length() == 6 && !args[5]->IsObject()) return VException("Fifth argument must be an object with options");
+
+ // Define pointer to data
+ Local<Object> obj = args[0]->ToObject();
+ uint32_t numberOfDocuments = args[2]->Uint32Value();
+ uint32_t index = args[1]->Uint32Value();
+ uint32_t resultIndex = args[4]->Uint32Value();
+
+ // Unpack the BSON parser instance
+ BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
+
+ // Unpack the buffer variable
+#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
+ Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
+ char* data = buffer->data();
+ size_t length = buffer->length();
+#else
+ char* data = Buffer::Data(obj);
+ size_t length = Buffer::Length(obj);
+#endif
+
+ // Fetch the documents
+ Local<Object> documents = args[3]->ToObject();
+
+ BSONDeserializer deserializer(bson, data+index, length-index);
+ for(uint32_t i = 0; i < numberOfDocuments; i++)
+ {
+ try
+ {
+ documents->Set(i + resultIndex, deserializer.DeserializeDocument());
+ }
+ catch (char* exception)
+ {
+ Handle<Value> error = VException(exception);
+ free(exception);
+ return error;
+ }
+ }
+
+ // Return new index of parsing
+ return scope.Close(Uint32::New((uint32_t) (index + deserializer.GetSerializeSize())));
+}
+
+// Exporting function
+extern "C" void init(Handle<Object> target)
+{
+ HandleScope scope;
+ BSON::Initialize(target);
+}
+
+NODE_MODULE(bson, BSON::Initialize);
diff --git a/node_modules/webworker-threads/src/bson.h b/node_modules/webworker-threads/src/bson.h
new file mode 100644
index 0000000..6f484b1
--- /dev/null
+++ b/node_modules/webworker-threads/src/bson.h
@@ -0,0 +1,277 @@
+//===========================================================================
+
+#ifndef BSON_H_
+#define BSON_H_
+
+#ifdef __sun
+#include <alloca.h>
+#endif
+
+//===========================================================================
+
+#define USE_MISALIGNED_MEMORY_ACCESS 1
+
+#include <node.h>
+#include <node_object_wrap.h>
+#include <v8.h>
+
+using namespace v8;
+using namespace node;
+
+//===========================================================================
+
+enum BsonType
+{
+ BSON_TYPE_NUMBER = 1,
+ BSON_TYPE_STRING = 2,
+ BSON_TYPE_OBJECT = 3,
+ BSON_TYPE_ARRAY = 4,
+ BSON_TYPE_BINARY = 5,
+ BSON_TYPE_UNDEFINED = 6,
+ BSON_TYPE_OID = 7,
+ BSON_TYPE_BOOLEAN = 8,
+ BSON_TYPE_DATE = 9,
+ BSON_TYPE_NULL = 10,
+ BSON_TYPE_REGEXP = 11,
+ BSON_TYPE_CODE = 13,
+ BSON_TYPE_SYMBOL = 14,
+ BSON_TYPE_CODE_W_SCOPE = 15,
+ BSON_TYPE_INT = 16,
+ BSON_TYPE_TIMESTAMP = 17,
+ BSON_TYPE_LONG = 18,
+ BSON_TYPE_MAX_KEY = 0x7f,
+ BSON_TYPE_MIN_KEY = 0xff
+};
+
+//===========================================================================
+
+template<typename T> class BSONSerializer;
+
+class BSON : public ObjectWrap {
+public:
+ BSON();
+ ~BSON() {}
+
+ static void Initialize(Handle<Object> target);
+ static Handle<Value> BSONDeserializeStream(const Arguments &args);
+
+ // JS based objects
+ static Handle<Value> BSONSerialize(const Arguments &args);
+ static Handle<Value> BSONDeserialize(const Arguments &args);
+
+ // Calculate size of function
+ static Handle<Value> CalculateObjectSize(const Arguments &args);
+ static Handle<Value> SerializeWithBufferAndIndex(const Arguments &args);
+
+ // Constructor used for creating new BSON objects from C++
+ static Persistent<FunctionTemplate> constructor_template;
+
+private:
+ static Handle<Value> New(const Arguments &args);
+ static Handle<Value> deserialize(BSON *bson, char *data, uint32_t dataLength, uint32_t startIndex, bool is_array_item);
+
+ // BSON type instantiate functions
+ Persistent<Function> longConstructor;
+ Persistent<Function> objectIDConstructor;
+ Persistent<Function> binaryConstructor;
+ Persistent<Function> codeConstructor;
+ Persistent<Function> dbrefConstructor;
+ Persistent<Function> symbolConstructor;
+ Persistent<Function> doubleConstructor;
+ Persistent<Function> timestampConstructor;
+ Persistent<Function> minKeyConstructor;
+ Persistent<Function> maxKeyConstructor;
+
+ // Equality Objects
+ Persistent<String> longString;
+ Persistent<String> objectIDString;
+ Persistent<String> binaryString;
+ Persistent<String> codeString;
+ Persistent<String> dbrefString;
+ Persistent<String> symbolString;
+ Persistent<String> doubleString;
+ Persistent<String> timestampString;
+ Persistent<String> minKeyString;
+ Persistent<String> maxKeyString;
+
+ // Equality speed up comparison objects
+ Persistent<String> _bsontypeString;
+ Persistent<String> _longLowString;
+ Persistent<String> _longHighString;
+ Persistent<String> _objectIDidString;
+ Persistent<String> _binaryPositionString;
+ Persistent<String> _binarySubTypeString;
+ Persistent<String> _binaryBufferString;
+ Persistent<String> _doubleValueString;
+ Persistent<String> _symbolValueString;
+
+ Persistent<String> _dbRefRefString;
+ Persistent<String> _dbRefIdRefString;
+ Persistent<String> _dbRefDbRefString;
+ Persistent<String> _dbRefNamespaceString;
+ Persistent<String> _dbRefDbString;
+ Persistent<String> _dbRefOidString;
+
+ Persistent<String> _codeCodeString;
+ Persistent<String> _codeScopeString;
+ Persistent<String> _toBSONString;
+
+public: Local<Object> GetSerializeObject(const Handle<Value>& object);
+
+ template<typename T> friend class BSONSerializer;
+ friend class BSONDeserializer;
+};
+
+//===========================================================================
+
+class CountStream
+{
+public:
+ CountStream() : count(0) { }
+
+ void WriteByte(int value) { ++count; }
+ void WriteByte(const Handle<Object>&, const Handle<String>&) { ++count; }
+ void WriteBool(const Handle<Value>& value) { ++count; }
+ void WriteInt32(int32_t value) { count += 4; }
+ void WriteInt32(const Handle<Value>& value) { count += 4; }
+ void WriteInt32(const Handle<Object>& object, const Handle<String>& key) { count += 4; }
+ void WriteInt64(int64_t value) { count += 8; }
+ void WriteInt64(const Handle<Value>& value) { count += 8; }
+ void WriteDouble(double value) { count += 8; }
+ void WriteDouble(const Handle<Value>& value) { count += 8; }
+ void WriteDouble(const Handle<Object>&, const Handle<String>&) { count += 8; }
+ void WriteUInt32String(uint32_t name) { char buffer[32]; count += sprintf(buffer, "%u", name) + 1; }
+ void WriteLengthPrefixedString(const Local<String>& value) { count += value->Utf8Length()+5; }
+ void WriteObjectId(const Handle<Object>& object, const Handle<String>& key) { count += 12; }
+ void WriteString(const Local<String>& value) { count += value->Utf8Length() + 1; } // This returns the number of bytes exclusive of the NULL terminator
+ void WriteData(const char* data, size_t length) { count += length; }
+
+ void* BeginWriteType() { ++count; return NULL; }
+ void CommitType(void*, BsonType) { }
+ void* BeginWriteSize() { count += 4; return NULL; }
+ void CommitSize(void*) { }
+
+ size_t GetSerializeSize() const { return count; }
+
+ // Do nothing. CheckKey is implemented for DataStream
+ void CheckKey(const Local<String>&) { }
+
+private:
+ size_t count;
+};
+
+class DataStream
+{
+public:
+ DataStream(char* aDestinationBuffer) : destinationBuffer(aDestinationBuffer), p(aDestinationBuffer) { }
+
+ void WriteByte(int value) { *p++ = value; }
+ void WriteByte(const Handle<Object>& object, const Handle<String>& key) { *p++ = object->Get(key)->Int32Value(); }
+#if USE_MISALIGNED_MEMORY_ACCESS
+ void WriteInt32(int32_t value) { *reinterpret_cast<int32_t*>(p) = value; p += 4; }
+ void WriteInt64(int64_t value) { *reinterpret_cast<int64_t*>(p) = value; p += 8; }
+ void WriteDouble(double value) { *reinterpret_cast<double*>(p) = value; p += 8; }
+#else
+ void WriteInt32(int32_t value) { memcpy(p, &value, 4); p += 4; }
+ void WriteInt64(int64_t value) { memcpy(p, &value, 8); p += 8; }
+ void WriteDouble(double value) { memcpy(p, &value, 8); p += 8; }
+#endif
+ void WriteBool(const Handle<Value>& value) { WriteByte(value->BooleanValue() ? 1 : 0); }
+ void WriteInt32(const Handle<Value>& value) { WriteInt32(value->Int32Value()); }
+ void WriteInt32(const Handle<Object>& object, const Handle<String>& key) { WriteInt32(object->Get(key)); }
+ void WriteInt64(const Handle<Value>& value) { WriteInt64(value->IntegerValue()); }
+ void WriteDouble(const Handle<Value>& value) { WriteDouble(value->NumberValue()); }
+ void WriteDouble(const Handle<Object>& object, const Handle<String>& key) { WriteDouble(object->Get(key)); }
+ void WriteUInt32String(uint32_t name) { p += sprintf(p, "%u", name) + 1; }
+ void WriteLengthPrefixedString(const Local<String>& value) { WriteInt32(value->Utf8Length()+1); WriteString(value); }
+ void WriteObjectId(const Handle<Object>& object, const Handle<String>& key);
+ void WriteString(const Local<String>& value) { p += value->WriteUtf8(p); } // This returns the number of bytes inclusive of the NULL terminator.
+ void WriteData(const char* data, size_t length) { memcpy(p, data, length); p += length; }
+
+ void* BeginWriteType() { void* returnValue = p; p++; return returnValue; }
+ void CommitType(void* beginPoint, BsonType value) { *reinterpret_cast<unsigned char*>(beginPoint) = value; }
+ void* BeginWriteSize() { void* returnValue = p; p += 4; return returnValue; }
+
+#if USE_MISALIGNED_MEMORY_ACCESS
+ void CommitSize(void* beginPoint) { *reinterpret_cast<int32_t*>(beginPoint) = (int32_t) (p - (char*) beginPoint); }
+#else
+ void CommitSize(void* beginPoint) { int32_t value = (int32_t) (p - (char*) beginPoint); memcpy(beginPoint, &value, 4); }
+#endif
+
+ size_t GetSerializeSize() const { return p - destinationBuffer; }
+
+ void CheckKey(const Local<String>& keyName);
+
+protected:
+ char *const destinationBuffer; // base, never changes
+ char* p; // cursor into buffer
+};
+
+template<typename T> class BSONSerializer : public T
+{
+private:
+ typedef T Inherited;
+
+public:
+ BSONSerializer(BSON* aBson, bool aCheckKeys, bool aSerializeFunctions) : Inherited(), checkKeys(aCheckKeys), serializeFunctions(aSerializeFunctions), bson(aBson) { }
+ BSONSerializer(BSON* aBson, bool aCheckKeys, bool aSerializeFunctions, char* parentParam) : Inherited(parentParam), checkKeys(aCheckKeys), serializeFunctions(aSerializeFunctions), bson(aBson) { }
+
+ void SerializeDocument(const Handle<Value>& value);
+ void SerializeArray(const Handle<Value>& value);
+ void SerializeValue(void* typeLocation, const Handle<Value>& value);
+
+private:
+ bool checkKeys;
+ bool serializeFunctions;
+ BSON* bson;
+};
+
+//===========================================================================
+
+class BSONDeserializer
+{
+public:
+ BSONDeserializer(BSON* aBson, char* data, size_t length);
+ BSONDeserializer(BSONDeserializer& parentSerializer, size_t length);
+
+ Handle<Value> DeserializeDocument();
+
+ bool HasMoreData() const { return p < pEnd; }
+ Local<String> ReadCString();
+ uint32_t ReadIntegerString();
+ int32_t ReadRegexOptions();
+ Local<String> ReadString();
+ Local<String> ReadObjectId();
+
+ unsigned char ReadByte() { return *reinterpret_cast<unsigned char*>(p++); }
+#if USE_MISALIGNED_MEMORY_ACCESS
+ int32_t ReadInt32() { int32_t returnValue = *reinterpret_cast<int32_t*>(p); p += 4; return returnValue; }
+ uint32_t ReadUInt32() { uint32_t returnValue = *reinterpret_cast<uint32_t*>(p); p += 4; return returnValue; }
+ int64_t ReadInt64() { int64_t returnValue = *reinterpret_cast<int64_t*>(p); p += 8; return returnValue; }
+ double ReadDouble() { double returnValue = *reinterpret_cast<double*>(p); p += 8; return returnValue; }
+#else
+ int32_t ReadInt32() { int32_t returnValue; memcpy(&returnValue, p, 4); p += 4; return returnValue; }
+ uint32_t ReadUInt32() { uint32_t returnValue; memcpy(&returnValue, p, 4); p += 4; return returnValue; }
+ int64_t ReadInt64() { int64_t returnValue; memcpy(&returnValue, p, 8); p += 8; return returnValue; }
+ double ReadDouble() { double returnValue; memcpy(&returnValue, p, 8); p += 8; return returnValue; }
+#endif
+
+ size_t GetSerializeSize() const { return p - pStart; }
+
+private:
+ Handle<Value> DeserializeArray();
+ Handle<Value> DeserializeValue(BsonType type);
+ Handle<Value> DeserializeDocumentInternal();
+ Handle<Value> DeserializeArrayInternal();
+
+ BSON* bson;
+ char* const pStart;
+ char* p;
+ char* const pEnd;
+};
+
+//===========================================================================
+
+#endif // BSON_H_
+
+//===========================================================================
diff --git a/node_modules/webworker-threads/src/createPool.js b/node_modules/webworker-threads/src/createPool.js
new file mode 100644
index 0000000..08dc9ca
--- /dev/null
+++ b/node_modules/webworker-threads/src/createPool.js
@@ -0,0 +1,169 @@
+function createPool(n){
+ var T, pool, idleThreads, q, poolObject, e, RUN, EMIT;
+ T = this;
+ n = Math.floor(n);
+ if (!(n > 0)) {
+ throw '.createPool( num ): number of threads must be a Number > 0';
+ }
+ pool = [];
+ idleThreads = [];
+ q = {
+ first: null,
+ last: null,
+ length: 0
+ };
+ poolObject = {
+ on: onEvent,
+ load: poolLoad,
+ destroy: destroy,
+ pendingJobs: getPendingJobs,
+ idleThreads: getIdleThreads,
+ totalThreads: getNumThreads,
+ any: {
+ eval: evalAny,
+ emit: emitAny
+ },
+ all: {
+ eval: evalAll,
+ emit: emitAll
+ }
+ };
+ try {
+ while (n--) {
+ pool[n] = idleThreads[n] = T.create();
+ }
+ } catch (e$) {
+ e = e$;
+ destroy('rudely');
+ throw e;
+ }
+ return poolObject;
+ RUN = 1;
+ EMIT = 2;
+ function poolLoad(path, cb){
+ var i;
+ i = pool.length;
+ while (i--) {
+ pool[i].load(path, cb);
+ }
+ }
+ function nextJob(t){
+ var job;
+ job = qPull();
+ if (job) {
+ if (job.type === RUN) {
+ t.eval(job.srcTextOrEventType, function(e, d){
+ var f;
+ nextJob(t);
+ f = job.cbOrData;
+ if (f) {
+ return job.cbOrData.call(t, e, d);
+ }
+ });
+ } else {
+ if (job.type === EMIT) {
+ t.emit(job.srcTextOrEventType, job.cbOrData);
+ nextJob(t);
+ }
+ }
+ } else {
+ idleThreads.push(t);
+ }
+ }
+ function qPush(srcTextOrEventType, cbOrData, type){
+ var job;
+ job = {
+ srcTextOrEventType: srcTextOrEventType,
+ cbOrData: cbOrData,
+ type: type,
+ next: null
+ };
+ if (q.last) {
+ q.last = q.last.next = job;
+ } else {
+ q.first = q.last = job;
+ }
+ q.length++;
+ }
+ function qPull(){
+ var job;
+ job = q.first;
+ if (job) {
+ if (q.last === job) {
+ q.first = q.last = null;
+ } else {
+ q.first = job.next;
+ }
+ q.length--;
+ }
+ return job;
+ }
+ function evalAny(src, cb){
+ qPush(src, cb, RUN);
+ if (idleThreads.length) {
+ nextJob(idleThreads.pop());
+ }
+ return poolObject;
+ }
+ function evalAll(src, cb){
+ pool.forEach(function(v, i, o){
+ return v.eval(src, cb);
+ });
+ return poolObject;
+ }
+ function emitAny(event, data){
+ qPush(event, data, EMIT);
+ if (idleThreads.length) {
+ nextJob(idleThreads.pop());
+ }
+ return poolObject;
+ }
+ function emitAll(event, data){
+ pool.forEach(function(v, i, o){
+ return v.emit(event, data);
+ });
+ return poolObject;
+ }
+ function onEvent(event, cb){
+ pool.forEach(function(v, i, o){
+ return v.on(event, cb);
+ });
+ return this;
+ }
+ function destroy(rudely){
+ var err, beNice, beRude;
+ err = function(){
+ throw 'This thread pool has been destroyed';
+ };
+ beNice = function(){
+ if (q.length) {
+ return setTimeout(beNice, 666);
+ } else {
+ return beRude();
+ }
+ };
+ beRude = function(){
+ q.length = 0;
+ q.first = null;
+ pool.forEach(function(v, i, o){
+ return v.destroy();
+ });
+ return poolObject.eval = poolObject.totalThreads = poolObject.idleThreads = poolObject.pendingJobs = poolObject.destroy = err;
+ };
+ if (rudely) {
+ beRude();
+ } else {
+ beNice();
+ }
+ }
+ function getNumThreads(){
+ return pool.length;
+ }
+ function getIdleThreads(){
+ return idleThreads.length;
+ }
+ function getPendingJobs(){
+ return q.length;
+ }
+ return getPendingJobs;
+}
diff --git a/node_modules/webworker-threads/src/createPool.js.c b/node_modules/webworker-threads/src/createPool.js.c
new file mode 100644
index 0000000..c0a4040
--- /dev/null
+++ b/node_modules/webworker-threads/src/createPool.js.c
@@ -0,0 +1 @@
+static const char* kCreatePool_js= "(\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x63\x72\x65\x61\x74\x65\x50\x6f\x6f\x6c\x28\x6e\x29\x7b\x76\x61\x72 \x54\x2c\x70\x6f\x6f\x6c\x2c\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x2c\x71\x2c\x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x2c\x65\x2c\x52\x55\x4e\x2c\x45\x4d\x49\x54\x3b\x54\x3d\x74\x68\x69\x73\x3b\x6e\x3d\x4d\x61\x74\x68\x2e\x66\x6c\x6f\x6f\x72\x28\x6e\x29\x3b\x69\x66\x28\x21\x28\x6e\x3e\x30\x29\x29\x7b\x74\x68\x72\x6f\x77\x27\x2e\x63\x72\x65\x61\x74\x65\x50\x6f\x6f\x6c\x28 \x6e\x75\x6d \x29\x3a \x6e\x75\x6d\x62\x65\x72 \x6f\x66 \x74\x68\x72\x65\x61\x64\x73 \x6d\x75\x73\x74 \x62\x65 \x61 \x4e\x75\x6d\x62\x65\x72 \x3e \x30\x27\x3b\x7d\n\x70\x6f\x6f\x6c\x3d\x5b\x5d\x3b\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x3d\x5b\x5d\x3b\x71\x3d\x7b\x66\x69\x72\x73\x74\x3a\x6e\x75\x6c\x6c\x2c\x6c\x61\x73\x74\x3a\x6e\x75\x6c\x6c\x2c\x6c\x65\x6e\x67\x74\x68\x3a\x30\x7d\x3b\x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x3d\x7b\x6f\x6e\x3a\x6f\x6e\x45\x76\x65\x6e\x74\x2c\x6c\x6f\x61\x64\x3a\x70\x6f\x6f\x6c\x4c\x6f\x61\x64\x2c\x64\x65\x73\x74\x72\x6f\x79\x3a\x64\x65\x73\x74\x72\x6f\x79\x2c\x70\x65\x6e\x64\x69\x6e\x67\x4a\x6f\x62\x73\x3a\x67\x65\x74\x50\x65\x6e\x64\x69\x6e\x67\x4a\x6f\x62\x73\x2c\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x3a\x67\x65\x74\x49\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x2c\x74\x6f\x74\x61\x6c\x54\x68\x72\x65\x61\x64\x73\x3a\x67\x65\x74\x4e\x75\x6d\x54\x68\x72\x65\x61\x64\x73\x2c\x61\x6e\x79\x3a\x7b\x65\x76\x61\x6c\x3a\x65\x76\x61\x6c\x41\x6e\x79\x2c\x65\x6d\x69\x74\x3a\x65\x6d\x69\x74\x41\x6e\x79\x7d\x2c\x61\x6c\x6c\x3a\x7b\x65\x76\x61\x6c\x3a\x65\x76\x61\x6c\x41\x6c\x6c\x2c\x65\x6d\x69\x74\x3a\x65\x6d\x69\x74\x41\x6c\x6c\x7d\x7d\x3b\x74\x72\x79\x7b\x77\x68\x69\x6c\x65\x28\x6e\x2d\x2d\x29\x7b\x70\x6f\x6f\x6c\x5b\x6e\x5d\x3d\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x5b\x6e\x5d\x3d\x54\x2e\x63\x72\x65\x61\x74\x65\x28\x29\x3b\x7d\x7d\x63\x61\x74\x63\x68\x28\x65\x24\x29\x7b\x65\x3d\x65\x24\x3b\x64\x65\x73\x74\x72\x6f\x79\x28\x27\x72\x75\x64\x65\x6c\x79\x27\x29\x3b\x74\x68\x72\x6f\x77 \x65\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x3b\x52\x55\x4e\x3d\x31\x3b\x45\x4d\x49\x54\x3d\x32\x3b\x66\x75\x6e\x63\x74\x69\x6f\x6e \x70\x6f\x6f\x6c\x4c\x6f\x61\x64\x28\x70\x61\x74\x68\x2c\x63\x62\x29\x7b\x76\x61\x72 \x69\x3b\x69\x3d\x70\x6f\x6f\x6c\x2e\x6c\x65\x6e\x67\x74\x68\x3b\x77\x68\x69\x6c\x65\x28\x69\x2d\x2d\x29\x7b\x70\x6f\x6f\x6c\x5b\x69\x5d\x2e\x6c\x6f\x61\x64\x28\x70\x61\x74\x68\x2c\x63\x62\x29\x3b\x7d\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x6e\x65\x78\x74\x4a\x6f\x62\x28\x74\x29\x7b\x76\x61\x72 \x6a\x6f\x62\x3b\x6a\x6f\x62\x3d\x71\x50\x75\x6c\x6c\x28\x29\x3b\x69\x66\x28\x6a\x6f\x62\x29\x7b\x69\x66\x28\x6a\x6f\x62\x2e\x74\x79\x70\x65\x3d\x3d\x3d\x52\x55\x4e\x29\x7b\x74\x2e\x65\x76\x61\x6c\x28\x6a\x6f\x62\x2e\x73\x72\x63\x54\x65\x78\x74\x4f\x72\x45\x76\x65\x6e\x74\x54\x79\x70\x65\x2c\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x65\x2c\x64\x29\x7b\x76\x61\x72 \x66\x3b\x6e\x65\x78\x74\x4a\x6f\x62\x28\x74\x29\x3b\x66\x3d\x6a\x6f\x62\x2e\x63\x62\x4f\x72\x44\x61\x74\x61\x3b\x69\x66\x28\x66\x29\x7b\x72\x65\x74\x75\x72\x6e \x6a\x6f\x62\x2e\x63\x62\x4f\x72\x44\x61\x74\x61\x2e\x63\x61\x6c\x6c\x28\x74\x2c\x65\x2c\x64\x29\x3b\x7d\x7d\x29\x3b\x7d\x65\x6c\x73\x65\x7b\x69\x66\x28\x6a\x6f\x62\x2e\x74\x79\x70\x65\x3d\x3d\x3d\x45\x4d\x49\x54\x29\x7b\x74\x2e\x65\x6d\x69\x74\x28\x6a\x6f\x62\x2e\x73\x72\x63\x54\x65\x78\x74\x4f\x72\x45\x76\x65\x6e\x74\x54\x79\x70\x65\x2c\x6a\x6f\x62\x2e\x63\x62\x4f\x72\x44\x61\x74\x61\x29\x3b\x6e\x65\x78\x74\x4a\x6f\x62\x28\x74\x29\x3b\x7d\x7d\x7d\x65\x6c\x73\x65\x7b\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x2e\x70\x75\x73\x68\x28\x74\x29\x3b\x7d\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x71\x50\x75\x73\x68\x28\x73\x72\x63\x54\x65\x78\x74\x4f\x72\x45\x76\x65\x6e\x74\x54\x79\x70\x65\x2c\x63\x62\x4f\x72\x44\x61\x74\x61\x2c\x74\x79\x70\x65\x29\x7b\x76\x61\x72 \x6a\x6f\x62\x3b\x6a\x6f\x62\x3d\x7b\x73\x72\x63\x54\x65\x78\x74\x4f\x72\x45\x76\x65\x6e\x74\x54\x79\x70\x65\x3a\x73\x72\x63\x54\x65\x78\x74\x4f\x72\x45\x76\x65\x6e\x74\x54\x79\x70\x65\x2c\x63\x62\x4f\x72\x44\x61\x74\x61\x3a\x63\x62\x4f\x72\x44\x61\x74\x61\x2c\x74\x79\x70\x65\x3a\x74\x79\x70\x65\x2c\x6e\x65\x78\x74\x3a\x6e\x75\x6c\x6c\x7d\x3b\x69\x66\x28\x71\x2e\x6c\x61\x73\x74\x29\x7b\x71\x2e\x6c\x61\x73\x74\x3d\x71\x2e\x6c\x61\x73\x74\x2e\x6e\x65\x78\x74\x3d\x6a\x6f\x62\x3b\x7d\x65\x6c\x73\x65\x7b\x71\x2e\x66\x69\x72\x73\x74\x3d\x71\x2e\x6c\x61\x73\x74\x3d\x6a\x6f\x62\x3b\x7d\n\x71\x2e\x6c\x65\x6e\x67\x74\x68\x2b\x2b\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x71\x50\x75\x6c\x6c\x28\x29\x7b\x76\x61\x72 \x6a\x6f\x62\x3b\x6a\x6f\x62\x3d\x71\x2e\x66\x69\x72\x73\x74\x3b\x69\x66\x28\x6a\x6f\x62\x29\x7b\x69\x66\x28\x71\x2e\x6c\x61\x73\x74\x3d\x3d\x3d\x6a\x6f\x62\x29\x7b\x71\x2e\x66\x69\x72\x73\x74\x3d\x71\x2e\x6c\x61\x73\x74\x3d\x6e\x75\x6c\x6c\x3b\x7d\x65\x6c\x73\x65\x7b\x71\x2e\x66\x69\x72\x73\x74\x3d\x6a\x6f\x62\x2e\x6e\x65\x78\x74\x3b\x7d\n\x71\x2e\x6c\x65\x6e\x67\x74\x68\x2d\x2d\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x6a\x6f\x62\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x65\x76\x61\x6c\x41\x6e\x79\x28\x73\x72\x63\x2c\x63\x62\x29\x7b\x71\x50\x75\x73\x68\x28\x73\x72\x63\x2c\x63\x62\x2c\x52\x55\x4e\x29\x3b\x69\x66\x28\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x2e\x6c\x65\x6e\x67\x74\x68\x29\x7b\x6e\x65\x78\x74\x4a\x6f\x62\x28\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x2e\x70\x6f\x70\x28\x29\x29\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x65\x76\x61\x6c\x41\x6c\x6c\x28\x73\x72\x63\x2c\x63\x62\x29\x7b\x70\x6f\x6f\x6c\x2e\x66\x6f\x72\x45\x61\x63\x68\x28\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x76\x2c\x69\x2c\x6f\x29\x7b\x72\x65\x74\x75\x72\x6e \x76\x2e\x65\x76\x61\x6c\x28\x73\x72\x63\x2c\x63\x62\x29\x3b\x7d\x29\x3b\x72\x65\x74\x75\x72\x6e \x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x65\x6d\x69\x74\x41\x6e\x79\x28\x65\x76\x65\x6e\x74\x2c\x64\x61\x74\x61\x29\x7b\x71\x50\x75\x73\x68\x28\x65\x76\x65\x6e\x74\x2c\x64\x61\x74\x61\x2c\x45\x4d\x49\x54\x29\x3b\x69\x66\x28\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x2e\x6c\x65\x6e\x67\x74\x68\x29\x7b\x6e\x65\x78\x74\x4a\x6f\x62\x28\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x2e\x70\x6f\x70\x28\x29\x29\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x65\x6d\x69\x74\x41\x6c\x6c\x28\x65\x76\x65\x6e\x74\x2c\x64\x61\x74\x61\x29\x7b\x70\x6f\x6f\x6c\x2e\x66\x6f\x72\x45\x61\x63\x68\x28\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x76\x2c\x69\x2c\x6f\x29\x7b\x72\x65\x74\x75\x72\x6e \x76\x2e\x65\x6d\x69\x74\x28\x65\x76\x65\x6e\x74\x2c\x64\x61\x74\x61\x29\x3b\x7d\x29\x3b\x72\x65\x74\x75\x72\x6e \x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x6f\x6e\x45\x76\x65\x6e\x74\x28\x65\x76\x65\x6e\x74\x2c\x63\x62\x29\x7b\x70\x6f\x6f\x6c\x2e\x66\x6f\x72\x45\x61\x63\x68\x28\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x76\x2c\x69\x2c\x6f\x29\x7b\x72\x65\x74\x75\x72\x6e \x76\x2e\x6f\x6e\x28\x65\x76\x65\x6e\x74\x2c\x63\x62\x29\x3b\x7d\x29\x3b\x72\x65\x74\x75\x72\x6e \x74\x68\x69\x73\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x64\x65\x73\x74\x72\x6f\x79\x28\x72\x75\x64\x65\x6c\x79\x29\x7b\x76\x61\x72 \x65\x72\x72\x2c\x62\x65\x4e\x69\x63\x65\x2c\x62\x65\x52\x75\x64\x65\x3b\x65\x72\x72\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x29\x7b\x74\x68\x72\x6f\x77\x27\x54\x68\x69\x73 \x74\x68\x72\x65\x61\x64 \x70\x6f\x6f\x6c \x68\x61\x73 \x62\x65\x65\x6e \x64\x65\x73\x74\x72\x6f\x79\x65\x64\x27\x3b\x7d\x3b\x62\x65\x4e\x69\x63\x65\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x29\x7b\x69\x66\x28\x71\x2e\x6c\x65\x6e\x67\x74\x68\x29\x7b\x72\x65\x74\x75\x72\x6e \x73\x65\x74\x54\x69\x6d\x65\x6f\x75\x74\x28\x62\x65\x4e\x69\x63\x65\x2c\x36\x36\x36\x29\x3b\x7d\x65\x6c\x73\x65\x7b\x72\x65\x74\x75\x72\x6e \x62\x65\x52\x75\x64\x65\x28\x29\x3b\x7d\x7d\x3b\x62\x65\x52\x75\x64\x65\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x29\x7b\x71\x2e\x6c\x65\x6e\x67\x74\x68\x3d\x30\x3b\x71\x2e\x66\x69\x72\x73\x74\x3d\x6e\x75\x6c\x6c\x3b\x70\x6f\x6f\x6c\x2e\x66\x6f\x72\x45\x61\x63\x68\x28\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x76\x2c\x69\x2c\x6f\x29\x7b\x72\x65\x74\x75\x72\x6e \x76\x2e\x64\x65\x73\x74\x72\x6f\x79\x28\x29\x3b\x7d\x29\x3b\x72\x65\x74\x75\x72\x6e \x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x2e\x65\x76\x61\x6c\x3d\x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x2e\x74\x6f\x74\x61\x6c\x54\x68\x72\x65\x61\x64\x73\x3d\x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x2e\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x3d\x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x2e\x70\x65\x6e\x64\x69\x6e\x67\x4a\x6f\x62\x73\x3d\x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x2e\x64\x65\x73\x74\x72\x6f\x79\x3d\x65\x72\x72\x3b\x7d\x3b\x69\x66\x28\x72\x75\x64\x65\x6c\x79\x29\x7b\x62\x65\x52\x75\x64\x65\x28\x29\x3b\x7d\x65\x6c\x73\x65\x7b\x62\x65\x4e\x69\x63\x65\x28\x29\x3b\x7d\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x67\x65\x74\x4e\x75\x6d\x54\x68\x72\x65\x61\x64\x73\x28\x29\x7b\x72\x65\x74\x75\x72\x6e \x70\x6f\x6f\x6c\x2e\x6c\x65\x6e\x67\x74\x68\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x67\x65\x74\x49\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x28\x29\x7b\x72\x65\x74\x75\x72\x6e \x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x2e\x6c\x65\x6e\x67\x74\x68\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x67\x65\x74\x50\x65\x6e\x64\x69\x6e\x67\x4a\x6f\x62\x73\x28\x29\x7b\x72\x65\x74\x75\x72\x6e \x71\x2e\x6c\x65\x6e\x67\x74\x68\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x67\x65\x74\x50\x65\x6e\x64\x69\x6e\x67\x4a\x6f\x62\x73\x3b\x7d)";
diff --git a/node_modules/webworker-threads/src/createPool.ls b/node_modules/webworker-threads/src/createPool.ls
new file mode 100644
index 0000000..36b7c47
--- /dev/null
+++ b/node_modules/webworker-threads/src/createPool.ls
@@ -0,0 +1,107 @@
+function create-pool (n)
+ T = this
+ n = Math.floor n
+ throw '.createPool( num ): number of threads must be a Number > 0' unless n > 0
+
+ pool = []
+ idle-threads = []
+ q = { first: null, last: null, length: 0 }
+ pool-object = {
+ on: on-event
+ load: pool-load
+ destroy: destroy
+ pending-jobs: get-pending-jobs
+ idle-threads: get-idle-threads
+ total-threads: get-num-threads
+ any: { eval: eval-any, emit: emit-any }
+ all: { eval: eval-all, emit: emit-all }
+ }
+
+ try
+ while n-- => pool[n] = idle-threads[n] = T.create!
+ catch e
+ destroy \rudely
+ throw e
+
+ return pool-object
+
+ ### Helper Functions Start Here ###
+
+ const RUN = 1
+ const EMIT = 2
+
+ function pool-load (path, cb)
+ i = pool.length
+ while i--
+ pool[i].load path, cb
+ return
+
+ function next-job (t)
+ job = q-pull!
+ if job
+ if job.type is RUN
+ t.eval job.src-text-or-event-type, (e, d) ->
+ next-job t
+ f = job.cb-or-data
+ job.cb-or-data.call t, e, d if f
+ else
+ if job.type is EMIT
+ t.emit job.src-text-or-event-type, job.cb-or-data
+ next-job t
+ else
+ idle-threads.push t
+ return
+
+ function q-push (src-text-or-event-type, cb-or-data, type)
+ job = { src-text-or-event-type, cb-or-data, type, next: null }
+ if q.last
+ q.last = q.last.next = job
+ else
+ q.first = q.last = job
+ q.length++
+ return
+
+ function q-pull
+ job = q.first
+ if job
+ if q.last is job then q.first = q.last = null else q.first = job.next
+ q.length--
+ return job
+
+ function eval-any (src, cb)
+ q-push src, cb, RUN
+ next-job idle-threads.pop! if idle-threads.length
+ return pool-object
+
+ function eval-all (src, cb)
+ pool.for-each (v, i, o) -> v.eval src, cb
+ return pool-object
+
+ function emit-any (event, data)
+ q-push event, data, EMIT
+ next-job idle-threads.pop! if idle-threads.length
+ return pool-object
+
+ function emit-all (event, data)
+ pool.for-each (v, i, o) -> v.emit event, data
+ return pool-object
+
+ function on-event (event, cb)
+ pool.for-each (v, i, o) -> v.on event, cb
+ return this
+
+ function destroy (rudely)
+ err = -> throw 'This thread pool has been destroyed'
+ be-nice = -> if q.length then setTimeout be-nice, 666 else be-rude!
+ be-rude = ->
+ q.length = 0
+ q.first = null
+ pool.for-each (v, i, o) -> v.destroy!
+ pool-object.eval = pool-object.total-threads = pool-object.idle-threads =
+ pool-object.pendingJobs = pool-object.destroy = err
+ if rudely then be-rude! else be-nice!
+ return
+
+ function get-num-threads => pool.length
+ function get-idle-threads => idle-threads.length
+ function get-pending-jobs => q.length
diff --git a/node_modules/webworker-threads/src/events.js b/node_modules/webworker-threads/src/events.js
new file mode 100644
index 0000000..b38a30e
--- /dev/null
+++ b/node_modules/webworker-threads/src/events.js
@@ -0,0 +1,53 @@
+function DispatchEvents(thread){
+ thread = (this.on = function(e, f, q){
+ if (q = thread._on[e]) {
+ q.push(f);
+ } else {
+ thread._on[e] = [f];
+ }
+ return thread;
+ }, this.once = function(e, f, q){
+ !(q = thread._on[e]) && (q = thread._on[e] = []);
+ if (q.once) {
+ q.once.push(f);
+ } else {
+ q.once = [f];
+ }
+ return thread;
+ }, this.removeAllListeners = function(e){
+ if (arguments_.length) {
+ delete thread._on[e];
+ } else {
+ thread._on = {};
+ }
+ return thread;
+ }, this.dispatchEvents = function(event, args, q, i, len){
+ var e, results$ = [];
+ if (q = thread._on[event]) {
+ try {
+ i = 0;
+ len = q.length;
+ while (i < len) {
+ q[i++].apply(thread, args);
+ }
+ if (q = q.once) {
+ q.once = undefined;
+ i = 0;
+ len = q.length;
+ while (i < len) {
+ results$.push(q[i++].apply(thread, args));
+ }
+ return results$;
+ }
+ } catch (e$) {
+ e = e$;
+ return __postError({
+ message: e,
+ filename: '',
+ lineno: 0
+ });
+ }
+ }
+ }, this._on = {}, this);
+ return this.dispatchEvents;
+}
diff --git a/node_modules/webworker-threads/src/events.js.c b/node_modules/webworker-threads/src/events.js.c
new file mode 100644
index 0000000..a21da23
--- /dev/null
+++ b/node_modules/webworker-threads/src/events.js.c
@@ -0,0 +1 @@
+static const char* kEvents_js= "(\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x44\x69\x73\x70\x61\x74\x63\x68\x45\x76\x65\x6e\x74\x73\x28\x74\x68\x72\x65\x61\x64\x29\x7b\x74\x68\x72\x65\x61\x64\x3d\x28\x74\x68\x69\x73\x2e\x6f\x6e\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x65\x2c\x66\x2c\x71\x29\x7b\x69\x66\x28\x71\x3d\x74\x68\x72\x65\x61\x64\x2e\x5f\x6f\x6e\x5b\x65\x5d\x29\x7b\x71\x2e\x70\x75\x73\x68\x28\x66\x29\x3b\x7d\x65\x6c\x73\x65\x7b\x74\x68\x72\x65\x61\x64\x2e\x5f\x6f\x6e\x5b\x65\x5d\x3d\x5b\x66\x5d\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x74\x68\x72\x65\x61\x64\x3b\x7d\x2c\x74\x68\x69\x73\x2e\x6f\x6e\x63\x65\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x65\x2c\x66\x2c\x71\x29\x7b\x21\x28\x71\x3d\x74\x68\x72\x65\x61\x64\x2e\x5f\x6f\x6e\x5b\x65\x5d\x29\x26\x26\x28\x71\x3d\x74\x68\x72\x65\x61\x64\x2e\x5f\x6f\x6e\x5b\x65\x5d\x3d\x5b\x5d\x29\x3b\x69\x66\x28\x71\x2e\x6f\x6e\x63\x65\x29\x7b\x71\x2e\x6f\x6e\x63\x65\x2e\x70\x75\x73\x68\x28\x66\x29\x3b\x7d\x65\x6c\x73\x65\x7b\x71\x2e\x6f\x6e\x63\x65\x3d\x5b\x66\x5d\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x74\x68\x72\x65\x61\x64\x3b\x7d\x2c\x74\x68\x69\x73\x2e\x72\x65\x6d\x6f\x76\x65\x41\x6c\x6c\x4c\x69\x73\x74\x65\x6e\x65\x72\x73\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x65\x29\x7b\x69\x66\x28\x61\x72\x67\x75\x6d\x65\x6e\x74\x73\x5f\x2e\x6c\x65\x6e\x67\x74\x68\x29\x7b\x64\x65\x6c\x65\x74\x65 \x74\x68\x72\x65\x61\x64\x2e\x5f\x6f\x6e\x5b\x65\x5d\x3b\x7d\x65\x6c\x73\x65\x7b\x74\x68\x72\x65\x61\x64\x2e\x5f\x6f\x6e\x3d\x7b\x7d\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x74\x68\x72\x65\x61\x64\x3b\x7d\x2c\x74\x68\x69\x73\x2e\x64\x69\x73\x70\x61\x74\x63\x68\x45\x76\x65\x6e\x74\x73\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x65\x76\x65\x6e\x74\x2c\x61\x72\x67\x73\x2c\x71\x2c\x69\x2c\x6c\x65\x6e\x29\x7b\x76\x61\x72 \x65\x2c\x72\x65\x73\x75\x6c\x74\x73\x24\x3d\x5b\x5d\x3b\x69\x66\x28\x71\x3d\x74\x68\x72\x65\x61\x64\x2e\x5f\x6f\x6e\x5b\x65\x76\x65\x6e\x74\x5d\x29\x7b\x74\x72\x79\x7b\x69\x3d\x30\x3b\x6c\x65\x6e\x3d\x71\x2e\x6c\x65\x6e\x67\x74\x68\x3b\x77\x68\x69\x6c\x65\x28\x69\x3c\x6c\x65\x6e\x29\x7b\x71\x5b\x69\x2b\x2b\x5d\x2e\x61\x70\x70\x6c\x79\x28\x74\x68\x72\x65\x61\x64\x2c\x61\x72\x67\x73\x29\x3b\x7d\n\x69\x66\x28\x71\x3d\x71\x2e\x6f\x6e\x63\x65\x29\x7b\x71\x2e\x6f\x6e\x63\x65\x3d\x75\x6e\x64\x65\x66\x69\x6e\x65\x64\x3b\x69\x3d\x30\x3b\x6c\x65\x6e\x3d\x71\x2e\x6c\x65\x6e\x67\x74\x68\x3b\x77\x68\x69\x6c\x65\x28\x69\x3c\x6c\x65\x6e\x29\x7b\x72\x65\x73\x75\x6c\x74\x73\x24\x2e\x70\x75\x73\x68\x28\x71\x5b\x69\x2b\x2b\x5d\x2e\x61\x70\x70\x6c\x79\x28\x74\x68\x72\x65\x61\x64\x2c\x61\x72\x67\x73\x29\x29\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x72\x65\x73\x75\x6c\x74\x73\x24\x3b\x7d\x7d\x63\x61\x74\x63\x68\x28\x65\x24\x29\x7b\x65\x3d\x65\x24\x3b\x72\x65\x74\x75\x72\x6e \x5f\x5f\x70\x6f\x73\x74\x45\x72\x72\x6f\x72\x28\x7b\x6d\x65\x73\x73\x61\x67\x65\x3a\x65\x2c\x66\x69\x6c\x65\x6e\x61\x6d\x65\x3a\x27\x27\x2c\x6c\x69\x6e\x65\x6e\x6f\x3a\x30\x7d\x29\x3b\x7d\x7d\x7d\x2c\x74\x68\x69\x73\x2e\x5f\x6f\x6e\x3d\x7b\x7d\x2c\x74\x68\x69\x73\x29\x3b\x72\x65\x74\x75\x72\x6e \x74\x68\x69\x73\x2e\x64\x69\x73\x70\x61\x74\x63\x68\x45\x76\x65\x6e\x74\x73\x3b\x7d)";
diff --git a/node_modules/webworker-threads/src/events.ls b/node_modules/webworker-threads/src/events.ls
new file mode 100644
index 0000000..4e604b7
--- /dev/null
+++ b/node_modules/webworker-threads/src/events.ls
@@ -0,0 +1,29 @@
+function DispatchEvents (thread)
+ thread = this <<< {
+ on: (e, f, q) ->
+ if q = thread._on[e] then q.push f else thread._on[e] = [f]
+ return thread
+ once: (e, f, q) ->
+ not (q = thread._on[e]) and (q = thread._on[e] = [])
+ if q.once then q.once.push f else q.once = [f]
+ return thread
+ remove-all-listeners: (e) ->
+ if arguments_.length then delete! thread._on[e] else thread._on = {}
+ return thread
+ dispatch-events: (event, args, q, i, len) ->
+ if q = thread._on[event] => try
+ i = 0
+ len = q.length
+ while i < len
+ q[i++].apply thread, args
+ if q = q.once
+ q.once = ``undefined``
+ i = 0
+ len = q.length
+ while i < len
+ q[i++].apply thread, args
+ catch
+ __postError { message: e, filename: '', lineno: 0 }
+ _on: {}
+ }
+ return @dispatch-events
diff --git a/node_modules/webworker-threads/src/jslib.cc b/node_modules/webworker-threads/src/jslib.cc
new file mode 100644
index 0000000..4476f22
--- /dev/null
+++ b/node_modules/webworker-threads/src/jslib.cc
@@ -0,0 +1,177 @@
+// Copyright(C) 2012 by RobertL
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+#include <errno.h>
+
+static const PropertyAttribute attribute_ro_dd = (PropertyAttribute)(ReadOnly | DontDelete);
+static const PropertyAttribute attribute_ro_de_dd = (PropertyAttribute)(ReadOnly | DontEnum | DontDelete);
+#define JSObjFn(obj, name, fnname) \
+ obj->Set(String::New(name), FunctionTemplate::New(fnname)->GetFunction(), attribute_ro_dd);
+
+static void ReportException(TryCatch* try_catch) {
+ HandleScope scope;
+
+ String::Utf8Value exception(try_catch->Exception());
+ Handle<Message> message = try_catch->Message();
+
+ if (message.IsEmpty()) {
+ printf("%s\n", *exception);
+
+ } else {
+ // Print (filename):(line number): (message).
+ String::Utf8Value filename(message->GetScriptResourceName());
+ int linenum = message->GetLineNumber();
+ printf("%s:%i: %s\n", *filename, linenum, *exception);
+
+ String::Utf8Value sourceline(message->GetSourceLine());
+ char *tmpbuf = *sourceline;
+ for (int i=0, n=sourceline.length(); i<n; ++i) {
+ if (tmpbuf[i] == '\t') {
+ putchar(' ');
+ } else {
+ putchar(tmpbuf[i]);
+ }
+ }
+ putchar('\n');
+
+
+ int start = message->GetStartColumn();
+ for (int i = 0; i < start; i++) {
+ putchar(' ');
+ }
+ int end = message->GetEndColumn();
+ for (int i = start; i < end; i++) {
+ putchar('^');
+ }
+ putchar('\n');
+
+ String::Utf8Value stack_trace(try_catch->StackTrace());
+ if (stack_trace.length() > 0) {
+ printf("%s\n", *stack_trace);
+ }
+ }
+}
+
+static Handle<Value> readFileSync_(const Arguments &args) {
+ HandleScope scope;
+
+ FILE *f = fopen(*String::Utf8Value(Handle<String>::Cast(args[0])), "rb");
+ if (f == NULL) {
+ char str[256];
+ sprintf(str, "Error: readfile open failed. %d %s\n", errno, strerror(errno));
+ return ThrowException(Exception::Error(String::New(str)));
+ }
+ fseek(f, 0, SEEK_END);
+ size_t s = ftell(f);
+ rewind(f);
+
+ char *buf = (char*)malloc((s+1)*sizeof(char));
+ size_t r = fread(buf, sizeof(char), s, f);
+ if (r < s) {
+ char str[256];
+ sprintf(str, "Error: readfile read failed. %d %s\n", ferror(f), strerror(ferror(f)));
+ delete[] buf;
+ fclose(f);
+ ThrowException(Exception::Error(String::New(str)));
+ }
+ buf[s] = 0;
+ Handle<String> str = String::New(buf);
+ free(buf);
+ fclose(f);
+
+ return scope.Close(str);
+}
+
+
+
+// console section
+static inline void console_common_1(const Handle<Value> &v, FILE* fd, const int deep) {
+ char indent[36] = {};
+ int i, n;
+ int mark = 0;
+ for (i=0; i<deep; ++i) {
+ indent[mark++] = 0x20;
+ indent[mark++] = 0x20;
+ }
+
+ Handle<Value> lv;
+ if (v->IsFunction()) {
+ fprintf(fd, "%s[Function]\n", indent);
+ } else if (v->IsObject()) {
+ Handle<Object> obj = Handle<Object>::Cast(v);
+ Handle<Array> ar = obj->GetPropertyNames();
+ fprintf(fd, "%s{Object}\n", indent);
+ for (i=0, n=ar->Length(); i<n; ++i) {
+ lv = obj->Get(ar->Get(i));
+ fprintf(fd, "%s%s: ", indent, *(String::Utf8Value(Handle<String>::Cast(ar->Get(i)))));
+ if (lv->IsFunction()) {
+ fprintf(fd, "%s[Function]\n", indent);
+ } else if (lv->IsObject() || lv->IsArray()) {
+ //fprintf(fd, "\n");
+ console_common_1(lv, fd, deep+1);
+ } else {
+ fprintf(fd, "%s%s\n", indent, *(String::Utf8Value(Handle<String>::Cast(lv))));
+ }
+ }
+ fprintf(fd, "%s{/Object}\n", indent);
+
+ } else if (v->IsArray()) {
+ Handle<Array> obj = Handle<Array>::Cast(v);
+ fprintf(fd, "%s[Array]\n", indent);
+ for (i=0, n=obj->Length(); i<n; ++i) {
+ lv = obj->Get(i);
+ fprintf(fd, "%s%d: ", indent, i);
+ if (lv->IsFunction()) {
+ fprintf(fd, "%s[Function]\n", indent);
+ } else if (lv->IsObject() || lv->IsArray()) {
+ fprintf(fd, "\n");
+ console_common_1(lv, fd, deep+1);
+ } else {
+ fprintf(fd, "%s%s\n", indent, *(String::Utf8Value(Handle<String>::Cast(lv))));
+ }
+ }
+ fprintf(fd, "%s[/Array]\n", indent);
+ } else {
+ fprintf(fd, "%s%s\n", indent, *(String::Utf8Value(Handle<String>::Cast(v))));
+ }
+}
+
+static inline void console_common(const Arguments &args, FILE* fd) {
+ TryCatch trycatch;
+
+ for (int i=0, n=args.Length(); i<n; ++i) {
+ console_common_1(args[i], stdout, 0);
+ }
+
+ if (trycatch.HasCaught()) {
+ ReportException(&trycatch);
+ }
+}
+
+static Handle<Value> console_log(const Arguments &args) {
+ HandleScope scope;
+ console_common(args, stdout);
+ return Undefined();
+}
+
+static Handle<Value> console_error(const Arguments &args) {
+ HandleScope scope;
+ console_common(args, stderr);
+ return Undefined();
+}
diff --git a/node_modules/webworker-threads/src/load.js b/node_modules/webworker-threads/src/load.js
new file mode 100644
index 0000000..ab705ed
--- /dev/null
+++ b/node_modules/webworker-threads/src/load.js
@@ -0,0 +1,19 @@
+var onmessage, this$ = this;
+function addEventListener(event, cb){
+ return this.thread.on(event, cb);
+}
+function close(){
+ return this.thread.emit('close');
+}
+function importScripts(){
+ var i$, len$, p, results$ = [];
+ for (i$ = 0, len$ = arguments.length; i$ < len$; ++i$) {
+ p = arguments[i$];
+ results$.push(self.eval(native_fs_.readFileSync(p, 'utf8')));
+ }
+ return results$;
+}
+onmessage = null;
+thread.on('message', function(args){
+ return typeof onmessage === 'function' ? onmessage(args) : void 8;
+});
diff --git a/node_modules/webworker-threads/src/load.js.c b/node_modules/webworker-threads/src/load.js.c
new file mode 100644
index 0000000..8424c21
--- /dev/null
+++ b/node_modules/webworker-threads/src/load.js.c
@@ -0,0 +1 @@
+static const char* kLoad_js= "\n\x76\x61\x72 \x6f\x6e\x6d\x65\x73\x73\x61\x67\x65\x2c\x74\x68\x69\x73\x24\x3d\x74\x68\x69\x73\x3b\x66\x75\x6e\x63\x74\x69\x6f\x6e \x61\x64\x64\x45\x76\x65\x6e\x74\x4c\x69\x73\x74\x65\x6e\x65\x72\x28\x65\x76\x65\x6e\x74\x2c\x63\x62\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x68\x69\x73\x2e\x74\x68\x72\x65\x61\x64\x2e\x6f\x6e\x28\x65\x76\x65\x6e\x74\x2c\x63\x62\x29\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x63\x6c\x6f\x73\x65\x28\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x68\x69\x73\x2e\x74\x68\x72\x65\x61\x64\x2e\x65\x6d\x69\x74\x28\x27\x63\x6c\x6f\x73\x65\x27\x29\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x69\x6d\x70\x6f\x72\x74\x53\x63\x72\x69\x70\x74\x73\x28\x29\x7b\x76\x61\x72 \x69\x24\x2c\x6c\x65\x6e\x24\x2c\x70\x2c\x72\x65\x73\x75\x6c\x74\x73\x24\x3d\x5b\x5d\x3b\x66\x6f\x72\x28\x69\x24\x3d\x30\x2c\x6c\x65\x6e\x24\x3d\x61\x72\x67\x75\x6d\x65\x6e\x74\x73\x2e\x6c\x65\x6e\x67\x74\x68\x3b\x69\x24\x3c\x6c\x65\x6e\x24\x3b\x2b\x2b\x69\x24\x29\x7b\x70\x3d\x61\x72\x67\x75\x6d\x65\x6e\x74\x73\x5b\x69\x24\x5d\x3b\x72\x65\x73\x75\x6c\x74\x73\x24\x2e\x70\x75\x73\x68\x28\x73\x65\x6c\x66\x2e\x65\x76\x61\x6c\x28\x6e\x61\x74\x69\x76\x65\x5f\x66\x73\x5f\x2e\x72\x65\x61\x64\x46\x69\x6c\x65\x53\x79\x6e\x63\x28\x70\x2c\x27\x75\x74\x66\x38\x27\x29\x29\x29\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x72\x65\x73\x75\x6c\x74\x73\x24\x3b\x7d\n\x6f\x6e\x6d\x65\x73\x73\x61\x67\x65\x3d\x6e\x75\x6c\x6c\x3b\x74\x68\x72\x65\x61\x64\x2e\x6f\x6e\x28\x27\x6d\x65\x73\x73\x61\x67\x65\x27\x2c\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x61\x72\x67\x73\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x79\x70\x65\x6f\x66 \x6f\x6e\x6d\x65\x73\x73\x61\x67\x65\x3d\x3d\x3d\x27\x66\x75\x6e\x63\x74\x69\x6f\x6e\x27\x3f\x6f\x6e\x6d\x65\x73\x73\x61\x67\x65\x28\x61\x72\x67\x73\x29\x3a\x76\x6f\x69\x64 \x38\x3b\x7d\x29\x3b";
diff --git a/node_modules/webworker-threads/src/load.ls b/node_modules/webworker-threads/src/load.ls
new file mode 100644
index 0000000..80650eb
--- /dev/null
+++ b/node_modules/webworker-threads/src/load.ls
@@ -0,0 +1,9 @@
+function add-event-listener (event, cb)
+ @thread.on event, cb
+function close ()
+ @thread.emit \close
+function importScripts ()
+ for p in arguments
+ self.eval native_fs_.readFileSync(p, \utf8)
+onmessage = null
+thread.on \message (args) ~> onmessage? args
diff --git a/node_modules/webworker-threads/src/queues_a_gogo.cc b/node_modules/webworker-threads/src/queues_a_gogo.cc
new file mode 100644
index 0000000..d675bb1
--- /dev/null
+++ b/node_modules/webworker-threads/src/queues_a_gogo.cc
@@ -0,0 +1,160 @@
+//2011-11 Proyectos Equis Ka, s.l., jorge@jorgechamorro.com
+//queues_a_gogo.cc
+
+#include <string.h>
+#include <stdio.h>
+#include <uv.h>
+#include <stdlib.h>
+#if defined(__unix__) || defined(__POSIX__) || defined(__APPLE__) || defined(_AIX)
+#include <unistd.h>
+#endif
+
+enum types {
+ kItemTypeNONE,
+ kItemTypeNumber,
+ kItemTypePointer,
+ kItemTypeQUIT
+};
+
+struct typeQueueItem {
+ int itemType;
+ typeQueueItem* next;
+ union {
+ void* asPtr;
+ double asNumber;
+ };
+};
+typedef struct typeQueueItem typeQueueItem;
+
+typedef struct {
+ typeQueueItem* first;
+ typeQueueItem* last;
+ uv_mutex_t queueLock;
+ long int id;
+ volatile long int length;
+} typeQueue;
+
+static typeQueue* queuesPool= NULL;
+static typeQueue* freeItemsQueue= NULL;
+
+
+
+
+static void queue_push (typeQueueItem* qitem, typeQueue* queue) {
+ qitem->next= NULL;
+
+ uv_mutex_lock(&queue->queueLock);
+ if (queue->last) {
+ queue->last->next= qitem;
+ }
+ else {
+ queue->first= qitem;
+ }
+ queue->last= qitem;
+ queue->length++;
+ uv_mutex_unlock(&queue->queueLock);
+}
+
+
+
+
+static typeQueueItem* queue_pull (typeQueue* queue) {
+ typeQueueItem* qitem;
+
+ uv_mutex_lock(&queue->queueLock);
+ if ((qitem= queue->first)) {
+ if (queue->last == qitem) {
+ queue->first= queue->last= NULL;
+ }
+ else {
+ queue->first= qitem->next;
+ }
+ queue->length--;
+ qitem->next= NULL;
+ }
+ uv_mutex_unlock(&queue->queueLock);
+
+ return qitem;
+}
+
+
+
+
+static typeQueueItem* nuItem (int itemType, void* item) {
+
+ typeQueueItem* qitem= queue_pull(freeItemsQueue);
+ if (!qitem) {
+ qitem= (typeQueueItem*) calloc(1, sizeof(typeQueueItem));
+ }
+
+ qitem->next= NULL;
+ qitem->itemType= itemType;
+ if (itemType == kItemTypeNumber) {
+ qitem->asNumber= *((double*) item);
+ }
+ else if (itemType == kItemTypePointer) {
+ qitem->asPtr= item;
+ }
+
+ return qitem;
+}
+
+
+
+
+static void destroyItem (typeQueueItem* qitem) {
+
+ if (freeItemsQueue) {
+ queue_push(qitem, freeItemsQueue);
+ }
+ else {
+ free(qitem);
+ }
+}
+
+
+
+
+static typeQueue* nuQueue (long int id) {
+
+ typeQueue* queue= NULL;
+ typeQueueItem* qitem= NULL;
+ if (queuesPool && queuesPool->first) qitem= queue_pull(queuesPool);
+ if (qitem) {
+ queue= (typeQueue*) qitem->asPtr;
+ destroyItem(qitem);
+ }
+ else {
+ queue= (typeQueue*) calloc(1, sizeof(typeQueue));
+ uv_mutex_init(&queue->queueLock);
+ }
+
+ queue->id= id;
+ queue->length= 0;
+ queue->first= queue->last= NULL;
+ return queue;
+}
+
+
+/*
+
+static void destroyQueue (typeQueue* queue) {
+ if (queuesPool) {
+ queue_push(nuItem(kItemTypePointer, queue), queuesPool);
+ }
+ else {
+ free(queue);
+ }
+}
+
+*/
+
+
+static void initQueues (void) {
+ freeItemsQueue= nuQueue(-2); //MUST be created before queuesPool
+ //queuesPool= nuQueue(-1);
+}
+
+
+
+
diff --git a/node_modules/webworker-threads/src/thread_nextTick.js b/node_modules/webworker-threads/src/thread_nextTick.js
new file mode 100644
index 0000000..e8cf3c0
--- /dev/null
+++ b/node_modules/webworker-threads/src/thread_nextTick.js
@@ -0,0 +1,29 @@
+function ThreadNextTick(){
+ function nextTick(cb){
+ thread._ntq.push(cb);
+ return this;
+ }
+ function dispatchNextTicks(l, p, err, _ntq){
+ var e;
+ if (l = (_ntq = thread._ntq).length) {
+ p = err = 0;
+ try {
+ for (;;) {
+ _ntq[p]();
+ if (!(++p < l)) {
+ break;
+ }
+ }
+ } catch (e$) {
+ e = e$;
+ thread._ntq = _ntq.slice(++p);
+ throw e;
+ }
+ return (thread._ntq = _ntq.slice(p)).length;
+ }
+ return 0;
+ }
+ thread._ntq = [];
+ thread.nextTick = nextTick;
+ return dispatchNextTicks;
+}
diff --git a/node_modules/webworker-threads/src/thread_nextTick.js.c b/node_modules/webworker-threads/src/thread_nextTick.js.c
new file mode 100644
index 0000000..c84dfd9
--- /dev/null
+++ b/node_modules/webworker-threads/src/thread_nextTick.js.c
@@ -0,0 +1 @@
+static const char* kThread_nextTick_js= "(\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x54\x68\x72\x65\x61\x64\x4e\x65\x78\x74\x54\x69\x63\x6b\x28\x29\x7b\x66\x75\x6e\x63\x74\x69\x6f\x6e \x6e\x65\x78\x74\x54\x69\x63\x6b\x28\x63\x62\x29\x7b\x74\x68\x72\x65\x61\x64\x2e\x5f\x6e\x74\x71\x2e\x70\x75\x73\x68\x28\x63\x62\x29\x3b\x72\x65\x74\x75\x72\x6e \x74\x68\x69\x73\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x64\x69\x73\x70\x61\x74\x63\x68\x4e\x65\x78\x74\x54\x69\x63\x6b\x73\x28\x6c\x2c\x70\x2c\x65\x72\x72\x2c\x5f\x6e\x74\x71\x29\x7b\x76\x61\x72 \x65\x3b\x69\x66\x28\x6c\x3d\x28\x5f\x6e\x74\x71\x3d\x74\x68\x72\x65\x61\x64\x2e\x5f\x6e\x74\x71\x29\x2e\x6c\x65\x6e\x67\x74\x68\x29\x7b\x70\x3d\x65\x72\x72\x3d\x30\x3b\x74\x72\x79\x7b\x66\x6f\x72\x28\x3b\x3b\x29\x7b\x5f\x6e\x74\x71\x5b\x70\x5d\x28\x29\x3b\x69\x66\x28\x21\x28\x2b\x2b\x70\x3c\x6c\x29\x29\x7b\x62\x72\x65\x61\x6b\x3b\x7d\x7d\x7d\x63\x61\x74\x63\x68\x28\x65\x24\x29\x7b\x65\x3d\x65\x24\x3b\x74\x68\x72\x65\x61\x64\x2e\x5f\x6e\x74\x71\x3d\x5f\x6e\x74\x71\x2e\x73\x6c\x69\x63\x65\x28\x2b\x2b\x70\x29\x3b\x74\x68\x72\x6f\x77 \x65\x3b\x7d\n\x72\x65\x74\x75\x72\x6e\x28\x74\x68\x72\x65\x61\x64\x2e\x5f\x6e\x74\x71\x3d\x5f\x6e\x74\x71\x2e\x73\x6c\x69\x63\x65\x28\x70\x29\x29\x2e\x6c\x65\x6e\x67\x74\x68\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x30\x3b\x7d\n\x74\x68\x72\x65\x61\x64\x2e\x5f\x6e\x74\x71\x3d\x5b\x5d\x3b\x74\x68\x72\x65\x61\x64\x2e\x6e\x65\x78\x74\x54\x69\x63\x6b\x3d\x6e\x65\x78\x74\x54\x69\x63\x6b\x3b\x72\x65\x74\x75\x72\x6e \x64\x69\x73\x70\x61\x74\x63\x68\x4e\x65\x78\x74\x54\x69\x63\x6b\x73\x3b\x7d)()";
diff --git a/node_modules/webworker-threads/src/thread_nextTick.ls b/node_modules/webworker-threads/src/thread_nextTick.ls
new file mode 100644
index 0000000..7ac3fe2
--- /dev/null
+++ b/node_modules/webworker-threads/src/thread_nextTick.ls
@@ -0,0 +1,19 @@
+function ThreadNextTick
+ function next-tick (cb)
+ thread._ntq.push cb
+ return this
+ function dispatch-next-ticks (l, p, err, _ntq)
+ if l = (_ntq = thread._ntq).length
+ p = err = 0
+ try
+ while true
+ _ntq[p]!
+ break unless ++p < l
+ catch e
+ thread._ntq = _ntq.slice ++p
+ throw e
+ return (thread._ntq = _ntq.slice p).length
+ return 0
+ thread._ntq = []
+ thread.next-tick = next-tick
+ return dispatch-next-ticks
diff --git a/node_modules/webworker-threads/src/worker.js b/node_modules/webworker-threads/src/worker.js
new file mode 100644
index 0000000..004bb54
--- /dev/null
+++ b/node_modules/webworker-threads/src/worker.js
@@ -0,0 +1,46 @@
+function Worker(){
+ var Threads;
+ Threads = this;
+ return (function(){
+ var prototype = constructor.prototype;
+ function constructor(code){
+ var t, this$ = this;
+ this.thread = t = Threads.create();
+ t.on('message', function(args){
+ return typeof this$.onmessage === 'function' ? this$.onmessage({
+ data: args
+ }) : void 8;
+ });
+ t.on('error', function(args){
+ return typeof this$.onerror === 'function' ? this$.onerror(args) : void 8;
+ });
+ t.on('close', function(){
+ return t.destroy();
+ });
+ this.terminate = function(){
+ return t.destroy();
+ };
+ this.addEventListener = function(event, cb){
+ if (event === 'message') {
+ return this$.onmessage = cb;
+ } else {
+ return t.on(event, cb);
+ }
+ };
+ this.dispatchEvent = function(event){
+ return t.emitSerialized(event.type, event);
+ };
+ this.postMessage = function(data){
+ return t.emitSerialized('message', {
+ data: data
+ });
+ };
+ if (typeof code === 'function') {
+ t.eval("(" + code + ")()");
+ } else if (code != null) {
+ t.load(code);
+ }
+ }
+ return constructor;
+ }());
+}
diff --git a/node_modules/webworker-threads/src/worker.js.c b/node_modules/webworker-threads/src/worker.js.c
new file mode 100644
index 0000000..1d97532
--- /dev/null
+++ b/node_modules/webworker-threads/src/worker.js.c
@@ -0,0 +1 @@
+static const char* kWorker_js= "(\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x57\x6f\x72\x6b\x65\x72\x28\x29\x7b\x76\x61\x72 \x54\x68\x72\x65\x61\x64\x73\x3b\x54\x68\x72\x65\x61\x64\x73\x3d\x74\x68\x69\x73\x3b\x72\x65\x74\x75\x72\x6e\x28\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x29\x7b\x76\x61\x72 \x70\x72\x6f\x74\x6f\x74\x79\x70\x65\x3d\x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72\x2e\x70\x72\x6f\x74\x6f\x74\x79\x70\x65\x3b\x66\x75\x6e\x63\x74\x69\x6f\x6e \x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72\x28\x63\x6f\x64\x65\x29\x7b\x76\x61\x72 \x74\x2c\x74\x68\x69\x73\x24\x3d\x74\x68\x69\x73\x3b\x74\x68\x69\x73\x2e\x74\x68\x72\x65\x61\x64\x3d\x74\x3d\x54\x68\x72\x65\x61\x64\x73\x2e\x63\x72\x65\x61\x74\x65\x28\x29\x3b\x74\x2e\x6f\x6e\x28\x27\x6d\x65\x73\x73\x61\x67\x65\x27\x2c\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x61\x72\x67\x73\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x79\x70\x65\x6f\x66 \x74\x68\x69\x73\x24\x2e\x6f\x6e\x6d\x65\x73\x73\x61\x67\x65\x3d\x3d\x3d\x27\x66\x75\x6e\x63\x74\x69\x6f\x6e\x27\x3f\x74\x68\x69\x73\x24\x2e\x6f\x6e\x6d\x65\x73\x73\x61\x67\x65\x28\x7b\x64\x61\x74\x61\x3a\x61\x72\x67\x73\x7d\x29\x3a\x76\x6f\x69\x64 \x38\x3b\x7d\x29\x3b\x74\x2e\x6f\x6e\x28\x27\x65\x72\x72\x6f\x72\x27\x2c\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x61\x72\x67\x73\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x79\x70\x65\x6f\x66 \x74\x68\x69\x73\x24\x2e\x6f\x6e\x65\x72\x72\x6f\x72\x3d\x3d\x3d\x27\x66\x75\x6e\x63\x74\x69\x6f\x6e\x27\x3f\x74\x68\x69\x73\x24\x2e\x6f\x6e\x65\x72\x72\x6f\x72\x28\x61\x72\x67\x73\x29\x3a\x76\x6f\x69\x64 \x38\x3b\x7d\x29\x3b\x74\x2e\x6f\x6e\x28\x27\x63\x6c\x6f\x73\x65\x27\x2c\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x2e\x64\x65\x73\x74\x72\x6f\x79\x28\x29\x3b\x7d\x29\x3b\x74\x68\x69\x73\x2e\x74\x65\x72\x6d\x69\x6e\x61\x74\x65\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x2e\x64\x65\x73\x74\x72\x6f\x79\x28\x29\x3b\x7d\x3b\x74\x68\x69\x73\x2e\x61\x64\x64\x45\x76\x65\x6e\x74\x4c\x69\x73\x74\x65\x6e\x65\x72\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x65\x76\x65\x6e\x74\x2c\x63\x62\x29\x7b\x69\x66\x28\x65\x76\x65\x6e\x74\x3d\x3d\x3d\x27\x6d\x65\x73\x73\x61\x67\x65\x27\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x68\x69\x73\x24\x2e\x6f\x6e\x6d\x65\x73\x73\x61\x67\x65\x3d\x63\x62\x3b\x7d\x65\x6c\x73\x65\x7b\x72\x65\x74\x75\x72\x6e \x74\x2e\x6f\x6e\x28\x65\x76\x65\x6e\x74\x2c\x63\x62\x29\x3b\x7d\x7d\x3b\x74\x68\x69\x73\x2e\x64\x69\x73\x70\x61\x74\x63\x68\x45\x76\x65\x6e\x74\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x65\x76\x65\x6e\x74\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x2e\x65\x6d\x69\x74\x53\x65\x72\x69\x61\x6c\x69\x7a\x65\x64\x28\x65\x76\x65\x6e\x74\x2e\x74\x79\x70\x65\x2c\x65\x76\x65\x6e\x74\x29\x3b\x7d\x3b\x74\x68\x69\x73\x2e\x70\x6f\x73\x74\x4d\x65\x73\x73\x61\x67\x65\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x64\x61\x74\x61\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x2e\x65\x6d\x69\x74\x53\x65\x72\x69\x61\x6c\x69\x7a\x65\x64\x28\x27\x6d\x65\x73\x73\x61\x67\x65\x27\x2c\x7b\x64\x61\x74\x61\x3a\x64\x61\x74\x61\x7d\x29\x3b\x7d\x3b\x69\x66\x28\x74\x79\x70\x65\x6f\x66 \x63\x6f\x64\x65\x3d\x3d\x3d\x27\x66\x75\x6e\x63\x74\x69\x6f\x6e\x27\x29\x7b\x74\x2e\x65\x76\x61\x6c\x28\x22\x28\x22\x2b\x63\x6f\x64\x65\x2b\x22\x29\x28\x29\x22\x29\x3b\x7d\x65\x6c\x73\x65 \x69\x66\x28\x63\x6f\x64\x65\x21\x3d\x6e\x75\x6c\x6c\x29\x7b\x74\x2e\x6c\x6f\x61\x64\x28\x63\x6f\x64\x65\x29\x3b\x7d\x7d\n\x72\x65\x74\x75\x72\x6e \x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72\x3b\x7d\x28\x29\x29\x3b\x7d)";
diff --git a/node_modules/webworker-threads/src/worker.ls b/node_modules/webworker-threads/src/worker.ls
new file mode 100644
index 0000000..4570bbb
--- /dev/null
+++ b/node_modules/webworker-threads/src/worker.ls
@@ -0,0 +1,18 @@
+function Worker () => Threads = this; class
+ (code) ->
+ @thread = t = Threads.create!
+ t.on \message (args) ~> @onmessage? data: args
+ t.on \error (args) ~> @onerror? args
+ t.on \close -> t.destroy!
+ @terminate = -> t.destroy!
+ @add-event-listener = (event, cb) ~>
+ if event is \message
+ @onmessage = cb
+ else
+ t.on event, cb
+ @dispatch-event = (event) -> t.emitSerialized event.type, event
+ @post-message = (data) -> t.emitSerialized \message {data}
+ if typeof code is \function
+ t.eval "(#code)()"
+ else if code?
+ t.load code
diff --git a/node_modules/webworker-threads/test.ls b/node_modules/webworker-threads/test.ls
new file mode 100755
index 0000000..a6610d0
--- /dev/null
+++ b/node_modules/webworker-threads/test.ls
@@ -0,0 +1,18 @@
+#!/usr/bin/env lsc
+{ Worker } = require \webworker-threads
+w = new Worker ->
+ # This also works, but less elegant:
+ # ``onmessage`` = (data: {max}) ->
+ @onmessage = (data: {max}) ->
+ :search for n from 2 to max
+ for i from 2 to Math.sqrt n
+ continue search unless n % i
+ postMessage { result: n }
+ throw \done
+w.onmessage = (data: {result}) ->
+ console.log "#result is a prime"
+w.onerror = ({data}) ->
+ console.log "Caught:", data
+ <~ setTimeout _, 100ms
+ @terminate!
+w.postMessage max: 100
diff --git a/node_modules/webworker-threads/test/ab.js b/node_modules/webworker-threads/test/ab.js
new file mode 100644
index 0000000..8fc6665
--- /dev/null
+++ b/node_modules/webworker-threads/test/ab.js
@@ -0,0 +1,96 @@
+
+
+var http= require('http');
+http.globalAgent.maxSockets= 16384;
+
+var options= {
+ port: +process.argv[2] || 1200
+};
+
+var results= {
+ requestsPerSecond: 0,
+ "duration(ms)": 0,
+ sent: 0,
+ connected: 0,
+ completed: 0,
+ errors: 0,
+ " QUICK": 1,
+ " 14930352": 1
+};
+
+
+var dsp= "";
+function display () {
+ process.stdout.write(dsp);
+ dsp= "";
+}
+
+//var displayInterval= setInterval(display, 333);
+
+function run (i) {
+ var now= Date.now();
+ if (now < (t+ duration)) {
+ if (results.sent <= (results.connected + results.errors)) {
+ i= 200;
+ while (i--) {
+ anotherOne();
+ }
+ }
+ setTimeout(run, 100);
+ }
+ else {
+ results["duration(ms)"]= now- t;
+ results.requestsPerSecond= (results.completed*1e3/(now-t)).toFixed(1);
+ //clearInterval(displayInterval);
+ display();
+ console.log("\n", results);
+ process.exit();
+ }
+
+}
+
+function anotherOne () {
+ results.sent++;
+ http.get(options, onConnect).on('error', onERR);
+}
+
+function onConnect (res) {
+ anotherOne();
+ res.on('data', onData);
+ results.connected++;
+ dsp+= ".";
+}
+
+function onData (txt) {
+ results[txt]++;
+ results.completed++;
+}
+
+function onERR (err) {
+ results.errors++;
+ dsp+= "❚";
+ console.log(err);
+}
+
+
+
+var t;
+var duration= 1000;
+(function wait () {
+ var exec= require('child_process').exec;
+ exec('netstat -f inet | grep -c TIME_WAIT', function (err, o, e) {
+ o= Math.floor(o+ e);
+ console.log("Sockets in TIME_WAIT: "+ o);
+ if (o) {
+ setTimeout(wait, 1500);
+ }
+ else {
+ console.log("GO!");
+ t= Date.now();
+ run();
+ }
+ });
+})();
+
+
+
diff --git a/node_modules/webworker-threads/test/test00_run_once_and_destroy.js b/node_modules/webworker-threads/test/test00_run_once_and_destroy.js
new file mode 100644
index 0000000..78eb895
--- /dev/null
+++ b/node_modules/webworker-threads/test/test00_run_once_and_destroy.js
@@ -0,0 +1,27 @@
+
+
+var Threads= require('webworker-threads');
+
+
+function cb (err, data) {
+ ++i;
+ console.log('['+ this.id+ '] -> '+ data);
+ this.destroy();
+}
+
+function ƒ () { return Math.random() }
+
+var i= +process.argv[2] || 1;
+console.log('Using '+ i+ ' threads');
+
+var t= Date.now();
+while (i--) {
+ Threads.create().eval(ƒ).eval('ƒ()', cb);
+}
+
+i= 0;
+process.on('exit', function () {
+ t= Date.now()- t;
+ console.log('THREADS PER SECOND -> '+ (i*1e3/t).toFixed(1));
+ console.log('BYE !');
+});
diff --git a/node_modules/webworker-threads/test/test01_loop_as_fast_as_possible.js b/node_modules/webworker-threads/test/test01_loop_as_fast_as_possible.js
new file mode 100644
index 0000000..f55d0d7
--- /dev/null
+++ b/node_modules/webworker-threads/test/test01_loop_as_fast_as_possible.js
@@ -0,0 +1,84 @@
+
+
+var Threads= require('webworker-threads');
+
+function cb (err, msg) {
+ i++;
+ threads[this.id]++;
+ this.eval(source, cb);
+ //process.stdout.write('['+ this.id+ ']');
+}
+
+
+function ƒ () { }
+var source= "ƒ()";
+
+var i= +process.argv[2] || 1;
+console.log('Using '+ i+ ' threads');
+
+var threads= [];
+while (i--) {
+ threads[i]= 0;
+ Threads.create().eval(ƒ)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb)
+ .eval(source, cb);
+ process.stdout.write('.');
+}
+
+i= 0;
+var t= Date.now();
+function display () {
+ var e= Date.now()- t;
+ var tps= (i*1e3/e).toFixed(1);
+ process.stdout.write('\nt (ms) -> '+ e+ ', i -> '+ i+ ', tps -> '+ tps+ ', [ '+ threads.map(percent)+ ' ]');
+ function percent (v) {
+ return Math.round(v/i*100);
+ }
+}
+
+
+
+setInterval(display, 1e3);
+
+function pi () {
+ var π= 0;
+ var num= 4;
+ var den= 1;
+ var plus= true;
+
+ while (den < 1e6) {
+ if (plus) {
+ π+= num/den;
+ plus= false;
+ }
+ else {
+ π-= num/den;
+ plus= true;
+ }
+ den+= 2;
+ }
+ return π;
+} \ No newline at end of file
diff --git a/node_modules/webworker-threads/test/test02_loop_as_fast_as_possible.js b/node_modules/webworker-threads/test/test02_loop_as_fast_as_possible.js
new file mode 100644
index 0000000..8585ec8
--- /dev/null
+++ b/node_modules/webworker-threads/test/test02_loop_as_fast_as_possible.js
@@ -0,0 +1,32 @@
+
+
+var Threads= require('webworker-threads');
+
+function cb (err, msg) {
+ i++;
+ this.eval(source, cb);
+ //process.stdout.write('['+ this.id+ ']');
+}
+
+
+function ƒ () { }
+var source= "ƒ()";
+
+var i= +process.argv[2] || 1;
+console.log('Using '+ i+ ' threads');
+
+
+while (i--) {
+ Threads.create().eval(ƒ).eval(source, cb);
+ process.stdout.write('.');
+}
+
+i= 0;
+var t= Date.now();
+function display () {
+ var e= Date.now()- t;
+ var tps= (i*1e3/e).toFixed(1);
+ console.log('t (ms) -> '+ e+ ', i -> '+ i+ ', tps -> '+ tps);
+}
+
+setInterval(display, 1e3);
diff --git a/node_modules/webworker-threads/test/test03_infiniteLoopFunction.js b/node_modules/webworker-threads/test/test03_infiniteLoopFunction.js
new file mode 100644
index 0000000..aca79c1
--- /dev/null
+++ b/node_modules/webworker-threads/test/test03_infiniteLoopFunction.js
@@ -0,0 +1,32 @@
+
+
+var Threads= require('webworker-threads');
+
+function cb (err, msg) {
+ ++i;
+ process.stdout.write('['+ this.id+ ']['+ i+ '] -> '+ msg+ '\n');
+ //process.stdout.write('['+ this.id+ ']');
+}
+
+function ƒ () { while (1) {} }
+
+
+var i= +process.argv[2] || 1;
+console.log('Using '+ i+ ' threads');
+
+var threads= [];
+var t= Date.now();
+while (i--) {
+ Threads.create().eval(ƒ).eval('ƒ()', cb);
+}
+
+
+i= 0;
+(function display () {
+ var e= Date.now()- t;
+ var tps= (i*1e3/e).toFixed(1);
+ console.log('\nTiempo total (ms) -> '+ e);
+ console.log('Threads por segundo -> '+ tps);
+ console.log('Total de threads ejecutadas -> '+ i);
+ setTimeout(display, 1e3);
+})();
diff --git a/node_modules/webworker-threads/test/test04_gc_versus_not_gc.js b/node_modules/webworker-threads/test/test04_gc_versus_not_gc.js
new file mode 100644
index 0000000..af745eb
--- /dev/null
+++ b/node_modules/webworker-threads/test/test04_gc_versus_not_gc.js
@@ -0,0 +1,44 @@
+
+
+var Threads= require('webworker-threads');
+
+console.log('Launch with/without --expose_gc to compare memory usage')
+
+function cb (err, msg) {
+ i++;
+ if (msg) console.log('['+ this.id+ ']'+ msg);
+ this.eval(source, cb);
+ //process.stdout.write('['+ this.id+ ']['+ i+ '] -> '+ msg+ '\n');
+ //process.stdout.write('['+ this.id+ ']');
+}
+
+
+function ƒ () {
+ if (++i % 10e3) return '';
+ try {
+ gc();
+ return ' -> gc()'
+ }
+ catch (e) {
+ return ' -> *NOT* gc()]';
+ }
+}
+var source= "ƒ()";
+
+var i= +process.argv[2] || 1;
+console.log('Using '+ i+ ' threads');
+
+
+while (i--) {
+ Threads.create().eval(ƒ+ '\nvar i= 0;').eval(source, cb);
+}
+
+i= 0;
+var t= Date.now();
+function display () {
+ var e= Date.now()- t;
+ var tps= (i*1e3/e).toFixed(1);
+ console.log('t (ms) -> '+ e+ ', i -> '+ i+ ', tps -> '+ tps);
+}
+
+setInterval(display, 1e3);
diff --git a/node_modules/webworker-threads/test/test05_debugLeaksNoCallbacks.js b/node_modules/webworker-threads/test/test05_debugLeaksNoCallbacks.js
new file mode 100644
index 0000000..ec006ec
--- /dev/null
+++ b/node_modules/webworker-threads/test/test05_debugLeaksNoCallbacks.js
@@ -0,0 +1,32 @@
+
+
+var Threads= require('webworker-threads');
+
+function ƒ () { return Math.random() }
+
+var i= +process.argv[2] || 1;
+console.log('Using '+ i+ ' threads');
+
+var threads= [];
+var t= Date.now();
+while (i--) {
+ var thread= Threads.create().eval(ƒ);
+ threads.push(thread);
+}
+
+i= 0;
+(function loop () {
+ threads.forEach(function (v) {
+ i++;
+ v.eval('ƒ()');
+ });
+ process.nextTick(loop); //segfaults
+})();
+
+
+(function display () {
+ var e= Date.now()- t;
+ var tps= (i*1e3/e).toFixed(1);
+ console.log('t (ms) -> '+ e+ ', tps -> '+ tps+ ', i -> '+ i);
+ setTimeout(display, 1e3);
+})();
diff --git a/node_modules/webworker-threads/test/test06_throw_from_the_thread.js b/node_modules/webworker-threads/test/test06_throw_from_the_thread.js
new file mode 100644
index 0000000..6e2ff62
--- /dev/null
+++ b/node_modules/webworker-threads/test/test06_throw_from_the_thread.js
@@ -0,0 +1,12 @@
+
+
+var Thread= require('webworker-threads');
+
+function cb (e,m) {
+ process.stdout.write('[ '+ e+ ', '+ m+ ' ]\n');
+ this.eval(src, cb);
+}
+
+var src= 'if (++i % 2) throw("An error -> "+ i); else ("No error -> "+ i);';
+
+Thread.create().eval('i=0').eval(src, cb);
diff --git a/node_modules/webworker-threads/test/test07_sigkill.js b/node_modules/webworker-threads/test/test07_sigkill.js
new file mode 100644
index 0000000..4749c14
--- /dev/null
+++ b/node_modules/webworker-threads/test/test07_sigkill.js
@@ -0,0 +1,24 @@
+
+
+var Thread= require('webworker-threads');
+
+
+function cb (e,m) {
+ this.ctr= this.ctr ? this.ctr+1 : 1;
+ console.log('['+ this.id+ '] -> '+ this.ctr);
+ if (this.ctr >= 9) this.destroy();
+ else this.eval('0', cb);
+}
+
+
+var i= +process.argv[2] || 1;
+console.log('Using '+ i+ ' threads');
+
+while (i--) {
+ Thread.create().eval('0', cb);
+}
+
+
+process.on('exit', function () {
+ console.log("process.on('exit') -> BYE!");
+});
diff --git a/node_modules/webworker-threads/test/test08_sigkill_leaks.js b/node_modules/webworker-threads/test/test08_sigkill_leaks.js
new file mode 100644
index 0000000..8b04c47
--- /dev/null
+++ b/node_modules/webworker-threads/test/test08_sigkill_leaks.js
@@ -0,0 +1,30 @@
+
+
+var Thread= require('webworker-threads');
+
+function cb (e,m) {
+ this.destroy();
+ console.log('['+this.id+'].destroy()');
+ //this.eval('0', cb);
+ again();
+}
+
+
+function again () {
+ Thread.create().eval('0', cb);
+}
+
+
+var i= +process.argv[2] || 1;
+console.log('Using '+ i+ ' threads');
+
+
+
+while (i--) {
+ again();
+}
+
+
+process.on('exit', function () {
+ console.log("process.on('exit') -> BYE!");
+});
diff --git a/node_modules/webworker-threads/test/test09_throw_from_the_callback.js b/node_modules/webworker-threads/test/test09_throw_from_the_callback.js
new file mode 100644
index 0000000..b5beddc
--- /dev/null
+++ b/node_modules/webworker-threads/test/test09_throw_from_the_callback.js
@@ -0,0 +1,15 @@
+
+
+var Thread= require('webworker-threads');
+
+function cb (e,m) {
+ console.log([e,m]);
+ this.destroy();
+ throw('An error');
+}
+
+Thread.create().eval('0', cb);
+
+process.on('uncaughtException', function () {
+ console.log('OK, BYE!');
+})
diff --git a/node_modules/webworker-threads/test/test10_node_nextTick_speed.js b/node_modules/webworker-threads/test/test10_node_nextTick_speed.js
new file mode 100644
index 0000000..1a31fc7
--- /dev/null
+++ b/node_modules/webworker-threads/test/test10_node_nextTick_speed.js
@@ -0,0 +1,35 @@
+
+
+var Threads= require('webworker-threads');
+
+function cb (err, msg) {
+ i++;
+ ƒ();
+ //process.stdout.write('['+ this.id+ ']');
+}
+
+
+function ƒ () { process.nextTick(cb) }
+
+var i= +process.argv[2] || 1;
+console.log('Using '+ i+ ' threads');
+
+var threads= [];
+while (i--) {
+ ƒ();
+}
+
+i= 0;
+var t= Date.now();
+function display () {
+ var e= Date.now()- t;
+ var tps= (i*1e3/e).toFixed(1);
+ process.stdout.write('\nt (ms) -> '+ e+ ', i -> '+ i+ ', tps -> '+ tps+ ', [ '+ threads.map(percent)+ ' ]');
+ function percent (v) {
+ return Math.round(v/i*100);
+ }
+}
+
+
+
+setInterval(display, 1e3); \ No newline at end of file
diff --git a/node_modules/webworker-threads/test/test11_multi_callbacks.js b/node_modules/webworker-threads/test/test11_multi_callbacks.js
new file mode 100644
index 0000000..9db4262
--- /dev/null
+++ b/node_modules/webworker-threads/test/test11_multi_callbacks.js
@@ -0,0 +1,38 @@
+
+
+var Threads= require('webworker-threads');
+
+function A (err, msg) {
+ i++;
+ this.eval('', B);
+ process.stdout.write('A');
+}
+
+function B (err, msg) {
+ i++;
+ this.eval('', C);
+ process.stdout.write('B');
+}
+
+function C (err, msg) {
+ i++;
+ this.eval('', A);
+ process.stdout.write('C');
+}
+
+var i= +process.argv[2] || 1;
+console.log('Using '+ i+ ' threads');
+
+while (i--) {
+ Threads.create().eval('0', A);
+ process.stdout.write('.');
+}
+
+i= 0;
+var t= Date.now();
+setInterval(function display () {
+ var e= Date.now()- t;
+ var tps= (i*1e3/e).toFixed(1);
+ process.stdout.write('\nt (ms) -> '+ e+ ', i -> '+ i+ ', tps -> '+ tps);
+}, 1e3);
+
diff --git a/node_modules/webworker-threads/test/test12_precompiled_vs_normal.js b/node_modules/webworker-threads/test/test12_precompiled_vs_normal.js
new file mode 100644
index 0000000..c4f86af
--- /dev/null
+++ b/node_modules/webworker-threads/test/test12_precompiled_vs_normal.js
@@ -0,0 +1,42 @@
+
+
+var Threads= require('webworker-threads');
+
+function A (err, msg) {
+ ctrA++;
+ this.eval(sourceText, A);
+ //process.stdout.write("\nA -> "+ msg);
+}
+
+function B (err, msg) {
+ ctrB++;
+ this.eval(precompiled, B);
+ //process.stdout.write("\nB -> "+ msg);
+}
+
+function ƒ () { return Math.random()* 10 }
+
+var sourceText= '('+ ƒ+ ')()';
+var precompiled= Threads.preCompile(sourceText);
+var i= +process.argv[2] || 1;
+console.log('Using '+ (i*2)+ ' threads');
+
+while (i--) {
+ var a= Threads.create();
+ var b= Threads.create();
+ b.eval(precompiled, B);
+ a.eval(sourceText, A);
+ process.stdout.write('.');
+}
+
+ctrA= 0;
+ctrB= 0;
+var t= Date.now();
+setInterval(function display () {
+ var e= Date.now()- t;
+ var tps= ((ctrA+ctrB)*1e3/e).toFixed(1);
+ var tpsA= (ctrA*1e3/e).toFixed(1);
+ var tpsB= (ctrB*1e3/e).toFixed(1);
+ process.stdout.write('\nt (ms) -> '+ e+ ', i -> '+ i+ ', tps -> '+ tps+ ', tpsA -> '+ tpsA+ ', tpsB -> '+ tpsB);
+}, 1e3);
+
diff --git a/node_modules/webworker-threads/test/test13_thread_nextTick_speed.js b/node_modules/webworker-threads/test/test13_thread_nextTick_speed.js
new file mode 100644
index 0000000..58e0e25
--- /dev/null
+++ b/node_modules/webworker-threads/test/test13_thread_nextTick_speed.js
@@ -0,0 +1,31 @@
+
+
+var Threads= require('webworker-threads');
+
+function ƒ () {
+ var i= 0;
+ var t= Date.now();
+
+ (function ƒ () {
+ thread.nextTick(ƒ);
+
+ if ((++i % 1e6) === 0) {
+ var e= Date.now()- t;
+ var cps= (i*1e3/e).toFixed(1);
+ thread.emit("data", cps);
+ }
+ })();
+
+}
+
+function onData (data) {
+ console.log(data);
+}
+
+var i= +process.argv[2] || 1;
+console.log('Using '+ i+ ' threads');
+
+while (i--) {
+ Threads.create().on('data', onData).eval(ƒ).eval('ƒ()');
+ process.stdout.write('.');
+}
diff --git a/node_modules/webworker-threads/test/test14_emit_once.js b/node_modules/webworker-threads/test/test14_emit_once.js
new file mode 100644
index 0000000..6b38812
--- /dev/null
+++ b/node_modules/webworker-threads/test/test14_emit_once.js
@@ -0,0 +1,20 @@
+
+
+var t= require('webworker-threads');
+
+function killHandler (data) {
+ console.log("GOT KILL with data -> "+ data);
+ o.destroy();
+}
+
+function boot () {
+ thread.once('kill', function (data) {
+ thread.emit('kill', data);
+ });
+}
+
+o= t.create().once('kill', killHandler).eval(boot).eval('boot()').emit('kill', "*** DATA");
+
+process.on('exit', function () {
+ console.log("Bye!");
+});
diff --git a/node_modules/webworker-threads/test/test15_emit_ping_pong.js b/node_modules/webworker-threads/test/test15_emit_ping_pong.js
new file mode 100644
index 0000000..98946a6
--- /dev/null
+++ b/node_modules/webworker-threads/test/test15_emit_ping_pong.js
@@ -0,0 +1,31 @@
+var t= require('webworker-threads');
+
+function eventHandler (data) {
+ ctr++;
+ this.emit('b', 0);
+}
+
+function boot () {
+ thread.on('b', eventHandler);
+
+ function eventHandler (data) {
+ thread.emit('a', 0);
+ }
+}
+
+var ctr= 0;
+var i= +process.argv[2] || 1;
+console.log('Using '+ i+ ' threads');
+
+var pool= t.createPool(i);
+pool.all.eval(boot).all.eval('boot()').on('a', eventHandler).all.emit('b', 0).all.emit('b', 0).all.emit('b', 0);
+
+
+var s= Date.now();
+function display () {
+ var e= Date.now()- s;
+ var ppps= (ctr*1e3/e).toFixed(1);
+ console.log("ping-pongs: "+ ctr+ ", ping-pongs-per-second: "+ ppps);
+}
+
+setInterval(display, 1e3);
diff --git a/node_modules/webworker-threads/test/test16_syntax_error_in_the_thread.js b/node_modules/webworker-threads/test/test16_syntax_error_in_the_thread.js
new file mode 100644
index 0000000..8a985ae
--- /dev/null
+++ b/node_modules/webworker-threads/test/test16_syntax_error_in_the_thread.js
@@ -0,0 +1,13 @@
+
+
+var Thread= require('webworker-threads');
+
+function cb (e,m) {
+ process.stdout.write('[ '+ e+ ', '+ m+ ', '+ (i++)+ ' ]\n');
+ this.eval(syntaxError, cb);
+}
+
+var i= 0;
+var syntaxError= 'if return then goto 1';
+
+Thread.create().eval(syntaxError, cb);
diff --git a/node_modules/webworker-threads/test/test17_pool_pi.js b/node_modules/webworker-threads/test/test17_pool_pi.js
new file mode 100644
index 0000000..1d8128f
--- /dev/null
+++ b/node_modules/webworker-threads/test/test17_pool_pi.js
@@ -0,0 +1,67 @@
+
+
+var T= require('webworker-threads');
+
+var i= process.argv[2] || 1;
+console.log("Creating a pool of "+ i+ " threads");
+
+var pool= T.createPool(i);
+
+pool.all.eval(pi);
+
+function pi () {
+ var π= 0;
+ var num= 4;
+ var den= 1;
+ var plus= true;
+
+ while (den < 1e7) {
+ if (plus) {
+ π+= num/den;
+ plus= false;
+ }
+ else {
+ π-= num/den;
+ plus= true;
+ }
+ den+= 2;
+ }
+ return π;
+}
+
+var piValue= pi()+ '';
+var ctr= 0;
+function cb (err, data) {
+ if (err) throw data;
+ if (data !== piValue) throw "*** BAD DATA -> "+ [piValue, data];
+ ctr++;
+ if (threads[this.id]) {
+ threads[this.id]+= 1;
+ }
+ else {
+ threads[this.id]= 1;
+ }
+}
+
+var threads= [];
+i= Math.floor(process.argv[3]) || 1e3;
+console.log("The pool will run "+ pi+ ' '+ i+ " times\n");
+while (i--) {
+ pool.any.eval("pi()", cb);
+}
+
+var t= Date.now();
+function display () {
+ var e= Date.now()- t;
+ var tps= (ctr*1e3/e).toFixed(1);
+ console.log("threadsPerSecond: "+ tps+ ', pool.pendingJobs: '+ pool.pendingJobs()+ ', pool.idleThreads: '+ pool.idleThreads());
+ console.log("distribution : "+ threads.join('+ ')+ "= "+ ctr+ "\n");
+ if (!pool.pendingJobs()) {
+ pool.destroy();
+ clearInterval(interval);
+ console.log("Done, BYE !");
+ }
+}
+
+var interval= setInterval(display, 1e3);
+
diff --git a/node_modules/webworker-threads/test/test18_pool_any_as_fast_as_possible.js b/node_modules/webworker-threads/test/test18_pool_any_as_fast_as_possible.js
new file mode 100644
index 0000000..06b2674
--- /dev/null
+++ b/node_modules/webworker-threads/test/test18_pool_any_as_fast_as_possible.js
@@ -0,0 +1,47 @@
+
+
+var T= require('webworker-threads');
+
+var i= Math.floor(process.argv[2]) || 1;
+console.log("Creating a pool of "+ i+ " threads");
+
+var pool= T.createPool(i);
+pool.all.eval(ƒ);
+
+function ƒ () { return 3.14 }
+
+var ctr= 0;
+function cb (err, data) {
+ if (err) throw data;
+ if (data !== '3.14') throw "*** BAD DATA ERROR -> "+ ['3.14', data];
+ ctr++;
+ if (threads[this.id]) {
+ threads[this.id]+= 1;
+ }
+ else {
+ threads[this.id]= 1;
+ }
+}
+
+var threads= [];
+i= Math.floor(process.argv[3]) || 4e5;
+console.log("The pool will run "+ ƒ+ ' '+ i+ " times\n");
+while (i--) {
+ pool.any.eval("ƒ()", cb);
+}
+
+var t= Date.now();
+function display () {
+ var e= Date.now()- t;
+ var tps= (ctr*1e3/e).toFixed(1);
+ console.log("threadsPerSecond: "+ tps+ ', pool.pendingJobs: '+ pool.pendingJobs()+ ', pool.idleThreads: '+ pool.idleThreads());
+ console.log("distribution : "+ threads.join('+ ')+ "= "+ ctr+ "\n");
+ if (!pool.pendingJobs()) {
+ pool.destroy();
+ clearInterval(interval);
+ console.log("Done, BYE !");
+ }
+}
+
+var interval= setInterval(display, 1e3);
+
diff --git a/node_modules/webworker-threads/test/test19_pool_emit_any_all.js b/node_modules/webworker-threads/test/test19_pool_emit_any_all.js
new file mode 100644
index 0000000..3133fd1
--- /dev/null
+++ b/node_modules/webworker-threads/test/test19_pool_emit_any_all.js
@@ -0,0 +1,37 @@
+
+
+var T= require('webworker-threads');
+
+var i= process.argv[2] || 1;
+console.log("Creating a pool of "+ i+ " threads");
+
+var pool= T.createPool(i);
+
+pool.all.eval('('+ ƒ+ ')()');
+
+pool.on('myEvent', function myEventHandler (data) {
+ console.log("Received myEvent with data -> "+ data);
+ if (data === "QUIT") {
+ setTimeout(function () { pool.destroy() }, 1e3);
+ }
+});
+
+function ƒ () {
+ thread.on('myEvent', function cb (data) {
+ thread.emit('myEvent', data);
+ });
+}
+
+
+console.log("pool.any.emit('myEvent', 'POOL.ANY')");
+pool.any.emit('myEvent', "POOL.ANY");
+
+console.log("pool.all.emit('myEvent', 'POOL.ALL')");
+pool.all.emit('myEvent', "POOL.ALL");
+
+console.log("pool.any.emit('myEvent', 'QUIT')");
+pool.any.emit('myEvent', "QUIT");
+
+process.on('exit', function () {
+ console.log("BYE !");
+});
diff --git a/node_modules/webworker-threads/test/test20_removeAllListeners.js b/node_modules/webworker-threads/test/test20_removeAllListeners.js
new file mode 100644
index 0000000..3550b0a
--- /dev/null
+++ b/node_modules/webworker-threads/test/test20_removeAllListeners.js
@@ -0,0 +1,23 @@
+
+
+var t= require('webworker-threads');
+
+function eHandler (data) {
+ console.log("TEST FAIL");
+}
+
+function boot () {
+ thread.on('e', function (data) {
+ thread.emit('e', 0);
+ });
+}
+
+o= t.create().once('e', eHandler).on('e', eHandler).eval(boot).eval('boot()').emit('e', 0).removeAllListeners();
+
+setTimeout(function () {
+ o.destroy();
+}, 1e3);
+
+process.on('exit', function () {
+ console.log("OK: Bye!");
+});
diff --git a/node_modules/webworker-threads/test/test21_emit_ping_pong_big_string.js b/node_modules/webworker-threads/test/test21_emit_ping_pong_big_string.js
new file mode 100644
index 0000000..a40ccc2
--- /dev/null
+++ b/node_modules/webworker-threads/test/test21_emit_ping_pong_big_string.js
@@ -0,0 +1,32 @@
+
+
+var i= 23; //8MB
+var big= "*";
+while (i--) big+= big;
+
+console.log("big.length is "+ big.length);
+
+var i= 0;
+var s= Date.now();
+var o= require('webworker-threads')
+ .create()
+ .eval(function boot () {
+ thread.on('b', function (data) {
+ thread.emit('a',data);
+ });
+ })
+ .eval('boot()')
+ .emit('b',big)
+ .on('a', function (data) {
+ o.emit('b',data);
+ i+= 2;
+ });
+
+
+function display () {
+ var e= Date.now()- s;
+ var ppps= (i*1e3/e).toFixed(1);
+ console.log("ping-pongs: "+ i+ ", ping-pongs-per-second: "+ ppps);
+}
+
+setInterval(display, 1e3);
diff --git a/node_modules/webworker-threads/test/test22_create_destroy_loop.js b/node_modules/webworker-threads/test/test22_create_destroy_loop.js
new file mode 100644
index 0000000..c568391
--- /dev/null
+++ b/node_modules/webworker-threads/test/test22_create_destroy_loop.js
@@ -0,0 +1,25 @@
+
+
+var T= require('webworker-threads');
+
+
+var i= 0;
+var k= 5;
+(function again () {
+ var j= k;
+ while (j--) {
+ T.create().destroy();
+ }
+ i+= k;
+ process.nextTick(again);
+})();
+
+
+var t= Date.now();
+function display () {
+ var e= Date.now()- t;
+ var tps= (i*1e3/e).toFixed(1);
+ process.stdout.write('\nt (ms) -> '+ e+ ', i -> '+ i+ ', created/destroyed-per-second -> '+ tps);
+}
+
+setInterval(display, 1e3); \ No newline at end of file
diff --git a/node_modules/webworker-threads/test/test23_create_destroy_loop.js b/node_modules/webworker-threads/test/test23_create_destroy_loop.js
new file mode 100644
index 0000000..3284e28
--- /dev/null
+++ b/node_modules/webworker-threads/test/test23_create_destroy_loop.js
@@ -0,0 +1,25 @@
+
+
+var T= require('webworker-threads');
+
+
+var i= 0;
+var k= 5;
+(function again () {
+ var j= k;
+ while (j--) {
+ T.create().destroy();
+ }
+ i+= k;
+ setTimeout(again, 5);
+})();
+
+
+var t= Date.now();
+function display () {
+ var e= Date.now()- t;
+ var tps= (i*1e3/e).toFixed(1);
+ process.stdout.write('\nt (ms) -> '+ e+ ', i -> '+ i+ ', created/destroyed-per-second -> '+ tps);
+}
+
+setInterval(display, 1e3); \ No newline at end of file
diff --git a/node_modules/webworker-threads/test/test24_puts.js b/node_modules/webworker-threads/test/test24_puts.js
new file mode 100644
index 0000000..7f52f3f
--- /dev/null
+++ b/node_modules/webworker-threads/test/test24_puts.js
@@ -0,0 +1,17 @@
+var Threads= require('webworker-threads');
+
+function cb (err, msg) {
+ if (err) {
+ process.stdout.write("["+ this.id+ "] -> "+ err+ '\n');
+ }
+ this.destroy();
+}
+
+function ƒ () {
+ puts("["+ thread.id+ "] -> puts('Hello!')\n");
+}
+
+var i= Math.abs(parseInt(process.argv[2], 10)) || 1;
+console.log('Using '+ i+ ' threads');
+
+Threads.createPool(i).all.eval(ƒ).all.eval('ƒ()', cb); \ No newline at end of file
diff --git a/node_modules/webworker-threads/test/test25_delete_puts.js b/node_modules/webworker-threads/test/test25_delete_puts.js
new file mode 100644
index 0000000..1e30fff
--- /dev/null
+++ b/node_modules/webworker-threads/test/test25_delete_puts.js
@@ -0,0 +1,23 @@
+/*
+
+If you don't want a thread to have the privilege of writing to stdout, simply delete its global puts symbol
+
+*/
+
+var Threads= require('webworker-threads');
+
+function cb (err, msg) {
+ if (err) {
+ process.stdout.write("["+ this.id+ "] -> "+ err+ '\n');
+ }
+ this.destroy();
+}
+
+function ƒ () {
+ puts("["+ thread.id+ "] -> puts('Hello!')\n");
+}
+
+var i= Math.abs(parseInt(process.argv[2], 10)) || 1;
+console.log('Using '+ i+ ' threads');
+
+Threads.createPool(i).all.eval('delete (global= this).puts; ('+ ƒ+ ')();', cb);
diff --git a/node_modules/webworker-threads/test/test26_puts_with_many_args.js b/node_modules/webworker-threads/test/test26_puts_with_many_args.js
new file mode 100644
index 0000000..51f9e12
--- /dev/null
+++ b/node_modules/webworker-threads/test/test26_puts_with_many_args.js
@@ -0,0 +1,18 @@
+var Threads= require('webworker-threads');
+
+function cb (err, msg) {
+ if (err) {
+ process.stdout.write("["+ this.id+ "] -> "+ err+ '\n');
+ }
+ this.destroy();
+}
+
+function ƒ () {
+ var prefix= "["+ thread.id+ "] -> ";
+ puts(prefix+ "1\n", prefix+ "2\n", prefix+ "3\n", prefix+ "4\n", prefix+ "5\n");
+}
+
+var i= Math.abs(parseInt(process.argv[2], 10)) || 1;
+console.log('Using '+ i+ ' threads');
+
+Threads.createPool(i).all.eval(ƒ).all.eval('ƒ()', cb); \ No newline at end of file
diff --git a/node_modules/webworker-threads/test/test27_puts_event_loop.js b/node_modules/webworker-threads/test/test27_puts_event_loop.js
new file mode 100644
index 0000000..fa1677b
--- /dev/null
+++ b/node_modules/webworker-threads/test/test27_puts_event_loop.js
@@ -0,0 +1,14 @@
+var i= parseInt(process.argv[2], 10) || 2;
+var pool= require('webworker-threads').createPool(i);
+console.log("Using "+ i+ " threads.");
+
+pool.on('again', function onAgain () {
+ this.eval('ƒ()');
+});
+
+function ƒ () {
+ puts(" ["+ thread.id+ "]"+ (++i));
+ thread.emit('again');
+}
+
+pool.all.eval(ƒ).all.eval('i=0').all.eval('ƒ()');
diff --git a/node_modules/webworker-threads/test/test28_puts_nextTick_loop.js b/node_modules/webworker-threads/test/test28_puts_nextTick_loop.js
new file mode 100644
index 0000000..513406f
--- /dev/null
+++ b/node_modules/webworker-threads/test/test28_puts_nextTick_loop.js
@@ -0,0 +1,14 @@
+var i= parseInt(process.argv[2], 10) || 2;
+var pool= require('webworker-threads').createPool(i);
+console.log("Using "+ i+ " threads.");
+
+function program () {
+ var i= 0;
+ function ƒ () {
+ puts(" ["+ thread.id+ "]"+ (++i));
+ thread.nextTick(ƒ);
+ }
+ ƒ();
+}
+
+pool.all.eval(program).all.eval('program()');
diff --git a/node_modules/webworker-threads/test/test29_puts_callback_loop.js b/node_modules/webworker-threads/test/test29_puts_callback_loop.js
new file mode 100644
index 0000000..d6cecae
--- /dev/null
+++ b/node_modules/webworker-threads/test/test29_puts_callback_loop.js
@@ -0,0 +1,14 @@
+var i= parseInt(process.argv[2], 10) || 2;
+var pool= require('webworker-threads').createPool(i);
+console.log("Using "+ i+ " threads.");
+
+function ƒ () {
+ puts(" ["+ thread.id+ "]"+ (++i));
+ //if (!(i%1e3)) gc();
+}
+
+function callback (err, data) {
+ this.eval('ƒ()', callback);
+}
+
+pool.all.eval('i=0').all.eval(ƒ).all.eval('ƒ()', callback);