summaryrefslogtreecommitdiff
path: root/node_modules/webworker-threads/src
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/src
Diffstat (limited to 'node_modules/webworker-threads/src')
-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
20 files changed, 3088 insertions, 0 deletions
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