summary refs log tree commit diff stats
path: root/lib/pure
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pure')
-rw-r--r--lib/pure/actors.nim2
-rw-r--r--lib/pure/algorithm.nim14
-rw-r--r--lib/pure/asyncdispatch.nim11
-rw-r--r--lib/pure/asyncftpclient.nim6
-rw-r--r--lib/pure/asynchttpserver.nim2
-rw-r--r--lib/pure/asyncio.nim98
-rw-r--r--lib/pure/asyncnet.nim2
-rw-r--r--lib/pure/collections/LockFreeHash.nim2
-rw-r--r--lib/pure/collections/critbits.nim13
-rw-r--r--lib/pure/collections/intsets.nim79
-rw-r--r--lib/pure/collections/sequtils.nim24
-rw-r--r--lib/pure/collections/sets.nim352
-rw-r--r--lib/pure/collections/tables.nim83
-rw-r--r--lib/pure/concurrency/cpuload.nim2
-rw-r--r--lib/pure/concurrency/threadpool.nim2
-rw-r--r--lib/pure/cookies.nim10
-rw-r--r--lib/pure/encodings.nim2
-rw-r--r--lib/pure/fenv.nim2
-rw-r--r--lib/pure/fsmonitor.nim2
-rw-r--r--lib/pure/ftpclient.nim54
-rw-r--r--lib/pure/gentabs.nim21
-rw-r--r--lib/pure/htmlgen.nim9
-rw-r--r--lib/pure/htmlparser.nim2
-rw-r--r--lib/pure/httpclient.nim12
-rw-r--r--lib/pure/httpserver.nim2
-rw-r--r--lib/pure/json.nim128
-rw-r--r--lib/pure/logging.nim70
-rw-r--r--lib/pure/marshal.nim2
-rw-r--r--lib/pure/math.nim11
-rw-r--r--lib/pure/mersenne.nim2
-rw-r--r--lib/pure/mimetypes.nim4
-rw-r--r--lib/pure/oids.nim2
-rw-r--r--lib/pure/os.nim9
-rw-r--r--lib/pure/osproc.nim16
-rw-r--r--lib/pure/parsecsv.nim2
-rw-r--r--lib/pure/parsesql.nim2
-rw-r--r--lib/pure/parseutils.nim8
-rw-r--r--lib/pure/parsexml.nim2
-rw-r--r--lib/pure/pegs.nim46
-rw-r--r--lib/pure/rationals.nim20
-rw-r--r--lib/pure/rawsockets.nim7
-rw-r--r--lib/pure/redis.nim2
-rw-r--r--lib/pure/romans.nim9
-rw-r--r--lib/pure/ropes.nim168
-rw-r--r--lib/pure/selectors.nim2
-rw-r--r--lib/pure/smtp.nim4
-rw-r--r--lib/pure/strutils.nim56
-rw-r--r--lib/pure/subexes.nim18
-rw-r--r--lib/pure/terminal.nim2
-rw-r--r--lib/pure/times.nim154
-rw-r--r--lib/pure/unicode.nim1930
-rw-r--r--lib/pure/unidecode/unidecode.nim2
-rw-r--r--lib/pure/xmldom.nim16
-rw-r--r--lib/pure/xmldomparser.nim2
-rw-r--r--lib/pure/xmlparser.nim2
-rw-r--r--lib/pure/xmltree.nim3
56 files changed, 1864 insertions, 1645 deletions
diff --git a/lib/pure/actors.nim b/lib/pure/actors.nim
index 8c61ce7df..294c24741 100644
--- a/lib/pure/actors.nim
+++ b/lib/pure/actors.nim
@@ -221,7 +221,7 @@ proc spawn*[TIn](p: var TActorPool[TIn, void], input: TIn,
   setupTask()
   schedule()
   
-when isMainModule:
+when not defined(testing) and isMainModule:
   var
     a: TActorPool[int, void]
   createActorPool(a)
diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim
index 08d224dfd..f7ccb9234 100644
--- a/lib/pure/algorithm.nim
+++ b/lib/pure/algorithm.nim
@@ -24,7 +24,7 @@ proc `*`*(x: int, order: SortOrder): int {.inline.} =
   var y = order.ord - 1
   result = (x xor y) - y
 
-proc reverse*[T](a: var openArray[T], first, last: int) =
+proc reverse*[T](a: var openArray[T], first, last: Natural) =
   ## reverses the array ``a[first..last]``.
   var x = first
   var y = last
@@ -37,11 +37,11 @@ proc reverse*[T](a: var openArray[T]) =
   ## reverses the array `a`.
   reverse(a, 0, a.high)
 
-proc reversed*[T](a: openArray[T], first, last: int): seq[T] =
+proc reversed*[T](a: openArray[T], first, last: Natural): seq[T] =
   ## returns the reverse of the array `a[first..last]`.
   result = newSeq[T](last - first + 1)
-  var x = first
-  var y = last
+  var x = first.int
+  var y = last.int
   while x <= last:
     result[x] = a[y]
     dec(y)
@@ -253,16 +253,16 @@ proc product*[T](x: openArray[seq[T]]): seq[seq[T]] =
   while true:
     while indexes[index] == -1:
       indexes[index] = initial[index]
-      index +=1
+      index += 1
       if index == x.len: return
-      indexes[index] -=1
+      indexes[index] -= 1
     for ni, i in indexes:
       next[ni] = x[ni][i]
     var res: seq[T]
     shallowCopy(res, next)
     result.add(res)
     index = 0
-    indexes[index] -=1
+    indexes[index] -= 1
 
 proc nextPermutation*[T](x: var openarray[T]): bool {.discardable.} =
   ## Calculates the next lexicographic permutation, directly modifying ``x``.
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 8e0ac8d21..27f77cef2 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -841,6 +841,8 @@ else:
   proc newAsyncRawSocket*(domain: cint, typ: cint, protocol: cint): TAsyncFD =
     result = newRawSocket(domain, typ, protocol).TAsyncFD
     result.SocketHandle.setBlocking(false)
+    when defined(macosx):
+        result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
     register(result)
 
   proc newAsyncRawSocket*(domain: Domain = AF_INET,
@@ -848,6 +850,8 @@ else:
                protocol: Protocol = IPPROTO_TCP): TAsyncFD =
     result = newRawSocket(domain, typ, protocol).TAsyncFD
     result.SocketHandle.setBlocking(false)
+    when defined(macosx):
+        result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
     register(result)
 
   proc closeSocket*(sock: TAsyncFD) =
@@ -959,7 +963,6 @@ else:
       result = true
       let res = recv(sock.SocketHandle, addr readBuffer[0], size.cint,
                      flags.toOSFlags())
-      #echo("recv cb res: ", res)
       if res < 0:
         let lastError = osLastError()
         if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}:
@@ -1273,7 +1276,7 @@ proc processBody(node, retFutureSym: NimNode,
   else: discard
 
   for i in 0 .. <result.len:
-    result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, tryStmt)
+    result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, nil)
 
 proc getName(node: NimNode): string {.compileTime.} =
   case node.kind
@@ -1378,8 +1381,8 @@ macro async*(prc: stmt): stmt {.immediate.} =
   result[6] = outerProcBody
 
   #echo(treeRepr(result))
-  if prc[0].getName == "test3":
-    echo(toStrLit(result))
+  #if prc[0].getName == "test":
+  #  echo(toStrLit(result))
 
 proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
   ## Reads a line of data from ``socket``. Returned future will complete once
diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim
index 8558ad10d..daf69d59f 100644
--- a/lib/pure/asyncftpclient.nim
+++ b/lib/pure/asyncftpclient.nim
@@ -61,8 +61,8 @@ proc pasv(ftp: AsyncFtpClient) {.async.} =
   assertReply(pasvMsg, "227")
   var betweenParens = captureBetween(pasvMsg.string, '(', ')')
   var nums = betweenParens.split(',')
-  var ip = nums[0.. -3]
-  var port = nums[-2.. -1]
+  var ip = nums[0.. ^3]
+  var port = nums[^2.. ^1]
   var properPort = port[0].parseInt()*256+port[1].parseInt()
   await ftp.dsock.connect(ip.join("."), Port(properPort.toU16))
   ftp.dsockConnected = true
@@ -300,7 +300,7 @@ proc newAsyncFtpClient*(address: string, port = Port(21),
   result.dsockConnected = false
   result.csock = newAsyncSocket()
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test")
   proc main(ftp: AsyncFtpClient) {.async.} =
     await ftp.connect()
diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim
index 52de9531e..f7a2b693f 100644
--- a/lib/pure/asynchttpserver.nim
+++ b/lib/pure/asynchttpserver.nim
@@ -263,7 +263,7 @@ proc close*(server: AsyncHttpServer) =
   ## Terminates the async http server instance.
   server.socket.close()
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   proc main =
     var server = newAsyncHttpServer()
     proc cb(req: Request) {.async.} =
diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim
index 6a7cbe396..6ae2c608b 100644
--- a/lib/pure/asyncio.nim
+++ b/lib/pure/asyncio.nim
@@ -18,8 +18,8 @@ import sockets, os
 ## This module implements an asynchronous event loop together with asynchronous
 ## sockets which use this event loop.
 ## It is akin to Python's asyncore module. Many modules that use sockets
-## have an implementation for this module, those modules should all have a 
-## ``register`` function which you should use to add the desired objects to a 
+## have an implementation for this module, those modules should all have a
+## ``register`` function which you should use to add the desired objects to a
 ## dispatcher which you created so
 ## that you can receive the events associated with that module's object.
 ##
@@ -27,19 +27,19 @@ import sockets, os
 ## function in a while loop.
 ##
 ## **Note:** Most modules have tasks which need to be ran regularly, this is
-## why you should not call ``poll`` with a infinite timeout, or even a 
+## why you should not call ``poll`` with a infinite timeout, or even a
 ## very long one. In most cases the default timeout is fine.
 ##
 ## **Note:** This module currently only supports select(), this is limited by
 ## FD_SETSIZE, which is usually 1024. So you may only be able to use 1024
 ## sockets at a time.
-## 
+##
 ## Most (if not all) modules that use asyncio provide a userArg which is passed
 ## on with the events. The type that you set userArg to must be inheriting from
 ## ``RootObj``!
 ##
-## **Note:** If you want to provide async ability to your module please do not 
-## use the ``Delegate`` object, instead use ``AsyncSocket``. It is possible 
+## **Note:** If you want to provide async ability to your module please do not
+## use the ``Delegate`` object, instead use ``AsyncSocket``. It is possible
 ## that in the future this type's fields will not be exported therefore breaking
 ## your code.
 ##
@@ -59,11 +59,11 @@ import sockets, os
 ## socket which will give you the client which is connecting. You should then
 ## set any events that you want to use on that client and add it to your dispatcher
 ## using the ``register`` procedure.
-## 
+##
 ## An example ``handleAccept`` follows:
-## 
+##
 ## .. code-block:: nim
-##   
+##
 ##    var disp = newDispatcher()
 ##    ...
 ##    proc handleAccept(s: AsyncSocket) =
@@ -74,7 +74,7 @@ import sockets, os
 ##      client.handleRead = ...
 ##      disp.register(client)
 ##    ...
-## 
+##
 ## For client sockets you should only be interested in the ``handleRead`` and
 ## ``handleConnect`` events. The former gets called whenever the socket has
 ## received messages and can be read from and the latter gets called whenever
@@ -83,14 +83,14 @@ import sockets, os
 ##
 ## Getting a blocking client from an AsyncSocket
 ## =============================================
-## 
+##
 ## If you need a asynchronous server socket but you wish to process the clients
 ## synchronously then you can use the ``getSocket`` converter to get
 ## a ``Socket`` from the ``AsyncSocket`` object, this can then be combined
 ## with ``accept`` like so:
 ##
 ## .. code-block:: nim
-##    
+##
 ##    proc handleAccept(s: AsyncSocket) =
 ##      var client: Socket
 ##      getSocket(s).accept(client)
@@ -113,11 +113,11 @@ type
     handleWrite*: proc (h: RootRef) {.nimcall, gcsafe.}
     handleError*: proc (h: RootRef) {.nimcall, gcsafe.}
     hasDataBuffered*: proc (h: RootRef): bool {.nimcall, gcsafe.}
-    
+
     open*: bool
     task*: proc (h: RootRef) {.nimcall, gcsafe.}
     mode*: FileMode
-    
+
   Delegate* = ref DelegateObj
 
   Dispatcher* = ref DispatcherObj
@@ -144,7 +144,7 @@ type
     deleg: Delegate
 
   SocketStatus* = enum
-    SockIdle, SockConnecting, SockConnected, SockListening, SockClosed, 
+    SockIdle, SockConnecting, SockConnected, SockListening, SockClosed,
     SockUDPBound
 
 {.deprecated: [TDelegate: DelegateObj, PDelegate: Delegate,
@@ -176,8 +176,8 @@ proc newAsyncSocket(): AsyncSocket =
   result.lineBuffer = "".TaintedString
   result.sendBuffer = ""
 
-proc asyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM, 
-                  protocol: Protocol = IPPROTO_TCP, 
+proc asyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
+                  protocol: Protocol = IPPROTO_TCP,
                   buffered = true): AsyncSocket =
   ## Initialises an AsyncSocket object. If a socket cannot be initialised
   ## EOS is raised.
@@ -236,7 +236,7 @@ proc asyncSockHandleWrite(h: RootRef) =
     if AsyncSocket(h).socket.isSSL and not
          AsyncSocket(h).socket.gotHandshake:
       return
-  
+
   if AsyncSocket(h).info == SockConnecting:
     AsyncSocket(h).handleConnect(AsyncSocket(h))
     AsyncSocket(h).info = SockConnected
@@ -256,10 +256,10 @@ proc asyncSockHandleWrite(h: RootRef) =
           # do nothing instead.
           discard
         elif bytesSent != sock.sendBuffer.len:
-          sock.sendBuffer = sock.sendBuffer[bytesSent .. -1]
+          sock.sendBuffer = sock.sendBuffer[bytesSent .. ^1]
         elif bytesSent == sock.sendBuffer.len:
           sock.sendBuffer = ""
-        
+
         if AsyncSocket(h).handleWrite != nil:
           AsyncSocket(h).handleWrite(AsyncSocket(h))
       except OSError:
@@ -284,7 +284,7 @@ when defined(ssl):
       else:
         # handshake will set socket's ``sslNoHandshake`` field.
         discard AsyncSocket(h).socket.handshake()
-        
+
 
 proc asyncSockTask(h: RootRef) =
   when defined(ssl):
@@ -377,9 +377,9 @@ proc acceptAddr*(server: AsyncSocket, client: var AsyncSocket,
 
   if c == invalidSocket: raiseSocketError(server.socket)
   c.setBlocking(false) # TODO: Needs to be tested.
-  
+
   # deleg.open is set in ``toDelegate``.
-  
+
   client.socket = c
   client.lineBuffer = "".TaintedString
   client.sendBuffer = ""
@@ -393,7 +393,7 @@ proc accept*(server: AsyncSocket, client: var AsyncSocket) =
 proc acceptAddr*(server: AsyncSocket): tuple[sock: AsyncSocket,
                                               address: string] {.deprecated.} =
   ## Equivalent to ``sockets.acceptAddr``.
-  ## 
+  ##
   ## **Deprecated since version 0.9.0:** Please use the function above.
   var client = newAsyncSocket()
   var address: string = ""
@@ -441,17 +441,17 @@ proc isConnected*(s: AsyncSocket): bool =
   ## Determines whether ``s`` is connected.
   return s.info == SockConnected
 proc isListening*(s: AsyncSocket): bool =
-  ## Determines whether ``s`` is listening for incoming connections.  
+  ## Determines whether ``s`` is listening for incoming connections.
   return s.info == SockListening
 proc isConnecting*(s: AsyncSocket): bool =
-  ## Determines whether ``s`` is connecting.  
+  ## Determines whether ``s`` is connecting.
   return s.info == SockConnecting
 proc isClosed*(s: AsyncSocket): bool =
   ## Determines whether ``s`` has been closed.
   return s.info == SockClosed
 proc isSendDataBuffered*(s: AsyncSocket): bool =
   ## Determines whether ``s`` has data waiting to be sent, i.e. whether this
-  ## socket's sendBuffer contains data. 
+  ## socket's sendBuffer contains data.
   return s.sendBuffer.len != 0
 
 proc setHandleWrite*(s: AsyncSocket,
@@ -550,7 +550,7 @@ proc send*(sock: AsyncSocket, data: string) =
     sock.sendBuffer.add(data)
     sock.deleg.mode = fmReadWrite
   elif bytesSent != data.len:
-    sock.sendBuffer.add(data[bytesSent .. -1])
+    sock.sendBuffer.add(data[bytesSent .. ^1])
     sock.deleg.mode = fmReadWrite
 
 proc timeValFromMilliseconds(timeout = 500): Timeval =
@@ -561,10 +561,10 @@ proc timeValFromMilliseconds(timeout = 500): Timeval =
 
 proc createFdSet(fd: var TFdSet, s: seq[Delegate], m: var int) =
   FD_ZERO(fd)
-  for i in items(s): 
+  for i in items(s):
     m = max(m, int(i.fd))
     FD_SET(i.fd, fd)
-   
+
 proc pruneSocketSet(s: var seq[Delegate], fd: var TFdSet) =
   var i = 0
   var L = s.len
@@ -576,16 +576,16 @@ proc pruneSocketSet(s: var seq[Delegate], fd: var TFdSet) =
       inc(i)
   setLen(s, L)
 
-proc select(readfds, writefds, exceptfds: var seq[Delegate], 
+proc select(readfds, writefds, exceptfds: var seq[Delegate],
              timeout = 500): int =
   var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
-  
+
   var rd, wr, ex: TFdSet
   var m = 0
   createFdSet(rd, readfds, m)
   createFdSet(wr, writefds, m)
   createFdSet(ex, exceptfds, m)
-  
+
   if timeout != -1:
     result = int(select(cint(m+1), addr(rd), addr(wr), addr(ex), addr(tv)))
   else:
@@ -599,7 +599,7 @@ proc poll*(d: Dispatcher, timeout: int = 500): bool =
   ## This function checks for events on all the delegates in the `PDispatcher`.
   ## It then proceeds to call the correct event handler.
   ##
-  ## This function returns ``True`` if there are file descriptors that are still 
+  ## This function returns ``True`` if there are file descriptors that are still
   ## open, otherwise ``False``. File descriptors that have been
   ## closed are immediately removed from the dispatcher automatically.
   ##
@@ -611,7 +611,7 @@ proc poll*(d: Dispatcher, timeout: int = 500): bool =
   var readDg, writeDg, errorDg: seq[Delegate] = @[]
   var len = d.delegates.len
   var dc = 0
-  
+
   while dc < len:
     let deleg = d.delegates[dc]
     if (deleg.mode != fmWrite or deleg.mode != fmAppend) and deleg.open:
@@ -625,20 +625,20 @@ proc poll*(d: Dispatcher, timeout: int = 500): bool =
       # File/socket has been closed. Remove it from dispatcher.
       d.delegates[dc] = d.delegates[len-1]
       dec len
-      
+
   d.delegates.setLen(len)
-  
+
   var hasDataBufferedCount = 0
   for d in d.delegates:
     if d.hasDataBuffered(d.deleVal):
       hasDataBufferedCount.inc()
       d.handleRead(d.deleVal)
   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
-  
+
   if select(readDg, writeDg, errorDg, timeout) != 0:
     for i in 0..len(d.delegates)-1:
       if i > len(d.delegates)-1: break # One delegate might've been removed.
@@ -651,7 +651,7 @@ proc poll*(d: Dispatcher, timeout: int = 500): bool =
         deleg.handleWrite(deleg.deleVal)
       if deleg notin errorDg:
         deleg.handleError(deleg.deleVal)
-  
+
   # Execute tasks
   for i in items(d.delegates):
     i.task(i.deleVal)
@@ -660,11 +660,11 @@ proc len*(disp: Dispatcher): int =
   ## Retrieves the amount of delegates in ``disp``.
   return disp.delegates.len
 
-when isMainModule:
+when not defined(testing) and isMainModule:
 
   proc testConnect(s: AsyncSocket, no: int) =
     echo("Connected! " & $no)
-  
+
   proc testRead(s: AsyncSocket, no: int) =
     echo("Reading! " & $no)
     var data = ""
@@ -682,31 +682,31 @@ when isMainModule:
     var address = ""
     s.acceptAddr(client, address)
     echo("Accepted ", address)
-    client.handleRead = 
+    client.handleRead =
       proc (s: AsyncSocket) =
         testRead(s, 2)
     disp.register(client)
 
   proc main =
     var d = newDispatcher()
-    
+
     var s = asyncSocket()
     s.connect("amber.tenthbit.net", Port(6667))
-    s.handleConnect = 
+    s.handleConnect =
       proc (s: AsyncSocket) =
         testConnect(s, 1)
-    s.handleRead = 
+    s.handleRead =
       proc (s: AsyncSocket) =
         testRead(s, 1)
     d.register(s)
-    
+
     var server = asyncSocket()
     server.handleAccept =
-      proc (s: AsyncSocket) = 
+      proc (s: AsyncSocket) =
         testAccept(s, d, 78)
     server.bindAddr(Port(5555))
     server.listen()
     d.register(server)
-    
+
     while d.poll(-1): discard
   main()
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index fa67b212a..7d23ad4b7 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -605,7 +605,7 @@ proc isClosed*(socket: AsyncSocket): bool =
   ## Determines whether the socket has been closed.
   return socket.closed
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   type
     TestCases = enum
       HighClient, LowClient, LowServer
diff --git a/lib/pure/collections/LockFreeHash.nim b/lib/pure/collections/LockFreeHash.nim
index c3954468a..0df97c685 100644
--- a/lib/pure/collections/LockFreeHash.nim
+++ b/lib/pure/collections/LockFreeHash.nim
@@ -525,7 +525,7 @@ proc get*[K,V](table: var PConcTable[K,V], key: var K): V =
 
 
 #Tests ----------------------------
-when isMainModule:
+when not defined(testing) and isMainModule:
   import locks, times, mersenne
   
   const 
diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim
index 3d10e39aa..7e3f23851 100644
--- a/lib/pure/collections/critbits.nim
+++ b/lib/pure/collections/critbits.nim
@@ -286,18 +286,19 @@ proc `$`*[T](c: CritBitTree[T]): string =
     result.add("}")
 
 when isMainModule:
+  import sequtils
+
   var r: CritBitTree[void]
   r.incl "abc"
   r.incl "xyz"
   r.incl "def"
   r.incl "definition"
   r.incl "prefix"
+
   doAssert r.contains"def"
-  #r.del "def"
 
-  for w in r.items:
-    echo w
-    
-  for w in r.itemsWithPrefix("de"):
-    echo w
+  r.excl "def"
+
+  assert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"]
 
+  assert toSeq(r.itemsWithPrefix("de")) == @["definition"]
diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim
index 7520e6e46..25f6616a6 100644
--- a/lib/pure/collections/intsets.nim
+++ b/lib/pure/collections/intsets.nim
@@ -14,12 +14,12 @@
 ## copy; use ``assign`` to get a deep copy.
 
 import
-  os, hashes, math
+  hashes, math
 
 type
   BitScalar = int
 
-const 
+const
   InitIntSetSize = 8         # must be a power of two!
   TrunkShift = 9
   BitsPerTrunk = 1 shl TrunkShift # needs to be a power of 2 and
@@ -31,11 +31,11 @@ const
 
 type
   PTrunk = ref TTrunk
-  TTrunk {.final.} = object 
+  TTrunk {.final.} = object
     next: PTrunk             # all nodes are connected with this pointer
     key: int                 # start address at bit 0
     bits: array[0..IntsPerTrunk - 1, BitScalar] # a bit vector
-  
+
   TTrunkSeq = seq[PTrunk]
   IntSet* = object ## an efficient set of 'int' implemented as a sparse bit set
     counter, max: int
@@ -44,42 +44,42 @@ type
 
 {.deprecated: [TIntSet: IntSet].}
 
-proc mustRehash(length, counter: int): bool {.inline.} = 
+proc mustRehash(length, counter: int): bool {.inline.} =
   assert(length > counter)
   result = (length * 2 < counter * 3) or (length - counter < 4)
 
-proc nextTry(h, maxHash: THash): THash {.inline.} = 
-  result = ((5 * h) + 1) and maxHash 
+proc nextTry(h, maxHash: THash): THash {.inline.} =
+  result = ((5 * h) + 1) and maxHash
 
-proc intSetGet(t: IntSet, key: int): PTrunk = 
+proc intSetGet(t: IntSet, key: int): PTrunk =
   var h = key and t.max
-  while t.data[h] != nil: 
-    if t.data[h].key == key: 
+  while t.data[h] != nil:
+    if t.data[h].key == key:
       return t.data[h]
     h = nextTry(h, t.max)
   result = nil
 
-proc intSetRawInsert(t: IntSet, data: var TTrunkSeq, desc: PTrunk) = 
+proc intSetRawInsert(t: IntSet, data: var TTrunkSeq, desc: PTrunk) =
   var h = desc.key and t.max
-  while data[h] != nil: 
+  while data[h] != nil:
     assert(data[h] != desc)
     h = nextTry(h, t.max)
   assert(data[h] == nil)
   data[h] = desc
 
-proc intSetEnlarge(t: var IntSet) = 
+proc intSetEnlarge(t: var IntSet) =
   var n: TTrunkSeq
   var oldMax = t.max
   t.max = ((t.max + 1) * 2) - 1
   newSeq(n, t.max + 1)
-  for i in countup(0, oldMax): 
+  for i in countup(0, oldMax):
     if t.data[i] != nil: intSetRawInsert(t, n, t.data[i])
   swap(t.data, n)
 
-proc intSetPut(t: var IntSet, key: int): PTrunk = 
+proc intSetPut(t: var IntSet, key: int): PTrunk =
   var h = key and t.max
-  while t.data[h] != nil: 
-    if t.data[h].key == key: 
+  while t.data[h] != nil:
+    if t.data[h].key == key:
       return t.data[h]
     h = nextTry(h, t.max)
   if mustRehash(t.max + 1, t.counter): intSetEnlarge(t)
@@ -94,43 +94,43 @@ proc intSetPut(t: var IntSet, key: int): PTrunk =
   t.data[h] = result
 
 proc contains*(s: IntSet, key: int): bool =
-  ## returns true iff `key` is in `s`.  
+  ## returns true iff `key` is in `s`.
   var t = intSetGet(s, `shr`(key, TrunkShift))
-  if t != nil: 
+  if t != nil:
     var u = key and TrunkMask
     result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
-  else: 
+  else:
     result = false
-  
-proc incl*(s: var IntSet, key: int) = 
+
+proc incl*(s: var IntSet, key: int) =
   ## includes an element `key` in `s`.
   var t = intSetPut(s, `shr`(key, TrunkShift))
   var u = key and TrunkMask
   t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
       `shl`(1, u and IntMask)
 
-proc excl*(s: var IntSet, key: int) = 
+proc excl*(s: var IntSet, key: int) =
   ## excludes `key` from the set `s`.
   var t = intSetGet(s, `shr`(key, TrunkShift))
-  if t != nil: 
+  if t != nil:
     var u = key and TrunkMask
     t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] and
         not `shl`(1, u and IntMask)
 
-proc containsOrIncl*(s: var IntSet, key: int): bool = 
+proc containsOrIncl*(s: var IntSet, key: int): bool =
   ## returns true if `s` contains `key`, otherwise `key` is included in `s`
   ## and false is returned.
   var t = intSetGet(s, `shr`(key, TrunkShift))
-  if t != nil: 
+  if t != nil:
     var u = key and TrunkMask
     result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
-    if not result: 
+    if not result:
       t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
           `shl`(1, u and IntMask)
-  else: 
+  else:
     incl(s, key)
     result = false
-    
+
 proc initIntSet*: IntSet =
   ## creates a new int set that is empty.
   newSeq(result.data, InitIntSetSize)
@@ -140,14 +140,14 @@ proc initIntSet*: IntSet =
 
 proc assign*(dest: var IntSet, src: IntSet) =
   ## copies `src` to `dest`. `dest` does not need to be initialized by
-  ## `initIntSet`. 
+  ## `initIntSet`.
   dest.counter = src.counter
   dest.max = src.max
   newSeq(dest.data, src.data.len)
-  
+
   var it = src.head
   while it != nil:
-    
+
     var h = it.key and dest.max
     while dest.data[h] != nil: h = nextTry(h, dest.max)
     assert(dest.data[h] == nil)
@@ -168,7 +168,7 @@ iterator items*(s: IntSet): int {.inline.} =
   while r != nil:
     var i = 0
     while i <= high(r.bits):
-      var w = r.bits[i] 
+      var w = r.bits[i]
       # taking a copy of r.bits[i] here is correct, because
       # modifying operations are not allowed during traversation
       var j = 0
@@ -198,14 +198,21 @@ proc empty*(s: IntSet): bool {.inline, deprecated.} =
   result = s.counter == 0
 
 when isMainModule:
+  import sequtils, algorithm
+
   var x = initIntSet()
   x.incl(1)
   x.incl(2)
   x.incl(7)
   x.incl(1056)
-  for e in items(x): echo e
 
-  var y: TIntSet
+  var xs = toSeq(items(x))
+  xs.sort(cmp[int])
+  assert xs == @[1, 2, 7, 1056]
+
+  var y: IntSet
   assign(y, x)
-  for e in items(y): echo e
+  var ys = toSeq(items(y))
+  ys.sort(cmp[int])
+  assert ys == @[1, 2, 7, 1056]
 
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index edb904cc6..e9cd2cb3c 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -81,7 +81,7 @@ proc deduplicate*[T](seq1: seq[T]): seq[T] =
     if not result.contains(itm): result.add(itm)
 
 {.deprecated: [distnct: deduplicate].}
-    
+
 proc zip*[S, T](seq1: seq[S], seq2: seq[T]): seq[tuple[a: S, b: T]] =
   ## Returns a new sequence with a combination of the two input sequences.
   ##
@@ -181,7 +181,7 @@ iterator filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): T =
   ##   for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
   ##     echo($n)
   ##   # echoes 4, 8, 4 in separate lines
-  for i in countup(0, len(seq1) -1):
+  for i in countup(0, len(seq1)-1):
     var item = seq1[i]
     if pred(item): yield seq1[i]
 
@@ -228,7 +228,7 @@ proc delete*[T](s: var seq[T], first=0, last=0) =
   ##   var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
   ##   dest.delete(3, 8)
   ##   assert outcome == dest
-  
+
   var i = first
   var j = last+1
   var newLen = len(s)-j+i
@@ -246,12 +246,12 @@ proc insert*[T](dest: var seq[T], src: openArray[T], pos=0) =
   ##
   ##.. code-block::
   ##   var dest = @[1,1,1,1,1,1,1,1]
-  ##   let 
+  ##   let
   ##     src = @[2,2,2,2,2,2]
   ##     outcome = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
   ##   dest.insert(src, 3)
   ##   assert dest == outcome
-  
+
   var j = len(dest) - 1
   var i = len(dest) + len(src) - 1
   dest.setLen(i + 1)
@@ -492,9 +492,8 @@ when isMainModule:
 
   block: # filter iterator test
     let numbers = @[1, 4, 5, 8, 9, 7, 4]
-    for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
-      echo($n)
-    # echoes 4, 8, 4 in separate lines
+    assert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) ==
+      @[4, 8, 4]
 
   block: # keepIf test
     var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
@@ -553,12 +552,12 @@ when isMainModule:
     var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
     dest.delete(3, 8)
     assert outcome == dest, """\
-    Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1] 
+    Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1]
     is [1,1,1,1,1,1,1,1]"""
 
   block: # insert tests
     var dest = @[1,1,1,1,1,1,1,1]
-    let 
+    let
       src = @[2,2,2,2,2,2]
       outcome = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
     dest.insert(src, 3)
@@ -610,10 +609,11 @@ when isMainModule:
     let
       a = @[1, 2, 3]
       b: seq[int] = @[]
-    
+
     doAssert a.repeat(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
     doAssert a.repeat(0) == @[]
     #doAssert a.repeat(-1) == @[] # will not compile!
     doAssert b.repeat(3) == @[]
 
-  echo "Finished doc tests"
+  when not defined(testing):
+    echo "Finished doc tests"
diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim
index 4a20d00a4..280e0eeba 100644
--- a/lib/pure/collections/sets.nim
+++ b/lib/pure/collections/sets.nim
@@ -114,7 +114,7 @@ proc mustRehash(length, counter: int): bool {.inline.} =
   assert(length > counter)
   result = (length * 2 < counter * 3) or (length - counter < 4)
 
-proc rightSize*(count: int): int {.inline.} =
+proc rightSize*(count: Natural): int {.inline.} =
   ## Return the value of `initialSize` to support `count` items.
   ##
   ## If more items are expected to be added, simply add that
@@ -798,177 +798,179 @@ proc `==`*[A](s, t: OrderedSet[A]): bool =
     g = nxg
   result = compared == s.counter
 
-proc testModule() =
-  ## Internal micro test to validate docstrings and such.
-  block isValidTest:
-    var options: HashSet[string]
-    proc savePreferences(options: HashSet[string]) =
-      assert options.isValid, "Pass an initialized set!"
-    options = initSet[string]()
-    options.savePreferences
-
-  block lenTest:
-    var values: HashSet[int]
-    assert(not values.isValid)
-    assert values.len == 0
-    assert values.card == 0
-
-  block setIterator:
-    type pair = tuple[a, b: int]
-    var a, b = initSet[pair]()
-    a.incl((2, 3))
-    a.incl((3, 2))
-    a.incl((2, 3))
-    for x, y in a.items:
-      b.incl((x - 2, y + 1))
-    assert a.len == b.card
-    assert a.len == 2
-    #echo b
-
-  block setContains:
-    var values = initSet[int]()
-    assert(not values.contains(2))
-    values.incl(2)
-    assert values.contains(2)
-    values.excl(2)
-    assert(not values.contains(2))
-
-    values.incl(4)
-    var others = toSet([6, 7])
-    values.incl(others)
-    assert values.len == 3
-
-    values.init
-    assert values.containsOrIncl(2) == false
-    assert values.containsOrIncl(2) == true
-    var
-      a = toSet([1, 2])
-      b = toSet([1])
-    b.incl(2)
-    assert a == b
-
-  block exclusions:
-    var s = toSet([2, 3, 6, 7])
-    s.excl(2)
-    s.excl(2)
-    assert s.len == 3
-
-    var
-      numbers = toSet([1, 2, 3, 4, 5])
-      even = toSet([2, 4, 6, 8])
-    numbers.excl(even)
-    #echo numbers
-    # --> {1, 3, 5}
-
-  block toSeqAndString:
-    var a = toSet([2, 4, 5])
-    var b = initSet[int]()
-    for x in [2, 4, 5]: b.incl(x)
-    assert($a == $b)
-    #echo a
-    #echo toSet(["no", "esc'aping", "is \" provided"])
-
-  #block orderedToSeqAndString:
-  #  echo toOrderedSet([2, 4, 5])
-  #  echo toOrderedSet(["no", "esc'aping", "is \" provided"])
-
-  block setOperations:
-    var
-      a = toSet(["a", "b"])
-      b = toSet(["b", "c"])
-      c = union(a, b)
-    assert c == toSet(["a", "b", "c"])
-    var d = intersection(a, b)
-    assert d == toSet(["b"])
-    var e = difference(a, b)
-    assert e == toSet(["a"])
-    var f = symmetricDifference(a, b)
-    assert f == toSet(["a", "c"])
-    assert d < a and d < b
-    assert((a < a) == false)
-    assert d <= a and d <= b
-    assert((a <= a))
-    # Alias test.
-    assert a + b == toSet(["a", "b", "c"])
-    assert a * b == toSet(["b"])
-    assert a - b == toSet(["a"])
-    assert a -+- b == toSet(["a", "c"])
-    assert disjoint(a, b) == false
-    assert disjoint(a, b - a) == true
-
-  block mapSet:
-    var a = toSet([1, 2, 3])
-    var b = a.map(proc (x: int): string = $x)
-    assert b == toSet(["1", "2", "3"])
-
-  block isValidTest:
-    var cards: OrderedSet[string]
-    proc saveTarotCards(cards: OrderedSet[string]) =
-      assert cards.isValid, "Pass an initialized set!"
-    cards = initOrderedSet[string]()
-    cards.saveTarotCards
-
-  block lenTest:
-    var values: OrderedSet[int]
-    assert(not values.isValid)
-    assert values.len == 0
-    assert values.card == 0
-
-  block setIterator:
-    type pair = tuple[a, b: int]
-    var a, b = initOrderedSet[pair]()
-    a.incl((2, 3))
-    a.incl((3, 2))
-    a.incl((2, 3))
-    for x, y in a.items:
-      b.incl((x - 2, y + 1))
-    assert a.len == b.card
-    assert a.len == 2
-
-  #block orderedSetIterator:
-  #  var a = initOrderedSet[int]()
-  #  for value in [9, 2, 1, 5, 1, 8, 4, 2]:
-  #    a.incl(value)
-  #  for value in a.items:
-  #    echo "Got ", value
-
-  block setContains:
-    var values = initOrderedSet[int]()
-    assert(not values.contains(2))
-    values.incl(2)
-    assert values.contains(2)
-
-  block toSeqAndString:
-    var a = toOrderedSet([2, 4, 5])
-    var b = initOrderedSet[int]()
-    for x in [2, 4, 5]: b.incl(x)
-    assert($a == $b)
-    assert(a == b) # https://github.com/Araq/Nimrod/issues/1413
-
-  block initBlocks:
-    var a: OrderedSet[int]
-    a.init(4)
-    a.incl(2)
-    a.init
-    assert a.len == 0 and a.isValid
-    a = initOrderedSet[int](4)
-    a.incl(2)
-    assert a.len == 1
-
-    var b: HashSet[int]
-    b.init(4)
-    b.incl(2)
-    b.init
-    assert b.len == 0 and b.isValid
-    b = initSet[int](4)
-    b.incl(2)
-    assert b.len == 1
-
-  for i in 0 .. 32:
-    var s = rightSize(i)
-    if s <= i or mustRehash(s, i):
-      echo "performance issue: rightSize() will not elide enlarge() at ", i
-
-  echo "Micro tests run successfully."
-
-when isMainModule and not defined(release): testModule()
+when isMainModule and not defined(release):
+  proc testModule() =
+    ## Internal micro test to validate docstrings and such.
+    block isValidTest:
+      var options: HashSet[string]
+      proc savePreferences(options: HashSet[string]) =
+        assert options.isValid, "Pass an initialized set!"
+      options = initSet[string]()
+      options.savePreferences
+
+    block lenTest:
+      var values: HashSet[int]
+      assert(not values.isValid)
+      assert values.len == 0
+      assert values.card == 0
+
+    block setIterator:
+      type pair = tuple[a, b: int]
+      var a, b = initSet[pair]()
+      a.incl((2, 3))
+      a.incl((3, 2))
+      a.incl((2, 3))
+      for x, y in a.items:
+        b.incl((x - 2, y + 1))
+      assert a.len == b.card
+      assert a.len == 2
+      #echo b
+
+    block setContains:
+      var values = initSet[int]()
+      assert(not values.contains(2))
+      values.incl(2)
+      assert values.contains(2)
+      values.excl(2)
+      assert(not values.contains(2))
+
+      values.incl(4)
+      var others = toSet([6, 7])
+      values.incl(others)
+      assert values.len == 3
+
+      values.init
+      assert values.containsOrIncl(2) == false
+      assert values.containsOrIncl(2) == true
+      var
+        a = toSet([1, 2])
+        b = toSet([1])
+      b.incl(2)
+      assert a == b
+
+    block exclusions:
+      var s = toSet([2, 3, 6, 7])
+      s.excl(2)
+      s.excl(2)
+      assert s.len == 3
+
+      var
+        numbers = toSet([1, 2, 3, 4, 5])
+        even = toSet([2, 4, 6, 8])
+      numbers.excl(even)
+      #echo numbers
+      # --> {1, 3, 5}
+
+    block toSeqAndString:
+      var a = toSet([2, 4, 5])
+      var b = initSet[int]()
+      for x in [2, 4, 5]: b.incl(x)
+      assert($a == $b)
+      #echo a
+      #echo toSet(["no", "esc'aping", "is \" provided"])
+
+    #block orderedToSeqAndString:
+    #  echo toOrderedSet([2, 4, 5])
+    #  echo toOrderedSet(["no", "esc'aping", "is \" provided"])
+
+    block setOperations:
+      var
+        a = toSet(["a", "b"])
+        b = toSet(["b", "c"])
+        c = union(a, b)
+      assert c == toSet(["a", "b", "c"])
+      var d = intersection(a, b)
+      assert d == toSet(["b"])
+      var e = difference(a, b)
+      assert e == toSet(["a"])
+      var f = symmetricDifference(a, b)
+      assert f == toSet(["a", "c"])
+      assert d < a and d < b
+      assert((a < a) == false)
+      assert d <= a and d <= b
+      assert((a <= a))
+      # Alias test.
+      assert a + b == toSet(["a", "b", "c"])
+      assert a * b == toSet(["b"])
+      assert a - b == toSet(["a"])
+      assert a -+- b == toSet(["a", "c"])
+      assert disjoint(a, b) == false
+      assert disjoint(a, b - a) == true
+
+    block mapSet:
+      var a = toSet([1, 2, 3])
+      var b = a.map(proc (x: int): string = $x)
+      assert b == toSet(["1", "2", "3"])
+
+    block isValidTest:
+      var cards: OrderedSet[string]
+      proc saveTarotCards(cards: OrderedSet[string]) =
+        assert cards.isValid, "Pass an initialized set!"
+      cards = initOrderedSet[string]()
+      cards.saveTarotCards
+
+    block lenTest:
+      var values: OrderedSet[int]
+      assert(not values.isValid)
+      assert values.len == 0
+      assert values.card == 0
+
+    block setIterator:
+      type pair = tuple[a, b: int]
+      var a, b = initOrderedSet[pair]()
+      a.incl((2, 3))
+      a.incl((3, 2))
+      a.incl((2, 3))
+      for x, y in a.items:
+        b.incl((x - 2, y + 1))
+      assert a.len == b.card
+      assert a.len == 2
+
+    #block orderedSetIterator:
+    #  var a = initOrderedSet[int]()
+    #  for value in [9, 2, 1, 5, 1, 8, 4, 2]:
+    #    a.incl(value)
+    #  for value in a.items:
+    #    echo "Got ", value
+
+    block setContains:
+      var values = initOrderedSet[int]()
+      assert(not values.contains(2))
+      values.incl(2)
+      assert values.contains(2)
+
+    block toSeqAndString:
+      var a = toOrderedSet([2, 4, 5])
+      var b = initOrderedSet[int]()
+      for x in [2, 4, 5]: b.incl(x)
+      assert($a == $b)
+      assert(a == b) # https://github.com/Araq/Nimrod/issues/1413
+
+    block initBlocks:
+      var a: OrderedSet[int]
+      a.init(4)
+      a.incl(2)
+      a.init
+      assert a.len == 0 and a.isValid
+      a = initOrderedSet[int](4)
+      a.incl(2)
+      assert a.len == 1
+
+      var b: HashSet[int]
+      b.init(4)
+      b.incl(2)
+      b.init
+      assert b.len == 0 and b.isValid
+      b = initSet[int](4)
+      b.incl(2)
+      assert b.len == 1
+
+    for i in 0 .. 32:
+      var s = rightSize(i)
+      if s <= i or mustRehash(s, i):
+        echo "performance issue: rightSize() will not elide enlarge() at ", i
+
+    when not defined(testing):
+      echo "Micro tests run successfully."
+
+  testModule()
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index feb965af3..232e52c89 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -128,7 +128,7 @@ proc mustRehash(length, counter: int): bool {.inline.} =
   assert(length > counter)
   result = (length * 2 < counter * 3) or (length - counter < 4)
 
-proc rightSize*(count: int): int {.inline.} =
+proc rightSize*(count: Natural): int {.inline.} =
   ## Return the value of `initialSize` to support `count` items.
   ##
   ## If more items are expected to be added, simply add that
@@ -192,7 +192,7 @@ proc `[]`*[A, B](t: Table[A, B], key: A): B =
 
 proc mget*[A, B](t: var Table[A, B], key: A): var B =
   ## retrieves the value at ``t[key]``. The value can be modified.
-  ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
+  ## If `key` is not in `t`, the ``KeyError`` exception is raised.
   var hc: THash
   var index = rawGet(t, key, hc)
   if index >= 0: result = t.data[index].val
@@ -314,7 +314,7 @@ proc initTable*[A, B](initialSize=64): Table[A, B] =
   result.counter = 0
   newSeq(result.data, initialSize)
 
-proc toTable*[A, B](pairs: openArray[(A, 
+proc toTable*[A, B](pairs: openArray[(A,
                     B)]): Table[A, B] =
   ## creates a new hash table that contains the given `pairs`.
   result = initTable[A, B](rightSize(pairs.len))
@@ -532,7 +532,7 @@ proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool =
   var hc: THash
   result = rawGet(t, key, hc) >= 0
 
-proc rawInsert[A, B](t: var OrderedTable[A, B], 
+proc rawInsert[A, B](t: var OrderedTable[A, B],
                      data: var OrderedKeyValuePairSeq[A, B],
                      key: A, val: B, hc: THash, h: THash) =
   rawInsertImpl()
@@ -584,7 +584,7 @@ proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] =
   result.last = -1
   newSeq(result.data, initialSize)
 
-proc toOrderedTable*[A, B](pairs: openArray[(A, 
+proc toOrderedTable*[A, B](pairs: openArray[(A,
                            B)]): OrderedTable[A, B] =
   ## creates a new ordered hash table that contains the given `pairs`.
   result = initOrderedTable[A, B](rightSize(pairs.len))
@@ -594,7 +594,7 @@ proc `$`*[A, B](t: OrderedTable[A, B]): string =
   ## The `$` operator for ordered hash tables.
   dollarImpl()
 
-proc sort*[A, B](t: var OrderedTable[A, B], 
+proc sort*[A, B](t: var OrderedTable[A, B],
                  cmp: proc (x,y: (A, B)): int) =
   ## sorts `t` according to `cmp`. This modifies the internal list
   ## that kept the insertion order, so insertion order is lost after this
@@ -617,7 +617,7 @@ proc sort*[A, B](t: var OrderedTable[A, B],
       while i < insize:
         inc(psize)
         q = t.data[q].next
-        if q < 0: break 
+        if q < 0: break
         inc(i)
       qsize = insize
       while psize > 0 or (qsize > 0 and q >= 0):
@@ -625,7 +625,7 @@ proc sort*[A, B](t: var OrderedTable[A, B],
           e = q; q = t.data[q].next; dec(qsize)
         elif qsize == 0 or q < 0:
           e = p; p = t.data[p].next; dec(psize)
-        elif cmp((t.data[p].key, t.data[p].val), 
+        elif cmp((t.data[p].key, t.data[p].val),
                  (t.data[q].key, t.data[q].val)) <= 0:
           e = p; p = t.data[p].next; dec(psize)
         else:
@@ -730,7 +730,7 @@ proc `$`*[A, B](t: OrderedTableRef[A, B]): string =
   ## The `$` operator for ordered hash tables.
   dollarImpl()
 
-proc sort*[A, B](t: OrderedTableRef[A, B], 
+proc sort*[A, B](t: OrderedTableRef[A, B],
                  cmp: proc (x,y: (A, B)): int) =
   ## sorts `t` according to `cmp`. This modifies the internal list
   ## that kept the insertion order, so insertion order is lost after this
@@ -848,7 +848,7 @@ proc `$`*[A](t: CountTable[A]): string =
   ## The `$` operator for count tables.
   dollarImpl()
 
-proc inc*[A](t: var CountTable[A], key: A, val = 1) = 
+proc inc*[A](t: var CountTable[A], key: A, val = 1) =
   ## increments `t[key]` by `val`.
   var index = rawGet(t, key)
   if index >= 0:
@@ -965,7 +965,7 @@ proc `$`*[A](t: CountTableRef[A]): string =
   ## The `$` operator for count tables.
   dollarImpl()
 
-proc inc*[A](t: CountTableRef[A], key: A, val = 1) = 
+proc inc*[A](t: CountTableRef[A], key: A, val = 1) =
   ## increments `t[key]` by `val`.
   t[].inc(key, val)
 
@@ -984,6 +984,22 @@ proc sort*[A](t: CountTableRef[A]) =
   ## `t` in the sorted order.
   t[].sort
 
+proc merge*[A](s: var CountTable[A], t: CountTable[A]) =
+  ## merges the second table into the first one
+  for key, value in t:
+    s.inc(key, value)
+
+proc merge*[A](s, t: CountTable[A]): CountTable[A] =
+  ## merges the two tables into a new one
+  result = initCountTable[A](nextPowerOfTwo(max(s.len, t.len)))
+  for table in @[s, t]:
+    for key, value in table:
+      result.inc(key, value)
+
+proc merge*[A](s, t: CountTableRef[A]) =
+  ## merges the second table into the first one
+  s[].merge(t[])
+
 when isMainModule:
   type
     Person = object
@@ -1012,3 +1028,48 @@ when isMainModule:
   s2[p2] = 45_000
   s3[p1] = 30_000
   s3[p2] = 45_000
+
+  var
+    t1 = initCountTable[string]()
+    t2 = initCountTable[string]()
+  t1.inc("foo")
+  t1.inc("bar", 2)
+  t1.inc("baz", 3)
+  t2.inc("foo", 4)
+  t2.inc("bar")
+  t2.inc("baz", 11)
+  merge(t1, t2)
+  assert(t1["foo"] == 5)
+  assert(t1["bar"] == 3)
+  assert(t1["baz"] == 14)
+
+  let
+    t1r = newCountTable[string]()
+    t2r = newCountTable[string]()
+  t1r.inc("foo")
+  t1r.inc("bar", 2)
+  t1r.inc("baz", 3)
+  t2r.inc("foo", 4)
+  t2r.inc("bar")
+  t2r.inc("baz", 11)
+  merge(t1r, t2r)
+  assert(t1r["foo"] == 5)
+  assert(t1r["bar"] == 3)
+  assert(t1r["baz"] == 14)
+
+  var
+    t1l = initCountTable[string]()
+    t2l = initCountTable[string]()
+  t1l.inc("foo")
+  t1l.inc("bar", 2)
+  t1l.inc("baz", 3)
+  t2l.inc("foo", 4)
+  t2l.inc("bar")
+  t2l.inc("baz", 11)
+  let
+    t1merging = t1l
+    t2merging = t2l
+  let merged = merge(t1merging, t2merging)
+  assert(merged["foo"] == 5)
+  assert(merged["bar"] == 3)
+  assert(merged["baz"] == 14)
diff --git a/lib/pure/concurrency/cpuload.nim b/lib/pure/concurrency/cpuload.nim
index c1796089a..7ce5e01b7 100644
--- a/lib/pure/concurrency/cpuload.nim
+++ b/lib/pure/concurrency/cpuload.nim
@@ -78,7 +78,7 @@ proc advice*(s: var ThreadPoolState): ThreadPoolAdvice =
     result = doNothing
   inc s.calls
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   proc busyLoop() =
     while true:
       discard random(80)
diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim
index a8ad30d04..9f1e53fb8 100644
--- a/lib/pure/concurrency/threadpool.nim
+++ b/lib/pure/concurrency/threadpool.nim
@@ -204,7 +204,7 @@ proc nimFlowVarSignal(fv: FlowVarBase) {.compilerProc.} =
     inc fv.ai.cv.counter
     release(fv.ai.cv.L)
     signal(fv.ai.cv.c)
-  if fv.usesSemaphore: 
+  if fv.usesSemaphore:
     signal(fv.cv)
 
 proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) =
diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim
index 6247efed2..9983c4a04 100644
--- a/lib/pure/cookies.nim
+++ b/lib/pure/cookies.nim
@@ -56,6 +56,12 @@ proc setCookie*(key, value: string, expires: TimeInfo,
 when isMainModule:
   var tim = Time(int(getTime()) + 76 * (60 * 60 * 24))
 
-  echo(setCookie("test", "value", tim.getGMTime()))
+  let cookie = setCookie("test", "value", tim.getGMTime())
+  when not defined(testing):
+    echo cookie
+  let start = "Set-Cookie: test=value; Expires="
+  assert cookie[0..start.high] == start
   
-  echo parseCookies("uid=1; kp=2")
+  let table = parseCookies("uid=1; kp=2")
+  assert table["uid"] == "1"
+  assert table["kp"] == "2"
diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim
index 25c7ad9ef..2a6134615 100644
--- a/lib/pure/encodings.nim
+++ b/lib/pure/encodings.nim
@@ -451,7 +451,7 @@ proc convert*(s: string, destEncoding = "UTF-8",
   finally:
     close(c)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   let
     orig = "öäüß"
     cp1252 = convert(orig, "CP1252", "UTF-8")
diff --git a/lib/pure/fenv.nim b/lib/pure/fenv.nim
index fd0eab310..f8f115ecc 100644
--- a/lib/pure/fenv.nim
+++ b/lib/pure/fenv.nim
@@ -104,7 +104,7 @@ proc feupdateenv*(envp: ptr Tfenv): cint {.importc, header: "<fenv.h>".}
 
 var FP_RADIX_INTERNAL {. importc: "FLT_RADIX" header: "<float.h>" .} : int
 
-template fpRadix* : int = FLT_RADIX_INTERNAL
+template fpRadix* : int = FP_RADIX_INTERNAL
   ## The (integer) value of the radix used to represent any floating
   ## point type on the architecture used to build the program.
 
diff --git a/lib/pure/fsmonitor.nim b/lib/pure/fsmonitor.nim
index e6919b661..83779eb9c 100644
--- a/lib/pure/fsmonitor.nim
+++ b/lib/pure/fsmonitor.nim
@@ -198,7 +198,7 @@ proc register*(d: Dispatcher, monitor: FSMonitor,
   var deleg = toDelegate(monitor)
   d.register(deleg)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   proc main =
     var disp = newDispatcher()
     var monitor = newMonitor()
diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim
index 46af1d528..b46f8343c 100644
--- a/lib/pure/ftpclient.nim
+++ b/lib/pure/ftpclient.nim
@@ -15,8 +15,8 @@ from rawsockets import nil
 from asyncdispatch import PFuture
 
 ## This module **partially** implements an FTP client as specified
-## by `RFC 959 <http://tools.ietf.org/html/rfc959>`_. 
-## 
+## by `RFC 959 <http://tools.ietf.org/html/rfc959>`_.
+##
 ## This module provides both a synchronous and asynchronous implementation.
 ## The asynchronous implementation requires you to use the ``asyncFTPClient``
 ## function. You are then required to register the ``AsyncFTPClient`` with a
@@ -27,7 +27,7 @@ from asyncdispatch import PFuture
 ## file transfers, calls to functions which use the command socket will block.
 ##
 ## Here is some example usage of this module:
-## 
+##
 ## .. code-block:: Nim
 ##    var ftp = ftpClient("example.org", user = "user", pass = "pass")
 ##    ftp.connect()
@@ -51,7 +51,7 @@ type
       port*: rawsockets.Port
     else:
       port*: Port
-    
+
     jobInProgress*: bool
     job*: FTPJob[SockType]
 
@@ -91,7 +91,7 @@ type
     of EvLines:
       lines*: string ## Lines that have been transferred.
     of EvRetr, EvStore: ## Retr/Store operation finished.
-      nil 
+      nil
     of EvTransferProgress:
       bytesTotal*: BiggestInt     ## Bytes total.
       bytesFinished*: BiggestInt  ## Bytes transferred.
@@ -213,7 +213,7 @@ proc handleConnect(s: AsyncSocket, ftp: AsyncFTPClient) =
 proc handleRead(s: AsyncSocket, ftp: AsyncFTPClient) =
   assert ftp.jobInProgress
   assert ftp.job.typ != JStore
-  # This can never return true, because it shouldn't check for code 
+  # This can never return true, because it shouldn't check for code
   # 226 from csock.
   assert(not ftp.job.prc(ftp, true))
 
@@ -236,13 +236,13 @@ proc pasv[T](ftp: FtpBase[T]) =
     ftp.disp.register(ftp.dsock)
   else:
     {.fatal: "Incorrect socket instantiation".}
-  
+
   var pasvMsg = ftp.send("PASV").string.strip.TaintedString
   assertReply(pasvMsg, "227")
   var betweenParens = captureBetween(pasvMsg.string, '(', ')')
   var nums = betweenParens.split(',')
-  var ip = nums[0.. -3]
-  var port = nums[-2.. -1]
+  var ip = nums[0.. ^3]
+  var port = nums[^2.. ^1]
   var properPort = port[0].parseInt()*256+port[1].parseInt()
   ftp.dsock.connect(ip.join("."), Port(properPort.toU16))
   when T is AsyncSocket:
@@ -307,7 +307,7 @@ proc getLines[T](ftp: FtpBase[T], async: bool = false): bool =
         ftp.job.lines.add(r.string & "\n")
     else:
       {.fatal: "Incorrect socket instantiation".}
-  
+
   if not async:
     var readSocks: seq[Socket] = @[ftp.csock]
     # This is only needed here. Asyncio gets this socket...
@@ -396,7 +396,7 @@ proc chmod*[T](ftp: FtpBase[T], path: string,
 proc list*[T](ftp: FtpBase[T], dir: string = "", async = false): string =
   ## Lists all files in ``dir``. If ``dir`` is ``""``, uses the current
   ## working directory. If ``async`` is true, this function will return
-  ## immediately and it will be your job to call asyncio's 
+  ## immediately and it will be your job to call asyncio's
   ## ``poll`` to progress this operation.
   ftp.createJob(getLines[T], JRetrText)
   ftp.pasv()
@@ -417,7 +417,7 @@ proc retrText*[T](ftp: FtpBase[T], file: string, async = false): string =
   ftp.createJob(getLines[T], JRetrText)
   ftp.pasv()
   assertReply ftp.send("RETR " & file.normalizePathSep), ["125", "150"]
-  
+
   if not async:
     while not ftp.job.prc(ftp, false): discard
     result = ftp.job.lines
@@ -436,7 +436,7 @@ proc getFile[T](ftp: FtpBase[T], async = false): bool =
       else:
         bytesRead = ftp.dsock.recvAsync(r, BufferSize)
         returned = bytesRead != -1
-    else: 
+    else:
       bytesRead = ftp.dsock.recv(r, BufferSize)
       returned = true
     let r2 = r.string
@@ -458,7 +458,7 @@ proc getFile[T](ftp: FtpBase[T], async = false): bool =
 proc retrFile*[T](ftp: FtpBase[T], file, dest: string, async = false) =
   ## Downloads ``file`` and saves it to ``dest``. Usage of this function
   ## asynchronously is recommended to view the progress of the download.
-  ## The ``EvRetr`` event is passed to the specified ``handleEvent`` function 
+  ## The ``EvRetr`` event is passed to the specified ``handleEvent`` function
   ## when the download is finished, and the ``filename`` field will be equal
   ## to ``file``.
   ftp.createJob(getFile[T], JRetr)
@@ -471,7 +471,7 @@ proc retrFile*[T](ftp: FtpBase[T], file, dest: string, async = false) =
   var fileSize: BiggestInt
   if reply.string.captureBetween('(', ')').parseBiggestInt(fileSize) == 0:
     raise newException(ReplyError, "Reply has no file size.")
-    
+
   ftp.job.total = fileSize
   ftp.job.lastProgressReport = epochTime()
   ftp.job.filename = file.normalizePathSep
@@ -488,7 +488,7 @@ proc doUpload[T](ftp: FtpBase[T], async = false): bool =
       if bytesSent == ftp.job.toStore.len:
         ftp.job.toStore = ""
       elif bytesSent != ftp.job.toStore.len and bytesSent != 0:
-        ftp.job.toStore = ftp.job.toStore[bytesSent .. -1]
+        ftp.job.toStore = ftp.job.toStore[bytesSent .. ^1]
       ftp.job.progress.inc(bytesSent)
       ftp.job.oneSecond.inc(bytesSent)
     else:
@@ -499,12 +499,12 @@ proc doUpload[T](ftp: FtpBase[T], async = false): bool =
         # File finished uploading.
         ftp.dsock.close()
         ftp.dsockConnected = false
-  
+
         if not async:
           assertReply ftp.expectReply(), "226"
           return true
         return false
-    
+
       if not async:
         ftp.dsock.send(s)
       else:
@@ -512,9 +512,9 @@ proc doUpload[T](ftp: FtpBase[T], async = false): bool =
         if bytesSent == 0:
           ftp.job.toStore.add(s)
         elif bytesSent != s.len:
-          ftp.job.toStore.add(s[bytesSent .. -1])
+          ftp.job.toStore.add(s[bytesSent .. ^1])
         len = bytesSent
-      
+
       ftp.job.progress.inc(len)
       ftp.job.oneSecond.inc(len)
 
@@ -522,8 +522,8 @@ proc store*[T](ftp: FtpBase[T], file, dest: string, async = false) =
   ## Uploads ``file`` to ``dest`` on the remote FTP server. Usage of this
   ## function asynchronously is recommended to view the progress of
   ## the download.
-  ## The ``EvStore`` event is passed to the specified ``handleEvent`` function 
-  ## when the upload is finished, and the ``filename`` field will be 
+  ## The ``EvStore`` event is passed to the specified ``handleEvent`` function
+  ## when the upload is finished, and the ``filename`` field will be
   ## equal to ``file``.
   ftp.createJob(doUpload[T], JStore)
   ftp.job.file = open(file)
@@ -531,7 +531,7 @@ proc store*[T](ftp: FtpBase[T], file, dest: string, async = false) =
   ftp.job.lastProgressReport = epochTime()
   ftp.job.filename = file
   ftp.pasv()
-  
+
   assertReply ftp.send("STOR " & dest.normalizePathSep), ["125", "150"]
 
   if not async:
@@ -564,12 +564,12 @@ proc csockHandleRead(s: AsyncSocket, ftp: AsyncFTPClient) =
       if ftp.job.progress != ftp.job.total:
         raise newException(FTPError, "Didn't upload full file.")
     ftp.deleteJob()
-    
+
     ftp.handleEvent(ftp, r)
 
 proc asyncFTPClient*(address: string, port = Port(21),
                      user, pass = "",
-    handleEvent: proc (ftp: AsyncFTPClient, ev: FTPEvent) {.closure,gcsafe.} = 
+    handleEvent: proc (ftp: AsyncFTPClient, ev: FTPEvent) {.closure,gcsafe.} =
       (proc (ftp: AsyncFTPClient, ev: FTPEvent) = discard)): AsyncFTPClient =
   ## Create a ``AsyncFTPClient`` object.
   ##
@@ -617,7 +617,7 @@ when isMainModule:
           echo d.len
         else: assert(false)
     var ftp = asyncFTPClient("example.com", user = "foo", pass = "bar", handleEvent = hev)
-    
+
     d.register(ftp)
     d.len.echo()
     ftp.connect()
@@ -629,7 +629,7 @@ when isMainModule:
       if not d.poll(): break
   main()
 
-when isMainModule and false:
+when not defined(testing) and isMainModule:
   var ftp = ftpClient("example.com", user = "foo", pass = "bar")
   ftp.connect()
   echo ftp.pwd()
diff --git a/lib/pure/gentabs.nim b/lib/pure/gentabs.nim
index a6128efc9..8c89a0ac3 100644
--- a/lib/pure/gentabs.nim
+++ b/lib/pure/gentabs.nim
@@ -186,8 +186,19 @@ when isMainModule:
   assert( z["first"]["one"] == 1)   # retrieve from first inner table
   assert( z["second"]["red"] == 10) # retrieve from second inner table
   
-  for k,v in pairs(z):
-    echo( "$# ($#) ->" % [k,$len(v)] )
-    #for k2,v2 in pairs(v):
-    #  echo( "   $# <-> $#" % [k2,$v2] )
-  echo()
+  var output = ""
+  for k, v in pairs(z):
+    output.add( "$# ($#) ->\n" % [k,$len(v)] )
+    for k2,v2 in pairs(v):
+      output.add( "  $# <-> $#\n" % [k2,$v2] )
+
+  let expected = unindent """
+    first (3) ->
+      two <-> 2
+      three <-> 3
+      one <-> 1
+    second (2) ->
+      red <-> 10
+      blue <-> 20
+  """
+  assert output == expected
diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim
index d712e53f3..e6c15371e 100644
--- a/lib/pure/htmlgen.nim
+++ b/lib/pure/htmlgen.nim
@@ -483,7 +483,8 @@ macro `var`*(e: expr): expr {.immediate.} =
   result = xmlCheckedTag(e, "var", commonAttr)
 
 when isMainModule:
-  var nim = "Nim"
-  echo h1(a(href="http://nim-lang.org", nim))
-  echo form(action="test", `accept-charset` = "Content-Type")
-
+  let nim = "Nim"
+  assert h1(a(href="http://nim-lang.org", nim)) ==
+    """<h1><a href="http://nim-lang.org">Nim</a></h1>"""
+  assert form(action="test", `accept-charset` = "Content-Type") ==
+    """<form action="test" accept-charset="Content-Type"></form>"""
diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim
index 5e4eba4e5..9719181b8 100644
--- a/lib/pure/htmlparser.nim
+++ b/lib/pure/htmlparser.nim
@@ -593,7 +593,7 @@ proc loadHtml*(path: string): XmlNode =
   var errors: seq[string] = @[]
   result = loadHtml(path, errors)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   import os
 
   var errors: seq[string] = @[]  
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index f11101511..9c27ecdab 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -227,7 +227,7 @@ proc parseResponse(s: Socket, getBody: bool, timeout: int): Response =
       inc(linei, le)
       # Status code
       linei.inc skipWhitespace(line, linei)
-      result.status = line[linei .. -1]
+      result.status = line[linei .. ^1]
       parsedStatus = true
     else:
       # Parse headers
@@ -238,7 +238,7 @@ proc parseResponse(s: Socket, getBody: bool, timeout: int): Response =
       if line[linei] != ':': httpError("invalid headers")
       inc(linei) # Skip :
 
-      result.headers[name] = line[linei.. -1].strip()
+      result.headers[name] = line[linei.. ^1].strip()
   if not fullyRead:
     httpError("Connection was closed before full request has been made")
   if getBody:
@@ -442,7 +442,7 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
   ## | Extra headers can be specified and must be separated by ``\c\L``
   ## | An optional timeout can be specified in miliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
-  result = request(url, $httpMethod, extraHeaders, body, sslContext, timeout, 
+  result = request(url, $httpMethod, extraHeaders, body, sslContext, timeout,
                    userAgent, proxy)
 
 proc redirection(status: string): bool =
@@ -725,7 +725,7 @@ proc parseResponse(client: AsyncHttpClient,
       inc(linei, le)
       # Status code
       linei.inc skipWhitespace(line, linei)
-      result.status = line[linei .. -1]
+      result.status = line[linei .. ^1]
       parsedStatus = true
     else:
       # Parse headers
@@ -736,7 +736,7 @@ proc parseResponse(client: AsyncHttpClient,
       if line[linei] != ':': httpError("invalid headers")
       inc(linei) # Skip :
 
-      result.headers[name] = line[linei.. -1].strip()
+      result.headers[name] = line[linei.. ^1].strip()
   if not fullyRead:
     httpError("Connection was closed before full request has been made")
   if getBody:
@@ -819,7 +819,7 @@ proc get*(client: AsyncHttpClient, url: string): Future[Response] {.async.} =
       result = await client.request(redirectTo, httpGET)
       lastUrl = redirectTo
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   when true:
     # Async
     proc main() {.async.} =
diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim
index 5efdbe297..dc76c9228 100644
--- a/lib/pure/httpserver.nim
+++ b/lib/pure/httpserver.nim
@@ -514,7 +514,7 @@ proc close*(h: PAsyncHTTPServer) =
   ## Closes the ``PAsyncHTTPServer``.
   h.asyncSocket.close()
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   var counter = 0
 
   var s: TServer
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index c3db5bdf8..5d824d6f8 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -605,6 +605,49 @@ proc newJArray*(): JsonNode =
   result.kind = JArray
   result.elems = @[]
 
+proc getStr*(n: JsonNode, default: string = ""): string =
+  ## Retrieves the string value of a `JString JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JString``.
+  if n.kind != JString: return default
+  else: return n.str
+
+proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
+  ## Retrieves the int value of a `JInt JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JInt``.
+  if n.kind != JInt: return default
+  else: return n.num
+
+proc getFNum*(n: JsonNode, default: float = 0.0): float =
+  ## Retrieves the float value of a `JFloat JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JFloat``.
+  if n.kind != JFloat: return default
+  else: return n.fnum
+
+proc getBVal*(n: JsonNode, default: bool = false): bool =
+  ## Retrieves the bool value of a `JBool JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JBool``.
+  if n.kind != JBool: return default
+  else: return n.bval
+
+proc getFields*(n: JsonNode,
+    default: seq[tuple[key: string, val: JsonNode]] = @[]):
+        seq[tuple[key: string, val: JsonNode]] =
+  ## Retrieves the key, value pairs of a `JObject JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JObject``.
+  if n.kind != JObject: return default
+  else: return n.fields
+
+proc getElems*(n: JsonNode, default: seq[JsonNode] = @[]): seq[JsonNode] =
+  ## Retrieves the int value of a `JArray JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JArray``.
+  if n.kind != JArray: return default
+  else: return n.elems
 
 proc `%`*(s: string): JsonNode =
   ## Generic constructor for JSON data. Creates a new `JString JsonNode`.
@@ -765,22 +808,25 @@ proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) =
       return
   obj.fields.add((key, val))
 
-proc `{}`*(node: JsonNode, key: string): JsonNode =
-  ## Transverses the node and gets the given value. If any of the
-  ## names does not exist, returns nil
+proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode =
+  ## Traverses the node and gets the given value. If any of the
+  ## keys do not exist, returns nil. Also returns nil if one of the
+  ## intermediate data structures is not an object
   result = node
-  if isNil(node): return nil
-  result = result[key]
-
-proc `{}=`*(node: JsonNode, names: varargs[string], value: JsonNode) =
-  ## Transverses the node and tries to set the value at the given location
-  ## to `value` If any of the names are missing, they are added
+  for key in keys:
+    if isNil(result) or result.kind!=JObject:
+      return nil    
+    result=result[key]
+
+proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) =
+  ## Traverses the node and tries to set the value at the given location
+  ## to `value` If any of the keys are missing, they are added
   var node = node
-  for i in 0..(names.len-2):
-    if isNil(node[names[i]]):
-      node[names[i]] = newJObject()
-    node = node[names[i]]
-  node[names[names.len-1]] = value
+  for i in 0..(keys.len-2):
+    if isNil(node[keys[i]]):
+      node[keys[i]] = newJObject()
+    node = node[keys[i]]
+  node[keys[keys.len-1]] = value
 
 proc delete*(obj: JsonNode, key: string) =
   ## Deletes ``obj[key]`` preserving the order of the other (key, value)-pairs.
@@ -1107,19 +1153,22 @@ when false:
 when isMainModule:
   #var node = parse("{ \"test\": null }")
   #echo(node.existsKey("test56"))
+  
   var parsed = parseFile("tests/testdata/jsontest.json")
   var parsed2 = parseFile("tests/testdata/jsontest2.json")
-  echo(parsed)
-  echo()
-  echo(pretty(parsed, 2))
-  echo()
-  echo(parsed["keyÄÖöoßß"])
-  echo()
-  echo(pretty(parsed2))
-  try:
-    echo(parsed["key2"][12123])
-    raise newException(ValueError, "That line was expected to fail")
-  except IndexError: echo()
+
+  when not defined(testing):
+    echo(parsed)
+    echo()
+    echo(pretty(parsed, 2))
+    echo()
+    echo(parsed["keyÄÖöoßß"])
+    echo()
+    echo(pretty(parsed2))
+    try:
+      echo(parsed["key2"][12123])
+      raise newException(ValueError, "That line was expected to fail")
+    except IndexError: echo()
 
   let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd" }"""
   # nil passthrough
@@ -1143,9 +1192,17 @@ when isMainModule:
   except:
     assert(false, "EInvalidIndex thrown for valid index")
 
+  assert(testJson{"b"}.str=="asd", "Couldn't fetch a singly nested key with {}") 
+  assert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil") 
+  assert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
+  assert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
+  assert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
+  assert(testJson{"a"}==parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found")
+  assert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil")
+ 
   # Generator:
   var j = %* [{"name": "John", "age": 30}, {"name": "Susan", "age": 31}]
-  assert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
+  assert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}] 
 
   var j2 = %*
     [
@@ -1173,12 +1230,13 @@ when isMainModule:
       }
     ]
   assert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
-
-  discard """
-  while true:
-    var json = stdin.readLine()
-    var node = parse(json)
-    echo(node)
-    echo()
-    echo()
-  """
+  
+  when not defined(testing):
+    discard """
+    while true:
+      var json = stdin.readLine()
+      var node = parse(json)
+      echo(node)
+      echo()
+      echo()
+    """
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
index 16c36e1f0..a2ea53472 100644
--- a/lib/pure/logging.nim
+++ b/lib/pure/logging.nim
@@ -10,7 +10,7 @@
 ## This module implements a simple logger. It has been designed to be as simple
 ## as possible to avoid bloat, if this library does not fulfill your needs,
 ## write your own.
-## 
+##
 ## Format strings support the following variables which must be prefixed with
 ## the dollar operator (``$``):
 ##
@@ -21,13 +21,13 @@
 ## $time         Current time
 ## $app          ``os.getAppFilename()``
 ## ============  =======================
-## 
+##
 ##
 ## The following example demonstrates logging to three different handlers
 ## simultaneously:
 ##
 ## .. code-block:: nim
-##     
+##
 ##    var L = newConsoleLogger()
 ##    var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
 ##    var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr)
@@ -64,20 +64,20 @@ const
 
 type
   Logger* = ref object of RootObj ## abstract logger; the base type of all loggers
-    levelThreshold*: Level    ## only messages of level >= levelThreshold 
+    levelThreshold*: Level    ## only messages of level >= levelThreshold
                               ## should be processed
     fmtStr: string ## = defaultFmtStr by default, see substituteLog for $date etc.
-    
+
   ConsoleLogger* = ref object of Logger ## logger that writes the messages to the
                                         ## console
-  
+
   FileLogger* = ref object of Logger ## logger that writes the messages to a file
     f: File
-  
-  RollingFileLogger* = ref object of FileLogger ## logger that writes the 
+
+  RollingFileLogger* = ref object of FileLogger ## logger that writes the
                                                 ## messages to a file and
                                                 ## performs log rotation
-    maxLines: int # maximum number of lines    
+    maxLines: int # maximum number of lines
     curLine : int
     baseName: string # initial filename
     baseMode: FileMode # initial file mode
@@ -86,22 +86,22 @@ type
 {.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger,
     PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].}
 
-proc substituteLog(frmt: string): string = 
+proc substituteLog(frmt: string): string =
   ## converts $date to the current date
   ## converts $time to the current time
   ## converts $app to getAppFilename()
-  ## converts 
+  ## converts
   result = newStringOfCap(frmt.len + 20)
   var i = 0
-  while i < frmt.len: 
-    if frmt[i] != '$': 
+  while i < frmt.len:
+    if frmt[i] != '$':
       result.add(frmt[i])
       inc(i)
     else:
       inc(i)
       var v = ""
       var app = getAppFilename()
-      while frmt[i] in IdentChars: 
+      while frmt[i] in IdentChars:
         v.add(toLower(frmt[i]))
         inc(i)
       case v
@@ -114,12 +114,12 @@ proc substituteLog(frmt: string): string =
 
 method log*(logger: Logger, level: Level,
             frmt: string, args: varargs[string, `$`]) {.
-            raises: [Exception], 
+            raises: [Exception],
             tags: [TimeEffect, WriteIOEffect, ReadIOEffect].} =
   ## Override this method in custom loggers. Default implementation does
   ## nothing.
   discard
-  
+
 method log*(logger: ConsoleLogger, level: Level,
             frmt: string, args: varargs[string, `$`]) =
   ## Logs to the console using ``logger`` only.
@@ -127,14 +127,14 @@ method log*(logger: ConsoleLogger, level: Level,
     writeln(stdout, LevelNames[level], " ", substituteLog(logger.fmtStr),
             frmt % args)
 
-method log*(logger: FileLogger, level: Level, 
+method log*(logger: FileLogger, level: Level,
             frmt: string, args: varargs[string, `$`]) =
   ## Logs to a file using ``logger`` only.
   if level >= logger.levelThreshold:
     writeln(logger.f, LevelNames[level], " ",
             substituteLog(logger.fmtStr), frmt % args)
 
-proc defaultFilename*(): string = 
+proc defaultFilename*(): string =
   ## Returns the default filename for a logger.
   var (path, name, ext) = splitFile(getAppFilename())
   result = changeFileExt(path / name, "log")
@@ -145,10 +145,10 @@ proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): Console
   result.fmtStr = fmtStr
   result.levelThreshold = levelThreshold
 
-proc newFileLogger*(filename = defaultFilename(), 
+proc newFileLogger*(filename = defaultFilename(),
                     mode: FileMode = fmAppend,
                     levelThreshold = lvlAll,
-                    fmtStr = defaultFmtStr): FileLogger = 
+                    fmtStr = defaultFmtStr): FileLogger =
   ## Creates a new file logger. This logger logs to a file.
   new(result)
   result.levelThreshold = levelThreshold
@@ -170,14 +170,14 @@ proc countFiles(filename: string): int =
     if kind == pcFile:
       let llfn = name & ext & ExtSep
       if path.extractFilename.startsWith(llfn):
-        let numS = path.extractFilename[llfn.len .. -1]
+        let numS = path.extractFilename[llfn.len .. ^1]
         try:
           let num = parseInt(numS)
           if num > result:
             result = num
         except ValueError: discard
 
-proc newRollingFileLogger*(filename = defaultFilename(), 
+proc newRollingFileLogger*(filename = defaultFilename(),
                            mode: FileMode = fmReadWrite,
                            levelThreshold = lvlAll,
                            fmtStr = defaultFmtStr,
@@ -192,9 +192,9 @@ proc newRollingFileLogger*(filename = defaultFilename(),
   result.curLine = 0
   result.baseName = filename
   result.baseMode = mode
-  
+
   result.logFiles = countFiles(filename)
-  
+
   if mode == fmAppend:
     # We need to get a line count because we will be appending to the file.
     result.curLine = countLogLines(result)
@@ -206,7 +206,7 @@ proc rotate(logger: RollingFileLogger) =
     moveFile(dir / (name & ext & srcSuff),
              dir / (name & ext & ExtSep & $(i+1)))
 
-method log*(logger: RollingFileLogger, level: Level, 
+method log*(logger: RollingFileLogger, level: Level,
             frmt: string, args: varargs[string, `$`]) =
   ## Logs to a file using rolling ``logger`` only.
   if level >= logger.levelThreshold:
@@ -216,7 +216,7 @@ method log*(logger: RollingFileLogger, level: Level,
       logger.logFiles.inc
       logger.curLine = 0
       logger.f = open(logger.baseName, logger.baseMode)
-    
+
     writeln(logger.f, LevelNames[level], " ",substituteLog(logger.fmtStr), frmt % args)
     logger.curLine.inc
 
@@ -226,7 +226,7 @@ var level {.threadvar.}: Level   ## global log filter
 var handlers {.threadvar.}: seq[Logger] ## handlers with their own log levels
 
 proc logLoop(level: Level, frmt: string, args: varargs[string, `$`]) =
-  for logger in items(handlers): 
+  for logger in items(handlers):
     if level >= logger.levelThreshold:
       log(logger, level, frmt, args)
 
@@ -235,7 +235,7 @@ template log*(level: Level, frmt: string, args: varargs[string, `$`]) =
   bind logLoop
   bind `%`
   bind logging.level
-  
+
   if level >= logging.level:
     logLoop(level, frmt, args)
 
@@ -243,19 +243,19 @@ template debug*(frmt: string, args: varargs[string, `$`]) =
   ## Logs a debug message to all registered handlers.
   log(lvlDebug, frmt, args)
 
-template info*(frmt: string, args: varargs[string, `$`]) = 
+template info*(frmt: string, args: varargs[string, `$`]) =
   ## Logs an info message to all registered handlers.
   log(lvlInfo, frmt, args)
 
-template warn*(frmt: string, args: varargs[string, `$`]) = 
+template warn*(frmt: string, args: varargs[string, `$`]) =
   ## Logs a warning message to all registered handlers.
   log(lvlWarn, frmt, args)
 
-template error*(frmt: string, args: varargs[string, `$`]) = 
+template error*(frmt: string, args: varargs[string, `$`]) =
   ## Logs an error message to all registered handlers.
   log(lvlError, frmt, args)
-  
-template fatal*(frmt: string, args: varargs[string, `$`]) =  
+
+template fatal*(frmt: string, args: varargs[string, `$`]) =
   ## Logs a fatal error message to all registered handlers.
   log(lvlFatal, frmt, args)
 
@@ -278,7 +278,7 @@ proc getLogFilter*(): Level =
 
 # --------------
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   var L = newConsoleLogger()
   var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
   var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr)
@@ -287,5 +287,5 @@ when isMainModule:
   addHandler(rL)
   for i in 0 .. 25:
     info("hello" & $i, [])
-  
+
 
diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim
index b63c334ff..bf9e33296 100644
--- a/lib/pure/marshal.nim
+++ b/lib/pure/marshal.nim
@@ -244,7 +244,7 @@ proc to*[T](data: string): T =
   var tab = initTable[BiggestInt, pointer]()
   loadAny(newStringStream(data), toAny(result), tab)
   
-when isMainModule:
+when not defined(testing) and isMainModule:
   template testit(x: expr) = echo($$to[type(x)]($$x))
 
   var x: array[0..4, array[0..4, string]] = [
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index c902af381..daa108460 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -152,6 +152,7 @@ proc randomize*(seed: int) {.benign.}
   ## Note: Does nothing for the JavaScript target,
   ## as JavaScript does not support this.
 
+{.push noSideEffect.}
 when not defined(JS):
   proc sqrt*(x: float): float {.importc: "sqrt", header: "<math.h>".}
     ## computes the square root of `x`.
@@ -273,6 +274,8 @@ else:
     var y = exp(2.0*x)
     return (y-1.0)/(y+1.0)
 
+{.pop.}
+
 proc `mod`*(x, y: float): float =
   result = if y == 0.0: x else: x - y * (x/y).floor
 
@@ -369,4 +372,10 @@ when isMainModule and not defined(JS):
   randomize(seed)
   for i in 0..SIZE-1:
     assert buf[i] == random(high(int)), "non deterministic random seeding"
-  echo "random values equal after reseeding"
+
+  when not defined(testing):
+    echo "random values equal after reseeding"
+
+  # Check for no side effect annotation
+  proc mySqrt(num: float): float {.noSideEffect.} =
+    return sqrt(num)
diff --git a/lib/pure/mersenne.nim b/lib/pure/mersenne.nim
index a6a781cb8..74112e304 100644
--- a/lib/pure/mersenne.nim
+++ b/lib/pure/mersenne.nim
@@ -32,7 +32,7 @@ proc getNum*(m: var MersenneTwister): int =
   return int(y)
 
 # Test
-when isMainModule:
+when not defined(testing) and isMainModule:
   var mt = newMersenneTwister(2525)
 
   for i in 0..99:
diff --git a/lib/pure/mimetypes.nim b/lib/pure/mimetypes.nim
index a52ba4ebe..642419e64 100644
--- a/lib/pure/mimetypes.nim
+++ b/lib/pure/mimetypes.nim
@@ -518,5 +518,5 @@ proc register*(mimedb: var MimeDB, ext: string, mimetype: string) =
 
 when isMainModule:
   var m = newMimetypes()
-  echo m.getMimetype("mp4")
-  echo m.getExt("text/html")
+  assert m.getMimetype("mp4") == "video/mp4"
+  assert m.getExt("text/html") == "html"
diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim
index 0dc8e3c15..ac90dd16b 100644
--- a/lib/pure/oids.nim
+++ b/lib/pure/oids.nim
@@ -88,6 +88,6 @@ proc generatedTime*(oid: Oid): Time =
   bigEndian32(addr(tmp), addr(dummy))
   result = Time(tmp)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   let xo = genOid()
   echo xo.generatedTime
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 82d6177e1..f53abe81d 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -1863,16 +1863,21 @@ proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1",
       close(f)
     else: raiseOSError(osLastError())
 
+proc expandTilde*(path: string): string {.tags: [ReadEnvEffect].}
+
 proc findExe*(exe: string): string {.tags: [ReadDirEffect, ReadEnvEffect].} =
   ## Searches for `exe` in the current working directory and then
   ## in directories listed in the ``PATH`` environment variable.
   ## Returns "" if the `exe` cannot be found. On DOS-like platforms, `exe`
-  ## is added an ``.exe`` file extension if it has no extension.
+  ## is added the `ExeExt <#ExeExt>`_ file extension if it has none.
   result = addFileExt(exe, os.ExeExt)
   if existsFile(result): return
   var path = string(os.getEnv("PATH"))
   for candidate in split(path, PathSep):
-    var x = candidate / result
+    when defined(windows):
+      var x = candidate / result
+    else:
+      var x = expandTilde(candidate) / result
     if existsFile(x): return x
   result = ""
 
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index cd3700019..dce0673ba 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -137,7 +137,7 @@ proc startProcess*(command: string,
   ## `env` is the environment that will be passed to the process.
   ## If ``env == nil`` the environment is inherited of
   ## the parent process. `options` are additional flags that may be passed
-  ## to `startProcess`. See the documentation of ``TProcessOption`` for the
+  ## to `startProcess`. See the documentation of ``ProcessOption`` for the
   ## meaning of these flags. You need to `close` the process when done.
   ##
   ## Note that you can't pass any `args` if you use the option
@@ -174,7 +174,7 @@ proc terminate*(p: Process) {.rtl, extern: "nosp$1", tags: [].}
 proc kill*(p: Process) {.rtl, extern: "nosp$1", tags: [].}
   ## Kill the process `p`. On Posix OSes the procedure sends ``SIGKILL`` to
   ## the process. On Windows ``kill()`` is simply an alias for ``terminate()``.
-  
+
 proc running*(p: Process): bool {.rtl, extern: "nosp$1", tags: [].}
   ## Returns true iff the process `p` is still running. Returns immediately.
 
@@ -666,7 +666,7 @@ elif not defined(useNimRtl):
     data.workingDir = workingDir
 
 
-    when declared(posix_spawn) and not defined(useFork) and 
+    when declared(posix_spawn) and not defined(useFork) and
         not defined(useClone) and not defined(linux):
       pid = startProcessAuxSpawn(data)
     else:
@@ -823,7 +823,7 @@ elif not defined(useNimRtl):
         discard execvp(data.sysCommand, data.sysArgs)
       else:
         when defined(uClibc):
-          # uClibc environment (OpenWrt included) doesn't have the full execvpe 
+          # uClibc environment (OpenWrt included) doesn't have the full execvpe
           discard execve(data.sysCommand, data.sysArgs, data.sysEnv)
         else:
           discard execvpe(data.sysCommand, data.sysArgs, data.sysEnv)
@@ -864,9 +864,9 @@ elif not defined(useNimRtl):
       raiseOsError(osLastError())
 
   proc kill(p: Process) =
-    if kill(p.id, SIGKILL) != 0'i32: 
+    if kill(p.id, SIGKILL) != 0'i32:
       raiseOsError(osLastError())
-    
+
   proc waitForExit(p: Process, timeout: int = -1): int =
     #if waitPid(p.id, p.exitCode, 0) == int(p.id):
     # ``waitPid`` fails if the process is not running anymore. But then
@@ -883,7 +883,7 @@ elif not defined(useNimRtl):
     var ret = waitpid(p.id, p.exitCode, WNOHANG)
     var b = ret == int(p.id)
     if b: result = -1
-    if p.exitCode == -3: result = -1
+    if not WIFEXITED(p.exitCode): result = -1
     else: result = p.exitCode.int shr 8
 
   proc createStream(stream: var Stream, handle: var FileHandle,
@@ -907,7 +907,7 @@ elif not defined(useNimRtl):
       createStream(p.errStream, p.errHandle, fmRead)
     return p.errStream
 
-  proc csystem(cmd: cstring): cint {.nodecl, importc: "system", 
+  proc csystem(cmd: cstring): cint {.nodecl, importc: "system",
                                      header: "<stdlib.h>".}
 
   proc execCmd(command: string): int =
diff --git a/lib/pure/parsecsv.nim b/lib/pure/parsecsv.nim
index f4943ed89..117d75cfa 100644
--- a/lib/pure/parsecsv.nim
+++ b/lib/pure/parsecsv.nim
@@ -166,7 +166,7 @@ proc close*(my: var CsvParser) {.inline.} =
   ## closes the parser `my` and its associated input stream.
   lexbase.close(my)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   import os
   var s = newFileStream(paramStr(1), fmRead)
   if s == nil: quit("cannot open the file" & paramStr(1))
diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim
index bb4ede779..91917b1c5 100644
--- a/lib/pure/parsesql.nim
+++ b/lib/pure/parsesql.nim
@@ -1330,7 +1330,7 @@ proc renderSQL*(n: SqlNode): string =
   result = ""
   ra(n, result, 0)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   echo(renderSQL(parseSQL(newStringStream("""
       CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic');
       CREATE TABLE holidays (
diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim
index eb649a878..c07b713de 100644
--- a/lib/pure/parseutils.nim
+++ b/lib/pure/parseutils.nim
@@ -323,8 +323,12 @@ iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
     i = j
 
 when isMainModule:
-  for k, v in interpolatedFragments("$test{}  $this is ${an{  example}}  "):
-    echo "(", k, ", \"", v, "\")"
+  import sequtils
+  let input = "$test{}  $this is ${an{  example}}  "
+  let expected = @[(ikVar, "test"), (ikStr, "{}  "), (ikVar, "this"),
+                   (ikStr, " is "), (ikExpr, "an{  example}"), (ikStr, "  ")]
+  assert toSeq(interpolatedFragments(input)) == expected
+
   var value = 0
   discard parseHex("0x38", value)
   assert value == 56
diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim
index 2663c5b2f..eb792f086 100644
--- a/lib/pure/parsexml.nim
+++ b/lib/pure/parsexml.nim
@@ -628,7 +628,7 @@ proc next*(my: var XmlParser) =
     my.kind = xmlError
     my.state = stateNormal
   
-when isMainModule:
+when not defined(testing) and isMainModule:
   import os
   var s = newFileStream(paramStr(1), fmRead)
   if s == nil: quit("cannot open the file" & paramStr(1))
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index 04c75ecae..39f0bfa95 100644
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -744,24 +744,6 @@ template fillMatches(s, caps, c: expr) =
     else:
       caps[k] = nil
 
-proc match*(s: string, pattern: Peg, matches: var openArray[string],
-            start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} =
-  ## returns ``true`` if ``s[start..]`` matches the ``pattern`` and
-  ## the captured substrings in the array ``matches``. If it does not
-  ## match, nothing is written into ``matches`` and ``false`` is
-  ## returned.
-  var c: Captures
-  c.origStart = start
-  result = rawMatch(s, pattern, start, c) == len(s) - start
-  if result: fillMatches(s, matches, c)
-
-proc match*(s: string, pattern: Peg,
-            start = 0): bool {.nosideEffect, rtl, extern: "npegs$1".} =
-  ## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``.
-  var c: Captures
-  c.origStart = start
-  result = rawMatch(s, pattern, start, c) == len(s)-start
-
 proc matchLen*(s: string, pattern: Peg, matches: var openArray[string],
                start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
   ## the same as ``match``, but it returns the length of the match,
@@ -783,6 +765,20 @@ proc matchLen*(s: string, pattern: Peg,
   c.origStart = start
   result = rawMatch(s, pattern, start, c)
 
+proc match*(s: string, pattern: Peg, matches: var openArray[string],
+            start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} =
+  ## returns ``true`` if ``s[start..]`` matches the ``pattern`` and
+  ## the captured substrings in the array ``matches``. If it does not
+  ## match, nothing is written into ``matches`` and ``false`` is
+  ## returned.
+  result = matchLen(s, pattern, matches, start) != -1
+
+proc match*(s: string, pattern: Peg,
+            start = 0): bool {.nosideEffect, rtl, extern: "npegs$1".} =
+  ## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``.
+  result = matchLen(s, pattern, start) != -1
+
+
 proc find*(s: string, pattern: Peg, matches: var openArray[string],
            start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
   ## returns the starting position of ``pattern`` in ``s`` and the captured
@@ -1686,8 +1682,10 @@ when isMainModule:
   assert "ABC 0232".match(peg"\w+\s+\d+")
   assert "ABC".match(peg"\d+ / \w+")
 
+  var accum: seq[string] = @[]
   for word in split("00232this02939is39an22example111", peg"\d+"):
-    writeln(stdout, word)
+    accum.add(word)
+  assert(accum == @["this", "is", "an", "example"])
 
   assert matchLen("key", ident) == 3
 
@@ -1748,8 +1746,10 @@ when isMainModule:
   else:
     assert false
 
+  accum = @[]
   for x in findAll("abcdef", peg".", 3):
-    echo x
+    accum.add(x)
+  assert(accum == @["d", "e", "f"])
 
   for x in findAll("abcdef", peg"^{.}", 3):
     assert x == "d"
@@ -1783,3 +1783,9 @@ when isMainModule:
   if "foo" =~ peg"{'foo'}":
     assert matches[0] == "foo"
   else: assert false
+
+  let empty_test = peg"^\d*"
+  let str = "XYZ"
+
+  assert(str.find(empty_test) == 0)
+  assert(str.match(empty_test))
diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim
index 04aa8316a..3b68a2381 100644
--- a/lib/pure/rationals.nim
+++ b/lib/pure/rationals.nim
@@ -12,6 +12,7 @@
 ## a denominator `den`, both of type int. The denominator can not be 0.
 
 import math
+import hashes
 
 type Rational*[T] = object
   ## a rational number, consisting of a numerator and denominator
@@ -32,7 +33,7 @@ proc `$`*[T](x: Rational[T]): string =
   ## Turn a rational number into a string.
   result = $x.num & "/" & $x.den
 
-proc toRational*[T](x: SomeInteger): Rational[T] =
+proc toRational*[T](x: T): Rational[T] =
   ## Convert some integer `x` to a rational number.
   result.num = x
   result.den = 1
@@ -188,7 +189,7 @@ proc `/=`*[T](x: var Rational[T], y: T) =
   x.den *= y
   reduce(x)
 
-proc cmp*(x, y: Rational): int =
+proc cmp*(x, y: Rational): int {.procvar.} =
   ## Compares two rationals.
   (x - y).num
 
@@ -205,6 +206,17 @@ proc abs*[T](x: Rational[T]): Rational[T] =
   result.num = abs x.num
   result.den = abs x.den
 
+proc hash*[T](x: Rational[T]): THash =
+  ## Computes hash for rational `x`
+  # reduce first so that hash(x) == hash(y) for x == y
+  var copy = x
+  reduce(copy)
+
+  var h: THash = 0
+  h = h !& hash(copy.num)
+  h = h !& hash(copy.den)
+  result = !$h
+  
 when isMainModule:
   var
     z = Rational[int](num: 0, den: 1)
@@ -242,11 +254,13 @@ when isMainModule:
   assert( not(o > o) )
   assert( cmp(o, o) == 0 )
   assert( cmp(z, z) == 0 )
+  assert( hash(o) == hash(o) )
 
   assert( a == b )
   assert( a >= b )
   assert( not(b > a) )
   assert( cmp(a, b) == 0 )
+  assert( hash(a) == hash(b) )
 
   var x = 1//3
 
@@ -270,6 +284,6 @@ when isMainModule:
   y /= 9
   assert( y == 13//27 )
 
-  assert toRational[int, int](5) == 5//1
+  assert toRational(5) == 5//1
   assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7
   assert toInt(z) == 0
diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim
index ac348eb1b..a30c23ada 100644
--- a/lib/pure/rawsockets.nim
+++ b/lib/pure/rawsockets.nim
@@ -39,6 +39,9 @@ export
   SO_KEEPALIVE, SO_OOBINLINE, SO_REUSEADDR,
   MSG_PEEK
 
+when defined(macosx):
+    export SO_NOSIGPIPE
+
 type
   Port* = distinct uint16  ## port type
   
@@ -428,10 +431,6 @@ proc selectWrite*(writefds: var seq[SocketHandle],
   
   pruneSocketSet(writefds, (wr))
 
-# We ignore signal SIGPIPE on Darwin
-when defined(macosx):
-  signal(SIGPIPE, SIG_IGN)
-
 when defined(Windows):
   var wsa: WSAData
   if wsaStartup(0x0101'i16, addr wsa) != 0: raiseOSError(osLastError())
diff --git a/lib/pure/redis.nim b/lib/pure/redis.nim
index 9177ddee5..aa2e0f9bd 100644
--- a/lib/pure/redis.nim
+++ b/lib/pure/redis.nim
@@ -1080,7 +1080,7 @@ proc assertListsIdentical(listA, listB: seq[string]) =
     assert(item == listB[i])
     i = i + 1
   
-when isMainModule:
+when not defined(testing) and isMainModule:
   when false:
     var r = open()
 
diff --git a/lib/pure/romans.nim b/lib/pure/romans.nim
index 79fb75526..0c182843a 100644
--- a/lib/pure/romans.nim
+++ b/lib/pure/romans.nim
@@ -44,16 +44,13 @@ proc decimalToRoman*(number: range[1..3_999]): string =
     ("XC", 90), ("L", 50), ("XL", 40), ("X", 10), ("IX", 9),
     ("V", 5), ("IV", 4), ("I", 1)]
   result = ""
-  var decVal = number
+  var decVal: int = number
   for key, val in items(romanComposites):
     while decVal >= val:
       dec(decVal, val)
       result.add(key)
 
 when isMainModule:
-  import math
-  randomize()
-  for i in 1 .. 100:
-    var rnd = 1 + random(3990)
-    assert rnd == rnd.decimalToRoman.romanToDecimal
+  for i in 1 .. 3_999:
+    assert i == i.decimalToRoman.romanToDecimal
 
diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim
index 4cc64a154..5c7fedfe3 100644
--- a/lib/pure/ropes.nim
+++ b/lib/pure/ropes.nim
@@ -52,9 +52,9 @@ proc len*(a: Rope): int {.rtl, extern: "nro$1".} =
   ## the rope's length
   if a == nil: result = 0
   else: result = a.length
-  
+
 proc newRope(): Rope = new(result)
-proc newRope(data: string): Rope = 
+proc newRope(data: string): Rope =
   new(result)
   result.length = len(data)
   result.data = data
@@ -65,18 +65,18 @@ var
 
 when countCacheMisses:
   var misses, hits: int
-  
-proc splay(s: string, tree: Rope, cmpres: var int): Rope = 
+
+proc splay(s: string, tree: Rope, cmpres: var int): Rope =
   var c: int
   var t = tree
   N.left = nil
   N.right = nil               # reset to nil
   var le = N
   var r = N
-  while true: 
+  while true:
     c = cmp(s, t.data)
-    if c < 0: 
-      if (t.left != nil) and (s < t.left.data): 
+    if c < 0:
+      if (t.left != nil) and (s < t.left.data):
         var y = t.left
         t.left = y.right
         y.right = t
@@ -85,8 +85,8 @@ proc splay(s: string, tree: Rope, cmpres: var int): Rope =
       r.left = t
       r = t
       t = t.left
-    elif c > 0: 
-      if (t.right != nil) and (s > t.right.data): 
+    elif c > 0:
+      if (t.right != nil) and (s > t.right.data):
         var y = t.right
         t.right = y.left
         y.left = t
@@ -95,8 +95,8 @@ proc splay(s: string, tree: Rope, cmpres: var int): Rope =
       le.right = t
       le = t
       t = t.right
-    else: 
-      break 
+    else:
+      break
   cmpres = c
   le.right = t.left
   r.left = t.right
@@ -104,50 +104,50 @@ proc splay(s: string, tree: Rope, cmpres: var int): Rope =
   t.right = N.left
   result = t
 
-proc insertInCache(s: string, tree: Rope): Rope = 
+proc insertInCache(s: string, tree: Rope): Rope =
   var t = tree
-  if t == nil: 
+  if t == nil:
     result = newRope(s)
     when countCacheMisses: inc(misses)
     return 
   var cmp: int
   t = splay(s, t, cmp)
-  if cmp == 0: 
+  if cmp == 0:
     # We get here if it's already in the Tree
     # Don't add it again
     result = t
     when countCacheMisses: inc(hits)
-  else: 
+  else:
     when countCacheMisses: inc(misses)
     result = newRope(s)
-    if cmp < 0: 
+    if cmp < 0:
       result.left = t.left
       result.right = t
       t.left = nil
-    else: 
+    else:
       # i > t.item:
       result.right = t.right
       result.left = t
       t.right = nil
 
 proc rope*(s: string): Rope {.rtl, extern: "nro$1Str".} =
-  ## Converts a string to a rope. 
-  if s.len == 0: 
+  ## Converts a string to a rope.
+  if s.len == 0:
     result = nil
-  elif cacheEnabled: 
+  elif cacheEnabled:
     result = insertInCache(s, cache)
     cache = result
-  else: 
+  else:
     result = newRope(s)
-  
-proc rope*(i: BiggestInt): Rope {.rtl, extern: "nro$1BiggestInt".} = 
-  ## Converts an int to a rope. 
+
+proc rope*(i: BiggestInt): Rope {.rtl, extern: "nro$1BiggestInt".} =
+  ## Converts an int to a rope.
   result = rope($i)
 
 proc rope*(f: BiggestFloat): Rope {.rtl, extern: "nro$1BiggestFloat".} =
-  ## Converts a float to a rope. 
+  ## Converts a float to a rope.
   result = rope($f)
-  
+
 proc enableCache*() {.rtl, extern: "nro$1".} =
   ## Enables the caching of leaves. This reduces the memory footprint at
   ## the cost of runtime efficiency.
@@ -160,9 +160,9 @@ proc disableCache*() {.rtl, extern: "nro$1".} =
 
 proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} =
   ## the concatenation operator for ropes.
-  if a == nil: 
+  if a == nil:
     result = b
-  elif b == nil: 
+  elif b == nil:
     result = a
   else:
     result = newRope()
@@ -177,16 +177,16 @@ proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} =
     else:
       result.left = a
       result.right = b
-  
-proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} = 
+
+proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} =
   ## the concatenation operator for ropes.
   result = a & rope(b)
-  
-proc `&`*(a: string, b: Rope): Rope {.rtl, extern: "nroConcStrRope".} = 
+
+proc `&`*(a: string, b: Rope): Rope {.rtl, extern: "nroConcStrRope".} =
   ## the concatenation operator for ropes.
   result = rope(a) & b
-  
-proc `&`*(a: openArray[Rope]): Rope {.rtl, extern: "nroConcOpenArray".} = 
+
+proc `&`*(a: openArray[Rope]): Rope {.rtl, extern: "nroConcOpenArray".} =
   ## the concatenation operator for an openarray of ropes.
   for i in countup(0, high(a)): result = result & a[i]
 
@@ -219,7 +219,7 @@ iterator leaves*(r: Rope): string =
   ## iterates over any leaf string in the rope `r`.
   if r != nil:
     var stack = @[r]
-    while stack.len > 0: 
+    while stack.len > 0:
       var it = stack.pop
       while isConc(it):
         stack.add(it.right)
@@ -227,7 +227,7 @@ iterator leaves*(r: Rope): string =
         assert(it != nil)
       assert(it.data != nil)
       yield it.data
-  
+
 iterator items*(r: Rope): char =
   ## iterates over any character in the rope `r`.
   for s in leaves(r):
@@ -237,7 +237,7 @@ proc write*(f: File, r: Rope) {.rtl, extern: "nro$1".} =
   ## writes a rope to a file.
   for s in leaves(r): write(f, s)
 
-proc `$`*(r: Rope): string  {.rtl, extern: "nroToString".}= 
+proc `$`*(r: Rope): string  {.rtl, extern: "nroToString".}=
   ## converts a rope back to a string.
   result = newString(r.len)
   setLen(result, 0)
@@ -251,25 +251,25 @@ when false:
     new(result)
     result.length = -idx
   
-  proc compileFrmt(frmt: string): Rope = 
+  proc compileFrmt(frmt: string): Rope =
     var i = 0
     var length = len(frmt)
     result = nil
     var num = 0
-    while i < length: 
-      if frmt[i] == '$': 
+    while i < length:
+      if frmt[i] == '$':
         inc(i)
         case frmt[i]
-        of '$': 
+        of '$':
           add(result, "$")
           inc(i)
-        of '#': 
+        of '#':
           inc(i)
           add(result, compiledArg(num+1))
           inc(num)
-        of '0'..'9': 
+        of '0'..'9':
           var j = 0
-          while true: 
+          while true:
             j = j * 10 + ord(frmt[i]) - ord('0')
             inc(i)
             if frmt[i] notin {'0'..'9'}: break 
@@ -285,13 +285,13 @@ when false:
           add(s, compiledArg(j))
         else: raise newException(EInvalidValue, "invalid format string")
       var start = i
-      while i < length: 
+      while i < length:
         if frmt[i] != '$': inc(i)
-        else: break 
-      if i - 1 >= start: 
+        else: break
+      if i - 1 >= start:
         add(result, substr(frmt, start, i-1))
-  
-proc `%`*(frmt: string, args: openArray[Rope]): Rope {. 
+
+proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
   rtl, extern: "nroFormat".} =
   ## `%` substitution operator for ropes. Does not support the ``$identifier``
   ## nor ``${identifier}`` notations.
@@ -299,23 +299,23 @@ proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
   var length = len(frmt)
   result = nil
   var num = 0
-  while i < length: 
-    if frmt[i] == '$': 
+  while i < length:
+    if frmt[i] == '$':
       inc(i)
       case frmt[i]
-      of '$': 
+      of '$':
         add(result, "$")
         inc(i)
-      of '#': 
+      of '#':
         inc(i)
         add(result, args[num])
         inc(num)
-      of '0'..'9': 
+      of '0'..'9':
         var j = 0
-        while true: 
+        while true:
           j = j * 10 + ord(frmt[i]) - ord('0')
           inc(i)
-          if frmt[i] notin {'0'..'9'}: break 
+          if frmt[i] notin {'0'..'9'}: break
         add(result, args[j-1])
       of '{':
         inc(i)
@@ -325,13 +325,14 @@ proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
           inc(i)
         if frmt[i] == '}': inc(i)
         else: raise newException(ValueError, "invalid format string")
+
         add(result, args[j-1])
       else: raise newException(ValueError, "invalid format string")
     var start = i
-    while i < length: 
+    while i < length:
       if frmt[i] != '$': inc(i)
-      else: break 
-    if i - 1 >= start: 
+      else: break
+    if i - 1 >= start:
       add(result, substr(frmt, start, i - 1))
 
 proc addf*(c: var Rope, frmt: string, args: openArray[Rope]) {.
@@ -339,29 +340,46 @@ proc addf*(c: var Rope, frmt: string, args: openArray[Rope]) {.
   ## shortcut for ``add(c, frmt % args)``.
   add(c, frmt % args)
 
+const
+  bufSize = 1024              # 1 KB is reasonable
+
 proc equalsFile*(r: Rope, f: File): bool {.rtl, extern: "nro$1File".} =
   ## returns true if the contents of the file `f` equal `r`.
-  var bufSize = 1024 # reasonable start value
-  var buf = alloc(bufSize)
+  var 
+    buf: array[bufSize, char]
+    bpos = buf.len
+    blen = buf.len
+
   for s in leaves(r):
-    if s.len > bufSize:
-      bufSize = max(bufSize * 2, s.len)
-      buf = realloc(buf, bufSize)
-    var readBytes = readBuffer(f, buf, s.len)
-    result = readBytes == s.len and equalMem(buf, cstring(s), s.len)
-    if not result: break
-  if result:
-    result = readBuffer(f, buf, 1) == 0 # really at the end of file?
-  dealloc(buf)
+    var spos = 0
+    let slen = s.len
+    while spos < slen:
+      if bpos == blen:
+        # Read more data
+        bpos = 0
+        blen = readBuffer(f, addr(buf[0]), buf.len)
+        if blen == 0:  # no more data in file
+          result = false
+          return
+      let n = min(blen - bpos, slen - spos)
+      # TODO There's gotta be a better way of comparing here...
+      if not equalMem(addr(buf[bpos]), 
+                      cast[pointer](cast[int](cstring(s))+spos), n):
+        result = false
+        return
+      spos += n
+      bpos += n
+
+  result = readBuffer(f, addr(buf[0]), 1) == 0  # check that we've read all
 
-proc equalsFile*(r: Rope, f: string): bool {.rtl, extern: "nro$1Str".} =
+proc equalsFile*(r: Rope, filename: string): bool {.rtl, extern: "nro$1Str".} =
   ## returns true if the contents of the file `f` equal `r`. If `f` does not
   ## exist, false is returned.
-  var bin: File
-  result = open(bin, f)
+  var f: File
+  result = open(f, filename)
   if result:
-    result = equalsFile(r, bin)
-    close(bin)
+    result = equalsFile(r, f)
+    close(f)
 
 new(N) # init dummy node for splay algorithm
 
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
index b6bc9dd3a..6901ecf58 100644
--- a/lib/pure/selectors.nim
+++ b/lib/pure/selectors.nim
@@ -296,7 +296,7 @@ proc contains*(s: Selector, key: SelectorKey): bool =
    TReadyInfo: ReadyInfo, PSelector: Selector].}
 
 
-when isMainModule and not defined(nimdoc):
+when not defined(testing) and isMainModule and not defined(nimdoc):
   # Select()
   import sockets
   type
diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim
index 26f0c9591..c1bc259a5 100644
--- a/lib/pure/smtp.nim
+++ b/lib/pure/smtp.nim
@@ -238,7 +238,7 @@ proc sendMail*(smtp: AsyncSmtp, fromAddr: string,
   await smtp.sock.send("MAIL FROM:<" & fromAddr & ">\c\L")
   await smtp.checkReply("250")
   for address in items(toAddrs):
-    await smtp.sock.send("RCPT TO:<" & smtp.address & ">\c\L")
+    await smtp.sock.send("RCPT TO:<" & address & ">\c\L")
     await smtp.checkReply("250")
   
   # Send the message
@@ -253,7 +253,7 @@ proc close*(smtp: AsyncSmtp) {.async.} =
   await smtp.sock.send("QUIT\c\L")
   smtp.sock.close()
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   #var msg = createMessage("Test subject!", 
   #     "Hello, my name is dom96.\n What\'s yours?", @["dominik@localhost"])
   #echo(msg)
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 655203cda..1b248126b 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -386,7 +386,7 @@ proc split*(s: string, sep: string): seq[string] {.noSideEffect,
   ## `split iterator <#split.i,string,string>`_.
   accumulateResult(split(s, sep))
 
-proc toHex*(x: BiggestInt, len: int): string {.noSideEffect,
+proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect,
   rtl, extern: "nsuToHex".} =
   ## Converts `x` to its hexadecimal representation.
   ##
@@ -403,7 +403,7 @@ proc toHex*(x: BiggestInt, len: int): string {.noSideEffect,
     # handle negative overflow
     if n == 0 and x < 0: n = -1
 
-proc intToStr*(x: int, minchars: int = 1): string {.noSideEffect,
+proc intToStr*(x: int, minchars: Positive = 1): string {.noSideEffect,
   rtl, extern: "nsuIntToStr".} =
   ## Converts `x` to its decimal representation.
   ##
@@ -499,7 +499,7 @@ proc parseEnum*[T: enum](s: string, default: T): T =
       return e
   result = default
 
-proc repeat*(c: char, count: int): string {.noSideEffect,
+proc repeat*(c: char, count: Natural): string {.noSideEffect,
   rtl, extern: "nsuRepeatChar".} =
   ## Returns a string of length `count` consisting only of
   ## the character `c`. You can use this proc to left align strings. Example:
@@ -514,7 +514,7 @@ proc repeat*(c: char, count: int): string {.noSideEffect,
   result = newString(count)
   for i in 0..count-1: result[i] = c
 
-proc repeat*(s: string, n: int): string {.noSideEffect,
+proc repeat*(s: string, n: Natural): string {.noSideEffect,
   rtl, extern: "nsuRepeatStr".} =
   ## Returns String `s` concatenated `n` times.  Example:
   ##
@@ -523,7 +523,7 @@ proc repeat*(s: string, n: int): string {.noSideEffect,
   result = newStringOfCap(n * s.len)
   for i in 1..n: result.add(s)
 
-template spaces*(n: int): string =  repeat(' ',n)
+template spaces*(n: Natural): string =  repeat(' ',n)
   ## Returns a String with `n` space characters. You can use this proc
   ## to left align strings. Example:
   ##
@@ -535,15 +535,15 @@ template spaces*(n: int): string =  repeat(' ',n)
   ##   echo text1 & spaces(max(0, width - text1.len)) & "|"
   ##   echo text2 & spaces(max(0, width - text2.len)) & "|"
 
-proc repeatChar*(count: int, c: char = ' '): string {.deprecated.} = repeat(c, count)
+proc repeatChar*(count: Natural, c: char = ' '): string {.deprecated.} = repeat(c, count)
   ## deprecated: use repeat() or spaces()
 
-proc repeatStr*(count: int, s: string): string {.deprecated.} = repeat(s, count)
+proc repeatStr*(count: Natural, s: string): string {.deprecated.} = repeat(s, count)
   ## deprecated: use repeat(string, count) or string.repeat(count)
 
-proc align*(s: string, count: int, padding = ' '): string {.
+proc align*(s: string, count: Natural, padding = ' '): string {.
   noSideEffect, rtl, extern: "nsuAlignString".} =
-  ## Aligns a string `s` with `padding`, so that is of length `count`.
+  ## Aligns a string `s` with `padding`, so that it is of length `count`.
   ##
   ## `padding` characters (by default spaces) are added before `s` resulting in
   ## right alignment. If ``s.len >= count``, no spaces are added and `s` is
@@ -682,7 +682,7 @@ proc endsWith*(s, suffix: string): bool {.noSideEffect,
     inc(i)
   if suffix[i] == '\0': return true
 
-proc continuesWith*(s, substr: string, start: int): bool {.noSideEffect,
+proc continuesWith*(s, substr: string, start: Natural): bool {.noSideEffect,
   rtl, extern: "nsuContinuesWith".} =
   ## Returns true iff ``s`` continues with ``substr`` at position ``start``.
   ##
@@ -693,8 +693,8 @@ proc continuesWith*(s, substr: string, start: int): bool {.noSideEffect,
     if s[i+start] != substr[i]: return false
     inc(i)
 
-proc addSep*(dest: var string, sep = ", ", startLen = 0) {.noSideEffect,
-                                                           inline.} =
+proc addSep*(dest: var string, sep = ", ", startLen: Natural = 0)
+  {.noSideEffect, inline.} =
   ## Adds a separator to `dest` only if its length is bigger than `startLen`.
   ##
   ## A shorthand for:
@@ -784,7 +784,7 @@ proc findAux(s, sub: string, start: int, a: SkipTable): int =
     inc(j, a[s[j+m]])
   return -1
 
-proc find*(s, sub: string, start: int = 0): int {.noSideEffect,
+proc find*(s, sub: string, start: Natural = 0): int {.noSideEffect,
   rtl, extern: "nsuFindStr".} =
   ## Searches for `sub` in `s` starting at position `start`.
   ##
@@ -793,7 +793,7 @@ proc find*(s, sub: string, start: int = 0): int {.noSideEffect,
   preprocessSub(sub, a)
   result = findAux(s, sub, start, a)
 
-proc find*(s: string, sub: char, start: int = 0): int {.noSideEffect,
+proc find*(s: string, sub: char, start: Natural = 0): int {.noSideEffect,
   rtl, extern: "nsuFindChar".} =
   ## Searches for `sub` in `s` starting at position `start`.
   ##
@@ -802,7 +802,7 @@ proc find*(s: string, sub: char, start: int = 0): int {.noSideEffect,
     if sub == s[i]: return i
   return -1
 
-proc find*(s: string, chars: set[char], start: int = 0): int {.noSideEffect,
+proc find*(s: string, chars: set[char], start: Natural = 0): int {.noSideEffect,
   rtl, extern: "nsuFindCharSet".} =
   ## Searches for `chars` in `s` starting at position `start`.
   ##
@@ -933,7 +933,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
     var j = findAux(s, sub, i, a)
     if j < 0: break
     # word boundary?
-    if (j == 0 or s[j-1] notin wordChars) and 
+    if (j == 0 or s[j-1] notin wordChars) and
         (j+sub.len >= s.len or s[j+sub.len] notin wordChars):
       add result, substr(s, i, j - 1)
       add result, by
@@ -976,7 +976,7 @@ proc parseOctInt*(s: string): int {.noSideEffect,
     of '\0': break
     else: raise newException(ValueError, "invalid integer: " & s)
 
-proc toOct*(x: BiggestInt, len: int): string {.noSideEffect,
+proc toOct*(x: BiggestInt, len: Positive): string {.noSideEffect,
   rtl, extern: "nsuToOct".} =
   ## Converts `x` into its octal representation.
   ##
@@ -992,7 +992,7 @@ proc toOct*(x: BiggestInt, len: int): string {.noSideEffect,
     shift = shift + 3
     mask = mask shl 3
 
-proc toBin*(x: BiggestInt, len: int): string {.noSideEffect,
+proc toBin*(x: BiggestInt, len: Positive): string {.noSideEffect,
   rtl, extern: "nsuToBin".} =
   ## Converts `x` into its binary representation.
   ##
@@ -1221,7 +1221,7 @@ proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault,
   ## of significant digits to be printed.
   ## `precision`'s default value is the maximum number of meaningful digits
   ## after the decimal point for Nim's ``biggestFloat`` type.
-  ## 
+  ##
   ## If ``precision == 0``, it tries to format it nicely.
   const floatFormatToChar: array[FloatFormatMode, char] = ['g', 'f', 'e']
   var
@@ -1286,7 +1286,7 @@ proc findNormalized(x: string, inArray: openArray[string]): int =
   return -1
 
 proc invalidFormatString() {.noinline.} =
-  raise newException(ValueError, "invalid format string")  
+  raise newException(ValueError, "invalid format string")
 
 proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.
   noSideEffect, rtl, extern: "nsuAddf".} =
@@ -1402,21 +1402,27 @@ when isMainModule:
   doAssert align("a", 0) == "a"
   doAssert align("1232", 6) == "  1232"
   doAssert align("1232", 6, '#') == "##1232"
-  echo wordWrap(""" this is a long text --  muchlongerthan10chars and here
-                   it goes""", 10, false)
+
+  let
+    inp = """ this is a long text --  muchlongerthan10chars and here
+               it goes"""
+    outp = " this is a\nlong text\n--\nmuchlongerthan10chars\nand here\nit goes"
+  doAssert wordWrap(inp, 10, false) == outp
+
   doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001"
   doAssert formatBiggestFloat(0.00000000001, ffScientific, 1) == "1.0e-11"
 
   doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
-  echo formatSize(1'i64 shl 31 + 300'i64) # == "4,GB"
-  echo formatSize(1'i64 shl 31)
+  when not defined(testing):
+    echo formatSize(1'i64 shl 31 + 300'i64) # == "4,GB"
+    echo formatSize(1'i64 shl 31)
 
   doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] ==
            "The cat eats fish."
 
   doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
   doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz  abc"
-  
+
   type MyEnum = enum enA, enB, enC, enuD, enE
   doAssert parseEnum[MyEnum]("enu_D") == enuD
 
diff --git a/lib/pure/subexes.nim b/lib/pure/subexes.nim
index d701b85b1..d213c99e6 100644
--- a/lib/pure/subexes.nim
+++ b/lib/pure/subexes.nim
@@ -386,8 +386,13 @@ when isMainModule:
     longishA, 
     longish)"""
   
-  echo "type TMyEnum* = enum\n  $', '2i'\n  '{..}" % ["fieldA", 
-    "fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"]
+  assert "type TMyEnum* = enum\n  $', '2i'\n  '{..}" % ["fieldA",
+    "fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"] ==
+    strutils.unindent """
+      type TMyEnum* = enum
+        fieldA, fieldB, 
+        FiledClkad, fieldD, 
+        fieldE, longishFieldName"""
   
   doAssert subex"$1($', '{2..})" % ["f", "a", "b", "c"] == "f(a, b, c)"
   
@@ -395,7 +400,12 @@ when isMainModule:
   
   doAssert subex"$['''|'|''''|']']#" % "0" == "'|"
   
-  echo subex("type\n  TEnum = enum\n    $', '40c'\n    '{..}") % [
-    "fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"]
+  assert subex("type\n  TEnum = enum\n    $', '40c'\n    '{..}") % [
+    "fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"] ==
+    strutils.unindent """
+      type
+        TEnum = enum
+          fieldNameA, fieldNameB, fieldNameC, 
+          fieldNameD"""
   
   
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim
index df637dcb6..a3c5cdcfb 100644
--- a/lib/pure/terminal.nim
+++ b/lib/pure/terminal.nim
@@ -375,7 +375,7 @@ when not defined(windows):
     result = stdin.readChar()
     discard fd.tcsetattr(TCSADRAIN, addr oldMode)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   system.addQuitProc(resetAttributes)
   write(stdout, "never mind")
   eraseLine()
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 25f6b85f6..c275ede69 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -33,36 +33,36 @@ when not defined(JS):
 
 when defined(posix) and not defined(JS):
   type
-    TimeImpl {.importc: "time_t", header: "<sys/time.h>".} = int
+    TimeImpl {.importc: "time_t", header: "<time.h>".} = int
     Time* = distinct TimeImpl ## distinct type that represents a time
                               ## measured as number of seconds since the epoch
-    
-    Timeval {.importc: "struct timeval", 
+
+    Timeval {.importc: "struct timeval",
               header: "<sys/select.h>".} = object ## struct timeval
-      tv_sec: int  ## Seconds. 
-      tv_usec: int ## Microseconds. 
-      
+      tv_sec: int  ## Seconds.
+      tv_usec: int ## Microseconds.
+
   # we cannot import posix.nim here, because posix.nim depends on times.nim.
-  # Ok, we could, but I don't want circular dependencies. 
+  # Ok, we could, but I don't want circular dependencies.
   # And gettimeofday() is not defined in the posix module anyway. Sigh.
-  
+
   proc posix_gettimeofday(tp: var Timeval, unused: pointer = nil) {.
     importc: "gettimeofday", header: "<sys/time.h>".}
 
   # we also need tzset() to make sure that tzname is initialized
-  proc tzset() {.importc, header: "<sys/time.h>".}
+  proc tzset() {.importc, header: "<time.h>".}
   # calling tzset() implicitly to initialize tzname data.
   tzset()
 
 elif defined(windows):
   import winlean
-  
+
   when defined(vcc):
     # newest version of Visual C++ defines time_t to be of 64 bits
     type TimeImpl {.importc: "time_t", header: "<time.h>".} = int64
   else:
     type TimeImpl {.importc: "time_t", header: "<time.h>".} = int32
-  
+
   type
     Time* = distinct TimeImpl
 
@@ -166,7 +166,7 @@ proc fromSeconds*(since1970: float): Time {.tags: [], raises: [], benign.}
   ## Takes a float which contains the number of seconds since the unix epoch and
   ## returns a time object.
 
-proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], benign.} = 
+proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], benign.} =
   ## Takes an int which contains the number of seconds since the unix epoch and
   ## returns a time object.
   fromSeconds(float(since1970))
@@ -184,12 +184,12 @@ proc `-`*(a, b: Time): int64 {.
   ## computes the difference of two calendar times. Result is in seconds.
 
 proc `<`*(a, b: Time): bool {.
-  rtl, extern: "ntLtTime", tags: [], raises: [].} = 
+  rtl, extern: "ntLtTime", tags: [], raises: [].} =
   ## returns true iff ``a < b``, that is iff a happened before b.
   result = a - b < 0
-  
+
 proc `<=` * (a, b: Time): bool {.
-  rtl, extern: "ntLeTime", tags: [], raises: [].}= 
+  rtl, extern: "ntLeTime", tags: [], raises: [].}=
   ## returns true iff ``a <= b``.
   result = a - b <= 0
 
@@ -211,7 +211,7 @@ proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], benign.}
   ## get the miliseconds from the start of the program. **Deprecated since
   ## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead.
 
-proc initInterval*(miliseconds, seconds, minutes, hours, days, months, 
+proc initInterval*(miliseconds, seconds, minutes, hours, days, months,
                    years: int = 0): TimeInterval =
   ## creates a new ``TimeInterval``.
   result.miliseconds = miliseconds
@@ -227,9 +227,9 @@ proc isLeapYear*(year: int): bool =
 
   if year mod 400 == 0:
     return true
-  elif year mod 100 == 0: 
+  elif year mod 100 == 0:
     return false
-  elif year mod 4 == 0: 
+  elif year mod 4 == 0:
     return true
   else:
     return false
@@ -238,7 +238,7 @@ proc getDaysInMonth*(month: Month, year: int): int =
   ## gets the amount of days in a ``month`` of a ``year``
 
   # http://www.dispersiondesign.com/articles/time/number_of_days_in_a_month
-  case month 
+  case month
   of mFeb: result = if isLeapYear(year): 29 else: 28
   of mApr, mJun, mSep, mNov: result = 30
   else: result = 31
@@ -250,7 +250,7 @@ proc toSeconds(a: TimeInfo, interval: TimeInterval): float =
   var anew = a
   var newinterv = interval
   result = 0
-  
+
   newinterv.months += interval.years * 12
   var curMonth = anew.month
   for mth in 1 .. newinterv.months:
@@ -290,18 +290,18 @@ proc `-`*(a: TimeInfo, interval: TimeInterval): TimeInfo =
   else:
     result = getLocalTime(fromSeconds(t - secs))
 
-when not defined(JS):  
+when not defined(JS):
   proc epochTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].}
     ## gets time after the UNIX epoch (1970) in seconds. It is a float
-    ## because sub-second resolution is likely to be supported (depending 
+    ## because sub-second resolution is likely to be supported (depending
     ## on the hardware/OS).
 
   proc cpuTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].}
     ## gets time spent that the CPU spent to run the current process in
     ## seconds. This may be more useful for benchmarking than ``epochTime``.
     ## However, it may measure the real time instead (depending on the OS).
-    ## The value of the result has no meaning. 
-    ## To generate useful timing values, take the difference between 
+    ## The value of the result has no meaning.
+    ## To generate useful timing values, take the difference between
     ## the results of two ``cpuTime`` calls:
     ##
     ## .. code-block:: nim
@@ -322,10 +322,10 @@ when not defined(JS):
         weekday {.importc: "tm_wday".},
         yearday {.importc: "tm_yday".},
         isdst {.importc: "tm_isdst".}: cint
-  
+
     TimeInfoPtr = ptr StructTM
     Clock {.importc: "clock_t".} = distinct int
-  
+
   proc localtime(timer: ptr Time): TimeInfoPtr {.
     importc: "localtime", header: "<time.h>", tags: [].}
   proc gmtime(timer: ptr Time): TimeInfoPtr {.
@@ -341,12 +341,12 @@ when not defined(JS):
   #  strftime(s: CString, maxsize: int, fmt: CString, t: tm): int {.
   #    importc: "strftime", header: "<time.h>".}
   proc getClock(): Clock {.importc: "clock", header: "<time.h>", tags: [TimeEffect].}
-  proc difftime(a, b: Time): float {.importc: "difftime", header: "<time.h>", 
+  proc difftime(a, b: Time): float {.importc: "difftime", header: "<time.h>",
     tags: [].}
-  
+
   var
     clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
-    
+
   # our own procs on top of that:
   proc tmToTimeInfo(tm: StructTM, local: bool): TimeInfo =
     const
@@ -370,7 +370,7 @@ when not defined(JS):
           "UTC",
       timezone: if local: getTimezone() else: 0
     )
-  
+
   proc timeInfoToTM(t: TimeInfo): StructTM =
     const
       weekDays: array [WeekDay, int8] = [1'i8,2'i8,3'i8,4'i8,5'i8,6'i8,0'i8]
@@ -383,11 +383,11 @@ when not defined(JS):
     result.weekday = weekDays[t.weekday]
     result.yearday = t.yearday
     result.isdst = if t.isDST: 1 else: 0
-  
+
   when not defined(useNimRtl):
     proc `-` (a, b: Time): int64 =
       return toBiggestInt(difftime(a, b))
-  
+
   proc getStartMilsecs(): int =
     #echo "clocks per sec: ", clocksPerSec, "clock: ", int(getClock())
     #return getClock() div (clocksPerSec div 1000)
@@ -400,37 +400,37 @@ when not defined(JS):
       posix_gettimeofday(a)
       result = a.tv_sec * 1000'i64 + a.tv_usec div 1000'i64
       #echo "result: ", result
-    
+
   proc getTime(): Time = return timec(nil)
   proc getLocalTime(t: Time): TimeInfo =
     var a = t
     result = tmToTimeInfo(localtime(addr(a))[], true)
     # copying is needed anyway to provide reentrancity; thus
     # the conversion is not expensive
-  
+
   proc getGMTime(t: Time): TimeInfo =
     var a = t
     result = tmToTimeInfo(gmtime(addr(a))[], false)
     # copying is needed anyway to provide reentrancity; thus
     # the conversion is not expensive
-  
+
   proc timeInfoToTime(timeInfo: TimeInfo): Time =
     var cTimeInfo = timeInfo # for C++ we have to make a copy,
     # because the header of mktime is broken in my version of libc
     return mktime(timeInfoToTM(cTimeInfo))
 
-  proc toStringTillNL(p: cstring): string = 
+  proc toStringTillNL(p: cstring): string =
     result = ""
     var i = 0
-    while p[i] != '\0' and p[i] != '\10' and p[i] != '\13': 
+    while p[i] != '\0' and p[i] != '\10' and p[i] != '\13':
       add(result, p[i])
       inc(i)
-    
+
   proc `$`(timeInfo: TimeInfo): string =
     # BUGFIX: asctime returns a newline at the end!
     var p = asctime(timeInfoToTM(timeInfo))
     result = toStringTillNL(p)
-  
+
   proc `$`(time: Time): string =
     # BUGFIX: ctime returns a newline at the end!
     var a = time
@@ -440,17 +440,17 @@ when not defined(JS):
     epochDiff = 116444736000000000'i64
     rateDiff = 10000000'i64 # 100 nsecs
 
-  proc unixTimeToWinTime*(t: Time): int64 = 
+  proc unixTimeToWinTime*(t: Time): int64 =
     ## converts a UNIX `Time` (``time_t``) to a Windows file time
     result = int64(t) * rateDiff + epochDiff
-    
-  proc winTimeToUnixTime*(t: int64): Time = 
+
+  proc winTimeToUnixTime*(t: int64): Time =
     ## converts a Windows time to a UNIX `Time` (``time_t``)
     result = Time((t - epochDiff) div rateDiff)
- 
+
   proc getTzname(): tuple[nonDST, DST: string] =
     return ($tzname[0], $tzname[1])
-  
+
   proc getTimezone(): int =
     return timezone
 
@@ -459,7 +459,7 @@ when not defined(JS):
   proc toSeconds(time: Time): float = float(time)
 
   when not defined(useNimRtl):
-    proc epochTime(): float = 
+    proc epochTime(): float =
       when defined(posix):
         var a: Timeval
         posix_gettimeofday(a)
@@ -473,14 +473,14 @@ when not defined(JS):
         result = toFloat(int(secs)) + toFloat(int(subsecs)) * 0.0000001
       else:
         {.error: "unknown OS".}
-      
-    proc cpuTime(): float = 
+
+    proc cpuTime(): float =
       result = toFloat(int(getClock())) / toFloat(clocksPerSec)
-    
+
 elif defined(JS):
   proc newDate(): Time {.importc: "new Date".}
   proc internGetTime(): Time {.importc: "new Date", tags: [].}
-  
+
   proc newDate(value: float): Time {.importc: "new Date".}
   proc newDate(value: string): Time {.importc: "new Date".}
   proc getTime(): Time =
@@ -490,7 +490,7 @@ elif defined(JS):
   const
     weekDays: array [0..6, WeekDay] = [
       dSun, dMon, dTue, dWed, dThu, dFri, dSat]
-  
+
   proc getLocalTime(t: Time): TimeInfo =
     result.second = t.getSeconds()
     result.minute = t.getMinutes()
@@ -510,7 +510,7 @@ elif defined(JS):
     result.year = t.getUTCFullYear()
     result.weekday = weekDays[t.getUTCDay()]
     result.yearday = 0
-  
+
   proc timeInfoToTime*(timeInfo: TimeInfo): Time =
     result = internGetTime()
     result.setSeconds(timeInfo.second)
@@ -519,16 +519,16 @@ elif defined(JS):
     result.setMonth(ord(timeInfo.month))
     result.setFullYear(timeInfo.year)
     result.setDate(timeInfo.monthday)
-  
+
   proc `$`(timeInfo: TimeInfo): string = return $(timeInfoToTime(timeInfo))
   proc `$`(time: Time): string = return $time.toLocaleString()
-    
-  proc `-` (a, b: Time): int64 = 
+
+  proc `-` (a, b: Time): int64 =
     return a.getTime() - b.getTime()
-  
+
   var
     startMilsecs = getTime()
-  
+
   proc getStartMilsecs(): int =
     ## get the miliseconds from the start of the program
     return int(getTime() - startMilsecs)
@@ -541,6 +541,8 @@ elif defined(JS):
 
   proc getTimezone(): int = result = newDate().getTimezoneOffset()
 
+  proc epochTime*(): float {.tags: [TimeEffect].} = newDate().toSeconds()
+
 proc getDateStr*(): string {.rtl, extern: "nt$1", tags: [TimeEffect].} =
   ## gets the current date as a string of the format ``YYYY-MM-DD``.
   var ti = getLocalTime(getTime())
@@ -561,7 +563,7 @@ proc `$`*(day: WeekDay): string =
 
 proc `$`*(m: Month): string =
   ## stingify operator for ``Month``.
-  const lookup: array[Month, string] = ["January", "February", "March", 
+  const lookup: array[Month, string] = ["January", "February", "March",
       "April", "May", "June", "July", "August", "September", "October",
       "November", "December"]
   return lookup[m]
@@ -682,7 +684,7 @@ proc formatToken(info: TimeInfo, token: string, buf: var string) =
 proc format*(info: TimeInfo, f: string): string =
   ## This function formats `info` as specified by `f`. The following format
   ## specifiers are available:
-  ## 
+  ##
   ## ==========  =================================================================================  ================================================
   ## Specifier   Description                                                                        Example
   ## ==========  =================================================================================  ================================================
@@ -729,14 +731,14 @@ proc format*(info: TimeInfo, f: string): string =
 
       currentF = ""
       if f[i] == '\0': break
-      
+
       if f[i] == '\'':
         inc(i) # Skip '
         while f[i] != '\'' and f.len-1 > i:
           result.add(f[i])
           inc(i)
       else: result.add(f[i])
-      
+
     else:
       # Check if the letter being added matches previous accumulated buffer.
       if currentF.len < 1 or currentF[high(currentF)] == f[i]:
@@ -803,7 +805,7 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
       info.weekday = dSat
       j += 8
     else:
-      raise newException(ValueError, "invalid day of week ")    
+      raise newException(ValueError, "invalid day of week ")
   of "h", "H":
     var pd = parseInt(value[j..j+1], sv)
     info.hour = sv
@@ -854,7 +856,7 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
     of "dec":
       info.month =  mDec
     else:
-      raise newException(ValueError, "invalid month") 
+      raise newException(ValueError, "invalid month")
     j += 3
   of "MMMM":
     if value.len >= j+7 and value[j..j+6].cmpIgnoreCase("january") == 0:
@@ -894,7 +896,7 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
       info.month =  mDec
       j += 8
     else:
-      raise newException(ValueError, "invalid month") 
+      raise newException(ValueError, "invalid month")
   of "s":
     var pd = parseInt(value[j..j+1], sv)
     info.second = sv
@@ -949,7 +951,7 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
   else:
     # Ignore the token and move forward in the value string by the same length
     j += token.len
-    
+
 proc parse*(value, layout: string): TimeInfo =
   ## This function parses a date/time string using the standard format identifiers (below)
   ## The function defaults information not provided in the format string from the running program (timezone, month, year, etc)
@@ -987,7 +989,7 @@ proc parse*(value, layout: string): TimeInfo =
   ## ``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.    
+  ## unambiguous format string like ``yyyyMMddhhmmss`` is valid too.
   var i = 0 # pointer for format string
   var j = 0 # pointer for value string
   var token = ""
@@ -1034,32 +1036,30 @@ when isMainModule:
   # Tue 19 Jan 03:14:07 GMT 2038
 
   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") == 
+    " 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" &
     " ss t tt y yy yyy yyyy yyyyy z zz zzz ZZZ") ==
     "27 27 Mon Monday 4 04 16 16 6 06 1 01 Jan January 29 29 P PM 5 75 975 1975 01975 0 00 00:00 UTC"
-  
+
   when not defined(JS) and sizeof(Time) == 8:
     var t3 = getGMTime(fromSeconds(889067643645)) # Fri  7 Jun 19:20:45 BST 30143
     assert t3.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") == 
+      " ss t tt y yy yyy yyyy yyyyy z zz zzz ZZZ") ==
       "7 07 Fri Friday 6 06 18 18 20 20 6 06 Jun June 45 45 P PM 3 43 143 0143 30143 0 00 00:00 UTC"
-    assert t3.format(":,[]()-/") == ":,[]()-/" 
-  
+    assert t3.format(":,[]()-/") == ":,[]()-/"
+
   var t4 = getGMTime(fromSeconds(876124714)) # Mon  6 Oct 08:58:34 BST 1997
   assert t4.format("M MM MMM MMMM") == "10 10 Oct October"
-  
+
   # Interval tests
   assert((t4 - initInterval(years = 2)).format("yyyy") == "1995")
   assert((t4 - initInterval(years = 7, minutes = 34, seconds = 24)).format("yyyy mm ss") == "1990 24 10")
@@ -1110,4 +1110,6 @@ when isMainModule:
   # Kitchen     = "3:04PM"
   s = "3:04PM"
   f = "h:mmtt"
-  echo "Kitchen: " & $s.parse(f)
+  assert "15:04:00" in $s.parse(f)
+  when not defined(testing):
+    echo "Kitchen: " & $s.parse(f)
diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim
index a6f8f916b..4a9f4631d 100644
--- a/lib/pure/unicode.nim
+++ b/lib/pure/unicode.nim
@@ -19,7 +19,7 @@ type
   Rune16* = distinct int16 ## 16 bit Unicode character
 
 {.deprecated: [TRune: Rune, TRune16: Rune16].}
-  
+
 proc `<=%`*(a, b: Rune): bool = return int(a) <=% int(b)
 proc `<%`*(a, b: Rune): bool = return int(a) <% int(b)
 proc `==`*(a, b: Rune): bool = return int(a) == int(b)
@@ -39,7 +39,7 @@ proc runeLen*(s: string): int {.rtl, extern: "nuc$1".} =
     else: inc i
     inc(result)
 
-proc runeLenAt*(s: string, i: int): int =
+proc runeLenAt*(s: string, i: Natural): int =
   ## returns the number of bytes the rune starting at ``s[i]`` takes.
   if ord(s[i]) <=% 127: result = 1
   elif ord(s[i]) shr 5 == 0b110: result = 2
@@ -58,7 +58,7 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
     when doInc: inc(i)
   elif ord(s[i]) shr 5 == 0b110:
     # assert(ord(s[i+1]) shr 6 == 0b10)
-    result = Rune((ord(s[i]) and (ones(5))) shl 6 or 
+    result = Rune((ord(s[i]) and (ones(5))) shl 6 or
                   (ord(s[i+1]) and ones(6)))
     when doInc: inc(i, 2)
   elif ord(s[i]) shr 4 == 0b1110:
@@ -77,7 +77,7 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
              (ord(s[i+2]) and ones(6)) shl 6 or
              (ord(s[i+3]) and ones(6)))
     when doInc: inc(i, 4)
-  elif ord(s[i]) shr 2 == 0b111110: 
+  elif ord(s[i]) shr 2 == 0b111110:
     # assert(ord(s[i+1]) shr 6 == 0b10)
     # assert(ord(s[i+2]) shr 6 == 0b10)
     # assert(ord(s[i+3]) shr 6 == 0b10)
@@ -88,7 +88,7 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
              (ord(s[i+3]) and ones(6)) shl 6 or
              (ord(s[i+4]) and ones(6)))
     when doInc: inc(i, 5)
-  elif ord(s[i]) shr 1 == 0b1111110: 
+  elif ord(s[i]) shr 1 == 0b1111110:
     # assert(ord(s[i+1]) shr 6 == 0b10)
     # assert(ord(s[i+2]) shr 6 == 0b10)
     # assert(ord(s[i+3]) shr 6 == 0b10)
@@ -105,11 +105,11 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
     result = Rune(ord(s[i]))
     when doInc: inc(i)
 
-proc runeAt*(s: string, i: int): Rune =
+proc runeAt*(s: string, i: Natural): Rune =
   ## returns the unicode character in `s` at byte index `i`
   fastRuneAt(s, i, result, false)
 
-proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} = 
+proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} =
   ## converts a rune into its UTF8 representation
   var i = RuneImpl(c)
   if i <=% 127:
@@ -159,967 +159,967 @@ proc `$`*(runes: seq[Rune]): string =
 
 const
   alphaRanges = [
-    0x00d8,  0x00f6,  #  - 
-    0x00f8,  0x01f5,  #  -    
-    0x0250,  0x02a8,  #  -    
-    0x038e,  0x03a1,  #  -    
-    0x03a3,  0x03ce,  #  -    
-    0x03d0,  0x03d6,  #  -    
-    0x03e2,  0x03f3,  #  -    
-    0x0490,  0x04c4,  #  -    
-    0x0561,  0x0587,  #  -    
-    0x05d0,  0x05ea,  #  -    
-    0x05f0,  0x05f2,  #  -    
-    0x0621,  0x063a,  #  -    
-    0x0640,  0x064a,  #  -    
-    0x0671,  0x06b7,  #  -    
-    0x06ba,  0x06be,  #  -    
-    0x06c0,  0x06ce,  #  -    
-    0x06d0,  0x06d3,  #  -    
-    0x0905,  0x0939,  #  -    
-    0x0958,  0x0961,  #  -    
-    0x0985,  0x098c,  #  -    
-    0x098f,  0x0990,  #  -    
-    0x0993,  0x09a8,  #  -    
-    0x09aa,  0x09b0,  #  -    
-    0x09b6,  0x09b9,  #  -    
-    0x09dc,  0x09dd,  #  -    
-    0x09df,  0x09e1,  #  -    
-    0x09f0,  0x09f1,  #  -    
-    0x0a05,  0x0a0a,  #  -    
-    0x0a0f,  0x0a10,  #  -    
-    0x0a13,  0x0a28,  #  -    
-    0x0a2a,  0x0a30,  #  -    
-    0x0a32,  0x0a33,  #  -    
-    0x0a35,  0x0a36,  #  -    
-    0x0a38,  0x0a39,  #  -    
-    0x0a59,  0x0a5c,  #  -    
-    0x0a85,  0x0a8b,  #  -    
-    0x0a8f,  0x0a91,  #  -    
-    0x0a93,  0x0aa8,  #  -    
-    0x0aaa,  0x0ab0,  #  -    
-    0x0ab2,  0x0ab3,  #  -    
-    0x0ab5,  0x0ab9,  #  -    
-    0x0b05,  0x0b0c,  #  -    
-    0x0b0f,  0x0b10,  #  -    
-    0x0b13,  0x0b28,  #  -    
-    0x0b2a,  0x0b30,  #  -    
-    0x0b32,  0x0b33,  #  -    
-    0x0b36,  0x0b39,  #  -    
-    0x0b5c,  0x0b5d,  #  -    
-    0x0b5f,  0x0b61,  #  -    
-    0x0b85,  0x0b8a,  #  -    
-    0x0b8e,  0x0b90,  #  -    
-    0x0b92,  0x0b95,  #  -    
-    0x0b99,  0x0b9a,  #  -    
-    0x0b9e,  0x0b9f,  #  -    
-    0x0ba3,  0x0ba4,  #  -    
-    0x0ba8,  0x0baa,  #  -    
-    0x0bae,  0x0bb5,  #  -    
-    0x0bb7,  0x0bb9,  #  -    
-    0x0c05,  0x0c0c,  #  -    
-    0x0c0e,  0x0c10,  #  -    
-    0x0c12,  0x0c28,  #  -    
-    0x0c2a,  0x0c33,  #  -    
-    0x0c35,  0x0c39,  #  -    
-    0x0c60,  0x0c61,  #  -    
-    0x0c85,  0x0c8c,  #  -    
-    0x0c8e,  0x0c90,  #  -    
-    0x0c92,  0x0ca8,  #  -    
-    0x0caa,  0x0cb3,  #  -    
-    0x0cb5,  0x0cb9,  #  -    
-    0x0ce0,  0x0ce1,  #  -    
-    0x0d05,  0x0d0c,  #  -    
-    0x0d0e,  0x0d10,  #  -    
-    0x0d12,  0x0d28,  #  -    
-    0x0d2a,  0x0d39,  #  -    
-    0x0d60,  0x0d61,  #  -    
-    0x0e01,  0x0e30,  #  -    
-    0x0e32,  0x0e33,  #  -    
-    0x0e40,  0x0e46,  #  -    
-    0x0e5a,  0x0e5b,  #  -    
-    0x0e81,  0x0e82,  #  -    
-    0x0e87,  0x0e88,  #  -    
-    0x0e94,  0x0e97,  #  -    
-    0x0e99,  0x0e9f,  #  -    
-    0x0ea1,  0x0ea3,  #  -    
-    0x0eaa,  0x0eab,  #  -    
-    0x0ead,  0x0eae,  #  -    
-    0x0eb2,  0x0eb3,  #  -    
-    0x0ec0,  0x0ec4,  #  -    
-    0x0edc,  0x0edd,  #  -    
-    0x0f18,  0x0f19,  #  -    
-    0x0f40,  0x0f47,  #  -    
-    0x0f49,  0x0f69,  #  -    
-    0x10d0,  0x10f6,  #  -    
-    0x1100,  0x1159,  #  -    
-    0x115f,  0x11a2,  #  -    
-    0x11a8,  0x11f9,  #  -    
-    0x1e00,  0x1e9b,  #  -    
-    0x1f50,  0x1f57,  #  -    
-    0x1f80,  0x1fb4,  #  -    
-    0x1fb6,  0x1fbc,  #  -    
-    0x1fc2,  0x1fc4,  #  -    
-    0x1fc6,  0x1fcc,  #  -    
-    0x1fd0,  0x1fd3,  #  -    
-    0x1fd6,  0x1fdb,  #  -    
-    0x1fe0,  0x1fec,  #  -    
-    0x1ff2,  0x1ff4,  #  -    
-    0x1ff6,  0x1ffc,  #  -    
-    0x210a,  0x2113,  #  -    
-    0x2115,  0x211d,  #  -    
-    0x2120,  0x2122,  #  -    
-    0x212a,  0x2131,  #  -    
-    0x2133,  0x2138,  #  -    
-    0x3041,  0x3094,  #  -    
-    0x30a1,  0x30fa,  #  -    
-    0x3105,  0x312c,  #  -    
-    0x3131,  0x318e,  #  -    
-    0x3192,  0x319f,  #  -    
-    0x3260,  0x327b,  #  -    
-    0x328a,  0x32b0,  #  -    
-    0x32d0,  0x32fe,  #  -    
-    0x3300,  0x3357,  #  -    
-    0x3371,  0x3376,  #  -    
-    0x337b,  0x3394,  #  -    
-    0x3399,  0x339e,  #  -    
-    0x33a9,  0x33ad,  #  -    
-    0x33b0,  0x33c1,  #  -    
-    0x33c3,  0x33c5,  #  -    
-    0x33c7,  0x33d7,  #  -    
-    0x33d9,  0x33dd,  #  -    
-    0x4e00,  0x9fff,  #  -    
-    0xac00,  0xd7a3,  #  -    
-    0xf900,  0xfb06,  #  -    
-    0xfb13,  0xfb17,  #  -    
-    0xfb1f,  0xfb28,  #  -    
-    0xfb2a,  0xfb36,  #  -    
-    0xfb38,  0xfb3c,  #  -    
-    0xfb40,  0xfb41,  #  -    
-    0xfb43,  0xfb44,  #  -    
-    0xfb46,  0xfbb1,  #  -    
-    0xfbd3,  0xfd3d,  #  -    
-    0xfd50,  0xfd8f,  #  -    
-    0xfd92,  0xfdc7,  #  -    
-    0xfdf0,  0xfdf9,  #  -    
-    0xfe70,  0xfe72,  #  -    
-    0xfe76,  0xfefc,  #  -    
-    0xff66,  0xff6f,  #  -    
-    0xff71,  0xff9d,  #  -    
-    0xffa0,  0xffbe,  #  -    
-    0xffc2,  0xffc7,  #  -    
-    0xffca,  0xffcf,  #  -    
-    0xffd2,  0xffd7,  #  -    
-    0xffda,  0xffdc]  #  -    
+    0x00d8,  0x00f6,  #  -
+    0x00f8,  0x01f5,  #  -
+    0x0250,  0x02a8,  #  -
+    0x038e,  0x03a1,  #  -
+    0x03a3,  0x03ce,  #  -
+    0x03d0,  0x03d6,  #  -
+    0x03e2,  0x03f3,  #  -
+    0x0490,  0x04c4,  #  -
+    0x0561,  0x0587,  #  -
+    0x05d0,  0x05ea,  #  -
+    0x05f0,  0x05f2,  #  -
+    0x0621,  0x063a,  #  -
+    0x0640,  0x064a,  #  -
+    0x0671,  0x06b7,  #  -
+    0x06ba,  0x06be,  #  -
+    0x06c0,  0x06ce,  #  -
+    0x06d0,  0x06d3,  #  -
+    0x0905,  0x0939,  #  -
+    0x0958,  0x0961,  #  -
+    0x0985,  0x098c,  #  -
+    0x098f,  0x0990,  #  -
+    0x0993,  0x09a8,  #  -
+    0x09aa,  0x09b0,  #  -
+    0x09b6,  0x09b9,  #  -
+    0x09dc,  0x09dd,  #  -
+    0x09df,  0x09e1,  #  -
+    0x09f0,  0x09f1,  #  -
+    0x0a05,  0x0a0a,  #  -
+    0x0a0f,  0x0a10,  #  -
+    0x0a13,  0x0a28,  #  -
+    0x0a2a,  0x0a30,  #  -
+    0x0a32,  0x0a33,  #  -
+    0x0a35,  0x0a36,  #  -
+    0x0a38,  0x0a39,  #  -
+    0x0a59,  0x0a5c,  #  -
+    0x0a85,  0x0a8b,  #  -
+    0x0a8f,  0x0a91,  #  -
+    0x0a93,  0x0aa8,  #  -
+    0x0aaa,  0x0ab0,  #  -
+    0x0ab2,  0x0ab3,  #  -
+    0x0ab5,  0x0ab9,  #  -
+    0x0b05,  0x0b0c,  #  -
+    0x0b0f,  0x0b10,  #  -
+    0x0b13,  0x0b28,  #  -
+    0x0b2a,  0x0b30,  #  -
+    0x0b32,  0x0b33,  #  -
+    0x0b36,  0x0b39,  #  -
+    0x0b5c,  0x0b5d,  #  -
+    0x0b5f,  0x0b61,  #  -
+    0x0b85,  0x0b8a,  #  -
+    0x0b8e,  0x0b90,  #  -
+    0x0b92,  0x0b95,  #  -
+    0x0b99,  0x0b9a,  #  -
+    0x0b9e,  0x0b9f,  #  -
+    0x0ba3,  0x0ba4,  #  -
+    0x0ba8,  0x0baa,  #  -
+    0x0bae,  0x0bb5,  #  -
+    0x0bb7,  0x0bb9,  #  -
+    0x0c05,  0x0c0c,  #  -
+    0x0c0e,  0x0c10,  #  -
+    0x0c12,  0x0c28,  #  -
+    0x0c2a,  0x0c33,  #  -
+    0x0c35,  0x0c39,  #  -
+    0x0c60,  0x0c61,  #  -
+    0x0c85,  0x0c8c,  #  -
+    0x0c8e,  0x0c90,  #  -
+    0x0c92,  0x0ca8,  #  -
+    0x0caa,  0x0cb3,  #  -
+    0x0cb5,  0x0cb9,  #  -
+    0x0ce0,  0x0ce1,  #  -
+    0x0d05,  0x0d0c,  #  -
+    0x0d0e,  0x0d10,  #  -
+    0x0d12,  0x0d28,  #  -
+    0x0d2a,  0x0d39,  #  -
+    0x0d60,  0x0d61,  #  -
+    0x0e01,  0x0e30,  #  -
+    0x0e32,  0x0e33,  #  -
+    0x0e40,  0x0e46,  #  -
+    0x0e5a,  0x0e5b,  #  -
+    0x0e81,  0x0e82,  #  -
+    0x0e87,  0x0e88,  #  -
+    0x0e94,  0x0e97,  #  -
+    0x0e99,  0x0e9f,  #  -
+    0x0ea1,  0x0ea3,  #  -
+    0x0eaa,  0x0eab,  #  -
+    0x0ead,  0x0eae,  #  -
+    0x0eb2,  0x0eb3,  #  -
+    0x0ec0,  0x0ec4,  #  -
+    0x0edc,  0x0edd,  #  -
+    0x0f18,  0x0f19,  #  -
+    0x0f40,  0x0f47,  #  -
+    0x0f49,  0x0f69,  #  -
+    0x10d0,  0x10f6,  #  -
+    0x1100,  0x1159,  #  -
+    0x115f,  0x11a2,  #  -
+    0x11a8,  0x11f9,  #  -
+    0x1e00,  0x1e9b,  #  -
+    0x1f50,  0x1f57,  #  -
+    0x1f80,  0x1fb4,  #  -
+    0x1fb6,  0x1fbc,  #  -
+    0x1fc2,  0x1fc4,  #  -
+    0x1fc6,  0x1fcc,  #  -
+    0x1fd0,  0x1fd3,  #  -
+    0x1fd6,  0x1fdb,  #  -
+    0x1fe0,  0x1fec,  #  -
+    0x1ff2,  0x1ff4,  #  -
+    0x1ff6,  0x1ffc,  #  -
+    0x210a,  0x2113,  #  -
+    0x2115,  0x211d,  #  -
+    0x2120,  0x2122,  #  -
+    0x212a,  0x2131,  #  -
+    0x2133,  0x2138,  #  -
+    0x3041,  0x3094,  #  -
+    0x30a1,  0x30fa,  #  -
+    0x3105,  0x312c,  #  -
+    0x3131,  0x318e,  #  -
+    0x3192,  0x319f,  #  -
+    0x3260,  0x327b,  #  -
+    0x328a,  0x32b0,  #  -
+    0x32d0,  0x32fe,  #  -
+    0x3300,  0x3357,  #  -
+    0x3371,  0x3376,  #  -
+    0x337b,  0x3394,  #  -
+    0x3399,  0x339e,  #  -
+    0x33a9,  0x33ad,  #  -
+    0x33b0,  0x33c1,  #  -
+    0x33c3,  0x33c5,  #  -
+    0x33c7,  0x33d7,  #  -
+    0x33d9,  0x33dd,  #  -
+    0x4e00,  0x9fff,  #  -
+    0xac00,  0xd7a3,  #  -
+    0xf900,  0xfb06,  #  -
+    0xfb13,  0xfb17,  #  -
+    0xfb1f,  0xfb28,  #  -
+    0xfb2a,  0xfb36,  #  -
+    0xfb38,  0xfb3c,  #  -
+    0xfb40,  0xfb41,  #  -
+    0xfb43,  0xfb44,  #  -
+    0xfb46,  0xfbb1,  #  -
+    0xfbd3,  0xfd3d,  #  -
+    0xfd50,  0xfd8f,  #  -
+    0xfd92,  0xfdc7,  #  -
+    0xfdf0,  0xfdf9,  #  -
+    0xfe70,  0xfe72,  #  -
+    0xfe76,  0xfefc,  #  -
+    0xff66,  0xff6f,  #  -
+    0xff71,  0xff9d,  #  -
+    0xffa0,  0xffbe,  #  -
+    0xffc2,  0xffc7,  #  -
+    0xffca,  0xffcf,  #  -
+    0xffd2,  0xffd7,  #  -
+    0xffda,  0xffdc]  #  -
 
   alphaSinglets = [
-    0x00aa,  #    
-    0x00b5,  #    
-    0x00ba,  #    
-    0x03da,  #    
-    0x03dc,  #    
-    0x03de,  #    
-    0x03e0,  #    
-    0x06d5,  #    
-    0x09b2,  #    
-    0x0a5e,  #    
-    0x0a8d,  #    
-    0x0ae0,  #    
-    0x0b9c,  #    
-    0x0cde,  #    
-    0x0e4f,  #    
-    0x0e84,  #    
-    0x0e8a,  #    
-    0x0e8d,  #    
-    0x0ea5,  #    
-    0x0ea7,  #    
-    0x0eb0,  #    
-    0x0ebd,  #    
-    0x1fbe,  #    
-    0x207f,  #    
-    0x20a8,  #    
-    0x2102,  #    
-    0x2107,  #    
-    0x2124,  #    
-    0x2126,  #    
-    0x2128,  #    
-    0xfb3e,  #    
-    0xfe74]  #    
+    0x00aa,  #
+    0x00b5,  #
+    0x00ba,  #
+    0x03da,  #
+    0x03dc,  #
+    0x03de,  #
+    0x03e0,  #
+    0x06d5,  #
+    0x09b2,  #
+    0x0a5e,  #
+    0x0a8d,  #
+    0x0ae0,  #
+    0x0b9c,  #
+    0x0cde,  #
+    0x0e4f,  #
+    0x0e84,  #
+    0x0e8a,  #
+    0x0e8d,  #
+    0x0ea5,  #
+    0x0ea7,  #
+    0x0eb0,  #
+    0x0ebd,  #
+    0x1fbe,  #
+    0x207f,  #
+    0x20a8,  #
+    0x2102,  #
+    0x2107,  #
+    0x2124,  #
+    0x2126,  #
+    0x2128,  #
+    0xfb3e,  #
+    0xfe74]  #
 
   spaceRanges = [
-    0x0009,  0x000a,  # tab and newline   
-    0x0020,  0x0020,  # space   
-    0x00a0,  0x00a0,  #    
-    0x2000,  0x200b,  #  -    
-    0x2028,  0x2029,  #  -     0x3000,  0x3000,  #    
-    0xfeff,  0xfeff]  #    
+    0x0009,  0x000a,  # tab and newline
+    0x0020,  0x0020,  # space
+    0x00a0,  0x00a0,  #
+    0x2000,  0x200b,  #  -
+    0x2028,  0x2029,  #  -     0x3000,  0x3000,  #
+    0xfeff,  0xfeff]  #
 
   toupperRanges = [
-    0x0061,  0x007a, 468,  # a-z A-Z   
-    0x00e0,  0x00f6, 468,  # - -   
-    0x00f8,  0x00fe, 468,  # - -   
-    0x0256,  0x0257, 295,  # - -   
-    0x0258,  0x0259, 298,  # - -   
-    0x028a,  0x028b, 283,  # - -   
-    0x03ad,  0x03af, 463,  # - -   
-    0x03b1,  0x03c1, 468,  # - -   
-    0x03c3,  0x03cb, 468,  # - -   
-    0x03cd,  0x03ce, 437,  # - -   
-    0x0430,  0x044f, 468,  # - -   
-    0x0451,  0x045c, 420,  # - -   
-    0x045e,  0x045f, 420,  # - -   
-    0x0561,  0x0586, 452,  # - -   
-    0x1f00,  0x1f07, 508,  # - -   
-    0x1f10,  0x1f15, 508,  # - -   
-    0x1f20,  0x1f27, 508,  # - -   
-    0x1f30,  0x1f37, 508,  # - -   
-    0x1f40,  0x1f45, 508,  # - -   
-    0x1f60,  0x1f67, 508,  # - -   
-    0x1f70,  0x1f71, 574,  # - -   
-    0x1f72,  0x1f75, 586,  # - -   
-    0x1f76,  0x1f77, 600,  # - -   
-    0x1f78,  0x1f79, 628,  # - -   
-    0x1f7a,  0x1f7b, 612,  # - -   
-    0x1f7c,  0x1f7d, 626,  # - -   
-    0x1f80,  0x1f87, 508,  # - -   
-    0x1f90,  0x1f97, 508,  # - -   
-    0x1fa0,  0x1fa7, 508,  # - -   
-    0x1fb0,  0x1fb1, 508,  # - -   
-    0x1fd0,  0x1fd1, 508,  # - -   
-    0x1fe0,  0x1fe1, 508,  # - -   
-    0x2170,  0x217f, 484,  # - -   
-    0x24d0,  0x24e9, 474,  # - -   
-    0xff41,  0xff5a, 468]  # - -   
+    0x0061,  0x007a, 468,  # a-z A-Z
+    0x00e0,  0x00f6, 468,  # - -
+    0x00f8,  0x00fe, 468,  # - -
+    0x0256,  0x0257, 295,  # - -
+    0x0258,  0x0259, 298,  # - -
+    0x028a,  0x028b, 283,  # - -
+    0x03ad,  0x03af, 463,  # - -
+    0x03b1,  0x03c1, 468,  # - -
+    0x03c3,  0x03cb, 468,  # - -
+    0x03cd,  0x03ce, 437,  # - -
+    0x0430,  0x044f, 468,  # - -
+    0x0451,  0x045c, 420,  # - -
+    0x045e,  0x045f, 420,  # - -
+    0x0561,  0x0586, 452,  # - -
+    0x1f00,  0x1f07, 508,  # - -
+    0x1f10,  0x1f15, 508,  # - -
+    0x1f20,  0x1f27, 508,  # - -
+    0x1f30,  0x1f37, 508,  # - -
+    0x1f40,  0x1f45, 508,  # - -
+    0x1f60,  0x1f67, 508,  # - -
+    0x1f70,  0x1f71, 574,  # - -
+    0x1f72,  0x1f75, 586,  # - -
+    0x1f76,  0x1f77, 600,  # - -
+    0x1f78,  0x1f79, 628,  # - -
+    0x1f7a,  0x1f7b, 612,  # - -
+    0x1f7c,  0x1f7d, 626,  # - -
+    0x1f80,  0x1f87, 508,  # - -
+    0x1f90,  0x1f97, 508,  # - -
+    0x1fa0,  0x1fa7, 508,  # - -
+    0x1fb0,  0x1fb1, 508,  # - -
+    0x1fd0,  0x1fd1, 508,  # - -
+    0x1fe0,  0x1fe1, 508,  # - -
+    0x2170,  0x217f, 484,  # - -
+    0x24d0,  0x24e9, 474,  # - -
+    0xff41,  0xff5a, 468]  # - -
 
   toupperSinglets = [
-    0x00ff, 621,  #     
-    0x0101, 499,  #     
-    0x0103, 499,  #     
-    0x0105, 499,  #     
-    0x0107, 499,  #     
-    0x0109, 499,  #     
-    0x010b, 499,  #     
-    0x010d, 499,  #     
-    0x010f, 499,  #     
-    0x0111, 499,  #     
-    0x0113, 499,  #     
-    0x0115, 499,  #     
-    0x0117, 499,  #     
-    0x0119, 499,  #     
-    0x011b, 499,  #     
-    0x011d, 499,  #     
-    0x011f, 499,  #     
-    0x0121, 499,  #     
-    0x0123, 499,  #     
-    0x0125, 499,  #     
-    0x0127, 499,  #     
-    0x0129, 499,  #     
-    0x012b, 499,  #     
-    0x012d, 499,  #     
-    0x012f, 499,  #     
-    0x0131, 268,  #  I   
-    0x0133, 499,  #     
-    0x0135, 499,  #     
-    0x0137, 499,  #     
-    0x013a, 499,  #     
-    0x013c, 499,  #     
-    0x013e, 499,  #     
-    0x0140, 499,  #     
-    0x0142, 499,  #     
-    0x0144, 499,  #     
-    0x0146, 499,  #     
-    0x0148, 499,  #     
-    0x014b, 499,  #     
-    0x014d, 499,  #     
-    0x014f, 499,  #     
-    0x0151, 499,  #     
-    0x0153, 499,  #     
-    0x0155, 499,  #     
-    0x0157, 499,  #     
-    0x0159, 499,  #     
-    0x015b, 499,  #     
-    0x015d, 499,  #     
-    0x015f, 499,  #     
-    0x0161, 499,  #     
-    0x0163, 499,  #     
-    0x0165, 499,  #     
-    0x0167, 499,  #     
-    0x0169, 499,  #     
-    0x016b, 499,  #     
-    0x016d, 499,  #     
-    0x016f, 499,  #     
-    0x0171, 499,  #     
-    0x0173, 499,  #     
-    0x0175, 499,  #     
-    0x0177, 499,  #     
-    0x017a, 499,  #     
-    0x017c, 499,  #     
-    0x017e, 499,  #     
-    0x017f, 200,  #  S   
-    0x0183, 499,  #     
-    0x0185, 499,  #     
-    0x0188, 499,  #     
-    0x018c, 499,  #     
-    0x0192, 499,  #     
-    0x0199, 499,  #     
-    0x01a1, 499,  #     
-    0x01a3, 499,  #     
-    0x01a5, 499,  #     
-    0x01a8, 499,  #     
-    0x01ad, 499,  #     
-    0x01b0, 499,  #     
-    0x01b4, 499,  #     
-    0x01b6, 499,  #     
-    0x01b9, 499,  #     
-    0x01bd, 499,  #     
-    0x01c5, 499,  #     
-    0x01c6, 498,  #     
-    0x01c8, 499,  #     
-    0x01c9, 498,  #     
-    0x01cb, 499,  #     
-    0x01cc, 498,  #     
-    0x01ce, 499,  #     
-    0x01d0, 499,  #     
-    0x01d2, 499,  #     
-    0x01d4, 499,  #     
-    0x01d6, 499,  #     
-    0x01d8, 499,  #     
-    0x01da, 499,  #     
-    0x01dc, 499,  #     
-    0x01df, 499,  #     
-    0x01e1, 499,  #     
-    0x01e3, 499,  #     
-    0x01e5, 499,  #     
-    0x01e7, 499,  #     
-    0x01e9, 499,  #     
-    0x01eb, 499,  #     
-    0x01ed, 499,  #     
-    0x01ef, 499,  #     
-    0x01f2, 499,  #     
-    0x01f3, 498,  #     
-    0x01f5, 499,  #     
-    0x01fb, 499,  #     
-    0x01fd, 499,  #     
-    0x01ff, 499,  #     
-    0x0201, 499,  #     
-    0x0203, 499,  #     
-    0x0205, 499,  #     
-    0x0207, 499,  #     
-    0x0209, 499,  #     
-    0x020b, 499,  #     
-    0x020d, 499,  #     
-    0x020f, 499,  #     
-    0x0211, 499,  #     
-    0x0213, 499,  #     
-    0x0215, 499,  #     
-    0x0217, 499,  #     
-    0x0253, 290,  #     
-    0x0254, 294,  #     
-    0x025b, 297,  #     
-    0x0260, 295,  #     
-    0x0263, 293,  #     
-    0x0268, 291,  #     
-    0x0269, 289,  #     
-    0x026f, 289,  #     
-    0x0272, 287,  #     
-    0x0283, 282,  #     
-    0x0288, 282,  #     
-    0x0292, 281,  #     
-    0x03ac, 462,  #     
-    0x03cc, 436,  #     
-    0x03d0, 438,  #     
-    0x03d1, 443,  #     
-    0x03d5, 453,  #     
-    0x03d6, 446,  #     
-    0x03e3, 499,  #     
-    0x03e5, 499,  #     
-    0x03e7, 499,  #     
-    0x03e9, 499,  #     
-    0x03eb, 499,  #     
-    0x03ed, 499,  #     
-    0x03ef, 499,  #     
-    0x03f0, 414,  #     
-    0x03f1, 420,  #     
-    0x0461, 499,  #     
-    0x0463, 499,  #     
-    0x0465, 499,  #     
-    0x0467, 499,  #     
-    0x0469, 499,  #     
-    0x046b, 499,  #     
-    0x046d, 499,  #     
-    0x046f, 499,  #     
-    0x0471, 499,  #     
-    0x0473, 499,  #     
-    0x0475, 499,  #     
-    0x0477, 499,  #     
-    0x0479, 499,  #     
-    0x047b, 499,  #     
-    0x047d, 499,  #     
-    0x047f, 499,  #     
-    0x0481, 499,  #     
-    0x0491, 499,  #     
-    0x0493, 499,  #     
-    0x0495, 499,  #     
-    0x0497, 499,  #     
-    0x0499, 499,  #     
-    0x049b, 499,  #     
-    0x049d, 499,  #     
-    0x049f, 499,  #     
-    0x04a1, 499,  #     
-    0x04a3, 499,  #     
-    0x04a5, 499,  #     
-    0x04a7, 499,  #     
-    0x04a9, 499,  #     
-    0x04ab, 499,  #     
-    0x04ad, 499,  #     
-    0x04af, 499,  #     
-    0x04b1, 499,  #     
-    0x04b3, 499,  #     
-    0x04b5, 499,  #     
-    0x04b7, 499,  #     
-    0x04b9, 499,  #     
-    0x04bb, 499,  #     
-    0x04bd, 499,  #     
-    0x04bf, 499,  #     
-    0x04c2, 499,  #     
-    0x04c4, 499,  #     
-    0x04c8, 499,  #     
-    0x04cc, 499,  #     
-    0x04d1, 499,  #     
-    0x04d3, 499,  #     
-    0x04d5, 499,  #     
-    0x04d7, 499,  #     
-    0x04d9, 499,  #     
-    0x04db, 499,  #     
-    0x04dd, 499,  #     
-    0x04df, 499,  #     
-    0x04e1, 499,  #     
-    0x04e3, 499,  #     
-    0x04e5, 499,  #     
-    0x04e7, 499,  #     
-    0x04e9, 499,  #     
-    0x04eb, 499,  #     
-    0x04ef, 499,  #     
-    0x04f1, 499,  #     
-    0x04f3, 499,  #     
-    0x04f5, 499,  #     
-    0x04f9, 499,  #     
-    0x1e01, 499,  #     
-    0x1e03, 499,  #     
-    0x1e05, 499,  #     
-    0x1e07, 499,  #     
-    0x1e09, 499,  #     
-    0x1e0b, 499,  #     
-    0x1e0d, 499,  #     
-    0x1e0f, 499,  #     
-    0x1e11, 499,  #     
-    0x1e13, 499,  #     
-    0x1e15, 499,  #     
-    0x1e17, 499,  #     
-    0x1e19, 499,  #     
-    0x1e1b, 499,  #     
-    0x1e1d, 499,  #     
-    0x1e1f, 499,  #     
-    0x1e21, 499,  #     
-    0x1e23, 499,  #     
-    0x1e25, 499,  #     
-    0x1e27, 499,  #     
-    0x1e29, 499,  #     
-    0x1e2b, 499,  #     
-    0x1e2d, 499,  #     
-    0x1e2f, 499,  #     
-    0x1e31, 499,  #     
-    0x1e33, 499,  #     
-    0x1e35, 499,  #     
-    0x1e37, 499,  #     
-    0x1e39, 499,  #     
-    0x1e3b, 499,  #     
-    0x1e3d, 499,  #     
-    0x1e3f, 499,  #     
-    0x1e41, 499,  #     
-    0x1e43, 499,  #     
-    0x1e45, 499,  #     
-    0x1e47, 499,  #     
-    0x1e49, 499,  #     
-    0x1e4b, 499,  #     
-    0x1e4d, 499,  #     
-    0x1e4f, 499,  #     
-    0x1e51, 499,  #     
-    0x1e53, 499,  #     
-    0x1e55, 499,  #     
-    0x1e57, 499,  #     
-    0x1e59, 499,  #     
-    0x1e5b, 499,  #     
-    0x1e5d, 499,  #     
-    0x1e5f, 499,  #     
-    0x1e61, 499,  #     
-    0x1e63, 499,  #     
-    0x1e65, 499,  #     
-    0x1e67, 499,  #     
-    0x1e69, 499,  #     
-    0x1e6b, 499,  #     
-    0x1e6d, 499,  #     
-    0x1e6f, 499,  #     
-    0x1e71, 499,  #     
-    0x1e73, 499,  #     
-    0x1e75, 499,  #     
-    0x1e77, 499,  #     
-    0x1e79, 499,  #     
-    0x1e7b, 499,  #     
-    0x1e7d, 499,  #     
-    0x1e7f, 499,  #     
-    0x1e81, 499,  #     
-    0x1e83, 499,  #     
-    0x1e85, 499,  #     
-    0x1e87, 499,  #     
-    0x1e89, 499,  #     
-    0x1e8b, 499,  #     
-    0x1e8d, 499,  #     
-    0x1e8f, 499,  #     
-    0x1e91, 499,  #     
-    0x1e93, 499,  #     
-    0x1e95, 499,  #     
-    0x1ea1, 499,  #     
-    0x1ea3, 499,  #     
-    0x1ea5, 499,  #     
-    0x1ea7, 499,  #     
-    0x1ea9, 499,  #     
-    0x1eab, 499,  #     
-    0x1ead, 499,  #     
-    0x1eaf, 499,  #     
-    0x1eb1, 499,  #     
-    0x1eb3, 499,  #     
-    0x1eb5, 499,  #     
-    0x1eb7, 499,  #     
-    0x1eb9, 499,  #     
-    0x1ebb, 499,  #     
-    0x1ebd, 499,  #     
-    0x1ebf, 499,  #     
-    0x1ec1, 499,  #     
-    0x1ec3, 499,  #     
-    0x1ec5, 499,  #     
-    0x1ec7, 499,  #     
-    0x1ec9, 499,  #     
-    0x1ecb, 499,  #     
-    0x1ecd, 499,  #     
-    0x1ecf, 499,  #     
-    0x1ed1, 499,  #     
-    0x1ed3, 499,  #     
-    0x1ed5, 499,  #     
-    0x1ed7, 499,  #     
-    0x1ed9, 499,  #     
-    0x1edb, 499,  #     
-    0x1edd, 499,  #     
-    0x1edf, 499,  #     
-    0x1ee1, 499,  #     
-    0x1ee3, 499,  #     
-    0x1ee5, 499,  #     
-    0x1ee7, 499,  #     
-    0x1ee9, 499,  #     
-    0x1eeb, 499,  #     
-    0x1eed, 499,  #     
-    0x1eef, 499,  #     
-    0x1ef1, 499,  #     
-    0x1ef3, 499,  #     
-    0x1ef5, 499,  #     
-    0x1ef7, 499,  #     
-    0x1ef9, 499,  #     
-    0x1f51, 508,  #     
-    0x1f53, 508,  #     
-    0x1f55, 508,  #     
-    0x1f57, 508,  #     
-    0x1fb3, 509,  #     
-    0x1fc3, 509,  #     
-    0x1fe5, 507,  #     
-    0x1ff3, 509]  #     
+    0x00ff, 621,  #
+    0x0101, 499,  #
+    0x0103, 499,  #
+    0x0105, 499,  #
+    0x0107, 499,  #
+    0x0109, 499,  #
+    0x010b, 499,  #
+    0x010d, 499,  #
+    0x010f, 499,  #
+    0x0111, 499,  #
+    0x0113, 499,  #
+    0x0115, 499,  #
+    0x0117, 499,  #
+    0x0119, 499,  #
+    0x011b, 499,  #
+    0x011d, 499,  #
+    0x011f, 499,  #
+    0x0121, 499,  #
+    0x0123, 499,  #
+    0x0125, 499,  #
+    0x0127, 499,  #
+    0x0129, 499,  #
+    0x012b, 499,  #
+    0x012d, 499,  #
+    0x012f, 499,  #
+    0x0131, 268,  #  I
+    0x0133, 499,  #
+    0x0135, 499,  #
+    0x0137, 499,  #
+    0x013a, 499,  #
+    0x013c, 499,  #
+    0x013e, 499,  #
+    0x0140, 499,  #
+    0x0142, 499,  #
+    0x0144, 499,  #
+    0x0146, 499,  #
+    0x0148, 499,  #
+    0x014b, 499,  #
+    0x014d, 499,  #
+    0x014f, 499,  #
+    0x0151, 499,  #
+    0x0153, 499,  #
+    0x0155, 499,  #
+    0x0157, 499,  #
+    0x0159, 499,  #
+    0x015b, 499,  #
+    0x015d, 499,  #
+    0x015f, 499,  #
+    0x0161, 499,  #
+    0x0163, 499,  #
+    0x0165, 499,  #
+    0x0167, 499,  #
+    0x0169, 499,  #
+    0x016b, 499,  #
+    0x016d, 499,  #
+    0x016f, 499,  #
+    0x0171, 499,  #
+    0x0173, 499,  #
+    0x0175, 499,  #
+    0x0177, 499,  #
+    0x017a, 499,  #
+    0x017c, 499,  #
+    0x017e, 499,  #
+    0x017f, 200,  #  S
+    0x0183, 499,  #
+    0x0185, 499,  #
+    0x0188, 499,  #
+    0x018c, 499,  #
+    0x0192, 499,  #
+    0x0199, 499,  #
+    0x01a1, 499,  #
+    0x01a3, 499,  #
+    0x01a5, 499,  #
+    0x01a8, 499,  #
+    0x01ad, 499,  #
+    0x01b0, 499,  #
+    0x01b4, 499,  #
+    0x01b6, 499,  #
+    0x01b9, 499,  #
+    0x01bd, 499,  #
+    0x01c5, 499,  #
+    0x01c6, 498,  #
+    0x01c8, 499,  #
+    0x01c9, 498,  #
+    0x01cb, 499,  #
+    0x01cc, 498,  #
+    0x01ce, 499,  #
+    0x01d0, 499,  #
+    0x01d2, 499,  #
+    0x01d4, 499,  #
+    0x01d6, 499,  #
+    0x01d8, 499,  #
+    0x01da, 499,  #
+    0x01dc, 499,  #
+    0x01df, 499,  #
+    0x01e1, 499,  #
+    0x01e3, 499,  #
+    0x01e5, 499,  #
+    0x01e7, 499,  #
+    0x01e9, 499,  #
+    0x01eb, 499,  #
+    0x01ed, 499,  #
+    0x01ef, 499,  #
+    0x01f2, 499,  #
+    0x01f3, 498,  #
+    0x01f5, 499,  #
+    0x01fb, 499,  #
+    0x01fd, 499,  #
+    0x01ff, 499,  #
+    0x0201, 499,  #
+    0x0203, 499,  #
+    0x0205, 499,  #
+    0x0207, 499,  #
+    0x0209, 499,  #
+    0x020b, 499,  #
+    0x020d, 499,  #
+    0x020f, 499,  #
+    0x0211, 499,  #
+    0x0213, 499,  #
+    0x0215, 499,  #
+    0x0217, 499,  #
+    0x0253, 290,  #
+    0x0254, 294,  #
+    0x025b, 297,  #
+    0x0260, 295,  #
+    0x0263, 293,  #
+    0x0268, 291,  #
+    0x0269, 289,  #
+    0x026f, 289,  #
+    0x0272, 287,  #
+    0x0283, 282,  #
+    0x0288, 282,  #
+    0x0292, 281,  #
+    0x03ac, 462,  #
+    0x03cc, 436,  #
+    0x03d0, 438,  #
+    0x03d1, 443,  #
+    0x03d5, 453,  #
+    0x03d6, 446,  #
+    0x03e3, 499,  #
+    0x03e5, 499,  #
+    0x03e7, 499,  #
+    0x03e9, 499,  #
+    0x03eb, 499,  #
+    0x03ed, 499,  #
+    0x03ef, 499,  #
+    0x03f0, 414,  #
+    0x03f1, 420,  #
+    0x0461, 499,  #
+    0x0463, 499,  #
+    0x0465, 499,  #
+    0x0467, 499,  #
+    0x0469, 499,  #
+    0x046b, 499,  #
+    0x046d, 499,  #
+    0x046f, 499,  #
+    0x0471, 499,  #
+    0x0473, 499,  #
+    0x0475, 499,  #
+    0x0477, 499,  #
+    0x0479, 499,  #
+    0x047b, 499,  #
+    0x047d, 499,  #
+    0x047f, 499,  #
+    0x0481, 499,  #
+    0x0491, 499,  #
+    0x0493, 499,  #
+    0x0495, 499,  #
+    0x0497, 499,  #
+    0x0499, 499,  #
+    0x049b, 499,  #
+    0x049d, 499,  #
+    0x049f, 499,  #
+    0x04a1, 499,  #
+    0x04a3, 499,  #
+    0x04a5, 499,  #
+    0x04a7, 499,  #
+    0x04a9, 499,  #
+    0x04ab, 499,  #
+    0x04ad, 499,  #
+    0x04af, 499,  #
+    0x04b1, 499,  #
+    0x04b3, 499,  #
+    0x04b5, 499,  #
+    0x04b7, 499,  #
+    0x04b9, 499,  #
+    0x04bb, 499,  #
+    0x04bd, 499,  #
+    0x04bf, 499,  #
+    0x04c2, 499,  #
+    0x04c4, 499,  #
+    0x04c8, 499,  #
+    0x04cc, 499,  #
+    0x04d1, 499,  #
+    0x04d3, 499,  #
+    0x04d5, 499,  #
+    0x04d7, 499,  #
+    0x04d9, 499,  #
+    0x04db, 499,  #
+    0x04dd, 499,  #
+    0x04df, 499,  #
+    0x04e1, 499,  #
+    0x04e3, 499,  #
+    0x04e5, 499,  #
+    0x04e7, 499,  #
+    0x04e9, 499,  #
+    0x04eb, 499,  #
+    0x04ef, 499,  #
+    0x04f1, 499,  #
+    0x04f3, 499,  #
+    0x04f5, 499,  #
+    0x04f9, 499,  #
+    0x1e01, 499,  #
+    0x1e03, 499,  #
+    0x1e05, 499,  #
+    0x1e07, 499,  #
+    0x1e09, 499,  #
+    0x1e0b, 499,  #
+    0x1e0d, 499,  #
+    0x1e0f, 499,  #
+    0x1e11, 499,  #
+    0x1e13, 499,  #
+    0x1e15, 499,  #
+    0x1e17, 499,  #
+    0x1e19, 499,  #
+    0x1e1b, 499,  #
+    0x1e1d, 499,  #
+    0x1e1f, 499,  #
+    0x1e21, 499,  #
+    0x1e23, 499,  #
+    0x1e25, 499,  #
+    0x1e27, 499,  #
+    0x1e29, 499,  #
+    0x1e2b, 499,  #
+    0x1e2d, 499,  #
+    0x1e2f, 499,  #
+    0x1e31, 499,  #
+    0x1e33, 499,  #
+    0x1e35, 499,  #
+    0x1e37, 499,  #
+    0x1e39, 499,  #
+    0x1e3b, 499,  #
+    0x1e3d, 499,  #
+    0x1e3f, 499,  #
+    0x1e41, 499,  #
+    0x1e43, 499,  #
+    0x1e45, 499,  #
+    0x1e47, 499,  #
+    0x1e49, 499,  #
+    0x1e4b, 499,  #
+    0x1e4d, 499,  #
+    0x1e4f, 499,  #
+    0x1e51, 499,  #
+    0x1e53, 499,  #
+    0x1e55, 499,  #
+    0x1e57, 499,  #
+    0x1e59, 499,  #
+    0x1e5b, 499,  #
+    0x1e5d, 499,  #
+    0x1e5f, 499,  #
+    0x1e61, 499,  #
+    0x1e63, 499,  #
+    0x1e65, 499,  #
+    0x1e67, 499,  #
+    0x1e69, 499,  #
+    0x1e6b, 499,  #
+    0x1e6d, 499,  #
+    0x1e6f, 499,  #
+    0x1e71, 499,  #
+    0x1e73, 499,  #
+    0x1e75, 499,  #
+    0x1e77, 499,  #
+    0x1e79, 499,  #
+    0x1e7b, 499,  #
+    0x1e7d, 499,  #
+    0x1e7f, 499,  #
+    0x1e81, 499,  #
+    0x1e83, 499,  #
+    0x1e85, 499,  #
+    0x1e87, 499,  #
+    0x1e89, 499,  #
+    0x1e8b, 499,  #
+    0x1e8d, 499,  #
+    0x1e8f, 499,  #
+    0x1e91, 499,  #
+    0x1e93, 499,  #
+    0x1e95, 499,  #
+    0x1ea1, 499,  #
+    0x1ea3, 499,  #
+    0x1ea5, 499,  #
+    0x1ea7, 499,  #
+    0x1ea9, 499,  #
+    0x1eab, 499,  #
+    0x1ead, 499,  #
+    0x1eaf, 499,  #
+    0x1eb1, 499,  #
+    0x1eb3, 499,  #
+    0x1eb5, 499,  #
+    0x1eb7, 499,  #
+    0x1eb9, 499,  #
+    0x1ebb, 499,  #
+    0x1ebd, 499,  #
+    0x1ebf, 499,  #
+    0x1ec1, 499,  #
+    0x1ec3, 499,  #
+    0x1ec5, 499,  #
+    0x1ec7, 499,  #
+    0x1ec9, 499,  #
+    0x1ecb, 499,  #
+    0x1ecd, 499,  #
+    0x1ecf, 499,  #
+    0x1ed1, 499,  #
+    0x1ed3, 499,  #
+    0x1ed5, 499,  #
+    0x1ed7, 499,  #
+    0x1ed9, 499,  #
+    0x1edb, 499,  #
+    0x1edd, 499,  #
+    0x1edf, 499,  #
+    0x1ee1, 499,  #
+    0x1ee3, 499,  #
+    0x1ee5, 499,  #
+    0x1ee7, 499,  #
+    0x1ee9, 499,  #
+    0x1eeb, 499,  #
+    0x1eed, 499,  #
+    0x1eef, 499,  #
+    0x1ef1, 499,  #
+    0x1ef3, 499,  #
+    0x1ef5, 499,  #
+    0x1ef7, 499,  #
+    0x1ef9, 499,  #
+    0x1f51, 508,  #
+    0x1f53, 508,  #
+    0x1f55, 508,  #
+    0x1f57, 508,  #
+    0x1fb3, 509,  #
+    0x1fc3, 509,  #
+    0x1fe5, 507,  #
+    0x1ff3, 509]  #
 
   tolowerRanges = [
     0x0041,  0x005a, 532,  # A-Z a-z
-    0x00c0,  0x00d6, 532,  # - -   
-    0x00d8,  0x00de, 532,  # - -   
-    0x0189,  0x018a, 705,  # - -   
-    0x018e,  0x018f, 702,  # - -   
-    0x01b1,  0x01b2, 717,  # - -   
-    0x0388,  0x038a, 537,  # - -   
-    0x038e,  0x038f, 563,  # - -   
-    0x0391,  0x03a1, 532,  # - -   
-    0x03a3,  0x03ab, 532,  # - -   
-    0x0401,  0x040c, 580,  # - -   
-    0x040e,  0x040f, 580,  # - -   
-    0x0410,  0x042f, 532,  # - -   
-    0x0531,  0x0556, 548,  # - -   
-    0x10a0,  0x10c5, 548,  # - -   
-    0x1f08,  0x1f0f, 492,  # - -   
-    0x1f18,  0x1f1d, 492,  # - -   
-    0x1f28,  0x1f2f, 492,  # - -   
-    0x1f38,  0x1f3f, 492,  # - -   
-    0x1f48,  0x1f4d, 492,  # - -   
-    0x1f68,  0x1f6f, 492,  # - -   
-    0x1f88,  0x1f8f, 492,  # - -   
-    0x1f98,  0x1f9f, 492,  # - -   
-    0x1fa8,  0x1faf, 492,  # - -   
-    0x1fb8,  0x1fb9, 492,  # - -   
-    0x1fba,  0x1fbb, 426,  # - -   
-    0x1fc8,  0x1fcb, 414,  # - -   
-    0x1fd8,  0x1fd9, 492,  # - -   
-    0x1fda,  0x1fdb, 400,  # - -   
-    0x1fe8,  0x1fe9, 492,  # - -   
-    0x1fea,  0x1feb, 388,  # - -   
-    0x1ff8,  0x1ff9, 372,  # - -   
-    0x1ffa,  0x1ffb, 374,  # - -   
-    0x2160,  0x216f, 516,  # - -   
-    0x24b6,  0x24cf, 526,  # - -   
-    0xff21,  0xff3a, 532]  # - -   
+    0x00c0,  0x00d6, 532,  # - -
+    0x00d8,  0x00de, 532,  # - -
+    0x0189,  0x018a, 705,  # - -
+    0x018e,  0x018f, 702,  # - -
+    0x01b1,  0x01b2, 717,  # - -
+    0x0388,  0x038a, 537,  # - -
+    0x038e,  0x038f, 563,  # - -
+    0x0391,  0x03a1, 532,  # - -
+    0x03a3,  0x03ab, 532,  # - -
+    0x0401,  0x040c, 580,  # - -
+    0x040e,  0x040f, 580,  # - -
+    0x0410,  0x042f, 532,  # - -
+    0x0531,  0x0556, 548,  # - -
+    0x10a0,  0x10c5, 548,  # - -
+    0x1f08,  0x1f0f, 492,  # - -
+    0x1f18,  0x1f1d, 492,  # - -
+    0x1f28,  0x1f2f, 492,  # - -
+    0x1f38,  0x1f3f, 492,  # - -
+    0x1f48,  0x1f4d, 492,  # - -
+    0x1f68,  0x1f6f, 492,  # - -
+    0x1f88,  0x1f8f, 492,  # - -
+    0x1f98,  0x1f9f, 492,  # - -
+    0x1fa8,  0x1faf, 492,  # - -
+    0x1fb8,  0x1fb9, 492,  # - -
+    0x1fba,  0x1fbb, 426,  # - -
+    0x1fc8,  0x1fcb, 414,  # - -
+    0x1fd8,  0x1fd9, 492,  # - -
+    0x1fda,  0x1fdb, 400,  # - -
+    0x1fe8,  0x1fe9, 492,  # - -
+    0x1fea,  0x1feb, 388,  # - -
+    0x1ff8,  0x1ff9, 372,  # - -
+    0x1ffa,  0x1ffb, 374,  # - -
+    0x2160,  0x216f, 516,  # - -
+    0x24b6,  0x24cf, 526,  # - -
+    0xff21,  0xff3a, 532]  # - -
 
   tolowerSinglets = [
-    0x0100, 501,  #     
-    0x0102, 501,  #     
-    0x0104, 501,  #     
-    0x0106, 501,  #     
-    0x0108, 501,  #     
-    0x010a, 501,  #     
-    0x010c, 501,  #     
-    0x010e, 501,  #     
-    0x0110, 501,  #     
-    0x0112, 501,  #     
-    0x0114, 501,  #     
-    0x0116, 501,  #     
-    0x0118, 501,  #     
-    0x011a, 501,  #     
-    0x011c, 501,  #     
-    0x011e, 501,  #     
-    0x0120, 501,  #     
-    0x0122, 501,  #     
-    0x0124, 501,  #     
-    0x0126, 501,  #     
-    0x0128, 501,  #     
-    0x012a, 501,  #     
-    0x012c, 501,  #     
-    0x012e, 501,  #     
-    0x0130, 301,  #  i   
-    0x0132, 501,  #     
-    0x0134, 501,  #     
-    0x0136, 501,  #     
-    0x0139, 501,  #     
-    0x013b, 501,  #     
-    0x013d, 501,  #     
-    0x013f, 501,  #     
-    0x0141, 501,  #     
-    0x0143, 501,  #     
-    0x0145, 501,  #     
-    0x0147, 501,  #     
-    0x014a, 501,  #     
-    0x014c, 501,  #     
-    0x014e, 501,  #     
-    0x0150, 501,  #     
-    0x0152, 501,  #     
-    0x0154, 501,  #     
-    0x0156, 501,  #     
-    0x0158, 501,  #     
-    0x015a, 501,  #     
-    0x015c, 501,  #     
-    0x015e, 501,  #     
-    0x0160, 501,  #     
-    0x0162, 501,  #     
-    0x0164, 501,  #     
-    0x0166, 501,  #     
-    0x0168, 501,  #     
-    0x016a, 501,  #     
-    0x016c, 501,  #     
-    0x016e, 501,  #     
-    0x0170, 501,  #     
-    0x0172, 501,  #     
-    0x0174, 501,  #     
-    0x0176, 501,  #     
-    0x0178, 379,  #     
-    0x0179, 501,  #     
-    0x017b, 501,  #     
-    0x017d, 501,  #     
-    0x0181, 710,  #     
-    0x0182, 501,  #     
-    0x0184, 501,  #     
-    0x0186, 706,  #     
-    0x0187, 501,  #     
-    0x018b, 501,  #     
-    0x0190, 703,  #     
-    0x0191, 501,  #     
-    0x0193, 705,  #     
-    0x0194, 707,  #     
-    0x0196, 711,  #     
-    0x0197, 709,  #     
-    0x0198, 501,  #     
-    0x019c, 711,  #     
-    0x019d, 713,  #     
-    0x01a0, 501,  #     
-    0x01a2, 501,  #     
-    0x01a4, 501,  #     
-    0x01a7, 501,  #     
-    0x01a9, 718,  #     
-    0x01ac, 501,  #     
-    0x01ae, 718,  #     
-    0x01af, 501,  #     
-    0x01b3, 501,  #     
-    0x01b5, 501,  #     
-    0x01b7, 719,  #     
-    0x01b8, 501,  #     
-    0x01bc, 501,  #     
-    0x01c4, 502,  #     
-    0x01c5, 501,  #     
-    0x01c7, 502,  #     
-    0x01c8, 501,  #     
-    0x01ca, 502,  #     
-    0x01cb, 501,  #     
-    0x01cd, 501,  #     
-    0x01cf, 501,  #     
-    0x01d1, 501,  #     
-    0x01d3, 501,  #     
-    0x01d5, 501,  #     
-    0x01d7, 501,  #     
-    0x01d9, 501,  #     
-    0x01db, 501,  #     
-    0x01de, 501,  #     
-    0x01e0, 501,  #     
-    0x01e2, 501,  #     
-    0x01e4, 501,  #     
-    0x01e6, 501,  #     
-    0x01e8, 501,  #     
-    0x01ea, 501,  #     
-    0x01ec, 501,  #     
-    0x01ee, 501,  #     
-    0x01f1, 502,  #     
-    0x01f2, 501,  #     
-    0x01f4, 501,  #     
-    0x01fa, 501,  #     
-    0x01fc, 501,  #     
-    0x01fe, 501,  #     
-    0x0200, 501,  #     
-    0x0202, 501,  #     
-    0x0204, 501,  #     
-    0x0206, 501,  #     
-    0x0208, 501,  #     
-    0x020a, 501,  #     
-    0x020c, 501,  #     
-    0x020e, 501,  #     
-    0x0210, 501,  #     
-    0x0212, 501,  #     
-    0x0214, 501,  #     
-    0x0216, 501,  #     
-    0x0386, 538,  #     
-    0x038c, 564,  #     
-    0x03e2, 501,  #     
-    0x03e4, 501,  #     
-    0x03e6, 501,  #     
-    0x03e8, 501,  #     
-    0x03ea, 501,  #     
-    0x03ec, 501,  #     
-    0x03ee, 501,  #     
-    0x0460, 501,  #     
-    0x0462, 501,  #     
-    0x0464, 501,  #     
-    0x0466, 501,  #     
-    0x0468, 501,  #     
-    0x046a, 501,  #     
-    0x046c, 501,  #     
-    0x046e, 501,  #     
-    0x0470, 501,  #     
-    0x0472, 501,  #     
-    0x0474, 501,  #     
-    0x0476, 501,  #     
-    0x0478, 501,  #     
-    0x047a, 501,  #     
-    0x047c, 501,  #     
-    0x047e, 501,  #     
-    0x0480, 501,  #     
-    0x0490, 501,  #     
-    0x0492, 501,  #     
-    0x0494, 501,  #     
-    0x0496, 501,  #     
-    0x0498, 501,  #     
-    0x049a, 501,  #     
-    0x049c, 501,  #     
-    0x049e, 501,  #     
-    0x04a0, 501,  #     
-    0x04a2, 501,  #     
-    0x04a4, 501,  #     
-    0x04a6, 501,  #     
-    0x04a8, 501,  #     
-    0x04aa, 501,  #     
-    0x04ac, 501,  #     
-    0x04ae, 501,  #     
-    0x04b0, 501,  #     
-    0x04b2, 501,  #     
-    0x04b4, 501,  #     
-    0x04b6, 501,  #     
-    0x04b8, 501,  #     
-    0x04ba, 501,  #     
-    0x04bc, 501,  #     
-    0x04be, 501,  #     
-    0x04c1, 501,  #     
-    0x04c3, 501,  #     
-    0x04c7, 501,  #     
-    0x04cb, 501,  #     
-    0x04d0, 501,  #     
-    0x04d2, 501,  #     
-    0x04d4, 501,  #     
-    0x04d6, 501,  #     
-    0x04d8, 501,  #     
-    0x04da, 501,  #     
-    0x04dc, 501,  #     
-    0x04de, 501,  #     
-    0x04e0, 501,  #     
-    0x04e2, 501,  #     
-    0x04e4, 501,  #     
-    0x04e6, 501,  #     
-    0x04e8, 501,  #     
-    0x04ea, 501,  #     
-    0x04ee, 501,  #     
-    0x04f0, 501,  #     
-    0x04f2, 501,  #     
-    0x04f4, 501,  #     
-    0x04f8, 501,  #     
-    0x1e00, 501,  #     
-    0x1e02, 501,  #     
-    0x1e04, 501,  #     
-    0x1e06, 501,  #     
-    0x1e08, 501,  #     
-    0x1e0a, 501,  #     
-    0x1e0c, 501,  #     
-    0x1e0e, 501,  #     
-    0x1e10, 501,  #     
-    0x1e12, 501,  #     
-    0x1e14, 501,  #     
-    0x1e16, 501,  #     
-    0x1e18, 501,  #     
-    0x1e1a, 501,  #     
-    0x1e1c, 501,  #     
-    0x1e1e, 501,  #     
-    0x1e20, 501,  #     
-    0x1e22, 501,  #     
-    0x1e24, 501,  #     
-    0x1e26, 501,  #     
-    0x1e28, 501,  #     
-    0x1e2a, 501,  #     
-    0x1e2c, 501,  #     
-    0x1e2e, 501,  #     
-    0x1e30, 501,  #     
-    0x1e32, 501,  #     
-    0x1e34, 501,  #     
-    0x1e36, 501,  #     
-    0x1e38, 501,  #     
-    0x1e3a, 501,  #     
-    0x1e3c, 501,  #     
-    0x1e3e, 501,  #     
-    0x1e40, 501,  #     
-    0x1e42, 501,  #     
-    0x1e44, 501,  #     
-    0x1e46, 501,  #     
-    0x1e48, 501,  #     
-    0x1e4a, 501,  #     
-    0x1e4c, 501,  #     
-    0x1e4e, 501,  #     
-    0x1e50, 501,  #     
-    0x1e52, 501,  #     
-    0x1e54, 501,  #     
-    0x1e56, 501,  #     
-    0x1e58, 501,  #     
-    0x1e5a, 501,  #     
-    0x1e5c, 501,  #     
-    0x1e5e, 501,  #     
-    0x1e60, 501,  #     
-    0x1e62, 501,  #     
-    0x1e64, 501,  #     
-    0x1e66, 501,  #     
-    0x1e68, 501,  #     
-    0x1e6a, 501,  #     
-    0x1e6c, 501,  #     
-    0x1e6e, 501,  #     
-    0x1e70, 501,  #     
-    0x1e72, 501,  #     
-    0x1e74, 501,  #     
-    0x1e76, 501,  #     
-    0x1e78, 501,  #     
-    0x1e7a, 501,  #     
-    0x1e7c, 501,  #     
-    0x1e7e, 501,  #     
-    0x1e80, 501,  #     
-    0x1e82, 501,  #     
-    0x1e84, 501,  #     
-    0x1e86, 501,  #     
-    0x1e88, 501,  #     
-    0x1e8a, 501,  #     
-    0x1e8c, 501,  #     
-    0x1e8e, 501,  #     
-    0x1e90, 501,  #     
-    0x1e92, 501,  #     
-    0x1e94, 501,  #     
-    0x1ea0, 501,  #     
-    0x1ea2, 501,  #     
-    0x1ea4, 501,  #     
-    0x1ea6, 501,  #     
-    0x1ea8, 501,  #     
-    0x1eaa, 501,  #     
-    0x1eac, 501,  #     
-    0x1eae, 501,  #     
-    0x1eb0, 501,  #     
-    0x1eb2, 501,  #     
-    0x1eb4, 501,  #     
-    0x1eb6, 501,  #     
-    0x1eb8, 501,  #     
-    0x1eba, 501,  #     
-    0x1ebc, 501,  #     
-    0x1ebe, 501,  #     
-    0x1ec0, 501,  #     
-    0x1ec2, 501,  #     
-    0x1ec4, 501,  #     
-    0x1ec6, 501,  #     
-    0x1ec8, 501,  #     
-    0x1eca, 501,  #     
-    0x1ecc, 501,  #     
-    0x1ece, 501,  #     
-    0x1ed0, 501,  #     
-    0x1ed2, 501,  #     
-    0x1ed4, 501,  #     
-    0x1ed6, 501,  #     
-    0x1ed8, 501,  #     
-    0x1eda, 501,  #     
-    0x1edc, 501,  #     
-    0x1ede, 501,  #     
-    0x1ee0, 501,  #     
-    0x1ee2, 501,  #     
-    0x1ee4, 501,  #     
-    0x1ee6, 501,  #     
-    0x1ee8, 501,  #     
-    0x1eea, 501,  #     
-    0x1eec, 501,  #     
-    0x1eee, 501,  #     
-    0x1ef0, 501,  #     
-    0x1ef2, 501,  #     
-    0x1ef4, 501,  #     
-    0x1ef6, 501,  #     
-    0x1ef8, 501,  #     
-    0x1f59, 492,  #     
-    0x1f5b, 492,  #     
-    0x1f5d, 492,  #     
-    0x1f5f, 492,  #     
-    0x1fbc, 491,  #     
-    0x1fcc, 491,  #     
-    0x1fec, 493,  #     
-    0x1ffc, 491]  #     
+    0x0100, 501,  #
+    0x0102, 501,  #
+    0x0104, 501,  #
+    0x0106, 501,  #
+    0x0108, 501,  #
+    0x010a, 501,  #
+    0x010c, 501,  #
+    0x010e, 501,  #
+    0x0110, 501,  #
+    0x0112, 501,  #
+    0x0114, 501,  #
+    0x0116, 501,  #
+    0x0118, 501,  #
+    0x011a, 501,  #
+    0x011c, 501,  #
+    0x011e, 501,  #
+    0x0120, 501,  #
+    0x0122, 501,  #
+    0x0124, 501,  #
+    0x0126, 501,  #
+    0x0128, 501,  #
+    0x012a, 501,  #
+    0x012c, 501,  #
+    0x012e, 501,  #
+    0x0130, 301,  #  i
+    0x0132, 501,  #
+    0x0134, 501,  #
+    0x0136, 501,  #
+    0x0139, 501,  #
+    0x013b, 501,  #
+    0x013d, 501,  #
+    0x013f, 501,  #
+    0x0141, 501,  #
+    0x0143, 501,  #
+    0x0145, 501,  #
+    0x0147, 501,  #
+    0x014a, 501,  #
+    0x014c, 501,  #
+    0x014e, 501,  #
+    0x0150, 501,  #
+    0x0152, 501,  #
+    0x0154, 501,  #
+    0x0156, 501,  #
+    0x0158, 501,  #
+    0x015a, 501,  #
+    0x015c, 501,  #
+    0x015e, 501,  #
+    0x0160, 501,  #
+    0x0162, 501,  #
+    0x0164, 501,  #
+    0x0166, 501,  #
+    0x0168, 501,  #
+    0x016a, 501,  #
+    0x016c, 501,  #
+    0x016e, 501,  #
+    0x0170, 501,  #
+    0x0172, 501,  #
+    0x0174, 501,  #
+    0x0176, 501,  #
+    0x0178, 379,  #
+    0x0179, 501,  #
+    0x017b, 501,  #
+    0x017d, 501,  #
+    0x0181, 710,  #
+    0x0182, 501,  #
+    0x0184, 501,  #
+    0x0186, 706,  #
+    0x0187, 501,  #
+    0x018b, 501,  #
+    0x0190, 703,  #
+    0x0191, 501,  #
+    0x0193, 705,  #
+    0x0194, 707,  #
+    0x0196, 711,  #
+    0x0197, 709,  #
+    0x0198, 501,  #
+    0x019c, 711,  #
+    0x019d, 713,  #
+    0x01a0, 501,  #
+    0x01a2, 501,  #
+    0x01a4, 501,  #
+    0x01a7, 501,  #
+    0x01a9, 718,  #
+    0x01ac, 501,  #
+    0x01ae, 718,  #
+    0x01af, 501,  #
+    0x01b3, 501,  #
+    0x01b5, 501,  #
+    0x01b7, 719,  #
+    0x01b8, 501,  #
+    0x01bc, 501,  #
+    0x01c4, 502,  #
+    0x01c5, 501,  #
+    0x01c7, 502,  #
+    0x01c8, 501,  #
+    0x01ca, 502,  #
+    0x01cb, 501,  #
+    0x01cd, 501,  #
+    0x01cf, 501,  #
+    0x01d1, 501,  #
+    0x01d3, 501,  #
+    0x01d5, 501,  #
+    0x01d7, 501,  #
+    0x01d9, 501,  #
+    0x01db, 501,  #
+    0x01de, 501,  #
+    0x01e0, 501,  #
+    0x01e2, 501,  #
+    0x01e4, 501,  #
+    0x01e6, 501,  #
+    0x01e8, 501,  #
+    0x01ea, 501,  #
+    0x01ec, 501,  #
+    0x01ee, 501,  #
+    0x01f1, 502,  #
+    0x01f2, 501,  #
+    0x01f4, 501,  #
+    0x01fa, 501,  #
+    0x01fc, 501,  #
+    0x01fe, 501,  #
+    0x0200, 501,  #
+    0x0202, 501,  #
+    0x0204, 501,  #
+    0x0206, 501,  #
+    0x0208, 501,  #
+    0x020a, 501,  #
+    0x020c, 501,  #
+    0x020e, 501,  #
+    0x0210, 501,  #
+    0x0212, 501,  #
+    0x0214, 501,  #
+    0x0216, 501,  #
+    0x0386, 538,  #
+    0x038c, 564,  #
+    0x03e2, 501,  #
+    0x03e4, 501,  #
+    0x03e6, 501,  #
+    0x03e8, 501,  #
+    0x03ea, 501,  #
+    0x03ec, 501,  #
+    0x03ee, 501,  #
+    0x0460, 501,  #
+    0x0462, 501,  #
+    0x0464, 501,  #
+    0x0466, 501,  #
+    0x0468, 501,  #
+    0x046a, 501,  #
+    0x046c, 501,  #
+    0x046e, 501,  #
+    0x0470, 501,  #
+    0x0472, 501,  #
+    0x0474, 501,  #
+    0x0476, 501,  #
+    0x0478, 501,  #
+    0x047a, 501,  #
+    0x047c, 501,  #
+    0x047e, 501,  #
+    0x0480, 501,  #
+    0x0490, 501,  #
+    0x0492, 501,  #
+    0x0494, 501,  #
+    0x0496, 501,  #
+    0x0498, 501,  #
+    0x049a, 501,  #
+    0x049c, 501,  #
+    0x049e, 501,  #
+    0x04a0, 501,  #
+    0x04a2, 501,  #
+    0x04a4, 501,  #
+    0x04a6, 501,  #
+    0x04a8, 501,  #
+    0x04aa, 501,  #
+    0x04ac, 501,  #
+    0x04ae, 501,  #
+    0x04b0, 501,  #
+    0x04b2, 501,  #
+    0x04b4, 501,  #
+    0x04b6, 501,  #
+    0x04b8, 501,  #
+    0x04ba, 501,  #
+    0x04bc, 501,  #
+    0x04be, 501,  #
+    0x04c1, 501,  #
+    0x04c3, 501,  #
+    0x04c7, 501,  #
+    0x04cb, 501,  #
+    0x04d0, 501,  #
+    0x04d2, 501,  #
+    0x04d4, 501,  #
+    0x04d6, 501,  #
+    0x04d8, 501,  #
+    0x04da, 501,  #
+    0x04dc, 501,  #
+    0x04de, 501,  #
+    0x04e0, 501,  #
+    0x04e2, 501,  #
+    0x04e4, 501,  #
+    0x04e6, 501,  #
+    0x04e8, 501,  #
+    0x04ea, 501,  #
+    0x04ee, 501,  #
+    0x04f0, 501,  #
+    0x04f2, 501,  #
+    0x04f4, 501,  #
+    0x04f8, 501,  #
+    0x1e00, 501,  #
+    0x1e02, 501,  #
+    0x1e04, 501,  #
+    0x1e06, 501,  #
+    0x1e08, 501,  #
+    0x1e0a, 501,  #
+    0x1e0c, 501,  #
+    0x1e0e, 501,  #
+    0x1e10, 501,  #
+    0x1e12, 501,  #
+    0x1e14, 501,  #
+    0x1e16, 501,  #
+    0x1e18, 501,  #
+    0x1e1a, 501,  #
+    0x1e1c, 501,  #
+    0x1e1e, 501,  #
+    0x1e20, 501,  #
+    0x1e22, 501,  #
+    0x1e24, 501,  #
+    0x1e26, 501,  #
+    0x1e28, 501,  #
+    0x1e2a, 501,  #
+    0x1e2c, 501,  #
+    0x1e2e, 501,  #
+    0x1e30, 501,  #
+    0x1e32, 501,  #
+    0x1e34, 501,  #
+    0x1e36, 501,  #
+    0x1e38, 501,  #
+    0x1e3a, 501,  #
+    0x1e3c, 501,  #
+    0x1e3e, 501,  #
+    0x1e40, 501,  #
+    0x1e42, 501,  #
+    0x1e44, 501,  #
+    0x1e46, 501,  #
+    0x1e48, 501,  #
+    0x1e4a, 501,  #
+    0x1e4c, 501,  #
+    0x1e4e, 501,  #
+    0x1e50, 501,  #
+    0x1e52, 501,  #
+    0x1e54, 501,  #
+    0x1e56, 501,  #
+    0x1e58, 501,  #
+    0x1e5a, 501,  #
+    0x1e5c, 501,  #
+    0x1e5e, 501,  #
+    0x1e60, 501,  #
+    0x1e62, 501,  #
+    0x1e64, 501,  #
+    0x1e66, 501,  #
+    0x1e68, 501,  #
+    0x1e6a, 501,  #
+    0x1e6c, 501,  #
+    0x1e6e, 501,  #
+    0x1e70, 501,  #
+    0x1e72, 501,  #
+    0x1e74, 501,  #
+    0x1e76, 501,  #
+    0x1e78, 501,  #
+    0x1e7a, 501,  #
+    0x1e7c, 501,  #
+    0x1e7e, 501,  #
+    0x1e80, 501,  #
+    0x1e82, 501,  #
+    0x1e84, 501,  #
+    0x1e86, 501,  #
+    0x1e88, 501,  #
+    0x1e8a, 501,  #
+    0x1e8c, 501,  #
+    0x1e8e, 501,  #
+    0x1e90, 501,  #
+    0x1e92, 501,  #
+    0x1e94, 501,  #
+    0x1ea0, 501,  #
+    0x1ea2, 501,  #
+    0x1ea4, 501,  #
+    0x1ea6, 501,  #
+    0x1ea8, 501,  #
+    0x1eaa, 501,  #
+    0x1eac, 501,  #
+    0x1eae, 501,  #
+    0x1eb0, 501,  #
+    0x1eb2, 501,  #
+    0x1eb4, 501,  #
+    0x1eb6, 501,  #
+    0x1eb8, 501,  #
+    0x1eba, 501,  #
+    0x1ebc, 501,  #
+    0x1ebe, 501,  #
+    0x1ec0, 501,  #
+    0x1ec2, 501,  #
+    0x1ec4, 501,  #
+    0x1ec6, 501,  #
+    0x1ec8, 501,  #
+    0x1eca, 501,  #
+    0x1ecc, 501,  #
+    0x1ece, 501,  #
+    0x1ed0, 501,  #
+    0x1ed2, 501,  #
+    0x1ed4, 501,  #
+    0x1ed6, 501,  #
+    0x1ed8, 501,  #
+    0x1eda, 501,  #
+    0x1edc, 501,  #
+    0x1ede, 501,  #
+    0x1ee0, 501,  #
+    0x1ee2, 501,  #
+    0x1ee4, 501,  #
+    0x1ee6, 501,  #
+    0x1ee8, 501,  #
+    0x1eea, 501,  #
+    0x1eec, 501,  #
+    0x1eee, 501,  #
+    0x1ef0, 501,  #
+    0x1ef2, 501,  #
+    0x1ef4, 501,  #
+    0x1ef6, 501,  #
+    0x1ef8, 501,  #
+    0x1f59, 492,  #
+    0x1f5b, 492,  #
+    0x1f5d, 492,  #
+    0x1f5f, 492,  #
+    0x1fbc, 491,  #
+    0x1fcc, 491,  #
+    0x1fec, 493,  #
+    0x1ffc, 491]  #
 
   toTitleSinglets = [
-    0x01c4, 501,  #     
-    0x01c6, 499,  #     
-    0x01c7, 501,  #     
-    0x01c9, 499,  #     
-    0x01ca, 501,  #     
-    0x01cc, 499,  #     
-    0x01f1, 501,  #     
-    0x01f3, 499]  #     
+    0x01c4, 501,  #
+    0x01c6, 499,  #
+    0x01c7, 501,  #
+    0x01c9, 499,  #
+    0x01ca, 501,  #
+    0x01cc, 499,  #
+    0x01f1, 501,  #
+    0x01f3, 499]  #
 
-proc binarySearch(c: RuneImpl, tab: openArray[RuneImpl], len, stride: int): int = 
+proc binarySearch(c: RuneImpl, tab: openArray[RuneImpl], len, stride: int): int =
   var n = len
   var t = 0
-  while n > 1: 
+  while n > 1:
     var m = n div 2
     var p = t + m*stride
     if c >= tab[p]:
@@ -1131,9 +1131,9 @@ proc binarySearch(c: RuneImpl, tab: openArray[RuneImpl], len, stride: int): int
     return t
   return -1
 
-proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = 
+proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
   ## Converts `c` into lower case. This works for any Unicode character.
-  ## If possible, prefer `toLower` over `toUpper`. 
+  ## If possible, prefer `toLower` over `toUpper`.
   var c = RuneImpl(c)
   var p = binarySearch(c, tolowerRanges, len(tolowerRanges) div 3, 3)
   if p >= 0 and c >= tolowerRanges[p] and c <= tolowerRanges[p+1]:
@@ -1143,9 +1143,9 @@ proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
     return Rune(c + tolowerSinglets[p+1] - 500)
   return Rune(c)
 
-proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = 
+proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
   ## Converts `c` into upper case. This works for any Unicode character.
-  ## If possible, prefer `toLower` over `toUpper`. 
+  ## If possible, prefer `toLower` over `toUpper`.
   var c = RuneImpl(c)
   var p = binarySearch(c, toupperRanges, len(toupperRanges) div 3, 3)
   if p >= 0 and c >= toupperRanges[p] and c <= toupperRanges[p+1]:
@@ -1155,16 +1155,16 @@ proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
     return Rune(c + toupperSinglets[p+1] - 500)
   return Rune(c)
 
-proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = 
+proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
   var c = RuneImpl(c)
   var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2)
   if p >= 0 and c == toTitleSinglets[p]:
     return Rune(c + toTitleSinglets[p+1] - 500)
   return Rune(c)
 
-proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = 
+proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
   ## returns true iff `c` is a lower case Unicode character
-  ## If possible, prefer `isLower` over `isUpper`. 
+  ## If possible, prefer `isLower` over `isUpper`.
   var c = RuneImpl(c)
   # Note: toUpperRanges is correct here!
   var p = binarySearch(c, toupperRanges, len(toupperRanges) div 3, 3)
@@ -1174,9 +1174,9 @@ proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
   if p >= 0 and c == toupperSinglets[p]:
     return true
 
-proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = 
+proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
   ## returns true iff `c` is a upper case Unicode character
-  ## If possible, prefer `isLower` over `isUpper`. 
+  ## If possible, prefer `isLower` over `isUpper`.
   var c = RuneImpl(c)
   # Note: toLowerRanges is correct here!
   var p = binarySearch(c, tolowerRanges, len(tolowerRanges) div 3, 3)
@@ -1186,9 +1186,9 @@ proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
   if p >= 0 and c == tolowerSinglets[p]:
     return true
 
-proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = 
+proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
   ## returns true iff `c` is an *alpha* Unicode character (i.e. a letter)
-  if isUpper(c) or isLower(c): 
+  if isUpper(c) or isLower(c):
     return true
   var c = RuneImpl(c)
   var p = binarySearch(c, alphaRanges, len(alphaRanges) div 2, 2)
@@ -1197,11 +1197,11 @@ proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
   p = binarySearch(c, alphaSinglets, len(alphaSinglets), 1)
   if p >= 0 and c == alphaSinglets[p]:
     return true
-  
-proc isTitle*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = 
+
+proc isTitle*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
   return isUpper(c) and isLower(c)
 
-proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = 
+proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
   ## returns true iff `c` is a Unicode whitespace character
   var c = RuneImpl(c)
   var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2)
@@ -1228,7 +1228,7 @@ iterator runes*(s: string): Rune =
     fastRuneAt(s, i, result, true)
     yield result
 
-proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} = 
+proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} =
   ## compares two UTF8 strings and ignores the case. Returns:
   ##
   ## | 0 iff a == b
diff --git a/lib/pure/unidecode/unidecode.nim b/lib/pure/unidecode/unidecode.nim
index 798eef5d0..a83b9be0f 100644
--- a/lib/pure/unidecode/unidecode.nim
+++ b/lib/pure/unidecode/unidecode.nim
@@ -70,5 +70,5 @@ proc unidecode*(s: string): string =
 
 when isMainModule:
   loadUnidecodeTable("lib/pure/unidecode/unidecode.dat")
-  echo unidecode("Äußerst")
+  assert unidecode("Äußerst") == "Ausserst"
 
diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim
index 6242e589e..6cf837f25 100644
--- a/lib/pure/xmldom.nim
+++ b/lib/pure/xmldom.nim
@@ -365,23 +365,21 @@ discard """proc getElementById*(doc: PDocument, elementId: string): PElement =
 proc getElementsByTagName*(doc: PDocument, tagName: string): seq[PNode] =
   ## Returns a NodeList of all the Elements with a given tag name in
   ## the order in which they are encountered in a preorder traversal of the Document tree.
-  var result: seq[PNode] = @[]
+  result = @[]
   if doc.fDocumentElement.fNodeName == tagName or tagName == "*":
     result.add(doc.fDocumentElement)
 
   result.add(doc.fDocumentElement.findNodes(tagName))
-  return result
 
 proc getElementsByTagNameNS*(doc: PDocument, namespaceURI: string, localName: string): seq[PNode] =
   ## Returns a NodeList of all the Elements with a given localName and namespaceURI
   ## in the order in which they are encountered in a preorder traversal of the Document tree.
-  var result: seq[PNode] = @[]
+  result = @[]
   if doc.fDocumentElement.fLocalName == localName or localName == "*":
     if doc.fDocumentElement.fNamespaceURI == namespaceURI or namespaceURI == "*":
       result.add(doc.fDocumentElement)
 
   result.add(doc.fDocumentElement.findNodesNS(namespaceURI, localName))
-  return result
 
 proc importNode*(doc: PDocument, importedNode: PNode, deep: bool): PNode =
   ## Imports a node from another document to this document
@@ -677,7 +675,7 @@ proc removeChild*(n: PNode, oldChild: PNode): PNode =
       if n.childNodes[i] == oldChild:
         result = n.childNodes[i]
         n.childNodes.delete(i)
-        return result
+        return
 
   raise newException(ENotFoundErr, "Node not found")
 
@@ -693,7 +691,7 @@ proc replaceChild*(n: PNode, newChild: PNode, oldChild: PNode): PNode =
       if n.childNodes[i] == oldChild:
         result = n.childNodes[i]
         n.childNodes[i] = newChild
-        return result
+        return
 
   raise newException(ENotFoundErr, "Node not found")
 
@@ -740,7 +738,7 @@ proc removeNamedItem*(nList: var seq[PNode], name: string): PNode =
     if nList[i].fNodeName == name:
       result = nList[i]
       nList.delete(i)
-      return result
+      return
 
   raise newException(ENotFoundErr, "Node not found")
 
@@ -750,7 +748,7 @@ proc removeNamedItemNS*(nList: var seq[PNode], namespaceURI: string, localName:
     if nList[i].fLocalName == localName and nList[i].fNamespaceURI == namespaceURI:
       result = nList[i]
       nList.delete(i)
-      return result
+      return
 
   raise newException(ENotFoundErr, "Node not found")
 
@@ -965,7 +963,7 @@ proc removeAttributeNode*(el: PElement, oldAttr: PAttr): PAttr =
       if el.attributes[i] == oldAttr:
         result = el.attributes[i]
         el.attributes.delete(i)
-        return result
+        return
 
   raise newException(ENotFoundErr, "oldAttr is not a member of el's Attributes")
 
diff --git a/lib/pure/xmldomparser.nim b/lib/pure/xmldomparser.nim
index 7f34d72a8..050362435 100644
--- a/lib/pure/xmldomparser.nim
+++ b/lib/pure/xmldomparser.nim
@@ -155,7 +155,7 @@ proc loadXMLFile*(path: string): PDocument =
   return loadXMLStream(s)
 
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   var xml = loadXMLFile("nim/xmldom/test.xml")
   #echo(xml.getElementsByTagName("m:test2")[0].namespaceURI)
   #echo(xml.getElementsByTagName("bla:test")[0].namespaceURI)
diff --git a/lib/pure/xmlparser.nim b/lib/pure/xmlparser.nim
index 755bfcdbc..840cae734 100644
--- a/lib/pure/xmlparser.nim
+++ b/lib/pure/xmlparser.nim
@@ -143,7 +143,7 @@ proc loadXml*(path: string): XmlNode =
   result = loadXml(path, errors)
   if errors.len > 0: raiseInvalidXml(errors)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   import os
 
   var errors: seq[string] = @[]  
diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim
index 0bf5b52a4..7526a989a 100644
--- a/lib/pure/xmltree.nim
+++ b/lib/pure/xmltree.nim
@@ -353,5 +353,6 @@ proc findAll*(n: XmlNode, tag: string): seq[XmlNode] =
   findAll(n, tag, result)
 
 when isMainModule:
-  assert """<a href="http://nim-lang.org">Nim rules.</a>""" ==
+  let link = "http://nim-lang.org"
+  assert """<a href="""" & escape(link) & """">Nim rules.</a>""" ==
     $(<>a(href="http://nim-lang.org", newText("Nim rules.")))