summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorSimon Hafner <hafnersimon@gmail.com>2014-03-31 15:49:04 -0500
committerSimon Hafner <hafnersimon@gmail.com>2014-03-31 15:49:04 -0500
commitffb36db5a6caa147119aed1728c8042dfa68a3e8 (patch)
tree0db6e9c9b39a21511cf6d5a1c2f489e35a10ed60 /lib
parent565031f0cd4768962fb19ac4e17efb994dfb4735 (diff)
parent44ee8aecfd70d1d381b5eed5ae52b01fae04452b (diff)
downloadNim-ffb36db5a6caa147119aed1728c8042dfa68a3e8.tar.gz
Merge branch 'devel' of github.com:Araq/Nimrod into seq_toString
Diffstat (limited to 'lib')
-rw-r--r--lib/core/macros.nim10
-rw-r--r--lib/impure/db_mongo.nim227
-rw-r--r--lib/impure/db_mysql.nim12
-rw-r--r--lib/nimbase.h10
-rw-r--r--lib/packages/docutils/docutils.babel6
-rw-r--r--lib/packages/docutils/highlite.nim7
-rw-r--r--lib/packages/docutils/rst.nim2
-rw-r--r--lib/posix/epoll.nim8
-rw-r--r--lib/posix/linux.nim25
-rw-r--r--lib/posix/posix.nim4
-rw-r--r--lib/pure/algorithm.nim30
-rw-r--r--lib/pure/asyncdispatch.nim956
-rw-r--r--lib/pure/asyncdispatch.nimrod.cfg3
-rw-r--r--lib/pure/asyncio.nim10
-rw-r--r--lib/pure/asyncio2.nim485
-rw-r--r--lib/pure/asyncnet.nim195
-rw-r--r--lib/pure/dynlib.nim12
-rw-r--r--lib/pure/htmlgen.nim11
-rw-r--r--lib/pure/httpclient.nim239
-rw-r--r--lib/pure/math.nim4
-rw-r--r--lib/pure/memfiles.nim45
-rw-r--r--lib/pure/net.nim1109
-rw-r--r--lib/pure/nimprof.nim4
-rw-r--r--lib/pure/os.nim19
-rw-r--r--lib/pure/osproc.nim276
-rw-r--r--lib/pure/parsesql.nim2
-rw-r--r--lib/pure/pegs.nim8
-rw-r--r--lib/pure/rawsockets.nim421
-rw-r--r--lib/pure/selectors.nim386
-rw-r--r--lib/pure/sockets2.nim202
-rw-r--r--lib/pure/times.nim242
-rw-r--r--lib/stdlib.babel6
-rw-r--r--lib/system.nim142
-rw-r--r--lib/system/arithm.nim12
-rw-r--r--lib/system/endb.nim6
-rw-r--r--lib/system/jssys.nim117
-rw-r--r--lib/system/repr.nim6
-rw-r--r--lib/windows/winlean.nim7
-rw-r--r--lib/wrappers/mongo.nim1204
-rw-r--r--lib/wrappers/zip/zlib.nim3
-rw-r--r--lib/wrappers/zmq.nim7
41 files changed, 3798 insertions, 2682 deletions
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 585ccf869..8ccad8fe3 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -48,17 +48,17 @@ type
     nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
     nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt,
     nnkDiscardStmt, nnkStmtList, 
-    
     nnkImportStmt,
     nnkImportExceptStmt,
     nnkExportStmt,
     nnkExportExceptStmt,
     nnkFromStmt,
     nnkIncludeStmt,
-    
     nnkBindStmt, nnkMixinStmt, nnkUsingStmt,
     nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
-    nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
+    nnkStmtListType, nnkBlockType,
+    nnkWith, nnkWithout,
+    nnkTypeOfExpr, nnkObjectTy,
     nnkTupleTy, nnkTypeClassTy, nnkStaticTy,
     nnkRecList, nnkRecCase, nnkRecWhen,
     nnkRefTy, nnkPtrTy, nnkVarTy,
@@ -88,7 +88,7 @@ type
     nskUnknown, nskConditional, nskDynLib, nskParam,
     nskGenericParam, nskTemp, nskModule, nskType, nskVar, nskLet, 
     nskConst, nskResult,
-    nskProc, nskMethod, nskIterator,
+    nskProc, nskMethod, nskIterator, nskClosureIterator,
     nskConverter, nskMacro, nskTemplate, nskField,
     nskEnumField, nskForVar, nskLabel,
     nskStub
@@ -516,7 +516,7 @@ proc last*(node: PNimrodNode): PNimrodNode {.compileTime.} = node[node.high]
 
 
 const
-  RoutineNodes* = {nnkProcDef, nnkMethodDef, nnkDo, nnkLambda}
+  RoutineNodes* = {nnkProcDef, nnkMethodDef, nnkDo, nnkLambda, nnkIteratorDef}
   AtomicNodes* = {nnkNone..nnkNilLit}
   CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand, 
     nnkCallStrLit, nnkHiddenCallConv}
diff --git a/lib/impure/db_mongo.nim b/lib/impure/db_mongo.nim
deleted file mode 100644
index dc8a808f2..000000000
--- a/lib/impure/db_mongo.nim
+++ /dev/null
@@ -1,227 +0,0 @@
-#
-#
-#            Nimrod's Runtime Library
-#        (c) Copyright 2012 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## This module implements a higher level wrapper for `mongodb`:idx:. Example:
-##
-## .. code-block:: nimrod
-##
-##    import mongo, db_mongo, oids, json
-##
-##    var conn = db_mongo.open()
-##
-##    # construct JSON data:
-##    var data = %{"a": %13, "b": %"my string value", 
-##                 "inner": %{"i": %71} }
-##
-##    var id = insertID(conn, "test.test", data)
-##
-##    for v in find(conn, "test.test", "this.a == 13"):
-##      print v
-##
-##    delete(conn, "test.test", id)
-##    close(conn)
-
-import mongo, oids, json
-
-type
-  EDb* = object of EIO ## exception that is raised if a database error occurs
-  TDbConn* = TMongo    ## a database connection; alias for ``TMongo``
-
-  FDb* = object of FIO ## effect that denotes a database operation
-  FReadDb* = object of FDB   ## effect that denotes a read operation
-  FWriteDb* = object of FDB  ## effect that denotes a write operation
-
-proc dbError*(db: TDbConn, msg: string) {.noreturn.} = 
-  ## raises an EDb exception with message `msg`.
-  var e: ref EDb
-  new(e)
-  if db.errstr[0] != '\0':
-    e.msg = $db.errstr
-  else:
-    e.msg = $db.err & " " & msg
-  raise e
-
-proc close*(db: var TDbConn) {.tags: [FDB].} = 
-  ## closes the database connection.
-  disconnect(db)
-  destroy(db)
-
-proc open*(host: string = defaultHost, port: int = defaultPort): TDbConn {.
-  tags: [FDB].} =
-  ## opens a database connection. Raises `EDb` if the connection could not
-  ## be established.
-  init(result)
-  
-  let x = client(result, host, port.cint)
-  if x != 0'i32:
-    dbError(result, "cannot open: " & host)
-
-proc jsonToBSon(b: var TBSon, key: string, j: PJsonNode) =
-  case j.kind
-  of JString:
-    add(b, key, j.str)
-  of JInt:
-    add(b, key, j.num)
-  of JFloat:
-    add(b, key, j.fnum)
-  of JBool:
-    addBool(b, key, ord(j.bval))
-  of JNull:
-    addNull(b, key)
-  of JObject:
-    addStartObject(b, key)
-    for k, v in items(j.fields):
-      jsonToBSon(b, k, v)
-    addFinishObject(b)
-  of JArray:
-    addStartArray(b, key)
-    for i, e in pairs(j.elems):
-      jsonToBSon(b, $i, e)
-    addFinishArray(b)
-
-proc jsonToBSon*(j: PJsonNode, oid: TOid): TBSon =
-  ## converts a JSON value into the BSON format. The result must be
-  ## ``destroyed`` explicitely!
-  init(result)
-  assert j.kind == JObject
-  add(result, "_id", oid)
-  for key, val in items(j.fields):
-    jsonToBSon(result, key, val)
-  finish(result)
-
-proc `[]`*(obj: var TBSon, fieldname: cstring): TBSon =
-  ## retrieves the value belonging to `fieldname`. Raises `EInvalidKey` if
-  ## the attribute does not exist.
-  var it = initIter(obj)
-  let res = find(it, result, fieldname)
-  if res == bkEOO:
-    raise newException(EInvalidIndex, "key not in object")
-
-proc getId*(obj: var TBSon): TOid =
-  ## retrieves the ``_id`` attribute of `obj`.
-  var it = initIter(obj)
-  var b: TBSon
-  let res = find(it, b, "_id")
-  if res == bkOID:
-    result = oidVal(it)[]
-  else:
-    raise newException(EInvalidIndex, "_id not in object")
-
-proc insertId*(db: var TDbConn, namespace: string, data: PJsonNode): TOid {.
-  tags: [FWriteDb].} =
-  ## converts `data` to BSON format and inserts it in `namespace`. Returns
-  ## the generated OID for the ``_id`` field.
-  result = genOid()
-  var x = jsonToBSon(data, result)
-  insert(db, namespace, x, nil)
-  destroy(x)
-
-proc insert*(db: var TDbConn, namespace: string, data: PJsonNode) {.
-  tags: [FWriteDb].} =
-  ## converts `data` to BSON format and inserts it in `namespace`.  
-  discard InsertID(db, namespace, data)
-
-proc update*(db: var TDbConn, namespace: string, obj: var TBSon) {.
-  tags: [FReadDB, FWriteDb].} =
-  ## updates `obj` in `namespace`.
-  var cond: TBson
-  init(cond)
-  cond.add("_id", getId(obj))
-  finish(cond)
-  update(db, namespace, cond, obj, ord(UPDATE_UPSERT))
-  destroy(cond)
-
-proc update*(db: var TDbConn, namespace: string, oid: TOid, obj: PJsonNode) {.
-  tags: [FReadDB, FWriteDb].} =
-  ## updates the data with `oid` to have the new data `obj`.
-  var a = jsonToBSon(obj, oid)
-  Update(db, namespace, a)
-  destroy(a)
-
-proc delete*(db: var TDbConn, namespace: string, oid: TOid) {.
-  tags: [FWriteDb].} =
-  ## Deletes the object belonging to `oid`.
-  var cond: TBson
-  init(cond)
-  cond.add("_id", oid)
-  finish(cond)
-  discard remove(db, namespace, cond)
-  destroy(cond)
-
-proc delete*(db: var TDbConn, namespace: string, obj: var TBSon) {.
-  tags: [FWriteDb].} =
-  ## Deletes the object `obj`.
-  delete(db, namespace, getId(obj))
-
-iterator find*(db: var TDbConn, namespace: string): var TBSon {.
-  tags: [FReadDB].} =
-  ## iterates over any object in `namespace`.
-  var cursor: TCursor
-  init(cursor, db, namespace)
-  while next(cursor) == mongo.OK:
-    yield bson(cursor)[]
-  destroy(cursor)
-
-iterator find*(db: var TDbConn, namespace: string, 
-               query, fields: var TBSon): var TBSon {.tags: [FReadDB].} =
-  ## yields the `fields` of any document that suffices `query`.
-  var cursor = find(db, namespace, query, fields, 0'i32, 0'i32, 0'i32)
-  if cursor != nil:
-    while next(cursor[]) == mongo.OK:
-      yield bson(cursor[])[]
-    destroy(cursor[])
-
-proc setupFieldnames(fields: varargs[string]): TBSon =
-  init(result)
-  for x in fields: add(result, x, 1'i32)
-  finish(result)
-
-iterator find*(db: var TDbConn, namespace: string, 
-               query: var TBSon, fields: varargs[string]): var TBSon {.
-               tags: [FReadDB].} =
-  ## yields the `fields` of any document that suffices `query`. If `fields` 
-  ## is ``[]`` the whole document is yielded.
-  var f = setupFieldnames(fields)
-  var cursor = find(db, namespace, query, f, 0'i32, 0'i32, 0'i32)
-  if cursor != nil:
-    while next(cursor[]) == mongo.OK:
-      yield bson(cursor[])[]
-    destroy(cursor[])
-  destroy(f)
-
-proc setupQuery(query: string): TBSon =
-  init(result)
-  add(result, "$where", query)
-  finish(result)
-
-iterator find*(db: var TDbConn, namespace: string, 
-               query: string, fields: varargs[string]): var TBSon {.
-               tags: [FReadDB].} =
-  ## yields the `fields` of any document that suffices `query`. If `fields` 
-  ## is ``[]`` the whole document is yielded.
-  var f = setupFieldnames(fields)
-  var q = setupQuery(query)
-  var cursor = find(db, namespace, q, f, 0'i32, 0'i32, 0'i32)
-  if cursor != nil:
-    while next(cursor[]) == mongo.OK:
-      yield bson(cursor[])[]
-    destroy(cursor[])
-  destroy(q)
-  destroy(f)
-
-when false:
-  # this doesn't work this way; would require low level hacking
-  iterator fieldPairs*(obj: var TBSon): tuple[key: cstring, value: TBSon] =
-    ## iterates over `obj` and yields all (key, value)-Pairs.
-    var it = initIter(obj)
-    var v: TBSon
-    while next(it) != bkEOO:
-      let key = key(it)
-      discard init(v, value(it))
-      yield (key, v)
diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim
index 8cdccda01..32cda3e4d 100644
--- a/lib/impure/db_mysql.nim
+++ b/lib/impure/db_mysql.nim
@@ -87,7 +87,7 @@ proc newRow(L: int): TRow =
   
 proc properFreeResult(sqlres: mysql.PRES, row: cstringArray) =  
   if row != nil:
-    while mysql.FetchRow(sqlres) != nil: nil
+    while mysql.FetchRow(sqlres) != nil: discard
   mysql.FreeResult(sqlres)
   
 iterator fastRows*(db: TDbConn, query: TSqlQuery,
@@ -195,8 +195,14 @@ proc open*(connection, user, password, database: string): TDbConn {.
   ## be established.
   result = mysql.Init(nil)
   if result == nil: dbError("could not open database connection") 
-  if mysql.RealConnect(result, "", user, password, database, 
-                       0'i32, nil, 0) == nil:
+  let
+    colonPos = connection.find(':')
+    host =        if colonPos < 0: connection
+                  else:            substr(connection, 0, colonPos-1)
+    port: int32 = if colonPos < 0: 0'i32
+                  else:            substr(connection, colonPos+1).parseInt.int32
+  if mysql.RealConnect(result, host, user, password, database, 
+                       port, nil, 0) == nil:
     var errmsg = $mysql.error(result)
     db_mysql.Close(result)
     dbError(errmsg)
diff --git a/lib/nimbase.h b/lib/nimbase.h
index 19d161adf..b16b27b2c 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -285,8 +285,8 @@ static N_INLINE(NI32, float32ToInt32)(float x) {
 
 typedef struct TStringDesc* string;
 
-/* declared size of a sequence: */
-#if defined(__GNUC__)
+/* declared size of a sequence/variable length array: */
+#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)
 #  define SEQ_DECL_SIZE /* empty is correct! */
 #else
 #  define SEQ_DECL_SIZE 1000000
@@ -314,6 +314,9 @@ static unsigned long nimNaN[2]={0xffffffff, 0x7fffffff};
 #    define INF INFINITY
 #  elif defined(HUGE_VAL)
 #    define INF  HUGE_VAL
+#  elif defined(_MSC_VER)
+#    include <float.h>
+#    define INF (DBL_MAX+DBL_MAX)
 #  else
 #    define INF (1.0 / 0.0)
 #  endif
@@ -373,5 +376,8 @@ static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); }
 #  define GC_GUARD
 #endif
 
+/* Test to see if nimrod and the C compiler agrees on the size of a pointer.
+   On disagreement, your C compiler will say something like: 
+   "error: 'assert_numbits' declared as an array with a negative size" */
 typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8 ? 1 : -1];
 #endif
diff --git a/lib/packages/docutils/docutils.babel b/lib/packages/docutils/docutils.babel
new file mode 100644
index 000000000..1ed86ca05
--- /dev/null
+++ b/lib/packages/docutils/docutils.babel
@@ -0,0 +1,6 @@
+[Package]
+name          = "docutils"
+version       = "0.9.0"
+author        = "Andreas Rumpf"
+description   = "Nimrod's reStructuredText processor."
+license       = "MIT"
diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim
index 4ca0c79e0..c507f5e1c 100644
--- a/lib/packages/docutils/highlite.nim
+++ b/lib/packages/docutils/highlite.nim
@@ -61,9 +61,8 @@ proc getSourceLanguage*(name: string): TSourceLanguage =
     if cmpIgnoreStyle(name, sourceLanguageToStr[i]) == 0: 
       return i
   result = langNone
-
-proc initGeneralTokenizer*(g: var TGeneralTokenizer, buf: string) = 
-  g.buf = cstring(buf)
+proc initGeneralTokenizer*(g: var TGeneralTokenizer, buf: cstring) =
+  g.buf = buf
   g.kind = low(TTokenClass)
   g.start = 0
   g.length = 0
@@ -71,6 +70,8 @@ proc initGeneralTokenizer*(g: var TGeneralTokenizer, buf: string) =
   var pos = 0                     # skip initial whitespace:
   while g.buf[pos] in {' ', '\x09'..'\x0D'}: inc(pos)
   g.pos = pos
+proc initGeneralTokenizer*(g: var TGeneralTokenizer, buf: string) = 
+  initGeneralTokenizer(g, cstring(buf))
 
 proc deinitGeneralTokenizer*(g: var TGeneralTokenizer) = 
   discard
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim
index bb018bc1e..30cc9026b 100644
--- a/lib/packages/docutils/rst.nim
+++ b/lib/packages/docutils/rst.nim
@@ -1543,7 +1543,7 @@ proc dirRaw(p: var TRstParser): PRstNode =
     elif cmpIgnoreCase(result.sons[0].sons[0].text, "latex") == 0: 
       dirRawAux(p, result, rnRawLatex, parseLiteralBlock)
     else:
-      rstMessage(p, meInvalidDirective, result.sons[0].text)
+      rstMessage(p, meInvalidDirective, result.sons[0].sons[0].text)
   else:
     dirRawAux(p, result, rnRaw, parseSectionWrapper)
 
diff --git a/lib/posix/epoll.nim b/lib/posix/epoll.nim
index d50394f60..57a2f001f 100644
--- a/lib/posix/epoll.nim
+++ b/lib/posix/epoll.nim
@@ -7,6 +7,8 @@
 #    distribution, for details about the copyright.
 #
 
+from posix import TSocketHandle
+
 const
   EPOLLIN* = 0x00000001
   EPOLLPRI* = 0x00000002
@@ -33,8 +35,8 @@ const
 type 
   epoll_data* {.importc: "union epoll_data", 
       header: "<sys/epoll.h>", pure, final.} = object # TODO: This is actually a union.
-    thePtr* {.importc: "ptr".}: pointer # \
-    #fd*: cint
+    #thePtr* {.importc: "ptr".}: pointer
+    fd* {.importc: "fd".}: cint # \
     #u32*: uint32
     #u64*: uint64
 
@@ -54,7 +56,7 @@ proc epoll_create1*(flags: cint): cint {.importc: "epoll_create1",
   ## Same as epoll_create but with an FLAGS parameter.  The unused SIZE
   ##   parameter has been dropped.  
 
-proc epoll_ctl*(epfd: cint; op: cint; fd: cint; event: ptr epoll_event): cint {.
+proc epoll_ctl*(epfd: cint; op: cint; fd: cint | TSocketHandle; event: ptr epoll_event): cint {.
     importc: "epoll_ctl", header: "<sys/epoll.h>".}
   ## Manipulate an epoll instance "epfd". Returns 0 in case of success,
   ##   -1 in case of error ( the "errno" variable will contain the
diff --git a/lib/posix/linux.nim b/lib/posix/linux.nim
new file mode 100644
index 000000000..1ed1af3b6
--- /dev/null
+++ b/lib/posix/linux.nim
@@ -0,0 +1,25 @@
+import posix
+
+const
+  CSIGNAL* = 0x000000FF
+  CLONE_VM* = 0x00000100
+  CLONE_FS* = 0x00000200
+  CLONE_FILES* = 0x00000400
+  CLONE_SIGHAND* = 0x00000800
+  CLONE_PTRACE* = 0x00002000
+  CLONE_VFORK* = 0x00004000
+  CLONE_PARENT* = 0x00008000
+  CLONE_THREAD* = 0x00010000
+  CLONE_NEWNS* = 0x00020000
+  CLONE_SYSVSEM* = 0x00040000
+  CLONE_SETTLS* = 0x00080000
+  CLONE_PARENT_SETTID* = 0x00100000
+  CLONE_CHILD_CLEARTID* = 0x00200000
+  CLONE_DETACHED* = 0x00400000
+  CLONE_UNTRACED* = 0x00800000
+  CLONE_CHILD_SETTID* = 0x01000000
+  CLONE_STOPPED* = 0x02000000
+
+# fn should be of type proc (a2: pointer): void {.cdecl.}
+proc clone*(fn: pointer; child_stack: pointer; flags: cint;
+            arg: pointer; ptid: ptr TPid; tls: pointer; ctid: ptr TPid): cint {.importc, header: "<sched.h>".}
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
index 41260b36f..131f23fdd 100644
--- a/lib/posix/posix.nim
+++ b/lib/posix/posix.nim
@@ -2066,6 +2066,7 @@ proc pthread_spin_unlock*(a1: ptr Tpthread_spinlock): cint {.
 proc pthread_testcancel*() {.importc, header: "<pthread.h>".}
 
 
+proc exitnow*(code: int): void {.importc: "_exit", header: "<unistd.h>".}
 proc access*(a1: cstring, a2: cint): cint {.importc, header: "<unistd.h>".}
 proc alarm*(a1: cint): cint {.importc, header: "<unistd.h>".}
 proc chdir*(a1: cstring): cint {.importc, header: "<unistd.h>".}
@@ -2265,6 +2266,7 @@ proc gmtime_r*(a1: var TTime, a2: var Ttm): ptr Ttm {.importc, header: "<time.h>
 proc localtime*(a1: var TTime): ptr Ttm {.importc, header: "<time.h>".}
 proc localtime_r*(a1: var TTime, a2: var Ttm): ptr Ttm {.importc, header: "<time.h>".}
 proc mktime*(a1: var Ttm): TTime  {.importc, header: "<time.h>".}
+proc timegm*(a1: var Ttm): TTime  {.importc, header: "<time.h>".}
 proc nanosleep*(a1, a2: var Ttimespec): cint {.importc, header: "<time.h>".}
 proc strftime*(a1: cstring, a2: int, a3: cstring,
            a4: var Ttm): int {.importc, header: "<time.h>".}
@@ -2356,7 +2358,7 @@ proc FD_ZERO*(a1: var TFdSet) {.importc, header: "<sys/select.h>".}
 
 proc pselect*(a1: cint, a2, a3, a4: ptr TFdSet, a5: ptr Ttimespec,
          a6: var Tsigset): cint  {.importc, header: "<sys/select.h>".}
-proc select*(a1: cint, a2, a3, a4: ptr TFdSet, a5: ptr Ttimeval): cint {.
+proc select*(a1: cint | TSocketHandle, a2, a3, a4: ptr TFdSet, a5: ptr Ttimeval): cint {.
              importc, header: "<sys/select.h>".}
 
 when hasSpawnH:
diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim
index 921c659de..37fbc948c 100644
--- a/lib/pure/algorithm.nim
+++ b/lib/pure/algorithm.nim
@@ -55,6 +55,36 @@ proc smartBinarySearch*[T](a: openArray[T], key: T): int =
 const
   onlySafeCode = true
 
+proc lowerBound*[T](a: openarray[T], key: T, cmp: proc(x,y: T): int {.closure.}): int =
+  ## same as binarySearch except that if key is not in `a` then this 
+  ## returns the location where `key` would be if it were. In other
+  ## words if you have a sorted sequence and you call insert(thing, elm, lowerBound(thing, elm))
+  ## the sequence will still be sorted
+  ##
+  ## `cmp` is the comparator function to use, the expected return values are the same as
+  ## that of system.cmp
+  ## 
+  ## example::
+  ##
+  ##   var arr = @[1,2,3,5,6,7,8,9]
+  ##   arr.insert(4, arr.lowerBound(4))
+  ## `after running the above arr is `[1,2,3,4,5,6,7,8,9]`
+  result = a.low
+  var pos = result
+  var count, step: int
+  count = a.high - a.low + 1
+  while count != 0:
+    pos = result
+    step = count div 2
+    pos += step
+    if cmp(a[pos], key) < 0:
+      pos.inc
+      result = pos
+      count -= step + 1
+    else:
+      count = step
+
+proc lowerBound*[T](a: openarray[T], key: T): int = lowerBound(a, key, cmp[T])
 proc merge[T](a, b: var openArray[T], lo, m, hi: int, 
               cmp: proc (x, y: T): int {.closure.}, order: TSortOrder) =
   template `<-` (a, b: expr) = 
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
new file mode 100644
index 000000000..344652c9f
--- /dev/null
+++ b/lib/pure/asyncdispatch.nim
@@ -0,0 +1,956 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2014 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import os, oids, tables, strutils, macros
+
+import rawsockets
+
+## AsyncDispatch
+## --------
+##
+## This module implements a brand new dispatcher based on Futures.
+## On Windows IOCP is used and on other operating systems the selectors module
+## is used instead.
+
+# -- Futures
+
+type
+  PFutureBase* = ref object of PObject
+    cb: proc () {.closure.}
+    finished: bool
+
+  PFuture*[T] = ref object of PFutureBase
+    value: T
+    error*: ref EBase # TODO: This shouldn't be necessary, generics bug?
+
+proc newFuture*[T](): PFuture[T] =
+  ## Creates a new future.
+  new(result)
+  result.finished = false
+
+proc complete*[T](future: PFuture[T], val: T) =
+  ## Completes ``future`` with value ``val``.
+  assert(not future.finished, "Future already finished, cannot finish twice.")
+  assert(future.error == nil)
+  future.value = val
+  future.finished = true
+  if future.cb != nil:
+    future.cb()
+
+proc complete*(future: PFuture[void]) =
+  ## Completes a void ``future``.
+  assert(not future.finished, "Future already finished, cannot finish twice.")
+  assert(future.error == nil)
+  future.finished = true
+  if future.cb != nil:
+    future.cb()
+
+proc fail*[T](future: PFuture[T], error: ref EBase) =
+  ## Completes ``future`` with ``error``.
+  assert(not future.finished, "Future already finished, cannot finish twice.")
+  future.finished = true
+  future.error = error
+  if future.cb != nil:
+    future.cb()
+
+proc `callback=`*(future: PFutureBase, cb: proc () {.closure.}) =
+  ## Sets the callback proc to be called when the future completes.
+  ##
+  ## If future has already completed then ``cb`` will be called immediately.
+  ##
+  ## **Note**: You most likely want the other ``callback`` setter which
+  ## passes ``future`` as a param to the callback.
+  future.cb = cb
+  if future.finished:
+    future.cb()
+
+proc `callback=`*[T](future: PFuture[T],
+    cb: proc (future: PFuture[T]) {.closure.}) =
+  ## Sets the callback proc to be called when the future completes.
+  ##
+  ## If future has already completed then ``cb`` will be called immediately.
+  future.callback = proc () = cb(future)
+
+proc read*[T](future: PFuture[T]): T =
+  ## Retrieves the value of ``future``. Future must be finished otherwise
+  ## this function will fail with a ``EInvalidValue`` exception.
+  ##
+  ## If the result of the future is an error then that error will be raised.
+  if future.finished:
+    if future.error != nil: raise future.error
+    when T isnot void:
+      return future.value
+  else:
+    # TODO: Make a custom exception type for this?
+    raise newException(EInvalidValue, "Future still in progress.")
+
+proc readError*[T](future: PFuture[T]): ref EBase =
+  if future.error != nil: return future.error
+  else:
+    raise newException(EInvalidValue, "No error in future.")
+
+proc finished*[T](future: PFuture[T]): bool =
+  ## Determines whether ``future`` has completed.
+  ##
+  ## ``True`` may indicate an error or a value. Use ``failed`` to distinguish.
+  future.finished
+
+proc failed*[T](future: PFuture[T]): bool =
+  ## Determines whether ``future`` completed with an error.
+  future.error != nil
+
+when defined(windows) or defined(nimdoc):
+  import winlean, sets, hashes
+  type
+    TCompletionKey = dword
+
+    TCompletionData* = object
+      sock: TAsyncFD
+      cb: proc (sock: TAsyncFD, bytesTransferred: DWORD,
+                errcode: TOSErrorCode) {.closure.}
+
+    PDispatcher* = ref object
+      ioPort: THandle
+      handles: TSet[TAsyncFD]
+
+    TCustomOverlapped = object
+      Internal*: DWORD
+      InternalHigh*: DWORD
+      Offset*: DWORD
+      OffsetHigh*: DWORD
+      hEvent*: THANDLE
+      data*: TCompletionData
+
+    PCustomOverlapped = ptr TCustomOverlapped
+
+    TAsyncFD* = distinct int
+
+  proc hash(x: TAsyncFD): THash {.borrow.}
+  proc `==`*(x: TAsyncFD, y: TAsyncFD): bool {.borrow.}
+
+  proc newDispatcher*(): PDispatcher =
+    ## Creates a new Dispatcher instance.
+    new result
+    result.ioPort = CreateIOCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1)
+    result.handles = initSet[TAsyncFD]()
+
+  var gDisp{.threadvar.}: PDispatcher ## Global dispatcher
+  proc getGlobalDispatcher*(): PDispatcher =
+    ## Retrieves the global thread-local dispatcher.
+    if gDisp.isNil: gDisp = newDispatcher()
+    result = gDisp
+
+  proc register*(sock: TAsyncFD) =
+    ## Registers ``sock`` with the dispatcher.
+    let p = getGlobalDispatcher()
+    if CreateIOCompletionPort(sock.THandle, p.ioPort,
+                              cast[TCompletionKey](sock), 1) == 0:
+      OSError(OSLastError())
+    p.handles.incl(sock)
+
+  proc verifyPresence(sock: TAsyncFD) =
+    ## Ensures that socket has been registered with the dispatcher.
+    let p = getGlobalDispatcher()
+    if sock notin p.handles:
+      raise newException(EInvalidValue,
+        "Operation performed on a socket which has not been registered with" &
+        " the dispatcher yet.")
+
+  proc poll*(timeout = 500) =
+    ## Waits for completion events and processes them.
+    let p = getGlobalDispatcher()
+    if p.handles.len == 0:
+      raise newException(EInvalidValue, "No handles registered in dispatcher.")
+    
+    let llTimeout =
+      if timeout ==  -1: winlean.INFINITE
+      else: timeout.int32
+    var lpNumberOfBytesTransferred: DWORD
+    var lpCompletionKey: ULONG
+    var lpOverlapped: POverlapped
+    let res = GetQueuedCompletionStatus(p.ioPort, addr lpNumberOfBytesTransferred,
+        addr lpCompletionKey, addr lpOverlapped, llTimeout).bool
+
+    # http://stackoverflow.com/a/12277264/492186
+    # TODO: http://www.serverframework.com/handling-multiple-pending-socket-read-and-write-operations.html
+    var customOverlapped = cast[PCustomOverlapped](lpOverlapped)
+    if res:
+      # This is useful for ensuring the reliability of the overlapped struct.
+      assert customOverlapped.data.sock == lpCompletionKey.TAsyncFD
+
+      customOverlapped.data.cb(customOverlapped.data.sock,
+          lpNumberOfBytesTransferred, TOSErrorCode(-1))
+      dealloc(customOverlapped)
+    else:
+      let errCode = OSLastError()
+      if lpOverlapped != nil:
+        assert customOverlapped.data.sock == lpCompletionKey.TAsyncFD
+        customOverlapped.data.cb(customOverlapped.data.sock,
+            lpNumberOfBytesTransferred, errCode)
+        dealloc(customOverlapped)
+      else:
+        if errCode.int32 == WAIT_TIMEOUT:
+          # Timed out
+          discard
+        else: OSError(errCode)
+
+  var connectExPtr: pointer = nil
+  var acceptExPtr: pointer = nil
+  var getAcceptExSockAddrsPtr: pointer = nil
+
+  proc initPointer(s: TSocketHandle, func: var pointer, guid: var TGUID): bool =
+    # Ref: https://github.com/powdahound/twisted/blob/master/twisted/internet/iocpreactor/iocpsupport/winsock_pointers.c
+    var bytesRet: DWord
+    func = nil
+    result = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, addr guid,
+                      sizeof(TGUID).dword, addr func, sizeof(pointer).DWORD,
+                      addr bytesRet, nil, nil) == 0
+
+  proc initAll() =
+    let dummySock = newRawSocket()
+    if not initPointer(dummySock, connectExPtr, WSAID_CONNECTEX):
+      OSError(OSLastError())
+    if not initPointer(dummySock, acceptExPtr, WSAID_ACCEPTEX):
+      OSError(OSLastError())
+    if not initPointer(dummySock, getAcceptExSockAddrsPtr, WSAID_GETACCEPTEXSOCKADDRS):
+      OSError(OSLastError())
+
+  proc connectEx(s: TSocketHandle, name: ptr TSockAddr, namelen: cint, 
+                  lpSendBuffer: pointer, dwSendDataLength: dword,
+                  lpdwBytesSent: PDWORD, lpOverlapped: POverlapped): bool =
+    if connectExPtr.isNil: raise newException(EInvalidValue, "Need to initialise ConnectEx().")
+    let func =
+      cast[proc (s: TSocketHandle, name: ptr TSockAddr, namelen: cint, 
+         lpSendBuffer: pointer, dwSendDataLength: dword,
+         lpdwBytesSent: PDWORD, lpOverlapped: POverlapped): bool {.stdcall.}](connectExPtr)
+
+    result = func(s, name, namelen, lpSendBuffer, dwSendDataLength, lpdwBytesSent,
+         lpOverlapped)
+
+  proc acceptEx(listenSock, acceptSock: TSocketHandle, lpOutputBuffer: pointer,
+                 dwReceiveDataLength, dwLocalAddressLength,
+                 dwRemoteAddressLength: DWORD, lpdwBytesReceived: PDWORD,
+                 lpOverlapped: POverlapped): bool =
+    if acceptExPtr.isNil: raise newException(EInvalidValue, "Need to initialise AcceptEx().")
+    let func =
+      cast[proc (listenSock, acceptSock: TSocketHandle, lpOutputBuffer: pointer,
+                 dwReceiveDataLength, dwLocalAddressLength,
+                 dwRemoteAddressLength: DWORD, lpdwBytesReceived: PDWORD,
+                 lpOverlapped: POverlapped): bool {.stdcall.}](acceptExPtr)
+    result = func(listenSock, acceptSock, lpOutputBuffer, dwReceiveDataLength,
+        dwLocalAddressLength, dwRemoteAddressLength, lpdwBytesReceived,
+        lpOverlapped)
+
+  proc getAcceptExSockaddrs(lpOutputBuffer: pointer,
+      dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength: DWORD,
+      LocalSockaddr: ptr ptr TSockAddr, LocalSockaddrLength: lpint,
+      RemoteSockaddr: ptr ptr TSockAddr, RemoteSockaddrLength: lpint) =
+    if getAcceptExSockAddrsPtr.isNil:
+      raise newException(EInvalidValue, "Need to initialise getAcceptExSockAddrs().")
+
+    let func =
+      cast[proc (lpOutputBuffer: pointer,
+                 dwReceiveDataLength, dwLocalAddressLength,
+                 dwRemoteAddressLength: DWORD, LocalSockaddr: ptr ptr TSockAddr,
+                 LocalSockaddrLength: lpint, RemoteSockaddr: ptr ptr TSockAddr,
+                RemoteSockaddrLength: lpint) {.stdcall.}](getAcceptExSockAddrsPtr)
+    
+    func(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength,
+                  dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength,
+                  RemoteSockaddr, RemoteSockaddrLength)
+
+  proc connect*(socket: TAsyncFD, address: string, port: TPort,
+    af = AF_INET): PFuture[void] =
+    ## Connects ``socket`` to server at ``address:port``.
+    ##
+    ## Returns a ``PFuture`` which will complete when the connection succeeds
+    ## or an error occurs.
+    verifyPresence(socket)
+    var retFuture = newFuture[void]()
+    # Apparently ``ConnectEx`` expects the socket to be initially bound:
+    var saddr: Tsockaddr_in
+    saddr.sin_family = int16(toInt(af))
+    saddr.sin_port = 0
+    saddr.sin_addr.s_addr = INADDR_ANY
+    if bindAddr(socket.TSocketHandle, cast[ptr TSockAddr](addr(saddr)),
+                  sizeof(saddr).TSockLen) < 0'i32:
+      OSError(OSLastError())
+
+    var aiList = getAddrInfo(address, port, af)
+    var success = false
+    var lastError: TOSErrorCode
+    var it = aiList
+    while it != nil:
+      # "the OVERLAPPED structure must remain valid until the I/O completes"
+      # http://blogs.msdn.com/b/oldnewthing/archive/2011/02/02/10123392.aspx
+      var ol = cast[PCustomOverlapped](alloc0(sizeof(TCustomOverlapped)))
+      ol.data = TCompletionData(sock: socket, cb:
+        proc (sock: TAsyncFD, bytesCount: DWord, errcode: TOSErrorCode) =
+          if not retFuture.finished:
+            if errcode == TOSErrorCode(-1):
+              retFuture.complete()
+            else:
+              retFuture.fail(newException(EOS, osErrorMsg(errcode)))
+      )
+      
+      var ret = connectEx(socket.TSocketHandle, it.ai_addr,
+                          sizeof(TSockAddrIn).cint, nil, 0, nil,
+                          cast[POverlapped](ol))
+      if ret:
+        # Request to connect completed immediately.
+        success = true
+        retFuture.complete()
+        # We don't deallocate ``ol`` here because even though this completed
+        # immediately poll will still be notified about its completion and it will
+        # free ``ol``.
+        break
+      else:
+        lastError = OSLastError()
+        if lastError.int32 == ERROR_IO_PENDING:
+          # In this case ``ol`` will be deallocated in ``poll``.
+          success = true
+          break
+        else:
+          dealloc(ol)
+          success = false
+      it = it.ai_next
+
+    dealloc(aiList)
+    if not success:
+      retFuture.fail(newException(EOS, osErrorMsg(lastError)))
+    return retFuture
+
+  proc recv*(socket: TAsyncFD, size: int,
+             flags: int = 0): PFuture[string] =
+    ## Reads ``size`` bytes from ``socket``. Returned future will complete once
+    ## all of the requested data is read. If socket is disconnected during the
+    ## recv operation then the future may complete with only a part of the
+    ## requested data read. If socket is disconnected and no data is available
+    ## to be read then the future will complete with a value of ``""``.
+    verifyPresence(socket)
+    var retFuture = newFuture[string]()
+    
+    var dataBuf: TWSABuf
+    dataBuf.buf = newString(size)
+    dataBuf.len = size
+    
+    var bytesReceived: DWord
+    var flagsio = flags.dword
+    var ol = cast[PCustomOverlapped](alloc0(sizeof(TCustomOverlapped)))
+    ol.data = TCompletionData(sock: socket, cb:
+      proc (sock: TAsyncFD, bytesCount: DWord, errcode: TOSErrorCode) =
+        if not retFuture.finished:
+          if errcode == TOSErrorCode(-1):
+            if bytesCount == 0 and dataBuf.buf[0] == '\0':
+              retFuture.complete("")
+            else:
+              var data = newString(size)
+              copyMem(addr data[0], addr dataBuf.buf[0], size)
+              retFuture.complete($data)
+          else:
+            retFuture.fail(newException(EOS, osErrorMsg(errcode)))
+    )
+
+    let ret = WSARecv(socket.TSocketHandle, addr dataBuf, 1, addr bytesReceived,
+                      addr flagsio, cast[POverlapped](ol), nil)
+    if ret == -1:
+      let err = OSLastError()
+      if err.int32 != ERROR_IO_PENDING:
+        retFuture.fail(newException(EOS, osErrorMsg(err)))
+        dealloc(ol)
+    elif ret == 0 and bytesReceived == 0 and dataBuf.buf[0] == '\0':
+      # We have to ensure that the buffer is empty because WSARecv will tell
+      # us immediatelly when it was disconnected, even when there is still
+      # data in the buffer.
+      # We want to give the user as much data as we can. So we only return
+      # the empty string (which signals a disconnection) when there is
+      # nothing left to read.
+      retFuture.complete("")
+      # TODO: "For message-oriented sockets, where a zero byte message is often 
+      # allowable, a failure with an error code of WSAEDISCON is used to 
+      # indicate graceful closure." 
+      # ~ http://msdn.microsoft.com/en-us/library/ms741688%28v=vs.85%29.aspx
+    else:
+      # Request to read completed immediately.
+      var data = newString(size)
+      copyMem(addr data[0], addr dataBuf.buf[0], size)
+      retFuture.complete($data)
+      # We don't deallocate ``ol`` here because even though this completed
+      # immediately poll will still be notified about its completion and it will
+      # free ``ol``.
+    return retFuture
+
+  proc send*(socket: TAsyncFD, data: string): PFuture[void] =
+    ## Sends ``data`` to ``socket``. The returned future will complete once all
+    ## data has been sent.
+    verifyPresence(socket)
+    var retFuture = newFuture[void]()
+
+    var dataBuf: TWSABuf
+    dataBuf.buf = data
+    dataBuf.len = data.len
+
+    var bytesReceived, flags: DWord
+    var ol = cast[PCustomOverlapped](alloc0(sizeof(TCustomOverlapped)))
+    ol.data = TCompletionData(sock: socket, cb:
+      proc (sock: TAsyncFD, bytesCount: DWord, errcode: TOSErrorCode) =
+        if not retFuture.finished:
+          if errcode == TOSErrorCode(-1):
+            retFuture.complete()
+          else:
+            retFuture.fail(newException(EOS, osErrorMsg(errcode)))
+    )
+
+    let ret = WSASend(socket.TSocketHandle, addr dataBuf, 1, addr bytesReceived,
+                      flags, cast[POverlapped](ol), nil)
+    if ret == -1:
+      let err = osLastError()
+      if err.int32 != ERROR_IO_PENDING:
+        retFuture.fail(newException(EOS, osErrorMsg(err)))
+        dealloc(ol)
+    else:
+      retFuture.complete()
+      # We don't deallocate ``ol`` here because even though this completed
+      # immediately poll will still be notified about its completion and it will
+      # free ``ol``.
+    return retFuture
+
+  proc acceptAddr*(socket: TAsyncFD): 
+      PFuture[tuple[address: string, client: TAsyncFD]] =
+    ## Accepts a new connection. Returns a future containing the client socket
+    ## corresponding to that connection and the remote address of the client.
+    ## The future will complete when the connection is successfully accepted.
+    ##
+    ## The resulting client socket is automatically registered to dispatcher.
+    verifyPresence(socket)
+    var retFuture = newFuture[tuple[address: string, client: TAsyncFD]]()
+
+    var clientSock = newRawSocket()
+    if clientSock == OSInvalidSocket: osError(osLastError())
+
+    const lpOutputLen = 1024
+    var lpOutputBuf = newString(lpOutputLen)
+    var dwBytesReceived: DWORD
+    let dwReceiveDataLength = 0.DWORD # We don't want any data to be read.
+    let dwLocalAddressLength = DWORD(sizeof (TSockaddr_in) + 16)
+    let dwRemoteAddressLength = DWORD(sizeof(TSockaddr_in) + 16)
+
+    template completeAccept(): stmt {.immediate, dirty.} =
+      var listenSock = socket
+      let setoptRet = setsockopt(clientSock, SOL_SOCKET,
+          SO_UPDATE_ACCEPT_CONTEXT, addr listenSock,
+          sizeof(listenSock).TSockLen)
+      if setoptRet != 0: osError(osLastError())
+
+      var LocalSockaddr, RemoteSockaddr: ptr TSockAddr
+      var localLen, remoteLen: int32
+      getAcceptExSockaddrs(addr lpOutputBuf[0], dwReceiveDataLength,
+                           dwLocalAddressLength, dwRemoteAddressLength,
+                           addr LocalSockaddr, addr localLen,
+                           addr RemoteSockaddr, addr remoteLen)
+      register(clientSock.TAsyncFD)
+      # TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186
+      retFuture.complete(
+        (address: $inet_ntoa(cast[ptr Tsockaddr_in](remoteSockAddr).sin_addr),
+         client: clientSock.TAsyncFD)
+      )
+
+    var ol = cast[PCustomOverlapped](alloc0(sizeof(TCustomOverlapped)))
+    ol.data = TCompletionData(sock: socket, cb:
+      proc (sock: TAsyncFD, bytesCount: DWord, errcode: TOSErrorCode) =
+        if not retFuture.finished:
+          if errcode == TOSErrorCode(-1):
+            completeAccept()
+          else:
+            retFuture.fail(newException(EOS, osErrorMsg(errcode)))
+    )
+
+    # http://msdn.microsoft.com/en-us/library/windows/desktop/ms737524%28v=vs.85%29.aspx
+    let ret = acceptEx(socket.TSocketHandle, clientSock, addr lpOutputBuf[0],
+                       dwReceiveDataLength, 
+                       dwLocalAddressLength,
+                       dwRemoteAddressLength,
+                       addr dwBytesReceived, cast[POverlapped](ol))
+
+    if not ret:
+      let err = osLastError()
+      if err.int32 != ERROR_IO_PENDING:
+        retFuture.fail(newException(EOS, osErrorMsg(err)))
+        dealloc(ol)
+    else:
+      completeAccept()
+      # We don't deallocate ``ol`` here because even though this completed
+      # immediately poll will still be notified about its completion and it will
+      # free ``ol``.
+
+    return retFuture
+
+  proc newAsyncRawSocket*(domain: TDomain = AF_INET,
+               typ: TType = SOCK_STREAM,
+               protocol: TProtocol = IPPROTO_TCP): TAsyncFD =
+    ## Creates a new socket and registers it with the dispatcher implicitly.
+    result = newRawSocket(domain, typ, protocol).TAsyncFD
+    result.TSocketHandle.setBlocking(false)
+    register(result)
+
+  proc close*(socket: TAsyncFD) =
+    ## Closes a socket and ensures that it is unregistered.
+    socket.TSocketHandle.close()
+    getGlobalDispatcher().handles.excl(socket)
+
+  initAll()
+else:
+  import selectors
+  from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK
+  type
+    TAsyncFD* = distinct cint
+    TCallback = proc (sock: TAsyncFD): bool {.closure.}
+
+    PData* = ref object of PObject
+      sock: TAsyncFD
+      readCBs: seq[TCallback]
+      writeCBs: seq[TCallback]
+
+    PDispatcher* = ref object
+      selector: PSelector
+
+  proc `==`*(x, y: TAsyncFD): bool {.borrow.}
+
+  proc newDispatcher*(): PDispatcher =
+    new result
+    result.selector = newSelector()
+
+  var gDisp{.threadvar.}: PDispatcher ## Global dispatcher
+  proc getGlobalDispatcher*(): PDispatcher =
+    if gDisp.isNil: gDisp = newDispatcher()
+    result = gDisp
+
+  proc update(sock: TAsyncFD, events: set[TEvent]) =
+    let p = getGlobalDispatcher()
+    assert sock.TSocketHandle in p.selector
+    discard p.selector.update(sock.TSocketHandle, events)
+
+  proc register(sock: TAsyncFD) =
+    let p = getGlobalDispatcher()
+    var data = PData(sock: sock, readCBs: @[], writeCBs: @[])
+    p.selector.register(sock.TSocketHandle, {}, data.PObject)
+
+  proc newAsyncRawSocket*(domain: TDomain = AF_INET,
+               typ: TType = SOCK_STREAM,
+               protocol: TProtocol = IPPROTO_TCP): TAsyncFD =
+    result = newRawSocket(domain, typ, protocol).TAsyncFD
+    result.TSocketHandle.setBlocking(false)
+    register(result)
+  
+  proc close*(sock: TAsyncFD) =
+    let disp = getGlobalDispatcher()
+    sock.TSocketHandle.close()
+    disp.selector.unregister(sock.TSocketHandle)
+
+  proc addRead(sock: TAsyncFD, cb: TCallback) =
+    let p = getGlobalDispatcher()
+    if sock.TSocketHandle notin p.selector:
+      raise newException(EInvalidValue, "File descriptor not registered.")
+    p.selector[sock.TSocketHandle].data.PData.readCBs.add(cb)
+    update(sock, p.selector[sock.TSocketHandle].events + {EvRead})
+  
+  proc addWrite(sock: TAsyncFD, cb: TCallback) =
+    let p = getGlobalDispatcher()
+    if sock.TSocketHandle notin p.selector:
+      raise newException(EInvalidValue, "File descriptor not registered.")
+    p.selector[sock.TSocketHandle].data.PData.writeCBs.add(cb)
+    update(sock, p.selector[sock.TSocketHandle].events + {EvWrite})
+  
+  proc poll*(timeout = 500) =
+    let p = getGlobalDispatcher()
+    for info in p.selector.select(timeout):
+      let data = PData(info.key.data)
+      assert data.sock == info.key.fd.TAsyncFD
+      #echo("In poll ", data.sock.cint)
+      if EvRead in info.events:
+        # Callback may add items to ``data.readCBs`` which causes issues if
+        # we are iterating over ``data.readCBs`` at the same time. We therefore
+        # make a copy to iterate over.
+        let currentCBs = data.readCBs
+        data.readCBs = @[]
+        for cb in currentCBs:
+          if not cb(data.sock):
+            # Callback wants to be called again.
+            data.readCBs.add(cb)
+      
+      if EvWrite in info.events:
+        let currentCBs = data.writeCBs
+        data.writeCBs = @[]
+        for cb in currentCBs:
+          if not cb(data.sock):
+            # Callback wants to be called again.
+            data.writeCBs.add(cb)
+      
+      if info.key in p.selector:
+        var newEvents: set[TEvent]
+        if data.readCBs.len != 0: newEvents = {EvRead}
+        if data.writeCBs.len != 0: newEvents = newEvents + {EvWrite}
+        if newEvents != info.key.events:
+          update(data.sock, newEvents)
+      else:
+        # FD no longer a part of the selector. Likely been closed
+        # (e.g. socket disconnected).
+  
+  proc connect*(socket: TAsyncFD, address: string, port: TPort,
+    af = AF_INET): PFuture[void] =
+    var retFuture = newFuture[void]()
+    
+    proc cb(sock: TAsyncFD): bool =
+      # We have connected.
+      retFuture.complete()
+      return true
+    
+    var aiList = getAddrInfo(address, port, af)
+    var success = false
+    var lastError: TOSErrorCode
+    var it = aiList
+    while it != nil:
+      var ret = connect(socket.TSocketHandle, it.ai_addr, it.ai_addrlen.TSocklen)
+      if ret == 0:
+        # Request to connect completed immediately.
+        success = true
+        retFuture.complete()
+        break
+      else:
+        lastError = osLastError()
+        if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
+          success = true
+          addWrite(socket, cb)
+          break
+        else:
+          success = false
+      it = it.ai_next
+
+    dealloc(aiList)
+    if not success:
+      retFuture.fail(newException(EOS, osErrorMsg(lastError)))
+    return retFuture
+
+  proc recv*(socket: TAsyncFD, size: int,
+             flags: int = 0): PFuture[string] =
+    var retFuture = newFuture[string]()
+    
+    var readBuffer = newString(size)
+    var sizeRead = 0
+    
+    proc cb(sock: TAsyncFD): bool =
+      result = true
+      let netSize = size - sizeRead
+      let res = recv(sock.TSocketHandle, addr readBuffer[sizeRead], netSize,
+                     flags.cint)
+      #echo("recv cb res: ", res)
+      if res < 0:
+        let lastError = osLastError()
+        if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}: 
+          retFuture.fail(newException(EOS, osErrorMsg(lastError)))
+        else:
+          result = false # We still want this callback to be called.
+      elif res == 0:
+        #echo("Disconnected recv: ", sizeRead)
+        # Disconnected
+        if sizeRead == 0:
+          retFuture.complete("")
+        else:
+          readBuffer.setLen(sizeRead)
+          retFuture.complete(readBuffer)
+      else:
+        sizeRead.inc(res)
+        if res != netSize:
+          result = false # We want to read all the data requested.
+        else:
+          retFuture.complete(readBuffer)
+      #echo("Recv cb result: ", result)
+  
+    addRead(socket, cb)
+    return retFuture
+
+  proc send*(socket: TAsyncFD, data: string): PFuture[void] =
+    var retFuture = newFuture[void]()
+    
+    var written = 0
+    
+    proc cb(sock: TAsyncFD): bool =
+      result = true
+      let netSize = data.len-written
+      var d = data.cstring
+      let res = send(sock.TSocketHandle, addr d[written], netSize, 0.cint)
+      if res < 0:
+        let lastError = osLastError()
+        if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}:
+          retFuture.fail(newException(EOS, osErrorMsg(lastError)))
+        else:
+          result = false # We still want this callback to be called.
+      else:
+        written.inc(res)
+        if res != netSize:
+          result = false # We still have data to send.
+        else:
+          retFuture.complete()
+    addWrite(socket, cb)
+    return retFuture
+
+  proc acceptAddr*(socket: TAsyncFD): 
+      PFuture[tuple[address: string, client: TAsyncFD]] =
+    var retFuture = newFuture[tuple[address: string, client: TAsyncFD]]()
+    proc cb(sock: TAsyncFD): bool =
+      result = true
+      var sockAddress: Tsockaddr_in
+      var addrLen = sizeof(sockAddress).TSocklen
+      var client = accept(sock.TSocketHandle,
+                          cast[ptr TSockAddr](addr(sockAddress)), addr(addrLen))
+      if client == osInvalidSocket:
+        let lastError = osLastError()
+        assert lastError.int32 notin {EWOULDBLOCK, EAGAIN}
+        if lastError.int32 == EINTR:
+          return false
+        else:
+          retFuture.fail(newException(EOS, osErrorMsg(lastError)))
+      else:
+        register(client.TAsyncFD)
+        retFuture.complete(($inet_ntoa(sockAddress.sin_addr), client.TAsyncFD))
+    addRead(socket, cb)
+    return retFuture
+
+proc accept*(socket: TAsyncFD): PFuture[TAsyncFD] =
+  ## Accepts a new connection. Returns a future containing the client socket
+  ## corresponding to that connection.
+  ## The future will complete when the connection is successfully accepted.
+  var retFut = newFuture[TAsyncFD]()
+  var fut = acceptAddr(socket)
+  fut.callback =
+    proc (future: PFuture[tuple[address: string, client: TAsyncFD]]) =
+      assert future.finished
+      if future.failed:
+        retFut.fail(future.error)
+      else:
+        retFut.complete(future.read.client)
+  return retFut
+
+# -- Await Macro
+
+template createCb*(cbName, varNameIterSym, retFutureSym: expr): stmt {.immediate, dirty.} =
+  proc cbName {.closure.} =
+    if not varNameIterSym.finished:
+      var next = varNameIterSym()
+      if next == nil:
+        assert retFutureSym.finished, "Async procedure's return Future was not finished."
+      else:
+        next.callback = cbName
+
+template createVar(futSymName: string, asyncProc: PNimrodNode,
+                   valueReceiver: expr) {.immediate, dirty.} =
+  # TODO: Used template here due to bug #926
+  result = newNimNode(nnkStmtList)
+  var futSym = genSym(nskVar, "future")
+  result.add newVarStmt(futSym, asyncProc) # -> var future<x> = y
+  result.add newNimNode(nnkYieldStmt).add(futSym) # -> yield future<x>
+  valueReceiver = newDotExpr(futSym, newIdentNode("read")) # -> future<x>.read
+
+proc processBody(node, retFutureSym: PNimrodNode): PNimrodNode {.compileTime.} =
+  result = node
+  case node.kind
+  of nnkReturnStmt:
+    result = newNimNode(nnkStmtList)
+    result.add newCall(newIdentNode("complete"), retFutureSym,
+      if node[0].kind == nnkEmpty: newIdentNode("result") else: node[0])
+    result.add newNimNode(nnkYieldStmt).add(newNilLit())
+  of nnkCommand:
+    if node[0].kind == nnkIdent and node[0].ident == !"await":
+      case node[1].kind
+      of nnkIdent:
+        # await x
+        result = newNimNode(nnkYieldStmt).add(node[1]) # -> yield x
+      of nnkCall:
+        # await foo(p, x)
+        var futureValue: PNimrodNode
+        createVar("future" & $node[1][0].toStrLit, node[1], futureValue)
+        result.add futureValue
+      else:
+        error("Invalid node kind in 'await', got: " & $node[1].kind)
+    elif node[1].kind == nnkCommand and node[1][0].kind == nnkIdent and
+         node[1][0].ident == !"await":
+      # foo await x
+      var newCommand = node
+      createVar("future" & $node[0].toStrLit, node[1][1], newCommand[1])
+      result.add newCommand
+
+  of nnkVarSection, nnkLetSection:
+    case node[0][2].kind
+    of nnkCommand:
+      if node[0][2][0].ident == !"await":
+        # var x = await y
+        var newVarSection = node # TODO: Should this use copyNimNode?
+        createVar("future" & $node[0][0].ident, node[0][2][1],
+          newVarSection[0][2])
+        result.add newVarSection
+    else: discard
+  of nnkAsgn:
+    case node[1].kind
+    of nnkCommand:
+      if node[1][0].ident == !"await":
+        # x = await y
+        var newAsgn = node
+        createVar("future" & $node[0].toStrLit, node[1][1], newAsgn[1])
+        result.add newAsgn
+    else: discard
+  of nnkDiscardStmt:
+    # discard await x
+    if node[0][0].kind == nnkIdent and node[0][0].ident == !"await":
+      var dummy = newNimNode(nnkStmtList)
+      createVar("futureDiscard_" & $toStrLit(node[0][1]), node[0][1], dummy)
+  else: discard
+  
+  for i in 0 .. <result.len:
+    result[i] = processBody(result[i], retFutureSym)
+  #echo(treeRepr(result))
+
+proc getName(node: PNimrodNode): string {.compileTime.} =
+  case node.kind
+  of nnkPostfix:
+    return $node[1].ident
+  of nnkIdent:
+    return $node.ident
+  else:
+    assert false
+
+macro async*(prc: stmt): stmt {.immediate.} =
+  ## Macro which processes async procedures into the appropriate
+  ## iterators and yield statements.
+
+  expectKind(prc, nnkProcDef)
+
+  hint("Processing " & prc[0].getName & " as an async proc.")
+
+  let returnType = prc[3][0]
+  var subtypeName = ""
+  # Verify that the return type is a PFuture[T]
+  if returnType.kind == nnkIdent:
+    error("Expected return type of 'PFuture' got '" & $returnType & "'")
+  elif returnType.kind == nnkBracketExpr:
+    if $returnType[0] != "PFuture":
+      error("Expected return type of 'PFuture' got '" & $returnType[0] & "'")
+    subtypeName = $returnType[1].ident
+  elif returnType.kind == nnkEmpty:
+    subtypeName = "void"
+
+  var outerProcBody = newNimNode(nnkStmtList)
+
+  # -> var retFuture = newFuture[T]()
+  var retFutureSym = genSym(nskVar, "retFuture")
+  outerProcBody.add(
+    newVarStmt(retFutureSym, 
+      newCall(
+        newNimNode(nnkBracketExpr).add(
+          newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`.
+          newIdentNode(subtypeName))))) # Get type from return type of this proc
+  
+  # -> iterator nameIter(): PFutureBase {.closure.} = 
+  # ->   var result: T
+  # ->   <proc_body>
+  # ->   complete(retFuture, result)
+  var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter")
+  var procBody = prc[6].processBody(retFutureSym)
+  if subtypeName != "void":
+    procBody.insert(0, newNimNode(nnkVarSection).add(
+      newIdentDefs(newIdentNode("result"), returnType[1]))) # -> var result: T
+    procBody.add(
+      newCall(newIdentNode("complete"),
+        retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result)
+  else:
+    # -> complete(retFuture)
+    procBody.add(newCall(newIdentNode("complete"), retFutureSym))
+  
+  var closureIterator = newProc(iteratorNameSym, [newIdentNode("PFutureBase")],
+                                procBody, nnkIteratorDef)
+  closureIterator[4] = newNimNode(nnkPragma).add(newIdentNode("closure"))
+  outerProcBody.add(closureIterator)
+
+  # -> var nameIterVar = nameIter
+  # -> var first = nameIterVar()
+  var varNameIterSym = genSym(nskVar, $prc[0].getName & "IterVar")
+  var varNameIter = newVarStmt(varNameIterSym, iteratorNameSym)
+  outerProcBody.add varNameIter
+  var varFirstSym = genSym(nskVar, "first")
+  var varFirst = newVarStmt(varFirstSym, newCall(varNameIterSym))
+  outerProcBody.add varFirst
+
+  # -> createCb(cb, nameIter, retFuture)
+  var cbName = newIdentNode("cb")
+  var procCb = newCall("createCb", cbName, varNameIterSym, retFutureSym)
+  outerProcBody.add procCb
+
+  # -> first.callback = cb
+  outerProcBody.add newAssignment(
+    newDotExpr(varFirstSym, newIdentNode("callback")),
+    cbName)
+
+  # -> return retFuture
+  outerProcBody.add newNimNode(nnkReturnStmt).add(retFutureSym)
+  
+  result = prc
+
+  # Remove the 'async' pragma.
+  for i in 0 .. <result[4].len:
+    if result[4][i].ident == !"async":
+      result[4].del(i)
+  if subtypeName == "void":
+    # Add discardable pragma.
+    result[4].add(newIdentNode("discardable"))
+    if returnType.kind == nnkEmpty:
+      # Add PFuture[void]
+      result[3][0] = parseExpr("PFuture[void]")
+
+  result[6] = outerProcBody
+
+  echo(toStrLit(result))
+
+proc recvLine*(socket: TAsyncFD): PFuture[string] {.async.} =
+  ## Reads a line of data from ``socket``. Returned future will complete once
+  ## a full line is read or an error occurs.
+  ##
+  ## If a full line is read ``\r\L`` is not
+  ## added to ``line``, however if solely ``\r\L`` is read then ``line``
+  ## will be set to it.
+  ## 
+  ## If the socket is disconnected, ``line`` will be set to ``""``.
+  ##
+  ## If the socket is disconnected in the middle of a line (before ``\r\L``
+  ## is read) then line will be set to ``""``.
+  ## The partial line **will be lost**.
+  
+  template addNLIfEmpty(): stmt =
+    if result.len == 0:
+      result.add("\c\L")
+
+  result = ""
+  var c = ""
+  while true:
+    c = await recv(socket, 1)
+    if c.len == 0:
+      return ""
+    if c == "\r":
+      c = await recv(socket, 1, MSG_PEEK)
+      if c.len > 0 and c == "\L":
+        discard await recv(socket, 1)
+      addNLIfEmpty()
+      return
+    elif c == "\L":
+      addNLIfEmpty()
+      return
+    add(result, c)
+
+proc runForever*() =
+  ## Begins a never ending global dispatcher poll loop.
+  while true:
+    poll()
diff --git a/lib/pure/asyncdispatch.nimrod.cfg b/lib/pure/asyncdispatch.nimrod.cfg
new file mode 100644
index 000000000..e88f8eec3
--- /dev/null
+++ b/lib/pure/asyncdispatch.nimrod.cfg
@@ -0,0 +1,3 @@
+@if nimdoc:
+  --os:linux
+@end
diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim
index 96afc6f4f..ab09dc860 100644
--- a/lib/pure/asyncio.nim
+++ b/lib/pure/asyncio.nim
@@ -167,7 +167,7 @@ proc asyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
   result = newAsyncSocket()
   result.socket = socket(domain, typ, protocol, buffered)
   result.proto = protocol
-  if result.socket == InvalidSocket: OSError(OSLastError())
+  if result.socket == invalidSocket: osError(osLastError())
   result.socket.setBlocking(false)
 
 proc toAsyncSocket*(sock: TSocket, state: TInfo = SockConnected): PAsyncSocket =
@@ -357,7 +357,7 @@ proc acceptAddr*(server: PAsyncSocket, client: var PAsyncSocket,
     client.sslNeedAccept = false
     client.info = SockConnected
 
-  if c == InvalidSocket: SocketError(server.socket)
+  if c == invalidSocket: socketError(server.socket)
   c.setBlocking(false) # TODO: Needs to be tested.
   
   # deleg.open is set in ``toDelegate``.
@@ -481,7 +481,7 @@ proc recvLine*(s: PAsyncSocket, line: var TaintedString): bool {.deprecated.} =
   of RecvDisconnected:
     result = true
   of RecvFail:
-    s.SocketError(async = true)
+    s.socketError(async = true)
     result = false
 {.pop.}
 
@@ -615,11 +615,11 @@ proc poll*(d: PDispatcher, timeout: int = 500): bool =
     if d.hasDataBuffered(d.deleVal):
       hasDataBufferedCount.inc()
       d.handleRead(d.deleVal)
-  if hasDataBufferedCount > 0: return True
+  if hasDataBufferedCount > 0: return true
   
   if readDg.len() == 0 and writeDg.len() == 0:
     ## TODO: Perhaps this shouldn't return if errorDg has something?
-    return False
+    return false
   
   if select(readDg, writeDg, errorDg, timeout) != 0:
     for i in 0..len(d.delegates)-1:
diff --git a/lib/pure/asyncio2.nim b/lib/pure/asyncio2.nim
deleted file mode 100644
index cdb4a6f49..000000000
--- a/lib/pure/asyncio2.nim
+++ /dev/null
@@ -1,485 +0,0 @@
-#
-#
-#            Nimrod's Runtime Library
-#        (c) Copyright 2014 Dominik Picheta
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-import os, oids, tables, strutils
-
-import winlean
-
-import sockets2, net
-
-## Asyncio2 
-## --------
-##
-## This module implements a brand new asyncio module based on Futures.
-## IOCP is used under the hood on Windows and the selectors module is used for
-## other operating systems.
-
-# -- Futures
-
-type
-  PFutureVoid* = ref object of PObject
-    cbVoid: proc () {.closure.}
-    finished: bool
-
-  PFuture*[T] = ref object of PFutureVoid
-    value: T
-    error: ref EBase
-    cb: proc (future: PFuture[T]) {.closure.}
-
-proc newFuture*[T](): PFuture[T] =
-  ## Creates a new future.
-  new(result)
-  result.finished = false
-
-proc complete*[T](future: PFuture[T], val: T) =
-  ## Completes ``future`` with value ``val``.
-  assert(not future.finished)
-  assert(future.error == nil)
-  future.value = val
-  future.finished = true
-  if future.cb != nil:
-    future.cb(future)
-  if future.cbVoid != nil:
-    future.cbVoid()
-
-proc fail*[T](future: PFuture[T], error: ref EBase) =
-  ## Completes ``future`` with ``error``.
-  assert(not future.finished)
-  future.finished = true
-  future.error = error
-  if future.cb != nil:
-    future.cb(future)
-
-proc `callback=`*[T](future: PFuture[T],
-    cb: proc (future: PFuture[T]) {.closure.}) =
-  ## Sets the callback proc to be called when the future completes.
-  ##
-  ## If future has already completed then ``cb`` will be called immediately.
-  future.cb = cb
-  if future.finished:
-    future.cb(future)
-
-proc `callbackVoid=`*(future: PFutureVoid, cb: proc () {.closure.}) =
-  ## Sets the **void** callback proc to be called when the future completes.
-  ##
-  ## If future has already completed then ``cb`` will be called immediately.
-  ##
-  ## **Note**: This is used for the ``await`` functionality, you most likely
-  ## want to use ``callback``.
-  future.cbVoid = cb
-  if future.finished:
-    future.cbVoid()
-
-proc read*[T](future: PFuture[T]): T =
-  ## Retrieves the value of ``future``. Future must be finished otherwise
-  ## this function will fail with a ``EInvalidValue`` exception.
-  ##
-  ## If the result of the future is an error then that error will be raised.
-  if future.finished:
-    if future.error != nil: raise future.error
-    return future.value
-  else:
-    # TODO: Make a custom exception type for this?
-    raise newException(EInvalidValue, "Future still in progress.")
-
-proc finished*[T](future: PFuture[T]): bool =
-  ## Determines whether ``future`` has completed.
-  ##
-  ## ``True`` may indicate an error or a value. Use ``hasError`` to distinguish.
-  future.finished
-
-proc failed*[T](future: PFuture[T]): bool =
-  ## Determines whether ``future`` completed with an error.
-  future.error != nil
-
-when defined(windows):
-  type
-    TCompletionKey = dword
-
-    TCompletionData* = object
-      sock: TSocketHandle
-      cb: proc (sock: TSocketHandle, errcode: TOSErrorCode) {.closure.}
-
-    PDispatcher* = ref object
-      ioPort: THandle
-
-    TCustomOverlapped = object
-      Internal*: DWORD
-      InternalHigh*: DWORD
-      Offset*: DWORD
-      OffsetHigh*: DWORD
-      hEvent*: THANDLE
-      data*: TCompletionData
-
-    PCustomOverlapped = ptr TCustomOverlapped
-
-  proc newDispatcher*(): PDispatcher =
-    ## Creates a new Dispatcher instance.
-    new result
-    result.ioPort = CreateIOCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1)
-
-  proc register*(p: PDispatcher, sock: TSocketHandle) =
-    ## Registers ``sock`` with the dispatcher ``p``.
-    if CreateIOCompletionPort(sock.THandle, p.ioPort,
-                              cast[TCompletionKey](sock), 1) == 0:
-      OSError(OSLastError())
-
-  proc poll*(p: PDispatcher, timeout = 500) =
-    ## Waits for completion events and processes them.
-    let llTimeout =
-      if timeout ==  -1: winlean.INFINITE
-      else: timeout.int32
-    var lpNumberOfBytesTransferred: DWORD
-    var lpCompletionKey: ULONG
-    var lpOverlapped: POverlapped
-    let res = GetQueuedCompletionStatus(p.ioPort, addr lpNumberOfBytesTransferred,
-        addr lpCompletionKey, addr lpOverlapped, llTimeout).bool
-
-    # http://stackoverflow.com/a/12277264/492186
-    # TODO: http://www.serverframework.com/handling-multiple-pending-socket-read-and-write-operations.html
-    var customOverlapped = cast[PCustomOverlapped](lpOverlapped)
-    if res:
-      assert customOverlapped.data.sock == lpCompletionKey.TSocketHandle
-
-      customOverlapped.data.cb(customOverlapped.data.sock, TOSErrorCode(-1))
-      dealloc(customOverlapped)
-    else:
-      let errCode = OSLastError()
-      if lpOverlapped != nil:
-        assert customOverlapped.data.sock == lpCompletionKey.TSocketHandle
-        dealloc(customOverlapped)
-        customOverlapped.data.cb(customOverlapped.data.sock, errCode)
-      else:
-        if errCode.int32 == WAIT_TIMEOUT:
-          # Timed out
-          discard
-        else: OSError(errCode)
-
-  var connectExPtr: pointer = nil
-  var acceptExPtr: pointer = nil
-  var getAcceptExSockAddrsPtr: pointer = nil
-
-  proc initPointer(s: TSocketHandle, func: var pointer, guid: var TGUID): bool =
-    # Ref: https://github.com/powdahound/twisted/blob/master/twisted/internet/iocpreactor/iocpsupport/winsock_pointers.c
-    var bytesRet: DWord
-    func = nil
-    result = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, addr guid,
-                      sizeof(TGUID).dword, addr func, sizeof(pointer).DWORD,
-                      addr bytesRet, nil, nil) == 0
-
-  proc initAll() =
-    let dummySock = socket()
-    if not initPointer(dummySock, connectExPtr, WSAID_CONNECTEX):
-      OSError(OSLastError())
-    if not initPointer(dummySock, acceptExPtr, WSAID_ACCEPTEX):
-      OSError(OSLastError())
-    if not initPointer(dummySock, getAcceptExSockAddrsPtr, WSAID_GETACCEPTEXSOCKADDRS):
-      OSError(OSLastError())
-
-  proc connectEx(s: TSocketHandle, name: ptr TSockAddr, namelen: cint, 
-                  lpSendBuffer: pointer, dwSendDataLength: dword,
-                  lpdwBytesSent: PDWORD, lpOverlapped: POverlapped): bool =
-    if connectExPtr.isNil: raise newException(EInvalidValue, "Need to initialise ConnectEx().")
-    let func =
-      cast[proc (s: TSocketHandle, name: ptr TSockAddr, namelen: cint, 
-         lpSendBuffer: pointer, dwSendDataLength: dword,
-         lpdwBytesSent: PDWORD, lpOverlapped: POverlapped): bool {.stdcall.}](connectExPtr)
-
-    result = func(s, name, namelen, lpSendBuffer, dwSendDataLength, lpdwBytesSent,
-         lpOverlapped)
-
-  proc acceptEx(listenSock, acceptSock: TSocketHandle, lpOutputBuffer: pointer,
-                 dwReceiveDataLength, dwLocalAddressLength,
-                 dwRemoteAddressLength: DWORD, lpdwBytesReceived: PDWORD,
-                 lpOverlapped: POverlapped): bool =
-    if acceptExPtr.isNil: raise newException(EInvalidValue, "Need to initialise AcceptEx().")
-    let func =
-      cast[proc (listenSock, acceptSock: TSocketHandle, lpOutputBuffer: pointer,
-                 dwReceiveDataLength, dwLocalAddressLength,
-                 dwRemoteAddressLength: DWORD, lpdwBytesReceived: PDWORD,
-                 lpOverlapped: POverlapped): bool {.stdcall.}](acceptExPtr)
-    result = func(listenSock, acceptSock, lpOutputBuffer, dwReceiveDataLength,
-        dwLocalAddressLength, dwRemoteAddressLength, lpdwBytesReceived,
-        lpOverlapped)
-
-  proc getAcceptExSockaddrs(lpOutputBuffer: pointer,
-      dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength: DWORD,
-      LocalSockaddr: ptr ptr TSockAddr, LocalSockaddrLength: lpint,
-      RemoteSockaddr: ptr ptr TSockAddr, RemoteSockaddrLength: lpint) =
-    if getAcceptExSockAddrsPtr.isNil:
-      raise newException(EInvalidValue, "Need to initialise getAcceptExSockAddrs().")
-
-    let func =
-      cast[proc (lpOutputBuffer: pointer,
-                 dwReceiveDataLength, dwLocalAddressLength,
-                 dwRemoteAddressLength: DWORD, LocalSockaddr: ptr ptr TSockAddr,
-                 LocalSockaddrLength: lpint, RemoteSockaddr: ptr ptr TSockAddr,
-                RemoteSockaddrLength: lpint) {.stdcall.}](getAcceptExSockAddrsPtr)
-    
-    func(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength,
-                  dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength,
-                  RemoteSockaddr, RemoteSockaddrLength)
-
-  proc connect*(p: PDispatcher, socket: TSocketHandle, address: string, port: TPort,
-    af = AF_INET): PFuture[int] =
-    ## Connects ``socket`` to server at ``address:port``.
-    ##
-    ## Returns a ``PFuture`` which will complete when the connection succeeds
-    ## or an error occurs.
-
-    var retFuture = newFuture[int]()# TODO: Change to void when that regression is fixed.
-    # Apparently ``ConnectEx`` expects the socket to be initially bound:
-    var saddr: Tsockaddr_in
-    saddr.sin_family = int16(toInt(af))
-    saddr.sin_port = 0
-    saddr.sin_addr.s_addr = INADDR_ANY
-    if bindAddr(socket, cast[ptr TSockAddr](addr(saddr)),
-                  sizeof(saddr).TSockLen) < 0'i32:
-      OSError(OSLastError())
-
-    var aiList = getAddrInfo(address, port, af)
-    var success = false
-    var lastError: TOSErrorCode
-    var it = aiList
-    while it != nil:
-      # "the OVERLAPPED structure must remain valid until the I/O completes"
-      # http://blogs.msdn.com/b/oldnewthing/archive/2011/02/02/10123392.aspx
-      var ol = cast[PCustomOverlapped](alloc0(sizeof(TCustomOverlapped)))
-      ol.data = TCompletionData(sock: socket, cb:
-        proc (sock: TSocketHandle, errcode: TOSErrorCode) =
-          if errcode == TOSErrorCode(-1):
-            retFuture.complete(0)
-          else:
-            retFuture.fail(newException(EOS, osErrorMsg(errcode)))
-      )
-      
-      var ret = connectEx(socket, it.ai_addr, sizeof(TSockAddrIn).cint,
-                          nil, 0, nil, cast[POverlapped](ol))
-      if ret:
-        # Request to connect completed immediately.
-        success = true
-        retFuture.complete(0)
-        dealloc(ol)
-        break
-      else:
-        lastError = OSLastError()
-        if lastError.int32 == ERROR_IO_PENDING:
-          # In this case ``ol`` will be deallocated in ``poll``.
-          success = true
-          break
-        else:
-          dealloc(ol)
-          success = false
-      it = it.ai_next
-
-    dealloc(aiList)
-    if not success:
-      retFuture.fail(newException(EOS, osErrorMsg(lastError)))
-    return retFuture
-
-  proc recv*(p: PDispatcher, socket: TSocketHandle, size: int): PFuture[string] =
-    ## Reads ``size`` bytes from ``socket``. Returned future will complete once
-    ## all of the requested data is read.
-
-    var retFuture = newFuture[string]()
-    
-    var dataBuf: TWSABuf
-    dataBuf.buf = newString(size)
-    dataBuf.len = size
-    
-    var bytesReceived, flags: DWord
-    var ol = cast[PCustomOverlapped](alloc0(sizeof(TCustomOverlapped)))
-    ol.data = TCompletionData(sock: socket, cb:
-      proc (sock: TSocketHandle, errcode: TOSErrorCode) =
-        if errcode == TOSErrorCode(-1):
-          var data = newString(size)
-          copyMem(addr data[0], addr dataBuf.buf[0], size)
-          retFuture.complete($data)
-        else:
-          retFuture.fail(newException(EOS, osErrorMsg(errcode)))
-    )
-    
-    let ret = WSARecv(socket, addr dataBuf, 1, addr bytesReceived,
-                      addr flags, cast[POverlapped](ol), nil)
-    if ret == -1:
-      let err = OSLastError()
-      if err.int32 != ERROR_IO_PENDING:
-        retFuture.fail(newException(EOS, osErrorMsg(err)))
-        dealloc(ol)
-    else:
-      # Request to read completed immediately.
-      var data = newString(size)
-      copyMem(addr data[0], addr dataBuf.buf[0], size)
-      retFuture.complete($data)
-      dealloc(ol)
-    return retFuture
-
-  proc send*(p: PDispatcher, socket: TSocketHandle, data: string): PFuture[int] =
-    ## Sends ``data`` to ``socket``. The returned future will complete once all
-    ## data has been sent.
-    var retFuture = newFuture[int]()
-
-    var dataBuf: TWSABuf
-    dataBuf.buf = data
-    dataBuf.len = data.len
-
-    var bytesReceived, flags: DWord
-    var ol = cast[PCustomOverlapped](alloc0(sizeof(TCustomOverlapped)))
-    ol.data = TCompletionData(sock: socket, cb:
-      proc (sock: TSocketHandle, errcode: TOSErrorCode) =
-        if errcode == TOSErrorCode(-1):
-          retFuture.complete(0)
-        else:
-          retFuture.fail(newException(EOS, osErrorMsg(errcode)))
-    )
-
-    let ret = WSASend(socket, addr dataBuf, 1, addr bytesReceived,
-                      flags, cast[POverlapped](ol), nil)
-    if ret == -1:
-      let err = osLastError()
-      if err.int32 != ERROR_IO_PENDING:
-        retFuture.fail(newException(EOS, osErrorMsg(err)))
-        dealloc(ol)
-    else:
-      retFuture.complete(0)
-      dealloc(ol)
-    return retFuture
-
-  proc acceptAddr*(p: PDispatcher, socket: TSocketHandle): 
-      PFuture[tuple[address: string, client: TSocketHandle]] =
-    ## Accepts a new connection. Returns a future containing the client socket
-    ## corresponding to that connection and the remote address of the client.
-    ## The future will complete when the connection is successfully accepted.
-    
-    var retFuture = newFuture[tuple[address: string, client: TSocketHandle]]()
-
-    var clientSock = socket()
-    if clientSock == OSInvalidSocket: osError(osLastError())
-
-    const lpOutputLen = 1024
-    var lpOutputBuf = newString(lpOutputLen)
-    var dwBytesReceived: DWORD
-    let dwReceiveDataLength = 0.DWORD # We don't want any data to be read.
-    let dwLocalAddressLength = DWORD(sizeof (TSockaddr_in) + 16)
-    let dwRemoteAddressLength = DWORD(sizeof(TSockaddr_in) + 16)
-
-    template completeAccept(): stmt {.immediate, dirty.} =
-      var listenSock = socket
-      let setoptRet = setsockopt(clientSock, SOL_SOCKET,
-          SO_UPDATE_ACCEPT_CONTEXT, addr listenSock,
-          sizeof(listenSock).TSockLen)
-      if setoptRet != 0: osError(osLastError())
-
-      var LocalSockaddr, RemoteSockaddr: ptr TSockAddr
-      var localLen, remoteLen: int32
-      getAcceptExSockaddrs(addr lpOutputBuf[0], dwReceiveDataLength,
-                           dwLocalAddressLength, dwRemoteAddressLength,
-                           addr LocalSockaddr, addr localLen,
-                           addr RemoteSockaddr, addr remoteLen)
-      # TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186
-      retFuture.complete(
-        (address: $inet_ntoa(cast[ptr Tsockaddr_in](remoteSockAddr).sin_addr),
-         client: clientSock)
-      )
-
-    var ol = cast[PCustomOverlapped](alloc0(sizeof(TCustomOverlapped)))
-    ol.data = TCompletionData(sock: socket, cb:
-      proc (sock: TSocketHandle, errcode: TOSErrorCode) =
-        if errcode == TOSErrorCode(-1):
-          completeAccept()
-        else:
-          retFuture.fail(newException(EOS, osErrorMsg(errcode)))
-    )
-
-    # http://msdn.microsoft.com/en-us/library/windows/desktop/ms737524%28v=vs.85%29.aspx
-    let ret = acceptEx(socket, clientSock, addr lpOutputBuf[0],
-                       dwReceiveDataLength, 
-                       dwLocalAddressLength,
-                       dwRemoteAddressLength,
-                       addr dwBytesReceived, cast[POverlapped](ol))
-
-    if not ret:
-      let err = osLastError()
-      if err.int32 != ERROR_IO_PENDING:
-        retFuture.fail(newException(EOS, osErrorMsg(err)))
-        dealloc(ol)
-    else:
-      completeAccept()
-      dealloc(ol)
-
-    return retFuture
-
-  proc accept*(p: PDispatcher, socket: TSocketHandle): PFuture[TSocketHandle] =
-    ## Accepts a new connection. Returns a future containing the client socket
-    ## corresponding to that connection.
-    ## The future will complete when the connection is successfully accepted.
-    var retFut = newFuture[TSocketHandle]()
-    var fut = p.acceptAddr(socket)
-    fut.callback =
-      proc (future: PFuture[tuple[address: string, client: TSocketHandle]]) =
-        assert future.finished
-        if future.failed:
-          retFut.fail(future.error)
-        else:
-          retFut.complete(future.read.client)
-    return retFut
-
-  initAll()
-else:
-  # TODO: Selectors.
-
-
-when isMainModule:
-  
-  var p = newDispatcher()
-  var sock = socket()
-  #sock.setBlocking false
-  p.register(sock)
-
-  when true:
-
-    var f = p.connect(sock, "irc.freenode.org", TPort(6667))
-    f.callback =
-      proc (future: PFuture[int]) =
-        echo("Connected in future!")
-        echo(future.read)
-        for i in 0 .. 50:
-          var recvF = p.recv(sock, 10)
-          recvF.callback =
-            proc (future: PFuture[string]) =
-              echo("Read: ", future.read)
-
-  else:
-
-    sock.bindAddr(TPort(6667))
-    sock.listen()
-    proc onAccept(future: PFuture[TSocketHandle]) =
-      echo "Accepted"
-      var t = p.send(future.read, "test\c\L")
-      t.callback =
-        proc (future: PFuture[int]) =
-          echo(future.read)
-      
-      var f = p.accept(sock)
-      f.callback = onAccept
-      
-    var f = p.accept(sock)
-    f.callback = onAccept
-  
-  while true:
-    p.poll()
-    echo "polled"
-
-
-
-
-
-  
-
-  
\ No newline at end of file
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
new file mode 100644
index 000000000..24651b08c
--- /dev/null
+++ b/lib/pure/asyncnet.nim
@@ -0,0 +1,195 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2014 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+import asyncdispatch
+import rawsockets
+import net
+
+when defined(ssl):
+  import openssl
+
+type
+  # TODO: I would prefer to just do:
+  # PAsyncSocket* {.borrow: `.`.} = distinct PSocket. But that doesn't work.
+  TAsyncSocket {.borrow: `.`.} = distinct TSocketImpl
+  PAsyncSocket* = ref TAsyncSocket
+
+# TODO: Save AF, domain etc info and reuse it in procs which need it like connect.
+
+proc newSocket(fd: TAsyncFD, isBuff: bool): PAsyncSocket =
+  assert fd != osInvalidSocket.TAsyncFD
+  new(result.PSocket)
+  result.fd = fd.TSocketHandle
+  result.isBuffered = isBuff
+  if isBuff:
+    result.currPos = 0
+
+proc newAsyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
+    protocol: TProtocol = IPPROTO_TCP, buffered = true): PAsyncSocket =
+  ## Creates a new asynchronous socket.
+  result = newSocket(newAsyncRawSocket(domain, typ, protocol), buffered)
+
+proc connect*(socket: PAsyncSocket, address: string, port: TPort,
+    af = AF_INET): PFuture[void] =
+  ## Connects ``socket`` to server at ``address:port``.
+  ##
+  ## Returns a ``PFuture`` which will complete when the connection succeeds
+  ## or an error occurs.
+  result = connect(socket.fd.TAsyncFD, address, port, af)
+
+proc recv*(socket: PAsyncSocket, size: int,
+           flags: int = 0): PFuture[string] =
+  ## Reads ``size`` bytes from ``socket``. Returned future will complete once
+  ## all of the requested data is read. If socket is disconnected during the
+  ## recv operation then the future may complete with only a part of the
+  ## requested data read. If socket is disconnected and no data is available
+  ## to be read then the future will complete with a value of ``""``.
+  result = recv(socket.fd.TAsyncFD, size, flags)
+
+proc send*(socket: PAsyncSocket, data: string): PFuture[void] =
+  ## Sends ``data`` to ``socket``. The returned future will complete once all
+  ## data has been sent.
+  result = send(socket.fd.TAsyncFD, data)
+
+proc acceptAddr*(socket: PAsyncSocket): 
+      PFuture[tuple[address: string, client: PAsyncSocket]] =
+  ## Accepts a new connection. Returns a future containing the client socket
+  ## corresponding to that connection and the remote address of the client.
+  ## The future will complete when the connection is successfully accepted.
+  var retFuture = newFuture[tuple[address: string, client: PAsyncSocket]]()
+  var fut = acceptAddr(socket.fd.TAsyncFD)
+  fut.callback =
+    proc (future: PFuture[tuple[address: string, client: TAsyncFD]]) =
+      assert future.finished
+      if future.failed:
+        retFuture.fail(future.readError)
+      else:
+        let resultTup = (future.read.address,
+                         newSocket(future.read.client, socket.isBuffered))
+        retFuture.complete(resultTup)
+  return retFuture
+
+proc accept*(socket: PAsyncSocket): PFuture[PAsyncSocket] =
+  ## Accepts a new connection. Returns a future containing the client socket
+  ## corresponding to that connection.
+  ## The future will complete when the connection is successfully accepted.
+  var retFut = newFuture[PAsyncSocket]()
+  var fut = acceptAddr(socket)
+  fut.callback =
+    proc (future: PFuture[tuple[address: string, client: PAsyncSocket]]) =
+      assert future.finished
+      if future.failed:
+        retFut.fail(future.readError)
+      else:
+        retFut.complete(future.read.client)
+  return retFut
+
+proc recvLine*(socket: PAsyncSocket): PFuture[string] {.async.} =
+  ## Reads a line of data from ``socket``. Returned future will complete once
+  ## a full line is read or an error occurs.
+  ##
+  ## If a full line is read ``\r\L`` is not
+  ## added to ``line``, however if solely ``\r\L`` is read then ``line``
+  ## will be set to it.
+  ## 
+  ## If the socket is disconnected, ``line`` will be set to ``""``.
+  ##
+  ## If the socket is disconnected in the middle of a line (before ``\r\L``
+  ## is read) then line will be set to ``""``.
+  ## The partial line **will be lost**.
+  
+  template addNLIfEmpty(): stmt =
+    if result.len == 0:
+      result.add("\c\L")
+
+  result = ""
+  var c = ""
+  while true:
+    c = await recv(socket, 1)
+    if c.len == 0:
+      return ""
+    if c == "\r":
+      c = await recv(socket, 1, MSG_PEEK)
+      if c.len > 0 and c == "\L":
+        discard await recv(socket, 1)
+      addNLIfEmpty()
+      return
+    elif c == "\L":
+      addNLIfEmpty()
+      return
+    add(result.string, c)
+
+proc bindAddr*(socket: PAsyncSocket, port = TPort(0), address = "") =
+  ## Binds ``address``:``port`` to the socket.
+  ##
+  ## If ``address`` is "" then ADDR_ANY will be bound.
+  socket.PSocket.bindAddr(port, address)
+
+proc listen*(socket: PAsyncSocket, backlog = SOMAXCONN) =
+  ## Marks ``socket`` as accepting connections.
+  ## ``Backlog`` specifies the maximum length of the
+  ## queue of pending connections.
+  ##
+  ## Raises an EOS error upon failure.
+  socket.PSocket.listen(backlog)
+
+proc close*(socket: PAsyncSocket) =
+  ## Closes the socket.
+  socket.fd.TAsyncFD.close()
+  # TODO SSL
+
+when isMainModule:
+  type
+    TestCases = enum
+      HighClient, LowClient, LowServer
+
+  const test = LowServer
+
+  when test == HighClient:
+    proc main() {.async.} =
+      var sock = newAsyncSocket()
+      await sock.connect("irc.freenode.net", TPort(6667))
+      while true:
+        let line = await sock.recvLine()
+        if line == "":
+          echo("Disconnected")
+          break
+        else:
+          echo("Got line: ", line)
+    main()
+  elif test == LowClient:
+    var sock = newAsyncSocket()
+    var f = connect(sock, "irc.freenode.net", TPort(6667))
+    f.callback =
+      proc (future: PFuture[void]) =
+        echo("Connected in future!")
+        for i in 0 .. 50:
+          var recvF = recv(sock, 10)
+          recvF.callback =
+            proc (future: PFuture[string]) =
+              echo("Read ", future.read.len, ": ", future.read.repr)
+  elif test == LowServer:
+    var sock = newAsyncSocket()
+    sock.bindAddr(TPort(6667))
+    sock.listen()
+    proc onAccept(future: PFuture[PAsyncSocket]) =
+      let client = future.read
+      echo "Accepted ", client.fd.cint
+      var t = send(client, "test\c\L")
+      t.callback =
+        proc (future: PFuture[void]) =
+          echo("Send")
+          client.close()
+      
+      var f = accept(sock)
+      f.callback = onAccept
+      
+    var f = accept(sock)
+    f.callback = onAccept
+  runForever()
+    
diff --git a/lib/pure/dynlib.nim b/lib/pure/dynlib.nim
index 3ed00fdb2..54a553173 100644
--- a/lib/pure/dynlib.nim
+++ b/lib/pure/dynlib.nim
@@ -14,7 +14,7 @@
 type
   TLibHandle* = pointer ## a handle to a dynamically loaded library
 
-proc loadLib*(path: string): TLibHandle
+proc loadLib*(path: string, global_symbols=false): TLibHandle
   ## loads a library from `path`. Returns nil if the library could not 
   ## be loaded.
 
@@ -53,6 +53,7 @@ when defined(posix):
   #
   var
     RTLD_NOW {.importc: "RTLD_NOW", header: "<dlfcn.h>".}: int
+    RTLD_GLOBAL {.importc: "RTLD_GLOBAL", header: "<dlfcn.h>".}: int
 
   proc dlclose(lib: TLibHandle) {.importc, header: "<dlfcn.h>".}
   proc dlopen(path: CString, mode: int): TLibHandle {.
@@ -60,7 +61,10 @@ when defined(posix):
   proc dlsym(lib: TLibHandle, name: cstring): pointer {.
       importc, header: "<dlfcn.h>".}
 
-  proc loadLib(path: string): TLibHandle = return dlopen(path, RTLD_NOW)
+  proc loadLib(path: string, global_symbols=false): TLibHandle = 
+    var flags = RTLD_NOW
+    if global_symbols: flags = flags or RTLD_GLOBAL
+    return dlopen(path, flags)
   proc loadLib(): TLibHandle = return dlopen(nil, RTLD_NOW)
   proc unloadLib(lib: TLibHandle) = dlclose(lib)
   proc symAddr(lib: TLibHandle, name: cstring): pointer = 
@@ -81,14 +85,14 @@ elif defined(windows) or defined(dos):
   proc getProcAddress(lib: THINSTANCE, name: cstring): pointer {.
       importc: "GetProcAddress", header: "<windows.h>", stdcall.}
 
-  proc loadLib(path: string): TLibHandle =
+  proc loadLib(path: string, global_symbols=false): TLibHandle =
     result = cast[TLibHandle](winLoadLibrary(path))
   proc loadLib(): TLibHandle =
     result = cast[TLibHandle](winLoadLibrary(nil))
   proc unloadLib(lib: TLibHandle) = FreeLibrary(cast[THINSTANCE](lib))
 
   proc symAddr(lib: TLibHandle, name: cstring): pointer =
-    result = GetProcAddress(cast[THINSTANCE](lib), name)
+    result = getProcAddress(cast[THINSTANCE](lib), name)
 
 else:
   {.error: "no implementation for dynlib".}
diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim
index 63737d583..b9d6aec7b 100644
--- a/lib/pure/htmlgen.nim
+++ b/lib/pure/htmlgen.nim
@@ -1,12 +1,17 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2012 Andreas Rumpf
+#        (c) Copyright 2014 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
+## **Warning**: This module uses ``immediate`` macros which are known to
+## cause problems. Do yourself a favor and import the module
+## as ``from htmlgen import nil`` and then fully qualify the macros.
+##
+##
 ## This module implements a simple `XML`:idx: and `HTML`:idx: code 
 ## generator. Each commonly used HTML tag has a corresponding macro
 ## that generates a string with its HTML representation.
@@ -15,11 +20,11 @@
 ##
 ## .. code-block:: nimrod
 ##   var nim = "Nimrod"
-##   echo h1(a(href="http://nimrod-code.org", nim))
+##   echo h1(a(href="http://nimrod-lang.org", nim))
 ##  
 ## Writes the string::
 ##   
-##   <h1><a href="http://nimrod-code.org">Nimrod</a></h1>
+##   <h1><a href="http://nimrod-lang.org">Nimrod</a></h1>
 ##
 
 import
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index bb9835fe7..62d9bea7c 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -76,6 +76,8 @@
 ## currently only basic authentication is supported.
 
 import sockets, strutils, parseurl, parseutils, strtabs, base64
+import asyncnet, asyncdispatch
+import rawsockets
 
 type
   TResponse* = tuple[
@@ -286,16 +288,16 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
   add(headers, "\c\L")
   
   var s = socket()
-  var port = TPort(80)
+  var port = sockets.TPort(80)
   if r.scheme == "https":
     when defined(ssl):
       sslContext.wrapSocket(s)
-      port = TPort(443)
+      port = sockets.TPort(443)
     else:
       raise newException(EHttpRequestErr,
                 "SSL support is not available. Cannot connect over SSL.")
   if r.port != "":
-    port = TPort(r.port.parseInt)
+    port = sockets.TPort(r.port.parseInt)
   
   if timeout == -1:
     s.connect(r.hostname, port)
@@ -413,28 +415,217 @@ proc downloadFile*(url: string, outputFilename: string,
   else:
     fileError("Unable to open file")
 
+proc generateHeaders(r: TURL, httpMethod: THttpMethod,
+                     headers: PStringTable): string =
+  result = substr($httpMethod, len("http"))
+  # TODO: Proxies
+  result.add(" /" & r.path & r.query)
+  result.add(" HTTP/1.1\c\L")
 
-when isMainModule:
-  #downloadFile("http://force7.de/nimrod/index.html", "nimrodindex.html")
-  #downloadFile("http://www.httpwatch.com/", "ChunkTest.html")
-  #downloadFile("http://validator.w3.org/check?uri=http%3A%2F%2Fgoogle.com",
-  # "validator.html")
+  add(result, "Host: " & r.hostname & "\c\L")
+  add(result, "Connection: Keep-Alive\c\L")
+  for key, val in headers:
+    add(result, key & ": " & val & "\c\L")
+
+  add(result, "\c\L")
+
+type
+  PAsyncHttpClient = ref object
+    socket: PAsyncSocket
+    connected: bool
+    currentURL: TURL ## Where we are currently connected.
+    headers: PStringTable
+    userAgent: string
+
+proc newAsyncHttpClient*(): PAsyncHttpClient =
+  new result
+  result.socket = newAsyncSocket()
+  result.headers = newStringTable(modeCaseInsensitive)
+  result.userAgent = defUserAgent
+
+proc parseChunks(client: PAsyncHttpClient): PFuture[string] {.async.} =
+  result = ""
+  var ri = 0
+  while true:
+    var chunkSize = 0
+    var chunkSizeStr = await client.socket.recvLine()
+    var i = 0
+    if chunkSizeStr == "":
+      httpError("Server terminated connection prematurely")
+    while true:
+      case chunkSizeStr[i]
+      of '0'..'9':
+        chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('0'))
+      of 'a'..'f':
+        chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('a') + 10)
+      of 'A'..'F':
+        chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('A') + 10)
+      of '\0':
+        break
+      of ';':
+        # http://tools.ietf.org/html/rfc2616#section-3.6.1
+        # We don't care about chunk-extensions.
+        break
+      else:
+        httpError("Invalid chunk size: " & chunkSizeStr)
+      inc(i)
+    if chunkSize <= 0: break
+    result.add await recv(client.socket, chunkSize)
+    discard await recv(client.socket, 2) # Skip \c\L
+    # Trailer headers will only be sent if the request specifies that we want
+    # them: http://tools.ietf.org/html/rfc2616#section-3.6.1
+  
+proc parseBody(client: PAsyncHttpClient,
+               headers: PStringTable): PFuture[string] {.async.} =
+  result = ""
+  if headers["Transfer-Encoding"] == "chunked":
+    result = await parseChunks(client)
+  else:
+    # -REGION- Content-Length
+    # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.3
+    var contentLengthHeader = headers["Content-Length"]
+    if contentLengthHeader != "":
+      var length = contentLengthHeader.parseint()
+      result = await client.socket.recv(length)
+      if result == "":
+        httpError("Got disconnected while trying to recv body.")
+    else:
+      # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.4 TODO
+      
+      # -REGION- Connection: Close
+      # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.5
+      if headers["Connection"] == "close":
+        var buf = ""
+        while True:
+          buf = await client.socket.recv(4000)
+          if buf == "": break
+          result.add(buf)
+
+proc parseResponse(client: PAsyncHttpClient,
+                   getBody: bool): PFuture[TResponse] {.async.} =
+  var parsedStatus = false
+  var linei = 0
+  var fullyRead = false
+  var line = ""
+  result.headers = newStringTable(modeCaseInsensitive)
+  while True:
+    linei = 0
+    line = await client.socket.recvLine()
+    if line == "": break # We've been disconnected.
+    if line == "\c\L":
+      fullyRead = true
+      break
+    if not parsedStatus:
+      # Parse HTTP version info and status code.
+      var le = skipIgnoreCase(line, "HTTP/", linei)
+      if le <= 0: httpError("invalid http version")
+      inc(linei, le)
+      le = skipIgnoreCase(line, "1.1", linei)
+      if le > 0: result.version = "1.1"
+      else:
+        le = skipIgnoreCase(line, "1.0", linei)
+        if le <= 0: httpError("unsupported http version")
+        result.version = "1.0"
+      inc(linei, le)
+      # Status code
+      linei.inc skipWhitespace(line, linei)
+      result.status = line[linei .. -1]
+      parsedStatus = true
+    else:
+      # Parse headers
+      var name = ""
+      var le = parseUntil(line, name, ':', linei)
+      if le <= 0: httpError("invalid headers")
+      inc(linei, le)
+      if line[linei] != ':': httpError("invalid headers")
+      inc(linei) # Skip :
+      
+      result.headers[name] = line[linei.. -1].strip()
+  if not fullyRead:
+    httpError("Connection was closed before full request has been made")
+  if getBody:
+    result.body = await parseBody(client, result.headers)
+  else:
+    result.body = ""
+
+proc close*(client: PAsyncHttpClient) =
+  ## Closes any connections held by the HttpClient.
+  if client.connected:
+    client.socket.close()
+    client.connected = false
+    #client.socket = newAsyncSocket()
+
+proc newConnection(client: PAsyncHttpClient, url: TURL) {.async.} =
+  if not client.connected or client.currentURL.hostname != url.hostname or
+      client.currentURL.scheme != url.scheme:
+    if client.connected: client.close()
+    if url.scheme == "https":
+      assert false, "TODO SSL"
 
-  #var r = get("http://validator.w3.org/check?uri=http%3A%2F%2Fgoogle.com&
-  #  charset=%28detect+automatically%29&doctype=Inline&group=0")
+    # TODO: I should be able to write 'net.TPort' here...
+    let port =
+      if url.port == "": rawsockets.TPort(80)
+      else: rawsockets.TPort(url.port.parseInt)
+    
+    await client.socket.connect(url.hostname, port)
+    client.currentURL = url
+
+proc request*(client: PAsyncHttpClient, url: string, httpMethod = httpGET,
+              body = ""): PFuture[TResponse] {.async.} =
+  let r = parseUrl(url)
+  await newConnection(client, r)
+
+  if not client.headers.hasKey("user-agent") and client.userAgent != "":
+    client.headers["User-Agent"] = client.userAgent
   
-  var headers: string = "Content-Type: multipart/form-data; boundary=xyz\c\L"
-  var body: string = "--xyz\c\L"
-  # soap 1.2 output
-  body.add("Content-Disposition: form-data; name=\"output\"\c\L")
-  body.add("\c\Lsoap12\c\L")
+  var headers = generateHeaders(r, httpMethod, client.headers)
+  
+  await client.socket.send(headers)
+  if body != "":
+    await client.socket.send(body)
   
-  # html
-  body.add("--xyz\c\L")
-  body.add("Content-Disposition: form-data; name=\"uploaded_file\";" &
-           " filename=\"test.html\"\c\L")
-  body.add("Content-Type: text/html\c\L")
-  body.add("\c\L<html><head></head><body><p>test</p></body></html>\c\L")
-  body.add("--xyz--")
-
-  echo(postContent("http://validator.w3.org/check", headers, body))
+  result = await parseResponse(client, httpMethod != httpHEAD)
+
+when isMainModule:
+  when true:
+    # Async
+    proc main() {.async.} =
+      var client = newAsyncHttpClient()
+      var resp = await client.request("http://picheta.me")
+      
+      echo("Got response: ", resp.status)
+      echo("Body:\n")
+      echo(resp.body)
+
+      #var resp1 = await client.request("http://freenode.net")
+      #echo("Got response: ", resp1.status)
+
+      var resp2 = await client.request("http://picheta.me/aasfasgf.html")
+      echo("Got response: ", resp2.status)
+    main()
+    runForever()
+
+  else:
+    #downloadFile("http://force7.de/nimrod/index.html", "nimrodindex.html")
+    #downloadFile("http://www.httpwatch.com/", "ChunkTest.html")
+    #downloadFile("http://validator.w3.org/check?uri=http%3A%2F%2Fgoogle.com",
+    # "validator.html")
+
+    #var r = get("http://validator.w3.org/check?uri=http%3A%2F%2Fgoogle.com&
+    #  charset=%28detect+automatically%29&doctype=Inline&group=0")
+    
+    var headers: string = "Content-Type: multipart/form-data; boundary=xyz\c\L"
+    var body: string = "--xyz\c\L"
+    # soap 1.2 output
+    body.add("Content-Disposition: form-data; name=\"output\"\c\L")
+    body.add("\c\Lsoap12\c\L")
+    
+    # html
+    body.add("--xyz\c\L")
+    body.add("Content-Disposition: form-data; name=\"uploaded_file\";" &
+             " filename=\"test.html\"\c\L")
+    body.add("Content-Type: text/html\c\L")
+    body.add("\c\L<html><head></head><body><p>test</p></body></html>\c\L")
+    body.add("--xyz--")
+
+    echo(postContent("http://validator.w3.org/check", headers, body))
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index 062cfae25..94570fc68 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -20,6 +20,8 @@
 when defined(Posix) and not defined(haiku):
   {.passl: "-lm".}
 
+import times
+
 const
   PI* = 3.1415926535897932384626433 ## the circle constant PI (Ludolph's number)
   E* = 2.71828182845904523536028747 ## Euler's number
@@ -201,7 +203,7 @@ when not defined(JS):
       result = drand48() * max
     
   proc randomize() =
-    randomize(gettime(nil))
+    randomize(cast[int](epochTime()))
 
   proc randomize(seed: int) =
     srand(cint(seed))
diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim
index 8c404abe8..807f3da43 100644
--- a/lib/pure/memfiles.nim
+++ b/lib/pure/memfiles.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2012 Nimrod Contributors
+#        (c) Copyright 2014 Nimrod Contributors
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -34,6 +34,43 @@ type
     else:
       handle: cint
 
+
+proc mapMem*(m: var TMemFile, mode: TFileMode = fmRead,
+             mappedSize = -1, offset = 0): pointer =
+  var readonly = mode == fmRead
+  when defined(windows):
+    result = mapViewOfFileEx(
+      m.mapHandle,
+      if readonly: FILE_MAP_READ else: FILE_MAP_WRITE,
+      int32(offset shr 32),
+      int32(offset and 0xffffffff),
+      if mappedSize == -1: 0 else: mappedSize,
+      nil)
+    if result == nil:
+      osError(osLastError())
+  else:
+    assert mappedSize > 0
+    result = mmap(
+      nil,
+      mappedSize,
+      if readonly: PROT_READ else: PROT_READ or PROT_WRITE,
+      if readonly: MAP_PRIVATE else: MAP_SHARED,
+      m.handle, offset)
+    if result == cast[pointer](MAP_FAILED):
+      osError(osLastError())
+
+
+proc unmapMem*(f: var TMemFile, p: pointer, size: int) =
+  ## unmaps the memory region ``(p, <p+size)`` of the mapped file `f`.
+  ## All changes are written back to the file system, if `f` was opened
+  ## with write access. ``size`` must be of exactly the size that was requested
+  ## via ``mapMem``.
+  when defined(windows):
+    if unmapViewOfFile(p) == 0: osError(osLastError())
+  else:
+    if munmap(p, size) != 0: osError(osLastError())
+
+
 proc open*(filename: string, mode: TFileMode = fmRead,
            mappedSize = -1, offset = 0, newFileSize = -1): TMemFile =
   ## opens a memory mapped file. If this fails, ``EOS`` is raised.
@@ -71,7 +108,7 @@ proc open*(filename: string, mode: TFileMode = fmRead,
     when useWinUnicode:
       result.fHandle = callCreateFile(createFileW, newWideCString(filename))
     else:
-      result.fHandle = callCreateFile(CreateFileA, filename)
+      result.fHandle = callCreateFile(createFileA, filename)
 
     if result.fHandle == INVALID_HANDLE_VALUE:
       fail(osLastError(), "error opening file")
@@ -170,14 +207,14 @@ proc close*(f: var TMemFile) =
 
   when defined(windows):
     if f.fHandle != INVALID_HANDLE_VALUE:
-      lastErr = osLastError()
       error = unmapViewOfFile(f.mem) == 0
+      lastErr = osLastError()
       error = (closeHandle(f.mapHandle) == 0) or error
       error = (closeHandle(f.fHandle) == 0) or error
   else:
     if f.handle != 0:
-      lastErr = osLastError()
       error = munmap(f.mem, f.size) != 0
+      lastErr = osLastError()
       error = (close(f.handle) != 0) or error
 
   f.size = 0
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index bdcae677e..4afb5c6ab 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -9,17 +9,519 @@
 
 ## This module implements a high-level cross-platform sockets interface.
 
-import sockets2, os
+{.deadCodeElim: on.}
+import rawsockets, os, strutils, unsigned, parseutils, times
+export TPort
+type
+  IpAddressFamily* {.pure.} = enum ## Describes the type of an IP address
+    IPv6, ## IPv6 address
+    IPv4  ## IPv4 address
+
+  TIpAddress* = object ## stores an arbitrary IP address    
+    case family*: IpAddressFamily ## the type of the IP address (IPv4 or IPv6)
+    of IpAddressFamily.IPv6:
+      address_v6*: array[0..15, uint8] ## Contains the IP address in bytes in
+                                       ## case of IPv6
+    of IpAddressFamily.IPv4:
+      address_v4*: array[0..3, uint8] ## Contains the IP address in bytes in
+                                      ## case of IPv4
+
+proc IPv4_any*(): TIpAddress =
+  ## Returns the IPv4 any address, which can be used to listen on all available
+  ## network adapters
+  result = TIpAddress(
+    family: IpAddressFamily.IPv4,
+    address_v4: [0'u8, 0, 0, 0])
+
+proc IPv4_loopback*(): TIpAddress =
+  ## Returns the IPv4 loopback address (127.0.0.1)
+  result = TIpAddress(
+    family: IpAddressFamily.IPv4,
+    address_v4: [127'u8, 0, 0, 1])
+
+proc IPv4_broadcast*(): TIpAddress =
+  ## Returns the IPv4 broadcast address (255.255.255.255)
+  result = TIpAddress(
+    family: IpAddressFamily.IPv4,
+    address_v4: [255'u8, 255, 255, 255])
+
+proc IPv6_any*(): TIpAddress =
+  ## Returns the IPv6 any address (::0), which can be used
+  ## to listen on all available network adapters 
+  result = TIpAddress(
+    family: IpAddressFamily.IPv6,
+    address_v6: [0'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
+
+proc IPv6_loopback*(): TIpAddress =
+  ## Returns the IPv6 loopback address (::1)
+  result = TIpAddress(
+    family: IpAddressFamily.IPv6,
+    address_v6: [0'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
+
+proc `==`*(lhs, rhs: TIpAddress): bool =
+  ## Compares two IpAddresses for Equality. Returns two if the addresses are equal
+  if lhs.family != rhs.family: return false
+  if lhs.family == IpAddressFamily.IPv4:
+    for i in low(lhs.address_v4) .. high(lhs.address_v4):
+      if lhs.address_v4[i] != rhs.address_v4[i]: return false
+  else: # IPv6
+    for i in low(lhs.address_v6) .. high(lhs.address_v6):
+      if lhs.address_v6[i] != rhs.address_v6[i]: return false
+  return true
+
+proc `$`*(address: TIpAddress): string =
+  ## Converts an TIpAddress into the textual representation
+  result = ""
+  case address.family
+  of IpAddressFamily.IPv4:
+    for i in 0 .. 3:
+      if i != 0:
+        result.add('.')
+      result.add($address.address_v4[i])
+  of IpAddressFamily.IPv6:
+    var
+      currentZeroStart = -1
+      currentZeroCount = 0
+      biggestZeroStart = -1
+      biggestZeroCount = 0
+    # Look for the largest block of zeros
+    for i in 0..7:
+      var isZero = address.address_v6[i*2] == 0 and address.address_v6[i*2+1] == 0
+      if isZero:
+        if currentZeroStart == -1:
+          currentZeroStart = i
+          currentZeroCount = 1
+        else:
+          currentZeroCount.inc()
+        if currentZeroCount > biggestZeroCount:
+          biggestZeroCount = currentZeroCount
+          biggestZeroStart = currentZeroStart
+      else:
+        currentZeroStart = -1
+
+    if biggestZeroCount == 8: # Special case ::0
+      result.add("::")
+    else: # Print address
+      var printedLastGroup = false
+      for i in 0..7:
+        var word:uint16 = (cast[uint16](address.address_v6[i*2])) shl 8
+        word = word or cast[uint16](address.address_v6[i*2+1])
+
+        if biggestZeroCount != 0 and # Check if group is in skip group
+          (i >= biggestZeroStart and i < (biggestZeroStart + biggestZeroCount)):
+          if i == biggestZeroStart: # skip start
+            result.add("::")
+          printedLastGroup = false
+        else:
+          if printedLastGroup:
+            result.add(':')
+          var
+            afterLeadingZeros = false
+            mask = 0xF000'u16
+          for j in 0'u16..3'u16:
+            var val = (mask and word) shr (4'u16*(3'u16-j))
+            if val != 0 or afterLeadingZeros:
+              if val < 0xA:
+                result.add(chr(uint16(ord('0'))+val))
+              else: # val >= 0xA
+                result.add(chr(uint16(ord('a'))+val-0xA))
+              afterLeadingZeros = true
+            mask = mask shr 4
+          printedLastGroup = true
+
+proc parseIPv4Address(address_str: string): TIpAddress =
+  ## Parses IPv4 adresses
+  ## Raises EInvalidValue on errors
+  var
+    byteCount = 0
+    currentByte:uint16 = 0
+    seperatorValid = false
+
+  result.family = IpAddressFamily.IPv4
+
+  for i in 0 .. high(address_str):
+    if address_str[i] in strutils.Digits: # Character is a number
+      currentByte = currentByte * 10 +
+        cast[uint16](ord(address_str[i]) - ord('0'))
+      if currentByte > 255'u16:
+        raise newException(EInvalidValue,
+          "Invalid IP Address. Value is out of range")
+      seperatorValid = true
+    elif address_str[i] == '.': # IPv4 address separator
+      if not seperatorValid or byteCount >= 3:
+        raise newException(EInvalidValue,
+          "Invalid IP Address. The address consists of too many groups")
+      result.address_v4[byteCount] = cast[uint8](currentByte)
+      currentByte = 0
+      byteCount.inc
+      seperatorValid = false
+    else:
+      raise newException(EInvalidValue,
+        "Invalid IP Address. Address contains an invalid character")
+
+  if byteCount != 3 or not seperatorValid:
+    raise newException(EInvalidValue, "Invalid IP Address")
+  result.address_v4[byteCount] = cast[uint8](currentByte)
+
+proc parseIPv6Address(address_str: string): TIpAddress =
+  ## Parses IPv6 adresses
+  ## Raises EInvalidValue on errors
+  result.family = IpAddressFamily.IPv6
+  if address_str.len < 2:
+    raise newException(EInvalidValue, "Invalid IP Address")
+
+  var
+    groupCount = 0
+    currentGroupStart = 0
+    currentShort:uint32 = 0
+    seperatorValid = true
+    dualColonGroup = -1
+    lastWasColon = false
+    v4StartPos = -1
+    byteCount = 0
+
+  for i,c in address_str:
+    if c == ':':
+      if not seperatorValid:
+        raise newException(EInvalidValue,
+          "Invalid IP Address. Address contains an invalid seperator")
+      if lastWasColon:        
+        if dualColonGroup != -1:
+          raise newException(EInvalidValue,
+            "Invalid IP Address. Address contains more than one \"::\" seperator")
+        dualColonGroup = groupCount
+        seperatorValid = false
+      elif i != 0 and i != high(address_str):
+        if groupCount >= 8:
+          raise newException(EInvalidValue,
+            "Invalid IP Address. The address consists of too many groups")
+        result.address_v6[groupCount*2] = cast[uint8](currentShort shr 8)
+        result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF)
+        currentShort = 0
+        groupCount.inc()        
+        if dualColonGroup != -1: seperatorValid = false
+      elif i == 0: # only valid if address starts with ::
+        if address_str[1] != ':':
+          raise newException(EInvalidValue,
+            "Invalid IP Address. Address may not start with \":\"")
+      else: # i == high(address_str) - only valid if address ends with ::
+        if address_str[high(address_str)-1] != ':': 
+          raise newException(EInvalidValue,
+            "Invalid IP Address. Address may not end with \":\"")
+      lastWasColon = true
+      currentGroupStart = i + 1
+    elif c == '.': # Switch to parse IPv4 mode
+      if i < 3 or not seperatorValid or groupCount >= 7:
+        raise newException(EInvalidValue, "Invalid IP Address")
+      v4StartPos = currentGroupStart
+      currentShort = 0
+      seperatorValid = false
+      break
+    elif c in strutils.HexDigits:
+      if c in strutils.Digits: # Normal digit
+        currentShort = (currentShort shl 4) + cast[uint32](ord(c) - ord('0'))
+      elif c >= 'a' and c <= 'f': # Lower case hex
+        currentShort = (currentShort shl 4) + cast[uint32](ord(c) - ord('a')) + 10
+      else: # Upper case hex
+        currentShort = (currentShort shl 4) + cast[uint32](ord(c) - ord('A')) + 10
+      if currentShort > 65535'u32:
+        raise newException(EInvalidValue,
+          "Invalid IP Address. Value is out of range")
+      lastWasColon = false
+      seperatorValid = true
+    else:
+      raise newException(EInvalidValue,
+        "Invalid IP Address. Address contains an invalid character")
+
+
+  if v4StartPos == -1: # Don't parse v4. Copy the remaining v6 stuff
+    if seperatorValid: # Copy remaining data
+      if groupCount >= 8:
+        raise newException(EInvalidValue,
+          "Invalid IP Address. The address consists of too many groups")
+      result.address_v6[groupCount*2] = cast[uint8](currentShort shr 8)
+      result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF)
+      groupCount.inc()
+  else: # Must parse IPv4 address
+    for i,c in address_str[v4StartPos..high(address_str)]:
+      if c in strutils.Digits: # Character is a number
+        currentShort = currentShort * 10 + cast[uint32](ord(c) - ord('0'))
+        if currentShort > 255'u32:
+          raise newException(EInvalidValue,
+            "Invalid IP Address. Value is out of range")
+        seperatorValid = true
+      elif c == '.': # IPv4 address separator
+        if not seperatorValid or byteCount >= 3:
+          raise newException(EInvalidValue, "Invalid IP Address")
+        result.address_v6[groupCount*2 + byteCount] = cast[uint8](currentShort)
+        currentShort = 0
+        byteCount.inc()
+        seperatorValid = false
+      else: # Invalid character
+        raise newException(EInvalidValue,
+          "Invalid IP Address. Address contains an invalid character")
+
+    if byteCount != 3 or not seperatorValid:
+      raise newException(EInvalidValue, "Invalid IP Address")
+    result.address_v6[groupCount*2 + byteCount] = cast[uint8](currentShort)
+    groupCount += 2
+
+  # Shift and fill zeros in case of ::
+  if groupCount > 8:
+    raise newException(EInvalidValue,
+      "Invalid IP Address. The address consists of too many groups")
+  elif groupCount < 8: # must fill
+    if dualColonGroup == -1:
+      raise newException(EInvalidValue,
+        "Invalid IP Address. The address consists of too few groups")
+    var toFill = 8 - groupCount # The number of groups to fill
+    var toShift = groupCount - dualColonGroup # Nr of known groups after ::
+    for i in 0..2*toShift-1: # shift
+      result.address_v6[15-i] = result.address_v6[groupCount*2-i-1]
+    for i in 0..2*toFill-1: # fill with 0s
+      result.address_v6[dualColonGroup*2+i] = 0
+  elif dualColonGroup != -1:
+    raise newException(EInvalidValue,
+      "Invalid IP Address. The address consists of too many groups")
+
+proc parseIpAddress*(address_str: string): TIpAddress =
+  ## Parses an IP address
+  ## Raises EInvalidValue on error
+  if address_str == nil:
+    raise newException(EInvalidValue, "IP Address string is nil")
+  if address_str.contains(':'):
+    return parseIPv6Address(address_str)
+  else:
+    return parseIPv4Address(address_str)
+
+when defined(ssl):
+  import openssl
+
+# Note: The enumerations are mapped to Window's constants.
+
+when defined(ssl):
+  type
+    ESSL* = object of ESynch
+
+    TSSLCVerifyMode* = enum
+      CVerifyNone, CVerifyPeer
+    
+    TSSLProtVersion* = enum
+      protSSLv2, protSSLv3, protTLSv1, protSSLv23
+    
+    PSSLContext* = distinct PSSLCTX
+
+    TSSLAcceptResult* = enum
+      AcceptNoClient = 0, AcceptNoHandshake, AcceptSuccess
+
+const
+  BufferSize*: int = 4000 ## size of a buffered socket's buffer
 
 type
-  TSocket* = TSocketHandle
+  TSocketImpl* = object ## socket type
+    fd*: TSocketHandle
+    case isBuffered*: bool # determines whether this socket is buffered.
+    of true:
+      buffer*: array[0..BufferSize, char]
+      currPos*: int # current index in buffer
+      bufLen*: int # current length of buffer
+    of false: nil
+    when defined(ssl):
+      case isSsl*: bool
+      of true:
+        sslHandle*: PSSL
+        sslContext*: PSSLContext
+        sslNoHandshake*: bool # True if needs handshake.
+        sslHasPeekChar*: bool
+        sslPeekChar*: char
+      of false: nil
+  
+  PSocket* = ref TSocketImpl
 
-proc bindAddr*(socket: TSocket, port = TPort(0), address = "") {.
-  tags: [FReadIO].} =
+  TSOBool* = enum ## Boolean socket options.
+    OptAcceptConn, OptBroadcast, OptDebug, OptDontRoute, OptKeepAlive,
+    OptOOBInline, OptReuseAddr
+
+  TReadLineResult* = enum ## result for readLineAsync
+    ReadFullLine, ReadPartialLine, ReadDisconnected, ReadNone
+
+  ETimeout* = object of ESynch
+
+proc createSocket(fd: TSocketHandle, isBuff: bool): PSocket =
+  assert fd != osInvalidSocket
+  new(result)
+  result.fd = fd
+  result.isBuffered = isBuff
+  if isBuff:
+    result.currPos = 0
+
+proc newSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
+             protocol: TProtocol = IPPROTO_TCP, buffered = true): PSocket =
+  ## Creates a new socket.
+  ##
+  ## If an error occurs EOS will be raised.
+  let fd = newRawSocket(domain, typ, protocol)
+  if fd == osInvalidSocket:
+    osError(osLastError())
+  result = createSocket(fd, buffered)
+
+when defined(ssl):
+  CRYPTO_malloc_init()
+  SslLibraryInit()
+  SslLoadErrorStrings()
+  ErrLoadBioStrings()
+  OpenSSL_add_all_algorithms()
+
+  proc SSLError(s = "") =
+    if s != "":
+      raise newException(ESSL, s)
+    let err = ErrPeekLastError()
+    if err == 0:
+      raise newException(ESSL, "No error reported.")
+    if err == -1:
+      OSError(OSLastError())
+    var errStr = ErrErrorString(err, nil)
+    raise newException(ESSL, $errStr)
+
+  # http://simplestcodings.blogspot.co.uk/2010/08/secure-server-client-using-openssl-in-c.html
+  proc loadCertificates(ctx: PSSL_CTX, certFile, keyFile: string) =
+    if certFile != "" and not existsFile(certFile):
+      raise newException(system.EIO, "Certificate file could not be found: " & certFile)
+    if keyFile != "" and not existsFile(keyFile):
+      raise newException(system.EIO, "Key file could not be found: " & keyFile)
+    
+    if certFile != "":
+      var ret = SSLCTXUseCertificateChainFile(ctx, certFile)
+      if ret != 1:
+        SSLError()
+    
+    # TODO: Password? www.rtfm.com/openssl-examples/part1.pdf
+    if keyFile != "":
+      if SSL_CTX_use_PrivateKey_file(ctx, keyFile,
+                                     SSL_FILETYPE_PEM) != 1:
+        SSLError()
+        
+      if SSL_CTX_check_private_key(ctx) != 1:
+        SSLError("Verification of private key file failed.")
 
-  ## binds an address/port number to a socket.
-  ## Use address string in dotted decimal form like "a.b.c.d"
-  ## or leave "" for any address.
+  proc newContext*(protVersion = ProtSSLv23, verifyMode = CVerifyPeer,
+                   certFile = "", keyFile = ""): PSSLContext =
+    ## Creates an SSL context.
+    ## 
+    ## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1 are 
+    ## are available with the addition of ``ProtSSLv23`` which allows for 
+    ## compatibility with all of them.
+    ##
+    ## There are currently only two options for verify mode;
+    ## one is ``CVerifyNone`` and with it certificates will not be verified
+    ## the other is ``CVerifyPeer`` and certificates will be verified for
+    ## it, ``CVerifyPeer`` is the safest choice.
+    ##
+    ## The last two parameters specify the certificate file path and the key file
+    ## path, a server socket will most likely not work without these.
+    ## Certificates can be generated using the following command:
+    ## ``openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert.pem -out mycert.pem``.
+    var newCTX: PSSL_CTX
+    case protVersion
+    of protSSLv23:
+      newCTX = SSL_CTX_new(SSLv23_method()) # SSlv2,3 and TLS1 support.
+    of protSSLv2:
+      when not defined(linux):
+        newCTX = SSL_CTX_new(SSLv2_method())
+      else:
+        SSLError()
+    of protSSLv3:
+      newCTX = SSL_CTX_new(SSLv3_method())
+    of protTLSv1:
+      newCTX = SSL_CTX_new(TLSv1_method())
+    
+    if newCTX.SSLCTXSetCipherList("ALL") != 1:
+      SSLError()
+    case verifyMode
+    of CVerifyPeer:
+      newCTX.SSLCTXSetVerify(SSLVerifyPeer, nil)
+    of CVerifyNone:
+      newCTX.SSLCTXSetVerify(SSLVerifyNone, nil)
+    if newCTX == nil:
+      SSLError()
+
+    discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY)
+    newCTX.loadCertificates(certFile, keyFile)
+    return PSSLContext(newCTX)
+
+  proc wrapSocket*(ctx: PSSLContext, socket: PSocket) =
+    ## Wraps a socket in an SSL context. This function effectively turns
+    ## ``socket`` into an SSL socket.
+    ##
+    ## **Disclaimer**: This code is not well tested, may be very unsafe and
+    ## prone to security vulnerabilities.
+    
+    socket.isSSL = true
+    socket.sslContext = ctx
+    socket.sslHandle = SSLNew(PSSLCTX(socket.sslContext))
+    socket.sslNoHandshake = false
+    socket.sslHasPeekChar = false
+    if socket.sslHandle == nil:
+      SSLError()
+    
+    if SSLSetFd(socket.sslHandle, socket.fd) != 1:
+      SSLError()
+
+proc socketError*(socket: PSocket, err: int = -1, async = false) =
+  ## Raises an EOS error based on the error code returned by ``SSLGetError``
+  ## (for SSL sockets) and ``osLastError`` otherwise.
+  ##
+  ## If ``async`` is ``True`` no error will be thrown in the case when the
+  ## error was caused by no data being available to be read.
+  ##
+  ## If ``err`` is not lower than 0 no exception will be raised.
+  when defined(ssl):
+    if socket.isSSL:
+      if err <= 0:
+        var ret = SSLGetError(socket.sslHandle, err.cint)
+        case ret
+        of SSL_ERROR_ZERO_RETURN:
+          SSLError("TLS/SSL connection failed to initiate, socket closed prematurely.")
+        of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
+          if async:
+            return
+          else: SSLError("Not enough data on socket.")
+        of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ:
+          if async:
+            return
+          else: SSLError("Not enough data on socket.")
+        of SSL_ERROR_WANT_X509_LOOKUP:
+          SSLError("Function for x509 lookup has been called.")
+        of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
+          SSLError()
+        else: SSLError("Unknown Error")
+  
+  if err == -1 and not (when defined(ssl): socket.isSSL else: false):
+    let lastError = osLastError()
+    if async:
+      when defined(windows):
+        if lastError.int32 == WSAEWOULDBLOCK:
+          return
+        else: osError(lastError)
+      else:
+        if lastError.int32 == EAGAIN or lastError.int32 == EWOULDBLOCK:
+          return
+        else: osError(lastError)
+    else: osError(lastError)
+
+proc listen*(socket: PSocket, backlog = SOMAXCONN) {.tags: [FReadIO].} =
+  ## Marks ``socket`` as accepting connections. 
+  ## ``Backlog`` specifies the maximum length of the 
+  ## queue of pending connections.
+  ##
+  ## Raises an EOS error upon failure.
+  if listen(socket.fd, backlog) < 0'i32: osError(osLastError())
+
+proc bindAddr*(socket: PSocket, port = TPort(0), address = "") {.
+  tags: [FReadIO].} =
+  ## Binds ``address``:``port`` to the socket.
+  ##
+  ## If ``address`` is "" then ADDR_ANY will be bound.
 
   if address == "":
     var name: TSockaddr_in
@@ -29,12 +531,599 @@ proc bindAddr*(socket: TSocket, port = TPort(0), address = "") {.
       name.sin_family = toInt(AF_INET)
     name.sin_port = htons(int16(port))
     name.sin_addr.s_addr = htonl(INADDR_ANY)
-    if bindAddr(socket, cast[ptr TSockAddr](addr(name)),
+    if bindAddr(socket.fd, cast[ptr TSockAddr](addr(name)),
                   sizeof(name).TSocklen) < 0'i32:
       osError(osLastError())
   else:
     var aiList = getAddrInfo(address, port, AF_INET)
-    if bindAddr(socket, aiList.ai_addr, aiList.ai_addrlen.TSocklen) < 0'i32:
+    if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.TSocklen) < 0'i32:
       dealloc(aiList)
       osError(osLastError())
-    dealloc(aiList)
\ No newline at end of file
+    dealloc(aiList)
+
+proc acceptAddr*(server: PSocket, client: var PSocket, address: var string) {.
+  tags: [FReadIO].} =
+  ## Blocks until a connection is being made from a client. When a connection
+  ## is made sets ``client`` to the client socket and ``address`` to the address
+  ## of the connecting client.
+  ## This function will raise EOS if an error occurs.
+  ##
+  ## The resulting client will inherit any properties of the server socket. For
+  ## example: whether the socket is buffered or not.
+  ##
+  ## **Note**: ``client`` must be initialised (with ``new``), this function 
+  ## makes no effort to initialise the ``client`` variable.
+  assert(client != nil)
+  var sockAddress: Tsockaddr_in
+  var addrLen = sizeof(sockAddress).TSocklen
+  var sock = accept(server.fd, cast[ptr TSockAddr](addr(sockAddress)),
+                    addr(addrLen))
+  
+  if sock == osInvalidSocket:
+    let err = osLastError()
+    osError(err)
+  else:
+    client.fd = sock
+    client.isBuffered = server.isBuffered
+
+    # Handle SSL.
+    when defined(ssl):
+      if server.isSSL:
+        # We must wrap the client sock in a ssl context.
+        
+        server.sslContext.wrapSocket(client)
+        let ret = SSLAccept(client.sslHandle)
+        socketError(client, ret, false)
+    
+    # Client socket is set above.
+    address = $inet_ntoa(sockAddress.sin_addr)
+
+when false: #defined(ssl):
+  proc acceptAddrSSL*(server: PSocket, client: var PSocket,
+                      address: var string): TSSLAcceptResult {.
+                      tags: [FReadIO].} =
+    ## This procedure should only be used for non-blocking **SSL** sockets. 
+    ## It will immediately return with one of the following values:
+    ## 
+    ## ``AcceptSuccess`` will be returned when a client has been successfully
+    ## accepted and the handshake has been successfully performed between
+    ## ``server`` and the newly connected client.
+    ##
+    ## ``AcceptNoHandshake`` will be returned when a client has been accepted
+    ## but no handshake could be performed. This can happen when the client
+    ## connects but does not yet initiate a handshake. In this case
+    ## ``acceptAddrSSL`` should be called again with the same parameters.
+    ##
+    ## ``AcceptNoClient`` will be returned when no client is currently attempting
+    ## to connect.
+    template doHandshake(): stmt =
+      when defined(ssl):
+        if server.isSSL:
+          client.setBlocking(false)
+          # We must wrap the client sock in a ssl context.
+          
+          if not client.isSSL or client.sslHandle == nil:
+            server.sslContext.wrapSocket(client)
+          let ret = SSLAccept(client.sslHandle)
+          while ret <= 0:
+            let err = SSLGetError(client.sslHandle, ret)
+            if err != SSL_ERROR_WANT_ACCEPT:
+              case err
+              of SSL_ERROR_ZERO_RETURN:
+                SSLError("TLS/SSL connection failed to initiate, socket closed prematurely.")
+              of SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE,
+                 SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
+                client.sslNoHandshake = true
+                return AcceptNoHandshake
+              of SSL_ERROR_WANT_X509_LOOKUP:
+                SSLError("Function for x509 lookup has been called.")
+              of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
+                SSLError()
+              else:
+                SSLError("Unknown error")
+          client.sslNoHandshake = false
+
+    if client.isSSL and client.sslNoHandshake:
+      doHandshake()
+      return AcceptSuccess
+    else:
+      acceptAddrPlain(AcceptNoClient, AcceptSuccess):
+        doHandshake()
+
+proc accept*(server: PSocket, client: var PSocket) {.tags: [FReadIO].} =
+  ## Equivalent to ``acceptAddr`` but doesn't return the address, only the
+  ## socket.
+  ## 
+  ## **Note**: ``client`` must be initialised (with ``new``), this function
+  ## makes no effort to initialise the ``client`` variable.
+  
+  var addrDummy = ""
+  acceptAddr(server, client, addrDummy)
+
+proc close*(socket: PSocket) =
+  ## Closes a socket.
+  socket.fd.close()
+  when defined(ssl):
+    if socket.isSSL:
+      let res = SSLShutdown(socket.sslHandle)
+      if res == 0:
+        if SSLShutdown(socket.sslHandle) != 1:
+          socketError(socket)
+      elif res != 1:
+        socketError(socket)
+
+proc toCInt(opt: TSOBool): cint =
+  case opt
+  of OptAcceptConn: SO_ACCEPTCONN
+  of OptBroadcast: SO_BROADCAST
+  of OptDebug: SO_DEBUG
+  of OptDontRoute: SO_DONTROUTE
+  of OptKeepAlive: SO_KEEPALIVE
+  of OptOOBInline: SO_OOBINLINE
+  of OptReuseAddr: SO_REUSEADDR
+
+proc getSockOpt*(socket: PSocket, opt: TSOBool, level = SOL_SOCKET): bool {.
+  tags: [FReadIO].} =
+  ## Retrieves option ``opt`` as a boolean value.
+  var res = getsockoptint(socket.fd, cint(level), toCInt(opt))
+  result = res != 0
+
+proc setSockOpt*(socket: PSocket, opt: TSOBool, value: bool, level = SOL_SOCKET) {.
+  tags: [FWriteIO].} =
+  ## Sets option ``opt`` to a boolean value specified by ``value``.
+  var valuei = cint(if value: 1 else: 0)
+  setsockoptint(socket.fd, cint(level), toCInt(opt), valuei)
+
+proc connect*(socket: PSocket, address: string, port = TPort(0), 
+              af: TDomain = AF_INET) {.tags: [FReadIO].} =
+  ## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a
+  ## host name. If ``address`` is a host name, this function will try each IP
+  ## of that host name. ``htons`` is already performed on ``port`` so you must
+  ## not do it.
+  ##
+  ## If ``socket`` is an SSL socket a handshake will be automatically performed.
+  var aiList = getAddrInfo(address, port, af)
+  # try all possibilities:
+  var success = false
+  var lastError: TOSErrorCode
+  var it = aiList
+  while it != nil:
+    if connect(socket.fd, it.ai_addr, it.ai_addrlen.TSocklen) == 0'i32:
+      success = true
+      break
+    else: lastError = osLastError()
+    it = it.ai_next
+
+  dealloc(aiList)
+  if not success: osError(lastError)
+  
+  when defined(ssl):
+    if socket.isSSL:
+      let ret = SSLConnect(socket.sslHandle)
+      socketError(socket, ret)
+
+when defined(ssl):
+  proc handshake*(socket: PSocket): bool {.tags: [FReadIO, FWriteIO].} =
+    ## This proc needs to be called on a socket after it connects. This is
+    ## only applicable when using ``connectAsync``.
+    ## This proc performs the SSL handshake.
+    ##
+    ## Returns ``False`` whenever the socket is not yet ready for a handshake,
+    ## ``True`` whenever handshake completed successfully.
+    ##
+    ## A ESSL error is raised on any other errors.
+    result = true
+    if socket.isSSL:
+      var ret = SSLConnect(socket.sslHandle)
+      if ret <= 0:
+        var errret = SSLGetError(socket.sslHandle, ret)
+        case errret
+        of SSL_ERROR_ZERO_RETURN:
+          SSLError("TLS/SSL connection failed to initiate, socket closed prematurely.")
+        of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT,
+          SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE:
+          return false
+        of SSL_ERROR_WANT_X509_LOOKUP:
+          SSLError("Function for x509 lookup has been called.")
+        of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
+          SSLError()
+        else:
+          SSLError("Unknown Error")
+      socket.sslNoHandshake = false
+    else:
+      SSLError("Socket is not an SSL socket.")
+
+  proc gotHandshake*(socket: PSocket): bool =
+    ## Determines whether a handshake has occurred between a client (``socket``)
+    ## and the server that ``socket`` is connected to.
+    ##
+    ## Throws ESSL if ``socket`` is not an SSL socket.
+    if socket.isSSL:
+      return not socket.sslNoHandshake
+    else:
+      SSLError("Socket is not an SSL socket.")
+
+proc hasDataBuffered*(s: PSocket): bool =
+  ## Determines whether a socket has data buffered.
+  result = false
+  if s.isBuffered:
+    result = s.bufLen > 0 and s.currPos != s.bufLen
+
+  when defined(ssl):
+    if s.isSSL and not result:
+      result = s.sslHasPeekChar
+
+proc select(readfd: PSocket, timeout = 500): int =
+  ## Used for socket operation timeouts.
+  if readfd.hasDataBuffered:
+    return 1
+
+  var fds = @[readFd.fd]
+  result = select(fds, timeout)
+
+proc readIntoBuf(socket: PSocket, flags: int32): int =
+  result = 0
+  when defined(ssl):
+    if socket.isSSL:
+      result = SSLRead(socket.sslHandle, addr(socket.buffer), int(socket.buffer.high))
+    else:
+      result = recv(socket.fd, addr(socket.buffer), cint(socket.buffer.high), flags)
+  else:
+    result = recv(socket.fd, addr(socket.buffer), cint(socket.buffer.high), flags)
+  if result <= 0:
+    socket.bufLen = 0
+    socket.currPos = 0
+    return result
+  socket.bufLen = result
+  socket.currPos = 0
+
+template retRead(flags, readBytes: int) {.dirty.} =
+  let res = socket.readIntoBuf(flags.int32)
+  if res <= 0:
+    if readBytes > 0:
+      return readBytes
+    else:
+      return res
+
+proc recv*(socket: PSocket, data: pointer, size: int): int {.tags: [FReadIO].} =
+  ## Receives data from a socket.
+  ##
+  ## **Note**: This is a low-level function, you may be interested in the higher
+  ## level versions of this function which are also named ``recv``.
+  if size == 0: return
+  if socket.isBuffered:
+    if socket.bufLen == 0:
+      retRead(0'i32, 0)
+    
+    var read = 0
+    while read < size:
+      if socket.currPos >= socket.bufLen:
+        retRead(0'i32, read)
+    
+      let chunk = min(socket.bufLen-socket.currPos, size-read)
+      var d = cast[cstring](data)
+      copyMem(addr(d[read]), addr(socket.buffer[socket.currPos]), chunk)
+      read.inc(chunk)
+      socket.currPos.inc(chunk)
+
+    result = read
+  else:
+    when defined(ssl):
+      if socket.isSSL:
+        if socket.sslHasPeekChar:
+          copyMem(data, addr(socket.sslPeekChar), 1)
+          socket.sslHasPeekChar = false
+          if size-1 > 0:
+            var d = cast[cstring](data)
+            result = SSLRead(socket.sslHandle, addr(d[1]), size-1) + 1
+          else:
+            result = 1
+        else:
+          result = SSLRead(socket.sslHandle, data, size)
+      else:
+        result = recv(socket.fd, data, size.cint, 0'i32)
+    else:
+      result = recv(socket.fd, data, size.cint, 0'i32)
+
+proc waitFor(socket: PSocket, waited: var float, timeout, size: int,
+             funcName: string): int {.tags: [FTime].} =
+  ## determines the amount of characters that can be read. Result will never
+  ## be larger than ``size``. For unbuffered sockets this will be ``1``.
+  ## For buffered sockets it can be as big as ``BufferSize``.
+  ##
+  ## If this function does not determine that there is data on the socket
+  ## within ``timeout`` ms, an ETimeout error will be raised.
+  result = 1
+  if size <= 0: assert false
+  if timeout == -1: return size
+  if socket.isBuffered and socket.bufLen != 0 and socket.bufLen != socket.currPos:
+    result = socket.bufLen - socket.currPos
+    result = min(result, size)
+  else:
+    if timeout - int(waited * 1000.0) < 1:
+      raise newException(ETimeout, "Call to '" & funcName & "' timed out.")
+    
+    when defined(ssl):
+      if socket.isSSL:
+        if socket.hasDataBuffered:
+          # sslPeekChar is present.
+          return 1
+        let sslPending = SSLPending(socket.sslHandle)
+        if sslPending != 0:
+          return sslPending
+    
+    var startTime = epochTime()
+    let selRet = select(socket, timeout - int(waited * 1000.0))
+    if selRet < 0: osError(osLastError())
+    if selRet != 1:
+      raise newException(ETimeout, "Call to '" & funcName & "' timed out.")
+    waited += (epochTime() - startTime)
+
+proc recv*(socket: PSocket, data: pointer, size: int, timeout: int): int {.
+  tags: [FReadIO, FTime].} =
+  ## overload with a ``timeout`` parameter in miliseconds.
+  var waited = 0.0 # number of seconds already waited  
+  
+  var read = 0
+  while read < size:
+    let avail = waitFor(socket, waited, timeout, size-read, "recv")
+    var d = cast[cstring](data)
+    result = recv(socket, addr(d[read]), avail)
+    if result == 0: break
+    if result < 0:
+      return result
+    inc(read, result)
+  
+  result = read
+
+proc recv*(socket: PSocket, data: var string, size: int, timeout = -1): int =
+  ## Higher-level version of ``recv``.
+  ##
+  ## When 0 is returned the socket's connection has been closed.
+  ##
+  ## This function will throw an EOS exception when an error occurs. A value
+  ## lower than 0 is never returned.
+  ##
+  ## A timeout may be specified in miliseconds, if enough data is not received
+  ## within the time specified an ETimeout exception will be raised.
+  ##
+  ## **Note**: ``data`` must be initialised.
+  data.setLen(size)
+  result = recv(socket, cstring(data), size, timeout)
+  if result < 0:
+    data.setLen(0)
+    socket.socketError(result)
+  data.setLen(result)
+
+proc peekChar(socket: PSocket, c: var char): int {.tags: [FReadIO].} =
+  if socket.isBuffered:
+    result = 1
+    if socket.bufLen == 0 or socket.currPos > socket.bufLen-1:
+      var res = socket.readIntoBuf(0'i32)
+      if res <= 0:
+        result = res
+    
+    c = socket.buffer[socket.currPos]
+  else:
+    when defined(ssl):
+      if socket.isSSL:
+        if not socket.sslHasPeekChar:
+          result = SSLRead(socket.sslHandle, addr(socket.sslPeekChar), 1)
+          socket.sslHasPeekChar = true
+        
+        c = socket.sslPeekChar
+        return
+    result = recv(socket.fd, addr(c), 1, MSG_PEEK)
+
+proc readLine*(socket: PSocket, line: var TaintedString, timeout = -1) {.
+  tags: [FReadIO, FTime].} =
+  ## Reads a line of data from ``socket``.
+  ##
+  ## If a full line is read ``\r\L`` is not
+  ## added to ``line``, however if solely ``\r\L`` is read then ``line``
+  ## will be set to it.
+  ## 
+  ## If the socket is disconnected, ``line`` will be set to ``""``.
+  ##
+  ## An EOS exception will be raised in the case of a socket error.
+  ##
+  ## A timeout can be specified in miliseconds, if data is not received within
+  ## the specified time an ETimeout exception will be raised.
+  
+  template addNLIfEmpty(): stmt =
+    if line.len == 0:
+      line.add("\c\L")
+
+  var waited = 0.0
+
+  setLen(line.string, 0)
+  while true:
+    var c: char
+    discard waitFor(socket, waited, timeout, 1, "readLine")
+    var n = recv(socket, addr(c), 1)
+    if n < 0: socket.socketError()
+    elif n == 0: return
+    if c == '\r':
+      discard waitFor(socket, waited, timeout, 1, "readLine")
+      n = peekChar(socket, c)
+      if n > 0 and c == '\L':
+        discard recv(socket, addr(c), 1)
+      elif n <= 0: socket.socketError()
+      addNLIfEmpty()
+      return
+    elif c == '\L': 
+      addNLIfEmpty()
+      return
+    add(line.string, c)
+
+proc recvFrom*(socket: PSocket, data: var string, length: int,
+               address: var string, port: var TPort, flags = 0'i32): int {.
+               tags: [FReadIO].} =
+  ## Receives data from ``socket``. This function should normally be used with
+  ## connection-less sockets (UDP sockets).
+  ##
+  ## If an error occurs an EOS exception will be raised. Otherwise the return
+  ## value will be the length of data received.
+  ##
+  ## **Warning:** This function does not yet have a buffered implementation,
+  ## so when ``socket`` is buffered the non-buffered implementation will be
+  ## used. Therefore if ``socket`` contains something in its buffer this
+  ## function will make no effort to return it.
+  
+  # TODO: Buffered sockets
+  data.setLen(length)
+  var sockAddress: Tsockaddr_in
+  var addrLen = sizeof(sockAddress).TSocklen
+  result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint,
+                    cast[ptr TSockAddr](addr(sockAddress)), addr(addrLen))
+
+  if result != -1:
+    data.setLen(result)
+    address = $inet_ntoa(sockAddress.sin_addr)
+    port = ntohs(sockAddress.sin_port).TPort
+  else:
+    osError(osLastError())
+
+proc skip*(socket: PSocket, size: int, timeout = -1) =
+  ## Skips ``size`` amount of bytes.
+  ##
+  ## An optional timeout can be specified in miliseconds, if skipping the
+  ## bytes takes longer than specified an ETimeout exception will be raised.
+  ##
+  ## Returns the number of skipped bytes.
+  var waited = 0.0
+  var dummy = alloc(size)
+  var bytesSkipped = 0
+  while bytesSkipped != size:
+    let avail = waitFor(socket, waited, timeout, size-bytesSkipped, "skip")
+    bytesSkipped += recv(socket, dummy, avail)
+  dealloc(dummy)
+
+proc send*(socket: PSocket, data: pointer, size: int): int {.
+  tags: [FWriteIO].} =
+  ## Sends data to a socket.
+  ##
+  ## **Note**: This is a low-level version of ``send``. You likely should use 
+  ## the version below.
+  when defined(ssl):
+    if socket.isSSL:
+      return SSLWrite(socket.sslHandle, cast[cstring](data), size)
+  
+  when defined(windows) or defined(macosx):
+    result = send(socket.fd, data, size.cint, 0'i32)
+  else:
+    when defined(solaris): 
+      const MSG_NOSIGNAL = 0
+    result = send(socket.fd, data, size, int32(MSG_NOSIGNAL))
+
+proc send*(socket: PSocket, data: string) {.tags: [FWriteIO].} =
+  ## sends data to a socket.
+  let sent = send(socket, cstring(data), data.len)
+  if sent < 0:
+    socketError(socket)
+
+  if sent != data.len:
+    raise newException(EOS, "Could not send all data.")
+
+proc trySend*(socket: PSocket, data: string): bool {.tags: [FWriteIO].} =
+  ## Safe alternative to ``send``. Does not raise an EOS when an error occurs,
+  ## and instead returns ``false`` on failure.
+  result = send(socket, cstring(data), data.len) == data.len
+
+proc sendTo*(socket: PSocket, address: string, port: TPort, data: pointer,
+             size: int, af: TDomain = AF_INET, flags = 0'i32): int {.
+             tags: [FWriteIO].} =
+  ## This proc sends ``data`` to the specified ``address``,
+  ## which may be an IP address or a hostname, if a hostname is specified 
+  ## this function will try each IP of that hostname.
+  ##
+  ##
+  ## **Note:** You may wish to use the high-level version of this function
+  ## which is defined below.
+  ##
+  ## **Note:** This proc is not available for SSL sockets.
+  var aiList = getAddrInfo(address, port, af)
+  
+  # try all possibilities:
+  var success = false
+  var it = aiList
+  while it != nil:
+    result = sendto(socket.fd, data, size.cint, flags.cint, it.ai_addr,
+                    it.ai_addrlen.TSocklen)
+    if result != -1'i32:
+      success = true
+      break
+    it = it.ai_next
+
+  dealloc(aiList)
+
+proc sendTo*(socket: PSocket, address: string, port: TPort, 
+             data: string): int {.tags: [FWriteIO].} =
+  ## This proc sends ``data`` to the specified ``address``,
+  ## which may be an IP address or a hostname, if a hostname is specified 
+  ## this function will try each IP of that hostname.
+  ##
+  ## This is the high-level version of the above ``sendTo`` function.
+  result = socket.sendTo(address, port, cstring(data), data.len)
+
+proc connectAsync(socket: PSocket, name: string, port = TPort(0),
+                  af: TDomain = AF_INET) {.tags: [FReadIO].} =
+  ## A variant of ``connect`` for non-blocking sockets.
+  ##
+  ## This procedure will immediatelly return, it will not block until a connection
+  ## is made. It is up to the caller to make sure the connection has been established
+  ## by checking (using ``select``) whether the socket is writeable.
+  ##
+  ## **Note**: For SSL sockets, the ``handshake`` procedure must be called
+  ## whenever the socket successfully connects to a server.
+  var aiList = getAddrInfo(name, port, af)
+  # try all possibilities:
+  var success = false
+  var lastError: TOSErrorCode
+  var it = aiList
+  while it != nil:
+    var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.TSocklen)
+    if ret == 0'i32:
+      success = true
+      break
+    else:
+      lastError = osLastError()
+      when defined(windows):
+        # Windows EINTR doesn't behave same as POSIX.
+        if lastError.int32 == WSAEWOULDBLOCK:
+          success = true
+          break
+      else:
+        if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
+          success = true
+          break
+        
+    it = it.ai_next
+
+  dealloc(aiList)
+  if not success: osError(lastError)
+
+proc connect*(socket: PSocket, address: string, port = TPort(0), timeout: int,
+             af: TDomain = AF_INET) {.tags: [FReadIO, FWriteIO].} =
+  ## Connects to server as specified by ``address`` on port specified by ``port``.
+  ##
+  ## The ``timeout`` paremeter specifies the time in miliseconds to allow for
+  ## the connection to the server to be made.
+  socket.fd.setBlocking(false)
+  
+  socket.connectAsync(address, port, af)
+  var s = @[socket.fd]
+  if selectWrite(s, timeout) != 1:
+    raise newException(ETimeout, "Call to 'connect' timed out.")
+  else:
+    when defined(ssl):
+      if socket.isSSL:
+        socket.fd.setBlocking(true)
+        doAssert socket.handshake()
+  socket.fd.setBlocking(true)
+
+proc isSSL*(socket: PSocket): bool = return socket.isSSL
+  ## Determines whether ``socket`` is a SSL socket.
+
+proc getFD*(socket: PSocket): TSocketHandle = return socket.fd
+  ## Returns the socket's file descriptor
diff --git a/lib/pure/nimprof.nim b/lib/pure/nimprof.nim
index 02f0366cd..3d0cc2154 100644
--- a/lib/pure/nimprof.nim
+++ b/lib/pure/nimprof.nim
@@ -67,7 +67,7 @@ when withThreads:
 
 proc hookAux(st: TStackTrace, costs: int) =
   # this is quite performance sensitive!
-  when withThreads: Acquire profilingLock
+  when withThreads: acquire profilingLock
   inc totalCalls
   var last = high(st)
   while last > 0 and isNil(st[last]): dec last
@@ -106,7 +106,7 @@ proc hookAux(st: TStackTrace, costs: int) =
       h = ((5 * h) + 1) and high(profileData)
       inc chain
     maxChainLen = max(maxChainLen, chain)
-  when withThreads: Release profilingLock
+  when withThreads: release profilingLock
 
 when defined(memProfiler):
   const
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index bb70f28b6..faca17e98 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -260,11 +260,12 @@ proc osError*(errorCode: TOSErrorCode) =
   ##
   ## If the error code is ``0`` or an error message could not be retrieved,
   ## the message ``unknown OS error`` will be used.
-  let msg = osErrorMsg(errorCode)
-  if msg == "":
-    raise newException(EOS, "unknown OS error")
-  else:
-    raise newException(EOS, msg)
+  var e: ref EOS; new(e)
+  e.errorCode = errorCode.int32
+  e.msg = osErrorMsg(errorCode)
+  if e.msg == "":
+    e.msg = "unknown OS error"
+  raise e
 
 {.push stackTrace:off.}
 proc osLastError*(): TOSErrorCode =
@@ -1037,7 +1038,10 @@ proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
   ## the process has finished. To execute a program without having a
   ## shell involved, use the `execProcess` proc of the `osproc`
   ## module.
-  result = c_system(command) shr 8
+  when defined(linux):
+    result = c_system(command) shr 8
+  else:
+    result = c_system(command)
 
 # Environment handling cannot be put into RTL, because the ``envPairs``
 # iterator depends on ``environment``.
@@ -1189,7 +1193,8 @@ iterator walkFiles*(pattern: string): string {.tags: [FReadDir].} =
     res = findFirstFile(pattern, f)
     if res != -1:
       while true:
-        if not skipFindData(f):
+        if not skipFindData(f) and
+            (f.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) == 0'i32:
           yield splitFile(pattern).dir / extractFilename(getFilename(f))
         if findNextFile(res, f) == 0'i32: break
       findClose(res)
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index 6df85bbc6..5d6848565 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -13,13 +13,16 @@
 include "system/inclrtl"
 
 import
-  strutils, os, strtabs, streams, sequtils
+  strutils, os, strtabs, streams
 
 when defined(windows):
   import winlean
 else:
   import posix
 
+when defined(linux):
+  import linux
+
 type
   TProcess = object of TObject
     when defined(windows):
@@ -44,7 +47,7 @@ type
     poStdErrToStdOut,    ## merge stdout and stderr to the stdout stream
     poParentStreams      ## use the parent's streams
 
-template poUseShell*: TProcessOption {.deprecated.} = poUsePath
+const poUseShell* {.deprecated.} = poUsePath
   ## Deprecated alias for poUsePath.
 
 proc quoteShellWindows*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
@@ -165,6 +168,9 @@ proc processID*(p: PProcess): int {.rtl, extern: "nosp$1".} =
 proc waitForExit*(p: PProcess, timeout: int = -1): int {.rtl,
   extern: "nosp$1", tags: [].}
   ## waits for the process to finish and returns `p`'s error code.
+  ##
+  ## **Warning**: Be careful when using waitForExit for processes created without
+  ## poParentStreams because they may fill output buffers, causing deadlock.
 
 proc peekExitCode*(p: PProcess): int {.tags: [].}
   ## return -1 if the process is still running. Otherwise the process' exit code
@@ -590,6 +596,24 @@ elif not defined(useNimRtl):
       copyMem(result[i], addr(x[0]), x.len+1)
       inc(i)
 
+  type TStartProcessData = object
+    sysCommand: cstring
+    sysArgs: cstringArray
+    sysEnv: cstringArray
+    workingDir: cstring
+    pStdin, pStdout, pStderr, pErrorPipe: array[0..1, cint]
+    optionPoUsePath: bool
+    optionPoParentStreams: bool
+    optionPoStdErrToStdOut: bool
+
+  when not defined(useFork):
+    proc startProcessAuxSpawn(data: TStartProcessData): TPid {.tags: [FExecIO, FReadEnv].}
+  proc startProcessAuxFork(data: TStartProcessData): TPid {.tags: [FExecIO, FReadEnv].}
+  {.push stacktrace: off, profiler: off.}
+  proc startProcessAfterFork(data: ptr TStartProcessData) {.
+    tags: [FExecIO, FReadEnv], cdecl.}
+  {.pop.}
+
   proc startProcess(command: string,
                  workingDir: string = "",
                  args: openArray[string] = [],
@@ -604,23 +628,76 @@ elif not defined(useNimRtl):
          pipe(pStderr) != 0'i32:
         osError(osLastError())
 
-    var sys_command: string
-    var sys_args_raw: seq[string]
+    var sysCommand: string
+    var sysArgsRaw: seq[string]
     if poEvalCommand in options:
-      sys_command = "/bin/sh"
-      sys_args_raw = @[sys_command, "-c", command]
+      sysCommand = "/bin/sh"
+      sysArgsRaw = @[sysCommand, "-c", command]
       assert args.len == 0
     else:
-      sys_command = command
-      sys_args_raw = @[command]
+      sysCommand = command
+      sysArgsRaw = @[command]
       for arg in args.items:
-        sys_args_raw.add arg
-
-    var sys_args = allocCStringArray(sys_args_raw)
-    finally: deallocCStringArray(sys_args)
+        sysArgsRaw.add arg
 
     var pid: TPid
-    when defined(posix_spawn) and not defined(useFork):
+
+    var sysArgs = allocCStringArray(sysArgsRaw)
+    finally: deallocCStringArray(sysArgs)
+
+    var sysEnv = if env == nil:
+        envToCStringArray()
+      else:
+        envToCStringArray(env)
+
+    finally: deallocCStringArray(sysEnv)
+
+    var data: TStartProcessData
+    data.sysCommand = sysCommand
+    data.sysArgs = sysArgs
+    data.sysEnv = sysEnv
+    data.pStdin = pStdin
+    data.pStdout = pStdout
+    data.pStderr = pStderr
+    data.optionPoParentStreams = poParentStreams in options
+    data.optionPoUsePath = poUsePath in options
+    data.optionPoStdErrToStdOut = poStdErrToStdOut in options
+    data.workingDir = workingDir
+
+
+    when defined(posix_spawn) and not defined(useFork) and 
+        not defined(useClone) and not defined(linux):
+      pid = startProcessAuxSpawn(data)
+    else:
+      pid = startProcessAuxFork(data)
+
+    # Parent process. Copy process information.
+    if poEchoCmd in options:
+      echo(command, " ", join(args, " "))
+    result.id = pid
+
+    if poParentStreams in options:
+      # does not make much sense, but better than nothing:
+      result.inHandle = 0
+      result.outHandle = 1
+      if poStdErrToStdOut in options:
+        result.errHandle = result.outHandle
+      else:
+        result.errHandle = 2
+    else:
+      result.inHandle = pStdin[writeIdx]
+      result.outHandle = pStdout[readIdx]
+      if poStdErrToStdOut in options:
+        result.errHandle = result.outHandle
+        discard close(pStderr[readIdx])
+      else:
+        result.errHandle = pStderr[readIdx]
+      discard close(pStderr[writeIdx])
+      discard close(pStdin[readIdx])
+      discard close(pStdout[writeIdx])
+
+  when not defined(useFork):
+    proc startProcessAuxSpawn(data: TStartProcessData): TPid =
       var attr: Tposix_spawnattr
       var fops: Tposix_spawn_file_actions
 
@@ -639,89 +716,117 @@ elif not defined(useNimRtl):
                                           POSIX_SPAWN_SETSIGMASK or
                                           POSIX_SPAWN_SETPGROUP)
 
-      if poParentStreams notin options:
-        chck posix_spawn_file_actions_addclose(fops, pStdin[writeIdx])
-        chck posix_spawn_file_actions_adddup2(fops, pStdin[readIdx], readIdx)
-        chck posix_spawn_file_actions_addclose(fops, pStdout[readIdx])
-        chck posix_spawn_file_actions_adddup2(fops, pStdout[writeIdx], writeIdx)
-        chck posix_spawn_file_actions_addclose(fops, pStderr[readIdx])
-        if poStdErrToStdOut in options:
-          chck posix_spawn_file_actions_adddup2(fops, pStdout[writeIdx], 2)
+      if not data.optionPoParentStreams:
+        chck posix_spawn_file_actions_addclose(fops, data.pStdin[writeIdx])
+        chck posix_spawn_file_actions_adddup2(fops, data.pStdin[readIdx], readIdx)
+        chck posix_spawn_file_actions_addclose(fops, data.pStdout[readIdx])
+        chck posix_spawn_file_actions_adddup2(fops, data.pStdout[writeIdx], writeIdx)
+        chck posix_spawn_file_actions_addclose(fops, data.pStderr[readIdx])
+        if data.optionPoStdErrToStdOut:
+          chck posix_spawn_file_actions_adddup2(fops, data.pStdout[writeIdx], 2)
         else:
-          chck posix_spawn_file_actions_adddup2(fops, p_stderr[writeIdx], 2)
+          chck posix_spawn_file_actions_adddup2(fops, data.pStderr[writeIdx], 2)
 
-      var sys_env = if env == nil: envToCStringArray() else: envToCStringArray(env)
       var res: cint
-      # This is incorrect!
-      if workingDir.len > 0: os.setCurrentDir(workingDir)
-      if poUsePath in options:
-        res = posix_spawnp(pid, sys_command, fops, attr, sys_args, sys_env)
+      # FIXME: chdir is global to process
+      if data.workingDir.len > 0:
+        setCurrentDir($data.workingDir)
+      var pid: TPid
+
+      if data.optionPoUsePath:
+        res = posix_spawnp(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv)
       else:
-        res = posix_spawn(pid, sys_command, fops, attr, sys_args, sys_env)
-      deallocCStringArray(sys_env)
+        res = posix_spawn(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv)
+
       discard posix_spawn_file_actions_destroy(fops)
       discard posix_spawnattr_destroy(attr)
       chck res
+      return pid
+
+  proc startProcessAuxFork(data: TStartProcessData): TPid =
+    if pipe(data.pErrorPipe) != 0:
+      osError(osLastError())
 
+    finally:
+      discard close(data.pErrorPipe[readIdx])
+
+    var pid: TPid
+    var dataCopy = data
+
+    when defined(useClone):
+      const stackSize = 65536
+      let stackEnd = cast[clong](alloc(stackSize))
+      let stack = cast[pointer](stackEnd + stackSize)
+      let fn: pointer = startProcessAfterFork
+      pid = clone(fn, stack,
+                  cint(CLONE_VM or CLONE_VFORK or SIGCHLD),
+                  pointer(addr dataCopy), nil, nil, nil)
+      discard close(data.pErrorPipe[writeIdx])
+      dealloc(stack)
     else:
       pid = fork()
-      if pid < 0: osError(osLastError())
       if pid == 0:
-        ## child process:
-
-        if poParentStreams notin options:
-          discard close(p_stdin[writeIdx])
-          if dup2(p_stdin[readIdx], readIdx) < 0: osError(osLastError())
-          discard close(p_stdout[readIdx])
-          if dup2(p_stdout[writeIdx], writeIdx) < 0: osError(osLastError())
-          discard close(p_stderr[readIdx])
-          if poStdErrToStdOut in options:
-            if dup2(p_stdout[writeIdx], 2) < 0: osError(osLastError())
-          else:
-            if dup2(p_stderr[writeIdx], 2) < 0: osError(osLastError())
-
-        # Create a new process group
-        if setpgid(0, 0) == -1: quit("setpgid call failed: " & $strerror(errno))
-
-        if workingDir.len > 0: os.setCurrentDir(workingDir)
-
-        if env == nil:
-          if poUsePath in options:
-            discard execvp(sys_command, sys_args)
-          else:
-            discard execv(sys_command, sys_args)
-        else:
-          var c_env = envToCStringArray(env)
-          if poUsePath in options:
-            discard execvpe(sys_command, sys_args, c_env)
-          else:
-            discard execve(sys_command, sys_args, c_env)
-        # too risky to raise an exception here:
-        quit("execve call failed: " & $strerror(errno))
-    # Parent process. Copy process information.
-    if poEchoCmd in options:
-      echo(command, " ", join(args, " "))
-    result.id = pid
-
-    if poParentStreams in options:
-      # does not make much sense, but better than nothing:
-      result.inHandle = 0
-      result.outHandle = 1
-      if poStdErrToStdOut in options:
-        result.errHandle = result.outHandle
+        startProcessAfterFork(addr(dataCopy))
+        exitnow(1)
+
+    discard close(data.pErrorPipe[writeIdx])
+    if pid < 0: osError(osLastError())
+
+    var error: cint
+    let sizeRead = read(data.pErrorPipe[readIdx], addr error, sizeof(error))
+    if sizeRead == sizeof(error):
+      osError($strerror(error))
+
+    return pid
+
+  {.push stacktrace: off, profiler: off.}
+  proc startProcessFail(data: ptr TStartProcessData) =
+    var error: cint = errno
+    discard write(data.pErrorPipe[writeIdx], addr error, sizeof(error))
+    exitnow(1)
+
+  when defined(macosx):
+    var environ {.importc.}: cstringArray
+
+  proc startProcessAfterFork(data: ptr TStartProcessData) =
+    # Warning: no GC here!
+    # Or anythink that touches global structures - all called nimrod procs
+    # must be marked with noStackFrame. Inspect C code after making changes.
+    if not data.optionPoParentStreams:
+      discard close(data.pStdin[writeIdx])
+      if dup2(data.pStdin[readIdx], readIdx) < 0:
+        startProcessFail(data)
+      discard close(data.pStdout[readIdx])
+      if dup2(data.pStdout[writeIdx], writeIdx) < 0:
+        startProcessFail(data)
+      discard close(data.pStderr[readIdx])
+      if data.optionPoStdErrToStdOut:
+        if dup2(data.pStdout[writeIdx], 2) < 0:
+          startProcessFail(data)
       else:
-        result.errHandle = 2
-    else:
-      result.inHandle = pStdin[writeIdx]
-      result.outHandle = pStdout[readIdx]
-      if poStdErrToStdOut in options:
-        result.errHandle = result.outHandle
-        discard close(pStderr[readIdx])
+        if dup2(data.pStderr[writeIdx], 2) < 0:
+          startProcessFail(data)
+
+    if data.workingDir.len > 0:
+      if chdir(data.workingDir) < 0:
+        startProcessFail(data)
+
+    discard close(data.pErrorPipe[readIdx])
+    discard fcntl(data.pErrorPipe[writeIdx], F_SETFD, FD_CLOEXEC)
+
+    if data.optionPoUsePath:
+      when defined(macosx):
+        # MacOSX doesn't have execvpe, so we need workaround.
+        # On MacOSX we can arrive here only from fork, so this is safe:
+        environ = data.sysEnv
+        discard execvp(data.sysCommand, data.sysArgs)
       else:
-        result.errHandle = pStderr[readIdx]
-      discard close(pStderr[writeIdx])
-      discard close(pStdin[readIdx])
-      discard close(pStdout[writeIdx])
+        discard execvpe(data.sysCommand, data.sysArgs, data.sysEnv)
+    else:
+      discard execve(data.sysCommand, data.sysArgs, data.sysEnv)
+
+    startProcessFail(data)
+  {.pop}
 
   proc close(p: PProcess) =
     if p.inStream != nil: close(p.inStream)
@@ -791,7 +896,10 @@ elif not defined(useNimRtl):
   proc csystem(cmd: cstring): cint {.nodecl, importc: "system".}
 
   proc execCmd(command: string): int =
-    result = csystem(command) shr 8
+    when defined(linux):
+      result = csystem(command) shr 8
+    else:
+      result = csystem(command)
 
   proc createFdSet(fd: var TFdSet, s: seq[PProcess], m: var int) =
     FD_ZERO(fd)
diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim
index 3f9686e1e..bd8836f7c 100644
--- a/lib/pure/parsesql.nim
+++ b/lib/pure/parsesql.nim
@@ -267,7 +267,7 @@ proc getSymbol(c: var TSqlLexer, tok: var TToken) =
   while true: 
     add(tok.literal, buf[pos])
     Inc(pos)
-    if not (buf[pos] in {'a'..'z','A'..'Z','0'..'9','_','$', '\128'..'\255'}):
+    if buf[pos] notin {'a'..'z','A'..'Z','0'..'9','_','$', '\128'..'\255'}:
       break
   c.bufpos = pos
   tok.kind = tkIdentifier
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index 70b617393..68b1ab223 100644
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -836,9 +836,11 @@ iterator findAll*(s: string, pattern: TPeg, start = 0): string =
   while i < s.len:
     c.ml = 0
     var L = rawMatch(s, pattern, i, c)
-    if L < 0: break
-    yield substr(s, i, i+L-1)
-    inc(i, L)
+    if L < 0:
+      inc(i, 1)
+    else:
+      yield substr(s, i, i+L-1)
+      inc(i, L)
     
 proc findAll*(s: string, pattern: TPeg, start = 0): seq[string] {.
   nosideEffect, rtl, extern: "npegs$1".} = 
diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim
new file mode 100644
index 000000000..aeaa7f3b5
--- /dev/null
+++ b/lib/pure/rawsockets.nim
@@ -0,0 +1,421 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2014 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a low-level cross-platform sockets interface. Look
+## at the ``net`` module for the higher-level version.
+
+# TODO: Clean up the exports a bit and everything else in general.
+
+import unsigned, os
+
+when hostos == "solaris":
+  {.passl: "-lsocket -lnsl".}
+
+when defined(Windows):
+  import winlean
+  export WSAEWOULDBLOCK
+else:
+  import posix
+  export fcntl, F_GETFL, O_NONBLOCK, F_SETFL, EAGAIN, EWOULDBLOCK, MSG_NOSIGNAL,
+    EINTR, EINPROGRESS
+
+export TSocketHandle, TSockaddr_in, TAddrinfo, INADDR_ANY, TSockAddr, TSockLen,
+  inet_ntoa, recv, `==`, connect, send, accept, recvfrom, sendto
+
+export
+  SO_ERROR,
+  SOL_SOCKET,
+  SOMAXCONN,
+  SO_ACCEPTCONN, SO_BROADCAST, SO_DEBUG, SO_DONTROUTE,
+  SO_KEEPALIVE, SO_OOBINLINE, SO_REUSEADDR,
+  MSG_PEEK
+
+type
+  
+  TPort* = distinct uint16  ## port type
+  
+  TDomain* = enum   ## domain, which specifies the protocol family of the
+                    ## created socket. Other domains than those that are listed
+                    ## here are unsupported.
+    AF_UNIX,        ## for local socket (using a file). Unsupported on Windows.
+    AF_INET = 2,    ## for network protocol IPv4 or
+    AF_INET6 = 23   ## for network protocol IPv6.
+
+  TType* = enum        ## second argument to `socket` proc
+    SOCK_STREAM = 1,   ## reliable stream-oriented service or Stream Sockets
+    SOCK_DGRAM = 2,    ## datagram service or Datagram Sockets
+    SOCK_RAW = 3,      ## raw protocols atop the network layer.
+    SOCK_SEQPACKET = 5 ## reliable sequenced packet service
+
+  TProtocol* = enum     ## third argument to `socket` proc
+    IPPROTO_TCP = 6,    ## Transmission control protocol. 
+    IPPROTO_UDP = 17,   ## User datagram protocol.
+    IPPROTO_IP,         ## Internet protocol. Unsupported on Windows.
+    IPPROTO_IPV6,       ## Internet Protocol Version 6. Unsupported on Windows.
+    IPPROTO_RAW,        ## Raw IP Packets Protocol. Unsupported on Windows.
+    IPPROTO_ICMP        ## Control message protocol. Unsupported on Windows.
+
+  TServent* {.pure, final.} = object ## information about a service
+    name*: string
+    aliases*: seq[string]
+    port*: TPort
+    proto*: string
+
+  Thostent* {.pure, final.} = object ## information about a given host
+    name*: string
+    aliases*: seq[string]
+    addrtype*: TDomain
+    length*: int
+    addrList*: seq[string]
+
+when defined(windows):
+  let
+    osInvalidSocket* = winlean.INVALID_SOCKET
+
+  const
+    IOCPARM_MASK* = 127
+    IOC_IN* = int(-2147483648)
+    FIONBIO* = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or 
+                             (102 shl 8) or 126
+
+  proc ioctlsocket*(s: TSocketHandle, cmd: clong, 
+                   argptr: ptr clong): cint {.
+                   stdcall, importc: "ioctlsocket", dynlib: "ws2_32.dll".}
+else:
+  let
+    osInvalidSocket* = posix.INVALID_SOCKET
+
+proc `==`*(a, b: TPort): bool {.borrow.}
+  ## ``==`` for ports.
+
+proc `$`*(p: TPort): string {.borrow.}
+  ## returns the port number as a string
+
+proc toInt*(domain: TDomain): cint
+  ## Converts the TDomain enum to a platform-dependent ``cint``.
+
+proc toInt*(typ: TType): cint
+  ## Converts the TType enum to a platform-dependent ``cint``.
+
+proc toInt*(p: TProtocol): cint
+  ## Converts the TProtocol enum to a platform-dependent ``cint``.
+
+when defined(posix):
+  proc toInt(domain: TDomain): cint =
+    case domain
+    of AF_UNIX:        result = posix.AF_UNIX
+    of AF_INET:        result = posix.AF_INET
+    of AF_INET6:       result = posix.AF_INET6
+    else: discard
+
+  proc toInt(typ: TType): cint =
+    case typ
+    of SOCK_STREAM:    result = posix.SOCK_STREAM
+    of SOCK_DGRAM:     result = posix.SOCK_DGRAM
+    of SOCK_SEQPACKET: result = posix.SOCK_SEQPACKET
+    of SOCK_RAW:       result = posix.SOCK_RAW
+    else: discard
+
+  proc toInt(p: TProtocol): cint =
+    case p
+    of IPPROTO_TCP:    result = posix.IPPROTO_TCP
+    of IPPROTO_UDP:    result = posix.IPPROTO_UDP
+    of IPPROTO_IP:     result = posix.IPPROTO_IP
+    of IPPROTO_IPV6:   result = posix.IPPROTO_IPV6
+    of IPPROTO_RAW:    result = posix.IPPROTO_RAW
+    of IPPROTO_ICMP:   result = posix.IPPROTO_ICMP
+    else: discard
+
+else:
+  proc toInt(domain: TDomain): cint = 
+    result = toU16(ord(domain))
+
+  proc toInt(typ: TType): cint =
+    result = cint(ord(typ))
+  
+  proc toInt(p: TProtocol): cint =
+    result = cint(ord(p))
+
+
+proc newRawSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
+             protocol: TProtocol = IPPROTO_TCP): TSocketHandle =
+  ## Creates a new socket; returns `InvalidSocket` if an error occurs.
+  socket(toInt(domain), toInt(typ), toInt(protocol))
+
+proc close*(socket: TSocketHandle) =
+  ## closes a socket.
+  when defined(windows):
+    discard winlean.closeSocket(socket)
+  else:
+    discard posix.close(socket)
+  # TODO: These values should not be discarded. An EOS should be raised.
+  # http://stackoverflow.com/questions/12463473/what-happens-if-you-call-close-on-a-bsd-socket-multiple-times
+
+proc bindAddr*(socket: TSocketHandle, name: ptr TSockAddr, namelen: TSockLen): cint =
+  result = bindSocket(socket, name, namelen)
+
+proc listen*(socket: TSocketHandle, backlog = SOMAXCONN): cint {.tags: [FReadIO].} =
+  ## Marks ``socket`` as accepting connections. 
+  ## ``Backlog`` specifies the maximum length of the 
+  ## queue of pending connections.
+  when defined(windows):
+    result = winlean.listen(socket, cint(backlog))
+  else:
+    result = posix.listen(socket, cint(backlog))
+
+proc getAddrInfo*(address: string, port: TPort, af: TDomain = AF_INET, typ: TType = SOCK_STREAM,
+                 prot: TProtocol = IPPROTO_TCP): ptr TAddrInfo =
+  ##
+  ##
+  ## **Warning**: The resulting ``ptr TAddrInfo`` must be freed using ``dealloc``!
+  var hints: TAddrInfo
+  result = nil
+  hints.ai_family = toInt(af)
+  hints.ai_socktype = toInt(typ)
+  hints.ai_protocol = toInt(prot)
+  var gaiResult = getAddrInfo(address, $port, addr(hints), result)
+  if gaiResult != 0'i32:
+    when defined(windows):
+      OSError(OSLastError())
+    else:
+      raise newException(EOS, $gai_strerror(gaiResult))
+
+proc dealloc*(ai: ptr TAddrInfo) =
+  freeaddrinfo(ai)
+
+proc ntohl*(x: int32): int32 = 
+  ## Converts 32-bit integers from network to host byte order.
+  ## On machines where the host byte order is the same as network byte order,
+  ## this is a no-op; otherwise, it performs a 4-byte swap operation.
+  when cpuEndian == bigEndian: result = x
+  else: result = (x shr 24'i32) or
+                 (x shr 8'i32 and 0xff00'i32) or
+                 (x shl 8'i32 and 0xff0000'i32) or
+                 (x shl 24'i32)
+
+proc ntohs*(x: int16): int16 =
+  ## Converts 16-bit integers from network to host byte order. On machines
+  ## where the host byte order is the same as network byte order, this is
+  ## a no-op; otherwise, it performs a 2-byte swap operation.
+  when cpuEndian == bigEndian: result = x
+  else: result = (x shr 8'i16) or (x shl 8'i16)
+
+proc htonl*(x: int32): int32 =
+  ## Converts 32-bit integers from host to network byte order. On machines
+  ## where the host byte order is the same as network byte order, this is
+  ## a no-op; otherwise, it performs a 4-byte swap operation.
+  result = rawsockets.ntohl(x)
+
+proc htons*(x: int16): int16 =
+  ## Converts 16-bit positive integers from host to network byte order.
+  ## On machines where the host byte order is the same as network byte
+  ## order, this is a no-op; otherwise, it performs a 2-byte swap operation.
+  result = rawsockets.ntohs(x)
+
+proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} =
+  ## Searches the database from the beginning and finds the first entry for 
+  ## which the service name specified by ``name`` matches the s_name member
+  ## and the protocol name specified by ``proto`` matches the s_proto member.
+  ##
+  ## On posix this will search through the ``/etc/services`` file.
+  when defined(Windows):
+    var s = winlean.getservbyname(name, proto)
+  else:
+    var s = posix.getservbyname(name, proto)
+  if s == nil: raise newException(EOS, "Service not found.")
+  result.name = $s.s_name
+  result.aliases = cstringArrayToSeq(s.s_aliases)
+  result.port = TPort(s.s_port)
+  result.proto = $s.s_proto
+  
+proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} = 
+  ## Searches the database from the beginning and finds the first entry for 
+  ## which the port specified by ``port`` matches the s_port member and the 
+  ## protocol name specified by ``proto`` matches the s_proto member.
+  ##
+  ## On posix this will search through the ``/etc/services`` file.
+  when defined(Windows):
+    var s = winlean.getservbyport(ze(int16(port)).cint, proto)
+  else:
+    var s = posix.getservbyport(ze(int16(port)).cint, proto)
+  if s == nil: raise newException(EOS, "Service not found.")
+  result.name = $s.s_name
+  result.aliases = cstringArrayToSeq(s.s_aliases)
+  result.port = TPort(s.s_port)
+  result.proto = $s.s_proto
+
+proc getHostByAddr*(ip: string): Thostent {.tags: [FReadIO].} =
+  ## This function will lookup the hostname of an IP Address.
+  var myaddr: TInAddr
+  myaddr.s_addr = inet_addr(ip)
+  
+  when defined(windows):
+    var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
+                                  cint(rawsockets.AF_INET))
+    if s == nil: osError(osLastError())
+  else:
+    var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).TSocklen, 
+                                cint(posix.AF_INET))
+    if s == nil:
+      raise newException(EOS, $hstrerror(h_errno))
+  
+  result.name = $s.h_name
+  result.aliases = cstringArrayToSeq(s.h_aliases)
+  when defined(windows): 
+    result.addrtype = TDomain(s.h_addrtype)
+  else:
+    if s.h_addrtype == posix.AF_INET:
+      result.addrtype = AF_INET
+    elif s.h_addrtype == posix.AF_INET6:
+      result.addrtype = AF_INET6
+    else:
+      raise newException(EOS, "unknown h_addrtype")
+  result.addrList = cstringArrayToSeq(s.h_addr_list)
+  result.length = int(s.h_length)
+
+proc getHostByName*(name: string): Thostent {.tags: [FReadIO].} = 
+  ## This function will lookup the IP address of a hostname.
+  when defined(Windows):
+    var s = winlean.gethostbyname(name)
+  else:
+    var s = posix.gethostbyname(name)
+  if s == nil: osError(osLastError())
+  result.name = $s.h_name
+  result.aliases = cstringArrayToSeq(s.h_aliases)
+  when defined(windows): 
+    result.addrtype = TDomain(s.h_addrtype)
+  else:
+    if s.h_addrtype == posix.AF_INET:
+      result.addrtype = AF_INET
+    elif s.h_addrtype == posix.AF_INET6:
+      result.addrtype = AF_INET6
+    else:
+      raise newException(EOS, "unknown h_addrtype")
+  result.addrList = cstringArrayToSeq(s.h_addr_list)
+  result.length = int(s.h_length)
+
+proc getSockName*(socket: TSocketHandle): TPort = 
+  ## returns the socket's associated port number.
+  var name: Tsockaddr_in
+  when defined(Windows):
+    name.sin_family = int16(ord(AF_INET))
+  else:
+    name.sin_family = posix.AF_INET
+  #name.sin_port = htons(cint16(port))
+  #name.sin_addr.s_addr = htonl(INADDR_ANY)
+  var namelen = sizeof(name).TSocklen
+  if getsockname(socket, cast[ptr TSockAddr](addr(name)),
+                 addr(namelen)) == -1'i32:
+    osError(osLastError())
+  result = TPort(rawsockets.ntohs(name.sin_port))
+
+proc getSockOptInt*(socket: TSocketHandle, level, optname: int): int {.
+  tags: [FReadIO].} = 
+  ## getsockopt for integer options.
+  var res: cint
+  var size = sizeof(res).TSocklen
+  if getsockopt(socket, cint(level), cint(optname), 
+                addr(res), addr(size)) < 0'i32:
+    osError(osLastError())
+  result = int(res)
+
+proc setSockOptInt*(socket: TSocketHandle, level, optname, optval: int) {.
+  tags: [FWriteIO].} =
+  ## setsockopt for integer options.
+  var value = cint(optval)
+  if setsockopt(socket, cint(level), cint(optname), addr(value),  
+                sizeof(value).TSocklen) < 0'i32:
+    osError(osLastError())
+
+proc setBlocking*(s: TSocketHandle, blocking: bool) =
+  ## Sets blocking mode on socket.
+  ##
+  ## Raises EOS on error.
+  when defined(Windows):
+    var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
+    if ioctlsocket(s, FIONBIO, addr(mode)) == -1:
+      osError(osLastError())
+  else: # BSD sockets
+    var x: int = fcntl(s, F_GETFL, 0)
+    if x == -1:
+      osError(osLastError())
+    else:
+      var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK
+      if fcntl(s, F_SETFL, mode) == -1:
+        osError(osLastError())
+
+proc timeValFromMilliseconds(timeout = 500): Ttimeval =
+  if timeout != -1:
+    var seconds = timeout div 1000
+    result.tv_sec = seconds.int32
+    result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
+
+proc createFdSet(fd: var TFdSet, s: seq[TSocketHandle], m: var int) = 
+  FD_ZERO(fd)
+  for i in items(s): 
+    m = max(m, int(i))
+    FD_SET(i, fd)
+   
+proc pruneSocketSet(s: var seq[TSocketHandle], fd: var TFdSet) = 
+  var i = 0
+  var L = s.len
+  while i < L:
+    if FD_ISSET(s[i], fd) == 0'i32:
+      s[i] = s[L-1]
+      dec(L)
+    else:
+      inc(i)
+  setLen(s, L)
+
+proc select*(readfds: var seq[TSocketHandle], timeout = 500): int =
+  ## Traditional select function. This function will return the number of
+  ## sockets that are ready to be read from, written to, or which have errors.
+  ## If there are none; 0 is returned. 
+  ## ``Timeout`` is in miliseconds and -1 can be specified for no timeout.
+  ## 
+  ## A socket is removed from the specific ``seq`` when it has data waiting to
+  ## be read/written to or has errors (``exceptfds``).
+  var tv {.noInit.}: Ttimeval = timeValFromMilliseconds(timeout)
+  
+  var rd: TFdSet
+  var m = 0
+  createFdSet((rd), readfds, m)
+  
+  if timeout != -1:
+    result = int(select(cint(m+1), addr(rd), nil, nil, addr(tv)))
+  else:
+    result = int(select(cint(m+1), addr(rd), nil, nil, nil))
+  
+  pruneSocketSet(readfds, (rd))
+
+proc selectWrite*(writefds: var seq[TSocketHandle], 
+                  timeout = 500): int {.tags: [FReadIO].} =
+  ## When a socket in ``writefds`` is ready to be written to then a non-zero
+  ## value will be returned specifying the count of the sockets which can be
+  ## written to. The sockets which can be written to will also be removed
+  ## from ``writefds``.
+  ##
+  ## ``timeout`` is specified in miliseconds and ``-1`` can be specified for
+  ## an unlimited time.
+  var tv {.noInit.}: Ttimeval = timeValFromMilliseconds(timeout)
+  
+  var wr: TFdSet
+  var m = 0
+  createFdSet((wr), writefds, m)
+  
+  if timeout != -1:
+    result = int(select(cint(m+1), nil, addr(wr), nil, addr(tv)))
+  else:
+    result = int(select(cint(m+1), nil, addr(wr), nil, nil))
+  
+  pruneSocketSet(writefds, (wr))
+
+when defined(Windows):
+  var wsa: TWSADATA
+  if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError())
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
index 83c158da1..085344e3e 100644
--- a/lib/pure/selectors.nim
+++ b/lib/pure/selectors.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2013 Dominik Picheta
+#        (c) Copyright 2014 Dominik Picheta
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -9,212 +9,230 @@
 
 # TODO: Docs.
 
-import tables, os, unsigned
-when defined(windows):
-  import winlean
-else:
-  import posix
+import tables, os, unsigned, hashes
+
+when defined(linux): import posix, epoll
+elif defined(windows): import winlean
+
+proc hash*(x: TSocketHandle): THash {.borrow.}
+proc `$`*(x: TSocketHandle): string {.borrow.}
 
 type
   TEvent* = enum
     EvRead, EvWrite
 
-  TSelectorKey* = object
-    fd: cint
-    events: set[TEvent]
-    data: PObject
-
-  TReadyInfo* = tuple[key: TSelectorKey, events: set[TEvent]]
-
-  PSelector* = ref object of PObject ## Selector interface.
-    fds*: TTable[cint, TSelectorKey]
-    registerImpl*: proc (s: PSelector, fd: cint, events: set[TEvent],
-                    data: PObject): TSelectorKey {.nimcall, tags: [FWriteIO].}
-    unregisterImpl*: proc (s: PSelector, fd: cint): TSelectorKey {.nimcall, tags: [FWriteIO].}
-    selectImpl*: proc (s: PSelector, timeout: int): seq[TReadyInfo] {.nimcall, tags: [FReadIO].}
-    closeImpl*: proc (s: PSelector) {.nimcall.}
-
-template initSelector(r: expr) =
-  new r
-  r.fds = initTable[cint, TSelectorKey]()
-
-proc register*(s: PSelector, fd: cint, events: set[TEvent], data: PObject):
-    TSelectorKey =
-  if not s.registerImpl.isNil: result = s.registerImpl(s, fd, events, data)
+  PSelectorKey* = ref object
+    fd*: TSocketHandle
+    events*: set[TEvent] ## The events which ``fd`` listens for.
+    data*: PObject ## User object.
 
-proc unregister*(s: PSelector, fd: cint): TSelectorKey =
-  ##
-  ## **Note:** For the ``epoll`` implementation the resulting ``TSelectorKey``
-  ## will only have the ``fd`` field set. This is an optimisation and may
-  ## change in the future if a viable use case is presented. 
-  if not s.unregisterImpl.isNil: result = s.unregisterImpl(s, fd)
+  TReadyInfo* = tuple[key: PSelectorKey, events: set[TEvent]]
 
-proc select*(s: PSelector, timeout = 500): seq[TReadyInfo] =
-  ##
-  ## The ``events`` field of the returned ``key`` contains the original events
-  ## for which the ``fd`` was bound. This is contrary to the ``events`` field
-  ## of the ``TReadyInfo`` tuple which determines which events are ready
-  ## on the ``fd``.
-
-  if not s.selectImpl.isNil: result = s.selectImpl(s, timeout)
-
-proc close*(s: PSelector) =
-  if not s.closeImpl.isNil: s.closeImpl(s)
-
-# ---- Select() ----------------------------------------------------------------
-
-type
-  PSelectSelector* = ref object of PSelector ## Implementation of select()
-
-proc ssRegister(s: PSelector, fd: cint, events: set[TEvent],
-    data: PObject): TSelectorKey =
-  if s.fds.hasKey(fd):
-    raise newException(EInvalidValue, "FD already exists in selector.")
-  var sk = TSelectorKey(fd: fd, events: events, data: data)
-  s.fds[fd] = sk
-  result = sk
-
-proc ssUnregister(s: PSelector, fd: cint): TSelectorKey =
-  result = s.fds[fd]
-  s.fds.del(fd)
-
-proc ssClose(s: PSelector) = nil
-
-proc timeValFromMilliseconds(timeout: int): TTimeVal =
-  if timeout != -1:
-    var seconds = timeout div 1000
-    result.tv_sec = seconds.int32
-    result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
-
-proc createFdSet(rd, wr: var TFdSet, fds: TTable[cint, TSelectorKey],
-    m: var int) =
-  FD_ZERO(rd); FD_ZERO(wr)
-  for k, v in pairs(fds):
-    if EvRead in v.events: 
-      m = max(m, int(k))
-      FD_SET(k, rd)
-    if EvWrite in v.events:
-      m = max(m, int(k))
-      FD_SET(k, wr)
-   
-proc getReadyFDs(rd, wr: var TFdSet, fds: TTable[cint, TSelectorKey]):
-    seq[TReadyInfo] =
-  result = @[]
-  for k, v in pairs(fds):
-    var events: set[TEvent] = {}
-    if FD_ISSET(k, rd) != 0'i32:
-      events = events + {EvRead}
-    if FD_ISSET(k, wr) != 0'i32:
-      events = events + {EvWrite}
-    result.add((v, events))
-
-proc select(fds: TTable[cint, TSelectorKey], timeout = 500):
-  seq[TReadyInfo] =
-  var tv {.noInit.}: TTimeVal = timeValFromMilliseconds(timeout)
-  
-  var rd, wr: TFdSet
-  var m = 0
-  createFdSet(rd, wr, fds, m)
-  
-  var retCode = 0
-  if timeout != -1:
-    retCode = int(select(cint(m+1), addr(rd), addr(wr), nil, addr(tv)))
-  else:
-    retCode = int(select(cint(m+1), addr(rd), addr(wr), nil, nil))
-  
-  if retCode < 0:
-    OSError(OSLastError())
-  elif retCode == 0:
-    return @[]
-  else:
-    return getReadyFDs(rd, wr, fds)
-
-proc ssSelect(s: PSelector, timeout: int): seq[TReadyInfo] =
-  result = select(s.fds, timeout)
-
-proc newSelectSelector*(): PSelectSelector =
-  initSelector(result)
-  result.registerImpl = ssRegister
-  result.unregisterImpl = ssUnregister
-  result.selectImpl = ssSelect
-  result.closeImpl = ssClose
-
-# ---- Epoll -------------------------------------------------------------------
-
-when defined(linux):
-  import epoll
+when defined(linux) or defined(nimdoc):
   type
-    PEpollSelector* = ref object of PSelector
+    PSelector* = ref object
       epollFD: cint
-      events: array[64, ptr epoll_event]
-  
-    TDataWrapper = object
-      fd: cint
-      boundEvents: set[TEvent] ## The events which ``fd`` listens for.
-      data: PObject ## User object.
+      events: array[64, epoll_event]
+      fds: TTable[TSocketHandle, PSelectorKey]
   
-  proc esRegister(s: PSelector, fd: cint, events: set[TEvent],
-      data: PObject): TSelectorKey =
-    var es = PEpollSelector(s)
-    var event: epoll_event
+  proc createEventStruct(events: set[TEvent], fd: TSocketHandle): epoll_event =
     if EvRead in events:
-      event.events = EPOLLIN
+      result.events = EPOLLIN
     if EvWrite in events:
-      event.events = event.events or EPOLLOUT
-    
-    var dw = cast[ptr TDataWrapper](alloc0(sizeof(TDataWrapper))) # TODO: This needs to be dealloc'd
-    dw.fd = fd
-    dw.boundEvents = events
-    dw.data = data
-    event.data.thePtr = dw
-    
-    if epoll_ctl(es.epollFD, EPOLL_CTL_ADD, fd, addr(event)) != 0:
-      OSError(OSLastError())
-    
-    result = TSelectorKey(fd: fd, events: events, data: data)
+      result.events = result.events or EPOLLOUT
+    result.events = result.events or EPOLLRDHUP
+    result.data.fd = fd.cint
   
-  proc esUnregister(s: PSelector, fd: cint): TSelectorKey =
-    # We cannot find out the information about this ``fd`` from the epoll
-    # context. As such I will simply return an almost empty TSelectorKey.
-    var es = PEpollSelector(s)
-    if epoll_ctl(es.epollFD, EPOLL_CTL_DEL, fd, nil) != 0:
+  proc register*(s: PSelector, fd: TSocketHandle, events: set[TEvent],
+      data: PObject): PSelectorKey {.discardable.} =
+    ## Registers file descriptor ``fd`` to selector ``s`` with a set of TEvent
+    ## ``events``.
+    var event = createEventStruct(events, fd)
+    if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fd, addr(event)) != 0:
       OSError(OSLastError())
-    # We could fill in the ``fds`` TTable to get the info, but that wouldn't
-    # be nice for our memory.
-    result = TSelectorKey(fd: fd, events: {}, data: nil)
+  
+    var key = PSelectorKey(fd: fd, events: events, data: data)
+  
+    s.fds[fd] = key
+    result = key
+  
+  proc update*(s: PSelector, fd: TSocketHandle,
+      events: set[TEvent]): PSelectorKey {.discardable.} =
+    ## Updates the events which ``fd`` wants notifications for.
+    if s.fds[fd].events != events:
+      var event = createEventStruct(events, fd)
+      
+      s.fds[fd].events = events
+      if epoll_ctl(s.epollFD, EPOLL_CTL_MOD, fd, addr(event)) != 0:
+        OSError(OSLastError())
+      result = s.fds[fd]
+  
+  proc unregister*(s: PSelector, fd: TSocketHandle): PSelectorKey {.discardable.} =
+    if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fd, nil) != 0:
+      let err = OSLastError()
+      if err.cint notin {ENOENT, EBADF}: # TODO: Why do we sometimes get an EBADF? Is this normal?
+        OSError(err)
+    result = s.fds[fd]
+    s.fds.del(fd)
 
-  proc esClose(s: PSelector) =
-    var es = PEpollSelector(s)
-    if es.epollFD.close() != 0: OSError(OSLastError())
-    dealloc(addr es.events) # TODO: Test this
+  proc close*(s: PSelector) =
+    if s.epollFD.close() != 0: OSError(OSLastError())
+    dealloc(addr s.events) # TODO: Test this
+  
+  proc epollHasFd(s: PSelector, fd: TSocketHandle): bool =
+    result = true
+    var event = createEventStruct(s.fds[fd].events, fd)
+    if epoll_ctl(s.epollFD, EPOLL_CTL_MOD, fd, addr(event)) != 0:
+      let err = osLastError()
+      if err.cint in {ENOENT, EBADF}:
+        return false
+      OSError(OSLastError())
   
-  proc esSelect(s: PSelector, timeout: int): seq[TReadyInfo] =
+  proc select*(s: PSelector, timeout: int): seq[TReadyInfo] =
+    ##
+    ## The ``events`` field of the returned ``key`` contains the original events
+    ## for which the ``fd`` was bound. This is contrary to the ``events`` field
+    ## of the ``TReadyInfo`` tuple which determines which events are ready
+    ## on the ``fd``.
     result = @[]
-    var es = PEpollSelector(s)
-    
-    let evNum = epoll_wait(es.epollFD, es.events[0], 64.cint, timeout.cint)
+    let evNum = epoll_wait(s.epollFD, addr s.events[0], 64.cint, timeout.cint)
     if evNum < 0: OSError(OSLastError())
     if evNum == 0: return @[]
     for i in 0 .. <evNum:
+      let fd = s.events[i].data.fd.TSocketHandle
+    
       var evSet: set[TEvent] = {}
-      if (es.events[i].events and EPOLLIN) != 0: evSet = evSet + {EvRead}
-      if (es.events[i].events and EPOLLOUT) != 0: evSet = evSet + {EvWrite}
-      let dw = cast[ptr TDataWrapper](es.events[i].data.thePtr)
-      
-      let selectorKey = TSelectorKey(fd: dw.fd, events: dw.boundEvents, 
-          data: dw.data)
+      if (s.events[i].events and EPOLLIN) != 0: evSet = evSet + {EvRead}
+      if (s.events[i].events and EPOLLOUT) != 0: evSet = evSet + {EvWrite}
+      let selectorKey = s.fds[fd]
+      assert selectorKey != nil
       result.add((selectorKey, evSet))
+
+      #echo("Epoll: ", result[i].key.fd, " ", result[i].events, " ", result[i].key.events)
   
-  proc newEpollSelector*(): PEpollSelector =
+  proc newSelector*(): PSelector =
     new result
     result.epollFD = epoll_create(64)
-    result.events = cast[array[64, ptr epoll_event]](alloc0(sizeof(epoll_event)*64))
+    result.events = cast[array[64, epoll_event]](alloc0(sizeof(epoll_event)*64))
+    result.fds = initTable[TSocketHandle, PSelectorKey]()
     if result.epollFD < 0:
       OSError(OSLastError())
-    result.registerImpl = esRegister
-    result.unregisterImpl = esUnregister
-    result.closeImpl = esClose
-    result.selectImpl = esSelect
+
+  proc contains*(s: PSelector, fd: TSocketHandle): bool =
+    ## Determines whether selector contains a file descriptor.
+    if s.fds.hasKey(fd):
+      # Ensure the underlying epoll instance still contains this fd.
+      result = epollHasFd(s, fd)
+    else:
+      return false
+
+  proc contains*(s: PSelector, key: PSelectorKey): bool =
+    ## Determines whether selector contains this selector key. More accurate
+    ## than checking if the file descriptor is in the selector because it
+    ## ensures that the keys are equal. File descriptors may not always be
+    ## unique especially when an fd is closed and then a new one is opened,
+    ## the new one may have the same value.
+    return key.fd in s and s.fds[key.fd] == key
+
+  proc `[]`*(s: PSelector, fd: TSocketHandle): PSelectorKey =
+    ## Retrieves the selector key for ``fd``.
+    return s.fds[fd]
+
+elif defined(windows):
+  type
+    PSelector* = ref object
+      fds: TTable[TSocketHandle, PSelectorKey]
+
+  proc register*(s: PSelector, fd: TSocketHandle, events: set[TEvent],
+      data: PObject): PSelectorKey {.discardable.} =
+    if s.fds.hasKey(fd):
+      raise newException(EInvalidValue, "File descriptor already exists.")
+    var sk = PSelectorKey(fd: fd, events: events, data: data)
+    s.fds[fd] = sk
+    result = sk
+
+  proc update*(s: PSelector, fd: TSocketHandle,
+      events: set[TEvent]): PSelectorKey {.discardable.} =
+    ## Updates the events which ``fd`` wants notifications for.
+    if not s.fds.hasKey(fd):
+      raise newException(EInvalidValue, "File descriptor not found.")
+
+    s.fds[fd].events = events
+    result = s.fds[fd]
+
+  proc unregister*(s: PSelector, fd: TSocketHandle): PSelectorKey {.discardable.} =
+    result = s.fds[fd]
+    s.fds.del(fd)
+
+  proc close*(s: PSelector) = nil
+
+  proc timeValFromMilliseconds(timeout: int): TTimeVal =
+    if timeout != -1:
+      var seconds = timeout div 1000
+      result.tv_sec = seconds.int32
+      result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
+
+  proc createFdSet(rd, wr: var TFdSet, fds: TTable[TSocketHandle, PSelectorKey],
+      m: var int) =
+    FD_ZERO(rd); FD_ZERO(wr)
+    for k, v in pairs(fds):
+      if EvRead in v.events: 
+        m = max(m, int(k))
+        FD_SET(k, rd)
+      if EvWrite in v.events:
+        m = max(m, int(k))
+        FD_SET(k, wr)
+     
+  proc getReadyFDs(rd, wr: var TFdSet, fds: TTable[TSocketHandle, PSelectorKey]):
+      seq[TReadyInfo] =
+    result = @[]
+    for k, v in pairs(fds):
+      var events: set[TEvent] = {}
+      if FD_ISSET(k, rd) != 0'i32:
+        events = events + {EvRead}
+      if FD_ISSET(k, wr) != 0'i32:
+        events = events + {EvWrite}
+      result.add((v, events))
+
+  proc select(fds: TTable[TSocketHandle, PSelectorKey], timeout = 500):
+    seq[TReadyInfo] =
+    var tv {.noInit.}: TTimeVal = timeValFromMilliseconds(timeout)
+    
+    var rd, wr: TFdSet
+    var m = 0
+    createFdSet(rd, wr, fds, m)
+    
+    var retCode = 0
+    if timeout != -1:
+      retCode = int(select(TSocketHandle(m+1), addr(rd), addr(wr), nil, addr(tv)))
+    else:
+      retCode = int(select(TSocketHandle(m+1), addr(rd), addr(wr), nil, nil))
+    
+    if retCode < 0:
+      OSError(OSLastError())
+    elif retCode == 0:
+      return @[]
+    else:
+      return getReadyFDs(rd, wr, fds)
+
+  proc select*(s: PSelector, timeout: int): seq[TReadyInfo] =
+    result = select(s.fds, timeout)
+
+  proc newSelector*(): PSelector =
+    new result
+    result.fds = initTable[TSocketHandle, PSelectorKey]()
+
+  proc contains*(s: PSelector, fd: TSocketHandle): bool =
+    return s.fds.hasKey(fd)
+
+  proc `[]`*(s: PSelector, fd: TSocketHandle): PSelectorKey =
+    return s.fds[fd]
+
+elif defined(bsd) or defined(macosx):
+  # TODO: kqueue
+  {.error: "Sorry your platform is not supported yet.".}
+else:
+  {.error: "Sorry your platform is not supported.".}
 
 when isMainModule:
   # Select()
@@ -224,11 +242,12 @@ when isMainModule:
       sock: TSocket
   
   var sock = socket()
+  sock.setBlocking(false)
   sock.connect("irc.freenode.net", TPort(6667))
   
-  var selector = newEpollSelector()
+  var selector = newSelector()
   var data = PSockWrapper(sock: sock)
-  let key = selector.register(sock.getFD.cint, {EvRead}, data)
+  let key = selector.register(sock.getFD, {EvWrite}, data)
   var i = 0
   while true:
     let ready = selector.select(1000)
@@ -236,6 +255,7 @@ when isMainModule:
     if ready.len > 0: echo ready[0].events
     i.inc
     if i == 6:
+      assert selector.unregister(sock.getFD).fd == sock.getFD
       selector.close()
       break
   
@@ -246,4 +266,4 @@ when isMainModule:
   
   
   
-  
\ No newline at end of file
+  
diff --git a/lib/pure/sockets2.nim b/lib/pure/sockets2.nim
deleted file mode 100644
index 22624bbad..000000000
--- a/lib/pure/sockets2.nim
+++ /dev/null
@@ -1,202 +0,0 @@
-#
-#
-#            Nimrod's Runtime Library
-#        (c) Copyright 2014 Dominik Picheta
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## This module implements a low-level cross-platform sockets interface. Look
-## at the ``net`` module for the higher-level version.
-
-import unsigned, os
-
-when hostos == "solaris":
-  {.passl: "-lsocket -lnsl".}
-
-when defined(Windows):
-  import winlean
-else:
-  import posix
-
-export TSocketHandle, TSockaddr_in, TAddrinfo, INADDR_ANY, TSockAddr, TSockLen,
-  inet_ntoa
-
-type
-  
-  TPort* = distinct uint16  ## port type
-  
-  TDomain* = enum   ## domain, which specifies the protocol family of the
-                    ## created socket. Other domains than those that are listed
-                    ## here are unsupported.
-    AF_UNIX,        ## for local socket (using a file). Unsupported on Windows.
-    AF_INET = 2,    ## for network protocol IPv4 or
-    AF_INET6 = 23   ## for network protocol IPv6.
-
-  TType* = enum        ## second argument to `socket` proc
-    SOCK_STREAM = 1,   ## reliable stream-oriented service or Stream Sockets
-    SOCK_DGRAM = 2,    ## datagram service or Datagram Sockets
-    SOCK_RAW = 3,      ## raw protocols atop the network layer.
-    SOCK_SEQPACKET = 5 ## reliable sequenced packet service
-
-  TProtocol* = enum     ## third argument to `socket` proc
-    IPPROTO_TCP = 6,    ## Transmission control protocol. 
-    IPPROTO_UDP = 17,   ## User datagram protocol.
-    IPPROTO_IP,         ## Internet protocol. Unsupported on Windows.
-    IPPROTO_IPV6,       ## Internet Protocol Version 6. Unsupported on Windows.
-    IPPROTO_RAW,        ## Raw IP Packets Protocol. Unsupported on Windows.
-    IPPROTO_ICMP        ## Control message protocol. Unsupported on Windows.
-
-  TServent* {.pure, final.} = object ## information about a service
-    name*: string
-    aliases*: seq[string]
-    port*: TPort
-    proto*: string
-
-  Thostent* {.pure, final.} = object ## information about a given host
-    name*: string
-    aliases*: seq[string]
-    addrtype*: TDomain
-    length*: int
-    addrList*: seq[string]
-
-when defined(windows):
-  let
-    OSInvalidSocket* = winlean.INVALID_SOCKET
-else:
-  let
-    OSInvalidSocket* = posix.INVALID_SOCKET
-
-proc `==`*(a, b: TPort): bool {.borrow.}
-  ## ``==`` for ports.
-
-proc `$`*(p: TPort): string {.borrow.}
-  ## returns the port number as a string
-
-proc toInt*(domain: TDomain): cint
-  ## Converts the TDomain enum to a platform-dependent ``cint``.
-
-proc toInt*(typ: TType): cint
-  ## Converts the TType enum to a platform-dependent ``cint``.
-
-proc toInt*(p: TProtocol): cint
-  ## Converts the TProtocol enum to a platform-dependent ``cint``.
-
-when defined(posix):
-  proc toInt(domain: TDomain): cint =
-    case domain
-    of AF_UNIX:        result = posix.AF_UNIX
-    of AF_INET:        result = posix.AF_INET
-    of AF_INET6:       result = posix.AF_INET6
-    else: nil
-
-  proc toInt(typ: TType): cint =
-    case typ
-    of SOCK_STREAM:    result = posix.SOCK_STREAM
-    of SOCK_DGRAM:     result = posix.SOCK_DGRAM
-    of SOCK_SEQPACKET: result = posix.SOCK_SEQPACKET
-    of SOCK_RAW:       result = posix.SOCK_RAW
-    else: nil
-
-  proc toInt(p: TProtocol): cint =
-    case p
-    of IPPROTO_TCP:    result = posix.IPPROTO_TCP
-    of IPPROTO_UDP:    result = posix.IPPROTO_UDP
-    of IPPROTO_IP:     result = posix.IPPROTO_IP
-    of IPPROTO_IPV6:   result = posix.IPPROTO_IPV6
-    of IPPROTO_RAW:    result = posix.IPPROTO_RAW
-    of IPPROTO_ICMP:   result = posix.IPPROTO_ICMP
-    else: nil
-
-else:
-  proc toInt(domain: TDomain): cint = 
-    result = toU16(ord(domain))
-
-  proc toInt(typ: TType): cint =
-    result = cint(ord(typ))
-  
-  proc toInt(p: TProtocol): cint =
-    result = cint(ord(p))
-
-
-proc socket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
-             protocol: TProtocol = IPPROTO_TCP): TSocketHandle =
-  ## Creates a new socket; returns `InvalidSocket` if an error occurs.
-  
-  # TODO: The function which will use this will raise EOS.
-  socket(toInt(domain), toInt(typ), toInt(protocol))
-
-proc close*(socket: TSocketHandle) =
-  ## closes a socket.
-  when defined(windows):
-    discard winlean.closeSocket(socket)
-  else:
-    discard posix.close(socket)
-  # TODO: These values should not be discarded. An EOS should be raised.
-  # http://stackoverflow.com/questions/12463473/what-happens-if-you-call-close-on-a-bsd-socket-multiple-times
-
-proc bindAddr*(socket: TSocketHandle, name: ptr TSockAddr, namelen: TSockLen): cint =
-  result = bindSocket(socket, name, namelen)
-
-proc listen*(socket: TSocketHandle, backlog = SOMAXCONN) {.tags: [FReadIO].} =
-  ## Marks ``socket`` as accepting connections. 
-  ## ``Backlog`` specifies the maximum length of the 
-  ## queue of pending connections.
-  when defined(windows):
-    if winlean.listen(socket, cint(backlog)) < 0'i32: osError(osLastError())
-  else:
-    if posix.listen(socket, cint(backlog)) < 0'i32: osError(osLastError())
-
-proc getAddrInfo*(address: string, port: TPort, af: TDomain = AF_INET, typ: TType = SOCK_STREAM,
-                 prot: TProtocol = IPPROTO_TCP): ptr TAddrInfo =
-  ##
-  ##
-  ## **Warning**: The resulting ``ptr TAddrInfo`` must be freed using ``dealloc``!
-  var hints: TAddrInfo
-  result = nil
-  hints.ai_family = toInt(af)
-  hints.ai_socktype = toInt(typ)
-  hints.ai_protocol = toInt(prot)
-  var gaiResult = getAddrInfo(address, $port, addr(hints), result)
-  if gaiResult != 0'i32:
-    when defined(windows):
-      OSError(OSLastError())
-    else:
-      raise newException(EOS, $gai_strerror(gaiResult))
-
-proc dealloc*(ai: ptr TAddrInfo) =
-  freeaddrinfo(ai)
-
-proc ntohl*(x: int32): int32 = 
-  ## Converts 32-bit integers from network to host byte order.
-  ## On machines where the host byte order is the same as network byte order,
-  ## this is a no-op; otherwise, it performs a 4-byte swap operation.
-  when cpuEndian == bigEndian: result = x
-  else: result = (x shr 24'i32) or
-                 (x shr 8'i32 and 0xff00'i32) or
-                 (x shl 8'i32 and 0xff0000'i32) or
-                 (x shl 24'i32)
-
-proc ntohs*(x: int16): int16 =
-  ## Converts 16-bit integers from network to host byte order. On machines
-  ## where the host byte order is the same as network byte order, this is
-  ## a no-op; otherwise, it performs a 2-byte swap operation.
-  when cpuEndian == bigEndian: result = x
-  else: result = (x shr 8'i16) or (x shl 8'i16)
-
-proc htonl*(x: int32): int32 =
-  ## Converts 32-bit integers from host to network byte order. On machines
-  ## where the host byte order is the same as network byte order, this is
-  ## a no-op; otherwise, it performs a 4-byte swap operation.
-  result = sockets2.ntohl(x)
-
-proc htons*(x: int16): int16 =
-  ## Converts 16-bit positive integers from host to network byte order.
-  ## On machines where the host byte order is the same as network byte
-  ## order, this is a no-op; otherwise, it performs a 2-byte swap operation.
-  result = sockets2.ntohs(x)
-
-when defined(Windows):
-  var wsa: TWSADATA
-  if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError())
\ No newline at end of file
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index de6c4e4fa..2fce235e2 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -557,6 +557,119 @@ proc `$`*(m: TMonth): string =
       "November", "December"]
   return lookup[m]
 
+proc format_token(info: TTimeInfo, token: string, buf: var string) =
+  ## Helper of the format proc to parse individual tokens.
+  ##
+  ## Pass the found token in the user input string, and the buffer where the
+  ## final string is being built. This has to be a var value because certain
+  ## formatting tokens require modifying the previous characters.
+  case token
+  of "d":
+    buf.add($info.monthday)
+  of "dd":
+    if info.monthday < 10:
+      buf.add("0")
+    buf.add($info.monthday)
+  of "ddd":
+    buf.add(($info.weekday)[0 .. 2])
+  of "dddd":
+    buf.add($info.weekday)
+  of "h":
+    buf.add($(if info.hour > 12: info.hour - 12 else: info.hour))
+  of "hh":
+    let amerHour = if info.hour > 12: info.hour - 12 else: info.hour
+    if amerHour < 10:
+      buf.add('0')
+    buf.add($amerHour)
+  of "H":
+    buf.add($info.hour)
+  of "HH":
+    if info.hour < 10:
+      buf.add('0')
+    buf.add($info.hour)
+  of "m":
+    buf.add($info.minute)
+  of "mm":
+    if info.minute < 10:
+      buf.add('0')
+    buf.add($info.minute)
+  of "M":
+    buf.add($(int(info.month)+1))
+  of "MM":
+    if info.month < mOct:
+      buf.add('0')
+    buf.add($(int(info.month)+1))
+  of "MMM":
+    buf.add(($info.month)[0..2])
+  of "MMMM":
+    buf.add($info.month)
+  of "s":
+    buf.add($info.second)
+  of "ss":
+    if info.second < 10:
+      buf.add('0')
+    buf.add($info.second)
+  of "t":
+    if info.hour >= 12:
+      buf.add('P')
+    else: buf.add('A')
+  of "tt":
+    if info.hour >= 12:
+      buf.add("PM")
+    else: buf.add("AM")
+  of "y":
+    var fr = ($info.year).len()-1
+    if fr < 0: fr = 0
+    buf.add(($info.year)[fr .. ($info.year).len()-1])
+  of "yy":
+    var fr = ($info.year).len()-2
+    if fr < 0: fr = 0
+    var fyear = ($info.year)[fr .. ($info.year).len()-1]
+    if fyear.len != 2: fyear = repeatChar(2-fyear.len(), '0') & fyear
+    buf.add(fyear)
+  of "yyy":
+    var fr = ($info.year).len()-3
+    if fr < 0: fr = 0
+    var fyear = ($info.year)[fr .. ($info.year).len()-1]
+    if fyear.len != 3: fyear = repeatChar(3-fyear.len(), '0') & fyear
+    buf.add(fyear)
+  of "yyyy":
+    var fr = ($info.year).len()-4
+    if fr < 0: fr = 0
+    var fyear = ($info.year)[fr .. ($info.year).len()-1]
+    if fyear.len != 4: fyear = repeatChar(4-fyear.len(), '0') & fyear
+    buf.add(fyear)
+  of "yyyyy":
+    var fr = ($info.year).len()-5
+    if fr < 0: fr = 0
+    var fyear = ($info.year)[fr .. ($info.year).len()-1]
+    if fyear.len != 5: fyear = repeatChar(5-fyear.len(), '0') & fyear
+    buf.add(fyear)
+  of "z":
+    let hrs = (info.timezone div 60) div 60
+    buf.add($hrs)
+  of "zz":
+    let hrs = (info.timezone div 60) div 60
+
+    buf.add($hrs)
+    if hrs.abs < 10:
+      var atIndex = buf.len-(($hrs).len-(if hrs < 0: 1 else: 0))
+      buf.insert("0", atIndex)
+  of "zzz":
+    let hrs = (info.timezone div 60) div 60
+
+    buf.add($hrs & ":00")
+    if hrs.abs < 10:
+      var atIndex = buf.len-(($hrs & ":00").len-(if hrs < 0: 1 else: 0))
+      buf.insert("0", atIndex)
+  of "ZZZ":
+    buf.add(info.tzname)
+  of "":
+    discard
+  else:
+    raise newException(EInvalidValue, "Invalid format string: " & token)
+
+
 proc format*(info: TTimeInfo, f: string): string =
   ## This function formats `info` as specified by `f`. The following format
   ## specifiers are available:
@@ -591,8 +704,11 @@ proc format*(info: TTimeInfo, f: string): string =
   ##    ZZZ      Displays the name of the timezone.                                                 ``GMT -> GMT``, ``EST -> EST``
   ## ==========  =================================================================================  ================================================
   ##
-  ## Other strings can be inserted by putting them in ``''``. For example ``hh'->'mm`` will give ``01->56``.
-  ## The following characters can be inserted without quoting them: ``:`` ``-`` ``(`` ``)`` ``/`` ``[`` ``]`` ``,``
+  ## Other strings can be inserted by putting them in ``''``. For example
+  ## ``hh'->'mm`` will give ``01->56``.  The following characters can be
+  ## inserted without quoting them: ``:`` ``-`` ``(`` ``)`` ``/`` ``[`` ``]``
+  ## ``,``. However you don't need to necessarily separate format specifiers, a
+  ## unambiguous format string like ``yyyyMMddhhmmss`` is valid too.
 
   result = ""
   var i = 0
@@ -600,112 +716,8 @@ proc format*(info: TTimeInfo, f: string): string =
   while true:
     case f[i]
     of ' ', '-', '/', ':', '\'', '\0', '(', ')', '[', ']', ',':
-      case currentF
-      of "d":
-        result.add($info.monthday)
-      of "dd":
-        if info.monthday < 10:
-          result.add("0")
-        result.add($info.monthday)
-      of "ddd":
-        result.add(($info.weekday)[0 .. 2])
-      of "dddd":
-        result.add($info.weekday)
-      of "h":
-        result.add($(if info.hour > 12: info.hour - 12 else: info.hour))
-      of "hh":
-        let amerHour = if info.hour > 12: info.hour - 12 else: info.hour
-        if amerHour < 10:
-          result.add('0')
-        result.add($amerHour)
-      of "H":
-        result.add($info.hour)
-      of "HH":
-        if info.hour < 10:
-          result.add('0')
-        result.add($info.hour)
-      of "m":
-        result.add($info.minute)
-      of "mm":
-        if info.minute < 10:
-          result.add('0')
-        result.add($info.minute)
-      of "M":
-        result.add($(int(info.month)+1))
-      of "MM":
-        if info.month < mOct:
-          result.add('0')
-        result.add($(int(info.month)+1))
-      of "MMM":
-        result.add(($info.month)[0..2])
-      of "MMMM":
-        result.add($info.month)
-      of "s":
-        result.add($info.second)
-      of "ss":
-        if info.second < 10:
-          result.add('0')
-        result.add($info.second)
-      of "t":
-        if info.hour >= 12:
-          result.add('P')
-        else: result.add('A')
-      of "tt":
-        if info.hour >= 12:
-          result.add("PM")
-        else: result.add("AM")
-      of "y":
-        var fr = ($info.year).len()-1
-        if fr < 0: fr = 0
-        result.add(($info.year)[fr .. ($info.year).len()-1])
-      of "yy":
-        var fr = ($info.year).len()-2
-        if fr < 0: fr = 0
-        var fyear = ($info.year)[fr .. ($info.year).len()-1]
-        if fyear.len != 2: fyear = repeatChar(2-fyear.len(), '0') & fyear
-        result.add(fyear)
-      of "yyy":
-        var fr = ($info.year).len()-3
-        if fr < 0: fr = 0
-        var fyear = ($info.year)[fr .. ($info.year).len()-1]
-        if fyear.len != 3: fyear = repeatChar(3-fyear.len(), '0') & fyear
-        result.add(fyear)
-      of "yyyy":
-        var fr = ($info.year).len()-4
-        if fr < 0: fr = 0
-        var fyear = ($info.year)[fr .. ($info.year).len()-1]
-        if fyear.len != 4: fyear = repeatChar(4-fyear.len(), '0') & fyear
-        result.add(fyear)
-      of "yyyyy":
-        var fr = ($info.year).len()-5
-        if fr < 0: fr = 0
-        var fyear = ($info.year)[fr .. ($info.year).len()-1]
-        if fyear.len != 5: fyear = repeatChar(5-fyear.len(), '0') & fyear
-        result.add(fyear)
-      of "z":
-        let hrs = (info.timezone div 60) div 60
-        result.add($hrs)
-      of "zz":
-        let hrs = (info.timezone div 60) div 60
-        
-        result.add($hrs)
-        if hrs.abs < 10:
-          var atIndex = result.len-(($hrs).len-(if hrs < 0: 1 else: 0))
-          result.insert("0", atIndex)
-      of "zzz":
-        let hrs = (info.timezone div 60) div 60
-        
-        result.add($hrs & ":00")
-        if hrs.abs < 10:
-          var atIndex = result.len-(($hrs & ":00").len-(if hrs < 0: 1 else: 0))
-          result.insert("0", atIndex)
-      of "ZZZ":
-        result.add(info.tzname)
-      of "":
-        discard
-      else:
-        raise newException(EInvalidValue, "Invalid format string: " & currentF)
-      
+      format_token(info, currentF, result)
+
       currentF = ""
       if f[i] == '\0': break
       
@@ -716,7 +728,15 @@ proc format*(info: TTimeInfo, f: string): string =
           inc(i)
       else: result.add(f[i])
       
-    else: currentF.add(f[i])
+    else:
+      # Check if the letter being added matches previous accumulated buffer.
+      if currentF.len < 1 or currentF[high(currentF)] == f[i]:
+        currentF.add(f[i])
+      else:
+        format_token(info, currentF, result)
+        dec(i) # Move position back to re-process the character separately.
+        currentF = ""
+
     inc(i)
 
 {.pop.}
@@ -727,11 +747,15 @@ when isMainModule:
 
   var t = getGMTime(fromSeconds(2147483647))
   echo t.format("ddd dd MMM hh:mm:ss ZZZ yyyy")
+  echo t.format("ddd ddMMMhhmmssZZZyyyy")
   assert t.format("ddd dd MMM hh:mm:ss ZZZ yyyy") == "Tue 19 Jan 03:14:07 UTC 2038"
+  assert t.format("ddd ddMMMhh:mm:ssZZZyyyy") == "Tue 19Jan03:14:07UTC2038"
   
   assert t.format("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" &
     " ss t tt y yy yyy yyyy yyyyy z zz zzz ZZZ") == 
     "19 19 Tue Tuesday 3 03 3 03 14 14 1 01 Jan January 7 07 A AM 8 38 038 2038 02038 0 00 00:00 UTC"
+
+  assert t.format("yyyyMMddhhmmss") == "20380119031407"
   
   var t2 = getGMTime(fromSeconds(160070789)) # Mon 27 Jan 16:06:29 GMT 1975
   assert t2.format("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" &
diff --git a/lib/stdlib.babel b/lib/stdlib.babel
new file mode 100644
index 000000000..f22598aba
--- /dev/null
+++ b/lib/stdlib.babel
@@ -0,0 +1,6 @@
+[Package]
+name          = "stdlib"
+version       = "0.9.0"
+author        = "Dominik Picheta"
+description   = "Nimrod's standard library."
+license       = "MIT"
diff --git a/lib/system.nim b/lib/system.nim
index fde24a9d0..38839387d 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -185,6 +185,8 @@ proc `..`*[T](b: T): TSlice[T] {.noSideEffect, inline.} =
 
 when not defined(niminheritable):
   {.pragma: inheritable.}
+when not defined(nimunion):
+  {.pragma: unchecked.}
 
 const NoFakeVars* = defined(NimrodVM) ## true if the backend doesn't support \
   ## "fake variables" like 'var EBADF {.importc.}: cint'.
@@ -194,9 +196,10 @@ when not defined(JS):
     TGenericSeq {.compilerproc, pure, inheritable.} = object
       len, reserved: int
     PGenericSeq {.exportc.} = ptr TGenericSeq
+    UncheckedCharArray {.unchecked.} = array[0..100_000_000, char]
     # len and space without counting the terminating zero:
     NimStringDesc {.compilerproc, final.} = object of TGenericSeq
-      data: array[0..100_000_000, char]
+      data: UncheckedCharArray
     NimString = ptr NimStringDesc
 
 when not defined(JS) and not defined(NimrodVM):
@@ -257,6 +260,7 @@ type
                               ## system raises.
   EIO* = object of ESystem    ## raised if an IO error occured.
   EOS* = object of ESystem    ## raised if an operating system service failed.
+    errorCode*: int32 ## OS-defined error code describing this error.
   EInvalidLibrary* = object of EOS ## raised if a dynamic library
                                    ## could not be loaded.
   EResourceExhausted* = object of ESystem ## raised if a resource request
@@ -1161,6 +1165,14 @@ when not defined(nimrodVM):
       ## from it before writing to it is undefined behaviour!
       ## The allocated memory belongs to its allocating thread!
       ## Use `allocShared` to allocate from a shared heap.
+    proc createU*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
+      ## allocates a new memory block with at least ``T.sizeof * size``
+      ## bytes. The block has to be freed with ``resize(block, 0)`` or
+      ## ``free(block)``. The block is not initialized, so reading
+      ## from it before writing to it is undefined behaviour!
+      ## The allocated memory belongs to its allocating thread!
+      ## Use `createSharedU` to allocate from a shared heap.
+      cast[ptr T](alloc(T.sizeof * size))
     proc alloc0*(size: int): pointer {.noconv, rtl, tags: [].}
       ## allocates a new memory block with at least ``size`` bytes. The
       ## block has to be freed with ``realloc(block, 0)`` or
@@ -1168,14 +1180,31 @@ when not defined(nimrodVM):
       ## containing zero, so it is somewhat safer than ``alloc``.
       ## The allocated memory belongs to its allocating thread!
       ## Use `allocShared0` to allocate from a shared heap.
-    proc realloc*(p: pointer, newsize: int): pointer {.noconv, rtl, tags: [].}
+    proc create*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
+      ## allocates a new memory block with at least ``T.sizeof * size``
+      ## bytes. The block has to be freed with ``resize(block, 0)`` or
+      ## ``free(block)``. The block is initialized with all bytes
+      ## containing zero, so it is somewhat safer than ``createU``.
+      ## The allocated memory belongs to its allocating thread!
+      ## Use `createShared` to allocate from a shared heap.
+      cast[ptr T](alloc0(T.sizeof * size))
+    proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [].}
       ## grows or shrinks a given memory block. If p is **nil** then a new
       ## memory block is returned. In either way the block has at least
-      ## ``newsize`` bytes. If ``newsize == 0`` and p is not **nil**
+      ## ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
       ## ``realloc`` calls ``dealloc(p)``. In other cases the block has to
       ## be freed with ``dealloc``.
       ## The allocated memory belongs to its allocating thread!
       ## Use `reallocShared` to reallocate from a shared heap.
+    proc resize*[T](p: ptr T, newSize: Natural): ptr T {.inline.} =
+      ## grows or shrinks a given memory block. If p is **nil** then a new
+      ## memory block is returned. In either way the block has at least
+      ## ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is not
+      ## **nil** ``resize`` calls ``free(p)``. In other cases the block
+      ## has to be freed with ``free``. The allocated memory belongs to
+      ## its allocating thread!
+      ## Use `resizeShared` to reallocate from a shared heap.
+      cast[ptr T](realloc(p, T.sizeof * newSize))
     proc dealloc*(p: pointer) {.noconv, rtl, tags: [].}
       ## frees the memory allocated with ``alloc``, ``alloc0`` or
       ## ``realloc``. This procedure is dangerous! If one forgets to
@@ -1184,31 +1213,60 @@ when not defined(nimrodVM):
       ## or other memory may be corrupted. 
       ## The freed memory must belong to its allocating thread!
       ## Use `deallocShared` to deallocate from a shared heap.
-
+    proc free*[T](p: ptr T) {.inline.} =
+      dealloc(p)
     proc allocShared*(size: int): pointer {.noconv, rtl.}
       ## allocates a new memory block on the shared heap with at
       ## least ``size`` bytes. The block has to be freed with
       ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
       ## is not initialized, so reading from it before writing to it is 
       ## undefined behaviour!
+    proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
+      ## allocates a new memory block on the shared heap with at
+      ## least ``T.sizeof * size`` bytes. The block has to be freed with
+      ## ``resizeShared(block, 0)`` or ``freeShared(block)``. The block
+      ## is not initialized, so reading from it before writing to it is 
+      ## undefined behaviour!
+      cast[ptr T](allocShared(T.sizeof * size))
     proc allocShared0*(size: int): pointer {.noconv, rtl.}
       ## allocates a new memory block on the shared heap with at 
       ## least ``size`` bytes. The block has to be freed with
       ## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
       ## The block is initialized with all bytes
       ## containing zero, so it is somewhat safer than ``allocShared``.
-    proc reallocShared*(p: pointer, newsize: int): pointer {.noconv, rtl.}
+    proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
+      ## allocates a new memory block on the shared heap with at 
+      ## least ``T.sizeof * size`` bytes. The block has to be freed with
+      ## ``resizeShared(block, 0)`` or ``freeShared(block)``.
+      ## The block is initialized with all bytes
+      ## containing zero, so it is somewhat safer than ``createSharedU``.
+      cast[ptr T](allocShared0(T.sizeof * size))
+    proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl.}
       ## grows or shrinks a given memory block on the heap. If p is **nil**
-      ## then a new memory block is returned. In either way the block has at least
-      ## ``newsize`` bytes. If ``newsize == 0`` and p is not **nil**
+      ## then a new memory block is returned. In either way the block has at
+      ## least ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
       ## ``reallocShared`` calls ``deallocShared(p)``. In other cases the
       ## block has to be freed with ``deallocShared``.
+    proc resizeShared*[T](p: ptr T, newSize: Natural): ptr T {.inline.} =
+      ## grows or shrinks a given memory block on the heap. If p is **nil**
+      ## then a new memory block is returned. In either way the block has at
+      ## least ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is
+      ## not **nil** ``resizeShared`` calls ``freeShared(p)``. In other
+      ## cases the block has to be freed with ``freeShared``.
+      cast[ptr T](reallocShared(p, T.sizeof * newSize))
     proc deallocShared*(p: pointer) {.noconv, rtl.}
       ## frees the memory allocated with ``allocShared``, ``allocShared0`` or
       ## ``reallocShared``. This procedure is dangerous! If one forgets to
       ## free the memory a leak occurs; if one tries to access freed
       ## memory (or just freeing it twice!) a core dump may happen
       ## or other memory may be corrupted.
+    proc freeShared*[T](p: ptr T) {.inline.} =
+      ## frees the memory allocated with ``createShared``, ``createSharedU`` or
+      ## ``resizeShared``. This procedure is dangerous! If one forgets to
+      ## free the memory a leak occurs; if one tries to access freed
+      ## memory (or just freeing it twice!) a core dump may happen
+      ## or other memory may be corrupted.
+      deallocShared(p)
 
 proc swap*[T](a, b: var T) {.magic: "Swap", noSideEffect.}
   ## swaps the values `a` and `b`. This is often more efficient than
@@ -1399,20 +1457,6 @@ iterator items*[IX, T](a: array[IX, T]): T {.inline.} =
       if i >= high(IX): break
       inc(i)
 
-iterator items*[T](a: seq[T]): T {.inline.} =
-  ## iterates over each item of `a`.
-  var i = 0
-  while i < len(a):
-    yield a[i]
-    inc(i)
-
-iterator items*(a: string): char {.inline.} =
-  ## iterates over each item of `a`.
-  var i = 0
-  while i < len(a):
-    yield a[i]
-    inc(i)
-
 iterator items*[T](a: set[T]): T {.inline.} =
   ## iterates over each element of `a`. `items` iterates only over the
   ## elements that are really in the set (and not over the ones the set is
@@ -1514,7 +1558,7 @@ when not defined(NimrodVM):
     proc seqToPtr[T](x: seq[T]): pointer {.inline, nosideeffect.} =
       result = cast[pointer](x)
   else:
-    proc seqToPtr[T](x: seq[T]): pointer {.noStackFrame, nosideeffect.} =
+    proc seqToPtr[T](x: seq[T]): pointer {.asmNoStackFrame, nosideeffect.} =
       asm """return `x`"""
   
   proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} =
@@ -1802,7 +1846,7 @@ type
     len*: int           ## length of the inspectable slots
 
 when defined(JS):
-  proc add*(x: var string, y: cstring) {.noStackFrame.} =
+  proc add*(x: var string, y: cstring) {.asmNoStackFrame.} =
     asm """
       var len = `x`[0].length-1;
       for (var i = 0; i < `y`.length; ++i) {
@@ -2019,8 +2063,10 @@ when not defined(JS): #and not defined(NimrodVM):
       ## Flushes `f`'s buffer.
 
     proc readAll*(file: TFile): TaintedString {.tags: [FReadIO].}
-      ## Reads all data from the stream `file`. Raises an IO exception
-      ## in case of an error
+      ## Reads all data from the stream `file`.
+      ##
+      ## Raises an IO exception in case of an error. It is an error if the
+      ## current file position is not at the beginning of the file.
     
     proc readFile*(filename: string): TaintedString {.tags: [FReadIO].}
       ## Opens a file named `filename` for reading. Then calls `readAll`
@@ -2309,12 +2355,32 @@ when not defined(JS): #and not defined(NimrodVM):
 
   when not defined(NimrodVM):
     proc likely*(val: bool): bool {.importc: "likely", nodecl, nosideeffect.}
-      ## can be used to mark a condition to be likely. This is a hint for the 
-      ## optimizer.
+      ## Hints the optimizer that `val` is likely going to be true.
+      ##
+      ## You can use this proc to decorate a branch condition. On certain
+      ## platforms this can help the processor predict better which branch is
+      ## going to be run. Example:
+      ##
+      ## .. code-block:: nimrod
+      ##   for value in inputValues:
+      ##     if likely(value <= 100):
+      ##       process(value)
+      ##     else:
+      ##       echo "Value too big!"
     
     proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.}
-      ## can be used to mark a condition to be unlikely. This is a hint for the 
-      ## optimizer.
+      ## Hints the optimizer that `val` is likely going to be false.
+      ##
+      ## You can use this proc to decorate a branch condition. On certain
+      ## platforms this can help the processor predict better which branch is
+      ## going to be run. Example:
+      ##
+      ## .. code-block:: nimrod
+      ##   for value in inputValues:
+      ##     if unlikely(value > 100):
+      ##       echo "Value too big!"
+      ##     else:
+      ##       process(value)
       
     proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} =
       ## retrieves the raw proc pointer of the closure `x`. This is
@@ -2612,6 +2678,24 @@ template doAssert*(cond: bool, msg = "") =
     if not cond:
       raiseAssert(astToStr(cond) & ' ' & msg)
 
+iterator items*[T](a: seq[T]): T {.inline.} =
+  ## iterates over each item of `a`.
+  var i = 0
+  let L = len(a)
+  while i < L:
+    yield a[i]
+    inc(i)
+    assert(len(a) == L, "seq modified while iterating over it")
+
+iterator items*(a: string): char {.inline.} =
+  ## iterates over each item of `a`.
+  var i = 0
+  let L = len(a)
+  while i < L:
+    yield a[i]
+    inc(i)
+    assert(len(a) == L, "string modified while iterating over it")
+
 when not defined(nimhygiene):
   {.pragma: inject.}
 
diff --git a/lib/system/arithm.nim b/lib/system/arithm.nim
index d764a6672..d9b3aebac 100644
--- a/lib/system/arithm.nim
+++ b/lib/system/arithm.nim
@@ -111,7 +111,7 @@ const
 when asmVersion and not defined(gcc) and not defined(llvm_gcc):
   # assembler optimized versions for compilers that
   # have an intel syntax assembler:
-  proc addInt(a, b: int): int {.compilerProc, noStackFrame.} =
+  proc addInt(a, b: int): int {.compilerProc, asmNoStackFrame.} =
     # a in eax, and b in edx
     asm """
         mov eax, `a`
@@ -121,7 +121,7 @@ when asmVersion and not defined(gcc) and not defined(llvm_gcc):
       theEnd:
     """
 
-  proc subInt(a, b: int): int {.compilerProc, noStackFrame.} =
+  proc subInt(a, b: int): int {.compilerProc, asmNoStackFrame.} =
     asm """
         mov eax, `a`
         sub eax, `b`
@@ -130,7 +130,7 @@ when asmVersion and not defined(gcc) and not defined(llvm_gcc):
       theEnd:
     """
 
-  proc negInt(a: int): int {.compilerProc, noStackFrame.} =
+  proc negInt(a: int): int {.compilerProc, asmNoStackFrame.} =
     asm """
         mov eax, `a`
         neg eax
@@ -139,7 +139,7 @@ when asmVersion and not defined(gcc) and not defined(llvm_gcc):
       theEnd:
     """
 
-  proc divInt(a, b: int): int {.compilerProc, noStackFrame.} =
+  proc divInt(a, b: int): int {.compilerProc, asmNoStackFrame.} =
     asm """
         mov eax, `a`
         mov ecx, `b`
@@ -150,7 +150,7 @@ when asmVersion and not defined(gcc) and not defined(llvm_gcc):
       theEnd:
     """
 
-  proc modInt(a, b: int): int {.compilerProc, noStackFrame.} =
+  proc modInt(a, b: int): int {.compilerProc, asmNoStackFrame.} =
     asm """
         mov eax, `a`
         mov ecx, `b`
@@ -162,7 +162,7 @@ when asmVersion and not defined(gcc) and not defined(llvm_gcc):
         mov eax, edx
     """
 
-  proc mulInt(a, b: int): int {.compilerProc, noStackFrame.} =
+  proc mulInt(a, b: int): int {.compilerProc, asmNoStackFrame.} =
     asm """
         mov eax, `a`
         mov ecx, `b`
diff --git a/lib/system/endb.nim b/lib/system/endb.nim
index 2d6a25824..74d3c37ac 100644
--- a/lib/system/endb.nim
+++ b/lib/system/endb.nim
@@ -179,7 +179,7 @@ proc scanAndAppendWord(src: cstring, a: var TStaticStr, start: int): int =
   while True:
     case src[result]
     of 'a'..'z', '0'..'9': add(a, src[result])
-    of '_': nil # just skip it
+    of '_': discard # just skip it
     of 'A'..'Z': add(a, chr(ord(src[result]) - ord('A') + ord('a')))
     else: break
     inc(result)
@@ -203,7 +203,7 @@ proc scanNumber(src: cstring, a: var int, start: int): int =
   while true:
     case src[result]
     of '0'..'9': a = a * 10 + ord(src[result]) - ord('0')
-    of '_': nil # skip underscores (nice for long line numbers)
+    of '_': discard # skip underscores (nice for long line numbers)
     else: break
     inc(result)
 
@@ -524,7 +524,7 @@ proc lineHookImpl() {.nimcall.} =
   of dbBreakpoints:
     # debugger is only interested in breakpoints
     checkForBreakpoint()
-  else: nil
+  else: discard
 
 proc watchpointHookImpl(name: cstring) {.nimcall.} =
   dbgWriteStackTrace(framePtr)
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index 4fc5f479b..1720804c4 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -23,9 +23,9 @@ type
   PCallFrame = ptr TCallFrame
   TCallFrame {.importc, nodecl, final.} = object
     prev: PCallFrame
-    procname: CString
+    procname: cstring
     line: int # current line number
-    filename: CString
+    filename: cstring
 
 var
   framePtr {.importc, nodecl, volatile.}: PCallFrame
@@ -48,7 +48,7 @@ proc getCurrentExceptionMsg*(): string =
 
 proc auxWriteStackTrace(f: PCallFrame): string =
   type
-    TTempFrame = tuple[procname: CString, line: int]
+    TTempFrame = tuple[procname: cstring, line: int]
   var
     it = f
     i = 0
@@ -84,7 +84,7 @@ proc rawWriteStackTrace(): string =
     framePtr = nil
 
 proc raiseException(e: ref E_Base, ename: cstring) {.
-    compilerproc, noStackFrame.} =
+    compilerproc, asmNoStackFrame.} =
   e.name = ename
   if excHandler != nil:
     excHandler.exc = e
@@ -104,7 +104,7 @@ proc raiseException(e: ref E_Base, ename: cstring) {.
     alert(buf)
   asm """throw `e`;"""
 
-proc reraiseException() {.compilerproc, noStackFrame.} =
+proc reraiseException() {.compilerproc, asmNoStackFrame.} =
   if excHandler == nil:
     raise newException(ENoExceptionToReraise, "no exception to reraise")
   else:
@@ -125,7 +125,7 @@ proc raiseIndexError() {.compilerproc, noreturn.} =
 proc raiseFieldError(f: string) {.compilerproc, noreturn.} =
   raise newException(EInvalidField, f & " is not accessible")
 
-proc SetConstr() {.varargs, noStackFrame, compilerproc.} =
+proc SetConstr() {.varargs, asmNoStackFrame, compilerproc.} =
   asm """
     var result = {};
     for (var i = 0; i < arguments.length; ++i) {
@@ -141,7 +141,7 @@ proc SetConstr() {.varargs, noStackFrame, compilerproc.} =
     return result;
   """
 
-proc cstrToNimstr(c: cstring): string {.noStackFrame, compilerproc.} =
+proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} =
   asm """
     var result = [];
     for (var i = 0; i < `c`.length; ++i) {
@@ -151,7 +151,7 @@ proc cstrToNimstr(c: cstring): string {.noStackFrame, compilerproc.} =
     return result;
   """
 
-proc toJSStr(s: string): cstring {.noStackFrame, compilerproc.} =
+proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
   asm """
     var len = `s`.length-1;
     var result = new Array(len);
@@ -162,7 +162,7 @@ proc toJSStr(s: string): cstring {.noStackFrame, compilerproc.} =
     return result.join("");
   """
 
-proc mnewString(len: int): string {.noStackFrame, compilerproc.} =
+proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} =
   asm """
     var result = new Array(`len`+1);
     result[0] = 0;
@@ -170,7 +170,7 @@ proc mnewString(len: int): string {.noStackFrame, compilerproc.} =
     return result;
   """
 
-proc SetCard(a: int): int {.compilerproc, noStackFrame.} =
+proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} =
   # argument type is a fake
   asm """
     var result = 0;
@@ -178,14 +178,14 @@ proc SetCard(a: int): int {.compilerproc, noStackFrame.} =
     return result;
   """
 
-proc SetEq(a, b: int): bool {.compilerproc, noStackFrame.} =
+proc SetEq(a, b: int): bool {.compilerproc, asmNoStackFrame.} =
   asm """
     for (var elem in `a`) { if (!`b`[elem]) return false; }
     for (var elem in `b`) { if (!`a`[elem]) return false; }
     return true;
   """
 
-proc SetLe(a, b: int): bool {.compilerproc, noStackFrame.} =
+proc SetLe(a, b: int): bool {.compilerproc, asmNoStackFrame.} =
   asm """
     for (var elem in `a`) { if (!`b`[elem]) return false; }
     return true;
@@ -194,7 +194,7 @@ proc SetLe(a, b: int): bool {.compilerproc, noStackFrame.} =
 proc SetLt(a, b: int): bool {.compilerproc.} =
   result = SetLe(a, b) and not SetEq(a, b)
 
-proc SetMul(a, b: int): int {.compilerproc, noStackFrame.} =
+proc SetMul(a, b: int): int {.compilerproc, asmNoStackFrame.} =
   asm """
     var result = {};
     for (var elem in `a`) {
@@ -203,7 +203,7 @@ proc SetMul(a, b: int): int {.compilerproc, noStackFrame.} =
     return result;
   """
 
-proc SetPlus(a, b: int): int {.compilerproc, noStackFrame.} =
+proc SetPlus(a, b: int): int {.compilerproc, asmNoStackFrame.} =
   asm """
     var result = {};
     for (var elem in `a`) { result[elem] = true; }
@@ -211,7 +211,7 @@ proc SetPlus(a, b: int): int {.compilerproc, noStackFrame.} =
     return result;
   """
 
-proc SetMinus(a, b: int): int {.compilerproc, noStackFrame.} =
+proc SetMinus(a, b: int): int {.compilerproc, asmNoStackFrame.} =
   asm """
     var result = {};
     for (var elem in `a`) {
@@ -220,7 +220,7 @@ proc SetMinus(a, b: int): int {.compilerproc, noStackFrame.} =
     return result;
   """
 
-proc cmpStrings(a, b: string): int {.noStackFrame, compilerProc.} =
+proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerProc.} =
   asm """
     if (`a` == `b`) return 0;
     if (!`a`) return -1;
@@ -234,7 +234,7 @@ proc cmpStrings(a, b: string): int {.noStackFrame, compilerProc.} =
 
 proc cmp(x, y: string): int = return cmpStrings(x, y)
 
-proc eqStrings(a, b: string): bool {.noStackFrame, compilerProc.} =
+proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerProc.} =
   asm """
     if (`a` == `b`) return true;
     if ((!`a`) || (!`b`)) return false;
@@ -300,7 +300,7 @@ type
     setAttributeNode*: proc (attr: ref TNode) {.nimcall.}
 
 when defined(kwin):
-  proc rawEcho {.compilerproc, nostackframe.} =
+  proc rawEcho {.compilerproc, asmNoStackFrame.} =
     asm """
       var buf = "";
       for (var i = 0; i < arguments.length; ++i) {
@@ -312,7 +312,7 @@ when defined(kwin):
 elif defined(nodejs):
   proc ewriteln(x: cstring) = log(x)
   
-  proc rawEcho {.compilerproc, nostackframe.} =
+  proc rawEcho {.compilerproc, asmNoStackFrame.} =
     asm """
       var buf = "";
       for (var i = 0; i < arguments.length; ++i) {
@@ -345,42 +345,42 @@ else:
     node.appendChild(document.createElement("br"))
 
 # Arithmetic:
-proc addInt(a, b: int): int {.noStackFrame, compilerproc.} =
+proc addInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
   asm """
     var result = `a` + `b`;
     if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
     return result;
   """
 
-proc subInt(a, b: int): int {.noStackFrame, compilerproc.} =
+proc subInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
   asm """
     var result = `a` - `b`;
     if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
     return result;
   """
 
-proc mulInt(a, b: int): int {.noStackFrame, compilerproc.} =
+proc mulInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
   asm """
     var result = `a` * `b`;
     if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
     return result;
   """
 
-proc divInt(a, b: int): int {.noStackFrame, compilerproc.} =
+proc divInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
   asm """
     if (`b` == 0) `raiseDivByZero`();
     if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
     return Math.floor(`a` / `b`);
   """
 
-proc modInt(a, b: int): int {.noStackFrame, compilerproc.} =
+proc modInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
   asm """
     if (`b` == 0) `raiseDivByZero`();
     if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
     return Math.floor(`a` % `b`);
   """
 
-proc addInt64(a, b: int): int {.noStackFrame, compilerproc.} =
+proc addInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
   asm """
     var result = `a` + `b`;
     if (result > 9223372036854775807
@@ -388,7 +388,7 @@ proc addInt64(a, b: int): int {.noStackFrame, compilerproc.} =
     return result;
   """
 
-proc subInt64(a, b: int): int {.noStackFrame, compilerproc.} =
+proc subInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
   asm """
     var result = `a` - `b`;
     if (result > 9223372036854775807
@@ -396,7 +396,7 @@ proc subInt64(a, b: int): int {.noStackFrame, compilerproc.} =
     return result;
   """
 
-proc mulInt64(a, b: int): int {.noStackFrame, compilerproc.} =
+proc mulInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
   asm """
     var result = `a` * `b`;
     if (result > 9223372036854775807
@@ -404,90 +404,89 @@ proc mulInt64(a, b: int): int {.noStackFrame, compilerproc.} =
     return result;
   """
 
-proc divInt64(a, b: int): int {.noStackFrame, compilerproc.} =
+proc divInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
   asm """
     if (`b` == 0) `raiseDivByZero`();
     if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`();
     return Math.floor(`a` / `b`);
   """
 
-proc modInt64(a, b: int): int {.noStackFrame, compilerproc.} =
+proc modInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
   asm """
     if (`b` == 0) `raiseDivByZero`();
     if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`();
     return Math.floor(`a` % `b`);
   """
 
-proc NegInt(a: int): int {.compilerproc.} =
+proc negInt(a: int): int {.compilerproc.} =
   result = a*(-1)
 
-proc NegInt64(a: int64): int64 {.compilerproc.} =
+proc negInt64(a: int64): int64 {.compilerproc.} =
   result = a*(-1)
 
-proc AbsInt(a: int): int {.compilerproc.} =
+proc absInt(a: int): int {.compilerproc.} =
   result = if a < 0: a*(-1) else: a
 
-proc AbsInt64(a: int64): int64 {.compilerproc.} =
+proc absInt64(a: int64): int64 {.compilerproc.} =
   result = if a < 0: a*(-1) else: a
 
-proc LeU(a, b: int): bool {.compilerproc.} =
+proc leU(a, b: int): bool {.compilerproc.} =
   result = abs(a) <= abs(b)
 
-proc LtU(a, b: int): bool {.compilerproc.} =
+proc ltU(a, b: int): bool {.compilerproc.} =
   result = abs(a) < abs(b)
 
-proc LeU64(a, b: int64): bool {.compilerproc.} =
+proc leU64(a, b: int64): bool {.compilerproc.} =
   result = abs(a) <= abs(b)
-
-proc LtU64(a, b: int64): bool {.compilerproc.} =
+proc ltU64(a, b: int64): bool {.compilerproc.} =
   result = abs(a) < abs(b)
 
-proc AddU(a, b: int): int {.compilerproc.} =
+proc addU(a, b: int): int {.compilerproc.} =
   result = abs(a) + abs(b)
-proc AddU64(a, b: int64): int64 {.compilerproc.} =
+proc addU64(a, b: int64): int64 {.compilerproc.} =
   result = abs(a) + abs(b)
 
-proc SubU(a, b: int): int {.compilerproc.} =
+proc subU(a, b: int): int {.compilerproc.} =
   result = abs(a) - abs(b)
-proc SubU64(a, b: int64): int64 {.compilerproc.} =
+proc subU64(a, b: int64): int64 {.compilerproc.} =
   result = abs(a) - abs(b)
 
-proc MulU(a, b: int): int {.compilerproc.} =
+proc mulU(a, b: int): int {.compilerproc.} =
   result = abs(a) * abs(b)
-proc MulU64(a, b: int64): int64 {.compilerproc.} =
+proc mulU64(a, b: int64): int64 {.compilerproc.} =
   result = abs(a) * abs(b)
 
-proc DivU(a, b: int): int {.compilerproc.} =
+proc divU(a, b: int): int {.compilerproc.} =
   result = abs(a) div abs(b)
-proc DivU64(a, b: int64): int64 {.compilerproc.} =
+proc divU64(a, b: int64): int64 {.compilerproc.} =
   result = abs(a) div abs(b)
 
-proc ModU(a, b: int): int {.compilerproc.} =
+proc modU(a, b: int): int {.compilerproc.} =
   result = abs(a) mod abs(b)
-proc ModU64(a, b: int64): int64 {.compilerproc.} =
+proc modU64(a, b: int64): int64 {.compilerproc.} =
   result = abs(a) mod abs(b)
 
-proc Ze(a: int): int {.compilerproc.} =
+proc ze*(a: int): int {.compilerproc.} =
   result = a
-proc Ze64(a: int64): int64 {.compilerproc.} =
+
+proc ze64*(a: int64): int64 {.compilerproc.} =
   result = a
 
-proc ToU8(a: int): int8 {.noStackFrame, compilerproc.} =
+proc ToU8(a: int): int8 {.asmNoStackFrame, compilerproc.} =
   asm """
     return `a`;
   """
 
-proc ToU16(a: int): int16 {.noStackFrame, compilerproc.} =
+proc ToU16(a: int): int16 {.asmNoStackFrame, compilerproc.} =
   asm """
     return `a`;
   """
 
-proc ToU32(a: int): int32 {.noStackFrame, compilerproc.} =
+proc ToU32(a: int): int32 {.asmNoStackFrame, compilerproc.} =
   asm """
     return `a`;
   """
 
-
 proc nimMin(a, b: int): int {.compilerproc.} = return if a <= b: a else: b
 proc nimMax(a, b: int): int {.compilerproc.} = return if a >= b: a else: b
 
@@ -500,9 +499,9 @@ proc isFatPointer(ti: PNimType): bool =
     tyArray, tyArrayConstr, tyTuple,
     tyOpenArray, tySet, tyVar, tyRef, tyPtr}
 
-proc NimCopy(x: pointer, ti: PNimType): pointer {.compilerproc.}
+proc nimCopy(x: pointer, ti: PNimType): pointer {.compilerproc.}
 
-proc NimCopyAux(dest, src: Pointer, n: ptr TNimNode) {.compilerproc.} =
+proc nimCopyAux(dest, src: Pointer, n: ptr TNimNode) {.compilerproc.} =
   case n.kind
   of nkNone: sysAssert(false, "NimCopyAux")
   of nkSlot:
@@ -518,7 +517,7 @@ proc NimCopyAux(dest, src: Pointer, n: ptr TNimNode) {.compilerproc.} =
       }
     """
 
-proc NimCopy(x: pointer, ti: PNimType): pointer =
+proc nimCopy(x: pointer, ti: PNimType): pointer =
   case ti.kind
   of tyPtr, tyRef, tyVar, tyNil:
     if not isFatPointer(ti):
@@ -586,7 +585,7 @@ proc genericReset(x: Pointer, ti: PNimType): pointer {.compilerproc.} =
     result = nil
 
 proc ArrayConstr(len: int, value: pointer, typ: PNimType): pointer {.
-                 noStackFrame, compilerproc.} =
+                 asmNoStackFrame, compilerproc.} =
   # types are fake
   asm """
     var result = new Array(`len`);
@@ -620,7 +619,7 @@ proc isObj(obj, subclass: PNimType): bool {.compilerproc.} =
     x = x.base
   return true
 
-proc addChar(x: string, c: char) {.compilerproc, noStackFrame.} =
+proc addChar(x: string, c: char) {.compilerproc, asmNoStackFrame.} =
   asm """
     `x`[`x`.length-1] = `c`; `x`.push(0);
   """
diff --git a/lib/system/repr.nim b/lib/system/repr.nim
index cd3f7c3f4..7c1a68bc7 100644
--- a/lib/system/repr.nim
+++ b/lib/system/repr.nim
@@ -59,7 +59,11 @@ proc reprChar(x: char): string {.compilerRtl.} =
 
 proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
   # we read an 'int' but this may have been too large, so mask the other bits:
-  let e = e and (1 shl (typ.size*8)-1)
+  let e = if typ.size == 1: e and 0xff
+          elif typ.size == 2: e and 0xffff
+          else: e
+  # XXX we need a proper narrowing based on signedness here
+  #e and ((1 shl (typ.size*8)) - 1)
   if ntfEnumHole notin typ.flags:
     if e <% typ.node.len:
       return $typ.node.sons[e].name
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index 6c8fa4882..4d87cf4b2 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -199,14 +199,14 @@ else:
     importc: "GetCurrentDirectoryA", dynlib: "kernel32", stdcall.}
   proc setCurrentDirectoryA*(lpPathName: cstring): int32 {.
     importc: "SetCurrentDirectoryA", dynlib: "kernel32", stdcall.}
-  proc createDirectoryA*(pathName: cstring, security: pointer=nil): int32 {.
+  proc createDirectoryA*(pathName: cstring, security: Pointer=nil): int32 {.
     importc: "CreateDirectoryA", dynlib: "kernel32", stdcall.}
   proc removeDirectoryA*(lpPathName: cstring): int32 {.
     importc: "RemoveDirectoryA", dynlib: "kernel32", stdcall.}
   proc setEnvironmentVariableA*(lpName, lpValue: cstring): int32 {.
     stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableA".}
 
-  proc getModuleFileNameA*(handle: THandle, buf: cstring, size: int32): int32 {.
+  proc getModuleFileNameA*(handle: THandle, buf: CString, size: int32): int32 {.
     importc: "GetModuleFileNameA", dynlib: "kernel32", stdcall.}
 
 when useWinUnicode:
@@ -304,7 +304,7 @@ else:
                            dwFileAttributes: int32): WINBOOL {.
       stdcall, dynlib: "kernel32", importc: "SetFileAttributesA".}
 
-  proc copyFileA*(lpExistingFileName, lpNewFileName: cstring,
+  proc copyFileA*(lpExistingFileName, lpNewFileName: CString,
                  bFailIfExists: cint): cint {.
     importc: "CopyFileA", stdcall, dynlib: "kernel32".}
 
@@ -456,6 +456,7 @@ var
 
   SO_DONTLINGER* {.importc, header: "Winsock2.h".}: cint
   SO_EXCLUSIVEADDRUSE* {.importc, header: "Winsock2.h".}: cint # disallow local address reuse
+  SO_ERROR* {.importc, header: "Winsock2.h".}: cint
 
 proc `==`*(x, y: TSocketHandle): bool {.borrow.}
 
diff --git a/lib/wrappers/mongo.nim b/lib/wrappers/mongo.nim
deleted file mode 100644
index 098b4f4d3..000000000
--- a/lib/wrappers/mongo.nim
+++ /dev/null
@@ -1,1204 +0,0 @@
-#
-#
-#            Nimrod's Runtime Library
-#        (c) Copyright 2012 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## This module is a wrapper for the `mongodb`:idx: client C library.
-## It allows you to connect to a mongo-server instance, send commands and
-## receive replies.
-
-# 
-#    Copyright 2009-2011 10gen Inc.
-# 
-#     Licensed under the Apache License, Version 2.0 (the "License");
-#     you may not use this file except in compliance with the License.
-#     You may obtain a copy of the License at
-# 
-#     http://www.apache.org/licenses/LICENSE-2.0
-# 
-#     Unless required by applicable law or agreed to in writing, software
-#     distributed under the License is distributed on an "AS IS" BASIS,
-#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#     See the License for the specific language governing permissions and
-#     limitations under the License.
-# 
-
-import oids, times
-
-{.deadCodeElim: on.}
-
-when defined(windows):
-  const
-    mongodll* = "mongoc.dll"
-    bsondll* = "bson.dll"
-elif defined(macosx):
-  const 
-    mongodll* = "libmongoc.dylib"
-    bsondll* = "libbson.dylib"
-else:
-  const 
-    mongodll* = "libmongoc.so"
-    bsondll* = "libbson.so"
-
-#
-#  This package supports both compile-time and run-time determination of CPU
-#  byte order.  If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
-#  compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
-#  defined as non-zero, the code will be compiled to run only on big-endian
-#  CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
-#  run on either big- or little-endian CPUs, but will run slightly less
-#  efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
-# 
-
-type 
-  Tmd5_state*{.pure, final.} = object 
-    count*: array[0..2 - 1, int32] # message length in bits, lsw first 
-    abcd*: array[0..4 - 1, int32] # digest buffer 
-    buf*: array[0..64 - 1, byte] # accumulate block 
-  
-
-proc sock_init*(): cint{.stdcall, importc: "mongo_sock_init", dynlib: mongodll.}
-const 
-  OK* = 0
-  ERROR* = - 1
-  SIZE_OVERFLOW* = 1
-  defaultHost* = "127.0.0.1"
-  defaultPort* = 27017
-
-type 
-  TValidity* = enum ## validity
-    VALID = 0,                ## BSON is valid and UTF-8 compliant. 
-    NOT_UTF8 = (1 shl 1),     ## A key or a string is not valid UTF-8. 
-    FIELD_HAS_DOT = (1 shl 2),  ## Warning: key contains '.' character. 
-    FIELD_INIT_DOLLAR = (1 shl 3),  ## Warning: key starts with '$' character. 
-    ALREADY_FINISHED = (1 shl 4) ## Trying to modify a finished BSON object. 
-  TBinarySubtype* = enum 
-    BIN_BINARY = 0, BIN_FUNC = 1, BIN_BINARY_OLD = 2, BIN_UUID = 3, BIN_MD5 = 5, 
-    BIN_USER = 128
-  TBsonKind* {.size: sizeof(cint).} = enum 
-    bkEOO = 0, 
-    bkDOUBLE = 1, 
-    bkSTRING = 2, 
-    bkOBJECT = 3, 
-    bkARRAY = 4, 
-    bkBINDATA = 5, 
-    bkUNDEFINED = 6, 
-    bkOID = 7, 
-    bkBOOL = 8, 
-    bkDATE = 9, 
-    bkNULL = 10, 
-    bkREGEX = 11, 
-    bkDBREF = 12,  #*< Deprecated. 
-    bkCODE = 13, 
-    bkSYMBOL = 14, 
-    bkCODEWSCOPE = 15, 
-    bkINT = 16, 
-    bkTIMESTAMP = 17, 
-    bkLONG = 18
-  TBsonBool* = cint
-  TIter* {.pure, final.} = object 
-    cur*: cstring
-    first*: TBsonBool
-
-  TBson* {.pure, final.} = object 
-    data*: cstring
-    cur*: cstring
-    dataSize*: cint
-    finished*: TBsonBool
-    ownsData*: TBsonBool
-    err*: cint
-    stackSize*: cint
-    stackPos*: cint
-    stackPtr*: ptr csize
-    stack*: array[0..32 - 1, csize]
-  
-  TDate* = int64
-
-# milliseconds since epoch UTC 
-
-type
-  TTimestamp*{.pure, final.} = object ## a timestamp
-    i*: cint                  # increment 
-    t*: cint                  # time in seconds 
-
-proc create*(): ptr TBson{.stdcall, importc: "bson_create", dynlib: bsondll.}
-proc dispose*(b: ptr TBson){.stdcall, importc: "bson_dispose", dynlib: bsondll.}
-
-proc size*(b: var TBson): cint {.stdcall, importc: "bson_size", dynlib: bsondll.}
-  ## Size of a BSON object.
-
-proc bufferSize*(b: var TBson): cint{.stdcall, importc: "bson_buffer_size", 
-                                      dynlib: bsondll.}
-  ## Buffer size of a BSON object.
-
-proc print*(b: var TBson){.stdcall, importc: "bson_print", dynlib: bsondll.}
-  ## Print a string representation of a BSON object.
-
-proc print*(TBson: cstring, depth: cint) {.stdcall, 
-    importc: "bson_print_raw", dynlib: bsondll.}
-  ## Print a string representation of a BSON object up to `depth`.
-
-
-proc data*(b: var TBson): cstring{.stdcall, importc: "bson_data", 
-                                   dynlib: bsondll.}
-  ## Return a pointer to the raw buffer stored by this bson object.
-
-proc find*(it: var TIter, obj: var TBson, name: cstring): TBsonKind {.stdcall, 
-    importc: "bson_find", dynlib: bsondll.}
-  ## Advance `it` to the named field. `obj` is the BSON object to use.
-  ## `name` is the name of the field to find. Returns the type of the found
-  ## object or ``bkEOO`` if it is not found.
-  
-proc createIter*(): ptr TIter{.stdcall, importc: "bson_iterator_create", 
-                               dynlib: bsondll.}
-proc dispose*(a2: ptr TIter){.stdcall, importc: "bson_iterator_dispose", 
-                              dynlib: bsondll.}
-
-proc initIter*(b: var TBson): TIter =
-  ## Initialize a bson iterator from the value `b`.
-  proc iterator_init(i: var TIter, b: var TBson){.stdcall, 
-      importc: "bson_iterator_init", dynlib: bsondll.}
-
-  iterator_init(result, b)
-
-proc fromBuffer*(i: var TIter, buffer: cstring) {.stdcall, 
-    importc: "bson_iterator_from_buffer", dynlib: bsondll.}
-  ## Initialize a bson iterator from a cstring buffer. Note
-  ## that this is mostly used internally.
-
-proc more*(i: var TIter): bool = 
-  ## Check to see if the bson_iterator has more data.
-  proc iterator_more(i: var TIter): TBsonBool{.stdcall, 
-      importc: "bson_iterator_more", dynlib: bsondll.}
-  result = iterator_more(i) != 0'i32
-  
-proc next*(i: var TIter): TBsonKind {.stdcall, 
-    importc: "bson_iterator_next", dynlib: bsondll.}
-  ## Point the iterator at the next BSON object.
-
-proc kind*(i: var TIter): TBsonKind{.stdcall, 
-    importc: "bson_iterator_type", dynlib: bsondll.}
-  ## Get the type of the BSON object currently pointed to by the iterator.
-
-proc key*(i: var TIter): cstring{.stdcall, 
-    importc: "bson_iterator_key", dynlib: bsondll.}
-  ##  Get the key of the BSON object currently pointed to by the iterator.
-  
-proc value*(i: var TIter): cstring{.stdcall, 
-    importc: "bson_iterator_value", dynlib: bsondll.}
-  ## Get the value of the BSON object currently pointed to by the iterator.
-  
-proc floatVal*(i: var TIter): float {.stdcall, 
-    importc: "bson_iterator_double", dynlib: bsondll.}
-  ## Get the double value of the BSON object currently pointed to by the
-  ## iterator.
-
-proc intVal*(i: var TIter): cint{.stdcall, importc: "bson_iterator_int", 
-                                  dynlib: bsondll.}
-  ## Get the int value of the BSON object currently pointed to by the iterator.
-
-proc int64Val*(i: var TIter): int64{.stdcall, 
-    importc: "bson_iterator_long", dynlib: bsondll.}
-  ## Get the long value of the BSON object currently pointed to by the iterator.
-
-proc timestamp*(i: var TIter): Ttimestamp {.stdcall, 
-    importc: "bson_iterator_timestamp", dynlib: bsondll.}
-  # return the bson timestamp as a whole or in parts 
-
-proc timestampTime*(i: var TIter): cint {.stdcall, 
-    importc: "bson_iterator_timestamp_time", dynlib: bsondll.}
-  # return the bson timestamp as a whole or in parts 
-proc timestampIncrement*(i: var TIter): cint{.stdcall, 
-    importc: "bson_iterator_timestamp_increment", dynlib: bsondll.}
-  # return the bson timestamp as a whole or in parts 
-
-proc boolVal*(i: var TIter): TBsonBool{.stdcall, 
-    importc: "bson_iterator_bool", dynlib: bsondll.}
-  ## Get the boolean value of the BSON object currently pointed to by
-  ## the iterator.
-  ##
-  ## | false: boolean false, 0 in any type, or null 
-  ## | true: anything else (even empty strings and objects) 
-
-proc floatRaw*(i: var TIter): cdouble{.stdcall, 
-    importc: "bson_iterator_double_raw", dynlib: bsondll.}
-  ## Get the double value of the BSON object currently pointed to by the
-  ## iterator. Assumes the correct type is used.
-      
-proc intRaw*(i: var TIter): cint{.stdcall, 
-    importc: "bson_iterator_int_raw", dynlib: bsondll.}
-  ## Get the int value of the BSON object currently pointed to by the
-  ## iterator. Assumes the correct type is used.
-    
-proc int64Raw*(i: var TIter): int64{.stdcall, 
-    importc: "bson_iterator_long_raw", dynlib: bsondll.}
-  ## Get the long value of the BSON object currently pointed to by the
-  ## iterator. Assumes the correct type is used.
-
-proc boolRaw*(i: var TIter): TBsonBool{.stdcall, 
-    importc: "bson_iterator_bool_raw", dynlib: bsondll.}
-  ## Get the bson_bool_t value of the BSON object currently pointed to by the
-  ## iterator. Assumes the correct type is used.
-
-proc oidVal*(i: var TIter): ptr TOid {.stdcall, 
-    importc: "bson_iterator_oid", dynlib: bsondll.}
-  ## Get the bson_oid_t value of the BSON object currently pointed to by the
-  ## iterator.
-
-proc strVal*(i: var TIter): cstring {.stdcall, 
-    importc: "bson_iterator_string", dynlib: bsondll.}
-  ## Get the string value of the BSON object currently pointed to by the
-  ## iterator.
-
-proc strLen*(i: var TIter): cint {.stdcall, 
-    importc: "bson_iterator_string_len", dynlib: bsondll.}
-  ## Get the string length of the BSON object currently pointed to by the
-  ## iterator.
-
-proc code*(i: var TIter): cstring {.stdcall, 
-    importc: "bson_iterator_code", dynlib: bsondll.}
-  ## Get the code value of the BSON object currently pointed to by the
-  ## iterator. Works with bson_code, bson_codewscope, and BSON_STRING
-  ## returns ``nil`` for everything else.
-    
-proc codeScope*(i: var TIter, scope: var TBson) {.stdcall, 
-    importc: "bson_iterator_code_scope", dynlib: bsondll.}
-  ## Calls bson_empty on scope if not a bson_codewscope
-  
-proc date*(i: var TIter): Tdate {.stdcall, 
-    importc: "bson_iterator_date", dynlib: bsondll.}
-  ## Get the date value of the BSON object currently pointed to by the
-  ## iterator.
-
-proc time*(i: var TIter): TTime {.stdcall, 
-    importc: "bson_iterator_time_t", dynlib: bsondll.}
-  ## Get the time value of the BSON object currently pointed to by the
-  ## iterator.
-
-proc binLen*(i: var TIter): cint {.stdcall, 
-    importc: "bson_iterator_bin_len", dynlib: bsondll.}
-  ## Get the length of the BSON binary object currently pointed to by the
-  ## iterator.
-
-proc binType*(i: var TIter): char {.stdcall, 
-    importc: "bson_iterator_bin_type", dynlib: bsondll.}
-  ## Get the type of the BSON binary object currently pointed to by the
-  ## iterator.
-
-proc binData*(i: var TIter): cstring {.stdcall, 
-    importc: "bson_iterator_bin_data", dynlib: bsondll.}
-  ## Get the value of the BSON binary object currently pointed to by the
-  ## iterator.
-
-proc regex*(i: var TIter): cstring {.stdcall, 
-    importc: "bson_iterator_regex", dynlib: bsondll.}
-  ## Get the value of the BSON regex object currently pointed to by the
-  ## iterator.
-
-proc regexOpts*(i: var TIter): cstring {.stdcall, 
-    importc: "bson_iterator_regex_opts", dynlib: bsondll.}
-  ## Get the options of the BSON regex object currently pointed to by the
-  ## iterator.
-
-proc subobject*(i: var TIter, sub: var TBson) {.stdcall, 
-    importc: "bson_iterator_subobject", dynlib: bsondll.}
-  ## Get the BSON subobject currently pointed to by the
-  ## iterator.
-
-proc subiterator*(i: var TIter, sub: var TIter) {.stdcall, 
-    importc: "bson_iterator_subiterator", dynlib: bsondll.}
-  ## Get a bson_iterator that on the BSON subobject.
-
-
-# ----------------------------
-#   BUILDING
-# ----------------------------
-
-proc init*(b: var TBson) {.stdcall, importc: "bson_init", dynlib: bsondll.}
-  ## Initialize a new bson object. If not created
-  ## with bson_new, you must initialize each new bson
-  ## object using this function.
-  ##
-  ## When finished, you must pass the bson object to bson_destroy().
-
-proc init*(b: var TBson, data: cstring): cint {.stdcall, 
-    importc: "bson_init_data", dynlib: bsondll.}
-  ## Initialize a BSON object, and point its data
-  ## pointer to the provided `data`.
-  ## Returns OK or ERROR.
-
-proc initFinished*(b: var TBson, data: cstring): cint {.stdcall, 
-    importc: "bson_init_finished_data", dynlib: bsondll.}
-
-proc initSize*(b: var TBson, size: cint) {.stdcall, importc: "bson_init_size", 
-    dynlib: bsondll.}
-  ## Initialize a BSON object, and set its buffer to the given size.
-  ## Returns OK or ERROR.
-
-proc ensureSpace*(b: var TBson, bytesNeeded: cint): cint {.stdcall, 
-    importc: "bson_ensure_space", dynlib: bsondll.}
-  ## Grow a bson object. `bytesNeeded` is the additional number of bytes needed.
-
-proc finish*(b: var TBson): cint{.stdcall, importc: "bson_finish", 
-                                  dynlib: bsondll, discardable.}
-  ## Finalize a bson object. Returns the standard error code.
-  ## To deallocate memory, call destroy on the bson object.
-
-proc destroy*(b: var TBson){.stdcall, importc: "bson_destroy", dynlib: bsondll.}
-  ## Destroy a bson object.
-
-proc empty*(obj: var TBson) {.stdcall, importc: "bson_empty", 
-                              dynlib: bsondll.}
-  ## Sets a pointer to a static empty BSON object.
-  ## `obj` is the BSON object to initialize. 
-
-proc copy*(outp, inp: var TBson): cint{.stdcall, importc: "bson_copy", 
-    dynlib: bsondll.}
-  ## Make a complete copy of the a BSON object.
-  ## The source bson object must be in a finished
-  ## state; otherwise, the copy will fail.
-
-proc add*(b: var TBson, name: cstring, oid: TOid) =
-  ## adds an OID to `b`.
-  proc appendOid(b: var TBson, name: cstring, oid: ptr TOid): cint {.stdcall, 
-      importc: "bson_append_oid", dynlib: bsondll.}
-  
-  var oid = oid
-  discard appendOid(b, name, addr(oid))
-
-proc add*(b: var TBson, name: cstring, i: cint): cint{.stdcall, 
-    importc: "bson_append_int", dynlib: bsondll, discardable.}
-  ## Append an int to a bson.
-
-proc add*(b: var TBson, name: cstring, i: int64): cint{.stdcall, 
-    importc: "bson_append_long", dynlib: bsondll, discardable.}
-  ## Append an long to a bson.
-
-proc add*(b: var TBson, name: cstring, d: float): cint{.stdcall, 
-    importc: "bson_append_double", dynlib: bsondll, discardable.}
-  ## Append an double to a bson.
-
-proc add*(b: var TBson, name: cstring, str: cstring): cint {.stdcall, 
-    importc: "bson_append_string", dynlib: bsondll, discardable.}
-  ## Append a string to a bson.
-
-proc add*(b: var TBson, name: cstring, str: cstring, len: cint): cint{.
-    stdcall, importc: "bson_append_string_n", dynlib: bsondll, discardable.}
-  ## Append len bytes of a string to a bson.
-
-proc add*(b: var TBson, name: cstring, str: string) =
-  ## Append a Nimrod string `str` to a bson.
-  discard add(b, name, str, str.len.cint)
-
-proc addSymbol*(b: var TBson, name: cstring, str: cstring): cint{.stdcall, 
-    importc: "bson_append_symbol", dynlib: bsondll, discardable.}
-  ##  Append a symbol to a bson.
-
-proc addSymbol*(b: var TBson, name: cstring, str: cstring, len: cint): cint{.
-    stdcall, importc: "bson_append_symbol_n", dynlib: bsondll, discardable.}
-  ## Append len bytes of a symbol to a bson.
-
-proc addCode*(b: var TBson, name: cstring, str: cstring): cint{.stdcall, 
-    importc: "bson_append_code", dynlib: bsondll, discardable.}
-  ## Append code to a bson.
-
-proc addCode*(b: var TBson, name: cstring, str: cstring, len: cint): cint{.
-    stdcall, importc: "bson_append_code_n", dynlib: bsondll, discardable.}
-  ## Append len bytes of code to a bson.
-
-proc addCode*(b: var TBson, name: cstring, code: cstring, 
-                          scope: var TBson): cint{.stdcall, 
-    importc: "bson_append_code_w_scope", dynlib: bsondll, discardable.}
-  ## Append code to a bson with scope.
-
-proc addCode*(b: var TBson, name: cstring, code: cstring, 
-              size: cint, scope: var TBson): cint{.stdcall, 
-    importc: "bson_append_code_w_scope_n", dynlib: bsondll, discardable.}
-  ## Append len bytes of code to a bson with scope.
-
-proc addBinary*(b: var TBson, name: cstring, typ: char, str: cstring, 
-                len: cint): cint{.stdcall, importc: "bson_append_binary", 
-                                 dynlib: bsondll, discardable.}
-  ## Append binary data to a bson.
-
-proc addBinary*(b: var TBson, name: cstring, data: string) =
-  ## Append binary data to a bson.
-  addBinary(b, name, '\5', data, data.len.cint)
-
-proc addBool*(b: var TBson, name: cstring, v: TBsonBool): cint{.stdcall, 
-    importc: "bson_append_bool", dynlib: bsondll, discardable.}
-  ## Append a bson_bool_t to a bson.
-
-proc addNull*(b: var TBson, name: cstring): cint {.stdcall, 
-    importc: "bson_append_null", dynlib: bsondll, discardable.}
-  ## Append a null value to a bson.
-
-proc addUndefined*(b: var TBson, name: cstring): cint{.stdcall, 
-    importc: "bson_append_undefined", dynlib: bsondll, discardable.}
-  ## Append an undefined value to a bson.
-
-proc addRegex*(b: var TBson, name: cstring, pattern: cstring, opts: cstring): cint{.
-    stdcall, importc: "bson_append_regex", dynlib: bsondll, discardable.}
-  ## Append a regex value to a bson.
-
-proc add*(b: var TBson, name: cstring, TBson: var TBson): cint {.stdcall, 
-    importc: "bson_append_bson", dynlib: bsondll, discardable.}
-  ## Append bson data to a bson.
-
-proc addElement*(b: var TBson, name_or_null: cstring, elem: var TIter): cint{.
-    stdcall, importc: "bson_append_element", dynlib: bsondll, discardable.}
-  ## Append a BSON element to a bson from the current point of an iterator.
-
-proc addTimestamp*(b: var TBson, name: cstring, ts: var TTimestamp): cint{.
-    stdcall, importc: "bson_append_timestamp", dynlib: bsondll, discardable.}
-  ## Append a bson_timestamp_t value to a bson.
-
-proc addTimestamp2*(b: var TBson, name: cstring, time: cint, increment: cint): cint{.
-    stdcall, importc: "bson_append_timestamp2", dynlib: bsondll, discardable.}
-proc addDate*(b: var TBson, name: cstring, millis: TDate): cint{.stdcall, 
-    importc: "bson_append_date", dynlib: bsondll, discardable.}
-  ## Append a bson_date_t value to a bson.
-
-proc addTime*(b: var TBson, name: cstring, secs: TTime): cint{.stdcall, 
-    importc: "bson_append_time_t", dynlib: bsondll, discardable.}
-  ## Append a time_t value to a bson.
-
-proc addStartObject*(b: var TBson, name: cstring): cint {.stdcall, 
-    importc: "bson_append_start_object", dynlib: bsondll, discardable.}
-  ## Start appending a new object to a bson.
-
-proc addStartArray*(b: var TBson, name: cstring): cint {.stdcall, 
-    importc: "bson_append_start_array", dynlib: bsondll, discardable.}
-  ## Start appending a new array to a bson.
-
-proc addFinishObject*(b: var TBson): cint {.stdcall, 
-    importc: "bson_append_finish_object", dynlib: bsondll, discardable.}
-  ## Finish appending a new object or array to a bson.
-
-proc addFinishArray*(b: var TBson): cint {.stdcall, 
-    importc: "bson_append_finish_array", dynlib: bsondll, discardable.}
-  ## Finish appending a new object or array to a bson. This
-  ## is simply an alias for bson_append_finish_object.
-
-proc numstr*(str: cstring, i: cint){.stdcall, importc: "bson_numstr", 
-                                     dynlib: bsondll.}
-proc incnumstr*(str: cstring){.stdcall, importc: "bson_incnumstr", 
-                               dynlib: bsondll.}
-
-type 
-  TErrHandler* = proc (errmsg: cstring){.
-    stdcall.} ## an error handler. Error handlers shouldn't return!
-
-proc setBsonErrHandler*(func: TErrHandler): TErrHandler {.stdcall, 
-    importc: "set_bson_err_handler", dynlib: bsondll.}
-  ## Set a function for error handling.
-  ## Returns the old error handling function, or nil.
-
-proc fatal*(ok: cint){.stdcall, importc: "bson_fatal", dynlib: bsondll.}
-  ## does nothing if ok != 0. Exit fatally.
-
-proc fatal*(ok: cint, msg: cstring){.stdcall, importc: "bson_fatal_msg", 
-    dynlib: bsondll.}
-  ## Exit fatally with an error message.
-
-proc builderError*(b: var TBson){.stdcall, importc: "bson_builder_error", 
-                                   dynlib: bsondll.}
-  ## Invoke the error handler, but do not exit.
-
-proc int64ToDouble*(i64: int64): cdouble {.stdcall, 
-    importc: "bson_int64_to_double", dynlib: bsondll.}
-  ## Cast an int64_t to double. This is necessary for embedding in
-  ## certain environments.
-
-const 
-  MAJOR* = 0
-  MINOR* = 4
-  PATCH* = 0
-
-type 
-  TError*{.size: sizeof(cint).} = enum ## connection errors
-    CONN_SUCCESS = 0,         ## Connection success! 
-    CONN_NO_SOCKET,           ## Could not create a socket. 
-    CONN_FAIL,                ## An error occured while calling connect(). 
-    CONN_ADDR_FAIL,           ## An error occured while calling getaddrinfo(). 
-    CONN_NOT_MASTER,          ## Warning: connected to a non-master node (read-only). 
-    CONN_BAD_SET_NAME,        ## Given rs name doesn't match this replica set. 
-    CONN_NO_PRIMARY,          ## Can't find primary in replica set. Connection closed. 
-    IO_ERROR,                 ## An error occurred while reading or writing on the socket. 
-    READ_SIZE_ERROR,          ## The response is not the expected length. 
-    COMMAND_FAILED,           ## The command returned with 'ok' value of 0. 
-    BSON_INVALID,             ## BSON not valid for the specified op. 
-    BSON_NOT_FINISHED         ## BSON object has not been finished. 
-  TCursorError*{.size: sizeof(cint).} = enum ## cursor error 
-    CURSOR_EXHAUSTED,         ## The cursor has no more results. 
-    CURSOR_INVALID,           ## The cursor has timed out or is not recognized. 
-    CURSOR_PENDING,           ## Tailable cursor still alive but no data. 
-    CURSOR_QUERY_FAIL,  ## The server returned an '$err' object, indicating query failure.
-                        ## See conn.lasterrcode and conn.lasterrstr for details. 
-    CURSOR_BSON_ERROR ## Something is wrong with the BSON provided. See conn.err
-                      ## for details. 
-  TCursorFlags* = enum ## cursor flags
-    CURSOR_MUST_FREE = 1,     ## mongo_cursor_destroy should free cursor. 
-    CURSOR_QUERY_SENT = (1 shl 1) ## Initial query has been sent. 
-  TindexOpts* = enum 
-    INDEX_UNIQUE = (1 shl 0), INDEX_DROP_DUPS = (1 shl 2), 
-    INDEX_BACKGROUND = (1 shl 3), INDEX_SPARSE = (1 shl 4)
-  TupdateOpts* = enum 
-    UPDATE_UPSERT = 0x00000001, 
-    UPDATE_MULTI = 0x00000002, 
-    UPDATE_BASIC = 0x00000004
-  TCursorOpts* = enum 
-    TAILABLE = (1 shl 1),     ## Create a tailable cursor. 
-    SLAVE_OK = (1 shl 2),     ## Allow queries on a non-primary node. 
-    NO_CURSOR_TIMEOUT = (1 shl 4),  ## Disable cursor timeouts. 
-    AWAIT_DATA = (1 shl 5),   ## Momentarily block for more data. 
-    EXHAUST = (1 shl 6),      ## Stream in multiple 'more' packages. 
-    PARTIAL = (1 shl 7)       ## Allow reads even if a shard is down. 
-  Toperations* = enum 
-    OP_MSG = 1000, OP_UPDATE = 2001, OP_INSERT = 2002, OP_QUERY = 2004, 
-    OP_GET_MORE = 2005, OP_DELETE = 2006, OP_KILL_CURSORS = 2007
-  THeader* {.pure, final.} = object 
-    len*: cint
-    id*: cint
-    responseTo*: cint
-    op*: cint
-
-  TMessage* {.pure, final.} = object 
-    head*: Theader
-    data*: char
-
-  TReplyFields*{.pure, final.} = object 
-    flag*: cint               # FIX THIS COMMENT non-zero on failure 
-    cursorID*: int64
-    start*: cint
-    num*: cint
-
-  TReply*{.pure, final.} = object 
-    head*: Theader
-    fields*: Treply_fields
-    objs*: char
-
-  THostPort*{.pure, final.} = object 
-    host*: array[0..255 - 1, char]
-    port*: cint
-    next*: ptr THostPort
-
-  TReplset*{.pure, final.} = object ## replset
-    seeds*: ptr THostPort    ## List of seeds provided by the user. 
-    hosts*: ptr THostPort    ## List of host/ports given by the replica set 
-    name*: cstring           ## Name of the replica set. 
-    primary_connected*: TBsonBool ## Primary node connection status. 
-
-  TWriteConcern*{.pure, final.} = object ## mongo_write_concern
-    w*: cint
-    wtimeout*: cint
-    j*: cint
-    fsync*: cint
-    mode*: cstring
-    cmd*: TBSon
-  
-  TMongo*{.pure, final.} = object ## mongo
-    primary*: ptr THostPort              ## Primary connection info. 
-    replset*: ptr TReplSet               ## replset object if connected to a replica set. 
-    sock*: cint                          ## Socket file descriptor. 
-    flags*: cint                         ## Flags on this connection object. 
-    conn_timeout_ms*: cint               ## Connection timeout in milliseconds. 
-    op_timeout_ms*: cint                 ## Read and write timeout in milliseconds. 
-    max_bson_size*: cint                 ## Largest BSON object allowed on this connection. 
-    connected*: TBsonBool                ## Connection status. 
-    write_concern*: TWriteConcern        ## The default write concern.
-    err*: TError                         ## Most recent driver error code. 
-    errcode*: cint                       ## Most recent errno or WSAGetLastError().
-    errstr*: array[0..128 - 1, char]     ## String version of most recent driver error code. 
-    lasterrcode*: cint                   ## getlasterror code given by the server on error. 
-    lasterrstr*: array[0..128 - 1, char] ## getlasterror string generated by server. 
-  
-  TCursor*{.pure, final.} = object ## cursor
-    reply*: ptr TReply        ## reply is owned by cursor 
-    conn*: ptr TMongo         ## connection is *not* owned by cursor 
-    ns*: cstring              ## owned by cursor 
-    flags*: cint              ## Flags used internally by this drivers. 
-    seen*: cint               ## Number returned so far. 
-    current*: TBson           ## This cursor's current bson object. 
-    err*: TCursorError        ## Errors on this cursor. 
-    query*: ptr TBson         ## Bitfield containing cursor options. 
-    fields*: ptr TBson        ## Bitfield containing cursor options. 
-    options*: cint            ## Bitfield containing cursor options. 
-    limit*: cint              ## Bitfield containing cursor options. 
-    skip*: cint               ## Bitfield containing cursor options. 
-  
-
-# Connection API 
-
-proc createMongo*(): ptr TMongo{.stdcall, importc: "mongo_create", dynlib: mongodll.}
-proc dispose*(conn: ptr TMongo){.stdcall, importc: "mongo_dispose", 
-                                 dynlib: mongodll.}
-proc getErr*(conn: var TMongo): cint{.stdcall, importc: "mongo_get_err", 
-                                     dynlib: mongodll.}
-proc isConnected*(conn: var TMongo): cint{.stdcall, 
-    importc: "mongo_is_connected", dynlib: mongodll.}
-proc getOpTimeout*(conn: var TMongo): cint{.stdcall, 
-    importc: "mongo_get_op_timeout", dynlib: mongodll.}
-proc getPrimary*(conn: var TMongo): cstring{.stdcall, 
-    importc: "mongo_get_primary", dynlib: mongodll.}
-proc getSocket*(conn: var TMongo): cint {.stdcall, importc: "mongo_get_socket", 
-    dynlib: mongodll.}
-proc getHostCount*(conn: var TMongo): cint{.stdcall, 
-    importc: "mongo_get_host_count", dynlib: mongodll.}
-proc getHost*(conn: var TMongo, i: cint): cstring {.stdcall, 
-    importc: "mongo_get_host", dynlib: mongodll.}
-proc createCursor*(): ptr TCursor{.stdcall, importc: "mongo_cursor_create", 
-                                  dynlib: mongodll.}
-proc dispose*(cursor: ptr TCursor){.stdcall, 
-    importc: "mongo_cursor_dispose", dynlib: mongodll.}
-proc getServerErr*(conn: var TMongo): cint{.stdcall, 
-    importc: "mongo_get_server_err", dynlib: mongodll.}
-proc getServerErrString*(conn: var TMongo): cstring{.stdcall, 
-    importc: "mongo_get_server_err_string", dynlib: mongodll.}
-
-proc init*(conn: var TMongo){.stdcall, importc: "mongo_init", dynlib: mongodll.}
-  ## Initialize a new mongo connection object. You must initialize each mongo
-  ## object using this function.
-  ## When finished, you must pass this object to ``destroy``.
-
-proc connect*(conn: var TMongo, host: cstring = defaultHost, 
-              port: cint = defaultPort): cint {.stdcall, 
-    importc: "mongo_connect", dynlib: mongodll, deprecated.}
-  ## Connect to a single MongoDB server.
-proc client*(conn: var TMongo, host: cstring = defaultHost, 
-              port: cint = defaultPort): cint {.stdcall, 
-    importc: "mongo_client", dynlib: mongodll.}
-  ## Connect to a single MongoDB server.
-
-proc replsetInit*(conn: var TMongo, name: cstring){.stdcall, 
-    importc: "mongo_replset_init", dynlib: mongodll.}
-  ## Set up this connection object for connecting to a replica set.
-  ## To connect, pass the object to replsetConnect.
-  ## `name` is the name of the replica set to connect to.
-
-proc replsetAddSeed*(conn: var TMongo, host: cstring = defaultHost, 
-  port: cint = defaultPort){.stdcall,
-  importc: "mongo_replset_add_seed", dynlib: mongodll.}
-  ## Add a seed node to the replica set connection object.
-  ## You must specify at least one seed node before connecting
-  ## to a replica set.
-
-proc parseHost*(hostString: cstring, hostPort: var ThostPort){.stdcall, 
-    importc: "mongo_parse_host", dynlib: mongodll.}
-  ## Utility function for converting a host-port string to a mongo_host_port.
-  ## `hostString` is a string containing either a host or a host and port
-  ## separated by a colon.
-  ## `hostPort` is the mongo_host_port object to write the result to.
-
-proc replsetConnect*(conn: var TMongo): cint{.stdcall, 
-    importc: "mongo_replset_connect", dynlib: mongodll.}
-  ## Connect to a replica set.
-  ## Before passing a connection object to this function, you must already
-  ## have called setReplset and replsetAddSeed.
-
-proc setOpTimeout*(conn: var TMongo, millis: cint): cint{.stdcall, 
-    importc: "mongo_set_op_timeout", dynlib: mongodll.}
-  ## Set a timeout for operations on this connection. This
-  ## is a platform-specific feature, and only work on Unix-like
-  ## systems. You must also compile for linux to support this.
-
-proc checkConnection*(conn: var TMongo): cint {.stdcall, 
-    importc: "mongo_check_connection", dynlib: mongodll.}
-  ## Ensure that this connection is healthy by performing
-  ## a round-trip to the server.
-  ## Returns OK if connected; otherwise ERROR.
-
-proc reconnect*(conn: var TMongo): cint {.stdcall, importc: "mongo_reconnect", 
-    dynlib: mongodll.}
-  ## Try reconnecting to the server using the existing connection settings.
-  ## This function will disconnect the current socket. If you've authenticated,
-  ## you'll need to re-authenticate after calling this function.
-
-proc disconnect*(conn: var TMongo){.stdcall, importc: "mongo_disconnect", 
-                                    dynlib: mongodll.}
-  ## Close the current connection to the server. After calling
-  ## this function, you may call reconnect with the same
-  ## connection object.
-
-proc destroy*(conn: var TMongo){.stdcall, importc: "mongo_destroy", 
-                                 dynlib: mongodll.}
-  ## Close any existing connection to the server and free all allocated
-  ## memory associated with the conn object.
-  ## You must always call this function when finished with the connection
-  ## object.
-
-proc insert*(conn: var TMongo, ns: cstring, data: var TBson,
-             custom_write_concern: ptr TWriteConcern): cint{.stdcall, 
-    importc: "mongo_insert", dynlib: mongodll, discardable.}
-  ## Insert a BSON document into a MongoDB server. This function
-  ## will fail if the supplied BSON struct is not UTF-8 or if
-  ## the keys are invalid for insert (contain '.' or start with '$').
-
-proc insertBatch*(conn: var TMongo, ns: cstring, 
-                  data: ptr ptr TBson, num: cint): cint{.
-    stdcall, importc: "mongo_insert_batch", dynlib: mongodll, discardable.}
-  ## Insert a batch of BSON documents into a MongoDB server. This function
-  ## will fail if any of the documents to be inserted is invalid.
-  ## `num` is the number of documents in data.
-
-proc update*(conn: var TMongo, ns: cstring, cond, op: var TBson, 
-             flags: cint): cint{.stdcall, importc: "mongo_update", 
-                                 dynlib: mongodll, discardable.}
-  ## Update a document in a MongoDB server.
-  ## 
-  ## | conn a mongo object.
-  ## | ns the namespace.
-  ## | cond the bson update query.
-  ## | op the bson update data.
-  ## | flags flags for the update.
-  ## | returns OK or ERROR with error stored in conn object.
-
-proc remove*(conn: var TMongo, namespace: cstring, cond: var TBson): cint{.stdcall, 
-    importc: "mongo_remove", dynlib: mongodll.}
-  ## Remove a document from a MongoDB server.
-  ##
-  ## | conn a mongo object.
-  ## | ns the namespace.
-  ## | cond the bson query.
-  ## | returns OK or ERROR with error stored in conn object.
-
-proc find*(conn: var TMongo, namespace: cstring, query, fields: var TBson, 
-           limit, skip: cint, options: cint): ptr TCursor{.stdcall, 
-    importc: "mongo_find", dynlib: mongodll.}
-  ## Find documents in a MongoDB server.
-  ##
-  ## | conn a mongo object.
-  ## | ns the namespace.
-  ## | query the bson query.
-  ## | fields a bson document of fields to be returned.
-  ## | limit the maximum number of documents to return.
-  ## | skip the number of documents to skip.
-  ## | options A bitfield containing cursor options.
-  ## | returns A cursor object allocated on the heap or nil if
-  ##   an error has occurred. For finer-grained error checking,
-  ##   use the cursor builder API instead.
-
-proc init*(cursor: var TCursor, conn: var TMongo, namespace: cstring){.stdcall, 
-    importc: "mongo_cursor_init", dynlib: mongodll.}
-  ## Initalize a new cursor object.
-  ##
-  ## The namespace is represented as the database
-  ## name and collection name separated by a dot. e.g., "test.users".
-
-proc setQuery*(cursor: var TCursor, query: var TBson) {.stdcall, 
-    importc: "mongo_cursor_set_query", dynlib: mongodll.}
-  ##  Set the bson object specifying this cursor's query spec. If
-  ## your query is the empty bson object "{}", then you need not
-  ## set this value.
-  ##
-  ## `query` is a bson object representing the query spec. This may
-  ## be either a simple query spec or a complex spec storing values for
-  ## $query, $orderby, $hint, and/or $explain. See
-  ## http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol for details.
-
-proc setFields*(cursor: var TCursor, fields: var TBson){.stdcall, 
-    importc: "mongo_cursor_set_fields", dynlib: mongodll.}
-  ## Set the fields to return for this cursor. If you want to return
-  ## all fields, you need not set this value.
-  ## `fields` is a bson object representing the fields to return.
-  ## See http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields.
-
-proc setSkip*(cursor: var TCursor, skip: cint){.stdcall, 
-    importc: "mongo_cursor_set_skip", dynlib: mongodll.}
-  ##  Set the number of documents to skip.
-
-proc setLimit*(cursor: var TCursor, limit: cint){.stdcall, 
-    importc: "mongo_cursor_set_limit", dynlib: mongodll.}
-  ## Set the number of documents to return.
-
-proc setOptions*(cursor: var TCursor, options: cint){.stdcall, 
-    importc: "mongo_cursor_set_options", dynlib: mongodll.}
-  ## Set any of the available query options (e.g., TAILABLE).
-  ## See `TCursorOpts` for available constants.
-
-proc data*(cursor: var TCursor): cstring {.stdcall, 
-    importc: "mongo_cursor_data", dynlib: mongodll.}
-  ## Return the current BSON object data as a ``cstring``. This is useful
-  ## for creating bson iterators.
-
-proc bson*(cursor: var TCursor): ptr TBson{.stdcall, 
-    importc: "mongo_cursor_bson", dynlib: mongodll.}
-  ## Return the current BSON object.
-
-proc next*(cursor: var TCursor): cint {.stdcall, 
-    importc: "mongo_cursor_next", dynlib: mongodll.}
-  ## Iterate the cursor, returning the next item. When successful,
-  ## the returned object will be stored in cursor.current;
-
-proc destroy*(cursor: var TCursor): cint {.stdcall,
-    importc: "mongo_cursor_destroy", dynlib: mongodll, discardable.}
-  ## Destroy a cursor object. When finished with a cursor, you
-  ## must pass it to this function.
-
-proc findOne*(conn: var TMongo, namespace: cstring, query: var TBson, 
-              fields: var TBson, outp: var TBson): cint{.stdcall, 
-    importc: "mongo_find_one", dynlib: mongodll.}
-  ## Find a single document in a MongoDB server.
-  ##
-  ## | conn a mongo object.
-  ## | ns the namespace.
-  ## | query the bson query.
-  ## | fields a bson document of the fields to be returned.
-  ## | outp a bson document in which to put the query result.
-  ##   outp can be nil if you don't care about results. Useful for commands.
-
-proc count*(conn: var TMongo, db: cstring, coll: cstring, query: var TBson): cdouble{.
-    stdcall, importc: "mongo_count", dynlib: mongodll.}
-  ## Count the number of documents in a collection matching a query.
-  ##
-  ## | conn a mongo object.
-  ## | db the db name.
-  ## | coll the collection name.
-  ## | query the BSON query.
-  ## | returns the number of matching documents. If the command fails,
-  ##   ERROR is returned.
-
-proc createIndex*(conn: var TMongo, namespace: cstring, key: var TBson, 
-                   options: cint, outp: var TBson): cint {.stdcall, 
-    importc: "mongo_create_index", dynlib: mongodll.}
-  ##  Create a compouned index.
-  ##
-  ## | conn a mongo object.
-  ## | ns the namespace.
-  ## | data the bson index data.
-  ## | options a bitfield for setting index options. Possibilities include
-  ##   INDEX_UNIQUE, INDEX_DROP_DUPS, INDEX_BACKGROUND,
-  ##   and INDEX_SPARSE.
-  ## | out a bson document containing errors, if any.
-  ## | returns MONGO_OK if index is created successfully; otherwise, MONGO_ERROR.
-
-proc createSimpleIndex*(conn: var TMongo, namespace, field: cstring, 
-                        options: cint, outp: var TBson): TBsonBool {.stdcall, 
-    importc: "mongo_create_simple_index", dynlib: mongodll.}
-  ## Create an index with a single key.
-  ##
-  ## | conn a mongo object.
-  ## | ns the namespace.
-  ## | field the index key.
-  ## | options index options.
-  ## | out a BSON document containing errors, if any.
-  ## | returns true if the index was created.
-
-
-# ----------------------------
-#   COMMANDS
-# ----------------------------
-
-
-proc runCommand*(conn: var TMongo, db: cstring, command: var TBson, 
-                  outp: var TBson): cint{.stdcall, importc: "mongo_run_command", 
-    dynlib: mongodll.}
-  ## Run a command on a MongoDB server.
-  ## 
-  ## | conn a mongo object.
-  ## | db the name of the database.
-  ## | command the BSON command to run.
-  ## | out the BSON result of the command.
-  ## | returns OK if the command ran without error.
-
-proc simpleIntCommand*(conn: var TMongo, db: cstring, cmd: cstring, arg: cint, 
-                         outp: var TBson): cint{.stdcall, 
-    importc: "mongo_simple_int_command", dynlib: mongodll.}
-  ## Run a command that accepts a simple string key and integer value.
-  ##
-  ## | conn a mongo object.
-  ## | db the name of the database.
-  ## | cmd the command to run.
-  ## | arg the integer argument to the command.
-  ## | out the BSON result of the command.
-  ## | returns OK or an error code.
-
-proc simpleStrCommand*(conn: var TMongo, db: cstring, cmd: cstring, 
-                         arg: cstring, outp: var TBson): cint{.stdcall, 
-    importc: "mongo_simple_str_command", dynlib: mongodll.}
-  ## Run a command that accepts a simple string key and value.
-  ##
-  ## | conn a mongo object.
-  ## | db the name of the database.
-  ## | cmd the command to run.
-  ## | arg the string argument to the command.
-  ## | out the BSON result of the command.
-  ## | returns true if the command ran without error.
-
-proc cmdDropDb*(conn: var TMongo, db: cstring): cint{.stdcall, 
-    importc: "mongo_cmd_drop_db", dynlib: mongodll.}
-  ## Drop a database.
-  ##
-  ## | conn a mongo object.
-  ## | db the name of the database to drop.
-  ## | returns OK or an error code.
-
-proc cmdDropCollection*(conn: var TMongo, db: cstring, collection: cstring, 
-                          outp: var TBson): cint{.stdcall, 
-    importc: "mongo_cmd_drop_collection", dynlib: mongodll.}
-  ## Drop a collection.
-  ##
-  ## | conn a mongo object.
-  ## | db the name of the database.
-  ## | collection the name of the collection to drop.
-  ## | out a BSON document containing the result of the command.
-  ## | returns true if the collection drop was successful.
-
-proc cmdAddUser*(conn: var TMongo, db: cstring, user: cstring, pass: cstring): cint{.
-    stdcall, importc: "mongo_cmd_add_user", dynlib: mongodll.}
-  ## Add a database user.
-  ##
-  ## | conn a mongo object.
-  ## | db the database in which to add the user.
-  ## | user the user name
-  ## | pass the user password
-  ## | returns OK or ERROR.
-
-proc cmdAuthenticate*(conn: var TMongo, db: cstring, user: cstring, 
-                      pass: cstring): cint{.stdcall, 
-    importc: "mongo_cmd_authenticate", dynlib: mongodll.}
-  ## Authenticate a user.
-  ##
-  ## | conn a mongo object.
-  ## | db the database to authenticate against.
-  ## | user the user name to authenticate.
-  ## | pass the user's password.
-  ## | returns OK on sucess and ERROR on failure.
-
-proc cmdIsMaster*(conn: var TMongo, outp: var TBson): TBsonBool {.stdcall, 
-    importc: "mongo_cmd_ismaster", dynlib: mongodll.}
-  ## Check if the current server is a master.
-  ##
-  ## | conn a mongo object.
-  ## | outp a BSON result of the command.
-  ## | returns true if the server is a master.
-
-proc cmdGetLastError*(conn: var TMongo, db: cstring, outp: var TBson): cint{.
-    stdcall, importc: "mongo_cmd_get_last_error", dynlib: mongodll.}
-  ## Get the error for the last command with the current connection.
-  ##
-  ## | conn a mongo object.
-  ## | db the name of the database.
-  ## | outp a BSON object containing the error details.
-  ## | returns OK or ERROR
-
-proc cmdGetPrevError*(conn: var TMongo, db: cstring, outp: var TBson): cint{.
-    stdcall, importc: "mongo_cmd_get_prev_error", dynlib: mongodll.}
-  ## Get the most recent error with the current connection.
-  ##
-  ## | conn a mongo object.
-  ## | db the name of the database.
-  ## | outp a BSON object containing the error details.
-  ## | returns OK or ERROR.
-  
-proc cmdResetError*(conn: var TMongo, db: cstring){.stdcall, 
-    importc: "mongo_cmd_reset_error", dynlib: mongodll.}
-  ## Reset the error state for the connection. `db` is the name of the database.
-
-# gridfs.h 
-
-const 
-  DEFAULT_CHUNK_SIZE* = 262144
-
-type 
-  TOffset* = int64
-
-# A GridFS represents a single collection of GridFS files in the database. 
-
-type 
-  TGridfs*{.pure, final.} = object 
-    client*: ptr TMongo       ## The client to db-connection. 
-    dbname*: cstring          ## The root database name 
-    prefix*: cstring          ## The prefix of the GridFS's collections,
-                              ## default is nil 
-    files_ns*: cstring        ## The namespace where the file's metadata
-                              ## is stored
-    chunks_ns*: cstring       ## The namespace where the files's data is
-                              ## stored in chunks
-
-# A GridFile is a single GridFS file. 
-
-type 
-  TGridFile*{.pure, final.} = object 
-    gfs*: ptr TGridfs         ## GridFS where the GridFile is located 
-    meta*: ptr TBson          ## GridFile's bson object where all
-                              ## its metadata is located 
-    pos*: TOffset             ## position is the offset in the file 
-    id*: TOid                 ## files_id of the gridfile 
-    remote_name*: cstring     ## name of the gridfile as a string 
-    content_type*: cstring    ## gridfile's content type 
-    length*: TOffset          ## length of this gridfile 
-    chunk_num*: cint          ## number of the current chunk being written to 
-    pending_data*: cstring    ## buffer storing data still to be
-                              ## written to chunks 
-    pending_len*: cint        ## length of pending_data buffer 
-  
-
-proc createGridfs*(): ptr TGridfs{.stdcall, importc: "gridfs_create", dynlib: mongodll.}
-proc dispose*(gfs: ptr TGridfs){.stdcall, importc: "gridfs_dispose", 
-                                 dynlib: mongodll.}
-proc createGridfile*(): ptr TGridFile{.stdcall, importc: "gridfile_create", 
-                               dynlib: mongodll.}
-proc dispose*(gf: ptr TGridFile){.stdcall, importc: "gridfile_dispose", 
-                                  dynlib: mongodll.}
-proc getDescriptor*(gf: var TGridFile, outp: var TBson){.stdcall, 
-    importc: "gridfile_get_descriptor", dynlib: mongodll.}
-
-
-proc init*(client: var TMongo, dbname: cstring, prefix: cstring, 
-           gfs: var TGridfs): cint{.stdcall, importc: "gridfs_init", 
-                                    dynlib: mongodll.}
-  ## Initializes a GridFS object
-  ## 
-  ## | client - db connection
-  ## | dbname - database name
-  ## | prefix - collection prefix, default is fs if NULL or empty
-  ## | gfs - the GridFS object to initialize
-  ## | returns - OK or ERROR.
-
-proc destroy*(gfs: var TGridfs){.stdcall, importc: "gridfs_destroy", 
-                                 dynlib: mongodll.}
-  ## Destroys a GridFS object. Call this when finished with the object.
-
-proc writerInit*(gfile: var TGridFile, gfs: var TGridfs, remote_name: cstring, 
-                  content_type: cstring){.stdcall, 
-    importc: "gridfile_writer_init", dynlib: mongodll.}
-  ## Initializes a gridfile for writing incrementally with ``writeBuffer``.
-  ## Once initialized, you can write any number of buffers with ``writeBuffer``.
-  ## When done, you must call ``writerDone`` to save the file metadata.
-
-proc writeBuffer*(gfile: var TGridFile, data: cstring, length: TOffset){.
-    stdcall, importc: "gridfile_write_buffer", dynlib: mongodll.}
-  ## Write to a GridFS file incrementally. You can call this function any number
-  ## of times with a new buffer each time. This allows you to effectively
-  ## stream to a GridFS file. When finished, be sure to call ``writerDone``.
-
-proc writerDone*(gfile: var TGridFile): cint{.stdcall, 
-    importc: "gridfile_writer_done", dynlib: mongodll.}
-  ## Signal that writing of this gridfile is complete by
-  ## writing any buffered chunks along with the entry in the
-  ## files collection. Returns OK or ERROR.
-
-proc storeBuffer*(gfs: var TGridfs, data: cstring, length: TOffset, 
-                   remotename: cstring, contenttype: cstring): cint{.stdcall, 
-    importc: "gridfs_store_buffer", dynlib: mongodll.}
-  ## Store a buffer as a GridFS file.
-  ##
-  ## | gfs - the working GridFS
-  ## | data - pointer to buffer to store in GridFS
-  ## | length - length of the buffer
-  ## | remotename - filename for use in the database
-  ## | contenttype - optional MIME type for this object
-  ## | returns - MONGO_OK or MONGO_ERROR.
-
-proc storeFile*(gfs: var TGridfs, filename: cstring, remotename: cstring, 
-                 contenttype: cstring): cint{.stdcall, 
-    importc: "gridfs_store_file", dynlib: mongodll.}
-  ## Open the file referenced by filename and store it as a GridFS file.
-  ## 
-  ## | gfs - the working GridFS
-  ## | filename - local filename relative to the process
-  ## | remotename - optional filename for use in the database
-  ## | contenttype - optional MIME type for this object
-  ## | returns - OK or ERROR.
-
-proc removeFilename*(gfs: var TGridfs, filename: cstring){.stdcall, 
-    importc: "gridfs_remove_filename", dynlib: mongodll.}
-  ## Removes the files referenced by filename from the db.
-
-proc findQuery*(gfs: var TGridfs, query: var TBson, gfile: var TGridFile): cint{.
-    stdcall, importc: "gridfs_find_query", dynlib: mongodll.}
-  ## Find the first file matching the provided query within the
-  ## GridFS files collection, and return the file as a GridFile.
-  ## Returns OK if successful, ERROR otherwise.
-  
-proc findFilename*(gfs: var TGridfs, filename: cstring, gfile: var TGridFile): cint{.
-    stdcall, importc: "gridfs_find_filename", dynlib: mongodll.}
-  ## Find the first file referenced by filename within the GridFS
-  ## and return it as a GridFile. Returns OK or ERROR.
-
-proc init*(gfs: var TGridfs, meta: var TBson, gfile: var TGridFile): cint{.
-    stdcall, importc: "gridfile_init", dynlib: mongodll.}
-  ## Initializes a GridFile containing the GridFS and file bson.
-
-proc destroy*(gfile: var TGridFile){.stdcall, importc: "gridfile_destroy", 
-                                     dynlib: mongodll.}
-  ## Destroys the GridFile.
-
-proc exists*(gfile: var TGridFile): TBsonBool{.stdcall, 
-    importc: "gridfile_exists", dynlib: mongodll.}
-  ## Returns whether or not the GridFile exists.
-
-proc getFilename*(gfile: var TGridFile): cstring{.stdcall, 
-    importc: "gridfile_get_filename", dynlib: mongodll.}
-  ## Returns the filename of GridFile.
-
-proc getChunksize*(gfile: var TGridFile): cint{.stdcall, 
-    importc: "gridfile_get_chunksize", dynlib: mongodll.}
-  ## Returns the size of the chunks of the GridFile.
-
-proc getContentlength*(gfile: var TGridFile): TOffset{.stdcall, 
-    importc: "gridfile_get_contentlength", dynlib: mongodll.}
-  ## Returns the length of GridFile's data.
-
-proc getContenttype*(gfile: var TGridFile): cstring{.stdcall, 
-    importc: "gridfile_get_contenttype", dynlib: mongodll.}
-  ## Returns the MIME type of the GridFile (nil if no type specified).
-
-proc getUploaddate*(gfile: var TGridFile): Tdate{.stdcall, 
-    importc: "gridfile_get_uploaddate", dynlib: mongodll.}
-  ## Returns the upload date of GridFile.
-
-proc getMd5*(gfile: var TGridFile): cstring {.stdcall, 
-    importc: "gridfile_get_md5", dynlib: mongodll.}
-  ## Returns the MD5 of GridFile.
-
-proc getField*(gfile: var TGridFile, name: cstring): cstring{.stdcall, 
-    importc: "gridfile_get_field", dynlib: mongodll.}
-  ## Returns the field in GridFile specified by name. Returns the data of the
-  ## field specified (nil if none exists).
-
-proc getBoolean*(gfile: var TGridFile, name: cstring): TBsonBool{.stdcall, 
-    importc: "gridfile_get_boolean", dynlib: mongodll.}
-  ## Returns a boolean field in GridFile specified by name.
-
-proc getMetadata*(gfile: var TGridFile, outp: var TBson){.stdcall, 
-    importc: "gridfile_get_metadata", dynlib: mongodll.}
-  ## Returns the metadata of GridFile (an empty bson is returned if none
-  ## exists).
-
-proc getNumchunks*(gfile: var TGridFile): cint{.stdcall, 
-    importc: "gridfile_get_numchunks", dynlib: mongodll.}
-  ## Returns the number of chunks in the GridFile.
-
-proc getChunk*(gfile: var TGridFile, n: cint, outp: var TBson){.stdcall, 
-    importc: "gridfile_get_chunk", dynlib: mongodll.}
-  ## Returns chunk `n` of GridFile.
-
-proc getChunks*(gfile: var TGridFile, start: cint, size: cint): ptr TCursor{.
-    stdcall, importc: "gridfile_get_chunks", dynlib: mongodll.}
-  ## Returns a mongo_cursor of `size` chunks starting with chunk `start`.
-  ## The cursor must be destroyed after use.
-
-proc writeFile*(gfile: ptr TGridFile, stream: TFile): TOffset{.stdcall, 
-    importc: "gridfile_write_file", dynlib: mongodll.}
-  ## Writes the GridFile to a stream.
-
-proc read*(gfile: var TGridFile, size: TOffset, buf: cstring): TOffset{.stdcall, 
-    importc: "gridfile_read", dynlib: mongodll.}
-  ## Reads length bytes from the GridFile to a buffer
-  ## and updates the position in the file.
-  ## (assumes the buffer is large enough)
-  ## (if size is greater than EOF gridfile_read reads until EOF).
-  ## Returns the number of bytes read.
-
-proc seek*(gfile: var TGridFile, offset: TOffset): TOffset{.stdcall, 
-    importc: "gridfile_seek", dynlib: mongodll.}
-  ## Updates the position in the file
-  ## (If the offset goes beyond the contentlength,
-  ## the position is updated to the end of the file.)
-  ## Returns the offset location
diff --git a/lib/wrappers/zip/zlib.nim b/lib/wrappers/zip/zlib.nim
index c4c6ac071..f505b95a7 100644
--- a/lib/wrappers/zip/zlib.nim
+++ b/lib/wrappers/zip/zlib.nim
@@ -7,7 +7,7 @@ when defined(windows):
 elif defined(macosx):
   const libz = "libz.dylib"
 else:
-  const libz = "libz.so"
+  const libz = "libz.so.1"
 
 type
   Uint* = int32
@@ -134,6 +134,7 @@ proc gzerror*(thefile: gzFile, errnum: var int32): pbytef{.cdecl, dynlib: libz,
     importc: "gzerror".}
 proc adler32*(adler: uLong, buf: pbytef, length: uInt): uLong{.cdecl, 
     dynlib: libz, importc: "adler32".}
+  ## **Warning**: Adler-32 requires at least a few hundred bytes to get rolling.
 proc crc32*(crc: uLong, buf: pbytef, length: uInt): uLong{.cdecl, dynlib: libz, 
     importc: "crc32".}
 proc deflateInitu*(strm: var TZStream, level: int32, version: cstring, 
diff --git a/lib/wrappers/zmq.nim b/lib/wrappers/zmq.nim
index 4e658028e..9826ab813 100644
--- a/lib/wrappers/zmq.nim
+++ b/lib/wrappers/zmq.nim
@@ -299,12 +299,12 @@ proc open*(address: string, server: bool, mode: TConnectionMode = conDEALER,
   else:
     if connect(result.s, address) != 0'i32: zmqError()
   
-proc close*(c: var TConnection) =
+proc close*(c: TConnection) =
   ## closes the connection.
   if close(c.s) != 0'i32: zmqError()
   if term(c.c) != 0'i32: zmqError()
   
-proc send*(c: var TConnection, msg: string) =
+proc send*(c: TConnection, msg: string) =
   ## sends a message over the connection.
   var m: TMsg
   if msg_init(m, msg.len) != 0'i32: zmqError()
@@ -312,7 +312,7 @@ proc send*(c: var TConnection, msg: string) =
   if send(c.s, m, 0'i32) != 0'i32: zmqError()
   discard msg_close(m)
   
-proc receive*(c: var TConnection): string =
+proc receive*(c: TConnection): string =
   ## receives a message from a connection.
   var m: TMsg
   if msg_init(m) != 0'i32: zmqError()
@@ -320,4 +320,3 @@ proc receive*(c: var TConnection): string =
   result = newString(msg_size(m))
   copyMem(addr(result[0]), msg_data(m), result.len)
   discard msg_close(m)
-