summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/core/macros.nim33
-rw-r--r--lib/core/seqs.nim6
-rw-r--r--lib/deprecated/core/unsigned.nim18
-rw-r--r--lib/deprecated/pure/actors.nim239
-rw-r--r--lib/deprecated/pure/actors.nim.cfg3
-rw-r--r--lib/deprecated/pure/ftpclient.nim1
-rw-r--r--lib/deprecated/pure/parseurl.nim112
-rw-r--r--lib/deprecated/pure/rawsockets.nim14
-rw-r--r--lib/deprecated/pure/securehash.nim (renamed from lib/pure/securehash.nim)0
-rw-r--r--lib/experimental/diff.nim14
-rw-r--r--lib/impure/db_odbc.nim2
-rw-r--r--lib/impure/db_sqlite.nim26
-rw-r--r--lib/impure/nre.nim8
-rw-r--r--lib/impure/re.nim27
-rw-r--r--lib/impure/ssl.nim99
-rw-r--r--lib/js/dom.nim30
-rw-r--r--lib/js/jscore.nim12
-rw-r--r--lib/js/jsffi.nim6
-rw-r--r--lib/nimbase.h4
-rw-r--r--lib/packages/docutils/rst.nim73
-rw-r--r--lib/packages/docutils/rstast.nim3
-rw-r--r--lib/packages/docutils/rstgen.nim4
-rw-r--r--lib/posix/posix_linux_amd64_consts.nim1
-rw-r--r--lib/posix/posix_nintendoswitch_consts.nim1
-rw-r--r--lib/posix/posix_other_consts.nim1
-rw-r--r--lib/pure/asynchttpserver.nim48
-rw-r--r--lib/pure/base64.nim84
-rw-r--r--lib/pure/cgi.nim5
-rw-r--r--lib/pure/collections/critbits.nim6
-rw-r--r--lib/pure/collections/deques.nim308
-rw-r--r--lib/pure/collections/intsets.nim66
-rw-r--r--lib/pure/collections/lists.nim533
-rw-r--r--lib/pure/collections/queues.nim257
-rw-r--r--lib/pure/collections/sequtils.nim712
-rw-r--r--lib/pure/collections/sets.nim7
-rw-r--r--lib/pure/collections/tableimpl.nim2
-rw-r--r--lib/pure/collections/tables.nim2699
-rw-r--r--lib/pure/concurrency/atomics.nim378
-rw-r--r--lib/pure/distros.nim11
-rw-r--r--lib/pure/httpclient.nim243
-rw-r--r--lib/pure/httpserver.nim535
-rw-r--r--lib/pure/includes/osenv.nim2
-rw-r--r--lib/pure/includes/oserr.nim4
-rw-r--r--lib/pure/includes/osseps.nim4
-rw-r--r--lib/pure/ioselects/ioselectors_epoll.nim22
-rw-r--r--lib/pure/json.nim34
-rw-r--r--lib/pure/logging.nim7
-rw-r--r--lib/pure/matchers.nim68
-rw-r--r--lib/pure/math.nim516
-rw-r--r--lib/pure/memfiles.nim26
-rw-r--r--lib/pure/nativesockets.nim70
-rw-r--r--lib/pure/net.nim77
-rw-r--r--lib/pure/os.nim243
-rw-r--r--lib/pure/osproc.nim39
-rw-r--r--lib/pure/parsecfg.nim2
-rw-r--r--lib/pure/parseopt.nim29
-rw-r--r--lib/pure/parseopt2.nim17
-rw-r--r--lib/pure/parsesql.nim2
-rw-r--r--lib/pure/parseutils.nim301
-rw-r--r--lib/pure/parsexml.nim2
-rw-r--r--lib/pure/pathnorm.nim24
-rw-r--r--lib/pure/random.nim50
-rw-r--r--lib/pure/scgi.nim295
-rw-r--r--lib/pure/selectors.nim3
-rw-r--r--lib/pure/streams.nim6
-rw-r--r--lib/pure/strtabs.nim31
-rw-r--r--lib/pure/strutils.nim2032
-rw-r--r--lib/pure/subexes.nim406
-rw-r--r--lib/pure/terminal.nim2
-rw-r--r--lib/pure/times.nim815
-rw-r--r--lib/pure/typetraits.nim49
-rw-r--r--lib/pure/unicode.nim207
-rw-r--r--lib/pure/unittest.nim4
-rw-r--r--lib/pure/uri.nim174
-rw-r--r--lib/std/sha1.nim65
-rw-r--r--lib/std/time_t.nim23
-rw-r--r--lib/std/wordwrap.nim5
-rw-r--r--lib/system.nim205
-rw-r--r--lib/system/alloc.nim6
-rw-r--r--lib/system/ansi_c.nim2
-rw-r--r--lib/system/embedded.nim1
-rw-r--r--lib/system/excpt.nim5
-rw-r--r--lib/system/gc.nim18
-rw-r--r--lib/system/gc_common.nim2
-rw-r--r--lib/system/gc_ms.nim3
-rw-r--r--lib/system/gc_regions.nim29
-rw-r--r--lib/system/helpers.nim23
-rw-r--r--lib/system/helpers2.nim2
-rw-r--r--lib/system/jssys.nim2
-rw-r--r--lib/system/mmdisp.nim3
-rw-r--r--lib/system/nimscript.nim35
-rw-r--r--lib/system/profiler.nim14
-rw-r--r--lib/system/strmantle.nim2
-rw-r--r--lib/system/sysio.nim17
-rw-r--r--lib/system/timers.nim2
-rw-r--r--lib/windows/winlean.nim11
-rw-r--r--lib/wrappers/openssl.nim6
97 files changed, 7226 insertions, 5449 deletions
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index f45ca3f82..3a85324ba 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -151,7 +151,7 @@ proc `==`*(a, b: NimNode): bool {.magic: "EqNimrodNode", noSideEffect.}
 
 proc `==`*(a, b: NimSym): bool {.magic: "EqNimrodNode", noSideEffect, deprecated.}
   ## compares two Nim symbols
-  ## **Deprecated since version 0.18.1**; Use ```==`(NimNode,NimNode)`` instead.
+  ## **Deprecated since version 0.18.1**; Use ``==(NimNode, NimNode)`` instead.
 
 
 proc sameType*(a, b: NimNode): bool {.magic: "SameNodeType", noSideEffect.} =
@@ -277,9 +277,9 @@ when defined(nimHasSymOwnerInMacro):
 when defined(nimHasInstantiationOfInMacro):
   proc isInstantiationOf*(instanceProcSym, genProcSym: NimNode): bool {.magic: "SymIsInstantiationOf", noSideEffect.}
     ## check if proc symbol is instance of the generic proc symbol
-    ## useful to check proc symbols against generic symbols 
+    ## useful to check proc symbols against generic symbols
     ## returned by `bindSym`
- 
+
 proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.}
   ## with 'getType' you can access the node's `type`:idx:. A Nim type is
   ## mapped to a Nim AST too, so it's slightly confusing but it means the same
@@ -377,7 +377,9 @@ proc copyNimNode*(n: NimNode): NimNode {.magic: "NCopyNimNode", noSideEffect.}
 proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.}
 
 proc error*(msg: string, n: NimNode = nil) {.magic: "NError", benign.}
-  ## writes an error message at compile time
+  ## writes an error message at compile time. The optional ``n: NimNode``
+  ## parameter is used as the source for file and line number information in
+  ## the compilation error message.
 
 proc warning*(msg: string, n: NimNode = nil) {.magic: "NWarning", benign.}
   ## writes a warning message at compile time
@@ -1402,8 +1404,14 @@ proc customPragmaNode(n: NimNode): NimNode =
     let impl = n.getImpl()
     if impl.kind in RoutineNodes:
       return impl.pragma
+    elif impl.kind == nnkIdentDefs and impl[0].kind == nnkPragmaExpr:
+      return impl[0][1]
     else:
-      return typ.getImpl()[0][1]
+      let timpl = typ.getImpl()
+      if timpl.len>0 and timpl[0].len>1:
+        return timpl[0][1]
+      else:
+        return timpl
 
   if n.kind in {nnkDotExpr, nnkCheckedFieldExpr}:
     let name = $(if n.kind == nnkCheckedFieldExpr: n[0][1] else: n[1])
@@ -1492,9 +1500,18 @@ macro getCustomPragmaVal*(n: typed, cp: typed{nkSym}): untyped =
   let pragmaNode = customPragmaNode(n)
   for p in pragmaNode:
     if p.kind in nnkPragmaCallKinds and p.len > 0 and p[0].kind == nnkSym and p[0] == cp:
-      return p[1]
-
-  error(n.repr & " doesn't have a pragma named " & cp.repr()) # returning an empty node results in most cases in a cryptic error,
+      if p.len == 2:
+        result = p[1]
+      else:
+        let def = p[0].getImpl[3]
+        result = newTree(nnkPar)
+        for i in 1..<p.len:
+          let key = def[i][0]
+          let val = p[i]
+          result.add newTree(nnkExprColonExpr, key, val)
+      break
+  if result.kind == nnkEmpty:
+    error(n.repr & " doesn't have a pragma named " & cp.repr()) # returning an empty node results in most cases in a cryptic error,
 
 
 when not defined(booting):
diff --git a/lib/core/seqs.nim b/lib/core/seqs.nim
index a41ef10ab..977b23b26 100644
--- a/lib/core/seqs.nim
+++ b/lib/core/seqs.nim
@@ -70,12 +70,6 @@ proc `=sink`[T](x: var seq[T]; y: seq[T]) =
   a.len = b.len
   a.p = b.p
 
-when false:
-  proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerProc.}
-  proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {.
-      compilerRtl.}
-  proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.}
-
 
 type
   PayloadBase = object
diff --git a/lib/deprecated/core/unsigned.nim b/lib/deprecated/core/unsigned.nim
deleted file mode 100644
index 93a29e1c9..000000000
--- a/lib/deprecated/core/unsigned.nim
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-#
-#            Nim's Runtime Library
-#        (c) Copyright 2012 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## **Warning:** Since version 0.11.4 this module is deprecated.
-##
-## This module implemented basic arithmetic operators for unsigned integers.
-## These operators are now available in the ``system`` module directly.
-
-{.deprecated.}
-
-export `shr`, `shl`, `and`, `or`, `xor`, `==`, `+`, `-`, `*`, `div`, `mod`,
-  `<=`, `<`
diff --git a/lib/deprecated/pure/actors.nim b/lib/deprecated/pure/actors.nim
deleted file mode 100644
index 77c67a3e4..000000000
--- a/lib/deprecated/pure/actors.nim
+++ /dev/null
@@ -1,239 +0,0 @@
-#
-#
-#            Nim's Runtime Library
-#        (c) Copyright 2012 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## `Actor`:idx: support for Nim. An actor is implemented as a thread with
-## a channel as its inbox. This module requires the ``--threads:on``
-## command line switch.
-##
-## Example:
-##
-## .. code-block:: nim
-##
-##      var
-##        a: ActorPool[int, void]
-##      createActorPool(a)
-##      for i in 0 ..< 300:
-##        a.spawn(i, proc (x: int) {.thread.} = echo x)
-##      a.join()
-##
-## **Note**: This whole module is deprecated. Use `threadpool` and ``spawn``
-## instead.
-
-{.deprecated.}
-
-from os import sleep
-
-type
-  Task*[In, Out] = object{.pure, final.} ## a task
-    when Out isnot void:
-      receiver*: ptr Channel[Out] ## the receiver channel of the response
-    action*: proc (x: In): Out {.thread.} ## action to execute;
-                                            ## sometimes useful
-    shutDown*: bool ## set to tell an actor to shut-down
-    data*: In ## the data to process
-
-  Actor[In, Out] = object{.pure, final.}
-    i: Channel[Task[In, Out]]
-    t: Thread[ptr Actor[In, Out]]
-
-  PActor*[In, Out] = ptr Actor[In, Out] ## an actor
-
-proc spawn*[In, Out](action: proc(
-    self: PActor[In, Out]){.thread.}): PActor[In, Out] =
-  ## creates an actor; that is a thread with an inbox. The caller MUST call
-  ## ``join`` because that also frees the actor's associated resources.
-  result = cast[PActor[In, Out]](allocShared0(sizeof(result[])))
-  open(result.i)
-  createThread(result.t, action, result)
-
-proc inbox*[In, Out](self: PActor[In, Out]): ptr Channel[In] =
-  ## gets a pointer to the associated inbox of the actor `self`.
-  result = addr(self.i)
-
-proc running*[In, Out](a: PActor[In, Out]): bool =
-  ## returns true if the actor `a` is running.
-  result = running(a.t)
-
-proc ready*[In, Out](a: PActor[In, Out]): bool =
-  ## returns true if the actor `a` is ready to process new messages.
-  result = ready(a.i)
-
-proc join*[In, Out](a: PActor[In, Out]) =
-  ## joins an actor.
-  joinThread(a.t)
-  close(a.i)
-  deallocShared(a)
-
-proc recv*[In, Out](a: PActor[In, Out]): Task[In, Out] =
-  ## receives a task from `a`'s inbox.
-  result = recv(a.i)
-
-proc send*[In, Out, X, Y](receiver: PActor[In, Out], msg: In,
-                            sender: PActor[X, Y]) =
-  ## sends a message to `a`'s inbox.
-  var t: Task[In, Out]
-  t.receiver = addr(sender.i)
-  shallowCopy(t.data, msg)
-  send(receiver.i, t)
-
-proc send*[In, Out](receiver: PActor[In, Out], msg: In,
-                      sender: ptr Channel[Out] = nil) =
-  ## sends a message to `receiver`'s inbox.
-  var t: Task[In, Out]
-  t.receiver = sender
-  shallowCopy(t.data, msg)
-  send(receiver.i, t)
-
-proc sendShutdown*[In, Out](receiver: PActor[In, Out]) =
-  ## send a shutdown message to `receiver`.
-  var t: Task[In, Out]
-  t.shutdown = true
-  send(receiver.i, t)
-
-proc reply*[In, Out](t: Task[In, Out], m: Out) =
-  ## sends a message to io's output message box.
-  when Out is void:
-    {.error: "you cannot reply to a void outbox".}
-  assert t.receiver != nil
-  send(t.receiver[], m)
-
-
-# ----------------- actor pools ----------------------------------------------
-
-type
-  ActorPool*[In, Out] = object{.pure, final.}  ## an actor pool
-    actors: seq[PActor[In, Out]]
-    when Out isnot void:
-      outputs: Channel[Out]
-
-proc `^`*[T](f: ptr Channel[T]): T =
-  ## alias for 'recv'.
-  result = recv(f[])
-
-proc poolWorker[In, Out](self: PActor[In, Out]) {.thread.} =
-  while true:
-    var m = self.recv
-    if m.shutDown: break
-    when Out is void:
-      m.action(m.data)
-    else:
-      send(m.receiver[], m.action(m.data))
-      #self.reply()
-
-proc createActorPool*[In, Out](a: var ActorPool[In, Out], poolSize = 4) =
-  ## creates an actor pool.
-  newSeq(a.actors, poolSize)
-  when Out isnot void:
-    open(a.outputs)
-  for i in 0 ..< a.actors.len:
-    a.actors[i] = spawn(poolWorker[In, Out])
-
-proc sync*[In, Out](a: var ActorPool[In, Out], polling=50) =
-  ## waits for every actor of `a` to finish with its work. Currently this is
-  ## implemented as polling every `polling` ms and has a slight chance
-  ## of failing since we check for every actor to be in `ready` state and not
-  ## for messages still in ether. This will change in a later
-  ## version, however.
-  var allReadyCount = 0
-  while true:
-    var wait = false
-    for i in 0..high(a.actors):
-      if not a.actors[i].i.ready:
-        wait = true
-        allReadyCount = 0
-        break
-    if not wait:
-      # it's possible that some actor sent a message to some other actor but
-      # both appeared to be non-working as the message takes some time to
-      # arrive. We assume that this won't take longer than `polling` and
-      # simply attempt a second time and declare victory then. ;-)
-      inc allReadyCount
-      if allReadyCount > 1: break
-    sleep(polling)
-
-proc terminate*[In, Out](a: var ActorPool[In, Out]) =
-  ## terminates each actor in the actor pool `a` and frees the
-  ## resources attached to `a`.
-  var t: Task[In, Out]
-  t.shutdown = true
-  for i in 0..<a.actors.len: send(a.actors[i].i, t)
-  for i in 0..<a.actors.len: join(a.actors[i])
-  when Out isnot void:
-    close(a.outputs)
-  a.actors = @[]
-
-proc join*[In, Out](a: var ActorPool[In, Out]) =
-  ## short-cut for `sync` and then `terminate`.
-  sync(a)
-  terminate(a)
-
-template setupTask =
-  t.action = action
-  shallowCopy(t.data, input)
-
-template schedule =
-  # extremely simple scheduler: We always try the first thread first, so that
-  # it remains 'hot' ;-). Round-robin hurts for keeping threads hot.
-  for i in 0..high(p.actors):
-    if p.actors[i].i.ready:
-      p.actors[i].i.send(t)
-      return
-  # no thread ready :-( --> send message to the thread which has the least
-  # messages pending:
-  var minIdx = -1
-  var minVal = high(int)
-  for i in 0..high(p.actors):
-    var curr = p.actors[i].i.peek
-    if curr == 0:
-      # ok, is ready now:
-      p.actors[i].i.send(t)
-      return
-    if curr < minVal and curr >= 0:
-      minVal = curr
-      minIdx = i
-  if minIdx >= 0:
-    p.actors[minIdx].i.send(t)
-  else:
-    raise newException(DeadThreadError, "cannot send message; thread died")
-
-proc spawn*[In, Out](p: var ActorPool[In, Out], input: In,
-                       action: proc (input: In): Out {.thread.}
-                       ): ptr Channel[Out] =
-  ## uses the actor pool to run ``action(input)`` concurrently.
-  ## `spawn` is guaranteed to not block.
-  var t: Task[In, Out]
-  setupTask()
-  result = addr(p.outputs)
-  t.receiver = result
-  schedule()
-
-proc spawn*[In](p: var ActorPool[In, void], input: In,
-                 action: proc (input: In) {.thread.}) =
-  ## uses the actor pool to run ``action(input)`` concurrently.
-  ## `spawn` is guaranteed to not block.
-  var t: Task[In, void]
-  setupTask()
-  schedule()
-
-when not defined(testing) and isMainModule:
-  var
-    a: ActorPool[int, void]
-  createActorPool(a)
-  for i in 0 ..< 300:
-    a.spawn(i, proc (x: int) {.thread.} = echo x)
-
-  when false:
-    proc treeDepth(n: PNode): int {.thread.} =
-      var x = a.spawn(treeDepth, n.le)
-      var y = a.spawn(treeDepth, n.ri)
-      result = max(^x, ^y) + 1
-
-  a.join()
-
-
diff --git a/lib/deprecated/pure/actors.nim.cfg b/lib/deprecated/pure/actors.nim.cfg
deleted file mode 100644
index c6bb9c545..000000000
--- a/lib/deprecated/pure/actors.nim.cfg
+++ /dev/null
@@ -1,3 +0,0 @@
-# to shut up the tester:
---threads:on
-
diff --git a/lib/deprecated/pure/ftpclient.nim b/lib/deprecated/pure/ftpclient.nim
index d70f9556a..206c21f27 100644
--- a/lib/deprecated/pure/ftpclient.nim
+++ b/lib/deprecated/pure/ftpclient.nim
@@ -81,7 +81,6 @@ type
       oneSecond: BiggestInt # Bytes transferred in one second.
       lastProgressReport: float # Time
       toStore: string # Data left to upload (Only used with async)
-    else: nil
 
   FtpClientObj* = FtpBaseObj[Socket]
   FtpClient* = ref FtpClientObj
diff --git a/lib/deprecated/pure/parseurl.nim b/lib/deprecated/pure/parseurl.nim
deleted file mode 100644
index b19f6dc85..000000000
--- a/lib/deprecated/pure/parseurl.nim
+++ /dev/null
@@ -1,112 +0,0 @@
-#
-#
-#            Nim's Runtime Library
-#        (c) Copyright 2015 Dominik Picheta
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## **Warnings:** This module is deprecated since version 0.10.2.
-## Use the `uri <uri.html>`_ module instead.
-##
-## Parses & constructs URLs.
-
-{.deprecated.}
-
-import strutils
-
-type
-  Url* = tuple[      ## represents a *Uniform Resource Locator* (URL)
-                     ## any optional component is "" if it does not exist
-    scheme, username, password,
-    hostname, port, path, query, anchor: string]
-
-proc parseUrl*(url: string): Url {.deprecated.} =
-  var i = 0
-
-  var scheme, username, password: string = ""
-  var hostname, port, path, query, anchor: string = ""
-
-  var temp = ""
-
-  if url[i] != '/': # url isn't a relative path
-    while true:
-      # Scheme
-      if url[i] == ':':
-        if url[i+1] == '/' and url[i+2] == '/':
-          scheme = temp
-          temp.setLen(0)
-          inc(i, 3) # Skip the //
-      # Authority(username, password)
-      if url[i] == '@':
-        username = temp
-        let colon = username.find(':')
-        if colon >= 0:
-          password = username.substr(colon+1)
-          username = username.substr(0, colon-1)
-        temp.setLen(0)
-        inc(i) #Skip the @
-      # hostname(subdomain, domain, port)
-      if url[i] == '/' or url[i] == '\0':
-        hostname = temp
-        let colon = hostname.find(':')
-        if colon >= 0:
-          port = hostname.substr(colon+1)
-          hostname = hostname.substr(0, colon-1)
-
-        temp.setLen(0)
-        break
-
-      temp.add(url[i])
-      inc(i)
-
-  if url[i] == '/': inc(i) # Skip the '/'
-  # Path
-  while true:
-    if url[i] == '?':
-      path = temp
-      temp.setLen(0)
-    if url[i] == '#':
-      if temp[0] == '?':
-        query = temp
-      else:
-        path = temp
-      temp.setLen(0)
-
-    if url[i] == '\0':
-      if temp[0] == '?':
-        query = temp
-      elif temp[0] == '#':
-        anchor = temp
-      else:
-        path = temp
-      break
-
-    temp.add(url[i])
-    inc(i)
-
-  return (scheme, username, password, hostname, port, path, query, anchor)
-
-proc `$`*(u: Url): string {.deprecated.} =
-  ## turns the URL `u` into its string representation.
-  result = ""
-  if u.scheme.len > 0:
-    result.add(u.scheme)
-    result.add("://")
-  if u.username.len > 0:
-    result.add(u.username)
-    if u.password.len > 0:
-      result.add(":")
-      result.add(u.password)
-    result.add("@")
-  result.add(u.hostname)
-  if u.port.len > 0:
-    result.add(":")
-    result.add(u.port)
-  if u.path.len > 0:
-    result.add("/")
-    result.add(u.path)
-  result.add(u.query)
-  result.add(u.anchor)
-
diff --git a/lib/deprecated/pure/rawsockets.nim b/lib/deprecated/pure/rawsockets.nim
deleted file mode 100644
index 876334f9e..000000000
--- a/lib/deprecated/pure/rawsockets.nim
+++ /dev/null
@@ -1,14 +0,0 @@
-import nativesockets
-export nativesockets
-
-{.warning: "rawsockets module is deprecated, use nativesockets instead".}
-
-template newRawSocket*(domain, sockType, protocol: cint): untyped =
-  {.warning: "newRawSocket is deprecated, use newNativeSocket instead".}
-  newNativeSocket(domain, sockType, protocol)
-
-template newRawSocket*(domain: Domain = AF_INET,
-                       sockType: SockType = SOCK_STREAM,
-                       protocol: Protocol = IPPROTO_TCP): untyped =
-  {.warning: "newRawSocket is deprecated, use newNativeSocket instead".}
-  newNativeSocket(domain, sockType, protocol)
diff --git a/lib/pure/securehash.nim b/lib/deprecated/pure/securehash.nim
index c6cde599a..c6cde599a 100644
--- a/lib/pure/securehash.nim
+++ b/lib/deprecated/pure/securehash.nim
diff --git a/lib/experimental/diff.nim b/lib/experimental/diff.nim
index bffce2803..253355707 100644
--- a/lib/experimental/diff.nim
+++ b/lib/experimental/diff.nim
@@ -252,8 +252,11 @@ proc createDiffs(dataA, dataB: DiffData): seq[Item] =
 
 proc diffInt*(arrayA, arrayB: openArray[int]): seq[Item] =
   ## Find the difference in 2 arrays of integers.
+  ##
   ## ``arrayA`` A-version of the numbers (usualy the old one)
+  ##
   ## ``arrayB`` B-version of the numbers (usualy the new one)
+  ##
   ## Returns a array of Items that describe the differences.
 
   # The A-Version of the data (original data) to be compared.
@@ -273,15 +276,16 @@ proc diffInt*(arrayA, arrayB: openArray[int]): seq[Item] =
 
 proc diffText*(textA, textB: string): seq[Item] =
   ## Find the difference in 2 text documents, comparing by textlines.
+  ##
   ## The algorithm itself is comparing 2 arrays of numbers so when comparing 2 text documents
   ## each line is converted into a (hash) number. This hash-value is computed by storing all
   ## textlines into a common hashtable so i can find dublicates in there, and generating a
   ## new number each time a new textline is inserted.
-  ## ``TextA`` A-version of the text (usualy the old one)
-  ## ``TextB`` B-version of the text (usualy the new one)
-  ## ``trimSpace`` When set to true, all leading and trailing whitespace characters are stripped out before the comparation is done.
-  ## ``ignoreSpace`` When set to true, all whitespace characters are converted to a single space character before the comparation is done.
-  ## ``ignoreCase`` When set to true, all characters are converted to their lowercase equivivalence before the comparation is done.
+  ##
+  ## ``textA`` A-version of the text (usually the old one)
+  ##
+  ## ``textB`` B-version of the text (usually the new one)
+  ##
   ## Returns a seq of Items that describe the differences.
 
   # prepare the input-text and convert to comparable numbers.
diff --git a/lib/impure/db_odbc.nim b/lib/impure/db_odbc.nim
index 72d7aa800..b7af5128a 100644
--- a/lib/impure/db_odbc.nim
+++ b/lib/impure/db_odbc.nim
@@ -131,7 +131,7 @@ proc getErrInfo(db: var DbConn): tuple[res: int, ss, ne, msg: string] {.
               511.TSqlSmallInt, retSz.addr.PSQLSMALLINT)
   except:
     discard
-  return (res.int, $sqlState, $nativeErr, $errMsg)
+  return (res.int, $(addr sqlState), $(addr nativeErr), $(addr errMsg))
 
 proc dbError*(db: var DbConn) {.
           tags: [ReadDbEffect, WriteDbEffect], raises: [DbError] .} =
diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim
index c7e373098..3910992bb 100644
--- a/lib/impure/db_sqlite.nim
+++ b/lib/impure/db_sqlite.nim
@@ -166,10 +166,12 @@ iterator fastRows*(db: DbConn, query: SqlQuery,
   var stmt = setupQuery(db, query, args)
   var L = (column_count(stmt))
   var result = newRow(L)
-  while step(stmt) == SQLITE_ROW:
-    setRow(stmt, result, L)
-    yield result
-  if finalize(stmt) != SQLITE_OK: dbError(db)
+  try:
+    while step(stmt) == SQLITE_ROW:
+      setRow(stmt, result, L)
+      yield result
+  finally:
+    if finalize(stmt) != SQLITE_OK: dbError(db)
 
 iterator instantRows*(db: DbConn, query: SqlQuery,
                       args: varargs[string, `$`]): InstantRow
@@ -177,9 +179,11 @@ iterator instantRows*(db: DbConn, query: SqlQuery,
   ## same as fastRows but returns a handle that can be used to get column text
   ## on demand using []. Returned handle is valid only within the iterator body.
   var stmt = setupQuery(db, query, args)
-  while step(stmt) == SQLITE_ROW:
-    yield stmt
-  if finalize(stmt) != SQLITE_OK: dbError(db)
+  try:
+    while step(stmt) == SQLITE_ROW:
+      yield stmt
+  finally:
+    if finalize(stmt) != SQLITE_OK: dbError(db)
 
 proc toTypeKind(t: var DbType; x: int32) =
   case x
@@ -210,9 +214,11 @@ iterator instantRows*(db: DbConn; columns: var DbColumns; query: SqlQuery,
   ## on demand using []. Returned handle is valid only within the iterator body.
   var stmt = setupQuery(db, query, args)
   setColumns(columns, stmt)
-  while step(stmt) == SQLITE_ROW:
-    yield stmt
-  if finalize(stmt) != SQLITE_OK: dbError(db)
+  try:
+    while step(stmt) == SQLITE_ROW:
+      yield stmt
+  finally:
+    if finalize(stmt) != SQLITE_OK: dbError(db)
 
 proc `[]`*(row: InstantRow, col: int32): string {.inline.} =
   ## returns text for given column of the row
diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim
index 94dd89db5..5c5125ba1 100644
--- a/lib/impure/nre.nim
+++ b/lib/impure/nre.nim
@@ -540,7 +540,7 @@ proc matchImpl(str: string, pattern: Regex, start, endpos: int, flags: int): Opt
       raise RegexInternalError(msg : "Unknown internal error: " & $execRet)
 
 proc match*(str: string, pattern: Regex, start = 0, endpos = int.high): Option[RegexMatch] =
-  ## Like ```find(...)`` <#proc-find>`_, but anchored to the start of the
+  ## Like ` ``find(...)`` <#proc-find>`_, but anchored to the start of the
   ## string.
   ##
   runnableExamples:
@@ -550,11 +550,11 @@ proc match*(str: string, pattern: Regex, start = 0, endpos = int.high): Option[R
   return str.matchImpl(pattern, start, endpos, pcre.ANCHORED)
 
 iterator findIter*(str: string, pattern: Regex, start = 0, endpos = int.high): RegexMatch =
-  ## Works the same as ```find(...)`` <#proc-find>`_, but finds every
+  ## Works the same as ` ``find(...)`` <#proc-find>`_, but finds every
   ## non-overlapping match. ``"2222".find(re"22")`` is ``"22", "22"``, not
   ## ``"22", "22", "22"``.
   ##
-  ## Arguments are the same as ```find(...)`` <#proc-find>`_
+  ## Arguments are the same as ` ``find(...)`` <#proc-find>`_
   ##
   ## Variants:
   ##
@@ -633,7 +633,7 @@ proc split*(str: string, pattern: Regex, maxSplit = -1, start = 0): seq[string]
   ## Splits the string with the given regex. This works according to the
   ## rules that Perl and Javascript use.
   ##
-  ## ``start`` behaves the same as in ```find(...)`` <#proc-find>`_.
+  ## ``start`` behaves the same as in ` ``find(...)`` <#proc-find>`_.
   ##
   runnableExamples:
     # -  If the match is zero-width, then the string is still split:
diff --git a/lib/impure/re.nim b/lib/impure/re.nim
index dc4ee326f..42be4a3c2 100644
--- a/lib/impure/re.nim
+++ b/lib/impure/re.nim
@@ -561,31 +561,6 @@ proc escapeRe*(s: string): string =
       result.add("\\x")
       result.add(toHex(ord(c), 2))
 
-const ## common regular expressions
-  reIdentifier* {.deprecated.} = r"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b"
-    ## describes an identifier
-  reNatural* {.deprecated.} = r"\b\d+\b"
-    ## describes a natural number
-  reInteger* {.deprecated.} = r"\b[-+]?\d+\b"
-    ## describes an integer
-  reHex* {.deprecated.} = r"\b0[xX][0-9a-fA-F]+\b"
-    ## describes a hexadecimal number
-  reBinary* {.deprecated.} = r"\b0[bB][01]+\b"
-    ## describes a binary number (example: 0b11101)
-  reOctal* {.deprecated.} = r"\b0[oO][0-7]+\b"
-    ## describes an octal number (example: 0o777)
-  reFloat* {.deprecated.} = r"\b[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\b"
-    ## describes a floating point number
-  reEmail* {.deprecated.} = r"\b[a-zA-Z0-9!#$%&'*+/=?^_`{|}~\-]+(?:\. &" &
-                            r"[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@" &
-                            r"(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+" &
-                            r"(?:[a-zA-Z]{2}|com|org|net|gov|mil|biz|" &
-                            r"info|mobi|name|aero|jobs|museum)\b"
-    ## describes a common email address
-  reURL* {.deprecated.} = r"\b(http(s)?|ftp|gopher|telnet|file|notes|ms-help)" &
-                          r":((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-\=\\\.\&]*\b"
-    ## describes an URL
-
 when isMainModule:
   doAssert match("(a b c)", rex"\( .* \)")
   doAssert match("WHiLe", re("while", {reIgnoreCase}))
@@ -595,7 +570,7 @@ when isMainModule:
   doAssert "ABC".match(rex"\d+ | \w+")
 
   {.push warnings:off.}
-  doAssert matchLen("key", re(reIdentifier)) == 3
+  doAssert matchLen("key", re"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b") == 3
   {.pop.}
 
   var pattern = re"[a-z0-9]+\s*=\s*[a-z0-9]+"
diff --git a/lib/impure/ssl.nim b/lib/impure/ssl.nim
deleted file mode 100644
index 0bcb3f217..000000000
--- a/lib/impure/ssl.nim
+++ /dev/null
@@ -1,99 +0,0 @@
-#
-#
-#            Nim's Runtime Library
-#        (c) Copyright 2012 Dominik Picheta
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## This module provides an easy to use sockets-style
-## nim interface to the OpenSSL library.
-##
-## **Warning:** This module is deprecated, use the SSL procedures defined in
-## the ``net`` module instead.
-
-{.deprecated.}
-
-import openssl, strutils, os
-
-type
-  SecureSocket* = object
-    ssl: SslPtr
-    bio: BIO
-
-proc connect*(sock: var SecureSocket, address: string,
-    port: int): int =
-  ## Connects to the specified `address` on the specified `port`.
-  ## Returns the result of the certificate validation.
-  SslLoadErrorStrings()
-  ERR_load_BIO_strings()
-
-  if SSL_library_init() != 1:
-    raiseOSError(osLastError())
-
-  var ctx = SSL_CTX_new(SSLv23_client_method())
-  if ctx == nil:
-    ERR_print_errors_fp(stderr)
-    raiseOSError(osLastError())
-
-  #if SSL_CTX_load_verify_locations(ctx,
-  #   "/tmp/openssl-0.9.8e/certs/vsign1.pem", NIL) == 0:
-  #  echo("Failed load verify locations")
-  #  ERR_print_errors_fp(stderr)
-
-  sock.bio = BIO_new_ssl_connect(ctx)
-  if BIO_get_ssl(sock.bio, addr(sock.ssl)) == 0:
-    raiseOSError(osLastError())
-
-  if BIO_set_conn_hostname(sock.bio, address & ":" & $port) != 1:
-    raiseOSError(osLastError())
-
-  if BIO_do_connect(sock.bio) <= 0:
-    ERR_print_errors_fp(stderr)
-    raiseOSError(osLastError())
-
-  result = SSL_get_verify_result(sock.ssl)
-
-proc recvLine*(sock: SecureSocket, line: var TaintedString): bool =
-  ## Acts in a similar fashion to the `recvLine` in the sockets module.
-  ## Returns false when no data is available to be read.
-  ## `Line` must be initialized and not nil!
-  setLen(line.string, 0)
-  while true:
-    var c: array[0..0, char]
-    var n = BIO_read(sock.bio, addr c, c.len.cint)
-    if n <= 0: return false
-    if c[0] == '\r':
-      n = BIO_read(sock.bio, addr c, c.len.cint)
-      if n > 0 and c[0] == '\L':
-        return true
-      elif n <= 0:
-        return false
-    elif c[0] == '\L': return true
-    add(line.string, c[0])
-
-
-proc send*(sock: SecureSocket, data: string) =
-  ## Writes `data` to the socket.
-  if BIO_write(sock.bio, data, data.len.cint) <= 0:
-    raiseOSError(osLastError())
-
-proc close*(sock: SecureSocket) =
-  ## Closes the socket
-  if BIO_free(sock.bio) <= 0:
-    ERR_print_errors_fp(stderr)
-    raiseOSError(osLastError())
-
-when not defined(testing) and isMainModule:
-  var s: SecureSocket
-  echo connect(s, "smtp.gmail.com", 465)
-
-  #var buffer: array[0..255, char]
-  #echo BIO_read(bio, buffer, buffer.len)
-  var buffer: string = ""
-
-  echo s.recvLine(buffer)
-  echo buffer
-  echo buffer.len
-
diff --git a/lib/js/dom.nim b/lib/js/dom.nim
index cf219df3d..668dee822 100644
--- a/lib/js/dom.nim
+++ b/lib/js/dom.nim
@@ -416,12 +416,12 @@ type
   BoundingRect* {.importc.} = ref object
     top*, bottom*, left*, right*, x*, y*, width*, height*: float
 
-  PerformanceMemory* {.importc.} = ref object 
+  PerformanceMemory* {.importc.} = ref object
     jsHeapSizeLimit*: float
     totalJSHeapSize*: float
     usedJSHeapSize*: float
 
-  PerformanceTiming* {.importc.} = ref object 
+  PerformanceTiming* {.importc.} = ref object
     connectStart*: float
     domComplete*: float
     domContentLoadedEventEnd*: float
@@ -459,7 +459,6 @@ proc dispatchEvent*(et: EventTarget, ev: Event)
 proc alert*(w: Window, msg: cstring)
 proc back*(w: Window)
 proc blur*(w: Window)
-proc captureEvents*(w: Window, eventMask: int) {.deprecated.}
 proc clearInterval*(w: Window, interval: ref TInterval)
 proc clearTimeout*(w: Window, timeout: ref TTimeOut)
 proc close*(w: Window)
@@ -478,7 +477,6 @@ proc open*(w: Window, uri, windowname: cstring,
            properties: cstring = nil): Window
 proc print*(w: Window)
 proc prompt*(w: Window, text, default: cstring): cstring
-proc releaseEvents*(w: Window, eventMask: int) {.deprecated.}
 proc resizeBy*(w: Window, x, y: int)
 proc resizeTo*(w: Window, x, y: int)
 proc routeEvent*(w: Window, event: Event)
@@ -513,7 +511,6 @@ proc setAttribute*(n: Node, name, value: cstring)
 proc setAttributeNode*(n: Node, attr: Node)
 
 # Document "methods"
-proc captureEvents*(d: Document, eventMask: int) {.deprecated.}
 proc createAttribute*(d: Document, identifier: cstring): Node
 proc createElement*(d: Document, identifier: cstring): Element
 proc createTextNode*(d: Document, identifier: cstring): Node
@@ -524,7 +521,6 @@ proc getElementsByClassName*(d: Document, name: cstring): seq[Element]
 proc getSelection*(d: Document): cstring
 proc handleEvent*(d: Document, event: Event)
 proc open*(d: Document)
-proc releaseEvents*(d: Document, eventMask: int) {.deprecated.}
 proc routeEvent*(d: Document, event: Event)
 proc write*(d: Document, text: cstring)
 proc writeln*(d: Document, text: cstring)
@@ -605,25 +601,3 @@ proc parseInt*(s: cstring): int {.importc, nodecl.}
 proc parseInt*(s: cstring, radix: int):int {.importc, nodecl.}
 
 proc newEvent*(name: cstring): Event {.importcpp: "new Event(@)", constructor.}
-
-type
-  TEventHandlers* {.deprecated.} = EventTargetObj
-  TWindow* {.deprecated.} = WindowObj
-  TFrame* {.deprecated.} = FrameObj
-  TNode* {.deprecated.} = NodeObj
-  TDocument* {.deprecated.} = DocumentObj
-  TElement* {.deprecated.} = ElementObj
-  TLink* {.deprecated.} = LinkObj
-  TEmbed* {.deprecated.} = EmbedObj
-  TAnchor* {.deprecated.} = AnchorObj
-  TOption* {.deprecated.} = OptionObj
-  TForm* {.deprecated.} = FormObj
-  TImage* {.deprecated.} = ImageObj
-  TNodeType* {.deprecated.} = NodeType
-  TEvent* {.deprecated.} = EventObj
-  TLocation* {.deprecated.} = LocationObj
-  THistory* {.deprecated.} = HistoryObj
-  TNavigator* {.deprecated.} = NavigatorObj
-  TStyle* {.deprecated.} = StyleObj
-  TScreen* {.deprecated.} = ScreenObj
-  TApplet* {.importc, deprecated.} = object of RootObj
diff --git a/lib/js/jscore.nim b/lib/js/jscore.nim
index bf64b0794..2e2bd2402 100644
--- a/lib/js/jscore.nim
+++ b/lib/js/jscore.nim
@@ -73,7 +73,7 @@ proc parse*(d: DateLib, s: cstring): int {.importcpp.}
 proc newDate*(): DateTime {.
   importcpp: "new Date()".}
 
-proc newDate*(date: int|string): DateTime {.
+proc newDate*(date: int|int64|string): DateTime {.
   importcpp: "new Date(#)".}
 
 proc newDate*(year, month, day, hours, minutes,
@@ -90,6 +90,16 @@ proc getSeconds*(d: DateTime): int {.importcpp.}
 proc getYear*(d: DateTime): int {.importcpp.}
 proc getTime*(d: DateTime): int {.importcpp.}
 proc toString*(d: DateTime): cstring {.importcpp.}
+proc getUTCDate*(d: DateTime): int {.importcpp.}
+proc getUTCFullYear*(d: DateTime): int {.importcpp.}
+proc getUTCHours*(d: DateTime): int {.importcpp.}
+proc getUTCMilliseconds*(d: DateTime): int {.importcpp.}
+proc getUTCMinutes*(d: DateTime): int {.importcpp.}
+proc getUTCMonth*(d: DateTime): int {.importcpp.}
+proc getUTCSeconds*(d: DateTime): int {.importcpp.}
+proc getUTCDay*(d: DateTime): int {.importcpp.}
+proc getTimezoneOffset*(d: DateTime): int {.importcpp.}
+proc setFullYear*(d: DateTime, year: int) {.importcpp.}
 
 #JSON library
 proc stringify*(l: JsonLib, s: JsRoot): cstring {.importcpp.}
diff --git a/lib/js/jsffi.nim b/lib/js/jsffi.nim
index e1c59803d..7f0939b08 100644
--- a/lib/js/jsffi.nim
+++ b/lib/js/jsffi.nim
@@ -104,6 +104,12 @@ var
   jsFilename* {.importc: "__filename", nodecl.}: cstring
     ## JavaScript's __filename pseudo-variable
 
+proc isNull*[T](x: T): bool {.noSideEffect, importcpp: "(# === null)".}
+  ## check if a value is exactly null
+
+proc isUndefined*[T](x: T): bool {.noSideEffect, importcpp: "(# === undefined)".}
+  ## check if a value is exactly undefined
+
 # Exceptions
 type
   JsError* {.importc: "Error".} = object of JsRoot
diff --git a/lib/nimbase.h b/lib/nimbase.h
index 2cb632787..ba4273726 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -166,13 +166,13 @@ __clang__
 #  define N_STDCALL(rettype, name) rettype __stdcall name
 #  define N_SYSCALL(rettype, name) rettype __syscall name
 #  define N_FASTCALL(rettype, name) rettype __fastcall name
-#  define N_SAFECALL(rettype, name) rettype __safecall name
+#  define N_SAFECALL(rettype, name) rettype __stdcall name
 /* function pointers with calling convention: */
 #  define N_CDECL_PTR(rettype, name) rettype (__cdecl *name)
 #  define N_STDCALL_PTR(rettype, name) rettype (__stdcall *name)
 #  define N_SYSCALL_PTR(rettype, name) rettype (__syscall *name)
 #  define N_FASTCALL_PTR(rettype, name) rettype (__fastcall *name)
-#  define N_SAFECALL_PTR(rettype, name) rettype (__safecall *name)
+#  define N_SAFECALL_PTR(rettype, name) rettype (__stdcall *name)
 
 #  ifdef __cplusplus
 #    define N_LIB_EXPORT  extern "C" __declspec(dllexport)
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim
index 161509afe..551df9919 100644
--- a/lib/packages/docutils/rst.nim
+++ b/lib/packages/docutils/rst.nim
@@ -560,9 +560,9 @@ proc match(p: RstParser, start: int, expr: string): bool =
       result = (p.tok[j].kind == tkWord) or (p.tok[j].symbol == "#")
       if result:
         case p.tok[j].symbol[0]
-        of 'a'..'z', 'A'..'Z': result = len(p.tok[j].symbol) == 1
+        of 'a'..'z', 'A'..'Z', '#': result = len(p.tok[j].symbol) == 1
         of '0'..'9': result = allCharsInSet(p.tok[j].symbol, {'0'..'9'})
-        else: discard
+        else: result = false
     else:
       var c = expr[i]
       var length = 0
@@ -780,6 +780,31 @@ proc parseMarkdownCodeblock(p: var RstParser): PRstNode =
   add(result, nil)
   add(result, lb)
 
+proc parseMarkdownLink(p: var RstParser; father: PRstNode): bool =
+  result = true
+  var desc, link = ""
+  var i = p.idx
+
+  template parse(endToken, dest) =
+    inc i # skip begin token
+    while true:
+      if p.tok[i].kind in {tkEof, tkIndent}: return false
+      if p.tok[i].symbol == endToken: break
+      dest.add p.tok[i].symbol
+      inc i
+    inc i # skip end token
+
+  parse("]", desc)
+  if p.tok[i].symbol != "(": return false
+  parse(")", link)
+  let child = newRstNode(rnHyperlink)
+  child.add desc
+  child.add link
+  # only commit if we detected no syntax error:
+  father.add child
+  p.idx = i
+  result = true
+
 proc parseInline(p: var RstParser, father: PRstNode) =
   case p.tok[p.idx].kind
   of tkPunct:
@@ -811,6 +836,9 @@ proc parseInline(p: var RstParser, father: PRstNode) =
       var n = newRstNode(rnSubstitutionReferences)
       parseUntil(p, n, "|", false)
       add(father, n)
+    elif roSupportMarkdown in p.s.options and p.tok[p.idx].symbol == "[" and
+        parseMarkdownLink(p, father):
+      discard "parseMarkdownLink already processed it"
     else:
       if roSupportSmilies in p.s.options:
         let n = parseSmiley(p)
@@ -1037,15 +1065,32 @@ proc isOptionList(p: RstParser): bool =
   result = match(p, p.idx, "-w") or match(p, p.idx, "--w") or
            match(p, p.idx, "/w") or match(p, p.idx, "//w")
 
+proc isMarkdownHeadlinePattern(s: string): bool =
+  if s.len >= 1 and s.len <= 6:
+    for c in s:
+      if c != '#': return false
+    result = true
+
+proc isMarkdownHeadline(p: RstParser): bool =
+  if roSupportMarkdown in p.s.options:
+    if isMarkdownHeadlinePattern(p.tok[p.idx].symbol) and p.tok[p.idx+1].kind == tkWhite:
+      if p.tok[p.idx+2].kind in {tkWord, tkOther, tkPunct}:
+        result = true
+
 proc whichSection(p: RstParser): RstNodeKind =
   case p.tok[p.idx].kind
   of tkAdornment:
     if match(p, p.idx + 1, "ii"): result = rnTransition
     elif match(p, p.idx + 1, " a"): result = rnTable
     elif match(p, p.idx + 1, "i"): result = rnOverline
-    else: result = rnLeaf
+    elif isMarkdownHeadline(p):
+      result = rnHeadline
+    else:
+      result = rnLeaf
   of tkPunct:
-    if match(p, tokenAfterNewline(p), "ai"):
+    if isMarkdownHeadline(p):
+      result = rnHeadline
+    elif match(p, tokenAfterNewline(p), "ai"):
       result = rnHeadline
     elif p.tok[p.idx].symbol == "::":
       result = rnLiteralBlock
@@ -1060,7 +1105,7 @@ proc whichSection(p: RstParser): RstNodeKind =
     elif match(p, p.idx, ":w:") and predNL(p):
       # (p.tok[p.idx].symbol == ":")
       result = rnFieldList
-    elif match(p, p.idx, "(e) "):
+    elif match(p, p.idx, "(e) ") or match(p, p.idx, "e. "):
       result = rnEnumList
     elif match(p, p.idx, "+a+"):
       result = rnGridTable
@@ -1130,12 +1175,18 @@ proc parseParagraph(p: var RstParser, result: PRstNode) =
 
 proc parseHeadline(p: var RstParser): PRstNode =
   result = newRstNode(rnHeadline)
-  parseUntilNewline(p, result)
-  assert(p.tok[p.idx].kind == tkIndent)
-  assert(p.tok[p.idx + 1].kind == tkAdornment)
-  var c = p.tok[p.idx + 1].symbol[0]
-  inc(p.idx, 2)
-  result.level = getLevel(p.s.underlineToLevel, p.s.uLevel, c)
+  if isMarkdownHeadline(p):
+    result.level = p.tok[p.idx].symbol.len
+    assert(p.tok[p.idx+1].kind == tkWhite)
+    inc p.idx, 2
+    parseUntilNewline(p, result)
+  else:
+    parseUntilNewline(p, result)
+    assert(p.tok[p.idx].kind == tkIndent)
+    assert(p.tok[p.idx + 1].kind == tkAdornment)
+    var c = p.tok[p.idx + 1].symbol[0]
+    inc(p.idx, 2)
+    result.level = getLevel(p.s.underlineToLevel, p.s.uLevel, c)
 
 type
   IntSeq = seq[int]
diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim
index 4a77b4f34..fee824b09 100644
--- a/lib/packages/docutils/rstast.nim
+++ b/lib/packages/docutils/rstast.nim
@@ -89,6 +89,9 @@ proc lastSon*(n: PRstNode): PRstNode =
 proc add*(father, son: PRstNode) =
   add(father.sons, son)
 
+proc add*(father: PRstNode; s: string) =
+  add(father.sons, newRstNode(rnLeaf, s))
+
 proc addIfNotNil*(father, son: PRstNode) =
   if son != nil: add(father, son)
 
diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim
index 232da5c93..766ce6ffd 100644
--- a/lib/packages/docutils/rstgen.nim
+++ b/lib/packages/docutils/rstgen.nim
@@ -1134,11 +1134,9 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
   of rnTripleEmphasis:
     renderAux(d, n, "<strong><em>$1</em></strong>",
                     "\\textbf{emph{$1}}", result)
-  of rnInterpretedText:
-    renderAux(d, n, "<cite>$1</cite>", "\\emph{$1}", result)
   of rnIdx:
     renderIndexTerm(d, n, result)
-  of rnInlineLiteral:
+  of rnInlineLiteral, rnInterpretedText:
     renderAux(d, n,
       "<tt class=\"docutils literal\"><span class=\"pre\">$1</span></tt>",
       "\\texttt{$1}", result)
diff --git a/lib/posix/posix_linux_amd64_consts.nim b/lib/posix/posix_linux_amd64_consts.nim
index c23005b1e..dfbfe7f64 100644
--- a/lib/posix/posix_linux_amd64_consts.nim
+++ b/lib/posix/posix_linux_amd64_consts.nim
@@ -295,6 +295,7 @@ const IF_NAMESIZE* = cint(16)
 const IPPROTO_IP* = cint(0)
 const IPPROTO_IPV6* = cint(41)
 const IPPROTO_ICMP* = cint(1)
+const IPPROTO_ICMPV6* = cint(58)
 const IPPROTO_RAW* = cint(255)
 const IPPROTO_TCP* = cint(6)
 const IPPROTO_UDP* = cint(17)
diff --git a/lib/posix/posix_nintendoswitch_consts.nim b/lib/posix/posix_nintendoswitch_consts.nim
index f0c0dd717..1e782d92e 100644
--- a/lib/posix/posix_nintendoswitch_consts.nim
+++ b/lib/posix/posix_nintendoswitch_consts.nim
@@ -237,6 +237,7 @@ const IF_NAMESIZE* = cint(16)
 const IPPROTO_IP* = cint(0)
 const IPPROTO_IPV6* = cint(41)
 const IPPROTO_ICMP* = cint(1)
+const IPPROTO_ICMPV6* = cint(58)
 const IPPROTO_RAW* = cint(255)
 const IPPROTO_TCP* = cint(6)
 const IPPROTO_UDP* = cint(17)
diff --git a/lib/posix/posix_other_consts.nim b/lib/posix/posix_other_consts.nim
index 2b4b70941..cd5199078 100644
--- a/lib/posix/posix_other_consts.nim
+++ b/lib/posix/posix_other_consts.nim
@@ -302,6 +302,7 @@ var IF_NAMESIZE* {.importc: "IF_NAMESIZE", header: "<net/if.h>".}: cint
 var IPPROTO_IP* {.importc: "IPPROTO_IP", header: "<netinet/in.h>".}: cint
 var IPPROTO_IPV6* {.importc: "IPPROTO_IPV6", header: "<netinet/in.h>".}: cint
 var IPPROTO_ICMP* {.importc: "IPPROTO_ICMP", header: "<netinet/in.h>".}: cint
+var IPPROTO_ICMPV6* {.importc: "IPPROTO_ICMPV6", header: "<netinet/in.h>".}: cint
 var IPPROTO_RAW* {.importc: "IPPROTO_RAW", header: "<netinet/in.h>".}: cint
 var IPPROTO_TCP* {.importc: "IPPROTO_TCP", header: "<netinet/in.h>".}: cint
 var IPPROTO_UDP* {.importc: "IPPROTO_UDP", header: "<netinet/in.h>".}: cint
diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim
index d27c2fb9c..e3fc75597 100644
--- a/lib/pure/asynchttpserver.nim
+++ b/lib/pure/asynchttpserver.nim
@@ -143,11 +143,14 @@ proc parseUppercaseMethod(name: string): HttpMethod =
     of "TRACE": HttpTrace
     else: raise newException(ValueError, "Invalid HTTP method " & name)
 
-proc processRequest(server: AsyncHttpServer, req: FutureVar[Request],
-                    client: AsyncSocket,
-                    address: string, lineFut: FutureVar[string],
-                    callback: proc (request: Request):
-                      Future[void] {.closure, gcsafe.}) {.async.} =
+proc processRequest(
+  server: AsyncHttpServer,
+  req: FutureVar[Request],
+  client: AsyncSocket,
+  address: string,
+  lineFut: FutureVar[string],
+  callback: proc (request: Request): Future[void] {.closure, gcsafe.},
+): Future[bool] {.async.} =
 
   # Alias `request` to `req.mget()` so we don't have to write `mget` everywhere.
   template request(): Request =
@@ -171,12 +174,12 @@ proc processRequest(server: AsyncHttpServer, req: FutureVar[Request],
 
     if lineFut.mget == "":
       client.close()
-      return
+      return false
 
     if lineFut.mget.len > maxLine:
       await request.respondError(Http413)
       client.close()
-      return
+      return false
     if lineFut.mget != "\c\L":
       break
 
@@ -189,22 +192,22 @@ proc processRequest(server: AsyncHttpServer, req: FutureVar[Request],
         request.reqMethod = parseUppercaseMethod(linePart)
       except ValueError:
         asyncCheck request.respondError(Http400)
-        return
+        return true # Retry processing of request
     of 1:
       try:
         parseUri(linePart, request.url)
       except ValueError:
         asyncCheck request.respondError(Http400)
-        return
+        return true
     of 2:
       try:
         request.protocol = parseProtocol(linePart)
       except ValueError:
         asyncCheck request.respondError(Http400)
-        return
+        return true
     else:
       await request.respondError(Http400)
-      return
+      return true
     inc i
 
   # Headers
@@ -215,10 +218,10 @@ proc processRequest(server: AsyncHttpServer, req: FutureVar[Request],
     await client.recvLineInto(lineFut, maxLength=maxLine)
 
     if lineFut.mget == "":
-      client.close(); return
+      client.close(); return false
     if lineFut.mget.len > maxLine:
       await request.respondError(Http413)
-      client.close(); return
+      client.close(); return false
     if lineFut.mget == "\c\L": break
     let (key, value) = parseHeader(lineFut.mget)
     request.headers[key] = value
@@ -226,7 +229,7 @@ proc processRequest(server: AsyncHttpServer, req: FutureVar[Request],
     if request.headers.len > headerLimit:
       await client.sendStatus("400 Bad Request")
       request.client.close()
-      return
+      return false
 
   if request.reqMethod == HttpPost:
     # Check for Expect header
@@ -242,24 +245,24 @@ proc processRequest(server: AsyncHttpServer, req: FutureVar[Request],
     var contentLength = 0
     if parseSaturatedNatural(request.headers["Content-Length"], contentLength) == 0:
       await request.respond(Http400, "Bad Request. Invalid Content-Length.")
-      return
+      return true
     else:
       if contentLength > server.maxBody:
         await request.respondError(Http413)
-        return
+        return false
       request.body = await client.recv(contentLength)
       if request.body.len != contentLength:
         await request.respond(Http400, "Bad Request. Content-Length does not match actual.")
-        return
+        return true
   elif request.reqMethod == HttpPost:
     await request.respond(Http411, "Content-Length required.")
-    return
+    return true
 
   # Call the user's callback.
   await callback(request)
 
   if "upgrade" in request.headers.getOrDefault("connection"):
-    return
+    return false
 
   # Persistent connections
   if (request.protocol == HttpVer11 and
@@ -273,7 +276,7 @@ proc processRequest(server: AsyncHttpServer, req: FutureVar[Request],
     discard
   else:
     request.client.close()
-    return
+    return false
 
 proc processClient(server: AsyncHttpServer, client: AsyncSocket, address: string,
                    callback: proc (request: Request):
@@ -285,7 +288,10 @@ proc processClient(server: AsyncHttpServer, client: AsyncSocket, address: string
   lineFut.mget() = newStringOfCap(80)
 
   while not client.isClosed:
-    await processRequest(server, request, client, address, lineFut, callback)
+    let retry = await processRequest(
+      server, request, client, address, lineFut, callback
+    )
+    if not retry: break
 
 proc serve*(server: AsyncHttpServer, port: Port,
             callback: proc (request: Request): Future[void] {.closure,gcsafe.},
diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim
index bfb8a1666..427f93926 100644
--- a/lib/pure/base64.nim
+++ b/lib/pure/base64.nim
@@ -9,37 +9,49 @@
 
 ## This module implements a base64 encoder and decoder.
 ##
+## Base64 is an encoding and decoding technique used to convert binary
+## data to an ASCII string format.
+## Each Base64 digit represents exactly 6 bits of data. Three 8-bit
+## bytes (i.e., a total of 24 bits) can therefore be represented by
+## four 6-bit Base64 digits.
+##
+##
+## Basic usage
+## ===========
+##
 ## Encoding data
 ## -------------
 ##
-## In order to encode some text simply call the ``encode`` procedure:
-##
-##   .. code-block::nim
-##      import base64
-##      let encoded = encode("Hello World")
-##      echo(encoded) # SGVsbG8gV29ybGQ=
+## .. code-block::nim
+##    import base64
+##    let encoded = encode("Hello World")
+##    assert encoded == "SGVsbG8gV29ybGQ="
 ##
 ## Apart from strings you can also encode lists of integers or characters:
 ##
-##   .. code-block::nim
-##      import base64
-##      let encodedInts = encode([1,2,3])
-##      echo(encodedInts) # AQID
-##      let encodedChars = encode(['h','e','y'])
-##      echo(encodedChars) # aGV5
+## .. code-block::nim
+##    import base64
+##    let encodedInts = encode([1,2,3])
+##    assert encodedInts == "AQID"
+##    let encodedChars = encode(['h','e','y'])
+##    assert encodedChars == "aGV5"
 ##
-## The ``encode`` procedure takes an ``openarray`` so both arrays and sequences
-## can be passed as parameters.
 ##
 ## Decoding data
 ## -------------
 ##
-## To decode a base64 encoded data string simply call the ``decode``
-## procedure:
+## .. code-block::nim
+##    import base64
+##    let decoded = decode("SGVsbG8gV29ybGQ=")
+##    assert decoded == "Hello World"
 ##
-##   .. code-block::nim
-##      import base64
-##      echo(decode("SGVsbG8gV29ybGQ=")) # Hello World
+##
+## See also
+## ========
+##
+## * `hashes module<hashes.html>`_ for efficient computations of hash values for diverse Nim types
+## * `md5 module<md5.html>`_ implements the MD5 checksum algorithm
+## * `sha1 module<sha1.html>`_ implements a sha1 encoder and decoder
 
 const
   cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
@@ -100,18 +112,33 @@ template encodeInternal(s: typed, lineLen: int, newLine: string): untyped =
     discard
 
 proc encode*[T:SomeInteger|char](s: openarray[T], lineLen = 75, newLine="\13\10"): string =
-  ## encodes `s` into base64 representation. After `lineLen` characters, a
-  ## `newline` is added.
+  ## Encodes ``s`` into base64 representation. After ``lineLen`` characters, a
+  ## ``newline`` is added.
   ##
   ## This procedure encodes an openarray (array or sequence) of either integers
   ## or characters.
+  ##
+  ## **See also:**
+  ## * `encode proc<#encode,string,int,string>`_ for encoding a string
+  ## * `decode proc<#decode,string>`_ for decoding a string
+  runnableExamples:
+    assert encode(['n', 'i', 'm']) == "bmlt"
+    assert encode(@['n', 'i', 'm']) == "bmlt"
+    assert encode([1, 2, 3, 4, 5]) == "AQIDBAU="
   encodeInternal(s, lineLen, newLine)
 
 proc encode*(s: string, lineLen = 75, newLine="\13\10"): string =
-  ## encodes `s` into base64 representation. After `lineLen` characters, a
-  ## `newline` is added.
+  ## Encodes ``s`` into base64 representation. After ``lineLen`` characters, a
+  ## ``newline`` is added.
   ##
   ## This procedure encodes a string.
+  ##
+  ## **See also:**
+  ## * `encode proc<#encode,openArray[T],int,string>`_ for encoding an openarray
+  ## * `decode proc<#decode,string>`_ for decoding a string
+  runnableExamples:
+    assert encode("Hello World") == "SGVsbG8gV29ybGQ="
+    assert encode("Hello World", 3, "\n") == "SGVs\nbG8g\nV29ybGQ="
   encodeInternal(s, lineLen, newLine)
 
 proc decodeByte(b: char): int {.inline.} =
@@ -123,8 +150,15 @@ proc decodeByte(b: char): int {.inline.} =
   else: result = 63
 
 proc decode*(s: string): string =
-  ## decodes a string in base64 representation back into its original form.
-  ## Whitespace is skipped.
+  ## Decodes string ``s`` in base64 representation back into its original form.
+  ## The initial whitespace is skipped.
+  ##
+  ## **See also:**
+  ## * `encode proc<#encode,openArray[T],int,string>`_ for encoding an openarray
+  ## * `encode proc<#encode,string,int,string>`_ for encoding a string
+  runnableExamples:
+    assert decode("SGVsbG8gV29ybGQ=") == "Hello World"
+    assert decode("  SGVsbG8gV29ybGQ=") == "Hello World"
   const Whitespace = {' ', '\t', '\v', '\r', '\l', '\f'}
   var total = ((len(s) + 3) div 4) * 3
   # total is an upper bound, as we will skip arbitrary whitespace:
diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim
index 869abc9cc..ec3562c35 100644
--- a/lib/pure/cgi.nim
+++ b/lib/pure/cgi.nim
@@ -337,11 +337,6 @@ proc setStackTraceStdout*() =
   ## Makes Nim output stacktraces to stdout, instead of server log.
   errorMessageWriter = writeErrorMessage
 
-proc setStackTraceNewLine*() {.deprecated.} =
-  ## Makes Nim output stacktraces to stdout, instead of server log.
-  ## Depracated alias for setStackTraceStdout.
-  setStackTraceStdout()
-
 proc setCookie*(name, value: string) =
   ## Sets a cookie.
   write(stdout, "Set-Cookie: ", name, "=", value, "\n")
diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim
index 32e0299ba..dd91fdb12 100644
--- a/lib/pure/collections/critbits.nim
+++ b/lib/pure/collections/critbits.nim
@@ -202,12 +202,6 @@ proc `[]`*[T](c: var CritBitTree[T], key: string): var T {.inline,
   ## If `key` is not in `t`, the ``KeyError`` exception is raised.
   get(c, key)
 
-proc mget*[T](c: var CritBitTree[T], key: string): var T {.inline, deprecated.} =
-  ## retrieves the value at ``c[key]``. The value can be modified.
-  ## If `key` is not in `t`, the ``KeyError`` exception is raised.
-  ## Use ```[]``` instead.
-  get(c, key)
-
 iterator leaves[T](n: Node[T]): Node[T] =
   if n != nil:
     # XXX actually we could compute the necessary stack size in advance:
diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim
index e8342e208..cb05e5112 100644
--- a/lib/pure/collections/deques.nim
+++ b/lib/pure/collections/deques.nim
@@ -20,41 +20,59 @@
 ## access, unless your program logic guarantees it indirectly.
 ##
 ## .. code-block:: Nim
-##   proc foo(a, b: Positive) =  # assume random positive values for `a` and `b`
-##     var deq = initDeque[int]()  # initializes the object
-##     for i in 1 ..< a: deq.addLast i  # populates the deque
+##   import deques
 ##
-##     if b < deq.len:  # checking before indexed access
-##       echo "The element at index position ", b, " is ", deq[b]
+##   var a = initDeque[int]()
 ##
-##     # The following two lines don't need any checking on access due to the
-##     # logic of the program, but that would not be the case if `a` could be 0.
-##     assert deq.peekFirst == 1
-##     assert deq.peekLast == a
+##   doAssertRaises(IndexError, echo a[0])
 ##
-##     while deq.len > 0:  # checking if the deque is empty
-##       echo deq.popLast()
+##   for i in 1 .. 5:
+##     a.addLast(10*i)
+##   assert $a == "[10, 20, 30, 40, 50]"
 ##
-## Note: For inter thread communication use
-## a `Channel <channels.html>`_ instead.
+##   assert a.peekFirst == 10
+##   assert a.peekLast == 50
+##   assert len(a) == 5
+##
+##   assert a.popFirst == 10
+##   assert a.popLast == 50
+##   assert len(a) == 3
+##
+##   a.addFirst(11)
+##   a.addFirst(22)
+##   a.addFirst(33)
+##   assert $a == "[33, 22, 11, 20, 30, 40]"
+##
+##   a.shrink(fromFirst = 1, fromLast = 2)
+##   assert $a == "[22, 11, 20]"
+##
+##
+## **See also:**
+## * `lists module <lists.html>`_ for singly and doubly linked lists and rings
+## * `channels module <channels.html>`_ for inter-thread communication
+
 
 import math, typetraits
 
 type
   Deque*[T] = object
     ## A double-ended queue backed with a ringed seq buffer.
+    ##
+    ## To initialize an empty deque use `initDeque proc <#initDeque,int>`_.
     data: seq[T]
     head, tail, count, mask: int
 
 proc initDeque*[T](initialSize: int = 4): Deque[T] =
-  ## Create a new deque.
-  ## Optionally, the initial capacity can be reserved via `initialSize` as a
-  ## performance optimization. The length of a newly created deque will still
-  ## be 0.
+  ## Create a new empty deque.
   ##
-  ## `initialSize` needs to be a power of two. If you need to accept runtime
-  ## values for this you could use the ``nextPowerOfTwo`` proc from the
-  ## `math <math.html>`_ module.
+  ## Optionally, the initial capacity can be reserved via `initialSize`
+  ## as a performance optimization.
+  ## The length of a newly created deque will still be 0.
+  ##
+  ## ``initialSize`` must be a power of two (default: 4).
+  ## If you need to accept runtime values for this you could use the
+  ## `nextPowerOfTwo proc<math.html#nextPowerOfTwo,int>`_ from the
+  ## `math module<math.html>`_.
   assert isPowerOfTwo(initialSize)
   result.mask = initialSize-1
   newSeq(result.data, initialSize)
@@ -75,33 +93,128 @@ template xBoundsCheck(deq, i) =
     if unlikely(i >= deq.count):  # x < deq.low is taken care by the Natural parameter
       raise newException(IndexError,
                          "Out of bounds: " & $i & " > " & $(deq.count - 1))
+    if unlikely(i < 0):  # when used with BackwardsIndex
+      raise newException(IndexError,
+                         "Out of bounds: " & $i & " < 0")
 
 proc `[]`*[T](deq: Deque[T], i: Natural) : T {.inline.} =
-  ## Access the i-th element of `deq` by order from first to last.
-  ## deq[0] is the first, deq[^1] is the last.
+  ## Access the i-th element of `deq`.
+  runnableExamples:
+    var a = initDeque[int]()
+    for i in 1 .. 5:
+      a.addLast(10*i)
+    assert a[0] == 10
+    assert a[3] == 40
+    doAssertRaises(IndexError, echo a[8])
+
   xBoundsCheck(deq, i)
   return deq.data[(deq.head + i) and deq.mask]
 
 proc `[]`*[T](deq: var Deque[T], i: Natural): var T {.inline.} =
-  ## Access the i-th element of `deq` and returns a mutable
+  ## Access the i-th element of `deq` and return a mutable
   ## reference to it.
+  runnableExamples:
+    var a = initDeque[int]()
+    for i in 1 .. 5:
+      a.addLast(10*i)
+    assert a[0] == 10
+    assert a[3] == 40
+    doAssertRaises(IndexError, echo a[8])
+
   xBoundsCheck(deq, i)
   return deq.data[(deq.head + i) and deq.mask]
 
-proc `[]=`* [T] (deq: var Deque[T], i: Natural, val : T) {.inline.} =
+proc `[]=`*[T](deq: var Deque[T], i: Natural, val : T) {.inline.} =
   ## Change the i-th element of `deq`.
+  runnableExamples:
+    var a = initDeque[int]()
+    for i in 1 .. 5:
+      a.addLast(10*i)
+    a[0] = 99
+    a[3] = 66
+    assert $a == "[99, 20, 30, 66, 50]"
+
   xBoundsCheck(deq, i)
   deq.data[(deq.head + i) and deq.mask] = val
 
+proc `[]`*[T](deq: Deque[T], i: BackwardsIndex): T {.inline.} =
+  ## Access the backwards indexed i-th element.
+  ##
+  ## `deq[^1]` is the last element.
+  runnableExamples:
+    var a = initDeque[int]()
+    for i in 1 .. 5:
+      a.addLast(10*i)
+    assert a[^1] == 50
+    assert a[^4] == 20
+    doAssertRaises(IndexError, echo a[^9])
+
+  xBoundsCheck(deq, deq.len - int(i))
+  return deq[deq.len - int(i)]
+
+proc `[]`*[T](deq: var Deque[T], i: BackwardsIndex): var T {.inline.} =
+  ## Access the backwards indexed i-th element.
+  ##
+  ## `deq[^1]` is the last element.
+  runnableExamples:
+    var a = initDeque[int]()
+    for i in 1 .. 5:
+      a.addLast(10*i)
+    assert a[^1] == 50
+    assert a[^4] == 20
+    doAssertRaises(IndexError, echo a[^9])
+
+  xBoundsCheck(deq, deq.len - int(i))
+  return deq[deq.len - int(i)]
+
+proc `[]=`*[T](deq: var Deque[T], i: BackwardsIndex, x: T) {.inline.} =
+  ## Change the backwards indexed i-th element.
+  ##
+  ## `deq[^1]` is the last element.
+  runnableExamples:
+    var a = initDeque[int]()
+    for i in 1 .. 5:
+      a.addLast(10*i)
+    a[^1] = 99
+    a[^3] = 77
+    assert $a == "[10, 20, 77, 40, 99]"
+
+  xBoundsCheck(deq, deq.len - int(i))
+  deq[deq.len - int(i)] = x
+
 iterator items*[T](deq: Deque[T]): T =
   ## Yield every element of `deq`.
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   var a = initDeque[int]()
+  ##   for i in 1 .. 3:
+  ##     a.addLast(10*i)
+  ##
+  ##   for x in a:  # the same as: for x in items(a):
+  ##     echo x
+  ##
+  ##   # 10
+  ##   # 20
+  ##   # 30
+  ##
   var i = deq.head
   for c in 0 ..< deq.count:
     yield deq.data[i]
     i = (i + 1) and deq.mask
 
 iterator mitems*[T](deq: var Deque[T]): var T =
-  ## Yield every element of `deq`.
+  ## Yield every element of `deq`, which can be modified.
+  runnableExamples:
+    var a = initDeque[int]()
+    for i in 1 .. 5:
+      a.addLast(10*i)
+    assert $a == "[10, 20, 30, 40, 50]"
+    for x in mitems(a):
+      x = 5*x - 1
+    assert $a == "[49, 99, 149, 199, 249]"
+
   var i = deq.head
   for c in 0 ..< deq.count:
     yield deq.data[i]
@@ -109,18 +222,35 @@ iterator mitems*[T](deq: var Deque[T]): var T =
 
 iterator pairs*[T](deq: Deque[T]): tuple[key: int, val: T] =
   ## Yield every (position, value) of `deq`.
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   var a = initDeque[int]()
+  ##   for i in 1 .. 3:
+  ##     a.addLast(10*i)
+  ##
+  ##   for k, v in pairs(a):
+  ##     echo "key: ", k, ", value: ", v
+  ##
+  ##   # key: 0, value: 10
+  ##   # key: 1, value: 20
+  ##   # key: 2, value: 30
+  ##
   var i = deq.head
   for c in 0 ..< deq.count:
     yield (c, deq.data[i])
     i = (i + 1) and deq.mask
 
 proc contains*[T](deq: Deque[T], item: T): bool {.inline.} =
-  ## Return true if `item` is in `deq` or false if not found. Usually used
-  ## via the ``in`` operator. It is the equivalent of ``deq.find(item) >= 0``.
+  ## Return true if `item` is in `deq` or false if not found.
+  ##
+  ## Usually used via the ``in`` operator.
+  ## It is the equivalent of ``deq.find(item) >= 0``.
   ##
   ## .. code-block:: Nim
   ##   if x in q:
-  ##     assert q.contains x
+  ##     assert q.contains(x)
   for e in deq:
     if e == item: return true
   return false
@@ -138,6 +268,19 @@ proc expandIfNeeded[T](deq: var Deque[T]) =
 
 proc addFirst*[T](deq: var Deque[T], item: T) =
   ## Add an `item` to the beginning of the `deq`.
+  ##
+  ## See also:
+  ## * `addLast proc <#addLast,Deque[T],T>`_
+  ## * `peekFirst proc <#peekFirst,Deque[T]>`_
+  ## * `peekLast proc <#peekLast,Deque[T]>`_
+  ## * `popFirst proc <#popFirst,Deque[T]>`_
+  ## * `popLast proc <#popLast,Deque[T]>`_
+  runnableExamples:
+    var a = initDeque[int]()
+    for i in 1 .. 5:
+      a.addFirst(10*i)
+    assert $a == "[50, 40, 30, 20, 10]"
+
   expandIfNeeded(deq)
   inc deq.count
   deq.head = (deq.head - 1) and deq.mask
@@ -145,6 +288,19 @@ proc addFirst*[T](deq: var Deque[T], item: T) =
 
 proc addLast*[T](deq: var Deque[T], item: T) =
   ## Add an `item` to the end of the `deq`.
+  ##
+  ## See also:
+  ## * `addFirst proc <#addFirst,Deque[T],T>`_
+  ## * `peekFirst proc <#peekFirst,Deque[T]>`_
+  ## * `peekLast proc <#peekLast,Deque[T]>`_
+  ## * `popFirst proc <#popFirst,Deque[T]>`_
+  ## * `popLast proc <#popLast,Deque[T]>`_
+  runnableExamples:
+    var a = initDeque[int]()
+    for i in 1 .. 5:
+      a.addLast(10*i)
+    assert $a == "[10, 20, 30, 40, 50]"
+
   expandIfNeeded(deq)
   inc deq.count
   deq.data[deq.tail] = item
@@ -152,11 +308,41 @@ proc addLast*[T](deq: var Deque[T], item: T) =
 
 proc peekFirst*[T](deq: Deque[T]): T {.inline.}=
   ## Returns the first element of `deq`, but does not remove it from the deque.
+  ##
+  ## See also:
+  ## * `addFirst proc <#addFirst,Deque[T],T>`_
+  ## * `addLast proc <#addLast,Deque[T],T>`_
+  ## * `peekLast proc <#peekLast,Deque[T]>`_
+  ## * `popFirst proc <#popFirst,Deque[T]>`_
+  ## * `popLast proc <#popLast,Deque[T]>`_
+  runnableExamples:
+    var a = initDeque[int]()
+    for i in 1 .. 5:
+      a.addLast(10*i)
+    assert $a == "[10, 20, 30, 40, 50]"
+    assert a.peekFirst == 10
+    assert len(a) == 5
+
   emptyCheck(deq)
   result = deq.data[deq.head]
 
 proc peekLast*[T](deq: Deque[T]): T {.inline.} =
   ## Returns the last element of `deq`, but does not remove it from the deque.
+  ##
+  ## See also:
+  ## * `addFirst proc <#addFirst,Deque[T],T>`_
+  ## * `addLast proc <#addLast,Deque[T],T>`_
+  ## * `peekFirst proc <#peekFirst,Deque[T]>`_
+  ## * `popFirst proc <#popFirst,Deque[T]>`_
+  ## * `popLast proc <#popLast,Deque[T]>`_
+  runnableExamples:
+    var a = initDeque[int]()
+    for i in 1 .. 5:
+      a.addLast(10*i)
+    assert $a == "[10, 20, 30, 40, 50]"
+    assert a.peekLast == 50
+    assert len(a) == 5
+
   emptyCheck(deq)
   result = deq.data[(deq.tail - 1) and deq.mask]
 
@@ -165,6 +351,23 @@ template destroy(x: untyped) =
 
 proc popFirst*[T](deq: var Deque[T]): T {.inline, discardable.} =
   ## Remove and returns the first element of the `deq`.
+  ##
+  ## See also:
+  ## * `addFirst proc <#addFirst,Deque[T],T>`_
+  ## * `addLast proc <#addLast,Deque[T],T>`_
+  ## * `peekFirst proc <#peekFirst,Deque[T]>`_
+  ## * `peekLast proc <#peekLast,Deque[T]>`_
+  ## * `popLast proc <#popLast,Deque[T]>`_
+  ## * `clear proc <#clear,Deque[T]>`_
+  ## * `shrink proc <#shrink,Deque[T],int,int>`_
+  runnableExamples:
+    var a = initDeque[int]()
+    for i in 1 .. 5:
+      a.addLast(10*i)
+    assert $a == "[10, 20, 30, 40, 50]"
+    assert a.popFirst == 10
+    assert $a == "[20, 30, 40, 50]"
+
   emptyCheck(deq)
   dec deq.count
   result = deq.data[deq.head]
@@ -173,6 +376,23 @@ proc popFirst*[T](deq: var Deque[T]): T {.inline, discardable.} =
 
 proc popLast*[T](deq: var Deque[T]): T {.inline, discardable.} =
   ## Remove and returns the last element of the `deq`.
+  ##
+  ## See also:
+  ## * `addFirst proc <#addFirst,Deque[T],T>`_
+  ## * `addLast proc <#addLast,Deque[T],T>`_
+  ## * `peekFirst proc <#peekFirst,Deque[T]>`_
+  ## * `peekLast proc <#peekLast,Deque[T]>`_
+  ## * `popFirst proc <#popFirst,Deque[T]>`_
+  ## * `clear proc <#clear,Deque[T]>`_
+  ## * `shrink proc <#shrink,Deque[T],int,int>`_
+  runnableExamples:
+    var a = initDeque[int]()
+    for i in 1 .. 5:
+      a.addLast(10*i)
+    assert $a == "[10, 20, 30, 40, 50]"
+    assert a.popLast == 50
+    assert $a == "[10, 20, 30, 40]"
+
   emptyCheck(deq)
   dec deq.count
   deq.tail = (deq.tail - 1) and deq.mask
@@ -181,17 +401,39 @@ proc popLast*[T](deq: var Deque[T]): T {.inline, discardable.} =
 
 proc clear*[T](deq: var Deque[T]) {.inline.} =
   ## Resets the deque so that it is empty.
+  ##
+  ## See also:
+  ## * `clear proc <#clear,Deque[T]>`_
+  ## * `shrink proc <#shrink,Deque[T],int,int>`_
+  runnableExamples:
+    var a = initDeque[int]()
+    for i in 1 .. 5:
+      a.addFirst(10*i)
+    assert $a == "[50, 40, 30, 20, 10]"
+    clear(a)
+    assert len(a) == 0
+
   for el in mitems(deq): destroy(el)
   deq.count = 0
   deq.tail = deq.head
 
 proc shrink*[T](deq: var Deque[T], fromFirst = 0, fromLast = 0) =
   ## Remove `fromFirst` elements from the front of the deque and
-  ## `fromLast` elements from the back. If the supplied number of
-  ## elements exceeds the total number of elements in the deque,
-  ## the deque will remain empty.
+  ## `fromLast` elements from the back.
+  ##
+  ## If the supplied number of elements exceeds the total number of elements
+  ## in the deque, the deque will remain empty.
   ##
-  ## Any user defined destructors
+  ## See also:
+  ## * `clear proc <#clear,Deque[T]>`_
+  runnableExamples:
+    var a = initDeque[int]()
+    for i in 1 .. 5:
+      a.addFirst(10*i)
+    assert $a == "[50, 40, 30, 20, 10]"
+    a.shrink(fromFirst = 2, fromLast = 1)
+    assert $a == "[30, 20]"
+
   if fromFirst + fromLast > deq.count:
     clear(deq)
     return
@@ -214,6 +456,8 @@ proc `$`*[T](deq: Deque[T]): string =
     result.addQuoted(x)
   result.add("]")
 
+
+
 when isMainModule:
   var deq = initDeque[int](1)
   deq.addLast(4)
diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim
index def96b8f7..9d7950ea6 100644
--- a/lib/pure/collections/intsets.nim
+++ b/lib/pure/collections/intsets.nim
@@ -9,9 +9,12 @@
 
 ## The ``intsets`` module implements an efficient int set implemented as a
 ## `sparse bit set`:idx:.
-## **Note**: Since Nim currently does not allow the assignment operator to
-## be overloaded, ``=`` for int sets performs some rather meaningless shallow
-## copy; use ``assign`` to get a deep copy.
+
+## **Note**: Currently the assignment operator ``=`` for ``intsets``
+## performs some rather meaningless shallow copy. Since Nim currently does
+## not allow the assignment operator to be overloaded, use ``assign`` to
+## get a deep copy.
+
 
 import
   hashes, math
@@ -94,7 +97,7 @@ 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`.
   if s.elems <= s.a.len:
     for i in 0..<s.elems:
       if s.a[i] == key: return true
@@ -107,7 +110,7 @@ proc contains*(s: IntSet, key: int): bool =
       result = false
 
 iterator items*(s: IntSet): int {.inline.} =
-  ## iterates over any included element of `s`.
+  ## Iterates over any included element of `s`.
   if s.elems <= s.a.len:
     for i in 0..<s.elems:
       yield s.a[i]
@@ -135,7 +138,7 @@ proc bitincl(s: var IntSet, key: int) {.inline.} =
       `shl`(1, u and IntMask)
 
 proc incl*(s: var IntSet, key: int) =
-  ## includes an element `key` in `s`.
+  ## Includes an element `key` in `s`.
   if s.elems <= s.a.len:
     for i in 0..<s.elems:
       if s.a[i] == key: return
@@ -170,7 +173,7 @@ proc exclImpl(s: var IntSet, key: int) =
           not `shl`(1, u and IntMask)
 
 proc excl*(s: var IntSet, key: int) =
-  ## excludes `key` from the set `s`.
+  ## Excludes `key` from the set `s`.
   exclImpl(s, key)
 
 proc excl*(s: var IntSet, other: IntSet) =
@@ -178,14 +181,14 @@ proc excl*(s: var IntSet, other: IntSet) =
   for item in other: excl(s, item)
 
 proc missingOrExcl*(s: var IntSet, key: int) : bool =
-  ## returns true if `s` does not contain `key`, otherwise
+  ## Returns true if `s` does not contain `key`, otherwise
   ## `key` is removed from `s` and false is returned.
   var count = s.elems
   exclImpl(s, key)
   result = count == s.elems
 
 proc containsOrIncl*(s: var IntSet, key: int): bool =
-  ## returns true if `s` contains `key`, otherwise `key` is included in `s`
+  ## Returns true if `s` contains `key`, otherwise `key` is included in `s`
   ## and false is returned.
   if s.elems <= s.a.len:
     for i in 0..<s.elems:
@@ -206,23 +209,28 @@ proc containsOrIncl*(s: var IntSet, key: int): bool =
       result = false
 
 proc initIntSet*: IntSet =
-  ## creates a new int set that is empty.
-
-  #newSeq(result.data, InitIntSetSize)
-  #result.max = InitIntSetSize-1
-  when defined(nimNoNilSeqs):
-    result.data = @[]
-  else:
-    result.data = nil
-  result.max = 0
-  result.counter = 0
-  result.head = nil
-  result.elems = 0
+  ## Returns an empty IntSet. Example:
+  ##
+  ## .. code-block ::
+  ##   var a = initIntSet()
+  ##   a.incl(2)
+
+  # newSeq(result.data, InitIntSetSize)
+  # result.max = InitIntSetSize-1
+  result = IntSet(
+    elems: 0,
+    counter: 0,
+    max: 0,
+    head: nil,
+    data: when defined(nimNoNilSeqs): @[] else: nil)
+  #  a: array[0..33, int] # profiling shows that 34 elements are enough
 
 proc clear*(result: var IntSet) =
-  #setLen(result.data, InitIntSetSize)
-  #for i in 0..InitIntSetSize-1: result.data[i] = nil
-  #result.max = InitIntSetSize-1
+  ## Clears the IntSet back to an empty state.
+
+  # setLen(result.data, InitIntSetSize)
+  # for i in 0..InitIntSetSize-1: result.data[i] = nil
+  # result.max = InitIntSetSize-1
   when defined(nimNoNilSeqs):
     result.data = @[]
   else:
@@ -304,7 +312,7 @@ proc `-`*(s1, s2: IntSet): IntSet {.inline.} =
   result = difference(s1, s2)
 
 proc disjoint*(s1, s2: IntSet): bool =
-  ## Returns true iff the sets `s1` and `s2` have no items in common.
+  ## Returns true if the sets `s1` and `s2` have no items in common.
   for item in s1:
     if contains(s2, item):
       return false
@@ -320,7 +328,7 @@ proc len*(s: IntSet): int {.inline.} =
       inc(result)
 
 proc card*(s: IntSet): int {.inline.} =
-  ## alias for `len() <#len>` _.
+  ## Alias for `len() <#len>` _.
   result = s.len()
 
 proc `<=`*(s1, s2: IntSet): bool =
@@ -349,12 +357,6 @@ proc `$`*(s: IntSet): string =
   ## The `$` operator for int sets.
   dollarImpl()
 
-proc empty*(s: IntSet): bool {.inline, deprecated.} =
-  ## returns true if `s` is empty. This is safe to call even before
-  ## the set has been initialized with `initIntSet`. Note this never
-  ## worked reliably and so is deprecated.
-  result = s.counter == 0
-
 when isMainModule:
   import sequtils, algorithm
 
diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim
index 15ce5d074..182eb8442 100644
--- a/lib/pure/collections/lists.nim
+++ b/lib/pure/collections/lists.nim
@@ -7,34 +7,112 @@
 #    distribution, for details about the copyright.
 #
 
-## Implementation of singly and doubly linked lists. Because it makes no sense
-## to do so, the 'next' and 'prev' pointers are not hidden from you and can
-## be manipulated directly for efficiency.
+## Implementation of:
+## * `singly linked lists <#SinglyLinkedList>`_
+## * `doubly linked lists <#DoublyLinkedList>`_
+## * `singly linked rings <#SinglyLinkedRing>`_ (circular lists)
+## * `doubly linked rings <#DoublyLinkedRing>`_ (circular lists)
+##
+##
+## Basic Usage
+## ===========
+##
+## Because it makes no sense to do otherwise, the `next` and `prev` pointers
+## are not hidden from you and can be manipulated directly for efficiency.
+##
+## Lists
+## -----
+##
+## .. code-block::
+##   import lists
+##
+##   var
+##     l = initDoublyLinkedList[int]()
+##     a = newDoublyLinkedNode[int](3)
+##     b = newDoublyLinkedNode[int](7)
+##     c = newDoublyLinkedNode[int](9)
+##
+##   l.append(a)
+##   l.append(b)
+##   l.prepend(c)
+##
+##   assert a.next == b
+##   assert a.prev == c
+##   assert c.next == a
+##   assert c.next.next == b
+##   assert c.prev == nil
+##   assert b.next == nil
+##
+##
+## Rings
+## -----
+##
+## .. code-block::
+##   import lists
+##
+##   var
+##     l = initSinglyLinkedRing[int]()
+##     a = newSinglyLinkedNode[int](3)
+##     b = newSinglyLinkedNode[int](7)
+##     c = newSinglyLinkedNode[int](9)
+##
+##   l.append(a)
+##   l.append(b)
+##   l.prepend(c)
+##
+##   assert c.next == a
+##   assert a.next == b
+##   assert c.next.next == b
+##   assert b.next == c
+##   assert c.next.next.next == c
+##
+## See also
+## ========
+##
+## * `deques module <#deques.html>`_ for double-ended queues
+## * `sharedlist module <#sharedlist.html>`_ for shared singly-linked lists
+
 
 when not defined(nimhygiene):
   {.pragma: dirty.}
 
 type
-  DoublyLinkedNodeObj*[T] = object ## a node a doubly linked list consists of
+  DoublyLinkedNodeObj*[T] = object ## A node a doubly linked list consists of.
+    ##
+    ## It consists of a `value` field, and pointers to `next` and `prev`.
     next*, prev*: ref DoublyLinkedNodeObj[T]
     value*: T
   DoublyLinkedNode*[T] = ref DoublyLinkedNodeObj[T]
 
-  SinglyLinkedNodeObj*[T] = object ## a node a singly linked list consists of
+  SinglyLinkedNodeObj*[T] = object ## A node a singly linked list consists of.
+    ##
+    ## It consists of a `value` field, and a pointer to `next`.
     next*: ref SinglyLinkedNodeObj[T]
     value*: T
   SinglyLinkedNode*[T] = ref SinglyLinkedNodeObj[T]
 
-  SinglyLinkedList*[T] = object ## a singly linked list
+  SinglyLinkedList*[T] = object ## A singly linked list.
+    ##
+    ## Use `initSinglyLinkedList proc <#initSinglyLinkedList,>`_ to create
+    ## a new empty list.
     head*, tail*: SinglyLinkedNode[T]
 
-  DoublyLinkedList*[T] = object ## a doubly linked list
+  DoublyLinkedList*[T] = object ## A doubly linked list.
+    ##
+    ## Use `initDoublyLinkedList proc <#initDoublyLinkedList,>`_ to create
+    ## a new empty list.
     head*, tail*: DoublyLinkedNode[T]
 
-  SinglyLinkedRing*[T] = object ## a singly linked ring
+  SinglyLinkedRing*[T] = object ## A singly linked ring.
+    ##
+    ## Use `initSinglyLinkedRing proc <#initSinglyLinkedRing,>`_ to create
+    ## a new empty ring.
     head*, tail*: SinglyLinkedNode[T]
 
-  DoublyLinkedRing*[T] = object ## a doubly linked ring
+  DoublyLinkedRing*[T] = object ## A doubly linked ring.
+    ##
+    ## Use `initDoublyLinkedRing proc <#initDoublyLinkedRing,>`_ to create
+    ## a new empty ring.
     head*: DoublyLinkedNode[T]
 
   SomeLinkedList*[T] = SinglyLinkedList[T] | DoublyLinkedList[T]
@@ -46,28 +124,44 @@ type
   SomeLinkedNode*[T] = SinglyLinkedNode[T] | DoublyLinkedNode[T]
 
 proc initSinglyLinkedList*[T](): SinglyLinkedList[T] =
-  ## creates a new singly linked list that is empty.
+  ## Creates a new singly linked list that is empty.
+  runnableExamples:
+    var a = initSinglyLinkedList[int]()
   discard
 
 proc initDoublyLinkedList*[T](): DoublyLinkedList[T] =
-  ## creates a new doubly linked list that is empty.
+  ## Creates a new doubly linked list that is empty.
+  runnableExamples:
+    var a = initDoublyLinkedList[int]()
   discard
 
 proc initSinglyLinkedRing*[T](): SinglyLinkedRing[T] =
-  ## creates a new singly linked ring that is empty.
+  ## Creates a new singly linked ring that is empty.
+  runnableExamples:
+    var a = initSinglyLinkedRing[int]()
   discard
 
 proc initDoublyLinkedRing*[T](): DoublyLinkedRing[T] =
-  ## creates a new doubly linked ring that is empty.
+  ## Creates a new doubly linked ring that is empty.
+  runnableExamples:
+    var a = initDoublyLinkedRing[int]()
   discard
 
 proc newDoublyLinkedNode*[T](value: T): DoublyLinkedNode[T] =
-  ## creates a new doubly linked node with the given `value`.
+  ## Creates a new doubly linked node with the given `value`.
+  runnableExamples:
+    var n = newDoublyLinkedNode[int](5)
+    assert n.value == 5
+
   new(result)
   result.value = value
 
 proc newSinglyLinkedNode*[T](value: T): SinglyLinkedNode[T] =
-  ## creates a new singly linked node with the given `value`.
+  ## Creates a new singly linked node with the given `value`.
+  runnableExamples:
+    var n = newSinglyLinkedNode[int](5)
+    assert n.value == 5
+
   new(result)
   result.value = value
 
@@ -86,24 +180,100 @@ template itemsRingImpl() {.dirty.} =
       if it == L.head: break
 
 iterator items*[T](L: SomeLinkedList[T]): T =
-  ## yields every value of `L`.
+  ## Yields every value of `L`.
+  ##
+  ## See also:
+  ## * `mitems iterator <#mitems.i,SomeLinkedList[T]>`_
+  ## * `nodes iterator <#nodes.i,SomeLinkedList[T]>`_
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   var a = initSinglyLinkedList[int]()
+  ##   for i in 1 .. 3:
+  ##     a.append(10*i)
+  ##
+  ##   for x in a:  # the same as: for x in items(a):
+  ##     echo x
+  ##
+  ##   # 10
+  ##   # 20
+  ##   # 30
   itemsListImpl()
 
 iterator items*[T](L: SomeLinkedRing[T]): T =
-  ## yields every value of `L`.
+  ## Yields every value of `L`.
+  ##
+  ## See also:
+  ## * `mitems iterator <#mitems.i,SomeLinkedRing[T]>`_
+  ## * `nodes iterator <#nodes.i,SomeLinkedRing[T]>`_
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   var a = initSinglyLinkedRing[int]()
+  ##   for i in 1 .. 3:
+  ##     a.append(10*i)
+  ##
+  ##   for x in a:  # the same as: for x in items(a):
+  ##     echo x
+  ##
+  ##   # 10
+  ##   # 20
+  ##   # 30
   itemsRingImpl()
 
 iterator mitems*[T](L: var SomeLinkedList[T]): var T =
-  ## yields every value of `L` so that you can modify it.
+  ## Yields every value of `L` so that you can modify it.
+  ##
+  ## See also:
+  ## * `items iterator <#items.i,SomeLinkedList[T]>`_
+  ## * `nodes iterator <#nodes.i,SomeLinkedList[T]>`_
+  runnableExamples:
+    var a = initSinglyLinkedList[int]()
+    for i in 1 .. 5:
+      a.append(10*i)
+    assert $a == "[10, 20, 30, 40, 50]"
+    for x in mitems(a):
+      x = 5*x - 1
+    assert $a == "[49, 99, 149, 199, 249]"
   itemsListImpl()
 
 iterator mitems*[T](L: var SomeLinkedRing[T]): var T =
-  ## yields every value of `L` so that you can modify it.
+  ## Yields every value of `L` so that you can modify it.
+  ##
+  ## See also:
+  ## * `items iterator <#items.i,SomeLinkedRing[T]>`_
+  ## * `nodes iterator <#nodes.i,SomeLinkedRing[T]>`_
+  runnableExamples:
+    var a = initSinglyLinkedRing[int]()
+    for i in 1 .. 5:
+      a.append(10*i)
+    assert $a == "[10, 20, 30, 40, 50]"
+    for x in mitems(a):
+      x = 5*x - 1
+    assert $a == "[49, 99, 149, 199, 249]"
   itemsRingImpl()
 
 iterator nodes*[T](L: SomeLinkedList[T]): SomeLinkedNode[T] =
-  ## iterates over every node of `x`. Removing the current node from the
+  ## Iterates over every node of `x`. Removing the current node from the
   ## list during traversal is supported.
+  ##
+  ## See also:
+  ## * `items iterator <#items.i,SomeLinkedList[T]>`_
+  ## * `mitems iterator <#mitems.i,SomeLinkedList[T]>`_
+  runnableExamples:
+    var a = initDoublyLinkedList[int]()
+    for i in 1 .. 5:
+      a.append(10*i)
+    assert $a == "[10, 20, 30, 40, 50]"
+    for x in nodes(a):
+      if x.value == 30:
+        a.remove(x)
+      else:
+        x.value = 5*x.value - 1
+    assert $a == "[49, 99, 199, 249]"
+
   var it = L.head
   while it != nil:
     var nxt = it.next
@@ -111,8 +281,24 @@ iterator nodes*[T](L: SomeLinkedList[T]): SomeLinkedNode[T] =
     it = nxt
 
 iterator nodes*[T](L: SomeLinkedRing[T]): SomeLinkedNode[T] =
-  ## iterates over every node of `x`. Removing the current node from the
+  ## Iterates over every node of `x`. Removing the current node from the
   ## list during traversal is supported.
+  ##
+  ## See also:
+  ## * `items iterator <#items.i,SomeLinkedRing[T]>`_
+  ## * `mitems iterator <#mitems.i,SomeLinkedRing[T]>`_
+  runnableExamples:
+    var a = initDoublyLinkedRing[int]()
+    for i in 1 .. 5:
+      a.append(10*i)
+    assert $a == "[10, 20, 30, 40, 50]"
+    for x in nodes(a):
+      if x.value == 30:
+        a.remove(x)
+      else:
+        x.value = 5*x.value - 1
+    assert $a == "[49, 99, 199, 249]"
+
   var it = L.head
   if it != nil:
     while true:
@@ -122,7 +308,7 @@ iterator nodes*[T](L: SomeLinkedRing[T]): SomeLinkedNode[T] =
       if it == L.head: break
 
 proc `$`*[T](L: SomeLinkedCollection[T]): string =
-  ## turns a list into its string representation.
+  ## Turns a list into its string representation for logging and printing.
   result = "["
   for x in nodes(L):
     if result.len > 1: result.add(", ")
@@ -130,19 +316,54 @@ proc `$`*[T](L: SomeLinkedCollection[T]): string =
   result.add("]")
 
 proc find*[T](L: SomeLinkedCollection[T], value: T): SomeLinkedNode[T] =
-  ## searches in the list for a value. Returns nil if the value does not
+  ## Searches in the list for a value. Returns `nil` if the value does not
   ## exist.
+  ##
+  ## See also:
+  ## * `contains proc <#contains,SomeLinkedCollection[T],T>`_
+  runnableExamples:
+    var a = initSinglyLinkedList[int]()
+    a.append(9)
+    a.append(8)
+    assert a.find(9).value == 9
+    assert a.find(1) == nil
+
   for x in nodes(L):
     if x.value == value: return x
 
 proc contains*[T](L: SomeLinkedCollection[T], value: T): bool {.inline.} =
-  ## searches in the list for a value. Returns false if the value does not
-  ## exist, true otherwise.
+  ## Searches in the list for a value. Returns `false` if the value does not
+  ## exist, `true` otherwise.
+  ##
+  ## See also:
+  ## * `find proc <#find,SomeLinkedCollection[T],T>`_
+  runnableExamples:
+    var a = initSinglyLinkedList[int]()
+    a.append(9)
+    a.append(8)
+    assert a.contains(9)
+    assert 8 in a
+    assert(not a.contains(1))
+    assert 2 notin a
+
   result = find(L, value) != nil
 
 proc append*[T](L: var SinglyLinkedList[T],
                 n: SinglyLinkedNode[T]) {.inline.} =
-  ## appends a node `n` to `L`. Efficiency: O(1).
+  ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1).
+  ##
+  ## See also:
+  ## * `append proc <#append,SinglyLinkedList[T],T>`_ for appending a value
+  ## * `prepend proc <#prepend,SinglyLinkedList[T],SinglyLinkedNode[T]>`_
+  ##   for prepending a node
+  ## * `prepend proc <#prepend,SinglyLinkedList[T],T>`_ for prepending a value
+  runnableExamples:
+    var
+      a = initSinglyLinkedList[int]()
+      n = newSinglyLinkedNode[int](9)
+    a.append(n)
+    assert a.contains(9)
+
   n.next = nil
   if L.tail != nil:
     assert(L.tail.next == nil)
@@ -151,22 +372,75 @@ proc append*[T](L: var SinglyLinkedList[T],
   if L.head == nil: L.head = n
 
 proc append*[T](L: var SinglyLinkedList[T], value: T) {.inline.} =
-  ## appends a value to `L`. Efficiency: O(1).
+  ## Appends (adds to the end) a value to `L`. Efficiency: O(1).
+  ##
+  ## See also:
+  ## * `append proc <#append,SinglyLinkedList[T],T>`_ for appending a value
+  ## * `prepend proc <#prepend,SinglyLinkedList[T],SinglyLinkedNode[T]>`_
+  ##   for prepending a node
+  ## * `prepend proc <#prepend,SinglyLinkedList[T],T>`_ for prepending a value
+  runnableExamples:
+    var a = initSinglyLinkedList[int]()
+    a.append(9)
+    a.append(8)
+    assert a.contains(9)
   append(L, newSinglyLinkedNode(value))
 
 proc prepend*[T](L: var SinglyLinkedList[T],
                  n: SinglyLinkedNode[T]) {.inline.} =
-  ## prepends a node to `L`. Efficiency: O(1).
+  ## Prepends (adds to the beginning) a node to `L`. Efficiency: O(1).
+  ##
+  ## See also:
+  ## * `append proc <#append,SinglyLinkedList[T],SinglyLinkedNode[T]>`_
+  ##   for appending a node
+  ## * `append proc <#append,SinglyLinkedList[T],T>`_ for appending a value
+  ## * `prepend proc <#prepend,SinglyLinkedList[T],T>`_ for prepending a value
+  runnableExamples:
+    var
+      a = initSinglyLinkedList[int]()
+      n = newSinglyLinkedNode[int](9)
+    a.prepend(n)
+    assert a.contains(9)
+
   n.next = L.head
   L.head = n
   if L.tail == nil: L.tail = n
 
 proc prepend*[T](L: var SinglyLinkedList[T], value: T) {.inline.} =
-  ## prepends a node to `L`. Efficiency: O(1).
+  ## Prepends (adds to the beginning) a node to `L`. Efficiency: O(1).
+  ##
+  ## See also:
+  ## * `append proc <#append,SinglyLinkedList[T],SinglyLinkedNode[T]>`_
+  ##   for appending a node
+  ## * `append proc <#append,SinglyLinkedList[T],T>`_ for appending a value
+  ## * `prepend proc <#prepend,SinglyLinkedList[T],SinglyLinkedNode[T]>`_
+  ##   for prepending a node
+  runnableExamples:
+    var a = initSinglyLinkedList[int]()
+    a.prepend(9)
+    a.prepend(8)
+    assert a.contains(9)
   prepend(L, newSinglyLinkedNode(value))
 
+
+
 proc append*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
-  ## appends a node `n` to `L`. Efficiency: O(1).
+  ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1).
+  ##
+  ## See also:
+  ## * `append proc <#append,DoublyLinkedList[T],T>`_ for appending a value
+  ## * `prepend proc <#prepend,DoublyLinkedList[T],DoublyLinkedNode[T]>`_
+  ##   for prepending a node
+  ## * `prepend proc <#prepend,DoublyLinkedList[T],T>`_ for prepending a value
+  ## * `remove proc <#remove,DoublyLinkedList[T],DoublyLinkedNode[T]>`_
+  ##   for removing a node
+  runnableExamples:
+    var
+      a = initDoublyLinkedList[int]()
+      n = newDoublyLinkedNode[int](9)
+    a.append(n)
+    assert a.contains(9)
+
   n.next = nil
   n.prev = L.tail
   if L.tail != nil:
@@ -176,11 +450,40 @@ proc append*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
   if L.head == nil: L.head = n
 
 proc append*[T](L: var DoublyLinkedList[T], value: T) =
-  ## appends a value to `L`. Efficiency: O(1).
+  ## Appends (adds to the end) a value to `L`. Efficiency: O(1).
+  ##
+  ## See also:
+  ## * `append proc <#append,DoublyLinkedList[T],DoublyLinkedNode[T]>`_
+  ##   for appending a node
+  ## * `prepend proc <#prepend,DoublyLinkedList[T],DoublyLinkedNode[T]>`_
+  ##   for prepending a node
+  ## * `prepend proc <#prepend,DoublyLinkedList[T],T>`_ for prepending a value
+  ## * `remove proc <#remove,DoublyLinkedList[T],DoublyLinkedNode[T]>`_
+  ##   for removing a node
+  runnableExamples:
+    var a = initDoublyLinkedList[int]()
+    a.append(9)
+    a.append(8)
+    assert a.contains(9)
   append(L, newDoublyLinkedNode(value))
 
 proc prepend*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
-  ## prepends a node `n` to `L`. Efficiency: O(1).
+  ## Prepends (adds to the beginning) a node `n` to `L`. Efficiency: O(1).
+  ##
+  ## See also:
+  ## * `append proc <#append,DoublyLinkedList[T],DoublyLinkedNode[T]>`_
+  ##   for appending a node
+  ## * `append proc <#append,DoublyLinkedList[T],T>`_ for appending a value
+  ## * `prepend proc <#prepend,DoublyLinkedList[T],T>`_ for prepending a value
+  ## * `remove proc <#remove,DoublyLinkedList[T],DoublyLinkedNode[T]>`_
+  ##   for removing a node
+  runnableExamples:
+    var
+      a = initDoublyLinkedList[int]()
+      n = newDoublyLinkedNode[int](9)
+    a.prepend(n)
+    assert a.contains(9)
+
   n.prev = nil
   n.next = L.head
   if L.head != nil:
@@ -190,18 +493,56 @@ proc prepend*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
   if L.tail == nil: L.tail = n
 
 proc prepend*[T](L: var DoublyLinkedList[T], value: T) =
-  ## prepends a value to `L`. Efficiency: O(1).
+  ## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1).
+  ##
+  ## See also:
+  ## * `append proc <#append,DoublyLinkedList[T],DoublyLinkedNode[T]>`_
+  ##   for appending a node
+  ## * `append proc <#append,DoublyLinkedList[T],T>`_ for appending a value
+  ## * `prepend proc <#prepend,DoublyLinkedList[T],DoublyLinkedNode[T]>`_
+  ##   for prepending a node
+  ## * `remove proc <#remove,DoublyLinkedList[T],DoublyLinkedNode[T]>`_
+  ##   for removing a node
+  runnableExamples:
+    var a = initDoublyLinkedList[int]()
+    a.prepend(9)
+    a.prepend(8)
+    assert a.contains(9)
   prepend(L, newDoublyLinkedNode(value))
 
 proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
-  ## removes `n` from `L`. Efficiency: O(1).
+  ## Removes a node `n` from `L`. Efficiency: O(1).
+  runnableExamples:
+    var
+      a = initDoublyLinkedList[int]()
+      n = newDoublyLinkedNode[int](5)
+    a.append(n)
+    assert 5 in a
+    a.remove(n)
+    assert 5 notin a
+
   if n == L.tail: L.tail = n.prev
   if n == L.head: L.head = n.next
   if n.next != nil: n.next.prev = n.prev
   if n.prev != nil: n.prev.next = n.next
 
+
+
 proc append*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) =
-  ## appends a node `n` to `L`. Efficiency: O(1).
+  ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1).
+  ##
+  ## See also:
+  ## * `append proc <#append,SinglyLinkedRing[T],T>`_ for appending a value
+  ## * `prepend proc <#prepend,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_
+  ##   for prepending a node
+  ## * `prepend proc <#prepend,SinglyLinkedRing[T],T>`_ for prepending a value
+  runnableExamples:
+    var
+      a = initSinglyLinkedRing[int]()
+      n = newSinglyLinkedNode[int](9)
+    a.append(n)
+    assert a.contains(9)
+
   if L.head != nil:
     n.next = L.head
     assert(L.tail != nil)
@@ -213,11 +554,36 @@ proc append*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) =
     L.tail = n
 
 proc append*[T](L: var SinglyLinkedRing[T], value: T) =
-  ## appends a value to `L`. Efficiency: O(1).
+  ## Appends (adds to the end) a value to `L`. Efficiency: O(1).
+  ##
+  ## See also:
+  ## * `append proc <#append,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_
+  ##   for appending a node
+  ## * `prepend proc <#prepend,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_
+  ##   for prepending a node
+  ## * `prepend proc <#prepend,SinglyLinkedRing[T],T>`_ for prepending a value
+  runnableExamples:
+    var a = initSinglyLinkedRing[int]()
+    a.append(9)
+    a.append(8)
+    assert a.contains(9)
   append(L, newSinglyLinkedNode(value))
 
 proc prepend*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) =
-  ## prepends a node `n` to `L`. Efficiency: O(1).
+  ## Prepends (adds to the beginning) a node `n` to `L`. Efficiency: O(1).
+  ##
+  ## See also:
+  ## * `append proc <#append,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_
+  ##   for appending a node
+  ## * `append proc <#append,SinglyLinkedRing[T],T>`_ for appending a value
+  ## * `prepend proc <#prepend,SinglyLinkedRing[T],T>`_ for prepending a value
+  runnableExamples:
+    var
+      a = initSinglyLinkedRing[int]()
+      n = newSinglyLinkedNode[int](9)
+    a.prepend(n)
+    assert a.contains(9)
+
   if L.head != nil:
     n.next = L.head
     assert(L.tail != nil)
@@ -228,11 +594,40 @@ proc prepend*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) =
   L.head = n
 
 proc prepend*[T](L: var SinglyLinkedRing[T], value: T) =
-  ## prepends a value to `L`. Efficiency: O(1).
+  ## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1).
+  ##
+  ## See also:
+  ## * `append proc <#append,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_
+  ##   for appending a node
+  ## * `append proc <#append,SinglyLinkedRing[T],T>`_ for appending a value
+  ## * `prepend proc <#prepend,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_
+  ##   for prepending a node
+  runnableExamples:
+    var a = initSinglyLinkedRing[int]()
+    a.prepend(9)
+    a.prepend(8)
+    assert a.contains(9)
   prepend(L, newSinglyLinkedNode(value))
 
+
+
 proc append*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) =
-  ## appends a node `n` to `L`. Efficiency: O(1).
+  ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1).
+  ##
+  ## See also:
+  ## * `append proc <#append,DoublyLinkedRing[T],T>`_ for appending a value
+  ## * `prepend proc <#prepend,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_
+  ##   for prepending a node
+  ## * `prepend proc <#prepend,DoublyLinkedRing[T],T>`_ for prepending a value
+  ## * `remove proc <#remove,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_
+  ##   for removing a node
+  runnableExamples:
+    var
+      a = initDoublyLinkedRing[int]()
+      n = newDoublyLinkedNode[int](9)
+    a.append(n)
+    assert a.contains(9)
+
   if L.head != nil:
     n.next = L.head
     n.prev = L.head.prev
@@ -244,11 +639,40 @@ proc append*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) =
     L.head = n
 
 proc append*[T](L: var DoublyLinkedRing[T], value: T) =
-  ## appends a value to `L`. Efficiency: O(1).
+  ## Appends (adds to the end) a value to `L`. Efficiency: O(1).
+  ##
+  ## See also:
+  ## * `append proc <#append,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_
+  ##   for appending a node
+  ## * `prepend proc <#prepend,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_
+  ##   for prepending a node
+  ## * `prepend proc <#prepend,DoublyLinkedRing[T],T>`_ for prepending a value
+  ## * `remove proc <#remove,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_
+  ##   for removing a node
+  runnableExamples:
+    var a = initDoublyLinkedRing[int]()
+    a.append(9)
+    a.append(8)
+    assert a.contains(9)
   append(L, newDoublyLinkedNode(value))
 
 proc prepend*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) =
-  ## prepends a node `n` to `L`. Efficiency: O(1).
+  ## Prepends (adds to the beginning) a node `n` to `L`. Efficiency: O(1).
+  ##
+  ## See also:
+  ## * `append proc <#append,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_
+  ##   for appending a node
+  ## * `append proc <#append,DoublyLinkedRing[T],T>`_ for appending a value
+  ## * `prepend proc <#prepend,DoublyLinkedRing[T],T>`_ for prepending a value
+  ## * `remove proc <#remove,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_
+  ##   for removing a node
+  runnableExamples:
+    var
+      a = initDoublyLinkedRing[int]()
+      n = newDoublyLinkedNode[int](9)
+    a.prepend(n)
+    assert a.contains(9)
+
   if L.head != nil:
     n.next = L.head
     n.prev = L.head.prev
@@ -260,11 +684,34 @@ proc prepend*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) =
   L.head = n
 
 proc prepend*[T](L: var DoublyLinkedRing[T], value: T) =
-  ## prepends a value to `L`. Efficiency: O(1).
+  ## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1).
+  ##
+  ## See also:
+  ## * `append proc <#append,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_
+  ##   for appending a node
+  ## * `append proc <#append,DoublyLinkedRing[T],T>`_ for appending a value
+  ## * `prepend proc <#prepend,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_
+  ##   for prepending a node
+  ## * `remove proc <#remove,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_
+  ##   for removing a node
+  runnableExamples:
+    var a = initDoublyLinkedRing[int]()
+    a.prepend(9)
+    a.prepend(8)
+    assert a.contains(9)
   prepend(L, newDoublyLinkedNode(value))
 
 proc remove*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) =
-  ## removes `n` from `L`. Efficiency: O(1).
+  ## Removes `n` from `L`. Efficiency: O(1).
+  runnableExamples:
+    var
+      a = initDoublyLinkedRing[int]()
+      n = newDoublyLinkedNode[int](5)
+    a.append(n)
+    assert 5 in a
+    a.remove(n)
+    assert 5 notin a
+
   n.next.prev = n.prev
   n.prev.next = n.next
   if n == L.head:
diff --git a/lib/pure/collections/queues.nim b/lib/pure/collections/queues.nim
deleted file mode 100644
index 9a1d169fb..000000000
--- a/lib/pure/collections/queues.nim
+++ /dev/null
@@ -1,257 +0,0 @@
-#
-#
-#            Nim's Runtime Library
-#        (c) Copyright 2012 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## Implementation of a `queue`:idx:. The underlying implementation uses a ``seq``.
-##
-## None of the procs that get an individual value from the queue can be used
-## on an empty queue.
-## If compiled with `boundChecks` option, those procs will raise an `IndexError`
-## on such access. This should not be relied upon, as `-d:release` will
-## disable those checks and may return garbage or crash the program.
-##
-## As such, a check to see if the queue is empty is needed before any
-## access, unless your program logic guarantees it indirectly.
-##
-## .. code-block:: Nim
-##   proc foo(a, b: Positive) =  # assume random positive values for `a` and `b`
-##     var q = initQueue[int]()  # initializes the object
-##     for i in 1 ..< a: q.add i  # populates the queue
-##
-##     if b < q.len:  # checking before indexed access
-##       echo "The element at index position ", b, " is ", q[b]
-##
-##     # The following two lines don't need any checking on access due to the
-##     # logic of the program, but that would not be the case if `a` could be 0.
-##     assert q.front == 1
-##     assert q.back == a
-##
-##     while q.len > 0:  # checking if the queue is empty
-##       echo q.pop()
-##
-## Note: For inter thread communication use
-## a `Channel <channels.html>`_ instead.
-
-import math
-
-{.warning: "`queues` module is deprecated - use `deques` instead".}
-
-type
-  Queue* {.deprecated.} [T] = object ## A queue.
-    data: seq[T]
-    rd, wr, count, mask: int
-
-proc initQueue*[T](initialSize: int = 4): Queue[T] =
-  ## Create a new queue.
-  ## Optionally, the initial capacity can be reserved via `initialSize` as a
-  ## performance optimization. The length of a newly created queue will still
-  ## be 0.
-  ##
-  ## `initialSize` needs to be a power of two. If you need to accept runtime
-  ## values for this you could use the ``nextPowerOfTwo`` proc from the
-  ## `math <math.html>`_ module.
-  assert isPowerOfTwo(initialSize)
-  result.mask = initialSize-1
-  newSeq(result.data, initialSize)
-
-proc len*[T](q: Queue[T]): int {.inline.}=
-  ## Return the number of elements of `q`.
-  result = q.count
-
-template emptyCheck(q) =
-  # Bounds check for the regular queue access.
-  when compileOption("boundChecks"):
-    if unlikely(q.count < 1):
-      raise newException(IndexError, "Empty queue.")
-
-template xBoundsCheck(q, i) =
-  # Bounds check for the array like accesses.
-  when compileOption("boundChecks"):  # d:release should disable this.
-    if unlikely(i >= q.count):  # x < q.low is taken care by the Natural parameter
-      raise newException(IndexError,
-                         "Out of bounds: " & $i & " > " & $(q.count - 1))
-
-proc front*[T](q: Queue[T]): T {.inline.}=
-  ## Return the oldest element of `q`. Equivalent to `q.pop()` but does not
-  ## remove it from the queue.
-  emptyCheck(q)
-  result = q.data[q.rd]
-
-proc back*[T](q: Queue[T]): T {.inline.} =
-  ## Return the newest element of `q` but does not remove it from the queue.
-  emptyCheck(q)
-  result = q.data[q.wr - 1 and q.mask]
-
-proc `[]`*[T](q: Queue[T], i: Natural) : T {.inline.} =
-  ## Access the i-th element of `q` by order of insertion.
-  ## q[0] is the oldest (the next one q.pop() will extract),
-  ## q[^1] is the newest (last one added to the queue).
-  xBoundsCheck(q, i)
-  return q.data[q.rd + i and q.mask]
-
-proc `[]`*[T](q: var Queue[T], i: Natural): var T {.inline.} =
-  ## Access the i-th element of `q` and returns a mutable
-  ## reference to it.
-  xBoundsCheck(q, i)
-  return q.data[q.rd + i and q.mask]
-
-proc `[]=`* [T] (q: var Queue[T], i: Natural, val : T) {.inline.} =
-  ## Change the i-th element of `q`.
-  xBoundsCheck(q, i)
-  q.data[q.rd + i and q.mask] = val
-
-iterator items*[T](q: Queue[T]): T =
-  ## Yield every element of `q`.
-  var i = q.rd
-  for c in 0 ..< q.count:
-    yield q.data[i]
-    i = (i + 1) and q.mask
-
-iterator mitems*[T](q: var Queue[T]): var T =
-  ## Yield every element of `q`.
-  var i = q.rd
-  for c in 0 ..< q.count:
-    yield q.data[i]
-    i = (i + 1) and q.mask
-
-iterator pairs*[T](q: Queue[T]): tuple[key: int, val: T] =
-  ## Yield every (position, value) of `q`.
-  var i = q.rd
-  for c in 0 ..< q.count:
-    yield (c, q.data[i])
-    i = (i + 1) and q.mask
-
-proc contains*[T](q: Queue[T], item: T): bool {.inline.} =
-  ## Return true if `item` is in `q` or false if not found. Usually used
-  ## via the ``in`` operator. It is the equivalent of ``q.find(item) >= 0``.
-  ##
-  ## .. code-block:: Nim
-  ##   if x in q:
-  ##     assert q.contains x
-  for e in q:
-    if e == item: return true
-  return false
-
-proc add*[T](q: var Queue[T], item: T) =
-  ## Add an `item` to the end of the queue `q`.
-  var cap = q.mask+1
-  if unlikely(q.count >= cap):
-    var n = newSeq[T](cap*2)
-    for i, x in pairs(q):  # don't use copyMem because the GC and because it's slower.
-      shallowCopy(n[i], x)
-    shallowCopy(q.data, n)
-    q.mask = cap*2 - 1
-    q.wr = q.count
-    q.rd = 0
-  inc q.count
-  q.data[q.wr] = item
-  q.wr = (q.wr + 1) and q.mask
-
-template default[T](t: typedesc[T]): T =
-  var v: T
-  v
-
-proc pop*[T](q: var Queue[T]): T {.inline, discardable.} =
-  ## Remove and returns the first (oldest) element of the queue `q`.
-  emptyCheck(q)
-  dec q.count
-  result = q.data[q.rd]
-  q.data[q.rd] = default(type(result))
-  q.rd = (q.rd + 1) and q.mask
-
-proc enqueue*[T](q: var Queue[T], item: T) =
-  ## Alias for the ``add`` operation.
-  q.add(item)
-
-proc dequeue*[T](q: var Queue[T]): T =
-  ## Alias for the ``pop`` operation.
-  q.pop()
-
-proc `$`*[T](q: Queue[T]): string =
-  ## Turn a queue into its string representation.
-  result = "["
-  for x in items(q):  # Don't remove the items here for reasons that don't fit in this margin.
-    if result.len > 1: result.add(", ")
-    result.add($x)
-  result.add("]")
-
-when isMainModule:
-  var q = initQueue[int](1)
-  q.add(123)
-  q.add(9)
-  q.enqueue(4)
-  var first = q.dequeue()
-  q.add(56)
-  q.add(6)
-  var second = q.pop()
-  q.add(789)
-
-  assert first == 123
-  assert second == 9
-  assert($q == "[4, 56, 6, 789]")
-
-  assert q[0] == q.front and q.front == 4
-  q[0] = 42
-  q[q.len - 1] = 7
-
-  assert 6 in q and 789 notin q
-  assert q.find(6) >= 0
-  assert q.find(789) < 0
-
-  for i in -2 .. 10:
-    if i in q:
-      assert q.contains(i) and q.find(i) >= 0
-    else:
-      assert(not q.contains(i) and q.find(i) < 0)
-
-  when compileOption("boundChecks"):
-    try:
-      echo q[99]
-      assert false
-    except IndexError:
-      discard
-
-    try:
-      assert q.len == 4
-      for i in 0 ..< 5: q.pop()
-      assert false
-    except IndexError:
-      discard
-
-  # grabs some types of resize error.
-  q = initQueue[int]()
-  for i in 1 .. 4: q.add i
-  q.pop()
-  q.pop()
-  for i in 5 .. 8: q.add i
-  assert $q == "[3, 4, 5, 6, 7, 8]"
-
-  # Similar to proc from the documentation example
-  proc foo(a, b: Positive) = # assume random positive values for `a` and `b`.
-    var q = initQueue[int]()
-    assert q.len == 0
-    for i in 1 .. a: q.add i
-
-    if b < q.len: # checking before indexed access.
-      assert q[b] == b + 1
-
-    # The following two lines don't need any checking on access due to the logic
-    # of the program, but that would not be the case if `a` could be 0.
-    assert q.front == 1
-    assert q.back == a
-
-    while q.len > 0: # checking if the queue is empty
-      assert q.pop() > 0
-
-  #foo(0,0)
-  foo(8,5)
-  foo(10,9)
-  foo(1,1)
-  foo(2,1)
-  foo(1,5)
-  foo(3,2)
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index 39ba6df49..b0d50bce2 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -7,16 +7,71 @@
 #    distribution, for details about the copyright.
 #
 
-## :Author: Alexander Mitchell-Robinson (Amrykid)
+## Although this module has ``seq`` in its name, it implements operations
+## not only for `seq`:idx: type, but for three built-in container types under
+## the ``openArray`` umbrella:
+## * sequences
+## * strings
+## * array
 ##
-## This module implements operations for the built-in `seq`:idx: type which
-## were inspired by functional programming languages.
+## The system module defines several common functions, such as:
+## * ``newseq[T]`` for creating new sequences of type ``T``
+## * ``@`` for converting arrays and strings to sequences
+## * ``add`` for adding new elements to strings and sequences
+## * ``&`` for string and seq concatenation
+## * ``in`` (alias for ``contains``) and ``notin`` for checking if an item is
+##   in a container
 ##
-## For functional style programming you may want to pass `anonymous procs
-## <manual.html#procedures-anonymous-procs>`_ to procs like ``filter`` to
-## reduce typing. Anonymous procs can use `the special do notation
-## <manual.html#procedures-do-notation>`_
-## which is more convenient in certain situations.
+## This module builds upon that, providing additional functionality in form of
+## procs, iterators and templates inspired by functional programming
+## languages.
+##
+## For functional style programming you have different options at your disposal:
+## * pass `anonymous proc<manual.html#procedures-anonymous-procs>`_
+## * import `sugar module<sugar.html>`_  and use
+##   `=> macro<sugar.html#%3D>.m,untyped,untyped>`_
+## * use `...It templates<#18>`_
+##   (`mapIt<#mapIt.t,typed,untyped>`_,
+##   `filterIt<#filterIt.t,untyped,untyped>`_, etc.)
+##
+## The chaining of functions is possible thanks to the
+## `method call syntax<manual.html#procs-method-call-syntax>`_.
+##
+## .. code-block::
+##   import sequtils, sugar
+##
+##   # Creating a sequence from 1 to 10, multiplying each member by 2,
+##   # keeping only the members which are not divisible by 6.
+##   let
+##     foo = toSeq(1..10).map(x => x*2).filter(x => x mod 6 != 0)
+##     bar = toSeq(1..10).mapIt(it*2).filterIt(it mod 6 != 0)
+##
+##   doAssert foo == bar
+##   echo foo                  # @[2, 4, 8, 10, 14, 16, 20]
+##
+##   echo foo.any(x => x > 17) # true
+##   echo bar.allIt(it < 20)   # false
+##   echo foo.foldl(a + b)     # 74; sum of all members
+##
+## .. code-block::
+##   import sequtils
+##   from strutils import join
+##
+##   let
+##     vowels = @"aeiou" # creates a sequence @['a', 'e', 'i', 'o', 'u']
+##     foo = "sequtils is an awesome module"
+##
+##   echo foo.filterIt(it notin vowels).join # "sqtls s n wsm mdl"
+##
+## ----
+##
+## **See also**:
+## * `strutils module<strutils.html>`_ for common string functions
+## * `sugar module<sugar.html>`_ for syntactic sugar macros
+## * `algorithm module<algorithm.html>`_ for common generic algorithms
+## * `json module<json.html>`_ for a structure which allows
+##   heterogeneous members
+
 
 include "system/inclrtl"
 
@@ -31,7 +86,7 @@ macro evalOnceAs(expAlias, exp: untyped, letAssigneable: static[bool]): untyped
   ##  substitution in macro arguments such as
   ## https://github.com/nim-lang/Nim/issues/7187
   ## ``evalOnceAs(myAlias, myExp)`` will behave as ``let myAlias = myExp``
-  ## except when ``letAssigneable`` is false (eg to handle openArray) where
+  ## except when ``letAssigneable`` is false (e.g. to handle openArray) where
   ## it just forwards ``exp`` unchanged
   expectKind(expAlias, nnkIdent)
   var val = exp
@@ -49,16 +104,20 @@ macro evalOnceAs(expAlias, exp: untyped, letAssigneable: static[bool]): untyped
 
 proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
   ## Takes several sequences' items and returns them inside a new sequence.
+  ## All sequences must be of the same type.
   ##
-  ## Example:
+  ## See also:
+  ## * `distribute proc<#distribute,seq[T],Positive>`_ for a reverse
+  ##   operation
   ##
-  ## .. code-block::
-  ##   let
-  ##     s1 = @[1, 2, 3]
-  ##     s2 = @[4, 5]
-  ##     s3 = @[6, 7]
-  ##     total = concat(s1, s2, s3)
-  ##   assert total == @[1, 2, 3, 4, 5, 6, 7]
+  runnableExamples:
+    let
+      s1 = @[1, 2, 3]
+      s2 = @[4, 5]
+      s3 = @[6, 7]
+      total = concat(s1, s2, s3)
+    assert total == @[1, 2, 3, 4, 5, 6, 7]
+
   var L = 0
   for seqitm in items(seqs): inc(L, len(seqitm))
   newSeq(result, L)
@@ -71,13 +130,14 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
 proc count*[T](s: openArray[T], x: T): int =
   ## Returns the number of occurrences of the item `x` in the container `s`.
   ##
-  ## Example:
-  ##
-  ## .. code-block::
-  ##   let
-  ##     s = @[1, 2, 2, 3, 2, 4, 2]
-  ##     c = count(s, 2)
-  ##   assert c == 4
+  runnableExamples:
+    let
+      a = @[1, 2, 2, 3, 2, 4, 2]
+      b = "abracadabra"
+    assert count(a, 2) == 4
+    assert count(a, 99) == 0
+    assert count(b, 'r') == 2
+
   for itm in items(s):
     if itm == x:
       inc result
@@ -85,15 +145,14 @@ proc count*[T](s: openArray[T], x: T): int =
 proc cycle*[T](s: openArray[T], n: Natural): seq[T] =
   ## Returns a new sequence with the items of the container `s` repeated
   ## `n` times.
+  ## `n` must be a non-negative number (zero or more).
   ##
-  ## Example:
-  ##
-  ## .. code-block::
-  ##
-  ##   let
-  ##     s = @[1, 2, 3]
-  ##     total = s.cycle(3)
-  ##   assert total == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
+  runnableExamples:
+    let
+      s = @[1, 2, 3]
+      total = s.cycle(3)
+    assert total == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
+
   result = newSeq[T](n * s.len)
   var o = 0
   for x in 0 ..< n:
@@ -103,14 +162,13 @@ proc cycle*[T](s: openArray[T], n: Natural): seq[T] =
 
 proc repeat*[T](x: T, n: Natural): seq[T] =
   ## Returns a new sequence with the item `x` repeated `n` times.
+  ## `n` must be a non-negative number (zero or more).
   ##
-  ## Example:
-  ##
-  ## .. code-block::
-  ##
-  ##   let
-  ##     total = repeat(5, 3)
-  ##   assert total == @[5, 5, 5]
+  runnableExamples:
+    let
+      total = repeat(5, 3)
+    assert total == @[5, 5, 5]
+
   result = newSeq[T](n)
   for i in 0 ..< n:
     result[i] = x
@@ -118,16 +176,18 @@ proc repeat*[T](x: T, n: Natural): seq[T] =
 proc deduplicate*[T](s: openArray[T], isSorted: bool = false): seq[T] =
   ## Returns a new sequence without duplicates.
   ##
-  ## Example:
+  ## Setting the optional argument ``isSorted`` to ``true`` (default: false)
+  ## uses a faster algorithm for deduplication.
   ##
-  ## .. code-block::
-  ##   let
-  ##     dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
-  ##     dup2 = @["a", "a", "c", "d", "d"]
-  ##     unique1 = deduplicate(dup1)
-  ##     unique2 = deduplicate(dup2)
-  ##   assert unique1 == @[1, 3, 4, 2, 8]
-  ##   assert unique2 == @["a", "c", "d"]
+  runnableExamples:
+    let
+      dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
+      dup2 = @["a", "a", "c", "d", "d"]
+      unique1 = deduplicate(dup1)
+      unique2 = deduplicate(dup2, isSorted = true)
+    assert unique1 == @[1, 3, 4, 2, 8]
+    assert unique2 == @["a", "c", "d"]
+
   result = @[]
   if s.len > 0:
     if isSorted:
@@ -144,39 +204,44 @@ proc deduplicate*[T](s: openArray[T], isSorted: bool = false): seq[T] =
 proc zip*[S, T](s1: openArray[S], s2: openArray[T]): seq[tuple[a: S, b: T]] =
   ## Returns a new sequence with a combination of the two input containers.
   ##
-  ## For convenience you can access the returned tuples through the named
-  ## fields `a` and `b`. If one container is shorter, the remaining items in
-  ## the longer container are discarded.
+  ## The input containers can be of different types.
+  ## If one container is shorter, the remaining items in the longer container
+  ## are discarded.
   ##
-  ## Example:
+  ## For convenience you can access the returned tuples through the named
+  ## fields `a` and `b`.
   ##
-  ## .. code-block::
-  ##   let
-  ##     short = @[1, 2, 3]
-  ##     long = @[6, 5, 4, 3, 2, 1]
-  ##     words = @["one", "two", "three"]
-  ##     zip1 = zip(short, long)
-  ##     zip2 = zip(short, words)
-  ##   assert zip1 == @[(1, 6), (2, 5), (3, 4)]
-  ##   assert zip2 == @[(1, "one"), (2, "two"), (3, "three")]
-  ##   assert zip1[2].b == 4
-  ##   assert zip2[2].b == "three"
+  runnableExamples:
+    let
+      short = @[1, 2, 3]
+      long = @[6, 5, 4, 3, 2, 1]
+      words = @["one", "two", "three"]
+      letters = "abcd"
+      zip1 = zip(short, long)
+      zip2 = zip(short, words)
+      zip3 = zip(long, letters)
+    assert zip1 == @[(1, 6), (2, 5), (3, 4)]
+    assert zip2 == @[(1, "one"), (2, "two"), (3, "three")]
+    assert zip3 == @[(a: 6, b: 'a'), (a: 5, b: 'b'), (a: 4, b: 'c'),
+                     (a: 3, b: 'd')]
+    assert zip1[2].b == 4
+    assert zip2[2].b == "three"
+
   var m = min(s1.len, s2.len)
   newSeq(result, m)
   for i in 0 ..< m:
     result[i] = (s1[i], s2[i])
 
 proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
-  ## Splits and distributes a sequence `s` into `num` sub sequences.
+  ## Splits and distributes a sequence `s` into `num` sub-sequences.
   ##
-  ## Returns a sequence of `num` sequences. For some input values this is the
-  ## inverse of the `concat <#concat>`_ proc. The proc will assert in debug
-  ## builds if `s` is nil or `num` is less than one, and will likely crash on
-  ## release builds.  The input sequence `s` can be empty, which will produce
+  ## Returns a sequence of `num` sequences. For *some* input values this is the
+  ## inverse of the `concat <#concat,varargs[seq[T]]>`_ proc.
+  ## The input sequence `s` can be empty, which will produce
   ## `num` empty sequences.
   ##
   ## If `spread` is false and the length of `s` is not a multiple of `num`, the
-  ## proc will max out the first sub sequences with ``1 + len(s) div num``
+  ## proc will max out the first sub-sequence with ``1 + len(s) div num``
   ## entries, leaving the remainder of elements to the last sequence.
   ##
   ## On the other hand, if `spread` is true, the proc will distribute evenly
@@ -184,18 +249,16 @@ proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
   ## more suited to multithreading where you are passing equal sized work units
   ## to a thread pool and want to maximize core usage.
   ##
-  ## Example:
-  ##
-  ## .. code-block::
-  ##   let numbers = @[1, 2, 3, 4, 5, 6, 7]
-  ##   assert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
-  ##   assert numbers.distribute(3, false)  == @[@[1, 2, 3], @[4, 5, 6], @[7]]
-  ##   assert numbers.distribute(6)[0] == @[1, 2]
-  ##   assert numbers.distribute(6)[5] == @[7]
+  runnableExamples:
+    let numbers = @[1, 2, 3, 4, 5, 6, 7]
+    assert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
+    assert numbers.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]]
+    assert numbers.distribute(6)[0] == @[1, 2]
+    assert numbers.distribute(6)[1] == @[3]
+
   if num < 2:
     result = @[s]
     return
-
   let num = int(num) # XXX probably only needed because of .. bug
 
   # Create the result and calculate the stride size and the remainder if any.
@@ -209,13 +272,11 @@ proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
   if extra == 0 or spread == false:
     # Use an algorithm which overcounts the stride and minimizes reading limits.
     if extra > 0: inc(stride)
-
     for i in 0 ..< num:
       result[i] = newSeq[T]()
       for g in first ..< min(s.len, first + stride):
         result[i].add(s[g])
       first += stride
-
   else:
     # Use an undercounting algorithm which *adds* the remainder each iteration.
     for i in 0 ..< num:
@@ -223,7 +284,6 @@ proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
       if extra > 0:
         extra -= 1
         inc(last)
-
       result[i] = newSeq[T]()
       for g in first ..< last:
         result[i].add(s[g])
@@ -231,110 +291,103 @@ proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
 
 proc map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}):
                                                             seq[S]{.inline.} =
-  ## Returns a new sequence with the results of `op` applied to every item in
-  ## the container `s`.
+  ## Returns a new sequence with the results of `op` proc applied to every
+  ## item in the container `s`.
   ##
-  ## Since the input is not modified you can use this version of ``map`` to
+  ## Since the input is not modified you can use it to
   ## transform the type of the elements in the input container.
   ##
-  ## Example:
+  ## See also:
+  ## * `mapIt template<#mapIt.t,typed,untyped>`_
+  ## * `apply proc<#apply,openArray[T],proc(T)_2>`_ for the in-place version
   ##
-  ## .. code-block:: nim
-  ##   let
-  ##     a = @[1, 2, 3, 4]
-  ##     b = map(a, proc(x: int): string = $x)
-  ##   assert b == @["1", "2", "3", "4"]
+  runnableExamples:
+    let
+      a = @[1, 2, 3, 4]
+      b = map(a, proc(x: int): string = $x)
+    assert b == @["1", "2", "3", "4"]
+
   newSeq(result, s.len)
   for i in 0 ..< s.len:
     result[i] = op(s[i])
 
-proc map*[T](s: var openArray[T], op: proc (x: var T) {.closure.})
-                                                              {.deprecated.} =
-  ## Applies `op` to every item in `s` modifying it directly.
-  ##
-  ## Note that this version of ``map`` requires your input and output types to
-  ## be the same, since they are modified in-place.
-  ##
-  ## Example:
-  ##
-  ## .. code-block:: nim
-  ##   var a = @["1", "2", "3", "4"]
-  ##   echo repr(a)
-  ##   # --> ["1", "2", "3", "4"]
-  ##   map(a, proc(x: var string) = x &= "42")
-  ##   echo repr(a)
-  ##   # --> ["142", "242", "342", "442"]
-  ## **Deprecated since version 0.12.0:** Use the ``apply`` proc instead.
-  for i in 0 ..< s.len: op(s[i])
-
 proc apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.})
                                                               {.inline.} =
   ## Applies `op` to every item in `s` modifying it directly.
   ##
-  ## Note that this requires your input and output types to
-  ## be the same, since they are modified in-place.
+  ## Note that container `s` must be declared as a ``var``
+  ## and it is required for your input and output types to
+  ## be the same, since `s` is modified in-place.
   ## The parameter function takes a ``var T`` type parameter.
   ##
-  ## Example:
-  ##
-  ## .. code-block:: nim
-  ##   var a = @["1", "2", "3", "4"]
-  ##   echo repr(a)
-  ##   # --> ["1", "2", "3", "4"]
-  ##   apply(a, proc(x: var string) = x &= "42")
-  ##   echo repr(a)
-  ##   # --> ["142", "242", "342", "442"]
+  ## See also:
+  ## * `applyIt template<#applyIt.t,untyped,untyped>`_
+  ## * `map proc<#map,openArray[T],proc(T)>`_
   ##
+  runnableExamples:
+    var a = @["1", "2", "3", "4"]
+    apply(a, proc(x: var string) = x &= "42")
+    assert a == @["142", "242", "342", "442"]
+
   for i in 0 ..< s.len: op(s[i])
 
 proc apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.})
                                                               {.inline.} =
   ## Applies `op` to every item in `s` modifying it directly.
   ##
-  ## Note that this requires your input and output types to
-  ## be the same, since they are modified in-place.
+  ## Note that container `s` must be declared as a ``var``
+  ## and it is required for your input and output types to
+  ## be the same, since `s` is modified in-place.
   ## The parameter function takes and returns a ``T`` type variable.
   ##
-  ## Example:
-  ##
-  ## .. code-block:: nim
-  ##   var a = @["1", "2", "3", "4"]
-  ##   echo repr(a)
-  ##   # --> ["1", "2", "3", "4"]
-  ##   apply(a, proc(x: string): string = x & "42")
-  ##   echo repr(a)
-  ##   # --> ["142", "242", "342", "442"]
+  ## See also:
+  ## * `applyIt template<#applyIt.t,untyped,untyped>`_
+  ## * `map proc<#map,openArray[T],proc(T)>`_
   ##
+  runnableExamples:
+    var a = @["1", "2", "3", "4"]
+    apply(a, proc(x: string): string = x & "42")
+    assert a == @["142", "242", "342", "442"]
+
   for i in 0 ..< s.len: s[i] = op(s[i])
 
 iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T =
-  ## Iterates through a container and yields every item that fulfills the
-  ## predicate.
+  ## Iterates through a container `s` and yields every item that fulfills the
+  ## predicate `pred` (function that returns a `bool`).
   ##
-  ## Example:
+  ## See also:
+  ## * `fliter proc<#filter,openArray[T],proc(T)>`_
+  ## * `filterIt template<#filterIt.t,untyped,untyped>`_
   ##
-  ## .. code-block::
-  ##   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
+  runnableExamples:
+    let numbers = @[1, 4, 5, 8, 9, 7, 4]
+    var evens = newSeq[int]()
+    for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
+      evens.add(n)
+    assert evens == @[4, 8, 4]
+
   for i in 0 ..< s.len:
     if pred(s[i]):
       yield s[i]
 
 proc filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T]
                                                                   {.inline.} =
-  ## Returns a new sequence with all the items that fulfilled the predicate.
+  ## Returns a new sequence with all the items of `s` that fulfilled the
+  ## predicate `pred` (function that returns a `bool`).
   ##
-  ## Example:
+  ## See also:
+  ## * `filterIt template<#filterIt.t,untyped,untyped>`_
+  ## * `filter iterator<#filter.i,openArray[T],proc(T)>`_
+  ## * `keepIf proc<#keepIf,seq[T],proc(T)>`_ for the in-place version
   ##
-  ## .. code-block::
-  ##   let
-  ##     colors = @["red", "yellow", "black"]
-  ##     f1 = filter(colors, proc(x: string): bool = x.len < 6)
-  ##     f2 = filter(colors) do (x: string) -> bool : x.len > 5
-  ##   assert f1 == @["red", "black"]
-  ##   assert f2 == @["yellow"]
+  runnableExamples:
+    let
+      colors = @["red", "yellow", "black"]
+      f1 = filter(colors, proc(x: string): bool = x.len < 6)
+      f2 = filter(colors, proc(x: string): bool = x.contains('y'))
+    assert f1 == @["red", "black"]
+    assert f2 == @["yellow"]
+
   result = newSeq[T]()
   for i in 0 ..< s.len:
     if pred(s[i]):
@@ -342,15 +395,23 @@ proc filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T]
 
 proc keepIf*[T](s: var seq[T], pred: proc(x: T): bool {.closure.})
                                                                 {.inline.} =
-  ## Keeps the items in the passed sequence if they fulfilled the predicate.
-  ## Same as the ``filter`` proc, but modifies the sequence directly.
+  ## Keeps the items in the passed sequence `s` if they fulfilled the
+  ## predicate `pred` (function that returns a `bool`).
   ##
-  ## Example:
+  ## Note that `s` must be declared as a ``var``.
   ##
-  ## .. code-block::
-  ##   var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
-  ##   keepIf(floats, proc(x: float): bool = x > 10)
-  ##   assert floats == @[13.0, 12.5, 10.1]
+  ## Similar to the `filter proc<#filter,openArray[T],proc(T)>`_,
+  ## but modifies the sequence directly.
+  ##
+  ## See also:
+  ## * `keepItIf template<#keepItIf.t,seq,untyped>`_
+  ## * `filter proc<#filter,openArray[T],proc(T)>`_
+  ##
+  runnableExamples:
+    var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
+    keepIf(floats, proc(x: float): bool = x > 10)
+    assert floats == @[13.0, 12.5, 10.1]
+
   var pos = 0
   for i in 0 ..< len(s):
     if pred(s[i]):
@@ -360,16 +421,15 @@ proc keepIf*[T](s: var seq[T], pred: proc(x: T): bool {.closure.})
   setLen(s, pos)
 
 proc delete*[T](s: var seq[T]; first, last: Natural) =
-  ## Deletes in `s` the items at position `first` .. `last`. This modifies
-  ## `s` itself, it does not return a copy.
-  ##
-  ## Example:
+  ## Deletes in the items of a sequence `s` at positions ``first..last``
+  ## (including both ends of a range).
+  ## This modifies `s` itself, it does not return a copy.
   ##
-  ##.. code-block::
-  ##   let outcome = @[1,1,1,1,1,1,1,1]
-  ##   var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
-  ##   dest.delete(3, 8)
-  ##   assert outcome == dest
+  runnableExamples:
+    let outcome = @[1,1,1,1,1,1,1,1]
+    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
@@ -384,15 +444,15 @@ proc insert*[T](dest: var seq[T], src: openArray[T], pos=0) =
   ## Inserts items from `src` into `dest` at position `pos`. This modifies
   ## `dest` itself, it does not return a copy.
   ##
-  ## Example:
+  ## Notice that `src` and `dest` must be of the same type.
   ##
-  ##.. code-block::
-  ##   var dest = @[1,1,1,1,1,1,1,1]
-  ##   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
+  runnableExamples:
+    var dest = @[1,1,1,1,1,1,1,1]
+    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
@@ -411,37 +471,48 @@ proc insert*[T](dest: var seq[T], src: openArray[T], pos=0) =
 
 
 template filterIt*(s, pred: untyped): untyped =
-  ## Returns a new sequence with all the items that fulfilled the predicate.
+  ## Returns a new sequence with all the items of `s` that fulfilled the
+  ## predicate `pred`.
   ##
-  ## Unlike the `proc` version, the predicate needs to be an expression using
-  ## the ``it`` variable for testing, like: ``filterIt("abcxyz", it == 'x')``.
+  ## Unlike the `filter proc<#filter,openArray[T],proc(T)>`_ and
+  ## `filter iterator<#filter.i,openArray[T],proc(T)>`_,
+  ## the predicate needs to be an expression using the ``it`` variable
+  ## for testing, like: ``filterIt("abcxyz", it == 'x')``.
   ##
-  ## Example:
+  ## See also:
+  ## * `fliter proc<#filter,openArray[T],proc(T)>`_
+  ## * `filter iterator<#filter.i,openArray[T],proc(T)>`_
   ##
-  ## .. code-block::
-  ##    let
-  ##      temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44]
-  ##      acceptable = filterIt(temperatures, it < 50 and it > -10)
-  ##      notAcceptable = filterIt(temperatures, it > 50 or it < -10)
-  ##    assert acceptable == @[-2.0, 24.5, 44.31]
-  ##    assert notAcceptable == @[-272.15, 99.9, -113.44]
+  runnableExamples:
+    let
+      temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44]
+      acceptable = temperatures.filterIt(it < 50 and it > -10)
+      notAcceptable = temperatures.filterIt(it > 50 or it < -10)
+    assert acceptable == @[-2.0, 24.5, 44.31]
+    assert notAcceptable == @[-272.15, 99.9, -113.44]
+
   var result = newSeq[type(s[0])]()
   for it {.inject.} in items(s):
     if pred: result.add(it)
   result
 
 template keepItIf*(varSeq: seq, pred: untyped) =
-  ## Convenience template around the ``keepIf`` proc to reduce typing.
+  ## Keeps the items in the passed sequence (must be declared as a ``var``)
+  ## if they fulfilled the predicate.
   ##
-  ## Unlike the `proc` version, the predicate needs to be an expression using
+  ## Unlike the `keepIf proc<#keepIf,seq[T],proc(T)>`_,
+  ## the predicate needs to be an expression using
   ## the ``it`` variable for testing, like: ``keepItIf("abcxyz", it == 'x')``.
   ##
-  ## Example:
+  ## See also:
+  ## * `keepIf proc<#keepIf,seq[T],proc(T)>`_
+  ## * `filterIt template<#filterIt.t,untyped,untyped>`_
   ##
-  ## .. code-block::
-  ##   var candidates = @["foo", "bar", "baz", "foobar"]
-  ##   keepItIf(candidates, it.len == 3 and it[0] == 'b')
-  ##   assert candidates == @["bar", "baz"]
+  runnableExamples:
+    var candidates = @["foo", "bar", "baz", "foobar"]
+    candidates.keepItIf(it.len == 3 and it[0] == 'b')
+    assert candidates == @["bar", "baz"]
+
   var pos = 0
   for i in 0 ..< len(varSeq):
     let it {.inject.} = varSeq[i]
@@ -455,26 +526,37 @@ proc all*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool =
   ## Iterates through a container and checks if every item fulfills the
   ## predicate.
   ##
-  ## Example:
+  ## See also:
+  ## * `allIt template<#allIt.t,untyped,untyped>`_
+  ## * `any proc<#any,openArray[T],proc(T)>`_
   ##
-  ## .. code-block::
-  ##   let numbers = @[1, 4, 5, 8, 9, 7, 4]
-  ##   assert all(numbers, proc (x: int): bool = return x < 10) == true
-  ##   assert all(numbers, proc (x: int): bool = return x < 9) == false
+  runnableExamples:
+     let numbers = @[1, 4, 5, 8, 9, 7, 4]
+     assert all(numbers, proc (x: int): bool = return x < 10) == true
+     assert all(numbers, proc (x: int): bool = return x < 9) == false
+
   for i in s:
     if not pred(i):
       return false
   return true
 
 template allIt*(s, pred: untyped): bool =
-  ## Checks if every item fulfills the predicate.
+  ## Iterates through a container and checks if every item fulfills the
+  ## predicate.
   ##
-  ## Example:
+  ## Unlike the `all proc<#all,openArray[T],proc(T)>`_,
+  ## the predicate needs to be an expression using
+  ## the ``it`` variable for testing, like: ``allIt("abba", it == 'a')``.
   ##
-  ## .. code-block::
-  ##   let numbers = @[1, 4, 5, 8, 9, 7, 4]
-  ##   assert allIt(numbers, it < 10) == true
-  ##   assert allIt(numbers, it < 9) == false
+  ## See also:
+  ## * `all proc<#all,openArray[T],proc(T)>`_
+  ## * `anyIt template<#anyIt.t,untyped,untyped>`_
+  ##
+  runnableExamples:
+    let numbers = @[1, 4, 5, 8, 9, 7, 4]
+    assert numbers.allIt(it < 10) == true
+    assert numbers.allIt(it < 9) == false
+
   var result = true
   for it {.inject.} in items(s):
     if not pred:
@@ -486,26 +568,37 @@ proc any*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool =
   ## Iterates through a container and checks if some item fulfills the
   ## predicate.
   ##
-  ## Example:
+  ## See also:
+  ## * `anyIt template<#anyIt.t,untyped,untyped>`_
+  ## * `all proc<#all,openArray[T],proc(T)>`_
   ##
-  ## .. code-block::
-  ##   let numbers = @[1, 4, 5, 8, 9, 7, 4]
-  ##   assert any(numbers, proc (x: int): bool = return x > 8) == true
-  ##   assert any(numbers, proc (x: int): bool = return x > 9) == false
+  runnableExamples:
+    let numbers = @[1, 4, 5, 8, 9, 7, 4]
+    assert any(numbers, proc (x: int): bool = return x > 8) == true
+    assert any(numbers, proc (x: int): bool = return x > 9) == false
+
   for i in s:
     if pred(i):
       return true
   return false
 
 template anyIt*(s, pred: untyped): bool =
-  ## Checks if some item fulfills the predicate.
+  ## Iterates through a container and checks if some item fulfills the
+  ## predicate.
   ##
-  ## Example:
+  ## Unlike the `any proc<#any,openArray[T],proc(T)>`_,
+  ## the predicate needs to be an expression using
+  ## the ``it`` variable for testing, like: ``anyIt("abba", it == 'a')``.
   ##
-  ## .. code-block::
-  ##   let numbers = @[1, 4, 5, 8, 9, 7, 4]
-  ##   assert anyIt(numbers, it > 8) == true
-  ##   assert anyIt(numbers, it > 9) == false
+  ## See also:
+  ## * `any proc<#any,openArray[T],proc(T)>`_
+  ## * `allIt template<#allIt.t,untyped,untyped>`_
+  ##
+  runnableExamples:
+    let numbers = @[1, 4, 5, 8, 9, 7, 4]
+    assert numbers.anyIt(it > 8) == true
+    assert numbers.anyIt(it > 9) == false
+
   var result = false
   for it {.inject.} in items(s):
     if pred:
@@ -555,19 +648,28 @@ template toSeq2(iter: iterator): untyped =
     result
 
 template toSeq*(iter: untyped): untyped =
-  ## Transforms any iterable into a sequence.
+  ## Transforms any iterable (anything that can be iterated over, e.g. with
+  ## a for-loop) into a sequence.
+  ##
   runnableExamples:
     let
-      numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
-      odd_numbers = toSeq(filter(numeric, proc(x: int): bool = x mod 2 == 1))
-    doAssert odd_numbers == @[1, 3, 5, 7, 9]
+      myRange = 1..5
+      mySet: set[int8] = {5'i8, 3, 1}
+    assert type(myRange) is HSlice[system.int, system.int]
+    assert type(mySet) is set[int8]
+
+    let
+      mySeq1 = toSeq(myRange)
+      mySeq2 = toSeq(mySet)
+    assert mySeq1 == @[1, 2, 3, 4, 5]
+    assert mySeq2 == @[1'i8, 3, 5]
 
   when compiles(toSeq1(iter)):
     toSeq1(iter)
   elif compiles(toSeq2(iter)):
     toSeq2(iter)
   else:
-    # overload for untyped, eg: `toSeq(myInlineIterator(3))`
+    # overload for untyped, e.g.: `toSeq(myInlineIterator(3))`
     when compiles(iter.len):
       block:
         evalOnceAs(iter2, iter, true)
@@ -597,20 +699,23 @@ template foldl*(sequence, operation: untyped): untyped =
   ## the sequence of numbers 1, 2 and 3 will be parenthesized as (((1) - 2) -
   ## 3).
   ##
-  ## Example:
+  ## See also:
+  ## * `foldl template<#foldl.t,,,>`_ with a starting parameter
+  ## * `foldr template<#foldr.t,untyped,untyped>`_
   ##
-  ## .. code-block::
-  ##   let
-  ##     numbers = @[5, 9, 11]
-  ##     addition = foldl(numbers, a + b)
-  ##     subtraction = foldl(numbers, a - b)
-  ##     multiplication = foldl(numbers, a * b)
-  ##     words = @["nim", "is", "cool"]
-  ##     concatenation = foldl(words, a & b)
-  ##   assert addition == 25, "Addition is (((5)+9)+11)"
-  ##   assert subtraction == -15, "Subtraction is (((5)-9)-11)"
-  ##   assert multiplication == 495, "Multiplication is (((5)*9)*11)"
-  ##   assert concatenation == "nimiscool"
+  runnableExamples:
+    let
+      numbers = @[5, 9, 11]
+      addition = foldl(numbers, a + b)
+      subtraction = foldl(numbers, a - b)
+      multiplication = foldl(numbers, a * b)
+      words = @["nim", "is", "cool"]
+      concatenation = foldl(words, a & b)
+    assert addition == 25, "Addition is (((5)+9)+11)"
+    assert subtraction == -15, "Subtraction is (((5)-9)-11)"
+    assert multiplication == 495, "Multiplication is (((5)*9)*11)"
+    assert concatenation == "nimiscool"
+
   let s = sequence
   assert s.len > 0, "Can't fold empty sequences"
   var result: type(s[0])
@@ -625,20 +730,22 @@ template foldl*(sequence, operation: untyped): untyped =
 template foldl*(sequence, operation, first): untyped =
   ## Template to fold a sequence from left to right, returning the accumulation.
   ##
-  ## This version of ``foldl`` gets a starting parameter. This makes it possible
+  ## This version of ``foldl`` gets a **starting parameter**. This makes it possible
   ## to accumulate the sequence into a different type than the sequence elements.
   ##
   ## The ``operation`` parameter should be an expression which uses the variables
   ## ``a`` and ``b`` for each step of the fold. The ``first`` parameter is the
   ## start value (the first ``a``) and therefor defines the type of the result.
   ##
-  ## Example:
+  ## See also:
+  ## * `foldr template<#foldr.t,untyped,untyped>`_
   ##
-  ## .. code-block::
-  ##   let
-  ##     numbers = @[0, 8, 1, 5]
-  ##     digits = foldl(numbers, a & (chr(b + ord('0'))), "")
-  ##   assert digits == "0815"
+  runnableExamples:
+    let
+      numbers = @[0, 8, 1, 5]
+      digits = foldl(numbers, a & (chr(b + ord('0'))), "")
+    assert digits == "0815"
+
   var result: type(first)
   result = first
   for x in items(sequence):
@@ -662,20 +769,23 @@ template foldr*(sequence, operation: untyped): untyped =
   ## the sequence of numbers 1, 2 and 3 will be parenthesized as (1 - (2 -
   ## (3))).
   ##
-  ## Example:
+  ## See also:
+  ## * `foldl template<#foldl.t,untyped,untyped>`_
+  ## * `foldl template<#foldl.t,,,>`_ with a starting parameter
   ##
-  ## .. code-block::
-  ##   let
-  ##     numbers = @[5, 9, 11]
-  ##     addition = foldr(numbers, a + b)
-  ##     subtraction = foldr(numbers, a - b)
-  ##     multiplication = foldr(numbers, a * b)
-  ##     words = @["nim", "is", "cool"]
-  ##     concatenation = foldr(words, a & b)
-  ##   assert addition == 25, "Addition is (5+(9+(11)))"
-  ##   assert subtraction == 7, "Subtraction is (5-(9-(11)))"
-  ##   assert multiplication == 495, "Multiplication is (5*(9*(11)))"
-  ##   assert concatenation == "nimiscool"
+  runnableExamples:
+    let
+      numbers = @[5, 9, 11]
+      addition = foldr(numbers, a + b)
+      subtraction = foldr(numbers, a - b)
+      multiplication = foldr(numbers, a * b)
+      words = @["nim", "is", "cool"]
+      concatenation = foldr(words, a & b)
+    assert addition == 25, "Addition is (5+(9+(11)))"
+    assert subtraction == 7, "Subtraction is (5-(9-(11)))"
+    assert multiplication == 495, "Multiplication is (5*(9*(11)))"
+    assert concatenation == "nimiscool"
+
   let s = sequence
   assert s.len > 0, "Can't fold empty sequences"
   var result: type(s[0])
@@ -687,41 +797,26 @@ template foldr*(sequence, operation: untyped): untyped =
     result = operation
   result
 
-template mapIt*(s, typ, op: untyped): untyped =
-  ## Convenience template around the ``map`` proc to reduce typing.
-  ##
-  ## The template injects the ``it`` variable which you can use directly in an
-  ## expression. You also need to pass as `typ` the type of the expression,
-  ## since the new returned sequence can have a different type than the
-  ## original.
-  ##
-  ## Example:
-  ##
-  ## .. code-block::
-  ##   let
-  ##     nums = @[1, 2, 3, 4]
-  ##     strings = nums.mapIt(string, $(4 * it))
-  ##   assert strings == @["4", "8", "12", "16"]
-  ## **Deprecated since version 0.12.0:** Use the ``mapIt(seq1, op)``
-  ##   template instead.
-  var result: seq[typ] = @[]
-  for it {.inject.} in items(s):
-    result.add(op)
-  result
-
 template mapIt*(s: typed, op: untyped): untyped =
-  ## Convenience template around the ``map`` proc to reduce typing.
+  ## Returns a new sequence with the results of `op` proc applied to every
+  ## item in the container `s`.
+  ##
+  ## Since the input is not modified you can use it to
+  ## transform the type of the elements in the input container.
   ##
   ## The template injects the ``it`` variable which you can use directly in an
   ## expression.
   ##
-  ## Example:
+  ## See also:
+  ## * `map proc<#map,openArray[T],proc(T)>`_
+  ## * `applyIt template<#applyIt.t,untyped,untyped>`_ for the in-place version
   ##
-  ## .. code-block::
-  ##   let
-  ##     nums = @[1, 2, 3, 4]
-  ##     strings = nums.mapIt($(4 * it))
-  ##   assert strings == @["4", "8", "12", "16"]
+  runnableExamples:
+    let
+      nums = @[1, 2, 3, 4]
+      strings = nums.mapIt($(4 * it))
+    assert strings == @["4", "8", "12", "16"]
+
   when defined(nimHasTypeof):
     type outType = typeof((
       block:
@@ -758,31 +853,38 @@ template applyIt*(varSeq, op: untyped) =
   ## expression. The expression has to return the same type as the sequence you
   ## are mutating.
   ##
-  ## Example:
+  ## See also:
+  ## * `apply proc<#apply,openArray[T],proc(T)_2>`_
+  ## * `mapIt template<#mapIt.t,typed,untyped>`_
   ##
-  ## .. code-block::
-  ##   var nums = @[1, 2, 3, 4]
-  ##   nums.applyIt(it * 3)
-  ##   assert nums[0] + nums[3] == 15
+  runnableExamples:
+     var nums = @[1, 2, 3, 4]
+     nums.applyIt(it * 3)
+     assert nums[0] + nums[3] == 15
+
   for i in low(varSeq) .. high(varSeq):
     let it {.inject.} = varSeq[i]
     varSeq[i] = op
 
 
 template newSeqWith*(len: int, init: untyped): untyped =
-  ## creates a new sequence, calling `init` to initialize each value.
+  ## Creates a new sequence of length `len`, calling `init` to initialize
+  ## each value of the sequence.
   ##
-  ## Example:
+  ## Useful for creating "2D" sequences - sequences containing other sequences
+  ## or to populate fields of the created sequence.
   ##
-  ## .. code-block::
-  ##   var seq2D = newSeqWith(20, newSeq[bool](10))
-  ##   seq2D[0][0] = true
-  ##   seq2D[1][0] = true
-  ##   seq2D[0][1] = true
-  ##
-  ##   import random
-  ##   var seqRand = newSeqWith(20, random(10))
-  ##   echo seqRand
+  runnableExamples:
+    ## Creates a seqence containing 5 bool sequences, each of length of 3.
+    var seq2D = newSeqWith(5, newSeq[bool](3))
+    assert seq2D.len == 5
+    assert seq2D[0].len == 3
+    assert seq2D[4][2] == false
+
+    ## Creates a sequence of 20 random numbers from 1 to 10
+    import random
+    var seqRand = newSeqWith(20, random(10))
+
   var result = newSeq[type(init)](len)
   for i in 0 ..< len:
     result[i] = init
@@ -804,7 +906,7 @@ proc mapLitsImpl(constructor: NimNode; op: NimNode; nested: bool;
 
 macro mapLiterals*(constructor, op: untyped;
                    nested = true): untyped =
-  ## applies ``op`` to each of the **atomic** literals like ``3``
+  ## Applies ``op`` to each of the **atomic** literals like ``3``
   ## or ``"abc"`` in the specified ``constructor`` AST. This can
   ## be used to map every array element to some target type:
   ##
@@ -819,16 +921,20 @@ macro mapLiterals*(constructor, op: untyped;
   ## .. code-block::
   ##   let x = [int(0.1), int(1.2), int(2.3), int(3.4)]
   ##
-  ## If ``nested`` is true, the literals are replaced everywhere
-  ## in the ``constructor`` AST, otherwise only the first level
+  ## If ``nested`` is true (which is the default), the literals are replaced
+  ## everywhere in the ``constructor`` AST, otherwise only the first level
   ## is considered:
   ##
   ## .. code-block::
-  ##   mapLiterals((1, ("abc"), 2), float, nested=false)
-  ##
-  ## Produces::
-  ##
-  ##   (float(1), ("abc"), float(2))
+  ##   let a = mapLiterals((1.2, (2.3, 3.4), 4.8), int)
+  ##   let b = mapLiterals((1.2, (2.3, 3.4), 4.8), int, nested=false)
+  ##   assert a == (1, (2, 3), 4)
+  ##   assert b == (1, (2.3, 3.4), 4)
+  ##
+  ##   let c = mapLiterals((1, (2, 3), 4, (5, 6)), `$`)
+  ##   let d = mapLiterals((1, (2, 3), 4, (5, 6)), `$`, nested=false)
+  ##   assert c == ("1", ("2", "3"), "4", ("5", "6"))
+  ##   assert d == ("1", (2, 3), "4", (5, 6))
   ##
   ## There are no constraints for the ``constructor`` AST, it
   ## works for nested tuples of arrays of sets etc.
diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim
index 1273cbc33..d1f941e92 100644
--- a/lib/pure/collections/sets.nim
+++ b/lib/pure/collections/sets.nim
@@ -191,13 +191,6 @@ proc `[]`*[A](s: var HashSet[A], key: A): var A =
     else:
       raise newException(KeyError, "key not found")
 
-proc mget*[A](s: var HashSet[A], key: A): var A {.deprecated.} =
-  ## returns the element that is actually stored in 's' which has the same
-  ## value as 'key' or raises the ``KeyError`` exception. This is useful
-  ## when one overloaded 'hash' and '==' but still needs reference semantics
-  ## for sharing. Use ```[]``` instead.
-  s[key]
-
 proc contains*[A](s: HashSet[A], key: A): bool =
   ## Returns true iff `key` is in `s`.
   ##
diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim
index 9a5bffcef..2cdc62996 100644
--- a/lib/pure/collections/tableimpl.nim
+++ b/lib/pure/collections/tableimpl.nim
@@ -7,7 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-## An ``include`` file for the different table implementations.
+# An ``include`` file for the different table implementations.
 
 # hcode for real keys cannot be zero.  hcode==0 signifies an empty slot.  These
 # two procs retain clarity of that encoding without the space cost of an enum.
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index f46a368b1..84ec422d4 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -9,16 +9,21 @@
 
 ## The ``tables`` module implements variants of an efficient `hash table`:idx:
 ## (also often named `dictionary`:idx: in other programming languages) that is
-## a mapping from keys to values. ``Table`` is the usual hash table,
-## ``OrderedTable`` is like ``Table`` but remembers insertion order
-## and ``CountTable`` is a mapping from a key to its number of occurrences.
+## a mapping from keys to values.
+##
+## There are several different types of hash tables available:
+## * `Table<#Table>`_ is the usual hash table,
+## * `OrderedTable<#OrderedTable>`_ is like ``Table`` but remembers insertion order,
+## * `CountTable<#CountTable>`_ is a mapping from a key to its number of occurrences
 ##
 ## For consistency with every other data type in Nim these have **value**
 ## semantics, this means that ``=`` performs a copy of the hash table.
-## For **reference** semantics use the ``Ref`` variant: ``TableRef``,
-## ``OrderedTableRef``, ``CountTableRef``.
 ##
-## To give an example, when ``a`` is a Table, then ``var b = a`` gives ``b``
+## For `ref semantics<manual.html#types-ref-and-pointer-types>`_
+## use their ``Ref`` variants: `TableRef<#TableRef>`_,
+## `OrderedTableRef<#OrderedTableRef>`_, and `CountTableRef<#CountTableRef>`_.
+##
+## To give an example, when ``a`` is a ``Table``, then ``var b = a`` gives ``b``
 ## as a new independent table. ``b`` is initialised with the contents of ``a``.
 ## Changing ``b`` does not affect ``a`` and vice versa:
 ##
@@ -35,8 +40,8 @@
 ##   echo a, b  # output: {1: one, 2: two}{1: one, 2: two, 3: three}
 ##   echo a == b  # output: false
 ##
-## On the other hand, when ``a`` is a TableRef instead, then changes to ``b``
-## also affect ``a``. Both ``a`` and ``b`` reference the same data structure:
+## On the other hand, when ``a`` is a ``TableRef`` instead, then changes to ``b``
+## also affect ``a``. Both ``a`` and ``b`` **ref** the same data structure:
 ##
 ## .. code-block::
 ##   import tables
@@ -51,27 +56,111 @@
 ##   echo a, b  # output: {1: one, 2: two, 3: three}{1: one, 2: two, 3: three}
 ##   echo a == b  # output: true
 ##
+## ----
+##
+## Basic usage
+## ===========
+##
+## Table
+## -----
+##
+## .. code-block::
+##   import tables
+##   from sequtils import zip
+##
+##   let
+##     names = ["John", "Paul", "George", "Ringo"]
+##     years = [1940, 1942, 1943, 1940]
+##
+##   var beatles = initTable[string, int]()
+##
+##   for pairs in zip(names, years):
+##     let (name, birthYear) = pairs
+##     beatles[name] = birthYear
+##
+##   echo beatles
+##   # {"George": 1943, "Ringo": 1940, "Paul": 1942, "John": 1940}
+##
+##
+##   var beatlesByYear = initTable[int, seq[string]]()
+##
+##   for pairs in zip(years, names):
+##     let (birthYear, name) = pairs
+##     if not beatlesByYear.hasKey(birthYear):
+##       # if a key doesn't exists, we create one with an empty sequence
+##       # before we can add elements to it
+##       beatlesByYear[birthYear] = @[]
+##     beatlesByYear[birthYear].add(name)
+##
+##   echo beatlesByYear
+##   # {1940: @["John", "Ringo"], 1942: @["Paul"], 1943: @["George"]}
+##
+##
 ##
-## Here is an example of ``CountTable`` usage:
+## OrderedTable
+## ------------
+##
+## `OrderedTable<#OrderedTable>`_ is used when it is important to preserve
+## the insertion order of keys.
+##
+## .. code-block::
+##   import tables
+##
+##   let
+##     a = [('z', 1), ('y', 2), ('x', 3)]
+##     t = a.toTable          # regular table
+##     ot = a.toOrderedTable  # ordered tables
+##
+##   echo t   # {'x': 3, 'y': 2, 'z': 1}
+##   echo ot  # {'z': 1, 'y': 2, 'x': 3}
+##
+##
+##
+## CountTable
+## ----------
+##
+## `CountTable<#CountTable>`_ is useful for counting number of items of some
+## container (e.g. string, sequence or array), as it is a mapping where the
+## items are the keys, and their number of occurrences are the values.
+## For that purpose `toCountTable proc<#toCountTable,openArray[A]>`_
+## comes handy:
+##
+## .. code-block::
+##   import tables
 ##
-## .. code-block:: nim
 ##   let myString = "abracadabra"
-##   var myTable = initCountTable[char]()
+##   let letterFrequencies = toCountTable(myString)
+##   echo letterFrequencies
+##   # 'a': 5, 'b': 2, 'c': 1, 'd': 1, 'r': 2}
+##
+## The same could have been achieved by manually iterating over a container
+## and increasing each key's value with `inc proc<#inc,CountTable[A],A,int>`_:
+##
+## .. code-block::
+##   import tables
 ##
+##   let myString = "abracadabra"
+##   var letterFrequencies = initCountTable[char]()
 ##   for c in myString:
-##     myTable.inc(c)
+##     letterFrequencies.inc(c)
+##   echo letterFrequencies
+##   # output: {'a': 5, 'b': 2, 'c': 1, 'd': 1, 'r': 2}
+##
+## ----
+##
 ##
-##   echo myTable  # output: {'a': 5, 'b': 2, 'c': 1, 'd': 1, 'r': 2}
 ##
+## Hashing
+## -------
 ##
 ## If you are using simple standard types like ``int`` or ``string`` for the
 ## keys of the table you won't have any problems, but as soon as you try to use
 ## a more complex object as a key you will be greeted by a strange compiler
-## error::
+## error:
 ##
 ##   Error: type mismatch: got (Person)
 ##   but expected one of:
-##   hashes.hash(x: openarray[A]): Hash
+##   hashes.hash(x: openArray[A]): Hash
 ##   hashes.hash(x: int): Hash
 ##   hashes.hash(x: float): Hash
 ##   …
@@ -89,6 +178,8 @@
 ## example implementing only ``hash`` suffices:
 ##
 ## .. code-block::
+##   import tables, hashes
+##
 ##   type
 ##     Person = object
 ##       firstName, lastName: string
@@ -111,45 +202,50 @@
 ##   p2.firstName = "소진"
 ##   p2.lastName = "박"
 ##   salaries[p2] = 45_000
+##
+## ----
+##
+## See also
+## ========
+##
+## * `json module<json.html>`_ for table-like structure which allows
+##   heterogeneous members
+## * `sharedtables module<sharedtables.html>`_ for shared hash table support
+## * `strtabs module<strtabs.html>`_ for efficient hash tables
+##   mapping from strings to strings
+## * `hashes module<hashes.html>`_ for helper functions for hashing
 
-import
-  hashes, math
+
+import hashes, math
 
 include "system/inclrtl"
 
 type
   KeyValuePair[A, B] = tuple[hcode: Hash, key: A, val: B]
   KeyValuePairSeq[A, B] = seq[KeyValuePair[A, B]]
-  Table*[A, B] = object ## generic hash table
+  Table*[A, B] = object
+    ## Generic hash table, consisting of a key-value pair.
+    ##
+    ## `data` and `counter` are internal implementation details which
+    ## can't be accessed.
+    ##
+    ## For creating an empty Table, use `initTable proc<#initTable,int>`_.
     data: KeyValuePairSeq[A, B]
     counter: int
-  TableRef*[A,B] = ref Table[A, B]
+  TableRef*[A,B] = ref Table[A, B] ## Ref version of `Table<#Table>`_.
+    ##
+    ## For creating a new empty TableRef, use `newTable proc
+    ## <#newTable,int>`_.
+
+
+# ------------------------------ helpers ---------------------------------
 
 template maxHash(t): untyped = high(t.data)
 template dataLen(t): untyped = len(t.data)
 
 include tableimpl
 
-proc clear*[A, B](t: var Table[A, B]) =
-  ## resets the table so that it is empty.
-  clearImpl()
-
-proc clear*[A, B](t: TableRef[A, B]) =
-  ## resets the ref table so that it is empty.
-  clearImpl()
-
-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
-  ## expected extra amount to the parameter before calling this.
-  ##
-  ## Internally, we want mustRehash(rightSize(x), x) == false.
-  result = nextPowerOfTwo(count * 3 div 2  +  4)
-
-proc len*[A, B](t: Table[A, B]): int =
-  ## returns the number of keys in ``t``.
-  result = t.counter
+proc rightSize*(count: Natural): int {.inline.}
 
 template get(t, key): untyped =
   ## retrieves the value at ``t[key]``. The value can be modified.
@@ -176,36 +272,340 @@ template getOrDefaultImpl(t, key, default: untyped): untyped =
   var index = rawGet(t, key, hc)
   result = if index >= 0: t.data[index].val else: default
 
-proc `[]`*[A, B](t: Table[A, B], key: A): B {.deprecatedGet.} =
-  ## retrieves the value at ``t[key]``. If ``key`` is not in ``t``, the
-  ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether
-  ## the key exists.
-  get(t, key)
+template dollarImpl(): untyped {.dirty.} =
+  if t.len == 0:
+    result = "{:}"
+  else:
+    result = "{"
+    for key, val in pairs(t):
+      if result.len > 1: result.add(", ")
+      result.addQuoted(key)
+      result.add(": ")
+      result.addQuoted(val)
+    result.add("}")
 
-proc `[]`*[A, B](t: var Table[A, B], key: A): var B {.deprecatedGet.} =
-  ## retrieves the value at ``t[key]``. The value can be modified.
+proc enlarge[A, B](t: var Table[A, B]) =
+  var n: KeyValuePairSeq[A, B]
+  newSeq(n, len(t.data) * growthFactor)
+  swap(t.data, n)
+  for i in countup(0, high(n)):
+    let eh = n[i].hcode
+    if isFilled(eh):
+      var j: Hash = eh and maxHash(t)
+      while isFilled(t.data[j].hcode):
+        j = nextTry(j, maxHash(t))
+      rawInsert(t, t.data, n[i].key, n[i].val, eh, j)
+
+template equalsImpl(s, t: typed): typed =
+  if s.counter == t.counter:
+    # different insertion orders mean different 'data' seqs, so we have
+    # to use the slow route here:
+    for key, val in s:
+      if not t.hasKey(key): return false
+      if t.getOrDefault(key) != val: return false
+    return true
+
+
+
+# -------------------------------------------------------------------
+# ------------------------------ Table ------------------------------
+# -------------------------------------------------------------------
+
+proc initTable*[A, B](initialSize=64): Table[A, B] =
+  ## Creates a new hash table that is empty.
+  ##
+  ## ``initialSize`` must be a power of two (default: 64).
+  ## If you need to accept runtime values for this you could use the
+  ## `nextPowerOfTwo proc<math.html#nextPowerOfTwo,int>`_ from the
+  ## `math module<math.html>`_ or the `rightSize proc<#rightSize,Natural>`_
+  ## from this module.
+  ##
+  ## See also:
+  ## * `toTable proc<#toTable,openArray[]>`_
+  ## * `newTable proc<#newTable,int>`_ for creating a `TableRef`
+  runnableExamples:
+    let
+      a = initTable[int, string]()
+      b = initTable[char, seq[int]]()
+  assert isPowerOfTwo(initialSize)
+  result.counter = 0
+  newSeq(result.data, initialSize)
+
+proc toTable*[A, B](pairs: openArray[(A, B)]): Table[A, B] =
+  ## Creates a new hash table that contains the given ``pairs``.
+  ##
+  ## ``pairs`` is a container consisting of ``(key, value)`` tuples.
+  ##
+  ## See also:
+  ## * `initTable proc<#initTable,int>`_
+  ## * `newTable proc<#newTable,openArray[]>`_ for a `TableRef` version
+  runnableExamples:
+    let a = [('a', 5), ('b', 9)]
+    let b = toTable(a)
+    assert b == {'a': 5, 'b': 9}.toTable
+  result = initTable[A, B](rightSize(pairs.len))
+  for key, val in items(pairs): result[key] = val
+
+proc `[]`*[A, B](t: Table[A, B], key: A): B =
+  ## Retrieves the value at ``t[key]``.
+  ##
   ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised.
+  ## One can check with `hasKey proc<#hasKey,Table[A,B],A>`_ whether
+  ## the key exists.
+  ##
+  ## See also:
+  ## * `getOrDefault proc<#getOrDefault,Table[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  ## * `getOrDefault proc<#getOrDefault,Table[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  ## * `[]= proc<#[]=,Table[A,B],A,B>`_ for inserting a new
+  ##   (key, value) pair in the table
+  ## * `hasKey proc<#hasKey,Table[A,B],A>`_ for checking if a key is in
+  ##   the table
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.toTable
+    doAssert a['a'] == 5
+    doAssertRaises(KeyError):
+      echo a['z']
   get(t, key)
 
-proc mget*[A, B](t: var Table[A, B], key: A): var B {.deprecated.} =
-  ## retrieves the value at ``t[key]``. The value can be modified.
+proc `[]`*[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 ``KeyError`` exception is raised.
-  ## Use ``[]`` instead.
+  ##
+  ## See also:
+  ## * `getOrDefault proc<#getOrDefault,Table[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  ## * `getOrDefault proc<#getOrDefault,Table[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  ## * `[]= proc<#[]=,Table[A,B],A,B>`_ for inserting a new
+  ##   (key, value) pair in the table
+  ## * `hasKey proc<#hasKey,Table[A,B],A>`_ for checking if a key is in
+  ##   the table
   get(t, key)
 
+proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) =
+  ## Inserts a ``(key, value)`` pair into ``t``.
+  ##
+  ## See also:
+  ## * `[] proc<#[],Table[A,B],A>`_ for retrieving a value of a key
+  ## * `hasKeyOrPut proc<#hasKeyOrPut,Table[A,B],A,B>`_
+  ## * `mgetOrPut proc<#mgetOrPut,Table[A,B],A,B>`_
+  ## * `del proc<#del,Table[A,B],A>`_ for removing a key from the table
+  runnableExamples:
+    var a = initTable[char, int]()
+    a['x'] = 7
+    a['y'] = 33
+    doAssert a == {'x': 7, 'y': 33}.toTable
+  putImpl(enlarge)
+
+proc hasKey*[A, B](t: Table[A, B], key: A): bool =
+  ## Returns true if ``key`` is in the table ``t``.
+  ##
+  ## See also:
+  ## * `contains proc<#contains,Table[A,B],A>`_ for use with the `in` operator
+  ## * `[] proc<#[],Table[A,B],A>`_ for retrieving a value of a key
+  ## * `getOrDefault proc<#getOrDefault,Table[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  ## * `getOrDefault proc<#getOrDefault,Table[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.toTable
+    doAssert a.hasKey('a') == true
+    doAssert a.hasKey('z') == false
+  var hc: Hash
+  result = rawGet(t, key, hc) >= 0
+
+proc contains*[A, B](t: Table[A, B], key: A): bool =
+  ## Alias of `hasKey proc<#hasKey,Table[A,B],A>`_ for use with
+  ## the ``in`` operator.
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.toTable
+    doAssert 'b' in a == true
+    doAssert a.contains('z') == false
+  return hasKey[A, B](t, key)
+
+proc hasKeyOrPut*[A, B](t: var Table[A, B], key: A, val: B): bool =
+  ## Returns true if ``key`` is in the table, otherwise inserts ``value``.
+  ##
+  ## See also:
+  ## * `hasKey proc<#hasKey,Table[A,B],A>`_
+  ## * `[] proc<#[],Table[A,B],A>`_ for retrieving a value of a key
+  ## * `getOrDefault proc<#getOrDefault,Table[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  ## * `getOrDefault proc<#getOrDefault,Table[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  runnableExamples:
+    var a = {'a': 5, 'b': 9}.toTable
+    if a.hasKeyOrPut('a', 50):
+      a['a'] = 99
+    if a.hasKeyOrPut('z', 50):
+      a['z'] = 99
+    doAssert a == {'a': 99, 'b': 9, 'z': 50}.toTable
+  hasKeyOrPutImpl(enlarge)
+
 proc getOrDefault*[A, B](t: Table[A, B], key: A): B =
-  ## retrieves the value at ``t[key]`` iff ``key`` is in ``t``. Otherwise, the
+  ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``. Otherwise, the
   ## default initialization value for type ``B`` is returned (e.g. 0 for any
   ## integer type).
+  ##
+  ## See also:
+  ## * `[] proc<#[],Table[A,B],A>`_ for retrieving a value of a key
+  ## * `hasKey proc<#hasKey,Table[A,B],A>`_
+  ## * `hasKeyOrPut proc<#hasKeyOrPut,Table[A,B],A,B>`_
+  ## * `mgetOrPut proc<#mgetOrPut,Table[A,B],A,B>`_
+  ## * `getOrDefault proc<#getOrDefault,Table[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.toTable
+    doAssert a.getOrDefault('a') == 5
+    doAssert a.getOrDefault('z') == 0
   getOrDefaultImpl(t, key)
 
 proc getOrDefault*[A, B](t: Table[A, B], key: A, default: B): B =
-  ## retrieves the value at ``t[key]`` iff ``key`` is in ``t``.
+  ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``.
   ## Otherwise, ``default`` is returned.
+  ##
+  ## See also:
+  ## * `[] proc<#[],Table[A,B],A>`_ for retrieving a value of a key
+  ## * `hasKey proc<#hasKey,Table[A,B],A>`_
+  ## * `hasKeyOrPut proc<#hasKeyOrPut,Table[A,B],A,B>`_
+  ## * `mgetOrPut proc<#mgetOrPut,Table[A,B],A,B>`_
+  ## * `getOrDefault proc<#getOrDefault,Table[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.toTable
+    doAssert a.getOrDefault('a', 99) == 5
+    doAssert a.getOrDefault('z', 99) == 99
   getOrDefaultImpl(t, key, default)
 
+proc mgetOrPut*[A, B](t: var Table[A, B], key: A, val: B): var B =
+  ## Retrieves value at ``t[key]`` or puts ``val`` if not present, either way
+  ## returning a value which can be modified.
+  ##
+  ## See also:
+  ## * `[] proc<#[],Table[A,B],A>`_ for retrieving a value of a key
+  ## * `hasKey proc<#hasKey,Table[A,B],A>`_
+  ## * `hasKeyOrPut proc<#hasKeyOrPut,Table[A,B],A,B>`_
+  ## * `getOrDefault proc<#getOrDefault,Table[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  ## * `getOrDefault proc<#getOrDefault,Table[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  runnableExamples:
+    var a = {'a': 5, 'b': 9}.toTable
+    doAssert a.mgetOrPut('a', 99) == 5
+    doAssert a.mgetOrPut('z', 99) == 99
+    doAssert a == {'a': 5, 'b': 9, 'z': 99}.toTable
+  mgetOrPutImpl(enlarge)
+
+proc len*[A, B](t: Table[A, B]): int =
+  ## Returns the number of keys in ``t``.
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.toTable
+    doAssert len(a) == 2
+  result = t.counter
+
+proc add*[A, B](t: var Table[A, B], key: A, val: B) =
+  ## Puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists.
+  ##
+  ## **This can introduce duplicate keys into the table!**
+  ##
+  ## Use `[]= proc<#[]=,Table[A,B],A,B>`_ for inserting a new
+  ## (key, value) pair in the table without introducing duplicates.
+  addImpl(enlarge)
+
+proc del*[A, B](t: var Table[A, B], key: A) =
+  ## Deletes ``key`` from hash table ``t``. Does nothing if the key does not exist.
+  ##
+  ## See also:
+  ## * `take proc<#take,Table[A,B],A,B>`_
+  ## * `clear proc<#clear,Table[A,B]>`_ to empty the whole table
+  runnableExamples:
+    var a = {'a': 5, 'b': 9, 'c': 13}.toTable
+    a.del('a')
+    doAssert a == {'b': 9, 'c': 13}.toTable
+    a.del('z')
+    doAssert a == {'b': 9, 'c': 13}.toTable
+  delImpl()
+
+proc take*[A, B](t: var Table[A, B], key: A, val: var B): bool =
+  ## Deletes the ``key`` from the table.
+  ## Returns ``true``, if the ``key`` existed, and sets ``val`` to the
+  ## mapping of the key. Otherwise, returns ``false``, and the ``val`` is
+  ## unchanged.
+  ##
+  ## See also:
+  ## * `del proc<#del,Table[A,B],A>`_
+  ## * `clear proc<#clear,Table[A,B]>`_ to empty the whole table
+  runnableExamples:
+    var
+      a = {'a': 5, 'b': 9, 'c': 13}.toTable
+      i: int
+    doAssert a.take('b', i) == true
+    doAssert a == {'a': 5, 'c': 13}.toTable
+    doAssert i == 9
+    i = 0
+    doAssert a.take('z', i) == false
+    doAssert a == {'a': 5, 'c': 13}.toTable
+    doAssert i == 0
+
+  var hc: Hash
+  var index = rawGet(t, key, hc)
+  result = index >= 0
+  if result:
+    shallowCopy(val, t.data[index].val)
+    delImplIdx(t, index)
+
+proc clear*[A, B](t: var Table[A, B]) =
+  ## Resets the table so that it is empty.
+  ##
+  ## See also:
+  ## * `del proc<#del,Table[A,B],A>`_
+  ## * `take proc<#take,Table[A,B],A,B>`_
+  runnableExamples:
+    var a = {'a': 5, 'b': 9, 'c': 13}.toTable
+    doAssert len(a) == 3
+    clear(a)
+    doAssert len(a) == 0
+  clearImpl()
+
+proc `$`*[A, B](t: Table[A, B]): string =
+  ## The ``$`` operator for hash tables. Used internally when calling `echo`
+  ## on a table.
+  dollarImpl()
+
+proc `==`*[A, B](s, t: Table[A, B]): bool =
+  ## The ``==`` operator for hash tables. Returns ``true`` if the content of both
+  ## tables contains the same key-value pairs. Insert order does not matter.
+  runnableExamples:
+    let
+      a = {'a': 5, 'b': 9, 'c': 13}.toTable
+      b = {'b': 9, 'c': 13, 'a': 5}.toTable
+    doAssert a == b
+  equalsImpl(s, t)
+
+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
+  ## expected extra amount to the parameter before calling this.
+  ##
+  ## Internally, we want mustRehash(rightSize(x), x) == false.
+  result = nextPowerOfTwo(count * 3 div 2  +  4)
+
+proc indexBy*[A, B, C](collection: A, index: proc(x: B): C): Table[C, B] =
+  ## Index the collection with the proc provided.
+  # TODO: As soon as supported, change collection: A to collection: A[B]
+  result = initTable[C, B]()
+  for item in collection:
+    result[index(item)] = item
+
+
+
 template withValue*[A, B](t: var Table[A, B], key: A, value, body: untyped) =
-  ## retrieves the value at ``t[key]``.
+  ## Retrieves the value at ``t[key]``.
+  ##
   ## ``value`` can be modified in the scope of the ``withValue`` call.
   ##
   ## .. code-block:: nim
@@ -225,7 +625,8 @@ template withValue*[A, B](t: var Table[A, B], key: A, value, body: untyped) =
 
 template withValue*[A, B](t: var Table[A, B], key: A,
                           value, body1, body2: untyped) =
-  ## retrieves the value at ``t[key]``.
+  ## Retrieves the value at ``t[key]``.
+  ##
   ## ``value`` can be modified in the scope of the ``withValue`` call.
   ##
   ## .. code-block:: nim
@@ -248,370 +649,535 @@ template withValue*[A, B](t: var Table[A, B], key: A,
   else:
     body2
 
-iterator allValues*[A, B](t: Table[A, B]; key: A): B =
-  ## iterates over any value in the table ``t`` that belongs to the given ``key``.
-  var h: Hash = genHash(key) and high(t.data)
-  while isFilled(t.data[h].hcode):
-    if t.data[h].key == key:
-      yield t.data[h].val
-    h = nextTry(h, high(t.data))
-
-proc hasKey*[A, B](t: Table[A, B], key: A): bool =
-  ## returns true iff ``key`` is in the table ``t``.
-  var hc: Hash
-  result = rawGet(t, key, hc) >= 0
-
-proc contains*[A, B](t: Table[A, B], key: A): bool =
-  ## alias of ``hasKey`` for use with the ``in`` operator.
-  return hasKey[A, B](t, key)
 
 iterator pairs*[A, B](t: Table[A, B]): (A, B) =
-  ## iterates over any ``(key, value)`` pair in the table ``t``.
+  ## Iterates over any ``(key, value)`` pair in the table ``t``.
+  ##
+  ## See also:
+  ## * `mpairs iterator<#mpairs.i,Table[A,B]>`_
+  ## * `keys iterator<#keys.i,Table[A,B]>`_
+  ## * `values iterator<#values.i,Table[A,B]>`_
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   let a = {
+  ##     'o': [1, 5, 7, 9],
+  ##     'e': [2, 4, 6, 8]
+  ##     }.toTable
+  ##
+  ##   for k, v in a.pairs:
+  ##     echo "key: ", k
+  ##     echo "value: ", v
+  ##
+  ##   # key: e
+  ##   # value: [2, 4, 6, 8]
+  ##   # key: o
+  ##   # value: [1, 5, 7, 9]
   for h in 0..high(t.data):
     if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
 
 iterator mpairs*[A, B](t: var Table[A, B]): (A, var B) =
-  ## iterates over any ``(key, value)`` pair in the table ``t``. The values
-  ## can be modified.
+  ## Iterates over any ``(key, value)`` pair in the table ``t`` (must be
+  ## declared as `var`). The values can be modified.
+  ##
+  ## See also:
+  ## * `pairs iterator<#pairs.i,Table[A,B]>`_
+  ## * `mvalues iterator<#mvalues.i,Table[A,B]>`_
+  runnableExamples:
+    var a = {
+      'o': @[1, 5, 7, 9],
+      'e': @[2, 4, 6, 8]
+      }.toTable
+    for k, v in a.mpairs:
+      v.add(v[0] + 10)
+    doAssert a == {'e': @[2, 4, 6, 8, 12], 'o': @[1, 5, 7, 9, 11]}.toTable
   for h in 0..high(t.data):
     if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
 
 iterator keys*[A, B](t: Table[A, B]): A =
-  ## iterates over any key in the table ``t``.
+  ## Iterates over any key in the table ``t``.
+  ##
+  ## See also:
+  ## * `pairs iterator<#pairs.i,Table[A,B]>`_
+  ## * `values iterator<#values.i,Table[A,B]>`_
+  runnableExamples:
+    var a = {
+      'o': @[1, 5, 7, 9],
+      'e': @[2, 4, 6, 8]
+      }.toTable
+    for k in a.keys:
+      a[k].add(99)
+    doAssert a == {'e': @[2, 4, 6, 8, 99], 'o': @[1, 5, 7, 9, 99]}.toTable
   for h in 0..high(t.data):
     if isFilled(t.data[h].hcode): yield t.data[h].key
 
 iterator values*[A, B](t: Table[A, B]): B =
-  ## iterates over any value in the table ``t``.
+  ## Iterates over any value in the table ``t``.
+  ##
+  ## See also:
+  ## * `pairs iterator<#pairs.i,Table[A,B]>`_
+  ## * `keys iterator<#keys.i,Table[A,B]>`_
+  ## * `mvalues iterator<#mvalues.i,Table[A,B]>`_
+  runnableExamples:
+    let a = {
+      'o': @[1, 5, 7, 9],
+      'e': @[2, 4, 6, 8]
+      }.toTable
+    for v in a.values:
+      doAssert v.len == 4
   for h in 0..high(t.data):
     if isFilled(t.data[h].hcode): yield t.data[h].val
 
 iterator mvalues*[A, B](t: var Table[A, B]): var B =
-  ## iterates over any value in the table ``t``. The values can be modified.
+  ## Iterates over any value in the table ``t`` (must be
+  ## declared as `var`). The values can be modified.
+  ##
+  ## See also:
+  ## * `mpairs iterator<#mpairs.i,Table[A,B]>`_
+  ## * `values iterator<#values.i,Table[A,B]>`_
+  runnableExamples:
+    var a = {
+      'o': @[1, 5, 7, 9],
+      'e': @[2, 4, 6, 8]
+      }.toTable
+    for v in a.mvalues:
+      v.add(99)
+    doAssert a == {'e': @[2, 4, 6, 8, 99], 'o': @[1, 5, 7, 9, 99]}.toTable
   for h in 0..high(t.data):
     if isFilled(t.data[h].hcode): yield t.data[h].val
 
-proc del*[A, B](t: var Table[A, B], key: A) =
-  ## deletes ``key`` from hash table ``t``. Does nothing if the key does not exist.
-  delImpl()
-
-proc take*[A, B](t: var Table[A, B], key: A, val: var B): bool =
-  ## deletes the ``key`` from the table.
-  ## Returns ``true``, if the ``key`` existed, and sets ``val`` to the
-  ## mapping of the key. Otherwise, returns ``false``, and the ``val`` is
-  ## unchanged.
-  var hc: Hash
-  var index = rawGet(t, key, hc)
-  result = index >= 0
-  if result:
-    shallowCopy(val, t.data[index].val)
-    delImplIdx(t, index)
-
-proc enlarge[A, B](t: var Table[A, B]) =
-  var n: KeyValuePairSeq[A, B]
-  newSeq(n, len(t.data) * growthFactor)
-  swap(t.data, n)
-  for i in countup(0, high(n)):
-    let eh = n[i].hcode
-    if isFilled(eh):
-      var j: Hash = eh and maxHash(t)
-      while isFilled(t.data[j].hcode):
-        j = nextTry(j, maxHash(t))
-      rawInsert(t, t.data, n[i].key, n[i].val, eh, j)
-
-proc mgetOrPut*[A, B](t: var Table[A, B], key: A, val: B): var B =
-  ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
-  ## returning a value which can be modified.
-  mgetOrPutImpl(enlarge)
-
-proc hasKeyOrPut*[A, B](t: var Table[A, B], key: A, val: B): bool =
-  ## returns true iff ``key`` is in the table, otherwise inserts ``value``.
-  hasKeyOrPutImpl(enlarge)
-
-proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) =
-  ## puts a ``(key, value)`` pair into ``t``.
-  putImpl(enlarge)
-
-proc add*[A, B](t: var Table[A, B], key: A, val: B) =
-  ## puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists.
-  ## This can introduce duplicate keys into the table!
-  addImpl(enlarge)
-
-proc len*[A, B](t: TableRef[A, B]): int =
-  ## returns the number of keys in ``t``.
-  result = t.counter
-
-proc initTable*[A, B](initialSize=64): Table[A, B] =
-  ## creates a new hash table that is empty.
+iterator allValues*[A, B](t: Table[A, B]; key: A): B =
+  ## Iterates over any value in the table ``t`` that belongs to the given ``key``.
   ##
-  ## ``initialSize`` needs to be a power of two. If you need to accept runtime
-  ## values for this you could use the ``nextPowerOfTwo`` proc from the
-  ## `math <math.html>`_ module or the ``rightSize`` proc from this module.
-  assert isPowerOfTwo(initialSize)
-  result.counter = 0
-  newSeq(result.data, initialSize)
+  ## Used if you have a table with duplicate keys (as a result of using
+  ## `add proc<#add,Table[A,B],A,B>`_).
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   var a = {'a': 3, 'b': 5}.toTable
+  ##   for i in 1..3:
+  ##     a.add('z', 10*i)
+  ##   echo a # {'a': 3, 'b': 5, 'z': 10, 'z': 20, 'z': 30}
+  ##
+  ##   for v in a.allValues('z'):
+  ##     echo v
+  ##   # 10
+  ##   # 20
+  ##   # 30
+  var h: Hash = genHash(key) and high(t.data)
+  while isFilled(t.data[h].hcode):
+    if t.data[h].key == key:
+      yield t.data[h].val
+    h = nextTry(h, high(t.data))
 
-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))
-  for key, val in items(pairs): result[key] = val
 
-template dollarImpl(): untyped {.dirty.} =
-  if t.len == 0:
-    result = "{:}"
-  else:
-    result = "{"
-    for key, val in pairs(t):
-      if result.len > 1: result.add(", ")
-      result.addQuoted(key)
-      result.add(": ")
-      result.addQuoted(val)
-    result.add("}")
 
-proc `$`*[A, B](t: Table[A, B]): string =
-  ## the ``$`` operator for hash tables.
-  dollarImpl()
+# -------------------------------------------------------------------
+# ---------------------------- TableRef -----------------------------
+# -------------------------------------------------------------------
 
-proc hasKey*[A, B](t: TableRef[A, B], key: A): bool =
-  ## returns true iff ``key`` is in the table ``t``.
-  result = t[].hasKey(key)
 
-template equalsImpl(s, t: typed): typed =
-  if s.counter == t.counter:
-    # different insertion orders mean different 'data' seqs, so we have
-    # to use the slow route here:
-    for key, val in s:
-      if not t.hasKey(key): return false
-      if t.getOrDefault(key) != val: return false
-    return true
+proc newTable*[A, B](initialSize=64): TableRef[A, B] =
+  ## Creates a new ref hash table that is empty.
+  ##
+  ## ``initialSize`` must be a power of two (default: 64).
+  ## If you need to accept runtime values for this you could use the
+  ## `nextPowerOfTwo proc<math.html#nextPowerOfTwo,int>`_ from the
+  ## `math module<math.html>`_ or the `rightSize proc<#rightSize,Natural>`_
+  ## from this module.
+  ##
+  ## See also:
+  ## * `newTable proc<#newTable,openArray[]>`_ for creating a `TableRef`
+  ##   from a collection of `(key, value)` pairs
+  ## * `initTable proc<#initTable,int>`_ for creating a `Table`
+  runnableExamples:
+    let
+      a = newTable[int, string]()
+      b = newTable[char, seq[int]]()
+  new(result)
+  result[] = initTable[A, B](initialSize)
 
-proc `==`*[A, B](s, t: Table[A, B]): bool =
-  ## The ``==`` operator for hash tables. Returns ``true`` iff the content of both
-  ## tables contains the same key-value pairs. Insert order does not matter.
-  equalsImpl(s, t)
+proc newTable*[A, B](pairs: openArray[(A, B)]): TableRef[A, B] =
+  ## Creates a new ref hash table that contains the given ``pairs``.
+  ##
+  ## ``pairs`` is a container consisting of ``(key, value)`` tuples.
+  ##
+  ## See also:
+  ## * `newTable proc<#newTable,int>`_
+  ## * `toTable proc<#toTable,openArray[]>`_ for a `Table` version
+  runnableExamples:
+    let a = [('a', 5), ('b', 9)]
+    let b = newTable(a)
+    assert b == {'a': 5, 'b': 9}.newTable
+  new(result)
+  result[] = toTable[A, B](pairs)
 
-proc indexBy*[A, B, C](collection: A, index: proc(x: B): C): Table[C, B] =
+proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B] =
   ## Index the collection with the proc provided.
   # TODO: As soon as supported, change collection: A to collection: A[B]
-  result = initTable[C, B]()
+  result = newTable[C, B]()
   for item in collection:
     result[index(item)] = item
 
-iterator pairs*[A, B](t: TableRef[A, B]): (A, B) =
-  ## iterates over any ``(key, value)`` pair in the table ``t``.
-  for h in 0..high(t.data):
-    if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
-
-iterator mpairs*[A, B](t: TableRef[A, B]): (A, var B) =
-  ## iterates over any ``(key, value)`` pair in the table ``t``. The values
-  ## can be modified.
-  for h in 0..high(t.data):
-    if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
-
-iterator keys*[A, B](t: TableRef[A, B]): A =
-  ## iterates over any key in the table ``t``.
-  for h in 0..high(t.data):
-    if isFilled(t.data[h].hcode): yield t.data[h].key
+proc `[]`*[A, B](t: TableRef[A, B], key: A): var B =
+  ## Retrieves the value at ``t[key]``.
+  ##
+  ## If ``key`` is not in ``t``, the  ``KeyError`` exception is raised.
+  ## One can check with `hasKey proc<#hasKey,TableRef[A,B],A>`_ whether
+  ## the key exists.
+  ##
+  ## See also:
+  ## * `getOrDefault proc<#getOrDefault,TableRef[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  ## * `getOrDefault proc<#getOrDefault,TableRef[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  ## * `[]= proc<#[]=,TableRef[A,B],A,B>`_ for inserting a new
+  ##   (key, value) pair in the table
+  ## * `hasKey proc<#hasKey,TableRef[A,B],A>`_ for checking if a key is in
+  ##   the table
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.newTable
+    doAssert a['a'] == 5
+    doAssertRaises(KeyError):
+      echo a['z']
+  result = t[][key]
 
-iterator values*[A, B](t: TableRef[A, B]): B =
-  ## iterates over any value in the table ``t``.
-  for h in 0..high(t.data):
-    if isFilled(t.data[h].hcode): yield t.data[h].val
+proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: B) =
+  ## Inserts a ``(key, value)`` pair into ``t``.
+  ##
+  ## See also:
+  ## * `[] proc<#[],TableRef[A,B],A>`_ for retrieving a value of a key
+  ## * `hasKeyOrPut proc<#hasKeyOrPut,TableRef[A,B],A,B>`_
+  ## * `mgetOrPut proc<#mgetOrPut,TableRef[A,B],A,B>`_
+  ## * `del proc<#del,TableRef[A,B],A>`_ for removing a key from the table
+  runnableExamples:
+    var a = newTable[char, int]()
+    a['x'] = 7
+    a['y'] = 33
+    doAssert a == {'x': 7, 'y': 33}.newTable
+  t[][key] = val
 
-iterator mvalues*[A, B](t: TableRef[A, B]): var B =
-  ## iterates over any value in the table ``t``. The values can be modified.
-  for h in 0..high(t.data):
-    if isFilled(t.data[h].hcode): yield t.data[h].val
+proc hasKey*[A, B](t: TableRef[A, B], key: A): bool =
+  ## Returns true if ``key`` is in the table ``t``.
+  ##
+  ## See also:
+  ## * `contains proc<#contains,TableRef[A,B],A>`_ for use with the `in`
+  ##   operator
+  ## * `[] proc<#[],TableRef[A,B],A>`_ for retrieving a value of a key
+  ## * `getOrDefault proc<#getOrDefault,TableRef[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  ## * `getOrDefault proc<#getOrDefault,TableRef[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.newTable
+    doAssert a.hasKey('a') == true
+    doAssert a.hasKey('z') == false
+  result = t[].hasKey(key)
 
-proc `[]`*[A, B](t: TableRef[A, B], key: A): var B {.deprecatedGet.} =
-  ## retrieves the value at ``t[key]``. If ``key`` is not in ``t``, the
-  ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether
-  ## the key exists.
-  result = t[][key]
+proc contains*[A, B](t: TableRef[A, B], key: A): bool =
+  ## Alias of `hasKey proc<#hasKey,TableRef[A,B],A>`_ for use with
+  ## the ``in`` operator.
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.newTable
+    doAssert 'b' in a == true
+    doAssert a.contains('z') == false
+  return hasKey[A, B](t, key)
 
-proc mget*[A, B](t: TableRef[A, B], key: A): var B {.deprecated.} =
-  ## retrieves the value at ``t[key]``. The value can be modified.
-  ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised.
-  ## Use ``[]`` instead.
-  t[][key]
+proc hasKeyOrPut*[A, B](t: var TableRef[A, B], key: A, val: B): bool =
+  ## Returns true if ``key`` is in the table, otherwise inserts ``value``.
+  ##
+  ## See also:
+  ## * `hasKey proc<#hasKey,TableRef[A,B],A>`_
+  ## * `[] proc<#[],TableRef[A,B],A>`_ for retrieving a value of a key
+  ## * `getOrDefault proc<#getOrDefault,TableRef[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  ## * `getOrDefault proc<#getOrDefault,TableRef[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  runnableExamples:
+    var a = {'a': 5, 'b': 9}.newTable
+    if a.hasKeyOrPut('a', 50):
+      a['a'] = 99
+    if a.hasKeyOrPut('z', 50):
+      a['z'] = 99
+    doAssert a == {'a': 99, 'b': 9, 'z': 50}.newTable
+  t[].hasKeyOrPut(key, val)
 
 proc getOrDefault*[A, B](t: TableRef[A, B], key: A): B =
-  ## retrieves the value at ``t[key]`` iff ``key`` is in ``t``. Otherwise, the
+  ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``. Otherwise, the
   ## default initialization value for type ``B`` is returned (e.g. 0 for any
   ## integer type).
+  ##
+  ## See also:
+  ## * `[] proc<#[],TableRef[A,B],A>`_ for retrieving a value of a key
+  ## * `hasKey proc<#hasKey,TableRef[A,B],A>`_
+  ## * `hasKeyOrPut proc<#hasKeyOrPut,TableRef[A,B],A,B>`_
+  ## * `mgetOrPut proc<#mgetOrPut,TableRef[A,B],A,B>`_
+  ## * `getOrDefault proc<#getOrDefault,TableRef[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.newTable
+    doAssert a.getOrDefault('a') == 5
+    doAssert a.getOrDefault('z') == 0
   getOrDefault(t[], key)
 
 proc getOrDefault*[A, B](t: TableRef[A, B], key: A, default: B): B =
-  ## retrieves the value at ``t[key]`` iff ``key`` is in ``t``.
+  ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``.
   ## Otherwise, ``default`` is returned.
+  ##
+  ## See also:
+  ## * `[] proc<#[],TableRef[A,B],A>`_ for retrieving a value of a key
+  ## * `hasKey proc<#hasKey,TableRef[A,B],A>`_
+  ## * `hasKeyOrPut proc<#hasKeyOrPut,TableRef[A,B],A,B>`_
+  ## * `mgetOrPut proc<#mgetOrPut,TableRef[A,B],A,B>`_
+  ## * `getOrDefault proc<#getOrDefault,TableRef[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.newTable
+    doAssert a.getOrDefault('a', 99) == 5
+    doAssert a.getOrDefault('z', 99) == 99
   getOrDefault(t[], key, default)
 
 proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B =
-  ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
+  ## Retrieves value at ``t[key]`` or puts ``val`` if not present, either way
   ## returning a value which can be modified.
+  ##
+  ## See also:
+  ## * `[] proc<#[],TableRef[A,B],A>`_ for retrieving a value of a key
+  ## * `hasKey proc<#hasKey,TableRef[A,B],A>`_
+  ## * `hasKeyOrPut proc<#hasKeyOrPut,TableRef[A,B],A,B>`_
+  ## * `getOrDefault proc<#getOrDefault,TableRef[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  ## * `getOrDefault proc<#getOrDefault,TableRef[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  runnableExamples:
+    var a = {'a': 5, 'b': 9}.newTable
+    doAssert a.mgetOrPut('a', 99) == 5
+    doAssert a.mgetOrPut('z', 99) == 99
+    doAssert a == {'a': 5, 'b': 9, 'z': 99}.newTable
   t[].mgetOrPut(key, val)
 
-proc hasKeyOrPut*[A, B](t: var TableRef[A, B], key: A, val: B): bool =
-  ## returns true iff ``key`` is in the table, otherwise inserts ``value``.
-  t[].hasKeyOrPut(key, val)
-
-proc contains*[A, B](t: TableRef[A, B], key: A): bool =
-  ## Alias of ``hasKey`` for use with the ``in`` operator.
-  return hasKey[A, B](t, key)
-
-proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: B) =
-  ## puts a ``(key, value)`` pair into ``t``.
-  t[][key] = val
+proc len*[A, B](t: TableRef[A, B]): int =
+  ## Returns the number of keys in ``t``.
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.newTable
+    doAssert len(a) == 2
+  result = t.counter
 
 proc add*[A, B](t: TableRef[A, B], key: A, val: B) =
-  ## puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists.
-  ## This can introduce duplicate keys into the table!
+  ## Puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists.
+  ##
+  ## **This can introduce duplicate keys into the table!**
+  ##
+  ## Use `[]= proc<#[]=,TableRef[A,B],A,B>`_ for inserting a new
+  ## (key, value) pair in the table without introducing duplicates.
   t[].add(key, val)
 
 proc del*[A, B](t: TableRef[A, B], key: A) =
-  ## deletes ``key`` from hash table ``t``. Does nothing if the key does not exist.
+  ## Deletes ``key`` from hash table ``t``. Does nothing if the key does not exist.
+  ##
+  ## See also:
+  ## * `take proc<#take,TableRef[A,B],A,B>`_
+  ## * `clear proc<#clear,TableRef[A,B]>`_ to empty the whole table
+  runnableExamples:
+    var a = {'a': 5, 'b': 9, 'c': 13}.newTable
+    a.del('a')
+    doAssert a == {'b': 9, 'c': 13}.newTable
+    a.del('z')
+    doAssert a == {'b': 9, 'c': 13}.newTable
   t[].del(key)
 
 proc take*[A, B](t: TableRef[A, B], key: A, val: var B): bool =
-  ## deletes the ``key`` from the table.
+  ## Deletes the ``key`` from the table.
   ## Returns ``true``, if the ``key`` existed, and sets ``val`` to the
   ## mapping of the key. Otherwise, returns ``false``, and the ``val`` is
   ## unchanged.
+  ##
+  ## See also:
+  ## * `del proc<#del,TableRef[A,B],A>`_
+  ## * `clear proc<#clear,TableRef[A,B]>`_ to empty the whole table
+  runnableExamples:
+    var
+      a = {'a': 5, 'b': 9, 'c': 13}.newTable
+      i: int
+    doAssert a.take('b', i) == true
+    doAssert a == {'a': 5, 'c': 13}.newTable
+    doAssert i == 9
+    i = 0
+    doAssert a.take('z', i) == false
+    doAssert a == {'a': 5, 'c': 13}.newTable
+    doAssert i == 0
   result = t[].take(key, val)
 
-proc newTable*[A, B](initialSize=64): TableRef[A, B] =
-  new(result)
-  result[] = initTable[A, B](initialSize)
-
-proc newTable*[A, B](pairs: openArray[(A, B)]): TableRef[A, B] =
-  ## creates a new hash table that contains the given ``pairs``.
-  new(result)
-  result[] = toTable[A, B](pairs)
+proc clear*[A, B](t: TableRef[A, B]) =
+  ## Resets the table so that it is empty.
+  ##
+  ## See also:
+  ## * `del proc<#del,Table[A,B],A>`_
+  ## * `take proc<#take,Table[A,B],A,B>`_
+  runnableExamples:
+    var a = {'a': 5, 'b': 9, 'c': 13}.newTable
+    doAssert len(a) == 3
+    clear(a)
+    doAssert len(a) == 0
+  clearImpl()
 
 proc `$`*[A, B](t: TableRef[A, B]): string =
-  ## The ``$`` operator for hash tables.
+  ## The ``$`` operator for hash tables. Used internally when calling `echo`
+  ## on a table.
   dollarImpl()
 
 proc `==`*[A, B](s, t: TableRef[A, B]): bool =
-  ## The ``==`` operator for hash tables. Returns ``true`` iff either both tables
-  ## are ``nil`` or none is ``nil`` and the content of both tables contains the
+  ## The ``==`` operator for hash tables. Returns ``true`` if either both tables
+  ## are ``nil``, or neither is ``nil`` and the content of both tables contains the
   ## same key-value pairs. Insert order does not matter.
+  runnableExamples:
+    let
+      a = {'a': 5, 'b': 9, 'c': 13}.newTable
+      b = {'b': 9, 'c': 13, 'a': 5}.newTable
+    doAssert a == b
   if isNil(s): result = isNil(t)
   elif isNil(t): result = false
   else: equalsImpl(s[], t[])
 
-proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B] =
-  ## Index the collection with the proc provided.
-  # TODO: As soon as supported, change collection: A to collection: A[B]
-  result = newTable[C, B]()
-  for item in collection:
-    result[index(item)] = item
 
-# ------------------------------ ordered table ------------------------------
 
-type
-  OrderedKeyValuePair[A, B] = tuple[
-    hcode: Hash, next: int, key: A, val: B]
-  OrderedKeyValuePairSeq[A, B] = seq[OrderedKeyValuePair[A, B]]
-  OrderedTable* [A, B] = object ## table that remembers insertion order
-    data: OrderedKeyValuePairSeq[A, B]
-    counter, first, last: int
-  OrderedTableRef*[A, B] = ref OrderedTable[A, B]
-
-proc len*[A, B](t: OrderedTable[A, B]): int {.inline.} =
-  ## returns the number of keys in ``t``.
-  result = t.counter
+iterator pairs*[A, B](t: TableRef[A, B]): (A, B) =
+  ## Iterates over any ``(key, value)`` pair in the table ``t``.
+  ##
+  ## See also:
+  ## * `mpairs iterator<#mpairs.i,TableRef[A,B]>`_
+  ## * `keys iterator<#keys.i,TableRef[A,B]>`_
+  ## * `values iterator<#values.i,TableRef[A,B]>`_
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   let a = {
+  ##     'o': [1, 5, 7, 9],
+  ##     'e': [2, 4, 6, 8]
+  ##     }.newTable
+  ##
+  ##   for k, v in a.pairs:
+  ##     echo "key: ", k
+  ##     echo "value: ", v
+  ##
+  ##   # key: e
+  ##   # value: [2, 4, 6, 8]
+  ##   # key: o
+  ##   # value: [1, 5, 7, 9]
+  for h in 0..high(t.data):
+    if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
 
-proc clear*[A, B](t: var OrderedTable[A, B]) =
-  ## resets the table so that it is empty.
-  clearImpl()
-  t.first = -1
-  t.last = -1
+iterator mpairs*[A, B](t: TableRef[A, B]): (A, var B) =
+  ## Iterates over any ``(key, value)`` pair in the table ``t``. The values
+  ## can be modified.
+  ##
+  ## See also:
+  ## * `pairs iterator<#pairs.i,TableRef[A,B]>`_
+  ## * `mvalues iterator<#mvalues.i,TableRef[A,B]>`_
+  runnableExamples:
+    let a = {
+      'o': @[1, 5, 7, 9],
+      'e': @[2, 4, 6, 8]
+      }.newTable
+    for k, v in a.mpairs:
+      v.add(v[0] + 10)
+    doAssert a == {'e': @[2, 4, 6, 8, 12], 'o': @[1, 5, 7, 9, 11]}.newTable
+  for h in 0..high(t.data):
+    if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
 
-proc clear*[A, B](t: var OrderedTableRef[A, B]) =
-  ## resets the table so that is is empty.
-  clear(t[])
+iterator keys*[A, B](t: TableRef[A, B]): A =
+  ## Iterates over any key in the table ``t``.
+  ##
+  ## See also:
+  ## * `pairs iterator<#pairs.i,TableRef[A,B]>`_
+  ## * `values iterator<#values.i,TableRef[A,B]>`_
+  runnableExamples:
+    let a = {
+      'o': @[1, 5, 7, 9],
+      'e': @[2, 4, 6, 8]
+      }.newTable
+    for k in a.keys:
+      a[k].add(99)
+    doAssert a == {'e': @[2, 4, 6, 8, 99], 'o': @[1, 5, 7, 9, 99]}.newTable
+  for h in 0..high(t.data):
+    if isFilled(t.data[h].hcode): yield t.data[h].key
 
-template forAllOrderedPairs(yieldStmt: untyped): typed {.dirty.} =
-  var h = t.first
-  while h >= 0:
-    var nxt = t.data[h].next
-    if isFilled(t.data[h].hcode): yieldStmt
-    h = nxt
+iterator values*[A, B](t: TableRef[A, B]): B =
+  ## Iterates over any value in the table ``t``.
+  ##
+  ## See also:
+  ## * `pairs iterator<#pairs.i,TableRef[A,B]>`_
+  ## * `keys iterator<#keys.i,TableRef[A,B]>`_
+  ## * `mvalues iterator<#mvalues.i,TableRef[A,B]>`_
+  runnableExamples:
+    let a = {
+      'o': @[1, 5, 7, 9],
+      'e': @[2, 4, 6, 8]
+      }.newTable
+    for v in a.values:
+      doAssert v.len == 4
+  for h in 0..high(t.data):
+    if isFilled(t.data[h].hcode): yield t.data[h].val
 
-iterator pairs*[A, B](t: OrderedTable[A, B]): (A, B) =
-  ## iterates over any ``(key, value)`` pair in the table ``t`` in insertion
-  ## order.
-  forAllOrderedPairs:
-    yield (t.data[h].key, t.data[h].val)
+iterator mvalues*[A, B](t: TableRef[A, B]): var B =
+  ## Iterates over any value in the table ``t``. The values can be modified.
+  ##
+  ## See also:
+  ## * `mpairs iterator<#mpairs.i,TableRef[A,B]>`_
+  ## * `values iterator<#values.i,TableRef[A,B]>`_
+  runnableExamples:
+    let a = {
+      'o': @[1, 5, 7, 9],
+      'e': @[2, 4, 6, 8]
+      }.newTable
+    for v in a.mvalues:
+      v.add(99)
+    doAssert a == {'e': @[2, 4, 6, 8, 99], 'o': @[1, 5, 7, 9, 99]}.newTable
+  for h in 0..high(t.data):
+    if isFilled(t.data[h].hcode): yield t.data[h].val
 
-iterator mpairs*[A, B](t: var OrderedTable[A, B]): (A, var B) =
-  ## iterates over any ``(key, value)`` pair in the table ``t`` in insertion
-  ## order. The values can be modified.
-  forAllOrderedPairs:
-    yield (t.data[h].key, t.data[h].val)
 
-iterator keys*[A, B](t: OrderedTable[A, B]): A =
-  ## iterates over any key in the table ``t`` in insertion order.
-  forAllOrderedPairs:
-    yield t.data[h].key
 
-iterator values*[A, B](t: OrderedTable[A, B]): B =
-  ## iterates over any value in the table ``t`` in insertion order.
-  forAllOrderedPairs:
-    yield t.data[h].val
 
-iterator mvalues*[A, B](t: var OrderedTable[A, B]): var B =
-  ## iterates over any value in the table ``t`` in insertion order. The values
-  ## can be modified.
-  forAllOrderedPairs:
-    yield t.data[h].val
 
-proc rawGetKnownHC[A, B](t: OrderedTable[A, B], key: A, hc: Hash): int =
-  rawGetKnownHCImpl()
 
-proc rawGetDeep[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int {.inline.} =
-  rawGetDeepImpl()
 
-proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int =
-  rawGetImpl()
 
-proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B {.deprecatedGet.} =
-  ## retrieves the value at ``t[key]``. If ``key`` is not in ``t``, the
-  ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether
-  ## the key exists.
-  get(t, key)
+# ---------------------------------------------------------------------------
+# ------------------------------ OrderedTable -------------------------------
+# ---------------------------------------------------------------------------
 
-proc `[]`*[A, B](t: var OrderedTable[A, B], key: A): var B{.deprecatedGet.} =
-  ## retrieves the value at ``t[key]``. The value can be modified.
-  ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised.
-  get(t, key)
+type
+  OrderedKeyValuePair[A, B] = tuple[
+    hcode: Hash, next: int, key: A, val: B]
+  OrderedKeyValuePairSeq[A, B] = seq[OrderedKeyValuePair[A, B]]
+  OrderedTable* [A, B] = object
+    ## Hash table that remembers insertion order.
+    ##
+    ## For creating an empty OrderedTable, use `initOrderedTable proc
+    ## <#initOrderedTable,int>`_.
+    data: OrderedKeyValuePairSeq[A, B]
+    counter, first, last: int
+  OrderedTableRef*[A, B] = ref OrderedTable[A, B] ## Ref version of
+    ## `OrderedTable<#OrderedTable>`_.
+    ##
+    ## For creating a new empty OrderedTableRef, use `newOrderedTable proc
+    ## <#newOrderedTable,int>`_.
 
-proc mget*[A, B](t: var OrderedTable[A, B], key: A): var B {.deprecated.} =
-  ## retrieves the value at ``t[key]``. The value can be modified.
-  ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised.
-  ## Use ``[]`` instead.
-  get(t, key)
 
-proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A): B =
-  ## retrieves the value at ``t[key]`` iff ``key`` is in ``t``. Otherwise, the
-  ## default initialization value for type ``B`` is returned (e.g. 0 for any
-  ## integer type).
-  getOrDefaultImpl(t, key)
+# ------------------------------ helpers ---------------------------------
 
-proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A, default: B): B =
-  ## retrieves the value at ``t[key]`` iff ``key`` is in ``t``. Otherwise,
-  ## ``default`` is returned.
-  getOrDefaultImpl(t, key, default)
+proc rawGetKnownHC[A, B](t: OrderedTable[A, B], key: A, hc: Hash): int =
+  rawGetKnownHCImpl()
 
-proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool =
-  ## returns true iff ``key`` is in the table ``t``.
-  var hc: Hash
-  result = rawGet(t, key, hc) >= 0
+proc rawGetDeep[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int {.inline.} =
+  rawGetDeepImpl()
 
-proc contains*[A, B](t: OrderedTable[A, B], key: A): bool =
-  ## Alias of ``hasKey`` for use with the ``in`` operator.
-  return hasKey[A, B](t, key)
+proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int =
+  rawGetImpl()
 
 proc rawInsert[A, B](t: var OrderedTable[A, B],
                      data: var OrderedKeyValuePairSeq[A, B],
@@ -639,30 +1205,32 @@ proc enlarge[A, B](t: var OrderedTable[A, B]) =
       rawInsert(t, t.data, n[h].key, n[h].val, n[h].hcode, j)
     h = nxt
 
-proc `[]=`*[A, B](t: var OrderedTable[A, B], key: A, val: B) =
-  ## puts a ``(key, value)`` pair into ``t``.
-  putImpl(enlarge)
-
-proc add*[A, B](t: var OrderedTable[A, B], key: A, val: B) =
-  ## puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists.
-  ## This can introduce duplicate keys into the table!
-  addImpl(enlarge)
+template forAllOrderedPairs(yieldStmt: untyped): typed {.dirty.} =
+  var h = t.first
+  while h >= 0:
+    var nxt = t.data[h].next
+    if isFilled(t.data[h].hcode): yieldStmt
+    h = nxt
 
-proc mgetOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): var B =
-  ## retrieves value at ``t[key]`` or puts ``value`` if not present, either way
-  ## returning a value which can be modified.
-  mgetOrPutImpl(enlarge)
-
-proc hasKeyOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): bool =
-  ## returns true iff ``key`` is in the table, otherwise inserts ``value``.
-  hasKeyOrPutImpl(enlarge)
+# ----------------------------------------------------------------------
 
 proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] =
-  ## creates a new ordered hash table that is empty.
+  ## Creates a new ordered hash table that is empty.
+  ##
+  ## ``initialSize`` must be a power of two (default: 64).
+  ## If you need to accept runtime values for this you could use the
+  ## `nextPowerOfTwo proc<math.html#nextPowerOfTwo,int>`_ from the
+  ## `math module<math.html>`_ or the `rightSize proc<#rightSize,Natural>`_
+  ## from this module.
   ##
-  ## ``initialSize`` needs to be a power of two. If you need to accept runtime
-  ## values for this you could use the ``nextPowerOfTwo`` proc from the
-  ## `math <math.html>`_ module or the ``rightSize`` proc from this module.
+  ## See also:
+  ## * `toOrderedTable proc<#toOrderedTable,openArray[]>`_
+  ## * `newOrderedTable proc<#newOrderedTable,int>`_ for creating an
+  ##   `OrderedTableRef`
+  runnableExamples:
+    let
+      a = initOrderedTable[int, string]()
+      b = initOrderedTable[char, seq[int]]()
   assert isPowerOfTwo(initialSize)
   result.counter = 0
   result.first = -1
@@ -670,36 +1238,250 @@ proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] =
   newSeq(result.data, initialSize)
 
 proc toOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTable[A, B] =
-  ## creates a new ordered hash table that contains the given ``pairs``.
+  ## Creates a new ordered hash table that contains the given ``pairs``.
+  ##
+  ## ``pairs`` is a container consisting of ``(key, value)`` tuples.
+  ##
+  ## See also:
+  ## * `initOrderedTable proc<#initOrderedTable,int>`_
+  ## * `newOrderedTable proc<#newOrderedTable,openArray[]>`_ for an
+  ##   `OrderedTableRef` version
+  runnableExamples:
+    let a = [('a', 5), ('b', 9)]
+    let b = toOrderedTable(a)
+    assert b == {'a': 5, 'b': 9}.toOrderedTable
   result = initOrderedTable[A, B](rightSize(pairs.len))
   for key, val in items(pairs): result[key] = val
 
-proc `$`*[A, B](t: OrderedTable[A, B]): string =
-  ## The ``$`` operator for ordered hash tables.
-  dollarImpl()
+proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B =
+  ## Retrieves the value at ``t[key]``.
+  ##
+  ## If ``key`` is not in ``t``, the  ``KeyError`` exception is raised.
+  ## One can check with `hasKey proc<#hasKey,OrderedTable[A,B],A>`_ whether
+  ## the key exists.
+  ##
+  ## See also:
+  ## * `getOrDefault proc<#getOrDefault,OrderedTable[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  ## * `getOrDefault proc<#getOrDefault,OrderedTable[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  ## * `[]= proc<#[]=,OrderedTable[A,B],A,B>`_ for inserting a new
+  ##   (key, value) pair in the table
+  ## * `hasKey proc<#hasKey,OrderedTable[A,B],A>`_ for checking if a
+  ##   key is in the table
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.toOrderedTable
+    doAssert a['a'] == 5
+    doAssertRaises(KeyError):
+      echo a['z']
+  get(t, key)
 
-proc `==`*[A, B](s, t: OrderedTable[A, B]): bool =
-  ## The ``==`` operator for ordered hash tables. Returns true iff both the
-  ## content and the order are equal.
-  if s.counter != t.counter:
-    return false
-  var ht = t.first
-  var hs = s.first
-  while ht >= 0 and hs >= 0:
-    var nxtt = t.data[ht].next
-    var nxts = s.data[hs].next
-    if isFilled(t.data[ht].hcode) and isFilled(s.data[hs].hcode):
-      if (s.data[hs].key != t.data[ht].key) or (s.data[hs].val != t.data[ht].val):
-        return false
-    ht = nxtt
-    hs = nxts
-  return true
+proc `[]`*[A, B](t: var OrderedTable[A, B], key: A): var B=
+  ## Retrieves the value at ``t[key]``. The value can be modified.
+  ##
+  ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised.
+  ##
+  ## See also:
+  ## * `getOrDefault proc<#getOrDefault,OrderedTable[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  ## * `getOrDefault proc<#getOrDefault,OrderedTable[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  ## * `[]= proc<#[]=,OrderedTable[A,B],A,B>`_ for inserting a new
+  ##   (key, value) pair in the table
+  ## * `hasKey proc<#hasKey,OrderedTable[A,B],A>`_ for checking if a
+  ##   key is in the table
+  get(t, key)
+
+proc `[]=`*[A, B](t: var OrderedTable[A, B], key: A, val: B) =
+  ## Inserts a ``(key, value)`` pair into ``t``.
+  ##
+  ## See also:
+  ## * `[] proc<#[],OrderedTable[A,B],A>`_ for retrieving a value of a key
+  ## * `hasKeyOrPut proc<#hasKeyOrPut,OrderedTable[A,B],A,B>`_
+  ## * `mgetOrPut proc<#mgetOrPut,OrderedTable[A,B],A,B>`_
+  ## * `del proc<#del,OrderedTable[A,B],A>`_ for removing a key from the table
+  runnableExamples:
+    var a = initOrderedTable[char, int]()
+    a['x'] = 7
+    a['y'] = 33
+    doAssert a == {'x': 7, 'y': 33}.toOrderedTable
+  putImpl(enlarge)
+
+proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool =
+  ## Returns true if ``key`` is in the table ``t``.
+  ##
+  ## See also:
+  ## * `contains proc<#contains,OrderedTable[A,B],A>`_ for use with the `in`
+  ##   operator
+  ## * `[] proc<#[],OrderedTable[A,B],A>`_ for retrieving a value of a key
+  ## * `getOrDefault proc<#getOrDefault,OrderedTable[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  ## * `getOrDefault proc<#getOrDefault,OrderedTable[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.toOrderedTable
+    doAssert a.hasKey('a') == true
+    doAssert a.hasKey('z') == false
+  var hc: Hash
+  result = rawGet(t, key, hc) >= 0
+
+proc contains*[A, B](t: OrderedTable[A, B], key: A): bool =
+  ## Alias of `hasKey proc<#hasKey,OrderedTable[A,B],A>`_ for use with
+  ## the ``in`` operator.
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.toOrderedTable
+    doAssert 'b' in a == true
+    doAssert a.contains('z') == false
+  return hasKey[A, B](t, key)
+
+proc hasKeyOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): bool =
+  ## Returns true if ``key`` is in the table, otherwise inserts ``value``.
+  ##
+  ## See also:
+  ## * `hasKey proc<#hasKey,OrderedTable[A,B],A>`_
+  ## * `[] proc<#[],OrderedTable[A,B],A>`_ for retrieving a value of a key
+  ## * `getOrDefault proc<#getOrDefault,OrderedTable[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  ## * `getOrDefault proc<#getOrDefault,OrderedTable[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  runnableExamples:
+    var a = {'a': 5, 'b': 9}.toOrderedTable
+    if a.hasKeyOrPut('a', 50):
+      a['a'] = 99
+    if a.hasKeyOrPut('z', 50):
+      a['z'] = 99
+    doAssert a == {'a': 99, 'b': 9, 'z': 50}.toOrderedTable
+  hasKeyOrPutImpl(enlarge)
+
+proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A): B =
+  ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``. Otherwise, the
+  ## default initialization value for type ``B`` is returned (e.g. 0 for any
+  ## integer type).
+  ##
+  ## See also:
+  ## * `[] proc<#[],OrderedTable[A,B],A>`_ for retrieving a value of a key
+  ## * `hasKey proc<#hasKey,OrderedTable[A,B],A>`_
+  ## * `hasKeyOrPut proc<#hasKeyOrPut,OrderedTable[A,B],A,B>`_
+  ## * `mgetOrPut proc<#mgetOrPut,OrderedTable[A,B],A,B>`_
+  ## * `getOrDefault proc<#getOrDefault,OrderedTable[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.toOrderedTable
+    doAssert a.getOrDefault('a') == 5
+    doAssert a.getOrDefault('z') == 0
+  getOrDefaultImpl(t, key)
+
+proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A, default: B): B =
+  ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``.
+  ## Otherwise, ``default`` is returned.
+  ##
+  ## See also:
+  ## * `[] proc<#[],OrderedTable[A,B],A>`_ for retrieving a value of a key
+  ## * `hasKey proc<#hasKey,OrderedTable[A,B],A>`_
+  ## * `hasKeyOrPut proc<#hasKeyOrPut,OrderedTable[A,B],A,B>`_
+  ## * `mgetOrPut proc<#mgetOrPut,OrderedTable[A,B],A,B>`_
+  ## * `getOrDefault proc<#getOrDefault,OrderedTable[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.toOrderedTable
+    doAssert a.getOrDefault('a', 99) == 5
+    doAssert a.getOrDefault('z', 99) == 99
+  getOrDefaultImpl(t, key, default)
+
+proc mgetOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): var B =
+  ## Retrieves value at ``t[key]`` or puts ``val`` if not present, either way
+  ## returning a value which can be modified.
+  ##
+  ## See also:
+  ## * `[] proc<#[],OrderedTable[A,B],A>`_ for retrieving a value of a key
+  ## * `hasKey proc<#hasKey,OrderedTable[A,B],A>`_
+  ## * `hasKeyOrPut proc<#hasKeyOrPut,OrderedTable[A,B],A,B>`_
+  ## * `getOrDefault proc<#getOrDefault,OrderedTable[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  ## * `getOrDefault proc<#getOrDefault,OrderedTable[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  runnableExamples:
+    var a = {'a': 5, 'b': 9}.toOrderedTable
+    doAssert a.mgetOrPut('a', 99) == 5
+    doAssert a.mgetOrPut('z', 99) == 99
+    doAssert a == {'a': 5, 'b': 9, 'z': 99}.toOrderedTable
+  mgetOrPutImpl(enlarge)
+
+proc len*[A, B](t: OrderedTable[A, B]): int {.inline.} =
+  ## Returns the number of keys in ``t``.
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.toOrderedTable
+    doAssert len(a) == 2
+  result = t.counter
+
+proc add*[A, B](t: var OrderedTable[A, B], key: A, val: B) =
+  ## Puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists.
+  ##
+  ## **This can introduce duplicate keys into the table!**
+  ##
+  ## Use `[]= proc<#[]=,OrderedTable[A,B],A,B>`_ for inserting a new
+  ## (key, value) pair in the table without introducing duplicates.
+  addImpl(enlarge)
+
+proc del*[A, B](t: var OrderedTable[A, B], key: A) =
+  ## Deletes ``key`` from hash table ``t``. Does nothing if the key does not exist.
+  ##
+  ## O(n) complexity.
+  ##
+  ## See also:
+  ## * `clear proc<#clear,OrderedTable[A,B]>`_ to empty the whole table
+  runnableExamples:
+    var a = {'a': 5, 'b': 9, 'c': 13}.toOrderedTable
+    a.del('a')
+    doAssert a == {'b': 9, 'c': 13}.toOrderedTable
+    a.del('z')
+    doAssert a == {'b': 9, 'c': 13}.toOrderedTable
+  var n: OrderedKeyValuePairSeq[A, B]
+  newSeq(n, len(t.data))
+  var h = t.first
+  t.first = -1
+  t.last = -1
+  swap(t.data, n)
+  let hc = genHash(key)
+  while h >= 0:
+    var nxt = n[h].next
+    if isFilled(n[h].hcode):
+      if n[h].hcode == hc and n[h].key == key:
+        dec t.counter
+      else:
+        var j = -1 - rawGetKnownHC(t, n[h].key, n[h].hcode)
+        rawInsert(t, t.data, n[h].key, n[h].val, n[h].hcode, j)
+    h = nxt
+
+proc clear*[A, B](t: var OrderedTable[A, B]) =
+  ## Resets the table so that it is empty.
+  ##
+  ## See also:
+  ## * `del proc<#del,OrderedTable[A,B],A>`_
+  runnableExamples:
+    var a = {'a': 5, 'b': 9, 'c': 13}.toOrderedTable
+    doAssert len(a) == 3
+    clear(a)
+    doAssert len(a) == 0
+  clearImpl()
+  t.first = -1
+  t.last = -1
 
 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
+  ## Sorts ``t`` according to the function ``cmp``.
+  ##
+  ## This modifies the internal list
   ## that kept the insertion order, so insertion order is lost after this
   ## call but key lookup and insertions remain possible after ``sort`` (in
-  ## contrast to the ``sort`` for count tables).
+  ## contrast to the `sort proc<#sort,CountTable[A]>`_ for count tables).
+  runnableExamples:
+    var a = initOrderedTable[char, int]()
+    for i, c in "cab":
+      a[c] = 10*i
+    doAssert a == {'c': 0, 'a': 10, 'b': 20}.toOrderedTable
+    a.sort(system.cmp)
+    doAssert a == {'a': 10, 'b': 20, 'c': 0}.toOrderedTable
+
   var list = t.first
   var
     p, q, e, tail, oldhead: int
@@ -740,244 +1522,519 @@ proc sort*[A, B](t: var OrderedTable[A, B], cmp: proc (x,y: (A, B)): int) =
   t.first = list
   t.last = tail
 
-proc len*[A, B](t: OrderedTableRef[A, B]): int {.inline.} =
-  ## returns the number of keys in ``t``.
-  result = t.counter
+proc `$`*[A, B](t: OrderedTable[A, B]): string =
+  ## The ``$`` operator for ordered hash tables. Used internally when calling
+  ## `echo` on a table.
+  dollarImpl()
 
-iterator pairs*[A, B](t: OrderedTableRef[A, B]): (A, B) =
-  ## iterates over any ``(key, value)`` pair in the table ``t`` in insertion
+proc `==`*[A, B](s, t: OrderedTable[A, B]): bool =
+  ## The ``==`` operator for ordered hash tables. Returns ``true`` if both the
+  ## content and the order are equal.
+  runnableExamples:
+    let
+      a = {'a': 5, 'b': 9, 'c': 13}.toOrderedTable
+      b = {'b': 9, 'c': 13, 'a': 5}.toOrderedTable
+    doAssert a != b
+
+  if s.counter != t.counter:
+    return false
+  var ht = t.first
+  var hs = s.first
+  while ht >= 0 and hs >= 0:
+    var nxtt = t.data[ht].next
+    var nxts = s.data[hs].next
+    if isFilled(t.data[ht].hcode) and isFilled(s.data[hs].hcode):
+      if (s.data[hs].key != t.data[ht].key) or (s.data[hs].val != t.data[ht].val):
+        return false
+    ht = nxtt
+    hs = nxts
+  return true
+
+
+
+iterator pairs*[A, B](t: OrderedTable[A, B]): (A, B) =
+  ## Iterates over any ``(key, value)`` pair in the table ``t`` in insertion
   ## order.
+  ##
+  ## See also:
+  ## * `mpairs iterator<#mpairs.i,OrderedTable[A,B]>`_
+  ## * `keys iterator<#keys.i,OrderedTable[A,B]>`_
+  ## * `values iterator<#values.i,OrderedTable[A,B]>`_
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   let a = {
+  ##     'o': [1, 5, 7, 9],
+  ##     'e': [2, 4, 6, 8]
+  ##     }.toOrderedTable
+  ##
+  ##   for k, v in a.pairs:
+  ##     echo "key: ", k
+  ##     echo "value: ", v
+  ##
+  ##   # key: o
+  ##   # value: [1, 5, 7, 9]
+  ##   # key: e
+  ##   # value: [2, 4, 6, 8]
   forAllOrderedPairs:
     yield (t.data[h].key, t.data[h].val)
 
-iterator mpairs*[A, B](t: OrderedTableRef[A, B]): (A, var B) =
-  ## iterates over any ``(key, value)`` pair in the table ``t`` in insertion
-  ## order. The values can be modified.
+iterator mpairs*[A, B](t: var OrderedTable[A, B]): (A, var B) =
+  ## Iterates over any ``(key, value)`` pair in the table ``t`` (must be
+  ## declared as `var`) in insertion order. The values can be modified.
+  ##
+  ## See also:
+  ## * `pairs iterator<#pairs.i,OrderedTable[A,B]>`_
+  ## * `mvalues iterator<#mvalues.i,OrderedTable[A,B]>`_
+  runnableExamples:
+    var a = {
+      'o': @[1, 5, 7, 9],
+      'e': @[2, 4, 6, 8]
+      }.toOrderedTable
+    for k, v in a.mpairs:
+      v.add(v[0] + 10)
+    doAssert a == {'o': @[1, 5, 7, 9, 11], 'e': @[2, 4, 6, 8, 12]}.toOrderedTable
   forAllOrderedPairs:
     yield (t.data[h].key, t.data[h].val)
 
-iterator keys*[A, B](t: OrderedTableRef[A, B]): A =
-  ## iterates over any key in the table ``t`` in insertion order.
+iterator keys*[A, B](t: OrderedTable[A, B]): A =
+  ## Iterates over any key in the table ``t`` in insertion order.
+  ##
+  ## See also:
+  ## * `pairs iterator<#pairs.i,OrderedTable[A,B]>`_
+  ## * `values iterator<#values.i,OrderedTable[A,B]>`_
+  runnableExamples:
+    var a = {
+      'o': @[1, 5, 7, 9],
+      'e': @[2, 4, 6, 8]
+      }.toOrderedTable
+    for k in a.keys:
+      a[k].add(99)
+    doAssert a == {'o': @[1, 5, 7, 9, 99], 'e': @[2, 4, 6, 8, 99]}.toOrderedTable
   forAllOrderedPairs:
     yield t.data[h].key
 
-iterator values*[A, B](t: OrderedTableRef[A, B]): B =
-  ## iterates over any value in the table ``t`` in insertion order.
+iterator values*[A, B](t: OrderedTable[A, B]): B =
+  ## Iterates over any value in the table ``t`` in insertion order.
+  ##
+  ## See also:
+  ## * `pairs iterator<#pairs.i,OrderedTable[A,B]>`_
+  ## * `keys iterator<#keys.i,OrderedTable[A,B]>`_
+  ## * `mvalues iterator<#mvalues.i,OrderedTable[A,B]>`_
+  runnableExamples:
+    let a = {
+      'o': @[1, 5, 7, 9],
+      'e': @[2, 4, 6, 8]
+      }.toOrderedTable
+    for v in a.values:
+      doAssert v.len == 4
   forAllOrderedPairs:
     yield t.data[h].val
 
-iterator mvalues*[A, B](t: OrderedTableRef[A, B]): var B =
-  ## iterates over any value in the table ``t`` in insertion order. The values
+iterator mvalues*[A, B](t: var OrderedTable[A, B]): var B =
+  ## Iterates over any value in the table ``t`` (must be
+  ## declared as `var`) in insertion order. The values
   ## can be modified.
+  ##
+  ## See also:
+  ## * `mpairs iterator<#mpairs.i,OrderedTable[A,B]>`_
+  ## * `values iterator<#values.i,OrderedTable[A,B]>`_
+  runnableExamples:
+    var a = {
+      'o': @[1, 5, 7, 9],
+      'e': @[2, 4, 6, 8]
+      }.toOrderedTable
+    for v in a.mvalues:
+      v.add(99)
+    doAssert a == {'o': @[1, 5, 7, 9, 99], 'e': @[2, 4, 6, 8, 99]}.toOrderedTable
   forAllOrderedPairs:
     yield t.data[h].val
 
+
+
+
+
+# ---------------------------------------------------------------------------
+# --------------------------- OrderedTableRef -------------------------------
+# ---------------------------------------------------------------------------
+
+proc newOrderedTable*[A, B](initialSize=64): OrderedTableRef[A, B] =
+  ## Creates a new ordered ref hash table that is empty.
+  ##
+  ## ``initialSize`` must be a power of two (default: 64).
+  ## If you need to accept runtime values for this you could use the
+  ## `nextPowerOfTwo proc<math.html#nextPowerOfTwo,int>`_ from the
+  ## `math module<math.html>`_ or the `rightSize proc<#rightSize,Natural>`_
+  ## from this module.
+  ##
+  ## See also:
+  ## * `newOrderedTable proc<#newOrderedTable,openArray[]>`_ for creating
+  ##   an `OrderedTableRef` from a collection of `(key, value)` pairs
+  ## * `initOrderedTable proc<#initOrderedTable,int>`_ for creating an
+  ##   `OrderedTable`
+  runnableExamples:
+    let
+      a = newOrderedTable[int, string]()
+      b = newOrderedTable[char, seq[int]]()
+  new(result)
+  result[] = initOrderedTable[A, B](initialSize)
+
+proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTableRef[A, B] =
+  ## Creates a new ordered ref hash table that contains the given ``pairs``.
+  ##
+  ## ``pairs`` is a container consisting of ``(key, value)`` tuples.
+  ##
+  ## See also:
+  ## * `newOrderedTable proc<#newOrderedTable,int>`_
+  ## * `toOrderedTable proc<#toOrderedTable,openArray[]>`_ for an
+  ##   `OrderedTable` version
+  runnableExamples:
+    let a = [('a', 5), ('b', 9)]
+    let b = newOrderedTable(a)
+    assert b == {'a': 5, 'b': 9}.newOrderedTable
+  result = newOrderedTable[A, B](rightSize(pairs.len))
+  for key, val in items(pairs): result.add(key, val)
+
+
 proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): var B =
-  ## retrieves the value at ``t[key]``. If ``key`` is not in ``t``, the
-  ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether
+  ## Retrieves the value at ``t[key]``.
+  ##
+  ## If ``key`` is not in ``t``, the  ``KeyError`` exception is raised.
+  ## One can check with `hasKey proc<#hasKey,OrderedTableRef[A,B],A>`_ whether
   ## the key exists.
+  ##
+  ## See also:
+  ## * `getOrDefault proc<#getOrDefault,OrderedTableRef[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  ## * `getOrDefault proc<#getOrDefault,OrderedTableRef[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  ## * `[]= proc<#[]=,OrderedTableRef[A,B],A,B>`_ for inserting a new
+  ##   (key, value) pair in the table
+  ## * `hasKey proc<#hasKey,OrderedTableRef[A,B],A>`_ for checking if
+  ##   a key is in the table
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.newOrderedTable
+    doAssert a['a'] == 5
+    doAssertRaises(KeyError):
+      echo a['z']
   result = t[][key]
 
-proc mget*[A, B](t: OrderedTableRef[A, B], key: A): var B {.deprecated.} =
-  ## retrieves the value at ``t[key]``. The value can be modified.
-  ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised.
-  ## Use ``[]`` instead.
-  result = t[][key]
+proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: A, val: B) =
+  ## Inserts a ``(key, value)`` pair into ``t``.
+  ##
+  ## See also:
+  ## * `[] proc<#[],OrderedTableRef[A,B],A>`_ for retrieving a value of a key
+  ## * `hasKeyOrPut proc<#hasKeyOrPut,OrderedTableRef[A,B],A,B>`_
+  ## * `mgetOrPut proc<#mgetOrPut,OrderedTableRef[A,B],A,B>`_
+  ## * `del proc<#del,OrderedTableRef[A,B],A>`_ for removing a key from the table
+  runnableExamples:
+    var a = newOrderedTable[char, int]()
+    a['x'] = 7
+    a['y'] = 33
+    doAssert a == {'x': 7, 'y': 33}.newOrderedTable
+  t[][key] = val
+
+proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool =
+  ## Returns true if ``key`` is in the table ``t``.
+  ##
+  ## See also:
+  ## * `contains proc<#contains,OrderedTableRef[A,B],A>`_ for use with the `in`
+  ##   operator
+  ## * `[] proc<#[],OrderedTableRef[A,B],A>`_ for retrieving a value of a key
+  ## * `getOrDefault proc<#getOrDefault,OrderedTableRef[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  ## * `getOrDefault proc<#getOrDefault,OrderedTableRef[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.newOrderedTable
+    doAssert a.hasKey('a') == true
+    doAssert a.hasKey('z') == false
+  result = t[].hasKey(key)
+
+proc contains*[A, B](t: OrderedTableRef[A, B], key: A): bool =
+  ## Alias of `hasKey proc<#hasKey,OrderedTableRef[A,B],A>`_ for use with
+  ## the ``in`` operator.
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.newOrderedTable
+    doAssert 'b' in a == true
+    doAssert a.contains('z') == false
+  return hasKey[A, B](t, key)
+
+proc hasKeyOrPut*[A, B](t: var OrderedTableRef[A, B], key: A, val: B): bool =
+  ## Returns true if ``key`` is in the table, otherwise inserts ``value``.
+  ##
+  ## See also:
+  ## * `hasKey proc<#hasKey,OrderedTableRef[A,B],A>`_
+  ## * `[] proc<#[],OrderedTableRef[A,B],A>`_ for retrieving a value of a key
+  ## * `getOrDefault proc<#getOrDefault,OrderedTableRef[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  ## * `getOrDefault proc<#getOrDefault,OrderedTableRef[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  runnableExamples:
+    var a = {'a': 5, 'b': 9}.newOrderedTable
+    if a.hasKeyOrPut('a', 50):
+      a['a'] = 99
+    if a.hasKeyOrPut('z', 50):
+      a['z'] = 99
+    doAssert a == {'a': 99, 'b': 9, 'z': 50}.newOrderedTable
+  result = t[].hasKeyOrPut(key, val)
 
 proc getOrDefault*[A, B](t: OrderedTableRef[A, B], key: A): B =
-  ## retrieves the value at ``t[key]`` iff ``key`` is in ``t``. Otherwise, the
+  ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``. Otherwise, the
   ## default initialization value for type ``B`` is returned (e.g. 0 for any
   ## integer type).
+  ##
+  ## See also:
+  ## * `[] proc<#[],OrderedTableRef[A,B],A>`_ for retrieving a value of a key
+  ## * `hasKey proc<#hasKey,OrderedTableRef[A,B],A>`_
+  ## * `hasKeyOrPut proc<#hasKeyOrPut,OrderedTableRef[A,B],A,B>`_
+  ## * `mgetOrPut proc<#mgetOrPut,OrderedTableRef[A,B],A,B>`_
+  ## * `getOrDefault proc<#getOrDefault,OrderedTableRef[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.newOrderedTable
+    doAssert a.getOrDefault('a') == 5
+    doAssert a.getOrDefault('z') == 0
   getOrDefault(t[], key)
 
 proc getOrDefault*[A, B](t: OrderedTableRef[A, B], key: A, default: B): B =
-  ## retrieves the value at ``t[key]`` iff ``key`` is in ``t``. Otherwise,
-  ## ``default`` is returned.
+  ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``.
+  ## Otherwise, ``default`` is returned.
+  ##
+  ## See also:
+  ## * `[] proc<#[],OrderedTableRef[A,B],A>`_ for retrieving a value of a key
+  ## * `hasKey proc<#hasKey,OrderedTableRef[A,B],A>`_
+  ## * `hasKeyOrPut proc<#hasKeyOrPut,OrderedTableRef[A,B],A,B>`_
+  ## * `mgetOrPut proc<#mgetOrPut,OrderedTableRef[A,B],A,B>`_
+  ## * `getOrDefault proc<#getOrDefault,OrderedTableRef[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.newOrderedTable
+    doAssert a.getOrDefault('a', 99) == 5
+    doAssert a.getOrDefault('z', 99) == 99
   getOrDefault(t[], key, default)
 
 proc mgetOrPut*[A, B](t: OrderedTableRef[A, B], key: A, val: B): var B =
-  ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
+  ## Retrieves value at ``t[key]`` or puts ``val`` if not present, either way
   ## returning a value which can be modified.
+  ##
+  ## See also:
+  ## * `[] proc<#[],OrderedTableRef[A,B],A>`_ for retrieving a value of a key
+  ## * `hasKey proc<#hasKey,OrderedTableRef[A,B],A>`_
+  ## * `hasKeyOrPut proc<#hasKeyOrPut,OrderedTableRef[A,B],A,B>`_
+  ## * `getOrDefault proc<#getOrDefault,OrderedTableRef[A,B],A>`_ to return
+  ##   a default value (e.g. zero for int) if the key doesn't exist
+  ## * `getOrDefault proc<#getOrDefault,OrderedTableRef[A,B],A,B>`_ to return
+  ##   a custom value if the key doesn't exist
+  runnableExamples:
+    var a = {'a': 5, 'b': 9}.newOrderedTable
+    doAssert a.mgetOrPut('a', 99) == 5
+    doAssert a.mgetOrPut('z', 99) == 99
+    doAssert a == {'a': 5, 'b': 9, 'z': 99}.newOrderedTable
   result = t[].mgetOrPut(key, val)
 
-proc hasKeyOrPut*[A, B](t: var OrderedTableRef[A, B], key: A, val: B): bool =
-  ## returns true iff ``key`` is in the table, otherwise inserts ``val``.
-  result = t[].hasKeyOrPut(key, val)
-
-proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool =
-  ## returns true iff ``key`` is in the table ``t``.
-  result = t[].hasKey(key)
-
-proc contains*[A, B](t: OrderedTableRef[A, B], key: A): bool =
-  ## Alias of ``hasKey`` for use with the ``in`` operator.
-  return hasKey[A, B](t, key)
-
-proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: A, val: B) =
-  ## puts a ``(key, value)`` pair into ``t``.
-  t[][key] = val
+proc len*[A, B](t: OrderedTableRef[A, B]): int {.inline.} =
+  ## Returns the number of keys in ``t``.
+  runnableExamples:
+    let a = {'a': 5, 'b': 9}.newOrderedTable
+    doAssert len(a) == 2
+  result = t.counter
 
 proc add*[A, B](t: OrderedTableRef[A, B], key: A, val: B) =
-  ## puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists.
-  ## This can introduce duplicate keys into the table!
+  ## Puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists.
+  ##
+  ## **This can introduce duplicate keys into the table!**
+  ##
+  ## Use `[]= proc<#[]=,OrderedTableRef[A,B],A,B>`_ for inserting a new
+  ## (key, value) pair in the table without introducing duplicates.
   t[].add(key, val)
 
-proc newOrderedTable*[A, B](initialSize=64): OrderedTableRef[A, B] =
-  ## creates a new ordered hash table that is empty.
+proc del*[A, B](t: var OrderedTableRef[A, B], key: A) =
+  ## Deletes ``key`` from hash table ``t``. Does nothing if the key does not exist.
   ##
-  ## ``initialSize`` needs to be a power of two. If you need to accept runtime
-  ## values for this you could use the ``nextPowerOfTwo`` proc from the
-  ## `math <math.html>`_ module or the ``rightSize`` proc from this module.
-  new(result)
-  result[] = initOrderedTable[A, B](initialSize)
+  ## See also:
+  ## * `clear proc<#clear,OrderedTableRef[A,B]>`_ to empty the whole table
+  runnableExamples:
+    var a = {'a': 5, 'b': 9, 'c': 13}.newOrderedTable
+    a.del('a')
+    doAssert a == {'b': 9, 'c': 13}.newOrderedTable
+    a.del('z')
+    doAssert a == {'b': 9, 'c': 13}.newOrderedTable
+  t[].del(key)
 
-proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTableRef[A, B] =
-  ## creates a new ordered hash table that contains the given ``pairs``.
-  result = newOrderedTable[A, B](rightSize(pairs.len))
-  for key, val in items(pairs): result.add(key, val)
+proc clear*[A, B](t: var OrderedTableRef[A, B]) =
+  ## Resets the table so that it is empty.
+  ##
+  ## See also:
+  ## * `del proc<#del,OrderedTable[A,B],A>`_
+  runnableExamples:
+    var a = {'a': 5, 'b': 9, 'c': 13}.newOrderedTable
+    doAssert len(a) == 3
+    clear(a)
+    doAssert len(a) == 0
+  clear(t[])
+
+proc sort*[A, B](t: OrderedTableRef[A, B], cmp: proc (x,y: (A, B)): int) =
+  ## Sorts ``t`` according to the function ``cmp``.
+  ##
+  ## This modifies the internal list
+  ## that kept the insertion order, so insertion order is lost after this
+  ## call but key lookup and insertions remain possible after ``sort`` (in
+  ## contrast to the `sort proc<#sort,CountTableRef[A]>`_ for count tables).
+  runnableExamples:
+    var a = newOrderedTable[char, int]()
+    for i, c in "cab":
+      a[c] = 10*i
+    doAssert a == {'c': 0, 'a': 10, 'b': 20}.newOrderedTable
+    a.sort(system.cmp)
+    doAssert a == {'a': 10, 'b': 20, 'c': 0}.newOrderedTable
+  t[].sort(cmp)
 
 proc `$`*[A, B](t: OrderedTableRef[A, B]): string =
-  ## The ``$`` operator for ordered hash tables.
+  ## The ``$`` operator for hash tables. Used internally when calling `echo`
+  ## on a table.
   dollarImpl()
 
 proc `==`*[A, B](s, t: OrderedTableRef[A, B]): bool =
-  ## The ``==`` operator for ordered hash tables. Returns true iff either both
-  ## tables are ``nil`` or none is ``nil`` and the content and the order of
+  ## The ``==`` operator for ordered hash tables. Returns true if either both
+  ## tables are ``nil``, or neither is ``nil`` and the content and the order of
   ## both are equal.
+  runnableExamples:
+    let
+      a = {'a': 5, 'b': 9, 'c': 13}.newOrderedTable
+      b = {'b': 9, 'c': 13, 'a': 5}.newOrderedTable
+    doAssert a != b
   if isNil(s): result = isNil(t)
   elif isNil(t): result = false
   else: result = s[] == t[]
 
-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
-  ## call but key lookup and insertions remain possible after ``sort`` (in
-  ## contrast to the ``sort`` for count tables).
-  t[].sort(cmp)
-
-proc del*[A, B](t: var OrderedTable[A, B], key: A) =
-  ## deletes ``key`` from ordered hash table ``t``. O(n) complexity. Does nothing
-  ## if the key does not exist.
-  var n: OrderedKeyValuePairSeq[A, B]
-  newSeq(n, len(t.data))
-  var h = t.first
-  t.first = -1
-  t.last = -1
-  swap(t.data, n)
-  let hc = genHash(key)
-  while h >= 0:
-    var nxt = n[h].next
-    if isFilled(n[h].hcode):
-      if n[h].hcode == hc and n[h].key == key:
-        dec t.counter
-      else:
-        var j = -1 - rawGetKnownHC(t, n[h].key, n[h].hcode)
-        rawInsert(t, t.data, n[h].key, n[h].val, n[h].hcode, j)
-    h = nxt
-
-proc del*[A, B](t: var OrderedTableRef[A, B], key: A) =
-  ## deletes ``key`` from ordered hash table ``t``. O(n) complexity.  Does nothing
-  ## if the key does not exist.
-  t[].del(key)
-
-# ------------------------------ count tables -------------------------------
-
-type
-  CountTable* [
-      A] = object ## table that counts the number of each key
-    data: seq[tuple[key: A, val: int]]
-    counter: int
-  CountTableRef*[A] = ref CountTable[A]
-
-proc len*[A](t: CountTable[A]): int =
-  ## returns the number of keys in ``t``.
-  result = t.counter
 
-proc clear*[A](t: CountTableRef[A]) =
-  ## resets the table so that it is empty.
-  clearImpl()
 
-proc clear*[A](t: var CountTable[A]) =
-  ## resets the table so that it is empty.
-  clearImpl()
+iterator pairs*[A, B](t: OrderedTableRef[A, B]): (A, B) =
+  ## Iterates over any ``(key, value)`` pair in the table ``t`` in insertion
+  ## order.
+  ##
+  ## See also:
+  ## * `mpairs iterator<#mpairs.i,OrderedTableRef[A,B]>`_
+  ## * `keys iterator<#keys.i,OrderedTableRef[A,B]>`_
+  ## * `values iterator<#values.i,OrderedTableRef[A,B]>`_
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   let a = {
+  ##     'o': [1, 5, 7, 9],
+  ##     'e': [2, 4, 6, 8]
+  ##     }.newOrderedTable
+  ##
+  ##   for k, v in a.pairs:
+  ##     echo "key: ", k
+  ##     echo "value: ", v
+  ##
+  ##   # key: o
+  ##   # value: [1, 5, 7, 9]
+  ##   # key: e
+  ##   # value: [2, 4, 6, 8]
+  forAllOrderedPairs:
+    yield (t.data[h].key, t.data[h].val)
 
-iterator pairs*[A](t: CountTable[A]): (A, int) =
-  ## iterates over any ``(key, value)`` pair in the table ``t``.
-  for h in 0..high(t.data):
-    if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
+iterator mpairs*[A, B](t: OrderedTableRef[A, B]): (A, var B) =
+  ## Iterates over any ``(key, value)`` pair in the table ``t`` in insertion
+  ## order. The values can be modified.
+  ##
+  ## See also:
+  ## * `pairs iterator<#pairs.i,OrderedTableRef[A,B]>`_
+  ## * `mvalues iterator<#mvalues.i,OrderedTableRef[A,B]>`_
+  runnableExamples:
+    let a = {
+      'o': @[1, 5, 7, 9],
+      'e': @[2, 4, 6, 8]
+      }.newOrderedTable
+    for k, v in a.mpairs:
+      v.add(v[0] + 10)
+    doAssert a == {'o': @[1, 5, 7, 9, 11], 'e': @[2, 4, 6, 8, 12]}.newOrderedTable
+  forAllOrderedPairs:
+    yield (t.data[h].key, t.data[h].val)
 
-iterator mpairs*[A](t: var CountTable[A]): (A, var int) =
-  ## iterates over any ``(key, value)`` pair in the table ``t``. The values can
-  ## be modified.
-  for h in 0..high(t.data):
-    if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
+iterator keys*[A, B](t: OrderedTableRef[A, B]): A =
+  ## Iterates over any key in the table ``t`` in insertion order.
+  ##
+  ## See also:
+  ## * `pairs iterator<#pairs.i,OrderedTableRef[A,B]>`_
+  ## * `values iterator<#values.i,OrderedTableRef[A,B]>`_
+  runnableExamples:
+    let a = {
+      'o': @[1, 5, 7, 9],
+      'e': @[2, 4, 6, 8]
+      }.newOrderedTable
+    for k in a.keys:
+      a[k].add(99)
+    doAssert a == {'o': @[1, 5, 7, 9, 99], 'e': @[2, 4, 6, 8, 99]}.newOrderedTable
+  forAllOrderedPairs:
+    yield t.data[h].key
 
-iterator keys*[A](t: CountTable[A]): A =
-  ## iterates over any key in the table ``t``.
-  for h in 0..high(t.data):
-    if t.data[h].val != 0: yield t.data[h].key
+iterator values*[A, B](t: OrderedTableRef[A, B]): B =
+  ## Iterates over any value in the table ``t`` in insertion order.
+  ##
+  ## See also:
+  ## * `pairs iterator<#pairs.i,OrderedTableRef[A,B]>`_
+  ## * `keys iterator<#keys.i,OrderedTableRef[A,B]>`_
+  ## * `mvalues iterator<#mvalues.i,OrderedTableRef[A,B]>`_
+  runnableExamples:
+    let a = {
+      'o': @[1, 5, 7, 9],
+      'e': @[2, 4, 6, 8]
+      }.newOrderedTable
+    for v in a.values:
+      doAssert v.len == 4
+  forAllOrderedPairs:
+    yield t.data[h].val
 
-iterator values*[A](t: CountTable[A]): int =
-  ## iterates over any value in the table ``t``.
-  for h in 0..high(t.data):
-    if t.data[h].val != 0: yield t.data[h].val
+iterator mvalues*[A, B](t: OrderedTableRef[A, B]): var B =
+  ## Iterates over any value in the table ``t`` in insertion order. The values
+  ## can be modified.
+  ##
+  ## See also:
+  ## * `mpairs iterator<#mpairs.i,OrderedTableRef[A,B]>`_
+  ## * `values iterator<#values.i,OrderedTableRef[A,B]>`_
+  runnableExamples:
+    let a = {
+      'o': @[1, 5, 7, 9],
+      'e': @[2, 4, 6, 8]
+      }.newOrderedTable
+    for v in a.mvalues:
+      v.add(99)
+    doAssert a == {'o': @[1, 5, 7, 9, 99], 'e': @[2, 4, 6, 8, 99]}.newOrderedTable
+  forAllOrderedPairs:
+    yield t.data[h].val
 
-iterator mvalues*[A](t: CountTable[A]): var int =
-  ## iterates over any value in the table ``t``. The values can be modified.
-  for h in 0..high(t.data):
-    if t.data[h].val != 0: yield t.data[h].val
 
-proc rawGet[A](t: CountTable[A], key: A): int =
-  var h: Hash = hash(key) and high(t.data) # start with real hash value
-  while t.data[h].val != 0:
-    if t.data[h].key == key: return h
-    h = nextTry(h, high(t.data))
-  result = -1 - h                   # < 0 => MISSING; insert idx = -1 - result
 
-template ctget(t, key: untyped): untyped =
-  var index = rawGet(t, key)
-  if index >= 0: result = t.data[index].val
-  else:
-    when compiles($key):
-      raise newException(KeyError, "key not found: " & $key)
-    else:
-      raise newException(KeyError, "key not found")
 
-proc `[]`*[A](t: CountTable[A], key: A): int {.deprecatedGet.} =
-  ## retrieves the value at ``t[key]``. If ``key`` is not in ``t``,
-  ## the ``KeyError`` exception is raised. One can check with ``hasKey``
-  ## whether the key exists.
-  ctget(t, key)
 
-proc `[]`*[A](t: var CountTable[A], key: A): var int {.deprecatedGet.} =
-  ## retrieves the value at ``t[key]``. The value can be modified.
-  ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised.
-  ctget(t, key)
 
-proc mget*[A](t: var CountTable[A], key: A): var int {.deprecated.} =
-  ## retrieves the value at ``t[key]``. The value can be modified.
-  ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised.
-  ## Use ``[]`` instead.
-  ctget(t, key)
 
-proc getOrDefault*[A](t: CountTable[A], key: A): int =
-  ## retrieves the value at ``t[key]`` iff ``key`` is in ``t``. Otherwise, 0 (the
-  ## default initialization value of ``int``), is returned.
-  var index = rawGet(t, key)
-  if index >= 0: result = t.data[index].val
+# -------------------------------------------------------------------------
+# ------------------------------ CountTable -------------------------------
+# -------------------------------------------------------------------------
 
-proc getOrDefault*[A](t: CountTable[A], key: A, default: int): int =
-  ## retrieves the value at ``t[key]`` iff ``key`` is in ``t``. Otherwise, the
-  ## integer value of ``default`` is returned.
-  var index = rawGet(t, key)
-  result = if index >= 0: t.data[index].val else: default
+type
+  CountTable* [A] = object
+    ## Hash table that counts the number of each key.
+    ##
+    ## For creating an empty CountTable, use `initCountTable proc
+    ## <#initCountTable,int>`_.
+    data: seq[tuple[key: A, val: int]]
+    counter: int
+  CountTableRef*[A] = ref CountTable[A] ## Ref version of
+    ## `CountTable<#CountTable>`_.
+    ##
+    ## For creating a new empty CountTableRef, use `newCountTable proc
+    ## <#newCountTable,int>`_.
 
-proc hasKey*[A](t: CountTable[A], key: A): bool =
-  ## returns true iff ``key`` is in the table ``t``.
-  result = rawGet(t, key) >= 0
 
-proc contains*[A](t: CountTable[A], key: A): bool =
-  ## Alias of ``hasKey`` for use with the ``in`` operator.
-  return hasKey[A](t, key)
+# ------------------------------ helpers ---------------------------------
 
 proc rawInsert[A](t: CountTable[A], data: var seq[tuple[key: A, val: int]],
                   key: A, val: int) =
@@ -993,22 +2050,87 @@ proc enlarge[A](t: var CountTable[A]) =
     if t.data[i].val != 0: rawInsert(t, n, t.data[i].key, t.data[i].val)
   swap(t.data, n)
 
+proc rawGet[A](t: CountTable[A], key: A): int =
+  var h: Hash = hash(key) and high(t.data) # start with real hash value
+  while t.data[h].val != 0:
+    if t.data[h].key == key: return h
+    h = nextTry(h, high(t.data))
+  result = -1 - h                   # < 0 => MISSING; insert idx = -1 - result
+
+template ctget(t, key, default: untyped): untyped =
+  var index = rawGet(t, key)
+  result = if index >= 0: t.data[index].val else: default
+
+proc inc*[A](t: var CountTable[A], key: A, val = 1)
+
+# ----------------------------------------------------------------------
+
+proc initCountTable*[A](initialSize=64): CountTable[A] =
+  ## Creates a new count table that is empty.
+  ##
+  ## ``initialSize`` must be a power of two (default: 64).
+  ## If you need to accept runtime values for this you could use the
+  ## `nextPowerOfTwo proc<math.html#nextPowerOfTwo,int>`_ from the
+  ## `math module<math.html>`_ or the `rightSize proc<#rightSize,Natural>`_
+  ## from this module.
+  ##
+  ## See also:
+  ## * `toCountTable proc<#toCountTable,openArray[A]>`_
+  ## * `newCountTable proc<#newCountTable,int>`_ for creating a
+  ##   `CountTableRef`
+  assert isPowerOfTwo(initialSize)
+  result.counter = 0
+  newSeq(result.data, initialSize)
+
+proc toCountTable*[A](keys: openArray[A]): CountTable[A] =
+  ## Creates a new count table with every member of a container ``keys``
+  ## having a count of how many times it occurs in that container.
+  result = initCountTable[A](rightSize(keys.len))
+  for key in items(keys): result.inc(key)
+
+proc `[]`*[A](t: CountTable[A], key: A): int =
+  ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``.
+  ## Otherwise ``0`` is returned.
+  ##
+  ## See also:
+  ## * `getOrDefault<#getOrDefault,CountTable[A],A,int>`_ to return
+  ##   a custom value if the key doesn't exist
+  ## * `mget proc<#mget,CountTable[A],A>`_
+  ## * `[]= proc<#[]%3D,CountTable[A],A,int>`_ for inserting a new
+  ##   (key, value) pair in the table
+  ## * `hasKey proc<#hasKey,CountTable[A],A>`_ for checking if a key
+  ##   is in the table
+  ctget(t, key, 0)
+
+proc mget*[A](t: var CountTable[A], key: A): var int =
+  ## Retrieves the value at ``t[key]``. The value can be modified.
+  ##
+  ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised.
+  get(t, key)
+
 proc `[]=`*[A](t: var CountTable[A], key: A, val: int) =
-  ## puts a ``(key, value)`` pair into ``t``.
+  ## Inserts a ``(key, value)`` pair into ``t``.
+  ##
+  ## See also:
+  ## * `[] proc<#[],CountTable[A],A>`_ for retrieving a value of a key
+  ## * `inc proc<#inc,CountTable[A],A,int>`_ for incrementing a
+  ##   value of a key
   assert val >= 0
-  var h = rawGet(t, key)
+  let h = rawGet(t, key)
   if h >= 0:
     t.data[h].val = val
   else:
     if mustRehash(len(t.data), t.counter): enlarge(t)
     rawInsert(t, t.data, key, val)
     inc(t.counter)
-    #h = -1 - h
-    #t.data[h].key = key
-    #t.data[h].val = val
 
 proc inc*[A](t: var CountTable[A], key: A, val = 1) =
-  ## increments ``t[key]`` by ``val``.
+  ## Increments ``t[key]`` by ``val`` (default: 1).
+  runnableExamples:
+    var a = toCountTable("aab")
+    a.inc('a')
+    a.inc('b', 10)
+    doAssert a == toCountTable("aaabbbbbbbbbbb")
   var index = rawGet(t, key)
   if index >= 0:
     inc(t.data[index].val, val)
@@ -1018,33 +2140,11 @@ proc inc*[A](t: var CountTable[A], key: A, val = 1) =
     rawInsert(t, t.data, key, val)
     inc(t.counter)
 
-proc initCountTable*[A](initialSize=64): CountTable[A] =
-  ## creates a new count table that is empty.
-  ##
-  ## ``initialSize`` needs to be a power of two. If you need to accept runtime
-  ## values for this you could use the ``nextPowerOfTwo`` proc from the
-  ## `math <math.html>`_ module or the ``rightSize`` proc in this module.
-  assert isPowerOfTwo(initialSize)
-  result.counter = 0
-  newSeq(result.data, initialSize)
-
-proc toCountTable*[A](keys: openArray[A]): CountTable[A] =
-  ## creates a new count table with every key in ``keys`` having a count
-  ## of how many times it occurs in ``keys``.
-  result = initCountTable[A](rightSize(keys.len))
-  for key in items(keys): result.inc(key)
-
-proc `$`*[A](t: CountTable[A]): string =
-  ## The ``$`` operator for count tables.
-  dollarImpl()
-
-proc `==`*[A](s, t: CountTable[A]): bool =
-  ## The ``==`` operator for count tables. Returns ``true`` iff both tables
-  ## contain the same keys with the same count. Insert order does not matter.
-  equalsImpl(s, t)
-
 proc smallest*[A](t: CountTable[A]): tuple[key: A, val: int] =
-  ## returns the ``(key, value)`` pair with the smallest ``val``. Efficiency: O(n)
+  ## Returns the ``(key, value)`` pair with the smallest ``val``. Efficiency: O(n)
+  ##
+  ## See also:
+  ## * `largest proc<#largest,CountTable[A]>`_
   assert t.len > 0
   var minIdx = -1
   for h in 0..high(t.data):
@@ -1054,7 +2154,10 @@ proc smallest*[A](t: CountTable[A]): tuple[key: A, val: int] =
   result.val = t.data[minIdx].val
 
 proc largest*[A](t: CountTable[A]): tuple[key: A, val: int] =
-  ## returns the ``(key, value)`` pair with the largest ``val``. Efficiency: O(n)
+  ## Returns the ``(key, value)`` pair with the largest ``val``. Efficiency: O(n)
+  ##
+  ## See also:
+  ## * `smallest proc<#smallest,CountTable[A]>`_
   assert t.len > 0
   var maxIdx = 0
   for h in 1..high(t.data):
@@ -1062,11 +2165,49 @@ proc largest*[A](t: CountTable[A]): tuple[key: A, val: int] =
   result.key = t.data[maxIdx].key
   result.val = t.data[maxIdx].val
 
+proc hasKey*[A](t: CountTable[A], key: A): bool =
+  ## Returns true if ``key`` is in the table ``t``.
+  ##
+  ## See also:
+  ## * `contains proc<#contains,CountTable[A],A>`_ for use with the `in`
+  ##   operator
+  ## * `[] proc<#[],CountTable[A],A>`_ for retrieving a value of a key
+  ## * `getOrDefault proc<#getOrDefault,CountTable[A],A,int>`_ to return
+  ##   a custom value if the key doesn't exist
+  result = rawGet(t, key) >= 0
+
+proc contains*[A](t: CountTable[A], key: A): bool =
+  ## Alias of `hasKey proc<#hasKey,CountTable[A],A>`_ for use with
+  ## the ``in`` operator.
+  return hasKey[A](t, key)
+
+proc getOrDefault*[A](t: CountTable[A], key: A; default: int = 0): int =
+  ## Retrieves the value at ``t[key]`` if``key`` is in ``t``. Otherwise, the
+  ## integer value of ``default`` is returned.
+  ##
+  ## See also:
+  ## * `[] proc<#[],CountTable[A],A>`_ for retrieving a value of a key
+  ## * `hasKey proc<#hasKey,CountTable[A],A>`_ for checking if a key
+  ##   is in the table
+  ctget(t, key, default)
+
+proc len*[A](t: CountTable[A]): int =
+  ## Returns the number of keys in ``t``.
+  result = t.counter
+
+proc clear*[A](t: var CountTable[A]) =
+  ## Resets the table so that it is empty.
+  clearImpl()
+
 proc sort*[A](t: var CountTable[A]) =
-  ## sorts the count table so that the entry with the highest counter comes
-  ## first. This is destructive! You must not modify ``t`` afterwards!
-  ## You can use the iterators ``pairs``, ``keys``, and ``values`` to iterate over
-  ## ``t`` in the sorted order.
+  ## Sorts the count table so that the entry with the highest counter comes
+  ## first.
+  ##
+  ## **This is destructive! You must not modify ``t`` afterwards!**
+  ##
+  ## You can use the iterators `pairs<#pairs.i,CountTable[A]>`_,
+  ## `keys<#keys.i,CountTable[A]>`_, and `values<#values.i,CountTable[A]>`_
+  ## to iterate over ``t`` in the sorted order.
 
   # we use shellsort here; fast enough and simple
   var h = 1
@@ -1083,131 +2224,373 @@ proc sort*[A](t: var CountTable[A]) =
         if j < h: break
     if h == 1: break
 
-proc len*[A](t: CountTableRef[A]): int =
-  ## returns the number of keys in ``t``.
-  result = t.counter
+proc merge*[A](s: var CountTable[A], t: CountTable[A]) =
+  ## Merges the second table into the first one (must be declared as `var`).
+  runnableExamples:
+    var a = toCountTable("aaabbc")
+    let b = toCountTable("bcc")
+    a.merge(b)
+    doAssert a == toCountTable("aaabbbccc")
+  for key, value in t:
+    s.inc(key, value)
 
-iterator pairs*[A](t: CountTableRef[A]): (A, int) =
-  ## iterates over any ``(key, value)`` pair in the table ``t``.
+proc merge*[A](s, t: CountTable[A]): CountTable[A] =
+  ## Merges the two tables into a new one.
+  runnableExamples:
+    let
+      a = toCountTable("aaabbc")
+      b = toCountTable("bcc")
+    doAssert merge(a, b) == toCountTable("aaabbbccc")
+  result = initCountTable[A](nextPowerOfTwo(max(s.len, t.len)))
+  for table in @[s, t]:
+    for key, value in table:
+      result.inc(key, value)
+
+proc `$`*[A](t: CountTable[A]): string =
+  ## The ``$`` operator for count tables. Used internally when calling `echo`
+  ## on a table.
+  dollarImpl()
+
+proc `==`*[A](s, t: CountTable[A]): bool =
+  ## The ``==`` operator for count tables. Returns ``true`` if both tables
+  ## contain the same keys with the same count. Insert order does not matter.
+  equalsImpl(s, t)
+
+
+iterator pairs*[A](t: CountTable[A]): (A, int) =
+  ## Iterates over any ``(key, value)`` pair in the table ``t``.
+  ##
+  ## See also:
+  ## * `mpairs iterator<#mpairs.i,CountTable[A]>`_
+  ## * `keys iterator<#keys.i,CountTable[A]>`_
+  ## * `values iterator<#values.i,CountTable[A]>`_
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   let a = toCountTable("abracadabra")
+  ##
+  ##   for k, v in pairs(a):
+  ##     echo "key: ", k
+  ##     echo "value: ", v
+  ##
+  ##   # key: a
+  ##   # value: 5
+  ##   # key: b
+  ##   # value: 2
+  ##   # key: c
+  ##   # value: 1
+  ##   # key: d
+  ##   # value: 1
+  ##   # key: r
+  ##   # value: 2
   for h in 0..high(t.data):
     if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
 
-iterator mpairs*[A](t: CountTableRef[A]): (A, var int) =
-  ## iterates over any ``(key, value)`` pair in the table ``t``. The values can
-  ## be modified.
+iterator mpairs*[A](t: var CountTable[A]): (A, var int) =
+  ## Iterates over any ``(key, value)`` pair in the table ``t`` (must be
+  ## declared as `var`). The values can be modified.
+  ##
+  ## See also:
+  ## * `pairs iterator<#pairs.i,CountTable[A]>`_
+  ## * `mvalues iterator<#mvalues.i,CountTable[A]>`_
+  runnableExamples:
+    var a = toCountTable("abracadabra")
+    for k, v in mpairs(a):
+      v = 2
+    doAssert a == toCountTable("aabbccddrr")
   for h in 0..high(t.data):
     if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
 
-iterator keys*[A](t: CountTableRef[A]): A =
-  ## iterates over any key in the table ``t``.
+iterator keys*[A](t: CountTable[A]): A =
+  ## Iterates over any key in the table ``t``.
+  ##
+  ## See also:
+  ## * `pairs iterator<#pairs.i,CountTable[A]>`_
+  ## * `values iterator<#values.i,CountTable[A]>`_
+  runnableExamples:
+    var a = toCountTable("abracadabra")
+    for k in keys(a):
+      a[k] = 2
+    doAssert a == toCountTable("aabbccddrr")
   for h in 0..high(t.data):
     if t.data[h].val != 0: yield t.data[h].key
 
-iterator values*[A](t: CountTableRef[A]): int =
-  ## iterates over any value in the table ``t``.
+iterator values*[A](t: CountTable[A]): int =
+  ## Iterates over any value in the table ``t``.
+  ##
+  ## See also:
+  ## * `pairs iterator<#pairs.i,CountTable[A]>`_
+  ## * `keys iterator<#keys.i,CountTable[A]>`_
+  ## * `mvalues iterator<#mvalues.i,CountTable[A]>`_
+  runnableExamples:
+    let a = toCountTable("abracadabra")
+    for v in values(a):
+      assert v < 10
   for h in 0..high(t.data):
     if t.data[h].val != 0: yield t.data[h].val
 
-iterator mvalues*[A](t: CountTableRef[A]): var int =
-  ## iterates over any value in the table ``t``. The values can be modified.
+iterator mvalues*[A](t: var CountTable[A]): var int =
+  ## Iterates over any value in the table ``t`` (must be
+  ## declared as `var`). The values can be modified.
+  ##
+  ## See also:
+  ## * `mpairs iterator<#mpairs.i,CountTable[A]>`_
+  ## * `values iterator<#values.i,CountTable[A]>`_
+  runnableExamples:
+    var a = toCountTable("abracadabra")
+    for v in mvalues(a):
+      v = 2
+    doAssert a == toCountTable("aabbccddrr")
   for h in 0..high(t.data):
     if t.data[h].val != 0: yield t.data[h].val
 
-proc `[]`*[A](t: CountTableRef[A], key: A): var int {.deprecatedGet.} =
-  ## retrieves the value at ``t[key]``. The value can be modified.
-  ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised.
-  result = t[][key]
 
-proc mget*[A](t: CountTableRef[A], key: A): var int {.deprecated.} =
-  ## retrieves the value at ``t[key]``. The value can be modified.
-  ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised.
-  ## Use ``[]`` instead.
-  result = t[][key]
 
-proc getOrDefault*[A](t: CountTableRef[A], key: A): int =
-  ## retrieves the value at ``t[key]`` iff ``key`` is in ``t``. Otherwise, 0 (the
-  ## default initialization value of ``int``), is returned.
-  result = t[].getOrDefault(key)
 
-proc getOrDefault*[A](t: CountTableRef[A], key: A, default: int): int =
-  ## retrieves the value at ``t[key]`` iff ``key`` is in ``t``. Otherwise, the
-  ## integer value of ``default`` is returned.
-  result = t[].getOrDefault(key, default)
 
-proc hasKey*[A](t: CountTableRef[A], key: A): bool =
-  ## returns true iff ``key`` is in the table ``t``.
-  result = t[].hasKey(key)
 
-proc contains*[A](t: CountTableRef[A], key: A): bool =
-  ## Alias of ``hasKey`` for use with the ``in`` operator.
-  return hasKey[A](t, key)
 
-proc `[]=`*[A](t: CountTableRef[A], key: A, val: int) =
-  ## puts a ``(key, value)`` pair into ``t``. ``val`` has to be positive.
-  assert val > 0
-  t[][key] = val
+# ---------------------------------------------------------------------------
+# ---------------------------- CountTableRef --------------------------------
+# ---------------------------------------------------------------------------
 
-proc inc*[A](t: CountTableRef[A], key: A, val = 1) =
-  ## increments ``t[key]`` by ``val``.
-  t[].inc(key, val)
+proc inc*[A](t: CountTableRef[A], key: A, val = 1)
 
 proc newCountTable*[A](initialSize=64): CountTableRef[A] =
-  ## creates a new count table that is empty.
+  ## Creates a new ref count table that is empty.
+  ##
+  ## ``initialSize`` must be a power of two (default: 64).
+  ## If you need to accept runtime values for this you could use the
+  ## `nextPowerOfTwo proc<math.html#nextPowerOfTwo,int>`_ from the
+  ## `math module<math.html>`_ or the `rightSize proc<#rightSize,Natural>`_
+  ## from this module.
   ##
-  ## ``initialSize`` needs to be a power of two. If you need to accept runtime
-  ## values for this you could use the ``nextPowerOfTwo`` proc from the
-  ## `math <math.html>`_ module or the ``rightSize`` method in this module.
+  ## See also:
+  ## * `newCountTable proc<#newCountTable,openArray[A]>`_ for creating
+  ##   a `CountTableRef` from a collection
+  ## * `initCountTable proc<#initCountTable,int>`_ for creating a
+  ##   `CountTable`
   new(result)
   result[] = initCountTable[A](initialSize)
 
 proc newCountTable*[A](keys: openArray[A]): CountTableRef[A] =
-  ## creates a new count table with every key in ``keys`` having a count
-  ## of how many times it occurs in ``keys``.
+  ## Creates a new ref count table with every member of a container ``keys``
+  ## having a count of how many times it occurs in that container.
   result = newCountTable[A](rightSize(keys.len))
   for key in items(keys): result.inc(key)
 
+proc `[]`*[A](t: CountTableRef[A], key: A): int =
+  ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``.
+  ## Otherwise ``0`` is returned.
+  ##
+  ## See also:
+  ## * `getOrDefault<#getOrDefault,CountTableRef[A],A,int>`_ to return
+  ##   a custom value if the key doesn't exist
+  ## * `mget proc<#mget,CountTableRef[A],A>`_
+  ## * `[]= proc<#[]%3D,CountTableRef[A],A,int>`_ for inserting a new
+  ##   (key, value) pair in the table
+  ## * `hasKey proc<#hasKey,CountTableRef[A],A>`_ for checking if a key
+  ##   is in the table
+  result = t[][key]
+
+proc mget*[A](t: CountTableRef[A], key: A): var int =
+  ## Retrieves the value at ``t[key]``. The value can be modified.
+  ##
+  ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised.
+  mget(t[], key)
+
+proc `[]=`*[A](t: CountTableRef[A], key: A, val: int) =
+  ## Inserts a ``(key, value)`` pair into ``t``.
+  ##
+  ## See also:
+  ## * `[] proc<#[],CountTableRef[A],A>`_ for retrieving a value of a key
+  ## * `inc proc<#inc,CountTableRef[A],A,int>`_ for incrementing a
+  ##   value of a key
+  assert val > 0
+  t[][key] = val
+
+proc inc*[A](t: CountTableRef[A], key: A, val = 1) =
+  ## Increments ``t[key]`` by ``val`` (default: 1).
+  runnableExamples:
+    var a = newCountTable("aab")
+    a.inc('a')
+    a.inc('b', 10)
+    doAssert a == newCountTable("aaabbbbbbbbbbb")
+  t[].inc(key, val)
+
+proc smallest*[A](t: CountTableRef[A]): (A, int) =
+  ## Returns the ``(key, value)`` pair with the smallest ``val``. Efficiency: O(n)
+  ##
+  ## See also:
+  ## * `largest proc<#largest,CountTableRef[A]>`_
+  t[].smallest
+
+proc largest*[A](t: CountTableRef[A]): (A, int) =
+  ## Returns the ``(key, value)`` pair with the largest ``val``. Efficiency: O(n)
+  ##
+  ## See also:
+  ## * `smallest proc<#smallest,CountTable[A]>`_
+  t[].largest
+
+proc hasKey*[A](t: CountTableRef[A], key: A): bool =
+  ## Returns true if ``key`` is in the table ``t``.
+  ##
+  ## See also:
+  ## * `contains proc<#contains,CountTableRef[A],A>`_ for use with the `in`
+  ##   operator
+  ## * `[] proc<#[],CountTableRef[A],A>`_ for retrieving a value of a key
+  ## * `getOrDefault proc<#getOrDefault,CountTableRef[A],A,int>`_ to return
+  ##   a custom value if the key doesn't exist
+  result = t[].hasKey(key)
+
+proc contains*[A](t: CountTableRef[A], key: A): bool =
+  ## Alias of `hasKey proc<#hasKey,CountTableRef[A],A>`_ for use with
+  ## the ``in`` operator.
+  return hasKey[A](t, key)
+
+proc getOrDefault*[A](t: CountTableRef[A], key: A, default: int): int =
+  ## Retrieves the value at ``t[key]`` if``key`` is in ``t``. Otherwise, the
+  ## integer value of ``default`` is returned.
+  ##
+  ## See also:
+  ## * `[] proc<#[],CountTableRef[A],A>`_ for retrieving a value of a key
+  ## * `hasKey proc<#hasKey,CountTableRef[A],A>`_ for checking if a key
+  ##   is in the table
+  result = t[].getOrDefault(key, default)
+
+proc len*[A](t: CountTableRef[A]): int =
+  ## Returns the number of keys in ``t``.
+  result = t.counter
+
+proc clear*[A](t: CountTableRef[A]) =
+  ## Resets the table so that it is empty.
+  clearImpl()
+
+proc sort*[A](t: CountTableRef[A]) =
+  ## Sorts the count table so that the entry with the highest counter comes
+  ## first.
+  ##
+  ## **This is destructive! You must not modify `t` afterwards!**
+  ##
+  ## You can use the iterators `pairs<#pairs.i,CountTableRef[A]>`_,
+  ## `keys<#keys.i,CountTableRef[A]>`_, and `values<#values.i,CountTableRef[A]>`_
+  ## to iterate over ``t`` in the sorted order.
+  t[].sort
+
+proc merge*[A](s, t: CountTableRef[A]) =
+  ## Merges the second table into the first one.
+  runnableExamples:
+    let
+      a = newCountTable("aaabbc")
+      b = newCountTable("bcc")
+    a.merge(b)
+    doAssert a == newCountTable("aaabbbccc")
+  s[].merge(t[])
+
 proc `$`*[A](t: CountTableRef[A]): string =
-  ## The ``$`` operator for count tables.
+  ## The ``$`` operator for count tables. Used internally when calling `echo`
+  ## on a table.
   dollarImpl()
 
 proc `==`*[A](s, t: CountTableRef[A]): bool =
-  ## The ``==`` operator for count tables. Returns ``true`` iff either both tables
-  ## are ``nil`` or none is ``nil`` and both contain the same keys with the same
+  ## The ``==`` operator for count tables. Returns ``true`` if either both tables
+  ## are ``nil``, or neither is ``nil`` and both contain the same keys with the same
   ## count. Insert order does not matter.
   if isNil(s): result = isNil(t)
   elif isNil(t): result = false
   else: result = s[] == t[]
 
-proc smallest*[A](t: CountTableRef[A]): (A, int) =
-  ## returns the ``(key, value)`` pair with the smallest ``val``. Efficiency: O(n)
-  t[].smallest
 
-proc largest*[A](t: CountTableRef[A]): (A, int) =
-  ## returns the ``(key, value)`` pair with the largest ``val``. Efficiency: O(n)
-  t[].largest
+iterator pairs*[A](t: CountTableRef[A]): (A, int) =
+  ## Iterates over any ``(key, value)`` pair in the table ``t``.
+  ##
+  ## See also:
+  ## * `mpairs iterator<#mpairs.i,CountTableRef[A]>`_
+  ## * `keys iterator<#keys.i,CountTableRef[A]>`_
+  ## * `values iterator<#values.i,CountTableRef[A]>`_
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   let a = newCountTable("abracadabra")
+  ##
+  ##   for k, v in pairs(a):
+  ##     echo "key: ", k
+  ##     echo "value: ", v
+  ##
+  ##   # key: a
+  ##   # value: 5
+  ##   # key: b
+  ##   # value: 2
+  ##   # key: c
+  ##   # value: 1
+  ##   # key: d
+  ##   # value: 1
+  ##   # key: r
+  ##   # value: 2
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
 
-proc sort*[A](t: CountTableRef[A]) =
-  ## sorts the count table so that the entry with the highest counter comes
-  ## first. This is destructive! You must not modify ``t`` afterwards!
-  ## You can use the iterators ``pairs``, ``keys``, and ``values`` to iterate over
-  ## ``t`` in the sorted order.
-  t[].sort
+iterator mpairs*[A](t: CountTableRef[A]): (A, var int) =
+  ## Iterates over any ``(key, value)`` pair in the table ``t``. The values can
+  ## be modified.
+  ##
+  ## See also:
+  ## * `pairs iterator<#pairs.i,CountTableRef[A]>`_
+  ## * `mvalues iterator<#mvalues.i,CountTableRef[A]>`_
+  runnableExamples:
+    let a = newCountTable("abracadabra")
+    for k, v in mpairs(a):
+      v = 2
+    doAssert a == newCountTable("aabbccddrr")
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
+
+iterator keys*[A](t: CountTableRef[A]): A =
+  ## Iterates over any key in the table ``t``.
+  ##
+  ## See also:
+  ## * `pairs iterator<#pairs.i,CountTable[A]>`_
+  ## * `values iterator<#values.i,CountTable[A]>`_
+  runnableExamples:
+    let a = newCountTable("abracadabra")
+    for k in keys(a):
+      a[k] = 2
+    doAssert a == newCountTable("aabbccddrr")
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield t.data[h].key
+
+iterator values*[A](t: CountTableRef[A]): int =
+  ## Iterates over any value in the table ``t``.
+  ##
+  ## See also:
+  ## * `pairs iterator<#pairs.i,CountTableRef[A]>`_
+  ## * `keys iterator<#keys.i,CountTableRef[A]>`_
+  ## * `mvalues iterator<#mvalues.i,CountTableRef[A]>`_
+  runnableExamples:
+    let a = newCountTable("abracadabra")
+    for v in values(a):
+      assert v < 10
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield t.data[h].val
+
+iterator mvalues*[A](t: CountTableRef[A]): var int =
+  ## Iterates over any value in the table ``t``. The values can be modified.
+  ##
+  ## See also:
+  ## * `mpairs iterator<#mpairs.i,CountTableRef[A]>`_
+  ## * `values iterator<#values.i,CountTableRef[A]>`_
+  runnableExamples:
+    var a = newCountTable("abracadabra")
+    for v in mvalues(a):
+      v = 2
+    doAssert a == newCountTable("aabbccddrr")
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield t.data[h].val
 
-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
@@ -1325,9 +2708,9 @@ when isMainModule:
     #test_counttable.nim(7, 43) template/generic instantiation from here
     #lib/pure/collections/tables.nim(117, 21) template/generic instantiation from here
     #lib/pure/collections/tableimpl.nim(32, 27) Error: undeclared field: 'hcode
-    doAssert 0 == t.getOrDefault(testKey)
+    doAssert 0 == t[testKey]
     t.inc(testKey, 3)
-    doAssert 3 == t.getOrDefault(testKey)
+    doAssert 3 == t[testKey]
 
   block:
     # Clear tests
@@ -1394,6 +2777,18 @@ when isMainModule:
     let t = toCountTable([0, 0, 5, 5, 5])
     doAssert t.smallest == (0, 2)
 
+  block: #10065
+    let t = toCountTable("abracadabra")
+    doAssert t['z'] == 0
+
+    var t_mut = toCountTable("abracadabra")
+    doAssert t_mut['z'] == 0
+    # the previous read may not have modified the table.
+    doAssert t_mut.hasKey('z') == false
+    t_mut['z'] = 1
+    doAssert t_mut['z'] == 1
+    doAssert t_mut.hasKey('z') == true
+
   block:
     var tp: Table[string, string] = initTable[string, string]()
     doAssert "test1" == tp.getOrDefault("test1", "test1")
diff --git a/lib/pure/concurrency/atomics.nim b/lib/pure/concurrency/atomics.nim
new file mode 100644
index 000000000..9e716bdf4
--- /dev/null
+++ b/lib/pure/concurrency/atomics.nim
@@ -0,0 +1,378 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2018 Jörg Wollenschläger
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Types and operations for atomic operations and lockless algorithms.
+
+import macros
+
+when defined(cpp) or defined(nimdoc):
+  # For the C++ backend, types and operations map directly to C++11 atomics.
+
+  {.push, header: "<atomic>".}
+
+  type
+    MemoryOrder* {.importcpp: "std::memory_order".} = enum
+      ## Specifies how non-atomic operations can be reordered around atomic 
+      ## operations.
+
+      moRelaxed
+        ## No ordering constraints. Only the atomicity and ordering against
+        ## other atomic operations is guaranteed.
+
+      moConsume
+        ## This ordering is currently discouraged as it's semantics are
+        ## being revised. Acquire operations should be preferred.
+
+      moAcquire
+        ## When applied to a load operation, no reads or writes in the
+        ## current thread can be reordered before this operation.
+
+      moRelease
+        ## When applied to a store operation, no reads or writes in the
+        ## current thread can be reorderd after this operation.
+
+      moAcquireRelease
+        ## When applied to a read-modify-write operation, this behaves like
+        ## both an acquire and a release operation.
+
+      moSequentiallyConsistent
+        ## Behaves like Acquire when applied to load, like Release when
+        ## applied to a store and like AcquireRelease when applied to a
+        ## read-modify-write operation.
+        ## Also garantees that all threads observe the same total ordering
+        ## with other moSequentiallyConsistent operations.
+
+  type
+    Atomic* {.importcpp: "std::atomic".} [T] = object
+      ## An atomic object with underlying type `T`.
+
+    AtomicFlag* {.importcpp: "std::atomic_flag".} = object
+      ## An atomic boolean state.
+
+  # Access operations
+
+  proc load*[T](location: var Atomic[T]; order: MemoryOrder = moSequentiallyConsistent): T {.importcpp: "#.load(@)".}
+    ## Atomically obtains the value of the atomic object.
+
+  proc store*[T](location: var Atomic[T]; desired: T; order: MemoryOrder = moSequentiallyConsistent) {.importcpp: "#.store(@)".}
+    ## Atomically replaces the value of the atomic object with the `desired`
+    ## value.
+
+  proc exchange*[T](location: var Atomic[T]; desired: T; order: MemoryOrder = moSequentiallyConsistent): T {.importcpp: "#.exchange(@)".}
+    ## Atomically replaces the value of the atomic object with the `desired`
+    ## value and returns the old value.
+
+  proc compareExchange*[T](location: var Atomic[T]; expected: var T; desired: T; order: MemoryOrder = moSequentiallyConsistent): bool {.importcpp: "#.compare_exchange_strong(@)".}
+    ## Atomically compares the value of the atomic object with the `expected`
+    ## value and performs exchange with the `desired` one if equal or load if
+    ## not. Returns true if the exchange was successful.
+
+  proc compareExchange*[T](location: var Atomic[T]; expected: var T; desired: T; success, failure: MemoryOrder): bool {.importcpp: "#.compare_exchange_strong(@)".}
+    ## Same as above, but allows for different memory orders for success and
+    ## failure.
+
+  proc compareExchangeWeak*[T](location: var Atomic[T]; expected: var T; desired: T; order: MemoryOrder = moSequentiallyConsistent): bool {.importcpp: "#.compare_exchange_weak(@)".}
+    ## Same as above, but is allowed to fail spuriously.
+
+  proc compareExchangeWeak*[T](location: var Atomic[T]; expected: var T; desired: T; success, failure: MemoryOrder): bool {.importcpp: "#.compare_exchange_weak(@)".}
+    ## Same as above, but allows for different memory orders for success and
+    ## failure.
+
+  # Numerical operations
+
+  proc fetchAdd*[T: SomeInteger](location: var Atomic[T]; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importcpp: "#.fetch_add(@)".}
+    ## Atomically adds a `value` to the atomic integer and returns the
+    ## original value.
+
+  proc fetchSub*[T: SomeInteger](location: var Atomic[T]; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importcpp: "#.fetch_sub(@)".}
+    ## Atomically subtracts a `value` to the atomic integer and returns the
+    ## original value.
+
+  proc fetchAnd*[T: SomeInteger](location: var Atomic[T]; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importcpp: "#.fetch_and(@)".}
+    ## Atomically replaces the atomic integer with it's bitwise AND
+    ## with the specified `value` and returns the original value.
+
+  proc fetchOr*[T: SomeInteger](location: var Atomic[T]; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importcpp: "#.fetch_or(@)".}
+    ## Atomically replaces the atomic integer with it's bitwise OR
+    ## with the specified `value` and returns the original value.
+
+  proc fetchXor*[T: SomeInteger](location: var Atomic[T]; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importcpp: "#.fetch_xor(@)".}
+    ## Atomically replaces the atomic integer with it's bitwise XOR
+    ## with the specified `value` and returns the original value.
+
+  # Flag operations
+
+  proc testAndSet*(location: var AtomicFlag; order: MemoryOrder = moSequentiallyConsistent): bool {.importcpp: "#.test_and_set(@)".}
+    ## Atomically sets the atomic flag to true and returns the original value.
+
+  proc clear*(location: var AtomicFlag; order: MemoryOrder = moSequentiallyConsistent) {.importcpp: "#.clear(@)".}
+    ## Atomically sets the value of the atomic flag to false.
+
+  proc fence*(order: MemoryOrder) {.importcpp: "std::atomic_thread_fence(@)".}
+    ## Ensures memory ordering without using atomic operations.
+
+  proc signalFence*(order: MemoryOrder) {.importcpp: "std::atomic_signal_fence(@)".}
+    ## Prevents reordering of accesses by the compiler as would fence, but
+    ## inserts no CPU instructions for memory ordering.
+
+  {.pop.}
+
+else:
+  # For the C backend, atomics map to C11 built-ins on GCC and Clang for
+  # trivial Nim types. Other types are implemented using spin locks.
+  # This could be overcome by supporting advanced importc-patterns.
+
+  # Since MSVC does not implement C11, we fall back to MS intrinsics
+  # where available.
+
+  type 
+    Trivial = SomeNumber | bool | ptr | pointer
+      # A type that is known to be atomic and whose size is known at
+      # compile time to be 8 bytes or less
+
+  template nonAtomicType(T: typedesc[Trivial]): untyped =
+    # Maps types to integers of the same size
+    when sizeof(T) == 1: int8
+    elif sizeof(T) == 2: int16
+    elif sizeof(T) == 4: int32
+    elif sizeof(T) == 8: int64
+
+  when defined(vcc):
+    
+    # TODO: Trivial types should be volatile and use VC's special volatile
+    # semantics for store and loads.
+
+    type
+      MemoryOrder* = enum
+        moRelaxed
+        moConsume
+        moAcquire
+        moRelease
+        moAcquireRelease
+        moSequentiallyConsistent
+
+      Atomic*[T] = object
+        when T is Trivial:
+          value: T.nonAtomicType
+        else:
+          nonAtomicValue: T
+          guard: AtomicFlag
+
+      AtomicFlag* = distinct int8
+
+    {.push header: "<intrin.h>".}
+
+    # MSVC intrinsics
+    proc interlockedExchange(location: pointer; desired: int8): int8 {.importc: "_InterlockedExchange8".}
+    proc interlockedExchange(location: pointer; desired: int16): int16 {.importc: "_InterlockedExchange".}
+    proc interlockedExchange(location: pointer; desired: int32): int32 {.importc: "_InterlockedExchange16".}
+    proc interlockedExchange(location: pointer; desired: int64): int64 {.importc: "_InterlockedExchange64".}
+
+    proc interlockedCompareExchange(location: pointer; desired, expected: int8): int8 {.importc: "_InterlockedCompareExchange8".}
+    proc interlockedCompareExchange(location: pointer; desired, expected: int16): int16 {.importc: "_InterlockedCompareExchange16".}
+    proc interlockedCompareExchange(location: pointer; desired, expected: int32): int32 {.importc: "_InterlockedCompareExchange".}
+    proc interlockedCompareExchange(location: pointer; desired, expected: int64): int64 {.importc: "_InterlockedCompareExchange64".}
+
+    proc interlockedAnd(location: pointer; value: int8): int8 {.importc: "_InterlockedAnd8".}
+    proc interlockedAnd(location: pointer; value: int16): int16 {.importc: "_InterlockedAnd16".}
+    proc interlockedAnd(location: pointer; value: int32): int32 {.importc: "_InterlockedAnd".}
+    proc interlockedAnd(location: pointer; value: int64): int64 {.importc: "_InterlockedAnd64".}
+
+    proc interlockedOr(location: pointer; value: int8): int8 {.importc: "_InterlockedOr8".}
+    proc interlockedOr(location: pointer; value: int16): int16 {.importc: "_InterlockedOr16".}
+    proc interlockedOr(location: pointer; value: int32): int32 {.importc: "_InterlockedOr".}
+    proc interlockedOr(location: pointer; value: int64): int64 {.importc: "_InterlockedOr64".}
+
+    proc interlockedXor(location: pointer; value: int8): int8 {.importc: "_InterlockedXor8".}
+    proc interlockedXor(location: pointer; value: int16): int16 {.importc: "_InterlockedXor16".}
+    proc interlockedXor(location: pointer; value: int32): int32 {.importc: "_InterlockedXor".}
+    proc interlockedXor(location: pointer; value: int64): int64 {.importc: "_InterlockedXor64".}
+
+    proc fence(order: MemoryOrder): int64 {.importc: "_ReadWriteBarrier()".}
+    proc signalFence(order: MemoryOrder): int64 {.importc: "_ReadWriteBarrier()".}
+
+    {.pop.}
+
+    proc testAndSet*(location: var AtomicFlag; order: MemoryOrder = moSequentiallyConsistent): bool =
+      interlockedOr(addr(location), 1'i8) == 1'i8
+    proc clear*(location: var AtomicFlag; order: MemoryOrder = moSequentiallyConsistent) =
+      discard interlockedAnd(addr(location), 0'i8)
+
+    proc load*[T: Trivial](location: var Atomic[T]; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} =
+      cast[T](interlockedOr(addr(location.value), (nonAtomicType(T))0))
+    proc store*[T: Trivial](location: var Atomic[T]; desired: T; order: MemoryOrder = moSequentiallyConsistent) {.inline.} =
+      discard interlockedExchange(addr(location.value), cast[nonAtomicType(T)](desired))
+
+    proc exchange*[T: Trivial](location: var Atomic[T]; desired: T; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} =
+      cast[T](interlockedExchange(addr(location.value), cast[int64](desired)))
+    proc compareExchange*[T: Trivial](location: var Atomic[T]; expected: var T; desired: T; success, failure: MemoryOrder): bool {.inline.} =
+      cast[T](interlockedCompareExchange(addr(location.value), cast[nonAtomicType(T)](desired), cast[nonAtomicType(T)](expected))) == expected
+    proc compareExchange*[T: Trivial](location: var Atomic[T]; expected: var T; desired: T; order: MemoryOrder = moSequentiallyConsistent): bool {.inline.} =
+      compareExchange(location, expected, desired, order, order)
+    proc compareExchangeWeak*[T: Trivial](location: var Atomic[T]; expected: var T; desired: T; success, failure: MemoryOrder): bool {.inline.} =
+      compareExchange(location, expected, desired, success, failure)
+    proc compareExchangeWeak*[T: Trivial](location: var Atomic[T]; expected: var T; desired: T; order: MemoryOrder = moSequentiallyConsistent): bool {.inline.} =
+      compareExchangeWeak(location, expected, desired, order, order)
+
+    proc fetchAdd*[T: SomeInteger](location: var Atomic[T]; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} =
+      var currentValue = location.load()
+      while not compareExchangeWeak(location, currentValue, currentValue + value): discard
+    proc fetchSub*[T: SomeInteger](location: var Atomic[T]; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} =
+      fetchAdd(location, -value, order)
+    proc fetchAnd*[T: SomeInteger](location: var Atomic[T]; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} =
+      cast[T](interlockedAnd(addr(location.value), cast[nonAtomicType(T)](value)))
+    proc fetchOr*[T: SomeInteger](location: var Atomic[T]; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} =
+      cast[T](interlockedOr(addr(location.value), cast[nonAtomicType(T)](value)))
+    proc fetchXor*[T: SomeInteger](location: var Atomic[T]; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} =
+      cast[T](interlockedXor(addr(location.value), cast[nonAtomicType(T)](value)))
+    
+  else:
+    {.push, header: "<stdatomic.h>".}
+
+    type
+      MemoryOrder* {.importc: "memory_order".} = enum
+        moRelaxed
+        moConsume
+        moAcquire
+        moRelease
+        moAcquireRelease
+        moSequentiallyConsistent
+
+    type
+      # Atomic* {.importcpp: "_Atomic('0)".} [T] = object
+
+      AtomicInt8 {.importc: "_Atomic NI8".} = object
+      AtomicInt16 {.importc: "_Atomic NI16".} = object
+      AtomicInt32 {.importc: "_Atomic NI32".} = object
+      AtomicInt64 {.importc: "_Atomic NI64".} = object
+
+    template atomicType(T: typedesc[Trivial]): untyped =
+      # Maps the size of a trivial type to it's internal atomic type
+      when sizeof(T) == 1: AtomicInt8
+      elif sizeof(T) == 2: AtomicInt16
+      elif sizeof(T) == 4: AtomicInt32
+      elif sizeof(T) == 8: AtomicInt64
+
+    type
+      AtomicFlag* {.importc: "atomic_flag".} = object
+
+      Atomic*[T] = object
+        when T is Trivial:
+          value: T.atomicType
+        else:
+          nonAtomicValue: T
+          guard: AtomicFlag
+
+    #proc init*[T](location: var Atomic[T]; value: T): T {.importcpp: "atomic_init(@)".}
+    proc atomic_load_explicit[T, A](location: ptr A; order: MemoryOrder): T {.importc.}
+    proc atomic_store_explicit[T, A](location: ptr A; desired: T; order: MemoryOrder = moSequentiallyConsistent) {.importc.}
+    proc atomic_exchange_explicit[T, A](location: ptr A; desired: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
+    proc atomic_compare_exchange_strong_explicit[T, A](location: ptr A; expected: ptr T; desired: T; success, failure: MemoryOrder): bool {.importc.}
+    proc atomic_compare_exchange_weak_explicit[T, A](location: ptr A; expected: ptr T; desired: T; success, failure: MemoryOrder): bool {.importc.}
+      
+    # Numerical operations
+    proc atomic_fetch_add_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
+    proc atomic_fetch_sub_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
+    proc atomic_fetch_and_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
+    proc atomic_fetch_or_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
+    proc atomic_fetch_xor_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
+  
+    # Flag operations
+    # var ATOMIC_FLAG_INIT {.importc, nodecl.}: AtomicFlag
+    # proc init*(location: var AtomicFlag) {.inline.} = location = ATOMIC_FLAG_INIT
+    proc testAndSet*(location: var AtomicFlag; order: MemoryOrder = moSequentiallyConsistent): bool {.importc: "atomic_flag_test_and_set_explicit".}
+    proc clear*(location: var AtomicFlag; order: MemoryOrder = moSequentiallyConsistent) {.importc: "atomic_flag_clear_explicit".}
+  
+    proc fence*(order: MemoryOrder) {.importc: "atomic_thread_fence".}
+    proc signalFence*(order: MemoryOrder) {.importc: "atomic_signal_fence".}  
+
+    {.pop.}
+
+    proc load*[T: Trivial](location: var Atomic[T]; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} =
+      cast[T](atomic_load_explicit[nonAtomicType(T), type(location.value)](addr(location.value), order))
+    proc store*[T: Trivial](location: var Atomic[T]; desired: T; order: MemoryOrder = moSequentiallyConsistent) {.inline.} =
+      atomic_store_explicit(addr(location.value), cast[nonAtomicType(T)](desired), order)
+    proc exchange*[T: Trivial](location: var Atomic[T]; desired: T; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} =
+      cast[T](atomic_exchange_explicit(addr(location.value), cast[nonAtomicType(T)](desired), order))
+    proc compareExchange*[T: Trivial](location: var Atomic[T]; expected: var T; desired: T; success, failure: MemoryOrder): bool {.inline.} =
+      atomic_compare_exchange_strong_explicit(addr(location.value), cast[ptr nonAtomicType(T)](addr(expected)), cast[nonAtomicType(T)](desired), success, failure)
+    proc compareExchange*[T: Trivial](location: var Atomic[T]; expected: var T; desired: T; order: MemoryOrder = moSequentiallyConsistent): bool {.inline.} =
+      compareExchange(location, expected, desired, order, order)
+
+    proc compareExchangeWeak*[T: Trivial](location: var Atomic[T]; expected: var T; desired: T; success, failure: MemoryOrder): bool {.inline.} =
+      atomic_compare_exchange_weak_explicit(addr(location.value), cast[ptr nonAtomicType(T)](addr(expected)), cast[nonAtomicType(T)](desired), success, failure)
+    proc compareExchangeWeak*[T: Trivial](location: var Atomic[T]; expected: var T; desired: T; order: MemoryOrder = moSequentiallyConsistent): bool {.inline.} =
+      compareExchangeWeak(location, expected, desired, order, order)
+  
+    # Numerical operations
+    proc fetchAdd*[T: SomeInteger](location: var Atomic[T]; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} =
+      cast[T](atomic_fetch_add_explicit(addr(location.value), cast[nonAtomicType(T)](value), order))
+    proc fetchSub*[T: SomeInteger](location: var Atomic[T]; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} =
+      cast[T](atomic_fetch_sub_explicit(addr(location.value), cast[nonAtomicType(T)](value), order))
+    proc fetchAnd*[T: SomeInteger](location: var Atomic[T]; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} =
+      cast[T](atomic_fetch_and_explicit(addr(location.value), cast[nonAtomicType(T)](value), order))
+    proc fetchOr*[T: SomeInteger](location: var Atomic[T]; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} =
+      cast[T](atomic_fetch_or_explicit(addr(location.value), cast[nonAtomicType(T)](value), order))
+    proc fetchXor*[T: SomeInteger](location: var Atomic[T]; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} =
+      cast[T](atomic_fetch_xor_explicit(addr(location.value), cast[nonAtomicType(T)](value), order))
+
+  template withLock[T: not Trivial](location: var Atomic[T]; order: MemoryOrder; body: untyped): untyped =
+    while location.guard.testAndSet(moAcquire): discard
+    body
+    location.guard.clear(moRelease)
+
+  proc load*[T: not Trivial](location: var Atomic[T]; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} =      
+    withLock(location, order):
+      result = location.nonAtomicValue
+
+  proc store*[T: not Trivial](location: var Atomic[T]; desired: T; order: MemoryOrder = moSequentiallyConsistent) {.inline.} =      
+    withLock(location, order):
+      location.nonAtomicValue = desired
+
+  proc exchange*[T: not Trivial](location: var Atomic[T]; desired: T; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} =
+    withLock(location, order):
+      result = location.nonAtomicValue
+      location.nonAtomicValue = desired
+
+  proc compareExchange*[T: not Trivial](location: var Atomic[T]; expected: var T; desired: T; success, failure: MemoryOrder): bool {.inline.} =
+    withLock(location, success):
+      if location.nonAtomicValue != expected:
+        return false
+      swap(location.nonAtomicValue, expected)
+      return true
+
+  proc compareExchangeWeak*[T: not Trivial](location: var Atomic[T]; expected: var T; desired: T; success, failure: MemoryOrder): bool {.inline.} =
+    withLock(location, success):
+      if location.nonAtomicValue != expected:
+        return false
+      swap(location.nonAtomicValue, expected)
+      return true
+
+  proc compareExchange*[T: not Trivial](location: var Atomic[T]; expected: var T; desired: T; order: MemoryOrder = moSequentiallyConsistent): bool {.inline.} =
+    compareExchange(location, expected, desired, order, order)
+
+  proc compareExchangeWeak*[T: not Trivial](location: var Atomic[T]; expected: var T; desired: T; order: MemoryOrder = moSequentiallyConsistent): bool {.inline.} =
+    compareExchangeWeak(location, expected, desired, order, order)
+
+proc atomicInc*[T: SomeInteger](location: var Atomic[T]; value: T = 1) {.inline.} =
+  ## Atomically increments the atomic integer by some `value`.
+  discard location.fetchAdd(value)
+
+proc atomicDec*[T: SomeInteger](location: var Atomic[T]; value: T = 1) {.inline.} =
+  ## Atomically decrements the atomic integer by some `value`.
+  discard location.fetchSub(value)
+
+proc `+=`*[T: SomeInteger](location: var Atomic[T]; value: T) {.inline.} =
+  ## Atomically increments the atomic integer by some `value`.
+  discard location.fetchAdd(value)
+
+proc `-=`*[T: SomeInteger](location: var Atomic[T]; value: T) {.inline.} =
+  ## Atomically decrements the atomic integer by some `value`.
+  discard location.fetchSub(value)
+  
\ No newline at end of file
diff --git a/lib/pure/distros.nim b/lib/pure/distros.nim
index 5847cfadb..0f1ffb1ab 100644
--- a/lib/pure/distros.nim
+++ b/lib/pure/distros.nim
@@ -133,16 +133,17 @@ const
   LacksDevPackages* = {Distribution.Gentoo, Distribution.Slackware,
     Distribution.ArchLinux}
 
-var unameRes, releaseRes: string ## we cache the result of the 'uname -a'
-                                 ## execution for faster platform detections.
+var unameRes, releaseRes, hostnamectlRes: string ## we cache the result of the 'uname -a'
+                                                 ## execution for faster platform detections.
 
 template unameRelease(cmd, cache): untyped =
   if cache.len == 0:
     cache = (when defined(nimscript): gorge(cmd) else: execProcess(cmd))
   cache
 
-template uname(): untyped = unameRelease("uname -a", unameRes)
-template release(): untyped = unameRelease("lsb_release -a", releaseRes)
+template uname(): untyped = unameRelease("uname -o", unameRes)
+template release(): untyped = unameRelease("lsb_release -d", releaseRes)
+template hostnamectl(): untyped = unameRelease("hostnamectl", hostnamectlRes)
 
 proc detectOsImpl(d: Distribution): bool =
   case d
@@ -172,7 +173,7 @@ proc detectOsImpl(d: Distribution): bool =
     result = defined(haiku)
   else:
     let dd = toLowerAscii($d)
-    result = dd in toLowerAscii(uname()) or dd in toLowerAscii(release())
+    result = dd in toLowerAscii(uname()) or dd in toLowerAscii(release()) or ("operating system: " & dd) in toLowerAscii(hostnamectl())
 
 template detectOs*(d: untyped): bool =
   ## Distro/OS detection. For convenience the
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index b7498b1c5..269ae476f 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -189,12 +189,6 @@ proc body*(response: Response): string =
     response.body = response.bodyStream.readAll()
   return response.body
 
-proc `body=`*(response: Response, value: string) {.deprecated.} =
-  ## Setter for backward compatibility.
-  ##
-  ## **This is deprecated and should not be used**.
-  response.body = value
-
 proc body*(response: AsyncResponse): Future[string] {.async.} =
   ## Reads the response's body and caches it. The read is performed only
   ## once.
@@ -477,119 +471,6 @@ proc format(p: MultipartData): tuple[contentType, body: string] =
     result.body.add("--" & bound & "\c\L" & s)
   result.body.add("--" & bound & "--\c\L")
 
-proc request*(url: string, httpMethod: string, extraHeaders = "",
-              body = "", sslContext = getDefaultSSL(), timeout = -1,
-              userAgent = defUserAgent, proxy: Proxy = nil): Response
-              {.deprecated: "use HttpClient.request instead".} =
-  ## | Requests ``url`` with the custom method string specified by the
-  ## | ``httpMethod`` parameter.
-  ## | Extra headers can be specified and must be separated by ``\c\L``
-  ## | An optional timeout can be specified in milliseconds, if reading from the
-  ## server takes longer than specified an ETimeout exception will be raised.
-  ##
-  ## **Deprecated since version 0.15.0**: use ``HttpClient.request`` instead.
-  var r = if proxy == nil: parseUri(url) else: proxy.url
-  var hostUrl = if proxy == nil: r else: parseUri(url)
-  var headers = httpMethod.toUpperAscii()
-  # TODO: Use generateHeaders further down once it supports proxies.
-
-  var s = newSocket()
-  defer: s.close()
-  if s == nil: raiseOSError(osLastError())
-  var port = net.Port(80)
-  if r.scheme == "https":
-    when defined(ssl):
-      sslContext.wrapSocket(s)
-      port = net.Port(443)
-    else:
-      raise newException(HttpRequestError,
-                "SSL support is not available. Cannot connect over SSL. Compile with -d:ssl to enable.")
-  if r.port != "":
-    port = net.Port(r.port.parseInt)
-
-
-  # get the socket ready. If we are connecting through a proxy to SSL,
-  # send the appropriate CONNECT header. If not, simply connect to the proper
-  # host (which may still be the proxy, for normal HTTP)
-  if proxy != nil and hostUrl.scheme == "https":
-    when defined(ssl):
-      var connectHeaders = "CONNECT "
-      let targetPort = if hostUrl.port == "": 443 else: hostUrl.port.parseInt
-      connectHeaders.add(hostUrl.hostname)
-      connectHeaders.add(":" & $targetPort)
-      connectHeaders.add(" HTTP/1.1\c\L")
-      connectHeaders.add("Host: " & hostUrl.hostname & ":" & $targetPort & "\c\L")
-      if proxy.auth != "":
-        let auth = base64.encode(proxy.auth, newline = "")
-        connectHeaders.add("Proxy-Authorization: basic " & auth & "\c\L")
-      connectHeaders.add("\c\L")
-      if timeout == -1:
-        s.connect(r.hostname, port)
-      else:
-        s.connect(r.hostname, port, timeout)
-
-      s.send(connectHeaders)
-      let connectResult = parseResponse(s, false, timeout)
-      if not connectResult.status.startsWith("200"):
-        raise newException(HttpRequestError,
-                           "The proxy server rejected a CONNECT request, " &
-                           "so a secure connection could not be established.")
-      sslContext.wrapConnectedSocket(s, handshakeAsClient, hostUrl.hostname)
-    else:
-      raise newException(HttpRequestError, "SSL support not available. Cannot " &
-                         "connect via proxy over SSL. Compile with -d:ssl to enable.")
-  else:
-    if timeout == -1:
-      s.connect(r.hostname, port)
-    else:
-      s.connect(r.hostname, port, timeout)
-
-
-  # now that the socket is ready, prepare the headers
-  if proxy == nil:
-    headers.add ' '
-    if r.path[0] != '/': headers.add '/'
-    headers.add(r.path)
-    if r.query.len > 0:
-      headers.add("?" & r.query)
-  else:
-    headers.add(" " & url)
-
-  headers.add(" HTTP/1.1\c\L")
-
-  if hostUrl.port == "":
-    add(headers, "Host: " & hostUrl.hostname & "\c\L")
-  else:
-    add(headers, "Host: " & hostUrl.hostname & ":" & hostUrl.port & "\c\L")
-
-  if userAgent != "":
-    add(headers, "User-Agent: " & userAgent & "\c\L")
-  if proxy != nil and proxy.auth != "":
-    let auth = base64.encode(proxy.auth, newline = "")
-    add(headers, "Proxy-Authorization: basic " & auth & "\c\L")
-  add(headers, extraHeaders)
-  add(headers, "\c\L")
-
-  # headers are ready. send them, await the result, and close the socket.
-  s.send(headers)
-  if body != "":
-    s.send(body)
-
-  result = parseResponse(s, httpMethod != "HEAD", timeout)
-
-proc request*(url: string, httpMethod = HttpGET, extraHeaders = "",
-              body = "", sslContext = getDefaultSSL(), timeout = -1,
-              userAgent = defUserAgent, proxy: Proxy = nil): Response
-              {.deprecated.} =
-  ## | Requests ``url`` with the specified ``httpMethod``.
-  ## | Extra headers can be specified and must be separated by ``\c\L``
-  ## | An optional timeout can be specified in milliseconds, if reading from the
-  ## server takes longer than specified an ETimeout exception will be raised.
-  ##
-  ## **Deprecated since version 0.15.0**: use ``HttpClient.request`` instead.
-  result = request(url, $httpMethod, extraHeaders, body, sslContext, timeout,
-                   userAgent, proxy)
-
 proc redirection(status: string): bool =
   const redirectionNRs = ["301", "302", "303", "307"]
   for i in items(redirectionNRs):
@@ -608,130 +489,6 @@ proc getNewLocation(lastURL: string, headers: HttpHeaders): string =
     parsed.anchor = r.anchor
     result = $parsed
 
-proc get*(url: string, extraHeaders = "", maxRedirects = 5,
-          sslContext: SSLContext = getDefaultSSL(),
-          timeout = -1, userAgent = defUserAgent,
-          proxy: Proxy = nil): Response {.deprecated.} =
-  ## | GETs the ``url`` and returns a ``Response`` object
-  ## | This proc also handles redirection
-  ## | Extra headers can be specified and must be separated by ``\c\L``.
-  ## | An optional timeout can be specified in milliseconds, if reading from the
-  ## server takes longer than specified an ETimeout exception will be raised.
-  ##
-  ## **Deprecated since version 0.15.0**: use ``HttpClient.get`` instead.
-  result = request(url, HttpGET, extraHeaders, "", sslContext, timeout,
-                   userAgent, proxy)
-  var lastURL = url
-  for i in 1..maxRedirects:
-    if result.status.redirection():
-      let redirectTo = getNewLocation(lastURL, result.headers)
-      result = request(redirectTo, HttpGET, extraHeaders, "", sslContext,
-                       timeout, userAgent, proxy)
-      lastURL = redirectTo
-
-proc getContent*(url: string, extraHeaders = "", maxRedirects = 5,
-                 sslContext: SSLContext = getDefaultSSL(),
-                 timeout = -1, userAgent = defUserAgent,
-                 proxy: Proxy = nil): string {.deprecated.} =
-  ## | GETs the body and returns it as a string.
-  ## | Raises exceptions for the status codes ``4xx`` and ``5xx``
-  ## | Extra headers can be specified and must be separated by ``\c\L``.
-  ## | An optional timeout can be specified in milliseconds, if reading from the
-  ## server takes longer than specified an ETimeout exception will be raised.
-  ##
-  ## **Deprecated since version 0.15.0**: use ``HttpClient.getContent`` instead.
-  var r = get(url, extraHeaders, maxRedirects, sslContext, timeout, userAgent,
-              proxy)
-  if r.status[0] in {'4','5'}:
-    raise newException(HttpRequestError, r.status)
-  else:
-    return r.body
-
-proc post*(url: string, extraHeaders = "", body = "",
-           maxRedirects = 5,
-           sslContext: SSLContext = getDefaultSSL(),
-           timeout = -1, userAgent = defUserAgent,
-           proxy: Proxy = nil,
-           multipart: MultipartData = nil): Response {.deprecated.} =
-  ## | POSTs ``body`` to the ``url`` and returns a ``Response`` object.
-  ## | This proc adds the necessary Content-Length header.
-  ## | This proc also handles redirection.
-  ## | Extra headers can be specified and must be separated by ``\c\L``.
-  ## | An optional timeout can be specified in milliseconds, if reading from the
-  ## server takes longer than specified an ETimeout exception will be raised.
-  ## | The optional ``multipart`` parameter can be used to create
-  ## ``multipart/form-data`` POSTs comfortably.
-  ##
-  ## **Deprecated since version 0.15.0**: use ``HttpClient.post`` instead.
-  let (mpContentType, mpBody) = format(multipart)
-
-  template withNewLine(x): untyped =
-    if x.len > 0 and not x.endsWith("\c\L"):
-      x & "\c\L"
-    else:
-      x
-
-  var xb = mpBody.withNewLine() & body
-
-  var xh = extraHeaders.withNewLine() &
-    withNewLine("Content-Length: " & $len(xb))
-
-  if not multipart.isNil:
-    xh.add(withNewLine("Content-Type: " & mpContentType))
-
-  result = request(url, HttpPOST, xh, xb, sslContext, timeout, userAgent,
-                   proxy)
-  var lastURL = url
-  for i in 1..maxRedirects:
-    if result.status.redirection():
-      let redirectTo = getNewLocation(lastURL, result.headers)
-      var meth = if result.status != "307": HttpGet else: HttpPost
-      result = request(redirectTo, meth, xh, xb, sslContext, timeout,
-                       userAgent, proxy)
-      lastURL = redirectTo
-
-proc postContent*(url: string, extraHeaders = "", body = "",
-                  maxRedirects = 5,
-                  sslContext: SSLContext = getDefaultSSL(),
-                  timeout = -1, userAgent = defUserAgent,
-                  proxy: Proxy = nil,
-                  multipart: MultipartData = nil): string
-                  {.deprecated.} =
-  ## | POSTs ``body`` to ``url`` and returns the response's body as a string
-  ## | Raises exceptions for the status codes ``4xx`` and ``5xx``
-  ## | Extra headers can be specified and must be separated by ``\c\L``.
-  ## | An optional timeout can be specified in milliseconds, if reading from the
-  ## server takes longer than specified an ETimeout exception will be raised.
-  ## | The optional ``multipart`` parameter can be used to create
-  ## ``multipart/form-data`` POSTs comfortably.
-  ##
-  ## **Deprecated since version 0.15.0**: use ``HttpClient.postContent``
-  ## instead.
-  var r = post(url, extraHeaders, body, maxRedirects, sslContext, timeout,
-               userAgent, proxy, multipart)
-  if r.status[0] in {'4','5'}:
-    raise newException(HttpRequestError, r.status)
-  else:
-    return r.body
-
-proc downloadFile*(url: string, outputFilename: string,
-                   sslContext: SSLContext = getDefaultSSL(),
-                   timeout = -1, userAgent = defUserAgent,
-                   proxy: Proxy = nil) {.deprecated.} =
-  ## | Downloads ``url`` and saves it to ``outputFilename``
-  ## | An optional timeout can be specified in milliseconds, if reading from the
-  ## server takes longer than specified an ETimeout exception will be raised.
-  ##
-  ## **Deprecated since version 0.16.2**: use ``HttpClient.downloadFile``
-  ## instead.
-  var f: File
-  if open(f, outputFilename, fmWrite):
-    f.write(getContent(url, sslContext = sslContext, timeout = timeout,
-            userAgent = userAgent, proxy = proxy))
-    f.close()
-  else:
-    fileError("Unable to open file")
-
 proc generateHeaders(requestUrl: Uri, httpMethod: string,
                      headers: HttpHeaders, body: string, proxy: Proxy): string =
   # GET
diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim
deleted file mode 100644
index a81e8c0a8..000000000
--- a/lib/pure/httpserver.nim
+++ /dev/null
@@ -1,535 +0,0 @@
-#
-#
-#            Nim's Runtime Library
-#        (c) Copyright 2012 Andreas Rumpf, Dominik Picheta
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## This module implements a simple HTTP-Server.
-##
-## **Warning**: This module will soon be deprecated in favour of
-## the ``asyncdispatch`` module, you should use it instead.
-##
-## Example:
-##
-## .. code-block:: nim
-##  import strutils, sockets, httpserver
-##
-##  var counter = 0
-##  proc handleRequest(client: Socket, path, query: string): bool {.procvar.} =
-##    inc(counter)
-##    client.send("Hello for the $#th time." % $counter & wwwNL)
-##    return false # do not stop processing
-##
-##  run(handleRequest, Port(80))
-##
-
-import parseutils, strutils, os, osproc, strtabs, streams, sockets, asyncio
-
-const
-  wwwNL* = "\r\L"
-  ServerSig = "Server: httpserver.nim/1.0.0" & wwwNL
-
-# --------------- output messages --------------------------------------------
-
-proc sendTextContentType(client: Socket) =
-  send(client, "Content-type: text/html" & wwwNL)
-  send(client, wwwNL)
-
-proc sendStatus(client: Socket, status: string) =
-  send(client, "HTTP/1.1 " & status & wwwNL)
-
-proc badRequest(client: Socket) =
-  # Inform the client that a request it has made has a problem.
-  send(client, "HTTP/1.1 400 Bad Request" & wwwNL)
-  sendTextContentType(client)
-  send(client, "<p>Your browser sent a bad request, " &
-               "such as a POST without a Content-Length.</p>" & wwwNL)
-
-when false:
-  proc cannotExec(client: Socket) =
-    send(client, "HTTP/1.1 500 Internal Server Error" & wwwNL)
-    sendTextContentType(client)
-    send(client, "<P>Error prohibited CGI execution." & wwwNL)
-
-proc headers(client: Socket, filename: string) =
-  # XXX could use filename to determine file type
-  send(client, "HTTP/1.1 200 OK" & wwwNL)
-  send(client, ServerSig)
-  sendTextContentType(client)
-
-proc notFound(client: Socket) =
-  send(client, "HTTP/1.1 404 NOT FOUND" & wwwNL)
-  send(client, ServerSig)
-  sendTextContentType(client)
-  send(client, "<html><title>Not Found</title>" & wwwNL)
-  send(client, "<body><p>The server could not fulfill" & wwwNL)
-  send(client, "your request because the resource specified" & wwwNL)
-  send(client, "is unavailable or nonexistent.</p>" & wwwNL)
-  send(client, "</body></html>" & wwwNL)
-
-proc unimplemented(client: Socket) =
-  send(client, "HTTP/1.1 501 Method Not Implemented" & wwwNL)
-  send(client, ServerSig)
-  sendTextContentType(client)
-  send(client, "<html><head><title>Method Not Implemented" &
-               "</title></head>" &
-               "<body><p>HTTP request method not supported.</p>" &
-               "</body></HTML>" & wwwNL)
-
-# ----------------- file serving ---------------------------------------------
-
-when false:
-  proc discardHeaders(client: Socket) = skip(client)
-
-proc serveFile*(client: Socket, filename: string) =
-  ## serves a file to the client.
-  var f: File
-  if open(f, filename):
-    headers(client, filename)
-    const bufSize = 8000 # != 8K might be good for memory manager
-    var buf = alloc(bufsize)
-    while true:
-      var bytesread = readBuffer(f, buf, bufsize)
-      if bytesread > 0:
-        var byteswritten = send(client, buf, bytesread)
-        if bytesread != bytesWritten:
-          dealloc(buf)
-          close(f)
-          raiseOSError(osLastError())
-      if bytesread != bufSize: break
-    dealloc(buf)
-    close(f)
-  else:
-    notFound(client)
-
-# ------------------ CGI execution -------------------------------------------
-when false:
-  # TODO: Fix this, or get rid of it.
-  type
-    RequestMethod = enum reqGet, reqPost
-
-  proc executeCgi(client: Socket, path, query: string, meth: RequestMethod) =
-    var env = newStringTable(modeCaseInsensitive)
-    var contentLength = -1
-    case meth
-    of reqGet:
-      discardHeaders(client)
-
-      env["REQUEST_METHOD"] = "GET"
-      env["QUERY_STRING"] = query
-    of reqPost:
-      var buf = TaintedString""
-      var dataAvail = false
-      while dataAvail:
-        dataAvail = recvLine(client, buf) # TODO: This is incorrect.
-        var L = toLowerAscii(buf.string)
-        if L.startsWith("content-length:"):
-          var i = len("content-length:")
-          while L[i] in Whitespace: inc(i)
-          contentLength = parseInt(substr(L, i))
-
-      if contentLength < 0:
-        badRequest(client)
-        return
-
-      env["REQUEST_METHOD"] = "POST"
-      env["CONTENT_LENGTH"] = $contentLength
-
-    send(client, "HTTP/1.0 200 OK" & wwwNL)
-
-    var process = startProcess(command=path, env=env)
-    if meth == reqPost:
-      # get from client and post to CGI program:
-      var buf = alloc(contentLength)
-      if recv(client, buf, contentLength) != contentLength:
-        dealloc(buf)
-        raiseOSError()
-      var inp = process.inputStream
-      inp.writeData(buf, contentLength)
-      dealloc(buf)
-
-    var outp = process.outputStream
-    var line = newStringOfCap(120).TaintedString
-    while true:
-      if outp.readLine(line):
-        send(client, line.string)
-        send(client, wwwNL)
-      elif not running(process): break
-
-  # --------------- Server Setup -----------------------------------------------
-
-  proc acceptRequest(client: Socket) =
-    var cgi = false
-    var query = ""
-    var buf = TaintedString""
-    discard recvLine(client, buf)
-    var path = ""
-    var data = buf.string.split()
-    var meth = reqGet
-
-    var q = find(data[1], '?')
-
-    # extract path
-    if q >= 0:
-      # strip "?..." from path, this may be found in both POST and GET
-      path = "." & data[1].substr(0, q-1)
-    else:
-      path = "." & data[1]
-    # path starts with "/", by adding "." in front of it we serve files from cwd
-
-    if cmpIgnoreCase(data[0], "GET") == 0:
-      if q >= 0:
-        cgi = true
-        query = data[1].substr(q+1)
-    elif cmpIgnoreCase(data[0], "POST") == 0:
-      cgi = true
-      meth = reqPost
-    else:
-      unimplemented(client)
-
-    if path[path.len-1] == '/' or existsDir(path):
-      path = path / "index.html"
-
-    if not existsFile(path):
-      discardHeaders(client)
-      notFound(client)
-    else:
-      when defined(Windows):
-        var ext = splitFile(path).ext.toLowerAscii
-        if ext == ".exe" or ext == ".cgi":
-          # XXX: extract interpreter information here?
-          cgi = true
-      else:
-        if {fpUserExec, fpGroupExec, fpOthersExec} * path.getFilePermissions != {}:
-          cgi = true
-      if not cgi:
-        serveFile(client, path)
-      else:
-        executeCgi(client, path, query, meth)
-
-type
-  Server* = object of RootObj  ## contains the current server state
-    socket: Socket
-    port: Port
-    client*: Socket          ## the socket to write the file data to
-    reqMethod*: string       ## Request method. GET or POST.
-    path*, query*: string    ## path and query the client requested
-    headers*: StringTableRef ## headers with which the client made the request
-    body*: string            ## only set with POST requests
-    ip*: string              ## ip address of the requesting client
-
-  PAsyncHTTPServer* = ref AsyncHTTPServer
-  AsyncHTTPServer = object of Server
-    asyncSocket: AsyncSocket
-
-proc open*(s: var Server, port = Port(80), reuseAddr = false) =
-  ## creates a new server at port `port`. If ``port == 0`` a free port is
-  ## acquired that can be accessed later by the ``port`` proc.
-  s.socket = socket(AF_INET)
-  if s.socket == invalidSocket: raiseOSError(osLastError())
-  if reuseAddr:
-    s.socket.setSockOpt(OptReuseAddr, true)
-  bindAddr(s.socket, port)
-  listen(s.socket)
-
-  if port == Port(0):
-    s.port = getSockName(s.socket)
-  else:
-    s.port = port
-  s.client = invalidSocket
-  s.reqMethod = ""
-  s.body = ""
-  s.path = ""
-  s.query = ""
-  s.headers = {:}.newStringTable()
-
-proc port*(s: var Server): Port =
-  ## get the port number the server has acquired.
-  result = s.port
-
-proc next*(s: var Server) =
-  ## proceed to the first/next request.
-  var client: Socket
-  new(client)
-  var ip: string
-  acceptAddr(s.socket, client, ip)
-  s.client = client
-  s.ip = ip
-  s.headers = newStringTable(modeCaseInsensitive)
-  #headers(s.client, "")
-  var data = ""
-  s.client.readLine(data)
-  if data == "":
-    # Socket disconnected
-    s.client.close()
-    next(s)
-    return
-  var header = ""
-  while true:
-    s.client.readLine(header)
-    if header == "\c\L": break
-    if header != "":
-      var i = 0
-      var key = ""
-      var value = ""
-      i = header.parseUntil(key, ':')
-      inc(i) # skip :
-      i += header.skipWhiteSpace(i)
-      i += header.parseUntil(value, {'\c', '\L'}, i)
-      s.headers[key] = value
-    else:
-      s.client.close()
-      next(s)
-      return
-
-  var i = skipWhitespace(data)
-  if skipIgnoreCase(data, "GET") > 0:
-    s.reqMethod = "GET"
-    inc(i, 3)
-  elif skipIgnoreCase(data, "POST") > 0:
-    s.reqMethod = "POST"
-    inc(i, 4)
-  else:
-    unimplemented(s.client)
-    s.client.close()
-    next(s)
-    return
-
-  if s.reqMethod == "POST":
-    # Check for Expect header
-    if s.headers.hasKey("Expect"):
-      if s.headers["Expect"].toLowerAscii == "100-continue":
-        s.client.sendStatus("100 Continue")
-      else:
-        s.client.sendStatus("417 Expectation Failed")
-
-    # Read the body
-    # - Check for Content-length header
-    if s.headers.hasKey("Content-Length"):
-      var contentLength = 0
-      if parseInt(s.headers["Content-Length"], contentLength) == 0:
-        badRequest(s.client)
-        s.client.close()
-        next(s)
-        return
-      else:
-        var totalRead = 0
-        var totalBody = ""
-        while totalRead < contentLength:
-          var chunkSize = 8000
-          if (contentLength - totalRead) < 8000:
-            chunkSize = (contentLength - totalRead)
-          var bodyData = newString(chunkSize)
-          var octetsRead = s.client.recv(cstring(bodyData), chunkSize)
-          if octetsRead <= 0:
-            s.client.close()
-            next(s)
-            return
-          totalRead += octetsRead
-          totalBody.add(bodyData)
-        if totalBody.len != contentLength:
-          s.client.close()
-          next(s)
-          return
-
-        s.body = totalBody
-    else:
-      badRequest(s.client)
-      s.client.close()
-      next(s)
-      return
-
-  var L = skipWhitespace(data, i)
-  inc(i, L)
-  # XXX we ignore "HTTP/1.1" etc. for now here
-  var query = 0
-  var last = i
-  while last < data.len and data[last] notin Whitespace:
-    if data[last] == '?' and query == 0: query = last
-    inc(last)
-  if query > 0:
-    s.query = data.substr(query+1, last-1)
-    s.path = data.substr(i, query-1)
-  else:
-    s.query = ""
-    s.path = data.substr(i, last-1)
-
-proc close*(s: Server) =
-  ## closes the server (and the socket the server uses).
-  close(s.socket)
-
-proc run*(handleRequest: proc (client: Socket,
-                               path, query: string): bool {.closure.},
-          port = Port(80)) =
-  ## encapsulates the server object and main loop
-  var s: Server
-  open(s, port, reuseAddr = true)
-  #echo("httpserver running on port ", s.port)
-  while true:
-    next(s)
-    if handleRequest(s.client, s.path, s.query): break
-    close(s.client)
-  close(s)
-
-# -- AsyncIO begin
-
-proc nextAsync(s: PAsyncHTTPServer) =
-  ## proceed to the first/next request.
-  var client: Socket
-  new(client)
-  var ip: string
-  acceptAddr(getSocket(s.asyncSocket), client, ip)
-  s.client = client
-  s.ip = ip
-  s.headers = newStringTable(modeCaseInsensitive)
-  #headers(s.client, "")
-  var data = ""
-  s.client.readLine(data)
-  if data == "":
-    # Socket disconnected
-    s.client.close()
-    return
-  var header = ""
-  while true:
-    s.client.readLine(header) # TODO: Very inefficient here. Prone to DOS.
-    if header == "\c\L": break
-    if header != "":
-      var i = 0
-      var key = ""
-      var value = ""
-      i = header.parseUntil(key, ':')
-      inc(i) # skip :
-      if i < header.len:
-        i += header.skipWhiteSpace(i)
-        i += header.parseUntil(value, {'\c', '\L'}, i)
-      s.headers[key] = value
-    else:
-      s.client.close()
-      return
-
-  var i = skipWhitespace(data)
-  if skipIgnoreCase(data, "GET") > 0:
-    s.reqMethod = "GET"
-    inc(i, 3)
-  elif skipIgnoreCase(data, "POST") > 0:
-    s.reqMethod = "POST"
-    inc(i, 4)
-  else:
-    unimplemented(s.client)
-    s.client.close()
-    return
-
-  if s.reqMethod == "POST":
-    # Check for Expect header
-    if s.headers.hasKey("Expect"):
-      if s.headers["Expect"].toLowerAscii == "100-continue":
-        s.client.sendStatus("100 Continue")
-      else:
-        s.client.sendStatus("417 Expectation Failed")
-
-    # Read the body
-    # - Check for Content-length header
-    if s.headers.hasKey("Content-Length"):
-      var contentLength = 0
-      if parseInt(s.headers["Content-Length"], contentLength) == 0:
-        badRequest(s.client)
-        s.client.close()
-        return
-      else:
-        var totalRead = 0
-        var totalBody = ""
-        while totalRead < contentLength:
-          var chunkSize = 8000
-          if (contentLength - totalRead) < 8000:
-            chunkSize = (contentLength - totalRead)
-          var bodyData = newString(chunkSize)
-          var octetsRead = s.client.recv(cstring(bodyData), chunkSize)
-          if octetsRead <= 0:
-            s.client.close()
-            return
-          totalRead += octetsRead
-          totalBody.add(bodyData)
-        if totalBody.len != contentLength:
-          s.client.close()
-          return
-
-        s.body = totalBody
-    else:
-      badRequest(s.client)
-      s.client.close()
-      return
-
-  var L = skipWhitespace(data, i)
-  inc(i, L)
-  # XXX we ignore "HTTP/1.1" etc. for now here
-  var query = 0
-  var last = i
-  while last < data.len and data[last] notin Whitespace:
-    if data[last] == '?' and query == 0: query = last
-    inc(last)
-  if query > 0:
-    s.query = data.substr(query+1, last-1)
-    s.path = data.substr(i, query-1)
-  else:
-    s.query = ""
-    s.path = data.substr(i, last-1)
-
-proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: Socket,
-                        path, query: string): bool {.closure, gcsafe.},
-                     port = Port(80), address = "",
-                     reuseAddr = false): PAsyncHTTPServer =
-  ## Creates an Asynchronous HTTP server at ``port``.
-  var capturedRet: PAsyncHTTPServer
-  new(capturedRet)
-  capturedRet.asyncSocket = asyncSocket()
-  capturedRet.asyncSocket.handleAccept =
-    proc (s: AsyncSocket) =
-      nextAsync(capturedRet)
-      let quit = handleRequest(capturedRet, capturedRet.client, capturedRet.path,
-                               capturedRet.query)
-      if quit: capturedRet.asyncSocket.close()
-  if reuseAddr:
-    capturedRet.asyncSocket.setSockOpt(OptReuseAddr, true)
-
-  capturedRet.asyncSocket.bindAddr(port, address)
-  capturedRet.asyncSocket.listen()
-  if port == Port(0):
-    capturedRet.port = getSockName(capturedRet.asyncSocket)
-  else:
-    capturedRet.port = port
-
-  capturedRet.client = invalidSocket
-  capturedRet.reqMethod = ""
-  capturedRet.body = ""
-  capturedRet.path = ""
-  capturedRet.query = ""
-  capturedRet.headers = {:}.newStringTable()
-  result = capturedRet
-
-proc register*(d: Dispatcher, s: PAsyncHTTPServer) =
-  ## Registers a ``PAsyncHTTPServer`` with a ``Dispatcher``.
-  d.register(s.asyncSocket)
-
-proc close*(h: PAsyncHTTPServer) =
-  ## Closes the ``PAsyncHTTPServer``.
-  h.asyncSocket.close()
-
-when not defined(testing) and isMainModule:
-  var counter = 0
-
-  var s: Server
-  open(s, Port(0))
-  echo("httpserver running on port ", s.port)
-  while true:
-    next(s)
-
-    inc(counter)
-    s.client.send("Hello, Andreas, for the $#th time. $# ? $#" % [
-      $counter, s.path, s.query] & wwwNL)
-
-    close(s.client)
-  close(s)
-
diff --git a/lib/pure/includes/osenv.nim b/lib/pure/includes/osenv.nim
index 4acc36b93..945555540 100644
--- a/lib/pure/includes/osenv.nim
+++ b/lib/pure/includes/osenv.nim
@@ -1,4 +1,4 @@
-## Include file that implements 'getEnv' and friends. Do not import it!
+# Include file that implements 'getEnv' and friends. Do not import it!
 
 when not declared(os):
   {.error: "This is an include file for os.nim!".}
diff --git a/lib/pure/includes/oserr.nim b/lib/pure/includes/oserr.nim
index abd0bf501..db7d84c1e 100644
--- a/lib/pure/includes/oserr.nim
+++ b/lib/pure/includes/oserr.nim
@@ -1,4 +1,4 @@
-## Include file that implements 'osErrorMsg' and friends. Do not import it!
+# Include file that implements 'osErrorMsg' and friends. Do not import it!
 
 when not declared(os):
   {.error: "This is an include file for os.nim!".}
@@ -59,7 +59,7 @@ proc raiseOSError*(errorCode: OSErrorCode; additionalInfo = "") {.noinline.} =
   e.errorCode = errorCode.int32
   e.msg = osErrorMsg(errorCode)
   if additionalInfo.len > 0:
-    if e.msg[^1] != '\n': e.msg.add '\n'
+    if e.msg.len > 0 and e.msg[^1] != '\n': e.msg.add '\n'
     e.msg.add  "Additional info: "
     e.msg.addQuoted additionalInfo
   if e.msg == "":
diff --git a/lib/pure/includes/osseps.nim b/lib/pure/includes/osseps.nim
index 9a79fe303..944ad123e 100644
--- a/lib/pure/includes/osseps.nim
+++ b/lib/pure/includes/osseps.nim
@@ -85,9 +85,9 @@ elif doslikeFileSystem:
   const
     CurDir* = '.'
     ParDir* = ".."
-    DirSep* = '\\' # seperator within paths
+    DirSep* = '\\' # separator within paths
     AltSep* = '/'
-    PathSep* = ';' # seperator between paths
+    PathSep* = ';' # separator between paths
     FileSystemCaseSensitive* = false
     ExeExt* = "exe"
     ScriptExt* = "bat"
diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim
index 16d901ff0..ffd60120e 100644
--- a/lib/pure/ioselects/ioselectors_epoll.nim
+++ b/lib/pure/ioselects/ioselectors_epoll.nim
@@ -53,6 +53,7 @@ when hasThreadSupport:
     SelectorImpl[T] = object
       epollFD: cint
       maxFD: int
+      numFD: int
       fds: ptr SharedArray[SelectorKey[T]]
       count: int
     Selector*[T] = ptr SelectorImpl[T]
@@ -61,6 +62,7 @@ else:
     SelectorImpl[T] = object
       epollFD: cint
       maxFD: int
+      numFD: int
       fds: seq[SelectorKey[T]]
       count: int
     Selector*[T] = ref SelectorImpl[T]
@@ -76,6 +78,8 @@ proc newSelector*[T](): Selector[T] =
     raiseOsError(osLastError())
   var maxFD = int(a.rlim_max)
   doAssert(maxFD > 0)
+  # Start with a reasonable size, checkFd() will grow this on demand
+  const numFD = 1024
 
   var epollFD = epoll_create(MAX_EPOLL_EVENTS)
   if epollFD < 0:
@@ -85,14 +89,16 @@ proc newSelector*[T](): Selector[T] =
     result = cast[Selector[T]](allocShared0(sizeof(SelectorImpl[T])))
     result.epollFD = epollFD
     result.maxFD = maxFD
-    result.fds = allocSharedArray[SelectorKey[T]](maxFD)
+    result.numFD = numFD
+    result.fds = allocSharedArray[SelectorKey[T]](numFD)
   else:
     result = Selector[T]()
     result.epollFD = epollFD
     result.maxFD = maxFD
-    result.fds = newSeq[SelectorKey[T]](maxFD)
+    result.numFD = numFD
+    result.fds = newSeq[SelectorKey[T]](numFD)
 
-  for i in 0 ..< maxFD:
+  for i in 0 ..< numFD:
     result.fds[i].ident = InvalidIdent
 
 proc close*[T](s: Selector[T]) =
@@ -127,6 +133,16 @@ template checkFd(s, f) =
   # FD if there is too many. -- DP
   if f >= s.maxFD:
     raiseIOSelectorsError("Maximum number of descriptors is exhausted!")
+  if f >= s.numFD:
+    var numFD = s.numFD
+    while numFD <= f: numFD *= 2
+    when hasThreadSupport:
+      s.fds = reallocSharedArray(s.fds, numFD)
+    else:
+      s.fds.setLen(numFD)
+    for i in s.numFD ..< numFD:
+      s.fds[i].ident = InvalidIdent
+    s.numFD = numFD
 
 proc registerHandle*[T](s: Selector[T], fd: int | SocketHandle,
                         events: set[Event], data: T) =
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 389df4087..cf979e2d0 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -134,8 +134,16 @@
 ##    j2["details"] = %* {"age":35, "pi":3.1415}
 ##    echo j2
 
+runnableExamples:
+  ## Note: for JObject, key ordering is preserved, unlike in some languages,
+  ## this is convenient for some use cases. Example:
+  type Foo = object
+    a1, a2, a0, a3, a4: int
+  doAssert $(%* Foo()) == """{"a1":0,"a2":0,"a0":0,"a3":0,"a4":0}"""
+
 import
-  hashes, tables, strutils, lexbase, streams, unicode, macros, parsejson
+  hashes, tables, strutils, lexbase, streams, unicode, macros, parsejson,
+  typetraits
 
 export
   tables.`$`
@@ -349,6 +357,25 @@ when false:
     assert false notin elements, "usage error: only empty sets allowed"
     assert true notin elements, "usage error: only empty sets allowed"
 
+proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} =
+  ## Sets a field from a `JObject`.
+  assert(obj.kind == JObject)
+  obj.fields[key] = val
+
+#[
+Note: could use simply:
+proc `%`*(o: object|tuple): JsonNode
+but blocked by https://github.com/nim-lang/Nim/issues/10019
+]#
+proc `%`*(o: tuple): JsonNode =
+  ## Generic constructor for JSON data. Creates a new `JObject JsonNode`
+  when isNamedTuple(type(o)):
+    result = newJObject()
+    for k, v in o.fieldPairs: result[k] = %v
+  else:
+    result = newJArray()
+    for a in o.fields: result.add(%a)
+
 proc `%`*(o: object): JsonNode =
   ## Generic constructor for JSON data. Creates a new `JObject JsonNode`
   result = newJObject()
@@ -500,11 +527,6 @@ proc contains*(node: JsonNode, val: JsonNode): bool =
 proc existsKey*(node: JsonNode, key: string): bool {.deprecated: "use hasKey instead".} = node.hasKey(key)
   ## **Deprecated:** use `hasKey` instead.
 
-proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} =
-  ## Sets a field from a `JObject`.
-  assert(obj.kind == JObject)
-  obj.fields[key] = val
-
 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
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
index cd13deec3..febd0b602 100644
--- a/lib/pure/logging.nim
+++ b/lib/pure/logging.nim
@@ -12,7 +12,7 @@
 ## write your own.
 ##
 ## Format strings support the following variables which must be prefixed with
-## the dollar operator (``$``):
+## the dollar operator (``$``, see example below):
 ##
 ## ============  =======================
 ##   Operator     Output
@@ -43,6 +43,11 @@
 ##    warn("4 8 15 16 23 4-- Error")
 ##    error("922044:16 SYSTEM FAILURE")
 ##    fatal("SYSTEM FAILURE SYSTEM FAILURE")
+##    # Using the aformetioned operator
+##    var opL = newConsoleLogger(fmtStr = "$datetime :: ")
+##    addHandler(opL)
+##    info("Starting web server...")
+##    # Will print something like 2018-12-17T19:28:05 :: Starting web server...
 ##
 ## **Warning:** The global list of handlers is a thread var, this means that
 ## the handlers must be re-added in each thread.
diff --git a/lib/pure/matchers.nim b/lib/pure/matchers.nim
deleted file mode 100644
index 97223ed01..000000000
--- a/lib/pure/matchers.nim
+++ /dev/null
@@ -1,68 +0,0 @@
-#
-#
-#            Nim's Runtime Library
-#        (c) Copyright 2015 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## This module contains various string matchers for email addresses, etc.
-##
-## **Warning:** This module is deprecated since version 0.14.0.
-{.deprecated.}
-
-{.deadCodeElim: on.}  # dce option deprecated
-
-{.push debugger:off .} # the user does not want to trace a part
-                       # of the standard library!
-
-include "system/inclrtl"
-
-import parseutils, strutils
-
-proc validEmailAddress*(s: string): bool {.noSideEffect,
-  rtl, extern: "nsuValidEmailAddress".} =
-  ## returns true if `s` seems to be a valid e-mail address.
-  ## The checking also uses a domain list.
-  const
-    chars = Letters + Digits + {'!','#','$','%','&',
-      '\'','*','+','/','=','?','^','_','`','{','}','|','~','-','.'}
-  var i = 0
-  if i >= s.len or s[i] notin chars or s[i] == '.': return false
-  while i < s.len and s[i] in chars:
-    if i+1 < s.len and s[i] == '.' and s[i+1] == '.': return false
-    inc(i)
-  if i >= s.len or s[i] != '@': return false
-  var j = len(s)-1
-  if j >= 0 and s[j] notin Letters: return false
-  while j >= i and s[j] in Letters: dec(j)
-  inc(i) # skip '@'
-  while i < s.len and s[i] in {'0'..'9', 'a'..'z', '-', '.'}: inc(i)
-  if i != s.len: return false
-
-  var x = substr(s, j+1)
-  if len(x) == 2 and x[0] in Letters and x[1] in Letters: return true
-  case toLowerAscii(x)
-  of "com", "org", "net", "gov", "mil", "biz", "info", "mobi", "name",
-     "aero", "jobs", "museum": return true
-  else: return false
-
-proc parseInt*(s: string, value: var int, validRange: HSlice[int, int]) {.
-  noSideEffect, rtl, extern: "nmatchParseInt".} =
-  ## parses `s` into an integer in the range `validRange`. If successful,
-  ## `value` is modified to contain the result. Otherwise no exception is
-  ## raised and `value` is not touched; this way a reasonable default value
-  ## won't be overwritten.
-  var x = value
-  try:
-    discard parseutils.parseInt(s, x, 0)
-  except OverflowError:
-    discard
-  if x in validRange: value = x
-
-when isMainModule:
-  doAssert "wuseldusel@codehome.com".validEmailAddress
-
-{.pop.}
-
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index ee32772b1..460be1cd0 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -7,15 +7,48 @@
 #    distribution, for details about the copyright.
 #
 
-##   Constructive mathematics is naturally typed. -- Simon Thompson
+## *Constructive mathematics is naturally typed.* -- Simon Thompson
 ##
 ## Basic math routines for Nim.
+##
+## Note that the trigonometric functions naturally operate on radians.
+## The helper functions `degToRad<#degToRad,T>`_ and `radToDeg<#radToDeg,T>`_
+## provide conversion between radians and degrees.
+##
+## .. code-block::
+##
+##   import math
+##   from sequtils import map
+##
+##   let a = [0.0, PI/6, PI/4, PI/3, PI/2]
+##
+##   echo a.map(sin)
+##   # @[0.0, 0.499…, 0.707…, 0.866…, 1.0]
+##
+##   echo a.map(tan)
+##   # @[0.0, 0.577…, 0.999…, 1.732…, 1.633…e+16]
+##
+##   echo cos(degToRad(180.0))
+##   # -1.0
+##
+##   echo sqrt(-1.0)
+##   # nan   (use `complex` module)
+##
 ## This module is available for the `JavaScript target
 ## <backends.html#the-javascript-target>`_.
 ##
-## Note that the trigonometric functions naturally operate on radians.
-## The helper functions `degToRad` and `radToDeg` provide conversion
-## between radians and degrees.
+## **See also:**
+## * `complex module<complex.html>`_ for complex numbers and their
+##   mathematical operations
+## * `rationals module<rationals.html>`_ for rational numbers and their
+##   mathematical operations
+## * `fenv module<fenv.html>`_ for handling of floating-point rounding
+##   and exceptions (overflow, zero-devide, etc.)
+## * `random module<random.html>`_ for fast and tiny random number generator
+## * `mersenne module<mersenne.html>`_ for Mersenne twister random number generator
+## * `stats module<stats.html>`_ for statistical analysis
+## * `strformat module<strformat>`_ for formatting floats for print
+
 
 include "system/inclrtl"
 {.push debugger:off .} # the user does not want to trace a part
@@ -25,9 +58,11 @@ import bitops
 
 proc binom*(n, k: int): int {.noSideEffect.} =
   ## Computes the `binomial coefficient <https://en.wikipedia.org/wiki/Binomial_coefficient>`_.
-  ##
-  ## .. code-block:: nim
-  ##  echo binom(6, 2) ## 15
+  runnableExamples:
+    doAssert binom(6, 2) == binom(6, 4)
+    doAssert binom(6, 2) == 15
+    doAssert binom(-6, 2) == 1
+    doAssert binom(6, 0) == 1
   if k <= 0: return 1
   if 2*k > n: return binom(n, n-k)
   result = n
@@ -40,10 +75,15 @@ proc createFactTable[N: static[int]]: array[N, int] =
     result[i] = result[i - 1] * i
 
 proc fac*(n: int): int =
-  ## Computes the `factorial <https://en.wikipedia.org/wiki/Factorial>`_ of a non-negative integer ``n``
+  ## Computes the `factorial <https://en.wikipedia.org/wiki/Factorial>`_ of
+  ## a non-negative integer ``n``.
   ##
-  ## .. code-block:: nim
-  ##  echo fac(4) ## 24
+  ## See also:
+  ## * `prod proc <#prod,openArray[T]>`_
+  runnableExamples:
+    doAssert fac(3) == 6
+    doAssert fac(4) == 24
+    doAssert fac(10) == 3628800
   const factTable =
     when sizeof(int) == 4:
       createFactTable[13]()
@@ -59,25 +99,26 @@ when defined(Posix):
   {.passl: "-lm".}
 
 const
-  PI* = 3.1415926535897932384626433 ## the circle constant PI (Ludolph's number)
-  TAU* = 2.0 * PI ## the circle constant TAU (= 2 * PI)
+  PI* = 3.1415926535897932384626433 ## The circle constant PI (Ludolph's number)
+  TAU* = 2.0 * PI ## The circle constant TAU (= 2 * PI)
   E* = 2.71828182845904523536028747 ## Euler's number
 
-  MaxFloat64Precision* = 16 ## maximum number of meaningful digits
+  MaxFloat64Precision* = 16 ## Maximum number of meaningful digits
                             ## after the decimal point for Nim's
                             ## ``float64`` type.
-  MaxFloat32Precision* = 8  ## maximum number of meaningful digits
+  MaxFloat32Precision* = 8  ## Maximum number of meaningful digits
                             ## after the decimal point for Nim's
                             ## ``float32`` type.
-  MaxFloatPrecision* = MaxFloat64Precision ## maximum number of
+  MaxFloatPrecision* = MaxFloat64Precision ## Maximum number of
                                            ## meaningful digits
                                            ## after the decimal point
                                            ## for Nim's ``float`` type.
-  RadPerDeg = PI / 180.0 ## number of radians per degree
+  RadPerDeg = PI / 180.0 ## Number of radians per degree
 
 type
-  FloatClass* = enum ## describes the class a floating point value belongs to.
-                     ## This is the type that is returned by `classify`.
+  FloatClass* = enum ## Describes the class a floating point value belongs to.
+                     ## This is the type that is returned by
+                     ## `classify proc <#classify,float>`_.
     fcNormal,    ## value is an ordinary nonzero floating point value
     fcSubnormal, ## value is a subnormal (a very small) floating point value
     fcZero,      ## value is zero
@@ -87,13 +128,14 @@ type
     fcNegInf     ## value is negative infinity
 
 proc classify*(x: float): FloatClass =
-  ## Classifies a floating point value. Returns ``x``'s class as specified by
-  ## `FloatClass`.
+  ## Classifies a floating point value.
   ##
-  ## .. code-block:: nim
-  ##  echo classify(0.3) ## fcNormal
-  ##  echo classify(0.0) ## fcZero
-  ##  echo classify(0.3/0.0) ## fcInf
+  ## Returns ``x``'s class as specified by `FloatClass enum<#FloatClass>`_.
+  runnableExamples:
+    doAssert classify(0.3) == fcNormal
+    doAssert classify(0.0) == fcZero
+    doAssert classify(0.3/0.0) == fcInf
+    doAssert classify(-0.3/0.0) == fcNegInf
 
   # JavaScript and most C compilers have no classify:
   if x == 0.0:
@@ -110,20 +152,30 @@ proc classify*(x: float): FloatClass =
 
 proc isPowerOfTwo*(x: int): bool {.noSideEffect.} =
   ## Returns ``true``, if ``x`` is a power of two, ``false`` otherwise.
+  ##
   ## Zero and negative numbers are not a power of two.
   ##
-  ## .. code-block:: nim
-  ##  echo isPowerOfTwo(5) ## false
-  ##  echo isPowerOfTwo(8) ## true
+  ## See also:
+  ## * `nextPowerOfTwo proc<#nextPowerOfTwo,int>`_
+  runnableExamples:
+    doAssert isPowerOfTwo(16) == true
+    doAssert isPowerOfTwo(5) == false
+    doAssert isPowerOfTwo(0) == false
+    doAssert isPowerOfTwo(-16) == false
   return (x > 0) and ((x and (x - 1)) == 0)
 
 proc nextPowerOfTwo*(x: int): int {.noSideEffect.} =
   ## Returns ``x`` rounded up to the nearest power of two.
+  ##
   ## Zero and negative numbers get rounded up to 1.
   ##
-  ## .. code-block:: nim
-  ##  echo nextPowerOfTwo(8) ## 8
-  ##  echo nextPowerOfTwo(9) ## 16
+  ## See also:
+  ## * `isPowerOfTwo proc<#isPowerOfTwo,int>`_
+  runnableExamples:
+    doAssert nextPowerOfTwo(16) == 16
+    doAssert nextPowerOfTwo(5) == 8
+    doAssert nextPowerOfTwo(0) == 1
+    doAssert nextPowerOfTwo(-16) == 1
   result = x - 1
   when defined(cpu64):
     result = result or (result shr 32)
@@ -138,9 +190,12 @@ proc nextPowerOfTwo*(x: int): int {.noSideEffect.} =
 
 proc countBits32*(n: int32): int {.noSideEffect.} =
   ## Counts the set bits in ``n``.
-  ##
-  ## .. code-block:: nim
-  ##  echo countBits32(13'i32) ## 3
+  runnableExamples:
+    doAssert countBits32(7) == 3
+    doAssert countBits32(8) == 1
+    doAssert countBits32(15) == 4
+    doAssert countBits32(16) == 1
+    doAssert countBits32(17) == 2
   var v = n
   v = v -% ((v shr 1'i32) and 0x55555555'i32)
   v = (v and 0x33333333'i32) +% ((v shr 2'i32) and 0x33333333'i32)
@@ -148,41 +203,99 @@ proc countBits32*(n: int32): int {.noSideEffect.} =
 
 proc sum*[T](x: openArray[T]): T {.noSideEffect.} =
   ## Computes the sum of the elements in ``x``.
+  ##
   ## If ``x`` is empty, 0 is returned.
   ##
-  ## .. code-block:: nim
-  ##  echo sum([1.0, 2.5, -3.0, 4.3]) ## 4.8
+  ## See also:
+  ## * `prod proc <#prod,openArray[T]>`_
+  ## * `cumsum proc <#cumsum,openArray[T]>`_
+  ## * `cumsummed proc <#cumsummed,openArray[T]>`_
+  runnableExamples:
+    doAssert sum([1, 2, 3, 4]) == 10
+    doAssert sum([-1.5, 2.7, -0.1]) == 1.1
   for i in items(x): result = result + i
 
 proc prod*[T](x: openArray[T]): T {.noSideEffect.} =
   ## Computes the product of the elements in ``x``.
+  ##
   ## If ``x`` is empty, 1 is returned.
   ##
-  ## .. code-block:: nim
-  ##  echo prod([1.0, 3.0, -0.2]) ## -0.6
+  ## See also:
+  ## * `sum proc <#sum,openArray[T]>`_
+  ## * `fac proc <#fac,int>`_
+  runnableExamples:
+    doAssert prod([1, 2, 3, 4]) == 24
+    doAssert prod([-4, 3, 5]) == -60
   result = 1.T
   for i in items(x): result = result * i
 
+proc cumsummed*[T](x: openArray[T]): seq[T] =
+  ## Return cumulative (aka prefix) summation of ``x``.
+  ##
+  ## See also:
+  ## * `sum proc <#sum,openArray[T]>`_
+  ## * `cumsum proc <#cumsum,openArray[T]>`_ for the in-place version
+  runnableExamples:
+    let a = [1, 2, 3, 4]
+    doAssert cumsummed(a) == @[1, 3, 6, 10]
+  result.setLen(x.len)
+  result[0] = x[0]
+  for i in 1 ..< x.len: result[i] = result[i-1] + x[i]
+
+proc cumsum*[T](x: var openArray[T]) =
+  ## Transforms ``x`` in-place (must be declared as `var`) into its
+  ## cumulative (aka prefix) summation.
+  ##
+  ## See also:
+  ## * `sum proc <#sum,openArray[T]>`_
+  ## * `cumsummed proc <#cumsummed,openArray[T]>`_ for a version which
+  ##   returns cumsummed sequence
+  runnableExamples:
+    var a = [1, 2, 3, 4]
+    cumsum(a)
+    doAssert a == @[1, 3, 6, 10]
+  for i in 1 ..< x.len: x[i] = x[i-1] + x[i]
+
 {.push noSideEffect.}
 when not defined(JS): # C
   proc sqrt*(x: float32): float32 {.importc: "sqrtf", header: "<math.h>".}
   proc sqrt*(x: float64): float64 {.importc: "sqrt", header: "<math.h>".}
     ## Computes the square root of ``x``.
     ##
+    ## See also:
+    ## * `cbrt proc <#cbrt,float64>`_ for cubic root
+    ##
     ## .. code-block:: nim
+    ##  echo sqrt(4.0)  ## 2.0
     ##  echo sqrt(1.44) ## 1.2
+    ##  echo sqrt(-4.0) ## nan
   proc cbrt*(x: float32): float32 {.importc: "cbrtf", header: "<math.h>".}
   proc cbrt*(x: float64): float64 {.importc: "cbrt", header: "<math.h>".}
     ## Computes the cubic root of ``x``.
     ##
+    ## See also:
+    ## * `sqrt proc <#sqrt,float64>`_ for square root
+    ##
     ## .. code-block:: nim
+    ##  echo cbrt(8.0)   ## 2.0
     ##  echo cbrt(2.197) ## 1.3
+    ##  echo cbrt(-27.0) ## -3.0
   proc ln*(x: float32): float32 {.importc: "logf", header: "<math.h>".}
   proc ln*(x: float64): float64 {.importc: "log", header: "<math.h>".}
-    ## Computes the `natural logarithm <https://en.wikipedia.org/wiki/Natural_logarithm>`_ of ``x``.
+    ## Computes the `natural logarithm <https://en.wikipedia.org/wiki/Natural_logarithm>`_
+    ## of ``x``.
+    ##
+    ## See also:
+    ## * `log proc <#log,T,T>`_
+    ## * `log10 proc <#log10,float64>`_
+    ## * `log2 proc <#log2,float64>`_
+    ## * `exp proc <#exp,float64>`_
     ##
     ## .. code-block:: nim
     ##  echo ln(exp(4.0)) ## 4.0
+    ##  echo ln(1.0))     ## 0.0
+    ##  echo ln(0.0)      ## -inf
+    ##  echo ln(-7.0)     ## nan
 else: # JS
   proc sqrt*(x: float32): float32 {.importc: "Math.sqrt", nodecl.}
   proc sqrt*(x: float64): float64 {.importc: "Math.sqrt", nodecl.}
@@ -193,8 +306,18 @@ else: # JS
 proc log*[T: SomeFloat](x, base: T): T =
   ## Computes the logarithm of ``x`` to base ``base``.
   ##
+  ## See also:
+  ## * `ln proc <#ln,float64>`_
+  ## * `log10 proc <#log10,float64>`_
+  ## * `log2 proc <#log2,float64>`_
+  ## * `exp proc <#exp,float64>`_
+  ##
   ## .. code-block:: nim
-  ##  echo log(9.0, 3.0) ## 2.0
+  ##  echo log(9.0, 3.0)  ## 2.0
+  ##  echo log(32.0, 2.0) ## 5.0
+  ##  echo log(0.0, 2.0)  ## -inf
+  ##  echo log(-7.0, 4.0) ## nan
+  ##  echo log(8.0, -2.0) ## nan
   ln(x) / ln(base)
 
 when not defined(JS): # C
@@ -202,77 +325,164 @@ when not defined(JS): # C
   proc log10*(x: float64): float64 {.importc: "log10", header: "<math.h>".}
     ## Computes the common logarithm (base 10) of ``x``.
     ##
+    ## See also:
+    ## * `ln proc <#ln,float64>`_
+    ## * `log proc <#log,T,T>`_
+    ## * `log2 proc <#log2,float64>`_
+    ## * `exp proc <#exp,float64>`_
+    ##
     ## .. code-block:: nim
-    ##  echo log10(100.0) ## 2.0
+    ##  echo log10(100.0)  ## 2.0
+    ##  echo log10(0.0)    ## nan
+    ##  echo log10(-100.0) ## -inf
   proc exp*(x: float32): float32 {.importc: "expf", header: "<math.h>".}
   proc exp*(x: float64): float64 {.importc: "exp", header: "<math.h>".}
-    ## Computes the exponential function of ``x`` (pow(E, x)).
+    ## Computes the exponential function of ``x`` (e^x).
+    ##
+    ## See also:
+    ## * `ln proc <#ln,float64>`_
+    ## * `log proc <#log,T,T>`_
+    ## * `log10 proc <#log10,float64>`_
+    ## * `log2 proc <#log2,float64>`_
     ##
     ## .. code-block:: nim
-    ##  echo exp(1.0) ## 2.718281828459045
+    ##  echo exp(1.0)     ## 2.718281828459045
     ##  echo ln(exp(4.0)) ## 4.0
+    ##  echo exp(0.0)     ## 1.0
+    ##  echo exp(-1.0)    ## 0.3678794411714423
   proc sin*(x: float32): float32 {.importc: "sinf", header: "<math.h>".}
   proc sin*(x: float64): float64 {.importc: "sin", header: "<math.h>".}
     ## Computes the sine of ``x``.
     ##
+    ## See also:
+    ## * `cos proc <#cos,float64>`_
+    ## * `tan proc <#tan,float64>`_
+    ## * `arcsin proc <#arcsin,float64>`_
+    ## * `sinh proc <#sinh,float64>`_
+    ##
     ## .. code-block:: nim
-    ##  echo sin(PI / 6) ## 0.4999999999999999
+    ##  echo sin(PI / 6)         ## 0.4999999999999999
     ##  echo sin(degToRad(90.0)) ## 1.0
   proc cos*(x: float32): float32 {.importc: "cosf", header: "<math.h>".}
   proc cos*(x: float64): float64 {.importc: "cos", header: "<math.h>".}
     ## Computes the cosine of ``x``.
     ##
+    ## See also:
+    ## * `sin proc <#sin,float64>`_
+    ## * `tan proc <#tan,float64>`_
+    ## * `arccos proc <#arccos,float64>`_
+    ## * `cosh proc <#cosh,float64>`_
+    ##
     ## .. code-block:: nim
-    ##  echo cos(2 * PI) ## 1.0
+    ##  echo cos(2 * PI)         ## 1.0
     ##  echo cos(degToRad(60.0)) ## 0.5000000000000001
   proc tan*(x: float32): float32 {.importc: "tanf", header: "<math.h>".}
   proc tan*(x: float64): float64 {.importc: "tan", header: "<math.h>".}
     ## Computes the tangent of ``x``.
     ##
+    ## See also:
+    ## * `sin proc <#sin,float64>`_
+    ## * `cos proc <#cos,float64>`_
+    ## * `arctan proc <#arctan,float64>`_
+    ## * `tanh proc <#tanh,float64>`_
+    ##
     ## .. code-block:: nim
     ##  echo tan(degToRad(45.0)) ## 0.9999999999999999
-    ##  echo tan(PI / 4) ## 0.9999999999999999
+    ##  echo tan(PI / 4)         ## 0.9999999999999999
   proc sinh*(x: float32): float32 {.importc: "sinhf", header: "<math.h>".}
   proc sinh*(x: float64): float64 {.importc: "sinh", header: "<math.h>".}
     ## Computes the `hyperbolic sine <https://en.wikipedia.org/wiki/Hyperbolic_function#Definitions>`_ of ``x``.
     ##
+    ## See also:
+    ## * `cosh proc <#cosh,float64>`_
+    ## * `tanh proc <#tanh,float64>`_
+    ## * `arcsinh proc <#arcsinh,float64>`_
+    ## * `sin proc <#sin,float64>`_
+    ##
     ## .. code-block:: nim
-    ##  echo sinh(1.0) ## 1.175201193643801
+    ##  echo sinh(0.0)            ## 0.0
+    ##  echo sinh(1.0)            ## 1.175201193643801
+    ##  echo sinh(degToRad(90.0)) ## 2.301298902307295
   proc cosh*(x: float32): float32 {.importc: "coshf", header: "<math.h>".}
   proc cosh*(x: float64): float64 {.importc: "cosh", header: "<math.h>".}
     ## Computes the `hyperbolic cosine <https://en.wikipedia.org/wiki/Hyperbolic_function#Definitions>`_ of ``x``.
     ##
+    ## See also:
+    ## * `sinh proc <#sinh,float64>`_
+    ## * `tanh proc <#tanh,float64>`_
+    ## * `arccosh proc <#arccosh,float64>`_
+    ## * `cos proc <#cos,float64>`_
+    ##
     ## .. code-block:: nim
-    ##  echo cosh(1.0) ## 1.543080634815244
+    ##  echo cosh(0.0)            ## 1.0
+    ##  echo cosh(1.0)            ## 1.543080634815244
+    ##  echo cosh(degToRad(90.0)) ## 2.509178478658057
   proc tanh*(x: float32): float32 {.importc: "tanhf", header: "<math.h>".}
   proc tanh*(x: float64): float64 {.importc: "tanh", header: "<math.h>".}
     ## Computes the `hyperbolic tangent <https://en.wikipedia.org/wiki/Hyperbolic_function#Definitions>`_ of ``x``.
     ##
+    ## See also:
+    ## * `sinh proc <#sinh,float64>`_
+    ## * `cosh proc <#cosh,float64>`_
+    ## * `arctanh proc <#arctanh,float64>`_
+    ## * `tan proc <#tan,float64>`_
+    ##
     ## .. code-block:: nim
-    ##  echo tanh(1.0) ## 0.7615941559557649
+    ##  echo tanh(0.0)            ## 0.0
+    ##  echo tanh(1.0)            ## 0.7615941559557649
+    ##  echo tanh(degToRad(90.0)) ## 0.9171523356672744
 
   proc arccos*(x: float32): float32 {.importc: "acosf", header: "<math.h>".}
   proc arccos*(x: float64): float64 {.importc: "acos", header: "<math.h>".}
     ## Computes the arc cosine of ``x``.
     ##
+    ## See also:
+    ## * `arcsin proc <#arcsin,float64>`_
+    ## * `arctan proc <#arctan,float64>`_
+    ## * `arctan2 proc <#arctan2,float64,float64>`_
+    ## * `cos proc <#cos,float64>`_
+    ##
     ## .. code-block:: nim
-    ##  echo arccos(1.0) ## 0.0
+    ##  echo radToDeg(arccos(0.0)) ## 90.0
+    ##  echo radToDeg(arccos(1.0)) ## 0.0
   proc arcsin*(x: float32): float32 {.importc: "asinf", header: "<math.h>".}
   proc arcsin*(x: float64): float64 {.importc: "asin", header: "<math.h>".}
     ## Computes the arc sine of ``x``.
+    ##
+    ## See also:
+    ## * `arccos proc <#arccos,float64>`_
+    ## * `arctan proc <#arctan,float64>`_
+    ## * `arctan2 proc <#arctan2,float64,float64>`_
+    ## * `sin proc <#sin,float64>`_
+    ##
+    ## .. code-block:: nim
+    ##  echo radToDeg(arcsin(0.0)) ## 0.0
+    ##  echo radToDeg(arcsin(1.0)) ## 90.0
   proc arctan*(x: float32): float32 {.importc: "atanf", header: "<math.h>".}
   proc arctan*(x: float64): float64 {.importc: "atan", header: "<math.h>".}
     ## Calculate the arc tangent of ``x``.
     ##
+    ## See also:
+    ## * `arcsin proc <#arcsin,float64>`_
+    ## * `arccos proc <#arccos,float64>`_
+    ## * `arctan2 proc <#arctan2,float64,float64>`_
+    ## * `tan proc <#tan,float64>`_
+    ##
     ## .. code-block:: nim
     ##  echo arctan(1.0) ## 0.7853981633974483
     ##  echo radToDeg(arctan(1.0)) ## 45.0
   proc arctan2*(y, x: float32): float32 {.importc: "atan2f", header: "<math.h>".}
   proc arctan2*(y, x: float64): float64 {.importc: "atan2", header: "<math.h>".}
     ## Calculate the arc tangent of ``y`` / ``x``.
-    ## `arctan2` returns the arc tangent of ``y`` / ``x``; it produces correct
-    ## results even when the resulting angle is near pi/2 or -pi/2
-    ## (``x`` near 0).
+    ##
+    ## It produces correct results even when the resulting angle is near
+    ## pi/2 or -pi/2 (``x`` near 0).
+    ##
+    ## See also:
+    ## * `arcsin proc <#arcsin,float64>`_
+    ## * `arccos proc <#arccos,float64>`_
+    ## * `arctan proc <#arctan,float64>`_
+    ## * `tan proc <#tan,float64>`_
     ##
     ## .. code-block:: nim
     ##  echo arctan2(1.0, 0.0) ## 1.570796326794897
@@ -313,18 +523,18 @@ else: # JS
   proc arctanh*[T: float32|float64](x: T): T {.importc: "Math.atanh", nodecl.}
 
 proc cot*[T: float32|float64](x: T): T = 1.0 / tan(x)
-  ## Computes the cotangent of ``x``.
+  ## Computes the cotangent of ``x`` (1 / tan(x)).
 proc sec*[T: float32|float64](x: T): T = 1.0 / cos(x)
-  ## Computes the secant of ``x``.
+  ## Computes the secant of ``x`` (1 / cos(x)).
 proc csc*[T: float32|float64](x: T): T = 1.0 / sin(x)
-  ## Computes the cosecant of ``x``.
+  ## Computes the cosecant of ``x`` (1 / sin(x)).
 
 proc coth*[T: float32|float64](x: T): T = 1.0 / tanh(x)
-  ## Computes the hyperbolic cotangent of ``x``.
+  ## Computes the hyperbolic cotangent of ``x`` (1 / tanh(x)).
 proc sech*[T: float32|float64](x: T): T = 1.0 / cosh(x)
-  ## Computes the hyperbolic secant of ``x``.
+  ## Computes the hyperbolic secant of ``x`` (1 / cosh(x)).
 proc csch*[T: float32|float64](x: T): T = 1.0 / sinh(x)
-  ## Computes the hyperbolic cosecant of ``x``.
+  ## Computes the hyperbolic cosecant of ``x`` (1 / sinh(x)).
 
 proc arccot*[T: float32|float64](x: T): T = arctan(1.0 / x)
   ## Computes the inverse cotangent of ``x``.
@@ -352,11 +562,17 @@ when not defined(JS): # C
     ##  echo hypot(4.0, 3.0) ## 5.0
   proc pow*(x, y: float32): float32 {.importc: "powf", header: "<math.h>".}
   proc pow*(x, y: float64): float64 {.importc: "pow", header: "<math.h>".}
-    ## computes x to power raised of y.
+    ## Computes x to power raised of y.
+    ##
+    ## To compute power between integers (e.g. 2^6), use `^ proc<#^,T,Natural>`_.
     ##
-    ## To compute power between integers, use ``^`` e.g. 2 ^ 6
+    ## See also:
+    ## * `^ proc<#^,T,Natural>`_
+    ## * `sqrt proc <#sqrt,float64>`_
+    ## * `cbrt proc <#cbrt,float64>`_
     ##
     ## .. code-block:: nim
+    ##  echo pow(100, 1.5)  ## 1000.0
     ##  echo pow(16.0, 0.5) ## 4.0
 
   # TODO: add C89 version on windows
@@ -370,6 +586,15 @@ when not defined(JS): # C
     proc gamma*(x: float32): float32 {.importc: "tgammaf", header: "<math.h>".}
     proc gamma*(x: float64): float64 {.importc: "tgamma", header: "<math.h>".}
       ## Computes the the `gamma function <https://en.wikipedia.org/wiki/Gamma_function>`_ for ``x``.
+      ##
+      ## See also:
+      ## * `lgamma proc <#lgamma,float64>`_ for a natural log of gamma function
+      ##
+      ## .. code-block:: Nim
+      ##  echo gamma(1.0)  # 1.0
+      ##  echo gamma(4.0)  # 6.0
+      ##  echo gamma(11.0) # 3628800.0
+      ##  echo gamma(-1.0) # nan
     proc tgamma*(x: float32): float32
       {.deprecated: "use gamma instead", importc: "tgammaf", header: "<math.h>".}
     proc tgamma*(x: float64): float64
@@ -379,19 +604,43 @@ when not defined(JS): # C
     proc lgamma*(x: float32): float32 {.importc: "lgammaf", header: "<math.h>".}
     proc lgamma*(x: float64): float64 {.importc: "lgamma", header: "<math.h>".}
       ## Computes the natural log of the gamma function for ``x``.
+      ##
+      ## See also:
+      ## * `gamma proc <#gamma,float64>`_ for gamma function
+      ##
+      ## .. code-block:: Nim
+      ##  echo lgamma(1.0)  # 1.0
+      ##  echo lgamma(4.0)  # 1.791759469228055
+      ##  echo lgamma(11.0) # 15.10441257307552
+      ##  echo lgamma(-1.0) # inf
 
   proc floor*(x: float32): float32 {.importc: "floorf", header: "<math.h>".}
   proc floor*(x: float64): float64 {.importc: "floor", header: "<math.h>".}
     ## Computes the floor function (i.e., the largest integer not greater than ``x``).
     ##
+    ## See also:
+    ## * `ceil proc <#ceil,float64>`_
+    ## * `round proc <#round,float64>`_
+    ## * `trunc proc <#trunc,float64>`_
+    ##
     ## .. code-block:: nim
+    ##  echo floor(2.1)  ## 2.0
+    ##  echo floor(2.9)  ## 2.0
     ##  echo floor(-3.5) ## -4.0
 
   proc ceil*(x: float32): float32 {.importc: "ceilf", header: "<math.h>".}
   proc ceil*(x: float64): float64 {.importc: "ceil", header: "<math.h>".}
-    ## Computes the ceiling function (i.e., the smallest integer not less than ``x``).
+    ## Computes the ceiling function (i.e., the smallest integer not smaller
+    ## than ``x``).
+    ##
+    ## See also:
+    ## * `floor proc <#floor,float64>`_
+    ## * `round proc <#round,float64>`_
+    ## * `trunc proc <#trunc,float64>`_
     ##
     ## .. code-block:: nim
+    ##  echo ceil(2.1)  ## 3.0
+    ##  echo ceil(2.9)  ## 3.0
     ##  echo ceil(-2.1) ## -2.0
 
   when windowsCC89:
@@ -452,26 +701,50 @@ when not defined(JS): # C
   else:
     proc round*(x: float32): float32 {.importc: "roundf", header: "<math.h>".}
     proc round*(x: float64): float64 {.importc: "round", header: "<math.h>".}
-      ## Rounds a float to zero decimal places.  Used internally by the round
-      ## function when the specified number of places is 0.
+      ## Rounds a float to zero decimal places.
+      ##
+      ## Used internally by the `round proc <#round,T,int>`_
+      ## when the specified number of places is 0.
+      ##
+      ## See also:
+      ## * `round proc <#round,T,int>`_ for rounding to the specific
+      ##   number of decimal places
+      ## * `floor proc <#floor,float64>`_
+      ## * `ceil proc <#ceil,float64>`_
+      ## * `trunc proc <#trunc,float64>`_
+      ##
+      ## .. code-block:: nim
+      ##   echo round(3.4) ## 3.0
+      ##   echo round(3.5) ## 4.0
+      ##   echo round(4.5) ## 5.0
 
     proc trunc*(x: float32): float32 {.importc: "truncf", header: "<math.h>".}
     proc trunc*(x: float64): float64 {.importc: "trunc", header: "<math.h>".}
       ## Truncates ``x`` to the decimal point.
       ##
+      ## See also:
+      ## * `floor proc <#floor,float64>`_
+      ## * `ceil proc <#ceil,float64>`_
+      ## * `round proc <#round,float64>`_
+      ##
       ## .. code-block:: nim
       ##  echo trunc(PI) # 3.0
       ##  echo trunc(-1.85) # -1.0
 
   proc fmod*(x, y: float32): float32 {.deprecated: "use mod instead", importc: "fmodf", header: "<math.h>".}
   proc fmod*(x, y: float64): float64 {.deprecated: "use mod instead", importc: "fmod", header: "<math.h>".}
+    ## **Deprecated since version 0.19.0**: Use the `mod proc
+    ## <#mod,float64,float64>`_ instead.
+    ##
     ## Computes the remainder of ``x`` divided by ``y``.
-    ## **Deprecated since version 0.19.0**: Use the ``mod`` operator instead.
 
   proc `mod`*(x, y: float32): float32 {.importc: "fmodf", header: "<math.h>".}
   proc `mod`*(x, y: float64): float64 {.importc: "fmod", header: "<math.h>".}
     ## Computes the modulo operation for float values (the remainder of ``x`` divided by ``y``).
     ##
+    ## See also:
+    ## * `floorMod proc <#floorMod,T,T>`_ for Python-like (% operator) behavior
+    ##
     ## .. code-block:: nim
     ##  ( 6.5 mod  2.5) ==  1.5
     ##  (-6.5 mod  2.5) == -1.5
@@ -502,16 +775,22 @@ else: # JS
     ##  (-6.5 mod -2.5) == -1.5
 
 proc round*[T: float32|float64](x: T, places: int): T {.deprecated: "use format instead".} =
+  ## **Deprecated:** use `strformat module <strformat.html>`_
+  ##
   ## Decimal rounding on a binary floating point number.
   ##
   ## This function is NOT reliable. Floating point numbers cannot hold
-  ## non integer decimals precisely.  If ``places`` is 0 (or omitted),
+  ## non integer decimals precisely. If ``places`` is 0 (or omitted),
   ## round to the nearest integral value following normal mathematical
-  ## rounding rules (e.g.  ``round(54.5) -> 55.0``).  If ``places`` is
+  ## rounding rules (e.g.  ``round(54.5) -> 55.0``). If ``places`` is
   ## greater than 0, round to the given number of decimal places,
-  ## e.g. ``round(54.346, 2) -> 54.350000000000001421...``.  If ``places`` is negative, round
-  ## to the left of the decimal place, e.g.  ``round(537.345, -1) ->
+  ## e.g. ``round(54.346, 2) -> 54.350000000000001421…``. If ``places`` is negative, round
+  ## to the left of the decimal place, e.g. ``round(537.345, -1) ->
   ## 540.0``
+  ##
+  ## .. code-block:: Nim
+  ##  echo round(PI, 2) ## 3.14
+  ##  echo round(PI, 4) ## 3.1416
   if places == 0:
     result = round(x)
   else:
@@ -520,9 +799,14 @@ proc round*[T: float32|float64](x: T, places: int): T {.deprecated: "use format
 
 proc floorDiv*[T: SomeInteger](x, y: T): T =
   ## Floor division is conceptually defined as ``floor(x / y)``.
-  ## This is different from the ``div`` operator, which is defined
-  ## as ``trunc(x / y)``. That is, ``div`` rounds towards ``0`` and ``floorDiv``
-  ## rounds down.
+  ##
+  ## This is different from the `system.div <system.html#div,int,int>`_
+  ## operator, which is defined as ``trunc(x / y)``.
+  ## That is, ``div`` rounds towards ``0`` and ``floorDiv`` rounds down.
+  ##
+  ## See also:
+  ## * `system.div proc <system.html#div,int,int>`_ for integer division
+  ## * `floorMod proc <#floorMod,T,T>`_ for Python-like (% operator) behavior
   ##
   ## .. code-block:: nim
   ##  echo floorDiv( 13,  3) #  4
@@ -535,8 +819,13 @@ proc floorDiv*[T: SomeInteger](x, y: T): T =
 
 proc floorMod*[T: SomeNumber](x, y: T): T =
   ## Floor modulus is conceptually defined as ``x - (floorDiv(x, y) * y)``.
+  ##
   ## This proc behaves the same as the ``%`` operator in Python.
   ##
+  ## See also:
+  ## * `mod proc <#mod,float64,float64>`_
+  ## * `floorDiv proc <#floorDiv,T,T>`_
+  ##
   ## .. code-block:: nim
   ##  echo floorMod( 13,  3) #  1
   ##  echo floorMod(-13,  3) #  2
@@ -552,6 +841,7 @@ when not defined(JS):
     importc: "frexp", header: "<math.h>".}
   proc frexp*[T, U](x: T, exponent: var U): T =
     ## Split a number into mantissa and exponent.
+    ##
     ## ``frexp`` calculates the mantissa m (a float greater than or equal to 0.5
     ## and less than 1) and the integer value n such that ``x`` (the original
     ## float value) equals ``m * 2**n``. frexp stores n in `exponent` and returns
@@ -584,7 +874,19 @@ when not defined(JS):
   else:
     proc log2*(x: float32): float32 {.importc: "log2f", header: "<math.h>".}
     proc log2*(x: float64): float64 {.importc: "log2", header: "<math.h>".}
-      ## Computes the binary logarithm (base 2) of ``x``
+      ## Computes the binary logarithm (base 2) of ``x``.
+      ##
+      ## See also:
+      ## * `log proc <#log,T,T>`_
+      ## * `log10 proc <#log10,float64>`_
+      ## * `ln proc <#ln,float64>`_
+      ## * `exp proc <#exp,float64>`_
+      ##
+      ## .. code-block:: Nim
+      ##  echo log2(8.0)  # 3.0
+      ##  echo log2(1.0)  # 0.0
+      ##  echo log2(0.0)  # -inf
+      ##  echo log2(-2.0) # nan
 
 else:
   proc frexp*[T: float32|float64](x: T, exponent: var int): T =
@@ -613,7 +915,8 @@ proc splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] =
   ## function in C.
   ##
   ## .. code-block:: nim
-  ##  echo splitDecimal(5.25) # (intpart: 5.0, floatpart: 0.25)
+  ##  echo splitDecimal(5.25)  # (intpart: 5.0, floatpart: 0.25)
+  ##  echo splitDecimal(-2.73) # (intpart: -2.0, floatpart: -0.73)
   var
     absolute: T
   absolute = abs(x)
@@ -626,26 +929,36 @@ proc splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] =
 {.pop.}
 
 proc degToRad*[T: float32|float64](d: T): T {.inline.} =
-  ## Convert from degrees to radians
+  ## Convert from degrees to radians.
+  ##
+  ## See also:
+  ## * `radToDeg proc <#radToDeg,T>`_
   ##
   ## .. code-block:: nim
   ##  echo degToRad(180.0) # 3.141592653589793
   result = T(d) * RadPerDeg
 
 proc radToDeg*[T: float32|float64](d: T): T {.inline.} =
-  ## Convert from radians to degrees
-
+  ## Convert from radians to degrees.
+  ##
+  ## See also:
+  ## * `degToRad proc <#degToRad,T>`_
+  ##
   ## .. code-block:: nim
   ##  echo degToRad(2 * PI) # 360.0
   result = T(d) / RadPerDeg
 
 proc sgn*[T: SomeNumber](x: T): int {.inline.} =
-  ## Sign function. Returns -1 for negative numbers and ``NegInf``, 1 for
-  ## positive numbers and ``Inf``, and 0 for positive zero, negative zero and
-  ## ``NaN``.
+  ## Sign function.
+  ##
+  ## Returns:
+  ## * `-1` for negative numbers and ``NegInf``,
+  ## * `1` for positive numbers and ``Inf``,
+  ## * `0` for positive zero, negative zero and ``NaN``
   ##
   ## .. code-block:: nim
-  ##  echo sgn(-5) # 1
+  ##  echo sgn(5)    # 1
+  ##  echo sgn(0)    # 0
   ##  echo sgn(-4.1) # -1
   ord(T(0) < x) - ord(x < T(0))
 
@@ -653,11 +966,20 @@ proc sgn*[T: SomeNumber](x: T): int {.inline.} =
 {.pop.}
 
 proc `^`*[T](x: T, y: Natural): T =
-  ## Computes ``x`` to the power ``y``. ``x`` must be non-negative, use
-  ## `pow <#pow,float,float>`_ for negative exponents.
+  ## Computes ``x`` to the power ``y``.
+  ##
+  ## Exponent ``y`` must be non-negative, use
+  ## `pow proc <#pow,float64,float64>`_ for negative exponents.
+  ##
+  ## See also:
+  ## * `pow proc <#pow,float64,float64>`_ for negative exponent or
+  ##   floats
+  ## * `sqrt proc <#sqrt,float64>`_
+  ## * `cbrt proc <#cbrt,float64>`_
   ##
   ## .. code-block:: nim
-  ##  echo 2 ^ 3 # 8
+  ##  echo 2^3  # 8
+  ##  echo -2^3 # -8
   when compiles(y >= T(0)):
     assert y >= T(0)
   else:
@@ -675,9 +997,16 @@ proc `^`*[T](x: T, y: Natural): T =
 
 proc gcd*[T](x, y: T): T =
   ## Computes the greatest common (positive) divisor of ``x`` and ``y``.
+  ##
   ## Note that for floats, the result cannot always be interpreted as
   ## "greatest decimal `z` such that ``z*N == x and z*M == y``
   ## where N and M are positive integers."
+  ##
+  ## See also:
+  ## * `gcd proc <#gcd,SomeInteger,SomeInteger>`_ for integer version
+  ## * `lcm proc <#lcm,T,T>`_
+  runnableExamples:
+    doAssert gcd(13.5, 9.0) == 4.5
   var (x, y) = (x, y)
   while y != 0:
     x = x mod y
@@ -685,11 +1014,15 @@ proc gcd*[T](x, y: T): T =
   abs x
 
 proc gcd*(x, y: SomeInteger): SomeInteger =
-  ## Computes the greatest common (positive) divisor of ``x`` and ``y``.
-  ## Using binary GCD (aka Stein's) algorithm.
+  ## Computes the greatest common (positive) divisor of ``x`` and ``y``,
+  ## using binary GCD (aka Stein's) algorithm.
   ##
-  ## .. code-block:: nim
-  ##  echo gcd(24, 30) # 6
+  ## See also:
+  ## * `gcd proc <#gcd,T,T>`_ for floats version
+  ## * `lcm proc <#lcm,T,T>`_
+  runnableExamples:
+    doAssert gcd(12, 8) == 4
+    doAssert gcd(17, 63) == 1
   when x is SomeSignedInt:
     var x = abs(x)
   else:
@@ -716,10 +1049,15 @@ proc gcd*(x, y: SomeInteger): SomeInteger =
 proc lcm*[T](x, y: T): T =
   ## Computes the least common multiple of ``x`` and ``y``.
   ##
-  ## .. code-block:: nim
-  ##  echo lcm(24, 30) # 120
+  ## See also:
+  ## * `gcd proc <#gcd,T,T>`_
+  runnableExamples:
+    doAssert lcm(24, 30) == 120
+    doAssert lcm(13, 39) == 39
   x div gcd(x, y) * y
 
+
+
 when isMainModule and not defined(JS) and not windowsCC89:
   # Check for no side effect annotation
   proc mySqrt(num: float): float {.noSideEffect.} =
diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim
index 810223d72..d1a006eee 100644
--- a/lib/pure/memfiles.nim
+++ b/lib/pure/memfiles.nim
@@ -42,9 +42,10 @@ type
       wasOpened*: bool     ## **Caution**: Windows specific public field.
     else:
       handle*: cint        ## **Caution**: Posix specific public field.
+      flags: cint          ## **Caution**: Platform specific private field.
 
 proc mapMem*(m: var MemFile, mode: FileMode = fmRead,
-             mappedSize = -1, offset = 0): pointer =
+             mappedSize = -1, offset = 0, mapFlags = cint(-1)): pointer =
   ## returns a pointer to a mapped portion of MemFile `m`
   ##
   ## ``mappedSize`` of ``-1`` maps to the whole file, and
@@ -65,11 +66,17 @@ proc mapMem*(m: var MemFile, mode: FileMode = fmRead,
       raiseOSError(osLastError())
   else:
     assert mappedSize > 0
+
+    m.flags = if mapFlags == cint(-1): MAP_SHARED else: mapFlags
+    #Ensure exactly one of MAP_PRIVATE cr MAP_SHARED is set
+    if int(m.flags and MAP_PRIVATE) == 0:
+      m.flags = m.flags or MAP_SHARED
+
     result = mmap(
       nil,
       mappedSize,
       if readonly: PROT_READ else: PROT_READ or PROT_WRITE,
-      if readonly: (MAP_PRIVATE or MAP_POPULATE) else: (MAP_SHARED or MAP_POPULATE),
+      m.flags,
       m.handle, offset)
     if result == cast[pointer](MAP_FAILED):
       raiseOSError(osLastError())
@@ -90,7 +97,7 @@ proc unmapMem*(f: var MemFile, p: pointer, size: int) =
 
 proc open*(filename: string, mode: FileMode = fmRead,
            mappedSize = -1, offset = 0, newFileSize = -1,
-           allowRemap = false): MemFile =
+           allowRemap = false, mapFlags = cint(-1)): MemFile =
   ## opens a memory mapped file. If this fails, ``OSError`` is raised.
   ##
   ## ``newFileSize`` can only be set if the file does not exist and is opened
@@ -105,6 +112,10 @@ proc open*(filename: string, mode: FileMode = fmRead,
   ## ``allowRemap`` only needs to be true if you want to call ``mapMem`` on
   ## the resulting MemFile; else file handles are not kept open.
   ##
+  ## ``mapFlags`` allows callers to override default choices for memory mapping
+  ## flags with a bitwise mask of a variety of likely platform-specific flags
+  ## which may be ignored or even cause `open` to fail if misspecified.
+  ##
   ## Example:
   ##
   ## .. code-block:: nim
@@ -245,11 +256,16 @@ proc open*(filename: string, mode: FileMode = fmRead,
       else:
         fail(osLastError(), "error getting file size")
 
+    result.flags = if mapFlags == cint(-1): MAP_SHARED else: mapFlags
+    #Ensure exactly one of MAP_PRIVATE cr MAP_SHARED is set
+    if int(result.flags and MAP_PRIVATE) == 0:
+      result.flags = result.flags or MAP_SHARED
+
     result.mem = mmap(
       nil,
       result.size,
       if readonly: PROT_READ else: PROT_READ or PROT_WRITE,
-      if readonly: (MAP_PRIVATE or MAP_POPULATE) else: (MAP_SHARED or MAP_POPULATE),
+      result.flags,
       result.handle,
       offset)
 
@@ -305,7 +321,7 @@ when defined(posix) or defined(nimdoc):
         if munmap(f.mem, f.size) != 0:
           raiseOSError(osLastError())
         let newAddr = mmap(nil, newFileSize, PROT_READ or PROT_WRITE,
-                            MAP_SHARED or MAP_POPULATE, f.handle, 0)
+                           f.flags, f.handle, 0)
         if newAddr == cast[pointer](MAP_FAILED):
           raiseOSError(osLastError())
       f.mem = newAddr
diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim
index f98f9a444..6d4df1c5d 100644
--- a/lib/pure/nativesockets.nim
+++ b/lib/pure/nativesockets.nim
@@ -71,6 +71,7 @@ type
     IPPROTO_IPV6,       ## Internet Protocol Version 6. Unsupported on Windows.
     IPPROTO_RAW,        ## Raw IP Packets Protocol. Unsupported on Windows.
     IPPROTO_ICMP        ## Control message protocol. Unsupported on Windows.
+    IPPROTO_ICMPV6      ## Control message protocol for IPv6. Unsupported on Windows.
 
   Servent* = object ## information about a service
     name*: string
@@ -154,6 +155,7 @@ when not useWinVersion:
     of IPPROTO_IPV6:   result = posix.IPPROTO_IPV6
     of IPPROTO_RAW:    result = posix.IPPROTO_RAW
     of IPPROTO_ICMP:   result = posix.IPPROTO_ICMP
+    of IPPROTO_ICMPV6:   result = posix.IPPROTO_ICMPV6
 
 else:
   proc toInt(domain: Domain): cint =
@@ -179,7 +181,7 @@ proc toSockType*(protocol: Protocol): SockType =
     SOCK_STREAM
   of IPPROTO_UDP:
     SOCK_DGRAM
-  of IPPROTO_IP, IPPROTO_IPV6, IPPROTO_RAW, IPPROTO_ICMP:
+  of IPPROTO_IP, IPPROTO_IPV6, IPPROTO_RAW, IPPROTO_ICMP, IPPROTO_ICMPV6:
     SOCK_RAW
 
 proc createNativeSocket*(domain: Domain = AF_INET,
@@ -255,17 +257,14 @@ proc getAddrInfo*(address: string, port: Port, domain: Domain = AF_INET,
   when not defined(freebsd) and not defined(openbsd) and not defined(netbsd) and not defined(android) and not defined(haiku):
     if domain == AF_INET6:
       hints.ai_flags = AI_V4MAPPED
-  var gaiResult = getaddrinfo(address, $port, addr(hints), result)
+  let socket_port = if sockType == SOCK_RAW: "" else: $port
+  var gaiResult = getaddrinfo(address, socket_port, addr(hints), result)
   if gaiResult != 0'i32:
     when useWinVersion:
       raiseOSError(osLastError())
     else:
       raiseOSError(osLastError(), $gai_strerror(gaiResult))
 
-proc dealloc*(ai: ptr AddrInfo) {.deprecated.} =
-  ## Deprecated since 0.16.2. Use ``freeAddrInfo`` instead.
-  freeaddrinfo(ai)
-
 proc ntohl*(x: uint32): uint32 =
   ## Converts 32-bit unsigned integers from network to host byte order.
   ## On machines where the host byte order is the same as network byte order,
@@ -276,15 +275,6 @@ proc ntohl*(x: uint32): uint32 =
                  (x shl 8'u32 and 0xff0000'u32) or
                  (x shl 24'u32)
 
-template ntohl*(x: int32): untyped {.deprecated.} =
-  ## Converts 32-bit integers from network to host byte order.
-  ## On machines where the host byte order is the same as network byte order,
-  ## this is a no-op; otherwise, it performs a 4-byte swap operation.
-  ## **Warning**: This template is deprecated since 0.14.0, IPv4
-  ## addresses are now treated as unsigned integers. Please use the unsigned
-  ## version of this template.
-  cast[int32](nativesockets.ntohl(cast[uint32](x)))
-
 proc ntohs*(x: uint16): uint16 =
   ## Converts 16-bit unsigned integers from network to host byte order. On
   ## machines where the host byte order is the same as network byte order,
@@ -292,39 +282,12 @@ proc ntohs*(x: uint16): uint16 =
   when cpuEndian == bigEndian: result = x
   else: result = (x shr 8'u16) or (x shl 8'u16)
 
-template ntohs*(x: int16): untyped {.deprecated.} =
-  ## Converts 16-bit integers from network to host byte order. On
-  ## machines where the host byte order is the same as network byte order,
-  ## this is a no-op; otherwise, it performs a 2-byte swap operation.
-  ## **Warning**: This template is deprecated since 0.14.0, where port
-  ## numbers became unsigned integers. Please use the unsigned version of
-  ## this template.
-  cast[int16](nativesockets.ntohs(cast[uint16](x)))
-
-template htonl*(x: int32): untyped {.deprecated.} =
-  ## Converts 32-bit integers from host to network byte order. On machines
-  ## where the host byte order is the same as network byte order, this is
-  ## a no-op; otherwise, it performs a 4-byte swap operation.
-  ## **Warning**: This template is deprecated since 0.14.0, IPv4
-  ## addresses are now treated as unsigned integers. Please use the unsigned
-  ## version of this template.
-  nativesockets.ntohl(x)
-
 template htonl*(x: uint32): untyped =
   ## Converts 32-bit unsigned integers from host to network byte order. On
   ## machines where the host byte order is the same as network byte order,
   ## this is a no-op; otherwise, it performs a 4-byte swap operation.
   nativesockets.ntohl(x)
 
-template htons*(x: int16): untyped {.deprecated.} =
-  ## Converts 16-bit integers from host to network byte order.
-  ## On machines where the host byte order is the same as network byte
-  ## order, this is a no-op; otherwise, it performs a 2-byte swap operation.
-  ## **Warning**: This template is deprecated since 0.14.0, where port
-  ## numbers became unsigned integers. Please use the unsigned version of
-  ## this template.
-  nativesockets.ntohs(x)
-
 template htons*(x: uint16): untyped =
   ## Converts 16-bit unsigned integers from host to network byte order.
   ## On machines where the host byte order is the same as network byte
@@ -646,29 +609,6 @@ proc pruneSocketSet(s: var seq[SocketHandle], fd: var TFdSet) =
       inc(i)
   setLen(s, L)
 
-proc select*(readfds: var seq[SocketHandle], timeout = 500): int {.deprecated: "use selectRead instead".} =
-  ## When a socket in ``readfds`` is ready to be read from then a non-zero
-  ## value will be returned specifying the count of the sockets which can be
-  ## read from. The sockets which can be read from will also be removed
-  ## from ``readfds``.
-  ##
-  ## ``timeout`` is specified in milliseconds and ``-1`` can be specified for
-  ## an unlimited time.
-  ## **Warning:** This is deprecated since version 0.16.2.
-  ## Use the ``selectRead`` procedure instead.
-  var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
-
-  var rd: TFdSet
-  var m = 0
-  createFdSet((rd), readfds, m)
-
-  if timeout != -1:
-    result = int(select(cint(m+1), addr(rd), nil, nil, addr(tv)))
-  else:
-    result = int(select(cint(m+1), addr(rd), nil, nil, nil))
-
-  pruneSocketSet(readfds, (rd))
-
 proc selectRead*(readfds: var seq[SocketHandle], timeout = 500): int =
   ## When a socket in ``readfds`` is ready to be read from then a non-zero
   ## value will be returned specifying the count of the sockets which can be
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index 840a81f17..a5bdf3ce6 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -233,7 +233,7 @@ proc parseIPv4Address(addressStr: string): IpAddress =
   var
     byteCount = 0
     currentByte:uint16 = 0
-    seperatorValid = false
+    separatorValid = false
 
   result.family = IpAddressFamily.IPv4
 
@@ -244,20 +244,20 @@ proc parseIPv4Address(addressStr: string): IpAddress =
       if currentByte > 255'u16:
         raise newException(ValueError,
           "Invalid IP Address. Value is out of range")
-      seperatorValid = true
+      separatorValid = true
     elif addressStr[i] == '.': # IPv4 address separator
-      if not seperatorValid or byteCount >= 3:
+      if not separatorValid or byteCount >= 3:
         raise newException(ValueError,
           "Invalid IP Address. The address consists of too many groups")
       result.address_v4[byteCount] = cast[uint8](currentByte)
       currentByte = 0
       byteCount.inc
-      seperatorValid = false
+      separatorValid = false
     else:
       raise newException(ValueError,
         "Invalid IP Address. Address contains an invalid character")
 
-  if byteCount != 3 or not seperatorValid:
+  if byteCount != 3 or not separatorValid:
     raise newException(ValueError, "Invalid IP Address")
   result.address_v4[byteCount] = cast[uint8](currentByte)
 
@@ -272,7 +272,7 @@ proc parseIPv6Address(addressStr: string): IpAddress =
     groupCount = 0
     currentGroupStart = 0
     currentShort:uint32 = 0
-    seperatorValid = true
+    separatorValid = true
     dualColonGroup = -1
     lastWasColon = false
     v4StartPos = -1
@@ -280,15 +280,15 @@ proc parseIPv6Address(addressStr: string): IpAddress =
 
   for i,c in addressStr:
     if c == ':':
-      if not seperatorValid:
+      if not separatorValid:
         raise newException(ValueError,
-          "Invalid IP Address. Address contains an invalid seperator")
+          "Invalid IP Address. Address contains an invalid separator")
       if lastWasColon:
         if dualColonGroup != -1:
           raise newException(ValueError,
-            "Invalid IP Address. Address contains more than one \"::\" seperator")
+            "Invalid IP Address. Address contains more than one \"::\" separator")
         dualColonGroup = groupCount
-        seperatorValid = false
+        separatorValid = false
       elif i != 0 and i != high(addressStr):
         if groupCount >= 8:
           raise newException(ValueError,
@@ -297,7 +297,7 @@ proc parseIPv6Address(addressStr: string): IpAddress =
         result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF)
         currentShort = 0
         groupCount.inc()
-        if dualColonGroup != -1: seperatorValid = false
+        if dualColonGroup != -1: separatorValid = false
       elif i == 0: # only valid if address starts with ::
         if addressStr[1] != ':':
           raise newException(ValueError,
@@ -309,11 +309,11 @@ proc parseIPv6Address(addressStr: string): IpAddress =
       lastWasColon = true
       currentGroupStart = i + 1
     elif c == '.': # Switch to parse IPv4 mode
-      if i < 3 or not seperatorValid or groupCount >= 7:
+      if i < 3 or not separatorValid or groupCount >= 7:
         raise newException(ValueError, "Invalid IP Address")
       v4StartPos = currentGroupStart
       currentShort = 0
-      seperatorValid = false
+      separatorValid = false
       break
     elif c in strutils.HexDigits:
       if c in strutils.Digits: # Normal digit
@@ -326,14 +326,14 @@ proc parseIPv6Address(addressStr: string): IpAddress =
         raise newException(ValueError,
           "Invalid IP Address. Value is out of range")
       lastWasColon = false
-      seperatorValid = true
+      separatorValid = true
     else:
       raise newException(ValueError,
         "Invalid IP Address. Address contains an invalid character")
 
 
   if v4StartPos == -1: # Don't parse v4. Copy the remaining v6 stuff
-    if seperatorValid: # Copy remaining data
+    if separatorValid: # Copy remaining data
       if groupCount >= 8:
         raise newException(ValueError,
           "Invalid IP Address. The address consists of too many groups")
@@ -347,19 +347,19 @@ proc parseIPv6Address(addressStr: string): IpAddress =
         if currentShort > 255'u32:
           raise newException(ValueError,
             "Invalid IP Address. Value is out of range")
-        seperatorValid = true
+        separatorValid = true
       elif c == '.': # IPv4 address separator
-        if not seperatorValid or byteCount >= 3:
+        if not separatorValid or byteCount >= 3:
           raise newException(ValueError, "Invalid IP Address")
         result.address_v6[groupCount*2 + byteCount] = cast[uint8](currentShort)
         currentShort = 0
         byteCount.inc()
-        seperatorValid = false
+        separatorValid = false
       else: # Invalid character
         raise newException(ValueError,
           "Invalid IP Address. Address contains an invalid character")
 
-    if byteCount != 3 or not seperatorValid:
+    if byteCount != 3 or not separatorValid:
       raise newException(ValueError, "Invalid IP Address")
     result.address_v6[groupCount*2 + byteCount] = cast[uint8](currentShort)
     groupCount += 2
@@ -967,39 +967,6 @@ when defined(posix) or defined(nimdoc):
         raiseOSError(osLastError())
 
 when defined(ssl):
-  proc handshake*(socket: Socket): bool
-    {.tags: [ReadIOEffect, WriteIOEffect], deprecated.} =
-    ## This proc needs to be called on a socket after it connects. This is
-    ## only applicable when using ``connectAsync``.
-    ## This proc performs the SSL handshake.
-    ##
-    ## Returns ``False`` whenever the socket is not yet ready for a handshake,
-    ## ``True`` whenever handshake completed successfully.
-    ##
-    ## A SslError error is raised on any other errors.
-    ##
-    ## **Note:** This procedure is deprecated since version 0.14.0.
-    result = true
-    if socket.isSSL:
-      var ret = SSLConnect(socket.sslHandle)
-      if ret <= 0:
-        var errret = SSLGetError(socket.sslHandle, ret)
-        case errret
-        of SSL_ERROR_ZERO_RETURN:
-          raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.")
-        of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT,
-          SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE:
-          return false
-        of SSL_ERROR_WANT_X509_LOOKUP:
-          raiseSSLError("Function for x509 lookup has been called.")
-        of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
-          raiseSSLError()
-        else:
-          raiseSSLError("Unknown Error")
-      socket.sslNoHandshake = false
-    else:
-      raiseSSLError("Socket is not an SSL socket.")
-
   proc gotHandshake*(socket: Socket): bool =
     ## Determines whether a handshake has occurred between a client (``socket``)
     ## and the server that ``socket`` is connected to.
@@ -1026,7 +993,7 @@ proc select(readfd: Socket, timeout = 500): int =
     return 1
 
   var fds = @[readfd.fd]
-  result = select(fds, timeout)
+  result = selectRead(fds, timeout)
 
 proc isClosed(socket: Socket): bool =
   socket.fd == osInvalidSocket
@@ -1694,7 +1661,5 @@ proc connect*(socket: Socket, address: string, port = Port(0),
     when defineSsl and not defined(nimdoc):
       if socket.isSSL:
         socket.fd.setBlocking(true)
-        {.warning[Deprecated]: off.}
-        doAssert socket.handshake()
-        {.warning[Deprecated]: on.}
+        doAssert socket.gotHandshake()
   socket.fd.setBlocking(true)
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 6521d827c..181bc5728 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -19,7 +19,9 @@ include "system/inclrtl"
 import
   strutils, pathnorm
 
-when defined(nimscript):
+const weirdTarget = defined(nimscript) or defined(js)
+
+when weirdTarget:
   discard
 elif defined(windows):
   import winlean, times
@@ -31,7 +33,7 @@ elif defined(posix):
 else:
   {.error: "OS module not ported to your operating system!".}
 
-when defined(nimscript) and defined(nimErrorProcCanHaveBody):
+when weirdTarget and defined(nimErrorProcCanHaveBody):
   {.pragma: noNimScript, error: "this proc is not available on the NimScript target".}
 else:
   {.pragma: noNimScript.}
@@ -334,7 +336,7 @@ proc searchExtPos*(path: string): int =
 
 proc splitFile*(path: string): tuple[dir, name, ext: string] {.
   noSideEffect, rtl, extern: "nos$1".} =
-  ## Splits a filename into (dir, filename, extension).
+  ## Splits a filename into (dir, name, extension).
   ## `dir` does not end in `DirSep`.
   ## `extension` includes the leading dot.
   ##
@@ -349,19 +351,30 @@ proc splitFile*(path: string): tuple[dir, name, ext: string] {.
   ## If `path` has no extension, `ext` is the empty string.
   ## If `path` has no directory component, `dir` is the empty string.
   ## If `path` has no filename component, `name` and `ext` are empty strings.
-  if path.len == 0 or path[path.len-1] in {DirSep, AltSep}:
-    result = (path, "", "")
+  if path.len == 0:
+      result = ("", "", "")
+  elif path[^1] in {DirSep, AltSep}:
+    if path.len == 1:
+      # issue #8255
+      result = ($path[0], "", "")
+    else:
+      result = (path[0 ..< ^1], "", "")
   else:
     var sepPos = -1
     var dotPos = path.len
     for i in countdown(len(path)-1, 0):
       if path[i] == ExtSep:
         if dotPos == path.len and i > 0 and
-            path[i-1] notin {DirSep, AltSep}: dotPos = i
+            path[i-1] notin {DirSep, AltSep, ExtSep}: dotPos = i
       elif path[i] in {DirSep, AltSep}:
         sepPos = i
         break
-    result.dir = substr(path, 0, sepPos-1)
+    if sepPos-1 >= 0:
+      result.dir = substr(path, 0, sepPos-1)
+    elif path[0] in {DirSep, AltSep}:
+      # issue #8255
+      result.dir = $path[0]
+
     result.name = substr(path, sepPos+1, dotPos-1)
     result.ext = substr(path, dotPos)
 
@@ -651,7 +664,7 @@ when defined(windows) or defined(posix) or defined(nintendoswitch):
       if i > 0: result.add " "
       result.add quoteShell(args[i])
 
-when not defined(nimscript):
+when not weirdTarget:
   proc c_rename(oldname, newname: cstring): cint {.
     importc: "rename", header: "<stdio.h>".}
   proc c_system(cmd: cstring): cint {.
@@ -662,7 +675,7 @@ when not defined(nimscript):
     importc: "free", header: "<stdlib.h>".}
 
 
-when defined(windows) and not defined(nimscript):
+when defined(windows) and not weirdTarget:
   when useWinUnicode:
     template wrapUnary(varname, winApiProc, arg: untyped) =
       var varname = winApiProc(newWideCString(arg))
@@ -744,7 +757,7 @@ proc dirExists*(dir: string): bool {.inline, noNimScript.} =
   ## Synonym for existsDir
   existsDir(dir)
 
-when not defined(windows) and not defined(nimscript):
+when not defined(windows) and not weirdTarget:
   proc checkSymlink(path: string): bool =
     var rawInfo: Stat
     if lstat(path, rawInfo) < 0'i32: result = false
@@ -805,7 +818,7 @@ proc findExe*(exe: string, followSymlinks: bool = true;
         return x
   result = ""
 
-when defined(nimscript):
+when weirdTarget:
   const times = "fake const"
   template Time(x: untyped): untyped = string
 
@@ -920,7 +933,7 @@ proc setCurrentDir*(newDir: string) {.inline, tags: [], noNimScript.} =
   else:
     if chdir(newDir) != 0'i32: raiseOSError(osLastError())
 
-when not defined(nimscript):
+when not weirdTarget:
   proc absolutePath*(path: string, root = getCurrentDir()): string {.noNimScript.} =
     ## Returns the absolute path of `path`, rooted at `root` (which must be absolute)
     ## if `path` is absolute, return it, ignoring `root`
@@ -932,48 +945,6 @@ when not defined(nimscript):
         raise newException(ValueError, "The specified root is not absolute: " & root)
       joinPath(root, path)
 
-proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
-  tags: [ReadDirEffect], noNimScript.} =
-  ## Returns the full (`absolute`:idx:) path of an existing file `filename`,
-  ## raises OSError in case of an error. Follows symlinks.
-  when defined(windows):
-    var bufsize = MAX_PATH.int32
-    when useWinUnicode:
-      var unused: WideCString = nil
-      var res = newWideCString("", bufsize)
-      while true:
-        var L = getFullPathNameW(newWideCString(filename), bufsize, res, unused)
-        if L == 0'i32:
-          raiseOSError(osLastError())
-        elif L > bufsize:
-          res = newWideCString("", L)
-          bufsize = L
-        else:
-          result = res$L
-          break
-    else:
-      var unused: cstring = nil
-      result = newString(bufsize)
-      while true:
-        var L = getFullPathNameA(filename, bufsize, result, unused)
-        if L == 0'i32:
-          raiseOSError(osLastError())
-        elif L > bufsize:
-          result = newString(L)
-          bufsize = L
-        else:
-          setLen(result, L)
-          break
-  else:
-    # according to Posix we don't need to allocate space for result pathname.
-    # But we need to free return value with free(3).
-    var r = realpath(filename, nil)
-    if r.isNil:
-      raiseOSError(osLastError())
-    else:
-      result = $r
-      c_free(cast[pointer](r))
-
 proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [], noNimScript.} =
   ## Normalize a path.
   ##
@@ -984,38 +955,39 @@ proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [], noNimScr
   ##
   ## Warning: URL-encoded and Unicode attempts at directory traversal are not detected.
   ## Triple dot is not handled.
-  let isAbs = isAbsolute(path)
-  var stack: seq[string] = @[]
-  for p in split(path, {DirSep}):
-    case p
-    of "", ".":
-      continue
-    of "..":
-      if stack.len == 0:
-        if isAbs:
-          discard  # collapse all double dots on absoluta paths
-        else:
+  path = pathnorm.normalizePath(path)
+  when false:
+    let isAbs = isAbsolute(path)
+    var stack: seq[string] = @[]
+    for p in split(path, {DirSep}):
+      case p
+      of "", ".":
+        continue
+      of "..":
+        if stack.len == 0:
+          if isAbs:
+            discard  # collapse all double dots on absoluta paths
+          else:
+            stack.add(p)
+        elif stack[^1] == "..":
           stack.add(p)
-      elif stack[^1] == "..":
-        stack.add(p)
+        else:
+          discard stack.pop()
       else:
-        discard stack.pop()
-    else:
-      stack.add(p)
+        stack.add(p)
 
-  if isAbs:
-    path = DirSep & join(stack, $DirSep)
-  elif stack.len > 0:
-    path = join(stack, $DirSep)
-  else:
-    path = "."
+    if isAbs:
+      path = DirSep & join(stack, $DirSep)
+    elif stack.len > 0:
+      path = join(stack, $DirSep)
+    else:
+      path = "."
 
 proc normalizedPath*(path: string): string {.rtl, extern: "nos$1", tags: [], noNimScript.} =
   ## Returns a normalized path for the current OS. See `<#normalizePath>`_
-  result = path
-  normalizePath(result)
+  result = pathnorm.normalizePath(path)
 
-when defined(Windows) and not defined(nimscript):
+when defined(Windows) and not weirdTarget:
   proc openHandle(path: string, followSymlink=true, writeAccess=false): Handle =
     var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL
     if not followSymlink:
@@ -1238,7 +1210,7 @@ when not declared(ENOENT) and not defined(Windows):
   else:
     var ENOENT {.importc, header: "<errno.h>".}: cint
 
-when defined(Windows) and not defined(nimscript):
+when defined(Windows) and not weirdTarget:
   when useWinUnicode:
     template deleteFile(file: untyped): untyped  = deleteFileW(file)
     template setFileAttributes(file, attrs: untyped): untyped =
@@ -1315,6 +1287,17 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
         discard tryRemoveFile(dest)
         raise
 
+proc exitStatusLikeShell*(status: cint): cint =
+  ## converts exit code from `c_system` into a shell exit code
+  when defined(posix) and not weirdTarget:
+    if WIFSIGNALED(status):
+      # like the shell!
+      128 + WTERMSIG(status)
+    else:
+      WEXITSTATUS(status)
+  else:
+    status
+
 proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
   tags: [ExecIOEffect], noNimScript.} =
   ## Executes a `shell command`:idx:.
@@ -1323,23 +1306,19 @@ proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
   ## line arguments given to program. The proc returns the error code
   ## of the shell when it has finished. The proc does not return until
   ## the process has finished. To execute a program without having a
-  ## shell involved, use the `execProcess` proc of the `osproc`
-  ## module.
-  when defined(posix):
-    result = c_system(command) shr 8
-  else:
-    result = c_system(command)
+  ## shell involved, use `osproc.execProcess`.
+  result = exitStatusLikeShell(c_system(command))
 
 # Templates for filtering directories and files
-when defined(windows) and not defined(nimscript):
+when defined(windows) and not weirdTarget:
   template isDir(f: WIN32_FIND_DATA): bool =
     (f.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) != 0'i32
   template isFile(f: WIN32_FIND_DATA): bool =
     not isDir(f)
 else:
-  template isDir(f: string): bool =
+  template isDir(f: string): bool {.dirty.} =
     dirExists(f)
-  template isFile(f: string): bool =
+  template isFile(f: string): bool {.dirty.} =
     fileExists(f)
 
 template defaultWalkFilter(item): bool =
@@ -1411,6 +1390,54 @@ iterator walkDirs*(pattern: string): string {.tags: [ReadDirEffect], noNimScript
   ## notation is supported.
   walkCommon(pattern, isDir)
 
+proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
+  tags: [ReadDirEffect], noNimScript.} =
+  ## Returns the full (`absolute`:idx:) path of an existing file `filename`,
+  ## raises OSError in case of an error. Follows symlinks.
+  when defined(windows):
+    var bufsize = MAX_PATH.int32
+    when useWinUnicode:
+      var unused: WideCString = nil
+      var res = newWideCString("", bufsize)
+      while true:
+        var L = getFullPathNameW(newWideCString(filename), bufsize, res, unused)
+        if L == 0'i32:
+          raiseOSError(osLastError())
+        elif L > bufsize:
+          res = newWideCString("", L)
+          bufsize = L
+        else:
+          result = res$L
+          break
+    else:
+      var unused: cstring = nil
+      result = newString(bufsize)
+      while true:
+        var L = getFullPathNameA(filename, bufsize, result, unused)
+        if L == 0'i32:
+          raiseOSError(osLastError())
+        elif L > bufsize:
+          result = newString(L)
+          bufsize = L
+        else:
+          setLen(result, L)
+          break
+    # getFullPathName doesn't do case corrections, so we have to use this convoluted
+    # way of retrieving the true filename
+    for x in walkFiles(result.string):
+      result = x
+    if not existsFile(result) and not existsDir(result):
+      raise newException(OSError, "file '" & result & "' does not exist")
+  else:
+    # according to Posix we don't need to allocate space for result pathname.
+    # But we need to free return value with free(3).
+    var r = realpath(filename, nil)
+    if r.isNil:
+      raiseOSError(osLastError())
+    else:
+      result = $r
+      c_free(cast[pointer](r))
+
 type
   PathComponent* = enum   ## Enumeration specifying a path component.
     pcFile,               ## path refers to a file
@@ -1418,7 +1445,13 @@ type
     pcDir,                ## path refers to a directory
     pcLinkToDir           ## path refers to a symbolic link to a directory
 
-when defined(posix) and not defined(nimscript):
+proc getCurrentCompilerExe*(): string {.compileTime.} = discard
+  ## `getAppFilename` at CT; can be used to retrive the currently executing
+  ## Nim compiler from a Nim or nimscript program, or the nimble binary
+  ## inside a nimble program (likewise with other binaries built from
+  ## compiler API).
+
+when defined(posix) and not weirdTarget:
   proc getSymlinkFileKind(path: string): PathComponent =
     # Helper function.
     var s: Stat
@@ -1459,7 +1492,7 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path:
     for k, v in items(staticWalkDir(dir, relative)):
       yield (k, v)
   else:
-    when defined(nimscript):
+    when weirdTarget:
       for k, v in items(staticWalkDir(dir, relative)):
         yield (k, v)
     elif defined(windows):
@@ -1494,8 +1527,9 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path:
             var y = $x.d_name.cstring
           if y != "." and y != "..":
             var s: Stat
+            let path = dir / y
             if not relative:
-              y = dir / y
+              y = path
             var k = pcFile
 
             when defined(linux) or defined(macosx) or
@@ -1503,16 +1537,16 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path:
               if x.d_type != DT_UNKNOWN:
                 if x.d_type == DT_DIR: k = pcDir
                 if x.d_type == DT_LNK:
-                  if dirExists(y): k = pcLinkToDir
+                  if dirExists(path): k = pcLinkToDir
                   else: k = pcLinkToFile
                 yield (k, y)
                 continue
 
-            if lstat(y, s) < 0'i32: break
+            if lstat(path, s) < 0'i32: break
             if S_ISDIR(s.st_mode):
               k = pcDir
             elif S_ISLNK(s.st_mode):
-              k = getSymlinkFileKind(y)
+              k = getSymlinkFileKind(path)
             yield (k, y)
 
 iterator walkDirRec*(dir: string,
@@ -1953,7 +1987,7 @@ when defined(nimdoc):
     ##   else:
     ##     # Do something else!
 
-elif defined(nintendoswitch) or defined(nimscript):
+elif defined(nintendoswitch) or weirdTarget:
   proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} =
     raise newException(OSError, "paramStr is not implemented on Nintendo Switch")
 
@@ -2030,7 +2064,7 @@ when declared(paramCount) or defined(nimdoc):
     for i in 1..paramCount():
       result.add(paramStr(i))
 
-when not defined(nimscript) and (defined(freebsd) or defined(dragonfly)):
+when not weirdTarget and (defined(freebsd) or defined(dragonfly)):
   proc sysctl(name: ptr cint, namelen: cuint, oldp: pointer, oldplen: ptr csize,
               newp: pointer, newplen: csize): cint
        {.importc: "sysctl",header: """#include <sys/types.h>
@@ -2063,7 +2097,7 @@ when not defined(nimscript) and (defined(freebsd) or defined(dragonfly)):
         result.setLen(pathLength)
         break
 
-when not defined(nimscript) and (defined(linux) or defined(solaris) or defined(bsd) or defined(aix)):
+when not weirdTarget and (defined(linux) or defined(solaris) or defined(bsd) or defined(aix)):
   proc getApplAux(procPath: string): string =
     result = newString(256)
     var len = readlink(procPath, result, 256)
@@ -2072,7 +2106,7 @@ when not defined(nimscript) and (defined(linux) or defined(solaris) or defined(b
       len = readlink(procPath, result, len)
     setLen(result, len)
 
-when not (defined(windows) or defined(macosx) or defined(nimscript)):
+when not (defined(windows) or defined(macosx) or weirdTarget):
   proc getApplHeuristic(): string =
     when declared(paramStr):
       result = string(paramStr(0))
@@ -2117,7 +2151,8 @@ when defined(haiku):
       result = ""
 
 proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noNimScript.} =
-  ## Returns the filename of the application's executable.
+  ## Returns the filename of the application's executable. See also
+  ## `getCurrentCompilerExe`.
   ##
   ## This procedure will resolve symlinks.
 
@@ -2207,7 +2242,7 @@ proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1",
       close(f)
     else: raiseOSError(osLastError())
 
-when defined(Windows) or defined(nimscript):
+when defined(Windows) or weirdTarget:
   type
     DeviceId* = int32
     FileId* = int64
@@ -2287,6 +2322,12 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped =
       assert(path != "") # symlinks can't occur for file handles
       formalInfo.kind = getSymlinkFileKind(path)
 
+when defined(js):
+  when not declared(FileHandle):
+    type FileHandle = distinct int32
+  when not declared(File):
+    type File = object
+
 proc getFileInfo*(handle: FileHandle): FileInfo {.noNimScript.} =
   ## Retrieves file information for the file object represented by the given
   ## handle.
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index b2239b9c5..e7ab395ae 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -60,9 +60,6 @@ type
   Process* = ref ProcessObj ## represents an operating system process
 
 
-const poUseShell* {.deprecated.} = poUsePath
-  ## Deprecated alias for poUsePath.
-
 proc execProcess*(command: string,
                   workingDir: string = "",
                   args: openArray[string] = [],
@@ -229,7 +226,7 @@ proc execProcesses*(cmds: openArray[string],
                     {.rtl, extern: "nosp$1",
                     tags: [ExecIOEffect, TimeEffect, ReadEnvEffect, RootEffect]} =
   ## executes the commands `cmds` in parallel. Creates `n` processes
-  ## that execute in parallel. The highest return value of all processes
+  ## that execute in parallel. The highest (absolute) return value of all processes
   ## is returned. Runs `beforeRunEvent` before running each command.
 
   assert n > 0
@@ -335,19 +332,6 @@ proc execProcesses*(cmds: openArray[string],
       if afterRunEvent != nil: afterRunEvent(i, p)
       close(p)
 
-proc select*(readfds: var seq[Process], timeout = 500): int
-  {.benign, deprecated.}
-  ## `select` with a sensible Nim interface. `timeout` is in milliseconds.
-  ## Specify -1 for no timeout. Returns the number of processes that are
-  ## ready to read from. The processes that are ready to be read from are
-  ## removed from `readfds`.
-  ##
-  ## **Warning**: This function may give unexpected or completely wrong
-  ## results on Windows.
-  ##
-  ## **Deprecated since version 0.17.0**: This procedure isn't cross-platform
-  ## and so should not be used in newly written code.
-
 when not defined(useNimRtl):
   proc execProcess(command: string,
                    workingDir: string = "",
@@ -724,13 +708,6 @@ elif not defined(useNimRtl):
   proc isExitStatus(status: cint): bool =
     WIFEXITED(status) or WIFSIGNALED(status)
 
-  proc exitStatus(status: cint): cint =
-    if WIFSIGNALED(status):
-      # like the shell!
-      128 + WTERMSIG(status)
-    else:
-      WEXITSTATUS(status)
-
   proc envToCStringArray(t: StringTableRef): cstringArray =
     result = cast[cstringArray](alloc0((t.len + 1) * sizeof(cstring)))
     var i = 0
@@ -1054,7 +1031,7 @@ elif not defined(useNimRtl):
 
     proc waitForExit(p: Process, timeout: int = -1): int =
       if p.exitFlag:
-        return exitStatus(p.exitStatus)
+        return exitStatusLikeShell(p.exitStatus)
 
       if timeout == -1:
         var status: cint = 1
@@ -1109,7 +1086,7 @@ elif not defined(useNimRtl):
         finally:
           discard posix.close(kqFD)
 
-      result = exitStatus(p.exitStatus)
+      result = exitStatusLikeShell(p.exitStatus)
   else:
     import times
 
@@ -1142,7 +1119,7 @@ elif not defined(useNimRtl):
         s.tv_nsec = b.tv_nsec
 
       if p.exitFlag:
-        return exitStatus(p.exitStatus)
+        return exitStatusLikeShell(p.exitStatus)
 
       if timeout == -1:
         var status: cint = 1
@@ -1220,20 +1197,20 @@ elif not defined(useNimRtl):
             if sigprocmask(SIG_UNBLOCK, nmask, omask) == -1:
               raiseOSError(osLastError())
 
-      result = exitStatus(p.exitStatus)
+      result = exitStatusLikeShell(p.exitStatus)
 
   proc peekExitCode(p: Process): int =
     var status = cint(0)
     result = -1
     if p.exitFlag:
-      return exitStatus(p.exitStatus)
+      return exitStatusLikeShell(p.exitStatus)
 
     var ret = waitpid(p.id, status, WNOHANG)
     if ret > 0:
       if isExitStatus(status):
         p.exitFlag = true
         p.exitStatus = status
-        result = exitStatus(status)
+        result = exitStatusLikeShell(status)
 
   proc createStream(stream: var Stream, handle: var FileHandle,
                     fileMode: FileMode) =
@@ -1265,7 +1242,7 @@ elif not defined(useNimRtl):
   proc execCmd(command: string): int =
     when defined(linux):
       let tmp = csystem(command)
-      result = if tmp == -1: tmp else: exitStatus(tmp)
+      result = if tmp == -1: tmp else: exitStatusLikeShell(tmp)
     else:
       result = csystem(command)
 
diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim
index b991dd57f..106d59017 100644
--- a/lib/pure/parsecfg.nim
+++ b/lib/pure/parsecfg.nim
@@ -111,7 +111,7 @@
 ##     dict.writeConfig("config.ini")
 
 import
-  hashes, strutils, lexbase, streams, tables
+  strutils, lexbase, streams, tables
 
 include "system/inclrtl"
 
diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim
index fe3d3186f..06f32f032 100644
--- a/lib/pure/parseopt.nim
+++ b/lib/pure/parseopt.nim
@@ -73,24 +73,6 @@ proc parseWord(s: string, i: int, w: var string,
       inc(result)
 
 when declared(os.paramCount):
-  proc quote(s: string): string =
-    if find(s, {' ', '\t'}) >= 0 and s.len > 0 and s[0] != '"':
-      if s[0] == '-':
-        result = newStringOfCap(s.len)
-        var i = parseWord(s, 0, result, {' ', '\t', ':', '='})
-        if i < s.len and s[i] in {':','='}:
-          result.add s[i]
-          inc i
-        result.add '"'
-        while i < s.len:
-          result.add s[i]
-          inc i
-        result.add '"'
-      else:
-        result = '"' & s & '"'
-    else:
-      result = s
-
   # we cannot provide this for NimRtl creation on Posix, because we can't
   # access the command line arguments then!
 
@@ -228,11 +210,12 @@ proc next*(p: var OptParser) {.rtl, extern: "npo$1".} =
 when declared(os.paramCount):
   proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} =
     ## retrieves the rest of the command line that has not been parsed yet.
-    var res = ""
-    for i in p.idx..<p.cmds.len:
-      if i > p.idx: res.add ' '
-      res.add quote(p.cmds[i])
-    result = res.TaintedString
+    result = p.cmds[p.idx .. ^1].quoteShellCommand.TaintedString
+
+  proc remainingArgs*(p: OptParser): seq[TaintedString] {.rtl, extern: "npo$1".} =
+    ## retrieves the rest of the command line that has not been parsed yet.
+    result = @[]
+    for i in p.idx..<p.cmds.len: result.add TaintedString(p.cmds[i])
 
 iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key, val: TaintedString] =
   ## This is an convenience iterator for iterating over the given OptParser object.
diff --git a/lib/pure/parseopt2.nim b/lib/pure/parseopt2.nim
index 51a70b6d1..9fd6cd2c7 100644
--- a/lib/pure/parseopt2.nim
+++ b/lib/pure/parseopt2.nim
@@ -55,15 +55,6 @@ proc initOptParser*(cmdline: seq[string]): OptParser {.rtl.} =
 
   result.cmd = @cmdline
 
-proc initOptParser*(cmdline: string): OptParser {.rtl, deprecated.} =
-  ## Initalizes option parses with cmdline. Splits cmdline in on spaces
-  ## and calls initOptParser(openarray[string])
-  ## Do not use.
-  if cmdline == "": # backward compatibility
-    return initOptParser(@[])
-  else:
-    return initOptParser(cmdline.split)
-
 when not defined(createNimRtl):
   proc initOptParser*(): OptParser =
     ## Initializes option parser from current command line arguments.
@@ -112,10 +103,10 @@ proc next(p: var OptParser) =
     p.key = token
     p.val = ""
 
-proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo2$1", deprecated.} =
-  ## Returns part of command line string that has not been parsed yet.
-  ## Do not use - does not correctly handle whitespace.
-  return p.cmd[p.pos..p.cmd.len-1].join(" ")
+proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo2$1".} =
+  ## Returns the part of command line string that has not been parsed yet,
+  ## properly quoted.
+  return p.cmd[p.pos..p.cmd.len-1].quoteShellCommand
 
 type
   GetoptResult* = tuple[kind: CmdLineKind, key, val: TaintedString]
diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim
index 20f02e815..f0961829b 100644
--- a/lib/pure/parsesql.nim
+++ b/lib/pure/parsesql.nim
@@ -11,7 +11,7 @@
 ## parser. It parses PostgreSQL syntax and the SQL ANSI standard.
 
 import
-  hashes, strutils, lexbase
+  strutils, lexbase
 
 # ------------------- scanner -------------------------------------------------
 
diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim
index fb4bc19af..ba09347a2 100644
--- a/lib/pure/parseutils.nim
+++ b/lib/pure/parseutils.nim
@@ -7,9 +7,46 @@
 #    distribution, for details about the copyright.
 #
 
-## This module contains helpers for parsing tokens, numbers, identifiers, etc.
+## This module contains helpers for parsing tokens, numbers, integers, floats,
+## identifiers, etc.
 ##
 ## To unpack raw bytes look at the `streams <streams.html>`_ module.
+##
+##
+## .. code-block::
+##    import parseutils
+##
+##    let logs = @["2019-01-10: OK_", "2019-01-11: FAIL_", "2019-01: aaaa"]
+##
+##    for log in logs:
+##      var res: string
+##      if parseUntil(log, res, ':') == 10: # YYYY-MM-DD == 10
+##        echo res & " - " & captureBetween(log, ' ', '_')
+##        # => 2019-01-10 - OK
+##
+##
+## .. code-block::
+##    import parseutils
+##    from strutils import Digits, parseInt
+##
+##    let userInput1 = "2019 school start"
+##    let userInput2 = "3 years back"
+##
+##    let startYear = input1[0..skipWhile(input1, Digits)-1] # 2019
+##    let yearsBack = input2[0..skipWhile(input2, Digits)-1] # 3
+##
+##    echo "Examination is in " & $(parseInt(startYear) + parseInt(yearsBack))
+##
+##
+## **See also:**
+## * `strutils module<strutils.html>`_ for combined and identical parsing proc's
+## * `json module<json.html>`_ for a JSON parser
+## * `parsecfg module<parsecfg.html>`_ for a configuration file parser
+## * `parsecsv module<parsecsv.html>`_ for a simple CSV (comma separated value) parser
+## * `parseopt module<parseopt.html>`_ for a command line parser
+## * `parsexml module<parsexml.html>`_ for a XML / HTML parser
+## * `other parsers<lib.html#pure-libraries-parsers>`_ for other parsers
+
 
 {.deadCodeElim: on.}  # dce option deprecated
 
@@ -35,21 +72,20 @@ proc parseHex*(s: string, number: var int, start = 0; maxLen = 0): int {.
   ## proc is sensitive to the already existing value of ``number`` and will
   ## likely not do what you want unless you make sure ``number`` is zero. You
   ## can use this feature to *chain* calls, though the result int will quickly
-  ## overflow. Example:
-  ##
-  ## .. code-block:: nim
-  ##   var value = 0
-  ##   discard parseHex("0x38", value)
-  ##   assert value == 56
-  ##   discard parseHex("0x34", value)
-  ##   assert value == 56 * 256 + 52
-  ##   value = -1
-  ##   discard parseHex("0x38", value)
-  ##   assert value == -200
+  ## overflow.
   ##
   ## If ``maxLen == 0`` the length of the hexadecimal number has no upper bound.
   ## Else no more than ``start + maxLen`` characters are parsed, up to the
   ## length of the string.
+  runnableExamples:
+    var value = 0
+    discard parseHex("0x38", value)
+    assert value == 56
+    discard parseHex("0x34", value)
+    assert value == 56 * 256 + 52
+    value = -1
+    discard parseHex("0x38", value)
+    assert value == -200
   var i = start
   var foundDigit = false
   # get last index based on minimum `start + maxLen` or `s.len`
@@ -80,6 +116,11 @@ proc parseOct*(s: string, number: var int, start = 0, maxLen = 0): int  {.
   ## If ``maxLen == 0`` the length of the octal number has no upper bound.
   ## Else no more than ``start + maxLen`` characters are parsed, up to the
   ## length of the string.
+  runnableExamples:
+    var res: int
+    doAssert parseOct("12", res) == 2
+    doAssert res == 10
+    doAssert parseOct("9", res) == 0
   var i = start
   var foundDigit = false
   # get last index based on minimum `start + maxLen` or `s.len`
@@ -95,7 +136,7 @@ proc parseOct*(s: string, number: var int, start = 0, maxLen = 0): int  {.
     inc(i)
   if foundDigit: result = i-start
 
-proc parseBin*(s: string, number: var int, start = 0, maxLen = 0): int  {.
+proc parseBin*(s: string, number: var int, start = 0, maxLen = 0): int {.
   rtl, extern: "npuParseBin", noSideEffect.} =
   ## Parses an binary number and stores its value in ``number``. Returns
   ## the number of the parsed characters or 0 in case of an error.
@@ -103,6 +144,10 @@ proc parseBin*(s: string, number: var int, start = 0, maxLen = 0): int  {.
   ## If ``maxLen == 0`` the length of the binary number has no upper bound.
   ## Else no more than ``start + maxLen`` characters are parsed, up to the
   ## length of the string.
+  runnableExamples:
+    var res: int
+    doAssert parseBin("010011100110100101101101", res) == 24
+    doAssert parseBin("3", res) == 0
   var i = start
   var foundDigit = false
   # get last index based on minimum `start + maxLen` or `s.len`
@@ -119,8 +164,16 @@ proc parseBin*(s: string, number: var int, start = 0, maxLen = 0): int  {.
   if foundDigit: result = i-start
 
 proc parseIdent*(s: string, ident: var string, start = 0): int =
-  ## parses an identifier and stores it in ``ident``. Returns
+  ## Parses an identifier and stores it in ``ident``. Returns
   ## the number of the parsed characters or 0 in case of an error.
+  runnableExamples:
+    var res: string
+    doAssert parseIdent("Hello World", res, 0) == 5
+    doAssert res == "Hello"
+    doAssert parseIdent("Hello World", res, 1) == 4
+    doAssert res == "ello"
+    doAssert parseIdent("Hello World", res, 6) == 5
+    doAssert res == "World"
   var i = start
   if i < s.len and s[i] in IdentStartChars:
     inc(i)
@@ -129,8 +182,13 @@ proc parseIdent*(s: string, ident: var string, start = 0): int =
     result = i-start
 
 proc parseIdent*(s: string, start = 0): string =
-  ## parses an identifier and returns it or an empty string in
+  ## Parses an identifier and returns it or an empty string in
   ## case of an error.
+  runnableExamples:
+    doAssert parseIdent("Hello World", 0) == "Hello"
+    doAssert parseIdent("Hello World", 1) == "ello"
+    doAssert parseIdent("Hello World", 5) == ""
+    doAssert parseIdent("Hello World", 6) == "World"
   result = ""
   var i = start
   if i < s.len and s[i] in IdentStartChars:
@@ -138,33 +196,35 @@ proc parseIdent*(s: string, start = 0): string =
     while i < s.len and s[i] in IdentChars: inc(i)
     result = substr(s, start, i-1)
 
-proc parseToken*(s: string, token: var string, validChars: set[char],
-                 start = 0): int {.inline, deprecated.} =
-  ## parses a token and stores it in ``token``. Returns
-  ## the number of the parsed characters or 0 in case of an error. A token
-  ## consists of the characters in `validChars`.
-  ##
-  ## **Deprecated since version 0.8.12**: Use ``parseWhile`` instead.
-  var i = start
-  while i < s.len and s[i] in validChars: inc(i)
-  result = i-start
-  token = substr(s, start, i-1)
-
 proc skipWhitespace*(s: string, start = 0): int {.inline.} =
-  ## skips the whitespace starting at ``s[start]``. Returns the number of
+  ## Skips the whitespace starting at ``s[start]``. Returns the number of
   ## skipped characters.
+  runnableExamples:
+    doAssert skipWhitespace("Hello World", 0) == 0
+    doAssert skipWhitespace(" Hello World", 0) == 1
+    doAssert skipWhitespace("Hello World", 5) == 1
+    doAssert skipWhitespace("Hello  World", 5) == 2
   while start+result < s.len and s[start+result] in Whitespace: inc(result)
 
 proc skip*(s, token: string, start = 0): int {.inline.} =
-  ## skips the `token` starting at ``s[start]``. Returns the length of `token`
+  ## Skips the `token` starting at ``s[start]``. Returns the length of `token`
   ## or 0 if there was no `token` at ``s[start]``.
+  runnableExamples:
+    doAssert skip("2019-01-22", "2019", 0) == 4
+    doAssert skip("2019-01-22", "19", 0) == 0
+    doAssert skip("2019-01-22", "19", 2) == 2
+    doAssert skip("CAPlow", "CAP", 0) == 3
+    doAssert skip("CAPlow", "cap", 0) == 0
   while start+result < s.len and result < token.len and
       s[result+start] == token[result]:
     inc(result)
   if result != token.len: result = 0
 
 proc skipIgnoreCase*(s, token: string, start = 0): int =
-  ## same as `skip` but case is ignored for token matching.
+  ## Same as `skip` but case is ignored for token matching.
+  runnableExamples:
+    doAssert skipIgnoreCase("CAPlow", "CAP", 0) == 3
+    doAssert skipIgnoreCase("CAPlow", "cap", 0) == 3
   while start+result < s.len and result < token.len and
       toLower(s[result+start]) == toLower(token[result]): inc(result)
   if result != token.len: result = 0
@@ -173,24 +233,45 @@ proc skipUntil*(s: string, until: set[char], start = 0): int {.inline.} =
   ## Skips all characters until one char from the set `until` is found
   ## or the end is reached.
   ## Returns number of characters skipped.
+  runnableExamples:
+    doAssert skipUntil("Hello World", {'W', 'e'}, 0) == 1
+    doAssert skipUntil("Hello World", {'W'}, 0) == 6
+    doAssert skipUntil("Hello World", {'W', 'd'}, 0) == 6
   while start+result < s.len and s[result+start] notin until: inc(result)
 
 proc skipUntil*(s: string, until: char, start = 0): int {.inline.} =
   ## Skips all characters until the char `until` is found
   ## or the end is reached.
   ## Returns number of characters skipped.
+  runnableExamples:
+    doAssert skipUntil("Hello World", 'o', 0) == 4
+    doAssert skipUntil("Hello World", 'o', 4) == 0
+    doAssert skipUntil("Hello World", 'W', 0) == 6
+    doAssert skipUntil("Hello World", 'w', 0) == 11
   while start+result < s.len and s[result+start] != until: inc(result)
 
 proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} =
   ## Skips all characters while one char from the set `token` is found.
   ## Returns number of characters skipped.
+  runnableExamples:
+    doAssert skipWhile("Hello World", {'H', 'e'}) == 2
+    doAssert skipWhile("Hello World", {'e'}) == 0
+    doAssert skipWhile("Hello World", {'W', 'o', 'r'}, 6) == 3
   while start+result < s.len and s[result+start] in toSkip: inc(result)
 
 proc parseUntil*(s: string, token: var string, until: set[char],
                  start = 0): int {.inline.} =
-  ## parses a token and stores it in ``token``. Returns
+  ## Parses a token and stores it in ``token``. Returns
   ## the number of the parsed characters or 0 in case of an error. A token
   ## consists of the characters notin `until`.
+  runnableExamples:
+    var myToken: string
+    doAssert parseUntil("Hello World", myToken, {'W', 'o', 'r'}) == 4
+    doAssert myToken == "Hell"
+    doAssert parseUntil("Hello World", myToken, {'W', 'r'}) == 6
+    doAssert myToken == "Hello "
+    doAssert parseUntil("Hello World", myToken, {'W', 'r'}, 3) == 3
+    doAssert myToken == "lo "
   var i = start
   while i < s.len and s[i] notin until: inc(i)
   result = i-start
@@ -198,9 +279,17 @@ proc parseUntil*(s: string, token: var string, until: set[char],
 
 proc parseUntil*(s: string, token: var string, until: char,
                  start = 0): int {.inline.} =
-  ## parses a token and stores it in ``token``. Returns
+  ## Parses a token and stores it in ``token``. Returns
   ## the number of the parsed characters or 0 in case of an error. A token
   ## consists of any character that is not the `until` character.
+  runnableExamples:
+    var myToken: string
+    doAssert parseUntil("Hello World", myToken, 'W') == 6
+    doAssert myToken == "Hello "
+    doAssert parseUntil("Hello World", myToken, 'o') == 4
+    doAssert myToken == "Hell"
+    doAssert parseUntil("Hello World", myToken, 'o', 2) == 2
+    doAssert myToken == "ll"
   var i = start
   while i < s.len and s[i] != until: inc(i)
   result = i-start
@@ -208,9 +297,15 @@ proc parseUntil*(s: string, token: var string, until: char,
 
 proc parseUntil*(s: string, token: var string, until: string,
                  start = 0): int {.inline.} =
-  ## parses a token and stores it in ``token``. Returns
+  ## Parses a token and stores it in ``token``. Returns
   ## the number of the parsed characters or 0 in case of an error. A token
   ## consists of any character that comes before the `until`  token.
+  runnableExamples:
+    var myToken: string
+    doAssert parseUntil("Hello World", myToken, "Wor") == 6
+    doAssert myToken == "Hello "
+    doAssert parseUntil("Hello World", myToken, "Wor", 2) == 4
+    doAssert myToken == "llo "
   if until.len == 0:
     token.setLen(0)
     return 0
@@ -227,9 +322,15 @@ proc parseUntil*(s: string, token: var string, until: string,
 
 proc parseWhile*(s: string, token: var string, validChars: set[char],
                  start = 0): int {.inline.} =
-  ## parses a token and stores it in ``token``. Returns
+  ## Parses a token and stores it in ``token``. Returns
   ## the number of the parsed characters or 0 in case of an error. A token
   ## consists of the characters in `validChars`.
+  runnableExamples:
+    var myToken: string
+    doAssert parseWhile("Hello World", myToken, {'W', 'o', 'r'}, 0) == 0
+    doAssert myToken.len() == 0
+    doAssert parseWhile("Hello World", myToken, {'W', 'o', 'r'}, 6) == 3
+    doAssert myToken == "Wor"
   var i = start
   while i < s.len and s[i] in validChars: inc(i)
   result = i-start
@@ -238,12 +339,21 @@ proc parseWhile*(s: string, token: var string, validChars: set[char],
 proc captureBetween*(s: string, first: char, second = '\0', start = 0): string =
   ## Finds the first occurrence of ``first``, then returns everything from there
   ## up to ``second`` (if ``second`` is '\0', then ``first`` is used).
+  runnableExamples:
+    doAssert captureBetween("Hello World", 'e') == "llo World"
+    doAssert captureBetween("Hello World", 'e', 'r') == "llo Wo"
+    doAssert captureBetween("Hello World", 'l', start = 6) == "d"
   var i = skipUntil(s, first, start)+1+start
   result = ""
   discard s.parseUntil(result, if second == '\0': first else: second, i)
 
-{.push overflowChecks: on.}
-# this must be compiled with overflow checking turned on:
+proc integerOutOfRangeError() {.noinline.} =
+  raise newException(ValueError, "Parsed integer outside of valid range")
+
+# See #6752
+when defined(js):
+  {.push overflowChecks: off.}
+
 proc rawParseInt(s: string, b: var BiggestInt, start = 0): int =
   var
     sign: BiggestInt = -1
@@ -256,48 +366,67 @@ proc rawParseInt(s: string, b: var BiggestInt, start = 0): int =
   if i < s.len and s[i] in {'0'..'9'}:
     b = 0
     while i < s.len and s[i] in {'0'..'9'}:
-      b = b * 10 - (ord(s[i]) - ord('0'))
+      let c = ord(s[i]) - ord('0')
+      if b >= (low(BiggestInt) + c) div 10:
+        b = b * 10 - c
+      else:
+        integerOutOfRangeError()
       inc(i)
       while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
-    b = b * sign
-    result = i - start
-{.pop.} # overflowChecks
+    if sign == -1 and b == low(BiggestInt):
+      integerOutOfRangeError()
+    else:
+      b = b * sign
+      result = i - start
+
+when defined(js):
+  {.pop.} # overflowChecks: off
 
 proc parseBiggestInt*(s: string, number: var BiggestInt, start = 0): int {.
-  rtl, extern: "npuParseBiggestInt", noSideEffect.} =
-  ## parses an integer starting at `start` and stores the value into `number`.
+  rtl, extern: "npuParseBiggestInt", noSideEffect, raises: [ValueError].} =
+  ## Parses an integer starting at `start` and stores the value into `number`.
   ## Result is the number of processed chars or 0 if there is no integer.
-  ## `OverflowError` is raised if an overflow occurs.
+  ## `ValueError` is raised if the parsed integer is out of the valid range.
+  runnableExamples:
+    var res: BiggestInt
+    doAssert parseBiggestInt("9223372036854775807", res, 0) == 19
+    doAssert res == 9223372036854775807
   var res: BiggestInt
   # use 'res' for exception safety (don't write to 'number' in case of an
   # overflow exception):
   result = rawParseInt(s, res, start)
-  number = res
+  if result != 0:
+    number = res
 
 proc parseInt*(s: string, number: var int, start = 0): int {.
-  rtl, extern: "npuParseInt", noSideEffect.} =
-  ## parses an integer starting at `start` and stores the value into `number`.
+  rtl, extern: "npuParseInt", noSideEffect, raises: [ValueError].} =
+  ## Parses an integer starting at `start` and stores the value into `number`.
   ## Result is the number of processed chars or 0 if there is no integer.
-  ## `OverflowError` is raised if an overflow occurs.
+  ## `ValueError` is raised if the parsed integer is out of the valid range.
+  runnableExamples:
+    var res: int
+    doAssert parseInt("2019", res, 0) == 4
+    doAssert res == 2019
+    doAssert parseInt("2019", res, 2) == 2
+    doAssert res == 19
   var res: BiggestInt
   result = parseBiggestInt(s, res, start)
-  if (sizeof(int) <= 4) and
-      ((res < low(int)) or (res > high(int))):
-    raise newException(OverflowError, "overflow")
-  elif result != 0:
+  when sizeof(int) <= 4:
+    if res < low(int) or res > high(int):
+      integerOutOfRangeError()
+  if result != 0:
     number = int(res)
 
-proc parseSaturatedNatural*(s: string, b: var int, start = 0): int =
-  ## parses a natural number into ``b``. This cannot raise an overflow
+proc parseSaturatedNatural*(s: string, b: var int, start = 0): int {.
+  raises: [].}=
+  ## Parses a natural number into ``b``. This cannot raise an overflow
   ## error. ``high(int)`` is returned for an overflow.
   ## The number of processed character is returned.
   ## This is usually what you really want to use instead of `parseInt`:idx:.
-  ## Example:
-  ##
-  ## .. code-block:: nim
-  ##   var res = 0
-  ##   discard parseSaturatedNatural("848", res)
-  ##   doAssert res == 848
+  runnableExamples:
+    var res = 0
+    discard parseSaturatedNatural("848", res)
+    doAssert res == 848
   var i = start
   if i < s.len and s[i] == '+': inc(i)
   if i < s.len and s[i] in {'0'..'9'}:
@@ -312,12 +441,13 @@ proc parseSaturatedNatural*(s: string, b: var int, start = 0): int =
       while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
     result = i - start
 
-# overflowChecks doesn't work with BiggestUInt
 proc rawParseUInt(s: string, b: var BiggestUInt, start = 0): int =
   var
     res = 0.BiggestUInt
     prev = 0.BiggestUInt
     i = start
+  if i < s.len - 1 and s[i] == '-' and s[i + 1] in {'0'..'9'}:
+    integerOutOfRangeError()
   if i < s.len and s[i] == '+': inc(i) # Allow
   if i < s.len and s[i] in {'0'..'9'}:
     b = 0
@@ -325,56 +455,75 @@ proc rawParseUInt(s: string, b: var BiggestUInt, start = 0): int =
       prev = res
       res = res * 10 + (ord(s[i]) - ord('0')).BiggestUInt
       if prev > res:
-        return 0 # overflowChecks emulation
+        integerOutOfRangeError()
       inc(i)
       while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
     b = res
     result = i - start
 
 proc parseBiggestUInt*(s: string, number: var BiggestUInt, start = 0): int {.
-  rtl, extern: "npuParseBiggestUInt", noSideEffect.} =
-  ## parses an unsigned integer starting at `start` and stores the value
+  rtl, extern: "npuParseBiggestUInt", noSideEffect, raises: [ValueError].} =
+  ## Parses an unsigned integer starting at `start` and stores the value
   ## into `number`.
-  ## Result is the number of processed chars or 0 if there is no integer
-  ## or overflow detected.
+  ## `ValueError` is raised if the parsed integer is out of the valid range.
+  runnableExamples:
+    var res: BiggestUInt
+    doAssert parseBiggestUInt("12", res, 0) == 2
+    doAssert res == 12
+    doAssert parseBiggestUInt("1111111111111111111", res, 0) == 19
+    doAssert res == 1111111111111111111'u64
   var res: BiggestUInt
   # use 'res' for exception safety (don't write to 'number' in case of an
   # overflow exception):
   result = rawParseUInt(s, res, start)
-  number = res
+  if result != 0:
+    number = res
 
 proc parseUInt*(s: string, number: var uint, start = 0): int {.
-  rtl, extern: "npuParseUInt", noSideEffect.} =
-  ## parses an unsigned integer starting at `start` and stores the value
+  rtl, extern: "npuParseUInt", noSideEffect, raises: [ValueError].} =
+  ## Parses an unsigned integer starting at `start` and stores the value
   ## into `number`.
-  ## Result is the number of processed chars or 0 if there is no integer or
-  ## overflow detected.
+  ## `ValueError` is raised if the parsed integer is out of the valid range.
+  runnableExamples:
+    var res: uint
+    doAssert parseUInt("3450", res) == 4
+    doAssert res == 3450
+    doAssert parseUInt("3450", res, 2) == 2
+    doAssert res == 50
   var res: BiggestUInt
   result = parseBiggestUInt(s, res, start)
   when sizeof(BiggestUInt) > sizeof(uint) and sizeof(uint) <= 4:
     if res > 0xFFFF_FFFF'u64:
-      raise newException(OverflowError, "overflow")
+      integerOutOfRangeError()
   if result != 0:
     number = uint(res)
 
 proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {.
   magic: "ParseBiggestFloat", importc: "nimParseBiggestFloat", noSideEffect.}
-  ## parses a float starting at `start` and stores the value into `number`.
+  ## Parses a float starting at `start` and stores the value into `number`.
   ## Result is the number of processed chars or 0 if a parsing error
   ## occurred.
 
 proc parseFloat*(s: string, number: var float, start = 0): int {.
   rtl, extern: "npuParseFloat", noSideEffect.} =
-  ## parses a float starting at `start` and stores the value into `number`.
+  ## Parses a float starting at `start` and stores the value into `number`.
   ## Result is the number of processed chars or 0 if there occurred a parsing
   ## error.
+  runnableExamples:
+    var res: float
+    doAssert parseFloat("32", res, 0) == 2
+    doAssert res == 32.0
+    doAssert parseFloat("32.57", res, 0) == 5
+    doAssert res == 32.57
+    doAssert parseFloat("32.57", res, 3) == 2
+    doAssert res == 57.00
   var bf: BiggestFloat
   result = parseBiggestFloat(s, bf, start)
   if result != 0:
     number = bf
 
 type
-  InterpolatedKind* = enum   ## describes for `interpolatedFragments`
+  InterpolatedKind* = enum   ## Describes for `interpolatedFragments`
                              ## which part of the interpolated string is
                              ## yielded; for example in "str$$$var${expr}"
     ikStr,                   ## ``str`` part of the interpolated string
@@ -490,4 +639,8 @@ when isMainModule:
   doAssert(parseSaturatedNatural("1_000_000", value) == 9)
   doAssert value == 1_000_000
 
+  var i64Value: int64
+  discard parseBiggestInt("9223372036854775807", i64Value)
+  doAssert i64Value == 9223372036854775807
+
 {.pop.}
diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim
index 0967f7983..953c5cdde 100644
--- a/lib/pure/parsexml.nim
+++ b/lib/pure/parsexml.nim
@@ -147,7 +147,7 @@ an HTML document contains.
 ]##
 
 import
-  hashes, strutils, lexbase, streams, unicode
+  strutils, lexbase, streams, unicode
 
 # the parser treats ``<br />`` as ``<br></br>``
 
diff --git a/lib/pure/pathnorm.nim b/lib/pure/pathnorm.nim
index a33afefbd..ca869fd03 100644
--- a/lib/pure/pathnorm.nim
+++ b/lib/pure/pathnorm.nim
@@ -66,19 +66,27 @@ proc addNormalizePath*(x: string; result: var string; state: var int; dirSep = D
     if (state shr 1 == 0) and isSlash(x, b):
       result.add dirSep
       state = state or 1
-    elif result.len > (state and 1) and isDotDot(x, b):
-      var d = result.len
-      # f/..
-      while (d-1) > (state and 1) and result[d-1] notin {DirSep, AltSep}:
-        dec d
-      if d > 0: setLen(result, d-1)
+    elif isDotDot(x, b):
+      if (state shr 1) >= 1:
+        var d = result.len
+        # f/..
+        while (d-1) > (state and 1) and result[d-1] notin {DirSep, AltSep}:
+          dec d
+        if d > 0:
+          setLen(result, d-1)
+          dec state, 2
+      else:
+        if result.len > 0 and result[^1] notin {DirSep, AltSep}:
+          result.add dirSep
+        result.add substr(x, b[0], b[1])
     elif isDot(x, b):
       discard "discard the dot"
     elif b[1] >= b[0]:
       if result.len > 0 and result[^1] notin {DirSep, AltSep}:
         result.add dirSep
       result.add substr(x, b[0], b[1])
-    inc state, 2
+      inc state, 2
+  if result == "" and x != "": result = "."
 
 proc normalizePath*(path: string; dirSep = DirSep): string =
   ## Example:
@@ -89,7 +97,7 @@ proc normalizePath*(path: string; dirSep = DirSep): string =
   ##
   ## - Turns multiple slashes into single slashes.
   ## - Resolves '/foo/../bar' to '/bar'.
-  ## - Removes './' from the path.
+  ## - Removes './' from the path (but "foo/.." becomes ".")
   result = newStringOfCap(path.len)
   var state = 0
   addNormalizePath(path, result, state, dirSep)
diff --git a/lib/pure/random.nim b/lib/pure/random.nim
index c458d51eb..378ca6f87 100644
--- a/lib/pure/random.nim
+++ b/lib/pure/random.nim
@@ -14,6 +14,8 @@
 ##
 ## **Do not use this module for cryptographic purposes!**
 
+import algorithm                    #For upperBound
+
 include "system/inclrtl"
 {.push debugger:off.}
 
@@ -155,14 +157,48 @@ proc rand*[T](x: HSlice[T, T]): T =
   ## For a slice `a .. b` returns a value in the range `a .. b`.
   result = rand(state, x)
 
-proc rand*[T](r: var Rand; a: openArray[T]): T =
-  ## returns a random element from the openarray `a`.
+proc rand*[T](r: var Rand; a: openArray[T]): T {.deprecated.} =
+  ## Returns a random element from the openarray `a`.
+  ## **Deprecated since v0.20.0:** use ``sample`` instead.
   result = a[rand(r, a.low..a.high)]
 
-proc rand*[T](a: openArray[T]): T =
+proc rand*[T: SomeInteger](t: typedesc[T]): T =
+  ## Returns a random integer in the range `low(T)..high(T)`.
+  result = cast[T](state.next)
+
+proc rand*[T](a: openArray[T]): T {.deprecated.} =
   ## returns a random element from the openarray `a`.
+  ## **Deprecated since v0.20.0:** use ``sample`` instead.
+  result = a[rand(a.low..a.high)]
+
+proc sample*[T](r: var Rand; a: openArray[T]): T =
+  ## returns a random element from openArray ``a`` using state in ``r``.
+  result = a[r.rand(a.low..a.high)]
+
+proc sample*[T](a: openArray[T]): T =
+  ## returns a random element from openArray ``a`` using non-thread-safe state.
   result = a[rand(a.low..a.high)]
 
+proc sample*[T, U](r: var Rand; a: openArray[T], cdf: openArray[U]): T =
+  ## Sample one element from openArray ``a`` when it has cumulative distribution
+  ## function (CDF) ``cdf`` (not necessarily normalized, any type of elements
+  ## convertible to ``float``). Uses state in ``r``. E.g.:
+  ##
+  ## .. code-block:: nim
+  ##   let val = [ "a", "b", "c", "d" ]  # some values
+  ##   var cnt = [1, 2, 3, 4]            # histogram of counts
+  ##   echo r.sample(val, cnt.cumsummed) # echo a sample
+  assert(cdf.len == a.len)              # Two basic sanity checks.
+  assert(float(cdf[^1]) > 0.0)
+  #While we could check cdf[i-1] <= cdf[i] for i in 1..cdf.len, that could get
+  #awfully expensive even in debugging modes.
+  let u = r.rand(float(cdf[^1]))
+  a[cdf.upperBound(U(u))]
+
+proc sample*[T, U](a: openArray[T], cdf: openArray[U]): T =
+  ## Like ``sample(var Rand; openArray[T], openArray[U])``, but uses default
+  ## non-thread-safe state.
+  state.sample(a, cdf)
 
 proc initRand*(seed: int64): Rand =
   ## Creates a new ``Rand`` state from ``seed``.
@@ -191,8 +227,12 @@ when not defined(nimscript):
   proc randomize*() {.benign.} =
     ## Initializes the random number generator with a "random"
     ## number, i.e. a tickcount. Note: Does not work for NimScript.
-    let now = times.getTime()
-    randomize(convert(Seconds, Nanoseconds, now.toUnix) + now.nanosecond)
+    when defined(js):
+      let time = int64(times.epochTime() * 1_000_000_000)
+      randomize(time)
+    else:
+      let now = times.getTime()
+      randomize(convert(Seconds, Nanoseconds, now.toUnix) + now.nanosecond)
 
 {.pop.}
 
diff --git a/lib/pure/scgi.nim b/lib/pure/scgi.nim
deleted file mode 100644
index e36803823..000000000
--- a/lib/pure/scgi.nim
+++ /dev/null
@@ -1,295 +0,0 @@
-#
-#
-#            Nim's Runtime Library
-#        (c) Copyright 2013 Andreas Rumpf, Dominik Picheta
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## This module implements helper procs for SCGI applications. Example:
-##
-## .. code-block:: Nim
-##
-##    import strtabs, sockets, scgi
-##
-##    var counter = 0
-##    proc handleRequest(client: Socket, input: string,
-##                       headers: StringTableRef): bool {.procvar.} =
-##      inc(counter)
-##      client.writeStatusOkTextContent()
-##      client.send("Hello for the $#th time." % $counter & "\c\L")
-##      return false # do not stop processing
-##
-##    run(handleRequest)
-##
-## **Warning:** The API of this module is unstable, and therefore is subject
-## to change.
-##
-## **Warning:** This module only supports the old asynchronous interface.
-## You may wish to use the `asynchttpserver <asynchttpserver.html>`_
-## instead for web applications.
-
-include "system/inclrtl"
-
-import sockets, strutils, os, strtabs, asyncio
-
-type
-  ScgiError* = object of IOError ## the exception that is raised, if a SCGI error occurs
-
-proc raiseScgiError*(msg: string) {.noreturn.} =
-  ## raises an ScgiError exception with message `msg`.
-  var e: ref ScgiError
-  new(e)
-  e.msg = msg
-  raise e
-
-proc parseWord(inp: string, outp: var string, start: int): int =
-  result = start
-  while inp[result] != '\0': inc(result)
-  outp = substr(inp, start, result-1)
-
-proc parseHeaders(s: string, L: int): StringTableRef =
-  result = newStringTable()
-  var i = 0
-  while i < L:
-    var key, val: string
-    i = parseWord(s, key, i)+1
-    i = parseWord(s, val, i)+1
-    result[key] = val
-  if s[i] == ',': inc(i)
-  else: raiseScgiError("',' after netstring expected")
-
-proc recvChar(s: Socket): char =
-  var c: char
-  if recv(s, addr(c), sizeof(c)) == sizeof(c):
-    result = c
-
-type
-  ScgiState* = object of RootObj ## SCGI state object
-    server: Socket
-    bufLen: int
-    client*: Socket ## the client socket to send data to
-    headers*: StringTableRef ## the parsed headers
-    input*: string  ## the input buffer
-
-
-  # Async
-
-  ClientMode = enum
-    ClientReadChar, ClientReadHeaders, ClientReadContent
-
-  AsyncClient = ref object
-    c: AsyncSocket
-    mode: ClientMode
-    dataLen: int
-    headers: StringTableRef ## the parsed headers
-    input: string  ## the input buffer
-
-  AsyncScgiStateObj = object
-    handleRequest: proc (client: AsyncSocket,
-                         input: string,
-                         headers: StringTableRef) {.closure, gcsafe.}
-    asyncServer: AsyncSocket
-    disp: Dispatcher
-  AsyncScgiState* = ref AsyncScgiStateObj
-
-proc recvBuffer(s: var ScgiState, L: int) =
-  if L > s.bufLen:
-    s.bufLen = L
-    s.input = newString(L)
-  if L > 0 and recv(s.client, cstring(s.input), L) != L:
-    raiseScgiError("could not read all data")
-  setLen(s.input, L)
-
-proc open*(s: var ScgiState, port = Port(4000), address = "127.0.0.1",
-           reuseAddr = false) =
-  ## opens a connection.
-  s.bufLen = 4000
-  s.input = newString(s.bufLen) # will be reused
-
-  s.server = socket()
-  if s.server == invalidSocket: raiseOSError(osLastError())
-  new(s.client) # Initialise s.client for `next`
-  if s.server == invalidSocket: raiseScgiError("could not open socket")
-  #s.server.connect(connectionName, port)
-  if reuseAddr:
-    s.server.setSockOpt(OptReuseAddr, true)
-  bindAddr(s.server, port, address)
-  listen(s.server)
-
-proc close*(s: var ScgiState) =
-  ## closes the connection.
-  s.server.close()
-
-proc next*(s: var ScgiState, timeout: int = -1): bool =
-  ## proceed to the first/next request. Waits ``timeout`` milliseconds for a
-  ## request, if ``timeout`` is `-1` then this function will never time out.
-  ## Returns `true` if a new request has been processed.
-  var rsocks = @[s.server]
-  if select(rsocks, timeout) == 1 and rsocks.len == 1:
-    new(s.client)
-    accept(s.server, s.client)
-    var L = 0
-    while true:
-      var d = s.client.recvChar()
-      if d == '\0':
-        s.client.close()
-        return false
-      if d notin strutils.Digits:
-        if d != ':': raiseScgiError("':' after length expected")
-        break
-      L = L * 10 + ord(d) - ord('0')
-    recvBuffer(s, L+1)
-    s.headers = parseHeaders(s.input, L)
-    if s.headers.getOrDefault("SCGI") != "1": raiseScgiError("SCGI Version 1 expected")
-    L = parseInt(s.headers.getOrDefault("CONTENT_LENGTH"))
-    recvBuffer(s, L)
-    return true
-
-proc writeStatusOkTextContent*(c: Socket, contentType = "text/html") =
-  ## sends the following string to the socket `c`::
-  ##
-  ##   Status: 200 OK\r\LContent-Type: text/html\r\L\r\L
-  ##
-  ## You should send this before sending your HTML page, for example.
-  c.send("Status: 200 OK\r\L" &
-         "Content-Type: $1\r\L\r\L" % contentType)
-
-proc run*(handleRequest: proc (client: Socket, input: string,
-                               headers: StringTableRef): bool {.nimcall,gcsafe.},
-          port = Port(4000)) =
-  ## encapsulates the SCGI object and main loop.
-  var s: ScgiState
-  s.open(port)
-  var stop = false
-  while not stop:
-    if next(s):
-      stop = handleRequest(s.client, s.input, s.headers)
-      s.client.close()
-  s.close()
-
-# -- AsyncIO start
-
-proc recvBufferAsync(client: AsyncClient, L: int): ReadLineResult =
-  result = ReadPartialLine
-  var data = ""
-  if L < 1:
-    raiseScgiError("Cannot read negative or zero length: " & $L)
-  let ret = recvAsync(client.c, data, L)
-  if ret == 0 and data == "":
-    client.c.close()
-    return ReadDisconnected
-  if ret == -1:
-    return ReadNone # No more data available
-  client.input.add(data)
-  if ret == L:
-    return ReadFullLine
-
-proc checkCloseSocket(client: AsyncClient) =
-  if not client.c.isClosed:
-    if client.c.isSendDataBuffered:
-      client.c.setHandleWrite do (s: AsyncSocket):
-        if not s.isClosed and not s.isSendDataBuffered:
-          s.close()
-          s.delHandleWrite()
-    else: client.c.close()
-
-proc handleClientRead(client: AsyncClient, s: AsyncScgiState) =
-  case client.mode
-  of ClientReadChar:
-    while true:
-      var d = ""
-      let ret = client.c.recvAsync(d, 1)
-      if d == "" and ret == 0:
-        # Disconnected
-        client.c.close()
-        return
-      if ret == -1:
-        return # No more data available
-      if d[0] notin strutils.Digits:
-        if d[0] != ':': raiseScgiError("':' after length expected")
-        break
-      client.dataLen = client.dataLen * 10 + ord(d[0]) - ord('0')
-    client.mode = ClientReadHeaders
-    handleClientRead(client, s) # Allow progression
-  of ClientReadHeaders:
-    let ret = recvBufferAsync(client, (client.dataLen+1)-client.input.len)
-    case ret
-    of ReadFullLine:
-      client.headers = parseHeaders(client.input, client.input.len-1)
-      if client.headers.getOrDefault("SCGI") != "1": raiseScgiError("SCGI Version 1 expected")
-      client.input = "" # For next part
-
-      let contentLen = parseInt(client.headers.getOrDefault("CONTENT_LENGTH"))
-      if contentLen > 0:
-        client.mode = ClientReadContent
-      else:
-        s.handleRequest(client.c, client.input, client.headers)
-        checkCloseSocket(client)
-    of ReadPartialLine, ReadDisconnected, ReadNone: return
-  of ClientReadContent:
-    let L = parseInt(client.headers.getOrDefault("CONTENT_LENGTH")) -
-               client.input.len
-    if L > 0:
-      let ret = recvBufferAsync(client, L)
-      case ret
-      of ReadFullLine:
-        s.handleRequest(client.c, client.input, client.headers)
-        checkCloseSocket(client)
-      of ReadPartialLine, ReadDisconnected, ReadNone: return
-    else:
-      s.handleRequest(client.c, client.input, client.headers)
-      checkCloseSocket(client)
-
-proc handleAccept(sock: AsyncSocket, s: AsyncScgiState) =
-  var client: AsyncSocket
-  new(client)
-  accept(s.asyncServer, client)
-  var asyncClient = AsyncClient(c: client, mode: ClientReadChar, dataLen: 0,
-                                 headers: newStringTable(), input: "")
-  client.handleRead =
-    proc (sock: AsyncSocket) =
-      handleClientRead(asyncClient, s)
-  s.disp.register(client)
-
-proc open*(handleRequest: proc (client: AsyncSocket,
-                                input: string, headers: StringTableRef) {.
-                                closure, gcsafe.},
-           port = Port(4000), address = "127.0.0.1",
-           reuseAddr = false): AsyncScgiState =
-  ## Creates an ``AsyncScgiState`` object which serves as a SCGI server.
-  ##
-  ## After the execution of ``handleRequest`` the client socket will be closed
-  ## automatically unless it has already been closed.
-  var cres: AsyncScgiState
-  new(cres)
-  cres.asyncServer = asyncSocket()
-  cres.asyncServer.handleAccept = proc (s: AsyncSocket) = handleAccept(s, cres)
-  if reuseAddr:
-    cres.asyncServer.setSockOpt(OptReuseAddr, true)
-  bindAddr(cres.asyncServer, port, address)
-  listen(cres.asyncServer)
-  cres.handleRequest = handleRequest
-  result = cres
-
-proc register*(d: Dispatcher, s: AsyncScgiState): Delegate {.discardable.} =
-  ## Registers ``s`` with dispatcher ``d``.
-  result = d.register(s.asyncServer)
-  s.disp = d
-
-proc close*(s: AsyncScgiState) =
-  ## Closes the ``AsyncScgiState``.
-  s.asyncServer.close()
-
-when false:
-  var counter = 0
-  proc handleRequest(client: Socket, input: string,
-                     headers: StringTableRef): bool {.procvar.} =
-    inc(counter)
-    client.writeStatusOkTextContent()
-    client.send("Hello for the $#th time." % $counter & "\c\L")
-    return false # do not stop processing
-
-  run(handleRequest)
-
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
index e4c2b2124..b9c834127 100644
--- a/lib/pure/selectors.nim
+++ b/lib/pure/selectors.nim
@@ -239,6 +239,9 @@ else:
     proc allocSharedArray[T](nsize: int): ptr SharedArray[T] =
       result = cast[ptr SharedArray[T]](allocShared0(sizeof(T) * nsize))
 
+    proc reallocSharedArray[T](sa: ptr SharedArray[T], nsize: int): ptr SharedArray[T] =
+      result = cast[ptr SharedArray[T]](reallocShared(sa, sizeof(T) * nsize))
+
     proc deallocSharedArray[T](sa: ptr SharedArray[T]) =
       deallocShared(cast[pointer](sa))
   type
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index b0ac62525..10de86e9f 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -146,12 +146,12 @@ proc writeLine*(s: Stream, args: varargs[string, `$`]) =
   for str in args: write(s, str)
   write(s, "\n")
 
-proc read[T](s: Stream, result: var T) =
+proc read*[T](s: Stream, result: var T) =
   ## generic read procedure. Reads `result` from the stream `s`.
   if readData(s, addr(result), sizeof(T)) != sizeof(T):
     raise newEIO("cannot read from stream")
 
-proc peek[T](s: Stream, result: var T) =
+proc peek*[T](s: Stream, result: var T) =
   ## generic peek procedure. Peeks `result` from the stream `s`.
   if peekData(s, addr(result), sizeof(T)) != sizeof(T):
     raise newEIO("cannot read from stream")
@@ -271,7 +271,7 @@ proc peekStr*(s: Stream, length: int): TaintedString =
 proc readLine*(s: Stream, line: var TaintedString): bool =
   ## reads a line of text from the stream `s` into `line`. `line` must not be
   ## ``nil``! May throw an IO exception.
-  ## A line of text may be delimited by ```LF`` or ``CRLF``.
+  ## A line of text may be delimited by ``LF`` or ``CRLF``.
   ## The newline character(s) are not part of the returned string.
   ## Returns ``false`` if the end of the file has been reached, ``true``
   ## otherwise. If ``false`` is returned `line` contains no new data.
diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim
index d8a23286a..7bafe1675 100644
--- a/lib/pure/strtabs.nim
+++ b/lib/pure/strtabs.nim
@@ -12,6 +12,34 @@
 ## style-insensitive mode. An efficient string substitution operator  ``%``
 ## for the string table is also provided.
 
+runnableExamples:
+
+  var t = newStringTable()
+  t["name"] = "John"
+  t["city"] = "Monaco"
+  doAssert t.len == 2
+  doAssert t.hasKey "name"
+  doAssert "name" in t
+
+## String tables can be created from a table constructor:
+
+runnableExamples:
+  var t = {"name": "John", "city": "Monaco"}.newStringTable
+
+
+## When using the style insensitive mode ``modeStyleInsensitive``, 
+## all letters are compared case insensitively within the ASCII range 
+## and underscores are ignored.
+
+runnableExamples:
+
+  var x = newStringTable(modeStyleInsensitive)
+  x["first_name"] = "John"
+  x["LastName"] = "Doe"
+
+  doAssert x["firstName"] == "John"
+  doAssert x["last_name"] == "Doe"
+
 import
   hashes, strutils
 
@@ -214,6 +242,9 @@ proc newStringTable*(keyValuePairs: varargs[tuple[key, val: string]],
 proc `%`*(f: string, t: StringTableRef, flags: set[FormatFlag] = {}): string {.
   rtlFunc, extern: "nstFormat".} =
   ## The `%` operator for string tables.
+  runnableExamples:
+    var t = {"name": "John", "city": "Monaco"}.newStringTable
+    doAssert "${name} lives in ${city}" % t == "John lives in Monaco"
   const
     PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF'}
   result = ""
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 4d0fe800e..8385eb24e 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -7,11 +7,70 @@
 #    distribution, for details about the copyright.
 #
 
-## This module contains various string utility routines.
-## See the module `re <re.html>`_ for regular expression support.
-## See the module `pegs <pegs.html>`_ for PEG support.
+## The system module defines several common functions for working with strings,
+## such as:
+## * ``$`` for converting other data-types to strings
+## * ``&`` for string concatenation
+## * ``add`` for adding a new character or a string to the existing one
+## * ``in`` (alias for ``contains``) and ``notin`` for checking if a character
+##   is in a string
+##
+## This module builds upon that, providing additional functionality in form of
+## procedures, iterators and templates for strings.
+##
+## .. code-block::
+##   import strutils
+##
+##   let
+##     numbers = @[867, 5309]
+##     multiLineString = "first line\nsecond line\nthird line"
+##
+##   let jenny = numbers.join("-")
+##   assert jenny == "867-5309"
+##
+##   assert splitLines(multiLineString) ==
+##          @["first line", "second line", "third line"]
+##   assert split(multiLineString) == @["first", "line", "second",
+##                                      "line", "third", "line"]
+##   assert indent(multiLineString, 4) ==
+##          "    first line\n    second line\n    third line"
+##   assert 'z'.repeat(5) == "zzzzz"
+##
+## The chaining of functions is possible thanks to the
+## `method call syntax<manual.html#procedures-method-call-syntax>`_:
+##
+## .. code-block::
+##   import strutils
+##   from sequtils import map
+##
+##   let jenny = "867-5309"
+##   assert jenny.split('-').map(parseInt) == @[867, 5309]
+##
+##   assert "Beetlejuice".indent(1).repeat(3).strip ==
+##          "Beetlejuice Beetlejuice Beetlejuice"
+##
 ## This module is available for the `JavaScript target
 ## <backends.html#the-javascript-target>`_.
+##
+## ----
+##
+## **See also:**
+## * `strformat module<strformat.html>`_ for string interpolation and formatting
+## * `unicode module<unicode.html>`_ for Unicode UTF-8 handling
+## * `sequtils module<collections/sequtils.html>`_ for operations on container
+##   types (including strings)
+## * `parseutils module<parseutils.html>`_ for lower-level parsing of tokens,
+##   numbers, identifiers, etc.
+## * `parseopt module<parseopt.html>`_ for command-line parsing
+## * `strtabs module<strtabs.html>`_ for efficient hash tables
+##   (dictionaries, in some programming languages) mapping from strings to strings
+## * `pegs module<pegs.html>`_ for PEG (Parsing Expression Grammar) support
+## * `ropes module<ropes.html>`_ for rope data type, which can represent very
+##   long strings efficiently
+## * `re module<re.html>`_ for regular expression (regex) support
+## * `strscans<strscans.html>`_ for ``scanf`` and ``scanp`` macros, which offer
+##   easier substring extraction than regular expressions
+
 
 import parseutils
 from math import pow, floor, log10
@@ -38,7 +97,8 @@ else:
 
 const
   Whitespace* = {' ', '\t', '\v', '\r', '\l', '\f'}
-    ## All the characters that count as whitespace.
+    ## All the characters that count as whitespace (space, tab, vertical tab,
+    ## carriage return, new line, form feed)
 
   Letters* = {'A'..'Z', 'a'..'z'}
     ## the set of letters
@@ -56,14 +116,15 @@ const
     ## the set of characters an identifier can start with
 
   NewLines* = {'\13', '\10'}
-    ## the set of characters a newline terminator can start with
+    ## the set of characters a newline terminator can start with (carriage
+    ## return, line feed)
 
   AllChars* = {'\x00'..'\xFF'}
     ## A set with all the possible characters.
     ##
     ## Not very useful by its own, you can use it to create *inverted* sets to
-    ## make the `find() proc <#find,string,set[char],int>`_ find **invalid**
-    ## characters in strings.  Example:
+    ## make the `find proc<#find,string,set[char],Natural,int>`_
+    ## find **invalid** characters in strings. Example:
     ##
     ## .. code-block:: nim
     ##   let invalid = AllChars - Digits
@@ -72,9 +133,10 @@ const
 
 proc isAlphaAscii*(c: char): bool {.noSideEffect, procvar,
   rtl, extern: "nsuIsAlphaAsciiChar".}=
-  ## Checks whether or not `c` is alphabetical.
+  ## Checks whether or not character `c` is alphabetical.
   ##
   ## This checks a-z, A-Z ASCII characters only.
+  ## Use `Unicode module<unicode.html>`_ for UTF-8 support.
   runnableExamples:
     doAssert isAlphaAscii('e') == true
     doAssert isAlphaAscii('E') == true
@@ -108,6 +170,7 @@ proc isSpaceAscii*(c: char): bool {.noSideEffect, procvar,
   runnableExamples:
     doAssert isSpaceAscii('n') == false
     doAssert isSpaceAscii(' ') == true
+    doAssert isSpaceAscii('\t') == true
   return c in Whitespace
 
 proc isLowerAscii*(c: char): bool {.noSideEffect, procvar,
@@ -115,6 +178,10 @@ proc isLowerAscii*(c: char): bool {.noSideEffect, procvar,
   ## Checks whether or not `c` is a lower case character.
   ##
   ## This checks ASCII characters only.
+  ## Use `Unicode module<unicode.html>`_ for UTF-8 support.
+  ##
+  ## See also:
+  ## * `toLowerAscii proc<#toLowerAscii,char>`_
   runnableExamples:
     doAssert isLowerAscii('e') == true
     doAssert isLowerAscii('E') == false
@@ -126,138 +193,28 @@ proc isUpperAscii*(c: char): bool {.noSideEffect, procvar,
   ## Checks whether or not `c` is an upper case character.
   ##
   ## This checks ASCII characters only.
+  ## Use `Unicode module<unicode.html>`_ for UTF-8 support.
+  ##
+  ## See also:
+  ## * `toUpperAscii proc<#toUpperAscii,char>`_
   runnableExamples:
     doAssert isUpperAscii('e') == false
     doAssert isUpperAscii('E') == true
     doAssert isUpperAscii('7') == false
   return c in {'A'..'Z'}
 
-template isImpl(call) =
-  if s.len == 0: return false
-  result = true
-  for c in s:
-    if not call(c): return false
-
-proc isAlphaAscii*(s: string): bool {.noSideEffect, procvar,
-  rtl, extern: "nsuIsAlphaAsciiStr",
-  deprecated: "Deprecated since version 0.20 since its semantics are unclear".} =
-  ## Checks whether or not `s` is alphabetical.
-  ##
-  ## This checks a-z, A-Z ASCII characters only.
-  ## Returns true if all characters in `s` are
-  ## alphabetic and there is at least one character
-  ## in `s`.
-  runnableExamples:
-    doAssert isAlphaAscii("fooBar") == true
-    doAssert isAlphaAscii("fooBar1") == false
-    doAssert isAlphaAscii("foo Bar") == false
-  isImpl isAlphaAscii
-
-proc isAlphaNumeric*(s: string): bool {.noSideEffect, procvar,
-  rtl, extern: "nsuIsAlphaNumericStr",
-  deprecated: "Deprecated since version 0.20 since its semantics are unclear".} =
-  ## Checks whether or not `s` is alphanumeric.
-  ##
-  ## This checks a-z, A-Z, 0-9 ASCII characters only.
-  ## Returns true if all characters in `s` are
-  ## alpanumeric and there is at least one character
-  ## in `s`.
-  runnableExamples:
-    doAssert isAlphaNumeric("fooBar") == true
-    doAssert isAlphaNumeric("fooBar") == true
-    doAssert isAlphaNumeric("foo Bar") == false
-  isImpl isAlphaNumeric
-
-proc isDigit*(s: string): bool {.noSideEffect, procvar,
-  rtl, extern: "nsuIsDigitStr",
-  deprecated: "Deprecated since version 0.20 since its semantics are unclear".} =
-  ## Checks whether or not `s` is a numeric value.
-  ##
-  ## This checks 0-9 ASCII characters only.
-  ## Returns true if all characters in `s` are
-  ## numeric and there is at least one character
-  ## in `s`.
-  runnableExamples:
-    doAssert isDigit("1908") == true
-    doAssert isDigit("fooBar1") == false
-  isImpl isDigit
-
-proc isSpaceAscii*(s: string): bool {.noSideEffect, procvar,
-  rtl, extern: "nsuIsSpaceAsciiStr",
-  deprecated: "Deprecated since version 0.20 since its semantics are unclear".} =
-  ## Checks whether or not `s` is completely whitespace.
-  ##
-  ## Returns true if all characters in `s` are whitespace
-  ## characters and there is at least one character in `s`.
-  runnableExamples:
-    doAssert isSpaceAscii("   ") == true
-    doAssert isSpaceAscii("") == false
-  isImpl isSpaceAscii
-
-template isCaseImpl(s, charProc, skipNonAlpha) =
-  var hasAtleastOneAlphaChar = false
-  if s.len == 0: return false
-  for c in s:
-    if skipNonAlpha:
-      var charIsAlpha = c.isAlphaAscii()
-      if not hasAtleastOneAlphaChar:
-        hasAtleastOneAlphaChar = charIsAlpha
-      if charIsAlpha and (not charProc(c)):
-        return false
-    else:
-      if not charProc(c):
-        return false
-  return if skipNonAlpha: hasAtleastOneAlphaChar else: true
-
-proc isLowerAscii*(s: string, skipNonAlpha: bool): bool {.
-  deprecated: "Deprecated since version 0.20 since its semantics are unclear".} =
-  ## Checks whether ``s`` is lower case.
-  ##
-  ## This checks ASCII characters only.
-  ##
-  ## If ``skipNonAlpha`` is true, returns true if all alphabetical
-  ## characters in ``s`` are lower case.  Returns false if none of the
-  ## characters in ``s`` are alphabetical.
-  ##
-  ## If ``skipNonAlpha`` is false, returns true only if all characters
-  ## in ``s`` are alphabetical and lower case.
-  ##
-  ## For either value of ``skipNonAlpha``, returns false if ``s`` is
-  ## an empty string.
-  runnableExamples:
-    doAssert isLowerAscii("1foobar", false) == false
-    doAssert isLowerAscii("1foobar", true) == true
-    doAssert isLowerAscii("1fooBar", true) == false
-  isCaseImpl(s, isLowerAscii, skipNonAlpha)
-
-proc isUpperAscii*(s: string, skipNonAlpha: bool): bool {.
-  deprecated: "Deprecated since version 0.20 since its semantics are unclear".} =
-  ## Checks whether ``s`` is upper case.
-  ##
-  ## This checks ASCII characters only.
-  ##
-  ## If ``skipNonAlpha`` is true, returns true if all alphabetical
-  ## characters in ``s`` are upper case.  Returns false if none of the
-  ## characters in ``s`` are alphabetical.
-  ##
-  ## If ``skipNonAlpha`` is false, returns true only if all characters
-  ## in ``s`` are alphabetical and upper case.
-  ##
-  ## For either value of ``skipNonAlpha``, returns false if ``s`` is
-  ## an empty string.
-  runnableExamples:
-    doAssert isUpperAscii("1FOO", false) == false
-    doAssert isUpperAscii("1FOO", true) == true
-    doAssert isUpperAscii("1Foo", true) == false
-  isCaseImpl(s, isUpperAscii, skipNonAlpha)
 
 proc toLowerAscii*(c: char): char {.noSideEffect, procvar,
   rtl, extern: "nsuToLowerAsciiChar".} =
-  ## Returns the lower case version of ``c``.
+  ## Returns the lower case version of character ``c``.
   ##
   ## This works only for the letters ``A-Z``. See `unicode.toLower
   ## <unicode.html#toLower>`_ for a version that works for any Unicode
   ## character.
+  ##
+  ## See also:
+  ## * `isLowerAscii proc<#isLowerAscii,char>`_
+  ## * `toLowerAscii proc<#toLowerAscii,string>`_ for converting a string
   runnableExamples:
     doAssert toLowerAscii('A') == 'a'
     doAssert toLowerAscii('e') == 'e'
@@ -273,22 +230,30 @@ template toImpl(call) =
 
 proc toLowerAscii*(s: string): string {.noSideEffect, procvar,
   rtl, extern: "nsuToLowerAsciiStr".} =
-  ## Converts `s` into lower case.
+  ## Converts string `s` into lower case.
   ##
   ## This works only for the letters ``A-Z``. See `unicode.toLower
   ## <unicode.html#toLower>`_ for a version that works for any Unicode
   ## character.
+  ##
+  ## See also:
+  ## * `normalize proc<#normalize,string>`_
   runnableExamples:
     doAssert toLowerAscii("FooBar!") == "foobar!"
   toImpl toLowerAscii
 
 proc toUpperAscii*(c: char): char {.noSideEffect, procvar,
   rtl, extern: "nsuToUpperAsciiChar".} =
-  ## Converts `c` into upper case.
+  ## Converts character `c` into upper case.
   ##
   ## This works only for the letters ``A-Z``.  See `unicode.toUpper
   ## <unicode.html#toUpper>`_ for a version that works for any Unicode
   ## character.
+  ##
+  ## See also:
+  ## * `isLowerAscii proc<#isLowerAscii,char>`_
+  ## * `toUpperAscii proc<#toUpperAscii,string>`_ for converting a string
+  ## * `capitalizeAscii proc<#capitalizeAscii,string>`_
   runnableExamples:
     doAssert toUpperAscii('a') == 'A'
     doAssert toUpperAscii('E') == 'E'
@@ -299,20 +264,27 @@ proc toUpperAscii*(c: char): char {.noSideEffect, procvar,
 
 proc toUpperAscii*(s: string): string {.noSideEffect, procvar,
   rtl, extern: "nsuToUpperAsciiStr".} =
-  ## Converts `s` into upper case.
+  ## Converts string `s` into upper case.
   ##
   ## This works only for the letters ``A-Z``.  See `unicode.toUpper
   ## <unicode.html#toUpper>`_ for a version that works for any Unicode
   ## character.
+  ##
+  ## See also:
+  ## * `capitalizeAscii proc<#capitalizeAscii,string>`_
   runnableExamples:
     doAssert toUpperAscii("FooBar!") == "FOOBAR!"
   toImpl toUpperAscii
 
 proc capitalizeAscii*(s: string): string {.noSideEffect, procvar,
   rtl, extern: "nsuCapitalizeAscii".} =
-  ## Converts the first character of `s` into upper case.
+  ## Converts the first character of string `s` into upper case.
   ##
   ## This works only for the letters ``A-Z``.
+  ## Use `Unicode module<unicode.html>`_ for UTF-8 support.
+  ##
+  ## See also:
+  ## * `toUpperAscii proc<#toUpperAscii,char>`_
   runnableExamples:
     doAssert capitalizeAscii("foo") == "Foo"
     doAssert capitalizeAscii("-bar") == "-bar"
@@ -325,6 +297,9 @@ proc normalize*(s: string): string {.noSideEffect, procvar,
   ##
   ## That means to convert it to lower case and remove any '_'. This
   ## should NOT be used to normalize Nim identifier names.
+  ##
+  ## See also:
+  ## * `toLowerAscii proc<#toLowerAscii,string>`_
   runnableExamples:
     doAssert normalize("Foo_bar") == "foobar"
     doAssert normalize("Foo Bar") == "foo bar"
@@ -343,9 +318,9 @@ proc cmpIgnoreCase*(a, b: string): int {.noSideEffect,
   rtl, extern: "nsuCmpIgnoreCase", procvar.} =
   ## Compares two strings in a case insensitive manner. Returns:
   ##
-  ## | 0 iff a == b
-  ## | < 0 iff a < b
-  ## | > 0 iff a > b
+  ## | 0 if a == b
+  ## | < 0 if a < b
+  ## | > 0 if a > b
   runnableExamples:
     doAssert cmpIgnoreCase("FooBar", "foobar") == 0
     doAssert cmpIgnoreCase("bar", "Foo") < 0
@@ -365,12 +340,14 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
   rtl, extern: "nsuCmpIgnoreStyle", procvar.} =
   ## Semantically the same as ``cmp(normalize(a), normalize(b))``. It
   ## is just optimized to not allocate temporary strings. This should
-  ## NOT be used to compare Nim identifier names. use `macros.eqIdent`
-  ## for that. Returns:
+  ## NOT be used to compare Nim identifier names.
+  ## Use `macros.eqIdent<macros.html#eqIdent,string,string>`_ for that.
+  ##
+  ## Returns:
   ##
-  ## | 0 iff a == b
-  ## | < 0 iff a < b
-  ## | > 0 iff a > b
+  ## | 0 if a == b
+  ## | < 0 if a < b
+  ## | > 0 if a > b
   runnableExamples:
     doAssert cmpIgnoreStyle("foo_bar", "FooBar") == 0
     doAssert cmpIgnoreStyle("foo_bar_5", "FooBar4") > 0
@@ -394,51 +371,8 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
     inc i
     inc j
 
-proc strip*(s: string, leading = true, trailing = true,
-            chars: set[char] = Whitespace): string
-  {.noSideEffect, rtl, extern: "nsuStrip".} =
-  ## Strips leading or trailing `chars` from `s` and returns
-  ## the resulting string.
-  ##
-  ## If `leading` is true, leading `chars` are stripped.
-  ## If `trailing` is true, trailing `chars` are stripped.
-  ## If both are false, the string is returned unchanged.
-  runnableExamples:
-    doAssert " vhellov ".strip().strip(trailing = false, chars = {'v'}) == "hellov"
-  var
-    first = 0
-    last = len(s)-1
-  if leading:
-    while first <= last and s[first] in chars: inc(first)
-  if trailing:
-    while last >= 0 and s[last] in chars: dec(last)
-  result = substr(s, first, last)
-
-proc toOctal*(c: char): string {.noSideEffect, rtl, extern: "nsuToOctal".} =
-  ## Converts a character `c` to its octal representation.
-  ##
-  ## The resulting string may not have a leading zero. Its length is always
-  ## exactly 3.
-  runnableExamples:
-    doAssert toOctal('!') == "041"
-  result = newString(3)
-  var val = ord(c)
-  for i in countdown(2, 0):
-    result[i] = chr(val mod 8 + ord('0'))
-    val = val div 8
 
-proc isNilOrEmpty*(s: string): bool {.noSideEffect, procvar, rtl,
-                                      extern: "nsuIsNilOrEmpty",
-                                      deprecated: "use 'x.len == 0' instead".} =
-  ## Checks if `s` is nil or empty.
-  result = len(s) == 0
-
-proc isNilOrWhitespace*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nsuIsNilOrWhitespace".} =
-  ## Checks if `s` is nil or consists entirely of whitespace characters.
-  result = true
-  for c in s:
-    if not c.isSpaceAscii():
-      return false
+# --------- Private templates for different split separators -----------
 
 proc substrEq(s: string, pos: int, substr: string): bool =
   var i = 0
@@ -447,8 +381,6 @@ proc substrEq(s: string, pos: int, substr: string): bool =
     inc i
   return i == length
 
-# --------- Private templates for different split separators -----------
-
 template stringHasSep(s: string, index: int, seps: set[char]): bool =
   s[index] in seps
 
@@ -459,7 +391,7 @@ template stringHasSep(s: string, index: int, sep: string): bool =
   s.substrEq(index, sep)
 
 template splitCommon(s, sep, maxsplit, sepLen) =
-  ## Common code for split procedures
+  ## Common code for split procs
   var last = 0
   var splits = maxsplit
 
@@ -487,6 +419,42 @@ template oldSplit(s, seps, maxsplit) =
       if splits == 0: break
       dec(splits)
 
+template accResult(iter: untyped) =
+  result = @[]
+  for x in iter: add(result, x)
+
+
+iterator split*(s: string, sep: char, maxsplit: int = -1): string =
+  ## Splits the string `s` into substrings using a single separator.
+  ##
+  ## Substrings are separated by the character `sep`.
+  ## The code:
+  ##
+  ## .. code-block:: nim
+  ##   for word in split(";;this;is;an;;example;;;", ';'):
+  ##     writeLine(stdout, word)
+  ##
+  ## Results in:
+  ##
+  ## .. code-block::
+  ##   ""
+  ##   ""
+  ##   "this"
+  ##   "is"
+  ##   "an"
+  ##   ""
+  ##   "example"
+  ##   ""
+  ##   ""
+  ##   ""
+  ##
+  ## See also:
+  ## * `rsplit iterator<#rsplit.i,string,char,int>`_
+  ## * `splitLines iterator<#splitLines.i,string>`_
+  ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_
+  ## * `split proc<#split,string,char,int>`_
+  splitCommon(s, sep, maxsplit, 1)
+
 iterator split*(s: string, seps: set[char] = Whitespace,
                 maxsplit: int = -1): string =
   ## Splits the string `s` into substrings using a group of separators.
@@ -529,79 +497,13 @@ iterator split*(s: string, seps: set[char] = Whitespace,
   ##   "08"
   ##   "08.398990"
   ##
+  ## See also:
+  ## * `rsplit iterator<#rsplit.i,string,set[char],int>`_
+  ## * `splitLines iterator<#splitLines.i,string>`_
+  ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_
+  ## * `split proc<#split,string,set[char],int>`_
   splitCommon(s, seps, maxsplit, 1)
 
-iterator splitWhitespace*(s: string, maxsplit: int = -1): string =
-  ## Splits the string ``s`` at whitespace stripping leading and trailing
-  ## whitespace if necessary. If ``maxsplit`` is specified and is positive,
-  ## no more than ``maxsplit`` splits is made.
-  ##
-  ## The following code:
-  ##
-  ## .. code-block:: nim
-  ##   let s = "  foo \t bar  baz  "
-  ##   for ms in [-1, 1, 2, 3]:
-  ##     echo "------ maxsplit = ", ms, ":"
-  ##     for item in s.splitWhitespace(maxsplit=ms):
-  ##       echo '"', item, '"'
-  ##
-  ## ...results in:
-  ##
-  ## .. code-block::
-  ##   ------ maxsplit = -1:
-  ##   "foo"
-  ##   "bar"
-  ##   "baz"
-  ##   ------ maxsplit = 1:
-  ##   "foo"
-  ##   "bar  baz  "
-  ##   ------ maxsplit = 2:
-  ##   "foo"
-  ##   "bar"
-  ##   "baz  "
-  ##   ------ maxsplit = 3:
-  ##   "foo"
-  ##   "bar"
-  ##   "baz"
-  ##
-  oldSplit(s, Whitespace, maxsplit)
-
-template accResult(iter: untyped) =
-  result = @[]
-  for x in iter: add(result, x)
-
-proc splitWhitespace*(s: string, maxsplit: int = -1): seq[string] {.noSideEffect,
-  rtl, extern: "nsuSplitWhitespace".} =
-  ## The same as the `splitWhitespace <#splitWhitespace.i,string,int>`_
-  ## iterator, but is a proc that returns a sequence of substrings.
-  accResult(splitWhitespace(s, maxsplit))
-
-iterator split*(s: string, sep: char, maxsplit: int = -1): string =
-  ## Splits the string `s` into substrings using a single separator.
-  ##
-  ## Substrings are separated by the character `sep`.
-  ## The code:
-  ##
-  ## .. code-block:: nim
-  ##   for word in split(";;this;is;an;;example;;;", ';'):
-  ##     writeLine(stdout, word)
-  ##
-  ## Results in:
-  ##
-  ## .. code-block::
-  ##   ""
-  ##   ""
-  ##   "this"
-  ##   "is"
-  ##   "an"
-  ##   ""
-  ##   "example"
-  ##   ""
-  ##   ""
-  ##   ""
-  ##
-  splitCommon(s, sep, maxsplit, 1)
-
 iterator split*(s: string, sep: string, maxsplit: int = -1): string =
   ## Splits the string `s` into substrings using a string separator.
   ##
@@ -619,8 +521,14 @@ iterator split*(s: string, sep: string, maxsplit: int = -1): string =
   ##   "is"
   ##   "corrupted"
   ##
+  ## See also:
+  ## * `rsplit iterator<#rsplit.i,string,string,int,bool>`_
+  ## * `splitLines iterator<#splitLines.i,string>`_
+  ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_
+  ## * `split proc<#split,string,string,int>`_
   splitCommon(s, sep, maxsplit, sep.len)
 
+
 template rsplitCommon(s, sep, maxsplit, sepLen) =
   ## Common code for rsplit functions
   var
@@ -645,14 +553,14 @@ template rsplitCommon(s, sep, maxsplit, sepLen) =
     dec(first)
     last = first
 
-iterator rsplit*(s: string, seps: set[char] = Whitespace,
+iterator rsplit*(s: string, sep: char,
                  maxsplit: int = -1): string =
   ## Splits the string `s` into substrings from the right using a
   ## string separator. Works exactly the same as `split iterator
   ## <#split.i,string,char,int>`_ except in reverse order.
   ##
   ## .. code-block:: nim
-  ##   for piece in "foo bar".rsplit(WhiteSpace):
+  ##   for piece in "foo:bar".rsplit(':'):
   ##     echo piece
   ##
   ## Results in:
@@ -661,17 +569,23 @@ iterator rsplit*(s: string, seps: set[char] = Whitespace,
   ##   "bar"
   ##   "foo"
   ##
-  ## Substrings are separated from the right by the set of chars `seps`
-  rsplitCommon(s, seps, maxsplit, 1)
+  ## Substrings are separated from the right by the char `sep`.
+  ##
+  ## See also:
+  ## * `split iterator<#split.i,string,char,int>`_
+  ## * `splitLines iterator<#splitLines.i,string>`_
+  ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_
+  ## * `rsplit proc<#rsplit,string,char,int>`_
+  rsplitCommon(s, sep, maxsplit, 1)
 
-iterator rsplit*(s: string, sep: char,
+iterator rsplit*(s: string, seps: set[char] = Whitespace,
                  maxsplit: int = -1): string =
   ## Splits the string `s` into substrings from the right using a
   ## string separator. Works exactly the same as `split iterator
   ## <#split.i,string,char,int>`_ except in reverse order.
   ##
   ## .. code-block:: nim
-  ##   for piece in "foo:bar".rsplit(':'):
+  ##   for piece in "foo bar".rsplit(WhiteSpace):
   ##     echo piece
   ##
   ## Results in:
@@ -680,8 +594,14 @@ iterator rsplit*(s: string, sep: char,
   ##   "bar"
   ##   "foo"
   ##
-  ## Substrings are separated from the right by the char `sep`
-  rsplitCommon(s, sep, maxsplit, 1)
+  ## Substrings are separated from the right by the set of chars `seps`
+  ##
+  ## See also:
+  ## * `split iterator<#split.i,string,set[char],int>`_
+  ## * `splitLines iterator<#splitLines.i,string>`_
+  ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_
+  ## * `rsplit proc<#rsplit,string,set[char],int>`_
+  rsplitCommon(s, seps, maxsplit, 1)
 
 iterator rsplit*(s: string, sep: string, maxsplit: int = -1,
                  keepSeparators: bool = false): string =
@@ -700,6 +620,12 @@ iterator rsplit*(s: string, sep: string, maxsplit: int = -1,
   ##   "foo"
   ##
   ## Substrings are separated from the right by the string `sep`
+  ##
+  ## See also:
+  ## * `split iterator<#split.i,string,string,int>`_
+  ## * `splitLines iterator<#splitLines.i,string>`_
+  ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_
+  ## * `rsplit proc<#rsplit,string,string,int>`_
   rsplitCommon(s, sep, maxsplit, sep.len)
 
 iterator splitLines*(s: string, keepEol = false): string =
@@ -726,6 +652,10 @@ iterator splitLines*(s: string, keepEol = false): string =
   ##   ""
   ##   "example"
   ##   ""
+  ##
+  ## See also:
+  ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_
+  ## * `splitLines proc<#splitLines,string>`_
   var first = 0
   var last = 0
   var eolpos = 0
@@ -747,76 +677,102 @@ iterator splitLines*(s: string, keepEol = false): string =
 
     first = last
 
-proc splitLines*(s: string, keepEol = false): seq[string] {.noSideEffect,
-  rtl, extern: "nsuSplitLines".} =
-  ## The same as the `splitLines <#splitLines.i,string>`_ iterator, but is a
-  ## proc that returns a sequence of substrings.
-  accResult(splitLines(s, keepEol=keepEol))
-
-proc countLines*(s: string): int {.noSideEffect,
-  rtl, extern: "nsuCountLines".} =
-  ## Returns the number of lines in the string `s`.
+iterator splitWhitespace*(s: string, maxsplit: int = -1): string =
+  ## Splits the string ``s`` at whitespace stripping leading and trailing
+  ## whitespace if necessary. If ``maxsplit`` is specified and is positive,
+  ## no more than ``maxsplit`` splits is made.
   ##
-  ## This is the same as ``len(splitLines(s))``, but much more efficient
-  ## because it doesn't modify the string creating temporal objects. Every
-  ## `character literal <manual.html#character-literals>`_ newline combination
-  ## (CR, LF, CR-LF) is supported.
+  ## The following code:
   ##
-  ## In this context, a line is any string seperated by a newline combination.
-  ## A line can be an empty string.
-  runnableExamples:
-    doAssert countLines("First line\l and second line.") == 2
-  result = 1
-  var i = 0
-  while i < s.len:
-    case s[i]
-    of '\c':
-      if i+1 < s.len and s[i+1] == '\l': inc i
-      inc result
-    of '\l': inc result
-    else: discard
-    inc i
+  ## .. code-block:: nim
+  ##   let s = "  foo \t bar  baz  "
+  ##   for ms in [-1, 1, 2, 3]:
+  ##     echo "------ maxsplit = ", ms, ":"
+  ##     for item in s.splitWhitespace(maxsplit=ms):
+  ##       echo '"', item, '"'
+  ##
+  ## ...results in:
+  ##
+  ## .. code-block::
+  ##   ------ maxsplit = -1:
+  ##   "foo"
+  ##   "bar"
+  ##   "baz"
+  ##   ------ maxsplit = 1:
+  ##   "foo"
+  ##   "bar  baz  "
+  ##   ------ maxsplit = 2:
+  ##   "foo"
+  ##   "bar"
+  ##   "baz  "
+  ##   ------ maxsplit = 3:
+  ##   "foo"
+  ##   "bar"
+  ##   "baz"
+  ##
+  ## See also:
+  ## * `splitLines iterator<#splitLines.i,string>`_
+  ## * `splitWhitespace proc<#splitWhitespace,string,int>`_
+  oldSplit(s, Whitespace, maxsplit)
+
 
-proc split*(s: string, seps: set[char] = Whitespace, maxsplit: int = -1): seq[string] {.
-  noSideEffect, rtl, extern: "nsuSplitCharSet".} =
-  ## The same as the `split iterator <#split.i,string,set[char],int>`_, but is a
-  ## proc that returns a sequence of substrings.
-  runnableExamples:
-    doAssert "a,b;c".split({',', ';'}) == @["a", "b", "c"]
-    doAssert "".split({' '}) == @[""]
-  accResult(split(s, seps, maxsplit))
 
 proc split*(s: string, sep: char, maxsplit: int = -1): seq[string] {.noSideEffect,
   rtl, extern: "nsuSplitChar".} =
-  ## The same as the `split iterator <#split.i,string,char,int>`_, but is a proc
-  ## that returns a sequence of substrings.
+  ## The same as the `split iterator <#split.i,string,char,int>`_ (see its
+  ## documentation), but is a proc that returns a sequence of substrings.
+  ##
+  ## See also:
+  ## * `split iterator <#split.i,string,char,int>`_
+  ## * `rsplit proc<#rsplit,string,char,int>`_
+  ## * `splitLines proc<#splitLines,string>`_
+  ## * `splitWhitespace proc<#splitWhitespace,string,int>`_
   runnableExamples:
     doAssert "a,b,c".split(',') == @["a", "b", "c"]
     doAssert "".split(' ') == @[""]
   accResult(split(s, sep, maxsplit))
 
+proc split*(s: string, seps: set[char] = Whitespace, maxsplit: int = -1): seq[string] {.
+  noSideEffect, rtl, extern: "nsuSplitCharSet".} =
+  ## The same as the `split iterator <#split.i,string,set[char],int>`_ (see its
+  ## documentation), but is a proc that returns a sequence of substrings.
+  ##
+  ## See also:
+  ## * `split iterator <#split.i,string,set[char],int>`_
+  ## * `rsplit proc<#rsplit,string,set[char],int>`_
+  ## * `splitLines proc<#splitLines,string>`_
+  ## * `splitWhitespace proc<#splitWhitespace,string,int>`_
+  runnableExamples:
+    doAssert "a,b;c".split({',', ';'}) == @["a", "b", "c"]
+    doAssert "".split({' '}) == @[""]
+  accResult(split(s, seps, maxsplit))
+
 proc split*(s: string, sep: string, maxsplit: int = -1): seq[string] {.noSideEffect,
   rtl, extern: "nsuSplitString".} =
   ## Splits the string `s` into substrings using a string separator.
   ##
   ## Substrings are separated by the string `sep`. This is a wrapper around the
   ## `split iterator <#split.i,string,string,int>`_.
+  ##
+  ## See also:
+  ## * `split iterator <#split.i,string,string,int>`_
+  ## * `rsplit proc<#rsplit,string,string,int>`_
+  ## * `splitLines proc<#splitLines,string>`_
+  ## * `splitWhitespace proc<#splitWhitespace,string,int>`_
   runnableExamples:
     doAssert "a,b,c".split(",") == @["a", "b", "c"]
     doAssert "a man a plan a canal panama".split("a ") == @["", "man ", "plan ", "canal panama"]
     doAssert "".split("Elon Musk") == @[""]
     doAssert "a  largely    spaced sentence".split(" ") == @["a", "", "largely", "", "", "", "spaced", "sentence"]
-
     doAssert "a  largely    spaced sentence".split(" ", maxsplit=1) == @["a", " largely    spaced sentence"]
   doAssert(sep.len > 0)
 
   accResult(split(s, sep, maxsplit))
 
-proc rsplit*(s: string, seps: set[char] = Whitespace,
-             maxsplit: int = -1): seq[string]
-             {.noSideEffect, rtl, extern: "nsuRSplitCharSet".} =
-  ## The same as the `rsplit iterator <#rsplit.i,string,set[char],int>`_, but is a
-  ## proc that returns a sequence of substrings.
+proc rsplit*(s: string, sep: char, maxsplit: int = -1): seq[string]
+             {.noSideEffect, rtl, extern: "nsuRSplitChar".} =
+  ## The same as the `rsplit iterator <#rsplit.i,string,char,int>`_, but is a proc
+  ## that returns a sequence of substrings.
   ##
   ## A possible common use case for `rsplit` is path manipulation,
   ## particularly on systems that don't use a common delimiter.
@@ -825,20 +781,26 @@ proc rsplit*(s: string, seps: set[char] = Whitespace,
   ## do the following to get the tail of the path:
   ##
   ## .. code-block:: nim
-  ##   var tailSplit = rsplit("Root#Object#Method#Index", {'#'}, maxsplit=1)
+  ##   var tailSplit = rsplit("Root#Object#Method#Index", '#', maxsplit=1)
   ##
   ## Results in `tailSplit` containing:
   ##
   ## .. code-block:: nim
   ##   @["Root#Object#Method", "Index"]
   ##
-  accResult(rsplit(s, seps, maxsplit))
+  ## See also:
+  ## * `rsplit iterator <#rsplit.i,string,char,int>`_
+  ## * `split proc<#split,string,char,int>`_
+  ## * `splitLines proc<#splitLines,string>`_
+  ## * `splitWhitespace proc<#splitWhitespace,string,int>`_
+  accResult(rsplit(s, sep, maxsplit))
   result.reverse()
 
-proc rsplit*(s: string, sep: char, maxsplit: int = -1): seq[string]
-             {.noSideEffect, rtl, extern: "nsuRSplitChar".} =
-  ## The same as the `rsplit iterator <#rsplit.i,string,char,int>`_, but is a proc
-  ## that returns a sequence of substrings.
+proc rsplit*(s: string, seps: set[char] = Whitespace,
+             maxsplit: int = -1): seq[string]
+             {.noSideEffect, rtl, extern: "nsuRSplitCharSet".} =
+  ## The same as the `rsplit iterator <#rsplit.i,string,set[char],int>`_, but is a
+  ## proc that returns a sequence of substrings.
   ##
   ## A possible common use case for `rsplit` is path manipulation,
   ## particularly on systems that don't use a common delimiter.
@@ -847,19 +809,24 @@ proc rsplit*(s: string, sep: char, maxsplit: int = -1): seq[string]
   ## do the following to get the tail of the path:
   ##
   ## .. code-block:: nim
-  ##   var tailSplit = rsplit("Root#Object#Method#Index", '#', maxsplit=1)
+  ##   var tailSplit = rsplit("Root#Object#Method#Index", {'#'}, maxsplit=1)
   ##
   ## Results in `tailSplit` containing:
   ##
   ## .. code-block:: nim
   ##   @["Root#Object#Method", "Index"]
   ##
-  accResult(rsplit(s, sep, maxsplit))
+  ## See also:
+  ## * `rsplit iterator <#rsplit.i,string,set[char],int>`_
+  ## * `split proc<#split,string,set[char],int>`_
+  ## * `splitLines proc<#splitLines,string>`_
+  ## * `splitWhitespace proc<#splitWhitespace,string,int>`_
+  accResult(rsplit(s, seps, maxsplit))
   result.reverse()
 
 proc rsplit*(s: string, sep: string, maxsplit: int = -1): seq[string]
              {.noSideEffect, rtl, extern: "nsuRSplitString".} =
-  ## The same as the `rsplit iterator <#rsplit.i,string,string,int>`_, but is a proc
+  ## The same as the `rsplit iterator <#rsplit.i,string,string,int,bool>`_, but is a proc
   ## that returns a sequence of substrings.
   ##
   ## A possible common use case for `rsplit` is path manipulation,
@@ -876,9 +843,13 @@ proc rsplit*(s: string, sep: string, maxsplit: int = -1): seq[string]
   ## .. code-block:: nim
   ##   @["Root#Object#Method", "Index"]
   ##
+  ## See also:
+  ## * `rsplit iterator <#rsplit.i,string,string,int,bool>`_
+  ## * `split proc<#split,string,string,int>`_
+  ## * `splitLines proc<#splitLines,string>`_
+  ## * `splitWhitespace proc<#splitWhitespace,string,int>`_
   runnableExamples:
     doAssert "a  largely    spaced sentence".rsplit(" ", maxsplit=1) == @["a  largely    spaced", "sentence"]
-
     doAssert "a,b,c".rsplit(",") == @["a", "b", "c"]
     doAssert "a man a plan a canal panama".rsplit("a ") == @["", "man ", "plan ", "canal panama"]
     doAssert "".rsplit("Elon Musk") == @[""]
@@ -886,6 +857,75 @@ proc rsplit*(s: string, sep: string, maxsplit: int = -1): seq[string]
   accResult(rsplit(s, sep, maxsplit))
   result.reverse()
 
+proc splitLines*(s: string, keepEol = false): seq[string] {.noSideEffect,
+  rtl, extern: "nsuSplitLines".} =
+  ## The same as the `splitLines iterator<#splitLines.i,string>`_ (see its
+  ## documentation), but is a proc that returns a sequence of substrings.
+  ##
+  ## See also:
+  ## * `splitLines iterator<#splitLines.i,string>`_
+  ## * `splitWhitespace proc<#splitWhitespace,string,int>`_
+  ## * `countLines proc<#countLines,string>`_
+  accResult(splitLines(s, keepEol=keepEol))
+
+proc splitWhitespace*(s: string, maxsplit: int = -1): seq[string] {.noSideEffect,
+  rtl, extern: "nsuSplitWhitespace".} =
+  ## The same as the `splitWhitespace iterator <#splitWhitespace.i,string,int>`_
+  ## (see its documentation), but is a proc that returns a sequence of substrings.
+  ##
+  ## See also:
+  ## * `splitWhitespace iterator <#splitWhitespace.i,string,int>`_
+  ## * `splitLines proc<#splitLines,string>`_
+  accResult(splitWhitespace(s, maxsplit))
+
+proc toBin*(x: BiggestInt, len: Positive): string {.noSideEffect,
+  rtl, extern: "nsuToBin".} =
+  ## Converts `x` into its binary representation.
+  ##
+  ## The resulting string is always `len` characters long. No leading ``0b``
+  ## prefix is generated.
+  runnableExamples:
+    let
+      a = 29
+      b = 257
+    doAssert a.toBin(8) == "00011101"
+    doAssert b.toBin(8) == "00000001"
+    doAssert b.toBin(9) == "100000001"
+  var
+    mask: BiggestInt = 1
+    shift: BiggestInt = 0
+  assert(len > 0)
+  result = newString(len)
+  for j in countdown(len-1, 0):
+    result[j] = chr(int((x and mask) shr shift) + ord('0'))
+    shift = shift + 1
+    mask = mask shl 1
+
+proc toOct*(x: BiggestInt, len: Positive): string {.noSideEffect,
+  rtl, extern: "nsuToOct".} =
+  ## Converts `x` into its octal representation.
+  ##
+  ## The resulting string is always `len` characters long. No leading ``0o``
+  ## prefix is generated.
+  ##
+  ## Do not confuse it with `toOctal proc<#toOctal,char>`_.
+  runnableExamples:
+    let
+      a = 62
+      b = 513
+    doAssert a.toOct(3) == "076"
+    doAssert b.toOct(3) == "001"
+    doAssert b.toOct(5) == "01001"
+  var
+    mask: BiggestInt = 7
+    shift: BiggestInt = 0
+  assert(len > 0)
+  result = newString(len)
+  for j in countdown(len-1, 0):
+    result[j] = chr(int((x and mask) shr shift) + ord('0'))
+    shift = shift + 3
+    mask = mask shl 3
+
 proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect,
   rtl, extern: "nsuToHex".} =
   ## Converts `x` to its hexadecimal representation.
@@ -893,8 +933,12 @@ proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect,
   ## The resulting string will be exactly `len` characters long. No prefix like
   ## ``0x`` is generated. `x` is treated as an unsigned value.
   runnableExamples:
-    doAssert toHex(1984, 6) == "0007C0"
-    doAssert toHex(1984, 2) == "C0"
+    let
+      a = 62
+      b = 4097
+    doAssert a.toHex(3) == "03E"
+    doAssert b.toHex(3) == "001"
+    doAssert b.toHex(4) == "1001"
   const
     HexChars = "0123456789ABCDEF"
   var
@@ -917,6 +961,18 @@ proc toHex*(s: string): string {.noSideEffect, rtl.} =
   ##
   ## The output is twice the input long. No prefix like
   ## ``0x`` is generated.
+  ##
+  ## See also:
+  ## * `parseHexStr proc<#parseHexStr,string>`_ for the reverse operation
+  runnableExamples:
+    let
+      a = "1"
+      b = "A"
+      c = "\0\255"
+    doAssert a.toHex() == "31"
+    doAssert b.toHex() == "41"
+    doAssert c.toHex() == "00FF"
+
   const HexChars = "0123456789ABCDEF"
   result = newString(s.len * 2)
   for pos, c in s:
@@ -925,6 +981,25 @@ proc toHex*(s: string): string {.noSideEffect, rtl.} =
     n = n shr 4
     result[pos * 2] = HexChars[n]
 
+proc toOctal*(c: char): string {.noSideEffect, rtl, extern: "nsuToOctal".} =
+  ## Converts a character `c` to its octal representation.
+  ##
+  ## The resulting string may not have a leading zero. Its length is always
+  ## exactly 3.
+  ##
+  ## Do not confuse it with `toOct proc<#toOct,BiggestInt,Positive>`_.
+  runnableExamples:
+    doAssert toOctal('1') == "061"
+    doAssert toOctal('A') == "101"
+    doAssert toOctal('a') == "141"
+    doAssert toOctal('!') == "041"
+
+  result = newString(3)
+  var val = ord(c)
+  for i in countdown(2, 0):
+    result[i] = chr(val mod 8 + ord('0'))
+    val = val div 8
+
 proc intToStr*(x: int, minchars: Positive = 1): string {.noSideEffect,
   rtl, extern: "nsuIntToStr".} =
   ## Converts `x` to its decimal representation.
@@ -980,9 +1055,10 @@ proc parseBiggestUInt*(s: string): BiggestUInt {.noSideEffect, procvar,
 
 proc parseFloat*(s: string): float {.noSideEffect, procvar,
   rtl, extern: "nsuParseFloat".} =
-  ## Parses a decimal floating point value contained in `s`. If `s` is not
-  ## a valid floating point number, `ValueError` is raised. ``NAN``,
-  ## ``INF``, ``-INF`` are also supported (case insensitive comparison).
+  ## Parses a decimal floating point value contained in `s`.
+  ##
+  ## If `s` is not a valid floating point number, `ValueError` is raised.
+  ##``NAN``, ``INF``, ``-INF`` are also supported (case insensitive comparison).
   runnableExamples:
     doAssert parseFloat("3.14") == 3.14
     doAssert parseFloat("inf") == 1.0/0
@@ -997,6 +1073,13 @@ proc parseBinInt*(s: string): int {.noSideEffect, procvar,
   ## If `s` is not a valid binary integer, `ValueError` is raised. `s` can have
   ## one of the following optional prefixes: ``0b``, ``0B``. Underscores within
   ## `s` are ignored.
+  runnableExamples:
+    let
+      a = "0b11_0101"
+      b = "111"
+    doAssert a.parseBinInt() == 53
+    doAssert b.parseBinInt() == 7
+
   let L = parseutils.parseBin(s, result, 0)
   if L != s.len or L == 0:
     raise newException(ValueError, "invalid binary integer: " & s)
@@ -1042,11 +1125,20 @@ proc parseHexStr*(s: string): string {.noSideEffect, procvar,
   rtl, extern: "nsuParseHexStr".} =
   ## Convert hex-encoded string to byte string, e.g.:
   ##
-  ## .. code-block:: nim
-  ##    hexToStr("00ff") == "\0\255"
-  ##
   ## Raises ``ValueError`` for an invalid hex values. The comparison is
   ## case-insensitive.
+  ##
+  ## See also:
+  ## * `toHex proc<#toHex,string>`_ for the reverse operation
+  runnableExamples:
+    let
+      a = "41"
+      b = "3161"
+      c = "00ff"
+    doAssert parseHexStr(a) == "A"
+    doAssert parseHexStr(b) == "1a"
+    doAssert parseHexStr(c) == "\0\255"
+
   if s.len mod 2 != 0:
     raise newException(ValueError, "Incorrect hex string len")
   result = newString(s.len div 2)
@@ -1067,6 +1159,10 @@ proc parseBool*(s: string): bool =
   ## returns `true`. If ``s`` is one of the following values: ``n, no, false,
   ## 0, off``, then returns `false`.  If ``s`` is something else a
   ## ``ValueError`` exception is raised.
+  runnableExamples:
+    let a = "n"
+    doAssert parseBool(a) == false
+
   case normalize(s)
   of "y", "yes", "true", "1", "on": result = true
   of "n", "no", "false", "0", "off": result = false
@@ -1095,39 +1191,41 @@ proc parseEnum*[T: enum](s: string, default: T): T =
 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:
-  ##
-  ## .. code-block:: nim
-  ##   proc tabexpand(indent: int, text: string, tabsize: int = 4) =
-  ##     echo '\t'.repeat(indent div tabsize), ' '.repeat(indent mod tabsize),
-  ##         text
-  ##
-  ##   tabexpand(4, "At four")
-  ##   tabexpand(5, "At five")
-  ##   tabexpand(6, "At six")
+  ## the character `c`.
+  runnableExamples:
+    let a = 'z'
+    doAssert a.repeat(5) == "zzzzz"
   result = newString(count)
   for i in 0..count-1: result[i] = c
 
 proc repeat*(s: string, n: Natural): string {.noSideEffect,
   rtl, extern: "nsuRepeatStr".} =
-  ## Returns String `s` concatenated `n` times.  Example:
-  ##
-  ## .. code-block:: nim
-  ##   echo "+++ STOP ".repeat(4), "+++"
+  ## Returns string `s` concatenated `n` times.
+  runnableExamples:
+    doAssert "+ foo +".repeat(3) == "+ foo ++ foo ++ foo +"
+
   result = newStringOfCap(n * s.len)
   for i in 1..n: result.add(s)
 
-template spaces*(n: Natural): string = repeat(' ', n)
-  ## Returns a String with `n` space characters. You can use this proc
-  ## to left align strings. Example:
+proc spaces*(n: Natural): string {.inline.} =
+  ## Returns a string with `n` space characters. You can use this proc
+  ## to left align strings.
   ##
-  ## .. code-block:: nim
-  ##   let
-  ##     width = 15
-  ##     text1 = "Hello user!"
-  ##     text2 = "This is a very long string"
-  ##   echo text1 & spaces(max(0, width - text1.len)) & "|"
-  ##   echo text2 & spaces(max(0, width - text2.len)) & "|"
+  ## See also:
+  ## * `align proc<#align,string,Natural,Char>`_
+  ## * `alignLeft proc<#alignLeft,string,Natural,Char>`_
+  ## * `indent proc<#indent,string,Natural,string>`_
+  ## * `center proc<#center,string,int,char>`_
+  runnableExamples:
+    let
+      width = 15
+      text1 = "Hello user!"
+      text2 = "This is a very long string"
+    doAssert text1 & spaces(max(0, width - text1.len)) & "|" ==
+             "Hello user!    |"
+    doAssert text2 & spaces(max(0, width - text2.len)) & "|" ==
+             "This is a very long string|"
+  repeat(' ', n)
 
 proc align*(s: string, count: Natural, padding = ' '): string {.
   noSideEffect, rtl, extern: "nsuAlignString".} =
@@ -1136,13 +1234,18 @@ proc align*(s: string, count: Natural, padding = ' '): string {.
   ## `padding` characters (by default spaces) are added before `s` resulting in
   ## right alignment. If ``s.len >= count``, no spaces are added and `s` is
   ## returned unchanged. If you need to left align a string use the `alignLeft
-  ## proc <#alignLeft>`_. Example:
+  ## proc <#alignLeft,string,Natural,Char>`_.
   ##
-  ## .. code-block:: nim
-  ##   assert align("abc", 4) == " abc"
-  ##   assert align("a", 0) == "a"
-  ##   assert align("1232", 6) == "  1232"
-  ##   assert align("1232", 6, '#') == "##1232"
+  ## See also:
+  ## * `alignLeft proc<#alignLeft,string,Natural,Char>`_
+  ## * `spaces proc<#spaces,Natural>`_
+  ## * `indent proc<#indent,string,Natural,string>`_
+  ## * `center proc<#center,string,int,char>`_
+  runnableExamples:
+    assert align("abc", 4) == " abc"
+    assert align("a", 0) == "a"
+    assert align("1232", 6) == "  1232"
+    assert align("1232", 6, '#') == "##1232"
   if s.len < count:
     result = newString(count)
     let spaces = count - s.len
@@ -1157,13 +1260,18 @@ proc alignLeft*(s: string, count: Natural, padding = ' '): string {.noSideEffect
   ## `padding` characters (by default spaces) are added after `s` resulting in
   ## left alignment. If ``s.len >= count``, no spaces are added and `s` is
   ## returned unchanged. If you need to right align a string use the `align
-  ## proc <#align>`_. Example:
+  ## proc <#align,string,Natural,Char>`_.
   ##
-  ## .. code-block:: nim
-  ##   assert alignLeft("abc", 4) == "abc "
-  ##   assert alignLeft("a", 0) == "a"
-  ##   assert alignLeft("1232", 6) == "1232  "
-  ##   assert alignLeft("1232", 6, '#') == "1232##"
+  ## See also:
+  ## * `align proc<#align,string,Natural,Char>`_
+  ## * `spaces proc<#spaces,Natural>`_
+  ## * `indent proc<#indent,string,Natural,string>`_
+  ## * `center proc<#center,string,int,char>`_
+  runnableExamples:
+    assert alignLeft("abc", 4) == "abc "
+    assert alignLeft("a", 0) == "a"
+    assert alignLeft("1232", 6) == "1232  "
+    assert alignLeft("1232", 6, '#') == "1232##"
   if s.len < count:
     result = newString(count)
     if s.len > 0:
@@ -1173,83 +1281,55 @@ proc alignLeft*(s: string, count: Natural, padding = ' '): string {.noSideEffect
   else:
     result = s
 
-iterator tokenize*(s: string, seps: set[char] = Whitespace): tuple[
-  token: string, isSep: bool] =
-  ## Tokenizes the string `s` into substrings.
-  ##
-  ## Substrings are separated by a substring containing only `seps`.
-  ## Examples:
-  ##
-  ## .. code-block:: nim
-  ##   for word in tokenize("  this is an  example  "):
-  ##     writeLine(stdout, word)
+proc center*(s: string, width: int, fillChar: char = ' '): string {.
+  noSideEffect, rtl, extern: "nsuCenterString".} =
+  ## Return the contents of `s` centered in a string `width` long using
+  ## `fillChar` (default: space) as padding.
   ##
-  ## Results in:
+  ## The original string is returned if `width` is less than or equal
+  ## to `s.len`.
   ##
-  ## .. code-block:: nim
-  ##   ("  ", true)
-  ##   ("this", false)
-  ##   (" ", true)
-  ##   ("is", false)
-  ##   (" ", true)
-  ##   ("an", false)
-  ##   ("  ", true)
-  ##   ("example", false)
-  ##   ("  ", true)
-  var i = 0
-  while true:
-    var j = i
-    var isSep = j < s.len and s[j] in seps
-    while j < s.len and (s[j] in seps) == isSep: inc(j)
-    if j > i:
-      yield (substr(s, i, j-1), isSep)
-    else:
-      break
-    i = j
-
-proc wordWrap*(s: string, maxLineWidth = 80,
-               splitLongWords = true,
-               seps: set[char] = Whitespace,
-               newLine = "\n"): string {.
-               noSideEffect, rtl, extern: "nsuWordWrap",
-               deprecated: "use wrapWords in std/wordwrap instead".} =
-  ## Word wraps `s`.
-  result = newStringOfCap(s.len + s.len shr 6)
-  var spaceLeft = maxLineWidth
-  var lastSep = ""
-  for word, isSep in tokenize(s, seps):
-    if isSep:
-      lastSep = word
-      spaceLeft = spaceLeft - len(word)
-      continue
-    if len(word) > spaceLeft:
-      if splitLongWords and len(word) > maxLineWidth:
-        result.add(substr(word, 0, spaceLeft-1))
-        var w = spaceLeft
-        var wordLeft = len(word) - spaceLeft
-        while wordLeft > 0:
-          result.add(newLine)
-          var L = min(maxLineWidth, wordLeft)
-          spaceLeft = maxLineWidth - L
-          result.add(substr(word, w, w+L-1))
-          inc(w, L)
-          dec(wordLeft, L)
-      else:
-        spaceLeft = maxLineWidth - len(word)
-        result.add(newLine)
-        result.add(word)
+  ## See also:
+  ## * `align proc<#align,string,Natural,Char>`_
+  ## * `alignLeft proc<#alignLeft,string,Natural,Char>`_
+  ## * `spaces proc<#spaces,Natural>`_
+  ## * `indent proc<#indent,string,Natural,string>`_
+  runnableExamples:
+    let a = "foo"
+    doAssert a.center(2) == "foo"
+    doAssert a.center(5) == " foo "
+    doAssert a.center(6) == " foo  "
+  if width <= s.len: return s
+  result = newString(width)
+  # Left padding will be one fillChar
+  # smaller if there are an odd number
+  # of characters
+  let
+    charsLeft = (width - s.len)
+    leftPadding = charsLeft div 2
+  for i in 0 ..< width:
+    if i >= leftPadding and i < leftPadding + s.len:
+      # we are where the string should be located
+      result[i] = s[i-leftPadding]
     else:
-      spaceLeft = spaceLeft - len(word)
-      result.add(lastSep & word)
-      lastSep.setLen(0)
+      # we are either before or after where
+      # the string s should go
+      result[i] = fillChar
 
 proc indent*(s: string, count: Natural, padding: string = " "): string
     {.noSideEffect, rtl, extern: "nsuIndent".} =
   ## Indents each line in ``s`` by ``count`` amount of ``padding``.
   ##
   ## **Note:** This does not preserve the new line characters used in ``s``.
+  ##
+  ## See also:
+  ## * `align proc<#align,string,Natural,Char>`_
+  ## * `alignLeft proc<#alignLeft,string,Natural,Char>`_
+  ## * `spaces proc<#spaces,Natural>`_
+  ## * `unindent proc<#unindent,string,Natural,string>`_
   runnableExamples:
-    doAssert indent("First line\c\l and second line.", 2) == "  First line\l   and second line."
+    doAssert indent("First line\c\l and second line.", 2) ==
+             "  First line\l   and second line."
   result = ""
   var i = 0
   for line in s.splitLines():
@@ -1266,8 +1346,15 @@ proc unindent*(s: string, count: Natural, padding: string = " "): string
   ## Sometimes called `dedent`:idx:
   ##
   ## **Note:** This does not preserve the new line characters used in ``s``.
+  ##
+  ## See also:
+  ## * `align proc<#align,string,Natural,Char>`_
+  ## * `alignLeft proc<#alignLeft,string,Natural,Char>`_
+  ## * `spaces proc<#spaces,Natural>`_
+  ## * `indent proc<#indent,string,Natural,string>`_
   runnableExamples:
-    doAssert unindent("  First line\l   and second line", 3) == "First line\land second line"
+    doAssert unindent("  First line\l   and second line", 3) ==
+             "First line\land second line"
   result = ""
   var i = 0
   for line in s.splitLines():
@@ -1286,37 +1373,105 @@ proc unindent*(s: string): string
     {.noSideEffect, rtl, extern: "nsuUnindentAll".} =
   ## Removes all indentation composed of whitespace from each line in ``s``.
   ##
-  ## For example:
+  ## See also:
+  ## * `align proc<#align,string,Natural,Char>`_
+  ## * `alignLeft proc<#alignLeft,string,Natural,Char>`_
+  ## * `spaces proc<#spaces,Natural>`_
+  ## * `indent proc<#indent,string,Natural,string>`_
+  runnableExamples:
+    let x = """
+      Hello
+      There
+    """.unindent()
+
+    doAssert x == "Hello\nThere\n"
+  unindent(s, 1000) # TODO: Passing a 1000 is a bit hackish.
+
+proc delete*(s: var string, first, last: int) {.noSideEffect,
+  rtl, extern: "nsuDelete".} =
+  ## Deletes in `s` (must be declared as ``var``) the characters at positions
+  ## ``first ..last`` (both ends included).
   ##
-  ## .. code-block:: nim
-  ##   const x = """
-  ##     Hello
-  ##     There
-  ##   """.unindent()
+  ## This modifies `s` itself, it does not return a copy.
+  runnableExamples:
+    var a = "abracadabra"
+
+    a.delete(4, 5)
+    doAssert a == "abradabra"
+
+    a.delete(1, 6)
+    doAssert a == "ara"
+
+  var i = first
+  var j = last+1
+  var newLen = len(s)-j+i
+  while i < newLen:
+    s[i] = s[j]
+    inc(i)
+    inc(j)
+  setLen(s, newLen)
+
+
+proc startsWith*(s: string, prefix: char): bool {.noSideEffect, inline.} =
+  ## Returns true if ``s`` starts with character ``prefix``.
   ##
-  ##   doAssert x == "Hello\nThere\n"
-  unindent(s, 1000) # TODO: Passing a 1000 is a bit hackish.
+  ## See also:
+  ## * `endsWith proc<#endsWith,string,char>`_
+  ## * `continuesWith proc<#continuesWith,string,string,Natural>`_
+  ## * `removePrefix proc<#removePrefix,string,char>`_
+  runnableExamples:
+    let a = "abracadabra"
+    doAssert a.startsWith('a') == true
+    doAssert a.startsWith('b') == false
+  result = s.len > 0 and s[0] == prefix
 
 proc startsWith*(s, prefix: string): bool {.noSideEffect,
   rtl, extern: "nsuStartsWith".} =
-  ## Returns true iff ``s`` starts with ``prefix``.
+  ## Returns true if ``s`` starts with string ``prefix``.
   ##
   ## If ``prefix == ""`` true is returned.
+  ##
+  ## See also:
+  ## * `endsWith proc<#endsWith,string,string>`_
+  ## * `continuesWith proc<#continuesWith,string,string,Natural>`_
+  ## * `removePrefix proc<#removePrefix,string,string>`_
+  runnableExamples:
+    let a = "abracadabra"
+    doAssert a.startsWith("abra") == true
+    doAssert a.startsWith("bra") == false
   var i = 0
   while true:
     if i >= prefix.len: return true
     if i >= s.len or s[i] != prefix[i]: return false
     inc(i)
 
-proc startsWith*(s: string, prefix: char): bool {.noSideEffect, inline.} =
-  ## Returns true iff ``s`` starts with ``prefix``.
-  result = s.len > 0 and s[0] == prefix
+proc endsWith*(s: string, suffix: char): bool {.noSideEffect, inline.} =
+  ## Returns true if ``s`` ends with ``suffix``.
+  ##
+  ## See also:
+  ## * `startsWith proc<#startsWith,string,char>`_
+  ## * `continuesWith proc<#continuesWith,string,string,Natural>`_
+  ## * `removeSuffix proc<#removeSuffix,string,char>`_
+  runnableExamples:
+    let a = "abracadabra"
+    doAssert a.endsWith('a') == true
+    doAssert a.endsWith('b') == false
+  result = s.len > 0 and s[s.high] == suffix
 
 proc endsWith*(s, suffix: string): bool {.noSideEffect,
   rtl, extern: "nsuEndsWith".} =
-  ## Returns true iff ``s`` ends with ``suffix``.
+  ## Returns true if ``s`` ends with ``suffix``.
   ##
   ## If ``suffix == ""`` true is returned.
+  ##
+  ## See also:
+  ## * `startsWith proc<#startsWith,string,string>`_
+  ## * `continuesWith proc<#continuesWith,string,string,Natural>`_
+  ## * `removeSuffix proc<#removeSuffix,string,string>`_
+  runnableExamples:
+    let a = "abracadabra"
+    doAssert a.endsWith("abra") == true
+    doAssert a.endsWith("dab") == false
   var i = 0
   var j = len(s) - len(suffix)
   while i+j <% s.len:
@@ -1324,21 +1479,136 @@ proc endsWith*(s, suffix: string): bool {.noSideEffect,
     inc(i)
   if i >= suffix.len: return true
 
-proc endsWith*(s: string, suffix: char): bool {.noSideEffect, inline.} =
-  ## Returns true iff ``s`` ends with ``suffix``.
-  result = s.len > 0 and s[s.high] == suffix
-
 proc continuesWith*(s, substr: string, start: Natural): bool {.noSideEffect,
   rtl, extern: "nsuContinuesWith".} =
-  ## Returns true iff ``s`` continues with ``substr`` at position ``start``.
+  ## Returns true if ``s`` continues with ``substr`` at position ``start``.
   ##
   ## If ``substr == ""`` true is returned.
+  ##
+  ## See also:
+  ## * `startsWith proc<#startsWith,string,string>`_
+  ## * `endsWith proc<#endsWith,string,string>`_
+  runnableExamples:
+    let a = "abracadabra"
+    doAssert a.continuesWith("ca", 4) == true
+    doAssert a.continuesWith("ca", 5) == false
+    doAssert a.continuesWith("dab", 6) == true
   var i = 0
   while true:
     if i >= substr.len: return true
     if i+start >= s.len or s[i+start] != substr[i]: return false
     inc(i)
 
+
+proc removePrefix*(s: var string, chars: set[char] = Newlines) {.
+  rtl, extern: "nsuRemovePrefixCharSet".} =
+  ## Removes all characters from `chars` from the start of the string `s`
+  ## (in-place).
+  ##
+  ## See also:
+  ## * `removeSuffix proc<#removeSuffix,string,set[char]>`_
+  runnableExamples:
+     var userInput = "\r\n*~Hello World!"
+     userInput.removePrefix
+     doAssert userInput == "*~Hello World!"
+     userInput.removePrefix({'~', '*'})
+     doAssert userInput == "Hello World!"
+
+     var otherInput = "?!?Hello!?!"
+     otherInput.removePrefix({'!', '?'})
+     doAssert otherInput == "Hello!?!"
+
+  var start = 0
+  while start < s.len and s[start] in chars: start += 1
+  if start > 0: s.delete(0, start - 1)
+
+proc removePrefix*(s: var string, c: char) {.
+  rtl, extern: "nsuRemovePrefixChar".} =
+  ## Removes all occurrences of a single character (in-place) from the start
+  ## of a string.
+  ##
+  ## See also:
+  ## * `removeSuffix proc<#removeSuffix,string,char>`_
+  ## * `startsWith proc<#startsWith,string,char>`_
+  runnableExamples:
+    var ident = "pControl"
+    ident.removePrefix('p')
+    doAssert ident == "Control"
+  removePrefix(s, chars = {c})
+
+proc removePrefix*(s: var string, prefix: string) {.
+  rtl, extern: "nsuRemovePrefixString".} =
+  ## Remove the first matching prefix (in-place) from a string.
+  ##
+  ## See also:
+  ## * `removeSuffix proc<#removeSuffix,string,string>`_
+  ## * `startsWith proc<#startsWith,string,string>`_
+  runnableExamples:
+     var answers = "yesyes"
+     answers.removePrefix("yes")
+     doAssert answers == "yes"
+  if s.startsWith(prefix):
+    s.delete(0, prefix.len - 1)
+
+proc removeSuffix*(s: var string, chars: set[char] = Newlines) {.
+  rtl, extern: "nsuRemoveSuffixCharSet".} =
+  ## Removes all characters from `chars` from the end of the string `s`
+  ## (in-place).
+  ##
+  ## See also:
+  ## * `removePrefix proc<#removePrefix,string,set[char]>`_
+  runnableExamples:
+     var userInput = "Hello World!*~\r\n"
+     userInput.removeSuffix
+     doAssert userInput == "Hello World!*~"
+     userInput.removeSuffix({'~', '*'})
+     doAssert userInput == "Hello World!"
+
+     var otherInput = "Hello!?!"
+     otherInput.removeSuffix({'!', '?'})
+     doAssert otherInput == "Hello"
+
+  if s.len == 0: return
+  var last = s.high
+  while last > -1 and s[last] in chars: last -= 1
+  s.setLen(last + 1)
+
+proc removeSuffix*(s: var string, c: char) {.
+  rtl, extern: "nsuRemoveSuffixChar".} =
+  ## Removes all occurrences of a single character (in-place) from the end
+  ## of a string.
+  ##
+  ## See also:
+  ## * `removePrefix proc<#removePrefix,string,char>`_
+  ## * `endsWith proc<#endsWith,string,char>`_
+  runnableExamples:
+    var table = "users"
+    table.removeSuffix('s')
+    doAssert table == "user"
+
+    var dots = "Trailing dots......."
+    dots.removeSuffix('.')
+    doAssert dots == "Trailing dots"
+
+  removeSuffix(s, chars = {c})
+
+proc removeSuffix*(s: var string, suffix: string) {.
+  rtl, extern: "nsuRemoveSuffixString".} =
+  ## Remove the first matching suffix (in-place) from a string.
+  ##
+  ## See also:
+  ## * `removePrefix proc<#removePrefix,string,string>`_
+  ## * `endsWith proc<#endsWith,string,string>`_
+  runnableExamples:
+    var answers = "yeses"
+    answers.removeSuffix("es")
+    doAssert answers == "yes"
+  var newLen = s.len
+  if s.endsWith(suffix):
+    newLen -= len(suffix)
+    s.setLen(newLen)
+
+
 proc addSep*(dest: var string, sep = ", ", startLen: Natural = 0)
   {.noSideEffect, inline.} =
   ## Adds a separator to `dest` only if its length is bigger than `startLen`.
@@ -1353,24 +1623,28 @@ proc addSep*(dest: var string, sep = ", ", startLen: Natural = 0)
   ## `startLen`. The following example creates a string describing
   ## an array of integers.
   runnableExamples:
-     var arr = "["
-     for x in items([2, 3, 5, 7, 11]):
-       addSep(arr, startLen=len("["))
-       add(arr, $x)
-     add(arr, "]")
+    var arr = "["
+    for x in items([2, 3, 5, 7, 11]):
+      addSep(arr, startLen=len("["))
+      add(arr, $x)
+    add(arr, "]")
+    doAssert arr == "[2, 3, 5, 7, 11]"
+
   if dest.len > startLen: add(dest, sep)
 
 proc allCharsInSet*(s: string, theSet: set[char]): bool =
-  ## Returns true iff each character of `s` is in the set `theSet`.
+  ## Returns true if every character of `s` is in the set `theSet`.
   runnableExamples:
     doAssert allCharsInSet("aeea", {'a', 'e'}) == true
     doAssert allCharsInSet("", {'a', 'e'}) == true
+
   for c in items(s):
     if c notin theSet: return false
   return true
 
 proc abbrev*(s: string, possibilities: openArray[string]): int =
-  ## Returns the index of the first item in ``possibilities`` which starts with ``s``, if not ambiguous.
+  ## Returns the index of the first item in ``possibilities`` which starts
+  ## with ``s``, if not ambiguous.
   ##
   ## Returns -1 if no item has been found and -2 if multiple items match.
   runnableExamples:
@@ -1378,6 +1652,7 @@ proc abbrev*(s: string, possibilities: openArray[string]): int =
     doAssert abbrev("foo", ["college", "faculty", "industry"]) == -1 # Not found
     doAssert abbrev("fac", ["college", "faculty", "faculties"]) == -2 # Ambiguous
     doAssert abbrev("college", ["college", "colleges", "industry"]) == 0
+
   result = -1 # none found
   for i in 0..possibilities.len-1:
     if possibilities[i].startsWith(s):
@@ -1391,9 +1666,10 @@ proc abbrev*(s: string, possibilities: openArray[string]): int =
 
 proc join*(a: openArray[string], sep: string = ""): string {.
   noSideEffect, rtl, extern: "nsuJoinSep".} =
-  ## Concatenates all strings in `a` separating them with `sep`.
+  ## Concatenates all strings in the container `a`, separating them with `sep`.
   runnableExamples:
     doAssert join(["A", "B", "Conclusion"], " -> ") == "A -> B -> Conclusion"
+
   if len(a) > 0:
     var L = sep.len * (a.len-1)
     for i in 0..high(a): inc(L, a[i].len)
@@ -1407,10 +1683,11 @@ proc join*(a: openArray[string], sep: string = ""): string {.
 
 proc join*[T: not string](a: openArray[T], sep: string = ""): string {.
   noSideEffect, rtl.} =
-  ## Converts all elements in `a` to strings using `$` and concatenates them
-  ## with `sep`.
+  ## Converts all elements in the container `a` to strings using `$`,
+  ## and concatenates them with `sep`.
   runnableExamples:
     doAssert join([1, 2, 3], " -> ") == "1 -> 2 -> 3"
+
   result = ""
   for i, x in a:
     if i > 0:
@@ -1441,14 +1718,13 @@ proc initSkipTable*(a: var SkipTable, sub: string)
 
 proc find*(a: SkipTable, s, sub: string, start: Natural = 0, last = 0): int
   {.noSideEffect, rtl, extern: "nsuFindStrA".} =
-  ## Searches for `sub` in `s` inside range `start`..`last` using preprocessed table `a`.
-  ## If `last` is unspecified, it defaults to `s.high`.
+  ## Searches for `sub` in `s` inside range `start`..`last` using preprocessed
+  ## table `a`. If `last` is unspecified, it defaults to `s.high` (the last
+  ## element).
   ##
   ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
-
   let
     last = if last==0: s.high else: last
-    sLen = last - start + 1
     subLast = sub.len - 1
 
   if subLast == -1:
@@ -1467,7 +1743,6 @@ proc find*(a: SkipTable, s, sub: string, start: Natural = 0, last = 0): int
         return skip
       dec i
     inc skip, a[s[skip + subLast]]
-
   return -1
 
 when not (defined(js) or defined(nimdoc) or defined(nimscript)):
@@ -1479,10 +1754,14 @@ else:
 
 proc find*(s: string, sub: char, start: Natural = 0, last = 0): int {.noSideEffect,
   rtl, extern: "nsuFindChar".} =
-  ## Searches for `sub` in `s` inside range `start`..`last`.
-  ## If `last` is unspecified, it defaults to `s.high`.
+  ## Searches for `sub` in `s` inside range ``start..last`` (both ends included).
+  ## If `last` is unspecified, it defaults to `s.high` (the last element).
   ##
   ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
+  ##
+  ## See also:
+  ## * `rfind proc<#rfind,string,char,int>`_
+  ## * `replace proc<#replace,string,char,char>`_
   let last = if last==0: s.high else: last
   when nimvm:
     for i in int(start)..last:
@@ -1499,34 +1778,72 @@ proc find*(s: string, sub: char, start: Natural = 0, last = 0): int {.noSideEffe
         if sub == s[i]: return i
   return -1
 
+proc find*(s: string, chars: set[char], start: Natural = 0, last = 0): int {.noSideEffect,
+  rtl, extern: "nsuFindCharSet".} =
+  ## Searches for `chars` in `s` inside range ``start..last`` (both ends included).
+  ## If `last` is unspecified, it defaults to `s.high` (the last element).
+  ##
+  ## If `s` contains none of the characters in `chars`, -1 is returned.
+  ##
+  ## See also:
+  ## * `rfind proc<#rfind,string,set[char],int>`_
+  ## * `multiReplace proc<#multiReplace,string,varargs[]>`_
+  let last = if last==0: s.high else: last
+  for i in int(start)..last:
+    if s[i] in chars: return i
+  return -1
+
 proc find*(s, sub: string, start: Natural = 0, last = 0): int {.noSideEffect,
   rtl, extern: "nsuFindStr".} =
-  ## Searches for `sub` in `s` inside range `start`..`last`.
-  ## If `last` is unspecified, it defaults to `s.high`.
+  ## Searches for `sub` in `s` inside range ``start..last`` (both ends included).
+  ## If `last` is unspecified, it defaults to `s.high` (the last element).
   ##
   ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
+  ##
+  ## See also:
+  ## * `rfind proc<#rfind,string,string,int>`_
+  ## * `replace proc<#replace,string,string,string>`_
   if sub.len > s.len: return -1
   if sub.len == 1: return find(s, sub[0], start, last)
   var a {.noinit.}: SkipTable
   initSkipTable(a, sub)
   result = find(a, s, sub, start, last)
 
-proc find*(s: string, chars: set[char], start: Natural = 0, last = 0): int {.noSideEffect,
-  rtl, extern: "nsuFindCharSet".} =
-  ## Searches for `chars` in `s` inside range `start`..`last`.
-  ## If `last` is unspecified, it defaults to `s.high`.
+proc rfind*(s: string, sub: char, start: int = -1): int {.noSideEffect,
+  rtl.} =
+  ## Searches for characer `sub` in `s` in reverse, starting at position `start`
+  ## (default: the last character) and going backwards to the first character.
   ##
-  ## If `s` contains none of the characters in `chars`, -1 is returned.
-  let last = if last==0: s.high else: last
-  for i in int(start)..last:
+  ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
+  ##
+  ## See also:
+  ## * `find proc<#find,string,char,int,int>`_
+  let realStart = if start == -1: s.len-1 else: start
+  for i in countdown(realStart, 0):
+    if sub == s[i]: return i
+  return -1
+
+proc rfind*(s: string, chars: set[char], start: int = -1): int {.noSideEffect.} =
+  ## Searches for `chars` in `s` in reverse, starting at position `start`
+  ## (default: the last character) and going backwards to the first character.
+  ##
+  ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
+  ##
+  ## See also:
+  ## * `find proc<#find,string,set[char],Natural,int>`_
+  let realStart = if start == -1: s.len-1 else: start
+  for i in countdown(realStart, 0):
     if s[i] in chars: return i
   return -1
 
 proc rfind*(s, sub: string, start: int = -1): int {.noSideEffect.} =
-  ## Searches for `sub` in `s` in reverse, starting at `start` and going
-  ## backwards to 0.
+  ## Searches for string `sub` in `s` in reverse, starting at position `start`
+  ## (default: the last character) and going backwards to the first character.
   ##
   ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
+  ##
+  ## See also:
+  ## * `find proc<#find,string,string,Natural,int>`_
   if sub.len == 0:
     return -1
   let realStart = if start == -1: s.len else: start
@@ -1539,54 +1856,34 @@ proc rfind*(s, sub: string, start: int = -1): int {.noSideEffect.} =
     if result != -1: return
   return -1
 
-proc rfind*(s: string, sub: char, start: int = -1): int {.noSideEffect,
-  rtl.} =
-  ## Searches for `sub` in `s` in reverse starting at position `start`.
-  ##
-  ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
-  let realStart = if start == -1: s.len-1 else: start
-  for i in countdown(realStart, 0):
-    if sub == s[i]: return i
-  return -1
 
-proc rfind*(s: string, chars: set[char], start: int = -1): int {.noSideEffect.} =
-  ## Searches for `chars` in `s` in reverse starting at position `start`.
+proc count*(s: string, sub: char): int {.noSideEffect,
+  rtl, extern: "nsuCountChar".} =
+  ## Count the occurrences of the character `sub` in the string `s`.
   ##
-  ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
-  let realStart = if start == -1: s.len-1 else: start
-  for i in countdown(realStart, 0):
-    if s[i] in chars: return i
-  return -1
+  ## See also:
+  ## * `countLines proc<#countLines,string>`_
+  for c in s:
+    if c == sub: inc result
 
-proc center*(s: string, width: int, fillChar: char = ' '): string {.
-  noSideEffect, rtl, extern: "nsuCenterString".} =
-  ## Return the contents of `s` centered in a string `width` long using
-  ## `fillChar` as padding.
+proc count*(s: string, subs: set[char]): int {.noSideEffect,
+  rtl, extern: "nsuCountCharSet".} =
+  ## Count the occurrences of the group of character `subs` in the string `s`.
   ##
-  ## The original string is returned if `width` is less than or equal
-  ## to `s.len`.
-  if width <= s.len: return s
-  result = newString(width)
-  # Left padding will be one fillChar
-  # smaller if there are an odd number
-  # of characters
-  let
-    charsLeft = (width - s.len)
-    leftPadding = charsLeft div 2
-  for i in 0 ..< width:
-    if i >= leftPadding and i < leftPadding + s.len:
-      # we are where the string should be located
-      result[i] = s[i-leftPadding]
-    else:
-      # we are either before or after where
-      # the string s should go
-      result[i] = fillChar
+  ## See also:
+  ## * `countLines proc<#countLines,string>`_
+  doAssert card(subs) > 0
+  for c in s:
+    if c in subs: inc result
 
 proc count*(s: string, sub: string, overlapping: bool = false): int {.
   noSideEffect, rtl, extern: "nsuCountString".} =
   ## Count the occurrences of a substring `sub` in the string `s`.
   ## Overlapping occurrences of `sub` only count when `overlapping`
-  ## is set to true.
+  ## is set to true (default: false).
+  ##
+  ## See also:
+  ## * `countLines proc<#countLines,string>`_
   doAssert sub.len > 0
   var i = 0
   while true:
@@ -1596,43 +1893,58 @@ proc count*(s: string, sub: string, overlapping: bool = false): int {.
     else: i += sub.len
     inc result
 
-proc count*(s: string, sub: char): int {.noSideEffect,
-  rtl, extern: "nsuCountChar".} =
-  ## Count the occurrences of the character `sub` in the string `s`.
-  for c in s:
-    if c == sub: inc result
-
-proc count*(s: string, subs: set[char]): int {.noSideEffect,
-  rtl, extern: "nsuCountCharSet".} =
-  ## Count the occurrences of the group of character `subs` in the string `s`.
-  doAssert card(subs) > 0
-  for c in s:
-    if c in subs: inc result
-
-proc quoteIfContainsWhite*(s: string): string {.deprecated.} =
-  ## Returns ``'"' & s & '"'`` if `s` contains a space and does not
-  ## start with a quote, else returns `s`.
+proc countLines*(s: string): int {.noSideEffect,
+  rtl, extern: "nsuCountLines".} =
+  ## Returns the number of lines in the string `s`.
+  ##
+  ## This is the same as ``len(splitLines(s))``, but much more efficient
+  ## because it doesn't modify the string creating temporal objects. Every
+  ## `character literal <manual.html#lexical-analysis-character-literals>`_
+  ## newline combination (CR, LF, CR-LF) is supported.
   ##
-  ## **DEPRECATED** as it was confused for shell quoting function.  For this
-  ## application use `osproc.quoteShell <osproc.html#quoteShell>`_.
-  if find(s, {' ', '\t'}) >= 0 and s[0] != '"': result = '"' & s & '"'
-  else: result = s
+  ## In this context, a line is any string seperated by a newline combination.
+  ## A line can be an empty string.
+  ##
+  ## See also:
+  ## * `splitLines proc<#splitLines,string>`_
+  runnableExamples:
+    doAssert countLines("First line\l and second line.") == 2
+  result = 1
+  var i = 0
+  while i < s.len:
+    case s[i]
+    of '\c':
+      if i+1 < s.len and s[i+1] == '\l': inc i
+      inc result
+    of '\l': inc result
+    else: discard
+    inc i
 
-proc contains*(s: string, c: char): bool {.noSideEffect.} =
-  ## Same as ``find(s, c) >= 0``.
-  return find(s, c) >= 0
 
 proc contains*(s, sub: string): bool {.noSideEffect.} =
   ## Same as ``find(s, sub) >= 0``.
+  ##
+  ## See also:
+  ## * `find proc<#find,string,string,Natural,int>`_
   return find(s, sub) >= 0
 
 proc contains*(s: string, chars: set[char]): bool {.noSideEffect.} =
   ## Same as ``find(s, chars) >= 0``.
+  ##
+  ## See also:
+  ## * `find proc<#find,string,set[char],Natural,int>`_
   return find(s, chars) >= 0
 
 proc replace*(s, sub: string, by = ""): string {.noSideEffect,
   rtl, extern: "nsuReplaceStr".} =
   ## Replaces `sub` in `s` by the string `by`.
+  ##
+  ## See also:
+  ## * `find proc<#find,string,string,Natural,int>`_
+  ## * `replace proc<#replace,string,char,char>`_ for replacing
+  ##   single characters
+  ## * `replaceWord proc<#replaceWord,string,string,string>`_
+  ## * `multiReplace proc<#multiReplace,string,varargs[]>`_
   result = ""
   let subLen = sub.len
   if subLen == 0:
@@ -1670,6 +1982,11 @@ proc replace*(s: string, sub, by: char): string {.noSideEffect,
   ## Replaces `sub` in `s` by the character `by`.
   ##
   ## Optimized version of `replace <#replace,string,string>`_ for characters.
+  ##
+  ## See also:
+  ## * `find proc<#find,string,char,Natural,int>`_
+  ## * `replaceWord proc<#replaceWord,string,string,string>`_
+  ## * `multiReplace proc<#multiReplace,string,varargs[]>`_
   result = newString(s.len)
   var i = 0
   while i < s.len:
@@ -1682,7 +1999,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
   ## Replaces `sub` in `s` by the string `by`.
   ##
   ## Each occurrence of `sub` has to be surrounded by word boundaries
-  ## (comparable to ``\\w`` in regular expressions), otherwise it is not
+  ## (comparable to ``\b`` in regular expressions), otherwise it is not
   ## replaced.
   if sub.len == 0: return s
   const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'}
@@ -1712,14 +2029,14 @@ proc multiReplace*(s: string, replacements: varargs[(string, string)]): string {
   ## Same as replace, but specialized for doing multiple replacements in a single
   ## pass through the input string.
   ##
-  ## multiReplace performs all replacements in a single pass, this means it can be used
-  ## to swap the occurences of "a" and "b", for instance.
+  ## `multiReplace` performs all replacements in a single pass, this means it
+  ## can be used to swap the occurences of "a" and "b", for instance.
   ##
-  ## If the resulting string is not longer than the original input string, only a single
-  ## memory allocation is required.
+  ## If the resulting string is not longer than the original input string,
+  ## only a single memory allocation is required.
   ##
-  ## The order of the replacements does matter. Earlier replacements are preferred over later
-  ## replacements in the argument list.
+  ## The order of the replacements does matter. Earlier replacements are
+  ## preferred over later replacements in the argument list.
   result = newStringOfCap(s.len)
   var i = 0
   var fastChk: set[char] = {}
@@ -1741,55 +2058,12 @@ proc multiReplace*(s: string, replacements: varargs[(string, string)]): string {
       add result, s[i]
       inc(i)
 
-proc delete*(s: var string, first, last: int) {.noSideEffect,
-  rtl, extern: "nsuDelete".} =
-  ## Deletes in `s` the characters at position `first` .. `last`.
-  ##
-  ## This modifies `s` itself, it does not return a copy.
-  var i = first
-  var j = last+1
-  var newLen = len(s)-j+i
-  while i < newLen:
-    s[i] = s[j]
-    inc(i)
-    inc(j)
-  setLen(s, newLen)
 
-proc toOct*(x: BiggestInt, len: Positive): string {.noSideEffect,
-  rtl, extern: "nsuToOct".} =
-  ## Converts `x` into its octal representation.
-  ##
-  ## The resulting string is always `len` characters long. No leading ``0o``
-  ## prefix is generated.
-  var
-    mask: BiggestInt = 7
-    shift: BiggestInt = 0
-  assert(len > 0)
-  result = newString(len)
-  for j in countdown(len-1, 0):
-    result[j] = chr(int((x and mask) shr shift) + ord('0'))
-    shift = shift + 3
-    mask = mask shl 3
-
-proc toBin*(x: BiggestInt, len: Positive): string {.noSideEffect,
-  rtl, extern: "nsuToBin".} =
-  ## Converts `x` into its binary representation.
-  ##
-  ## The resulting string is always `len` characters long. No leading ``0b``
-  ## prefix is generated.
-  var
-    mask: BiggestInt = 1
-    shift: BiggestInt = 0
-  assert(len > 0)
-  result = newString(len)
-  for j in countdown(len-1, 0):
-    result[j] = chr(int((x and mask) shr shift) + ord('0'))
-    shift = shift + 1
-    mask = mask shl 1
 
 proc insertSep*(s: string, sep = '_', digits = 3): string {.noSideEffect,
   rtl, extern: "nsuInsertSep".} =
-  ## Inserts the separator `sep` after `digits` digits from right to left.
+  ## Inserts the separator `sep` after `digits` characters (default: 3)
+  ## from right to left.
   ##
   ## Even though the algorithm works with any string `s`, it is only useful
   ## if `s` contains a number.
@@ -1811,11 +2085,15 @@ proc insertSep*(s: string, sep = '_', digits = 3): string {.noSideEffect,
 
 proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
   rtl, extern: "nsuEscape".} =
-  ## Escapes a string `s`. See `system.addEscapedChar <system.html#addEscapedChar>`_
-  ## for the escaping scheme.
+  ## Escapes a string `s`. See `system.addEscapedChar
+  ## <system.html#addEscapedChar,string,char>`_ for the escaping scheme.
   ##
   ## The resulting string is prefixed with `prefix` and suffixed with `suffix`.
   ## Both may be empty strings.
+  ##
+  ## See also:
+  ## * `unescape proc<#unescape,string,string,string>`_ for the opposite
+  ## operation
   result = newStringOfCap(s.len + s.len shr 2)
   result.add(prefix)
   for c in items(s):
@@ -1833,8 +2111,8 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
   rtl, extern: "nsuUnescape".} =
   ## Unescapes a string `s`.
   ##
-  ## This complements `escape <#escape>`_ as it performs the opposite
-  ## operations.
+  ## This complements `escape proc<#escape,string,string,string>`_
+  ## as it performs the opposite operations.
   ##
   ## If `s` does not begin with ``prefix`` and end with ``suffix`` a
   ## ValueError exception will be raised.
@@ -1880,101 +2158,12 @@ proc validIdentifier*(s: string): bool {.noSideEffect,
   ## and is followed by any number of characters of the set `IdentChars`.
   runnableExamples:
     doAssert "abc_def08".validIdentifier
+
   if s.len > 0 and s[0] in IdentStartChars:
     for i in 1..s.len-1:
       if s[i] notin IdentChars: return false
     return true
 
-{.push warning[Deprecated]: off.}
-proc editDistance*(a, b: string): int {.noSideEffect,
-  rtl, extern: "nsuEditDistance",
-  deprecated: "use editdistance.editDistanceAscii instead".} =
-  ## Returns the edit distance between `a` and `b`.
-  ##
-  ## This uses the `Levenshtein`:idx: distance algorithm with only a linear
-  ## memory overhead.
-  var len1 = a.len
-  var len2 = b.len
-  if len1 > len2:
-    # make `b` the longer string
-    return editDistance(b, a)
-
-  # strip common prefix:
-  var s = 0
-  while s < len1 and a[s] == b[s]:
-    inc(s)
-    dec(len1)
-    dec(len2)
-  # strip common suffix:
-  while len1 > 0 and len2 > 0 and a[s+len1-1] == b[s+len2-1]:
-    dec(len1)
-    dec(len2)
-  # trivial cases:
-  if len1 == 0: return len2
-  if len2 == 0: return len1
-
-  # another special case:
-  if len1 == 1:
-    for j in s..s+len2-1:
-      if a[s] == b[j]: return len2 - 1
-    return len2
-
-  inc(len1)
-  inc(len2)
-  var half = len1 shr 1
-  # initalize first row:
-  #var row = cast[ptr array[0..high(int) div 8, int]](alloc(len2*sizeof(int)))
-  var row: seq[int]
-  newSeq(row, len2)
-  var e = s + len2 - 1 # end marker
-  for i in 1..len2 - half - 1: row[i] = i
-  row[0] = len1 - half - 1
-  for i in 1 .. len1 - 1:
-    var char1 = a[i + s - 1]
-    var char2p: int
-    var D, x: int
-    var p: int
-    if i >= len1 - half:
-      # skip the upper triangle:
-      var offset = i - len1 + half
-      char2p = offset
-      p = offset
-      var c3 = row[p] + ord(char1 != b[s + char2p])
-      inc(p)
-      inc(char2p)
-      x = row[p] + 1
-      D = x
-      if x > c3: x = c3
-      row[p] = x
-      inc(p)
-    else:
-      p = 1
-      char2p = 0
-      D = i
-      x = i
-    if i <= half + 1:
-      # skip the lower triangle:
-      e = len2 + i - half - 2
-    # main:
-    while p <= e:
-      dec(D)
-      var c3 = D + ord(char1 != b[char2p + s])
-      inc(char2p)
-      inc(x)
-      if x > c3: x = c3
-      D = row[p] + 1
-      if x > D: x = D
-      row[p] = x
-      inc(p)
-    # lower triangle sentinel:
-    if i <= half:
-      dec(D)
-      var c3 = D + ord(char1 != b[char2p + s])
-      inc(x)
-      if x > c3: x = c3
-      row[p] = x
-  result = row[e]
-{.pop.}
 
 # floating point formating:
 when not defined(js):
@@ -1982,10 +2171,11 @@ when not defined(js):
                                      importc: "sprintf", varargs, noSideEffect.}
 
 type
-  FloatFormatMode* = enum ## the different modes of floating point formating
-    ffDefault,         ## use the shorter floating point notation
-    ffDecimal,         ## use decimal floating point notation
-    ffScientific       ## use scientific notation (using ``e`` character)
+  FloatFormatMode* = enum
+    ## the different modes of floating point formating
+    ffDefault,   ## use the shorter floating point notation
+    ffDecimal,   ## use decimal floating point notation
+    ffScientific ## use scientific notation (using ``e`` character)
 
 proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault,
                          precision: range[-1..32] = 16;
@@ -2001,6 +2191,11 @@ proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault,
   ## after the decimal point for Nim's ``biggestFloat`` type.
   ##
   ## If ``precision == -1``, it tries to format it nicely.
+  runnableExamples:
+    let x = 123.456
+    doAssert x.formatBiggestFloat() == "123.4560000000000"
+    doAssert x.formatBiggestFloat(ffDecimal, 4) == "123.4560"
+    doAssert x.formatBiggestFloat(ffScientific, 2) == "1.23e+02"
   when defined(js):
     var precision = precision
     if precision == -1:
@@ -2080,11 +2275,18 @@ proc formatFloat*(f: float, format: FloatFormatMode = ffDefault,
     doAssert x.formatFloat() == "123.4560000000000"
     doAssert x.formatFloat(ffDecimal, 4) == "123.4560"
     doAssert x.formatFloat(ffScientific, 2) == "1.23e+02"
+
   result = formatBiggestFloat(f, format, precision, decimalSep)
 
 proc trimZeros*(x: var string) {.noSideEffect.} =
   ## Trim trailing zeros from a formatted floating point
-  ## value (`x`).  Modifies the passed value.
+  ## value `x` (must be declared as ``var``).
+  ##
+  ## This modifies `x` itself, it does not return a copy.
+  runnableExamples:
+    var x = "123.456000000"
+    x.trimZeros()
+    doAssert x == "123.456"
   var spl: seq[string]
   if x.contains('.') or x.contains(','):
     if x.contains('e'):
@@ -2114,6 +2316,9 @@ proc formatSize*(bytes: int64,
   ##
   ## `includeSpace` can be set to true to include the (SI preferred) space
   ## between the number and the unit (e.g. 1 KiB).
+  ##
+  ## See also:
+  ## * `strformat module<strformat.html>`_ for string interpolation and formatting
   runnableExamples:
     doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB"
     doAssert formatSize((2.234*1024*1024).int) == "2.234MiB"
@@ -2121,6 +2326,7 @@ proc formatSize*(bytes: int64,
     doAssert formatSize(4096, prefix=bpColloquial, includeSpace=true) == "4 kB"
     doAssert formatSize(4096) == "4KiB"
     doAssert formatSize(5_378_934, prefix=bpColloquial, decimalSep=',') == "5,13MB"
+
   const iecPrefixes = ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"]
   const collPrefixes = ["", "k", "M", "G", "T", "P", "E", "Z", "Y"]
   var
@@ -2216,6 +2422,9 @@ proc formatEng*(f: BiggestFloat,
   ##    formatEng(4100, unit="", useUnitSpace=true) == "4.1e3 " # Space with useUnitSpace=true
   ##
   ## `decimalSep` is used as the decimal separator.
+  ##
+  ## See also:
+  ## * `strformat module<strformat.html>`_ for string interpolation and formatting
   var
     absolute: BiggestFloat
     significand: BiggestFloat
@@ -2403,110 +2612,69 @@ proc `%` *(formatstr: string, a: openArray[string]): string {.noSideEffect,
   ##
   ## The variables are compared with `cmpIgnoreStyle`. `ValueError` is
   ## raised if an ill-formed format string has been passed to the `%` operator.
+  ##
+  ## See also:
+  ## * `strformat module<strformat.html>`_ for string interpolation and formatting
   result = newStringOfCap(formatstr.len + a.len shl 4)
   addf(result, formatstr, a)
 
 proc `%` *(formatstr, a: string): string {.noSideEffect,
   rtl, extern: "nsuFormatSingleElem".} =
-  ## This is the same as ``formatstr % [a]``.
+  ## This is the same as ``formatstr % [a]`` (see
+  ## `% proc<#%25,string,openArray[string]>`_).
   result = newStringOfCap(formatstr.len + a.len)
   addf(result, formatstr, [a])
 
 proc format*(formatstr: string, a: varargs[string, `$`]): string {.noSideEffect,
   rtl, extern: "nsuFormatVarargs".} =
-  ## This is the same as ``formatstr % a`` except that it supports
+  ## This is the same as ``formatstr % a`` (see
+  ## `% proc<#%25,string,openArray[string]>`_) except that it supports
   ## auto stringification.
+  ##
+  ## See also:
+  ## * `strformat module<strformat.html>`_ for string interpolation and formatting
   result = newStringOfCap(formatstr.len + a.len)
   addf(result, formatstr, a)
 
 {.pop.}
 
-proc removeSuffix*(s: var string, chars: set[char] = Newlines) {.
-  rtl, extern: "nsuRemoveSuffixCharSet".} =
-  ## Removes all characters from `chars` from the end of the string `s`
-  ## (in-place).
-  runnableExamples:
-     var userInput = "Hello World!*~\r\n"
-     userInput.removeSuffix
-     doAssert userInput == "Hello World!*~"
-     userInput.removeSuffix({'~', '*'})
-     doAssert userInput == "Hello World!"
 
-     var otherInput = "Hello!?!"
-     otherInput.removeSuffix({'!', '?'})
-     doAssert otherInput == "Hello"
-  if s.len == 0: return
-  var last = s.high
-  while last > -1 and s[last] in chars: last -= 1
-  s.setLen(last + 1)
 
-proc removeSuffix*(s: var string, c: char) {.
-  rtl, extern: "nsuRemoveSuffixChar".} =
-  ## Removes all occurrences of a single character (in-place) from the end
-  ## of a string.
+proc strip*(s: string, leading = true, trailing = true,
+            chars: set[char] = Whitespace): string
+  {.noSideEffect, rtl, extern: "nsuStrip".} =
+  ## Strips leading or trailing `chars` (default: whitespace characters)
+  ## from `s` and returns the resulting string.
   ##
-  runnableExamples:
-     var table = "users"
-     table.removeSuffix('s')
-     doAssert table == "user"
-
-     var dots = "Trailing dots......."
-     dots.removeSuffix('.')
-     doAssert dots == "Trailing dots"
-  removeSuffix(s, chars = {c})
-
-proc removeSuffix*(s: var string, suffix: string) {.
-  rtl, extern: "nsuRemoveSuffixString".} =
-  ## Remove the first matching suffix (in-place) from a string.
-  runnableExamples:
-     var answers = "yeses"
-     answers.removeSuffix("es")
-     doAssert answers == "yes"
-  var newLen = s.len
-  if s.endsWith(suffix):
-    newLen -= len(suffix)
-    s.setLen(newLen)
-
-proc removePrefix*(s: var string, chars: set[char] = Newlines) {.
-  rtl, extern: "nsuRemovePrefixCharSet".} =
-  ## Removes all characters from `chars` from the start of the string `s`
-  ## (in-place).
+  ## If `leading` is true (default), leading `chars` are stripped.
+  ## If `trailing` is true (default), trailing `chars` are stripped.
+  ## If both are false, the string is returned unchanged.
   ##
+  ## See also:
+  ## * `stripLineEnd proc<#stripLineEnd,string>`_
   runnableExamples:
-     var userInput = "\r\n*~Hello World!"
-     userInput.removePrefix
-     doAssert userInput == "*~Hello World!"
-     userInput.removePrefix({'~', '*'})
-     doAssert userInput == "Hello World!"
+    let a = "  vhellov   "
+    let b = strip(a)
+    doAssert b == "vhellov"
 
-     var otherInput = "?!?Hello!?!"
-     otherInput.removePrefix({'!', '?'})
-     doAssert otherInput == "Hello!?!"
-  var start = 0
-  while start < s.len and s[start] in chars: start += 1
-  if start > 0: s.delete(0, start - 1)
+    doAssert a.strip(leading = false) == "  vhellov"
+    doAssert a.strip(trailing = false) == "vhellov   "
 
-proc removePrefix*(s: var string, c: char) {.
-  rtl, extern: "nsuRemovePrefixChar".} =
-  ## Removes all occurrences of a single character (in-place) from the start
-  ## of a string.
-  ##
-  runnableExamples:
-     var ident = "pControl"
-     ident.removePrefix('p')
-     doAssert ident == "Control"
-  removePrefix(s, chars = {c})
+    doAssert b.strip(chars = {'v'}) == "hello"
+    doAssert b.strip(leading = false, chars = {'v'}) == "vhello"
 
-proc removePrefix*(s: var string, prefix: string) {.
-  rtl, extern: "nsuRemovePrefixString".} =
-  ## Remove the first matching prefix (in-place) from a string.
-  ##
-  runnableExamples:
-     var answers = "yesyes"
-     answers.removePrefix("yes")
-     doAssert answers == "yes"
-  if s.startsWith(prefix):
-    s.delete(0, prefix.len - 1)
+    let c = "blaXbla"
+    doAssert c.strip(chars = {'b', 'a'}) == "laXbl"
+    doAssert c.strip(chars = {'b', 'a', 'l'}) == "X"
+
+  var
+    first = 0
+    last = len(s)-1
+  if leading:
+    while first <= last and s[first] in chars: inc(first)
+  if trailing:
+    while last >= 0 and s[last] in chars: dec(last)
+  result = substr(s, first, last)
 
 proc stripLineEnd*(s: var string) =
   ## Returns ``s`` stripped from one of these suffixes:
@@ -2520,6 +2688,7 @@ proc stripLineEnd*(s: var string) =
     s = "foo\r\n"
     s.stripLineEnd
     doAssert s == "foo"
+
   if s.len > 0:
     case s[^1]
     of '\n':
@@ -2532,6 +2701,331 @@ proc stripLineEnd*(s: var string) =
     else:
       discard
 
+
+iterator tokenize*(s: string, seps: set[char] = Whitespace): tuple[
+  token: string, isSep: bool] =
+  ## Tokenizes the string `s` into substrings.
+  ##
+  ## Substrings are separated by a substring containing only `seps`.
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##   for word in tokenize("  this is an  example  "):
+  ##     writeLine(stdout, word)
+  ##
+  ## Results in:
+  ##
+  ## .. code-block:: nim
+  ##   ("  ", true)
+  ##   ("this", false)
+  ##   (" ", true)
+  ##   ("is", false)
+  ##   (" ", true)
+  ##   ("an", false)
+  ##   ("  ", true)
+  ##   ("example", false)
+  ##   ("  ", true)
+  var i = 0
+  while true:
+    var j = i
+    var isSep = j < s.len and s[j] in seps
+    while j < s.len and (s[j] in seps) == isSep: inc(j)
+    if j > i:
+      yield (substr(s, i, j-1), isSep)
+    else:
+      break
+    i = j
+
+
+
+
+
+# --------------------------------------------------------------------------
+# Deprecated procs
+
+{.push warning[Deprecated]: off.}
+proc editDistance*(a, b: string): int {.noSideEffect,
+  rtl, extern: "nsuEditDistance",
+  deprecated: "use editdistance.editDistanceAscii instead".} =
+  ## **Deprecated**: Use `editdistance module<editdistance.html>`_
+  ##
+  ## Returns the edit distance between `a` and `b`.
+  ##
+  ## This uses the `Levenshtein`:idx: distance algorithm with only a linear
+  ## memory overhead.
+  var len1 = a.len
+  var len2 = b.len
+  if len1 > len2:
+    # make `b` the longer string
+    return editDistance(b, a)
+
+  # strip common prefix:
+  var s = 0
+  while s < len1 and a[s] == b[s]:
+    inc(s)
+    dec(len1)
+    dec(len2)
+  # strip common suffix:
+  while len1 > 0 and len2 > 0 and a[s+len1-1] == b[s+len2-1]:
+    dec(len1)
+    dec(len2)
+  # trivial cases:
+  if len1 == 0: return len2
+  if len2 == 0: return len1
+
+  # another special case:
+  if len1 == 1:
+    for j in s..s+len2-1:
+      if a[s] == b[j]: return len2 - 1
+    return len2
+
+  inc(len1)
+  inc(len2)
+  var half = len1 shr 1
+  # initalize first row:
+  #var row = cast[ptr array[0..high(int) div 8, int]](alloc(len2*sizeof(int)))
+  var row: seq[int]
+  newSeq(row, len2)
+  var e = s + len2 - 1 # end marker
+  for i in 1..len2 - half - 1: row[i] = i
+  row[0] = len1 - half - 1
+  for i in 1 .. len1 - 1:
+    var char1 = a[i + s - 1]
+    var char2p: int
+    var D, x: int
+    var p: int
+    if i >= len1 - half:
+      # skip the upper triangle:
+      var offset = i - len1 + half
+      char2p = offset
+      p = offset
+      var c3 = row[p] + ord(char1 != b[s + char2p])
+      inc(p)
+      inc(char2p)
+      x = row[p] + 1
+      D = x
+      if x > c3: x = c3
+      row[p] = x
+      inc(p)
+    else:
+      p = 1
+      char2p = 0
+      D = i
+      x = i
+    if i <= half + 1:
+      # skip the lower triangle:
+      e = len2 + i - half - 2
+    # main:
+    while p <= e:
+      dec(D)
+      var c3 = D + ord(char1 != b[char2p + s])
+      inc(char2p)
+      inc(x)
+      if x > c3: x = c3
+      D = row[p] + 1
+      if x > D: x = D
+      row[p] = x
+      inc(p)
+    # lower triangle sentinel:
+    if i <= half:
+      dec(D)
+      var c3 = D + ord(char1 != b[char2p + s])
+      inc(x)
+      if x > c3: x = c3
+      row[p] = x
+  result = row[e]
+{.pop.}
+
+proc isNilOrEmpty*(s: string): bool {.noSideEffect, procvar, rtl,
+                                      extern: "nsuIsNilOrEmpty",
+                                      deprecated: "use 'x.len == 0' instead".} =
+  ## **Deprecated**: use 'x.len == 0'
+  ##
+  ## Checks if `s` is nil or empty.
+  result = len(s) == 0
+
+proc isNilOrWhitespace*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nsuIsNilOrWhitespace".} =
+  ## Checks if `s` is nil or consists entirely of whitespace characters.
+  result = true
+  for c in s:
+    if not c.isSpaceAscii():
+      return false
+
+template isImpl(call) =
+  if s.len == 0: return false
+  result = true
+  for c in s:
+    if not call(c): return false
+
+proc isAlphaAscii*(s: string): bool {.noSideEffect, procvar,
+  rtl, extern: "nsuIsAlphaAsciiStr",
+  deprecated: "Deprecated since version 0.20 since its semantics are unclear".} =
+  ## **Deprecated**: Deprecated since version 0.20 since its semantics are unclear
+  ##
+  ## Checks whether or not `s` is alphabetical.
+  ##
+  ## This checks a-z, A-Z ASCII characters only.
+  ## Returns true if all characters in `s` are
+  ## alphabetic and there is at least one character
+  ## in `s`.
+  ## Use `Unicode module<unicode.html>`_ for UTF-8 support.
+  runnableExamples:
+    doAssert isAlphaAscii("fooBar") == true
+    doAssert isAlphaAscii("fooBar1") == false
+    doAssert isAlphaAscii("foo Bar") == false
+  isImpl isAlphaAscii
+
+proc isAlphaNumeric*(s: string): bool {.noSideEffect, procvar,
+  rtl, extern: "nsuIsAlphaNumericStr",
+  deprecated: "Deprecated since version 0.20 since its semantics are unclear".} =
+  ## **Deprecated**: Deprecated since version 0.20 since its semantics are unclear
+  ##
+  ## Checks whether or not `s` is alphanumeric.
+  ##
+  ## This checks a-z, A-Z, 0-9 ASCII characters only.
+  ## Returns true if all characters in `s` are
+  ## alpanumeric and there is at least one character
+  ## in `s`.
+  ## Use `Unicode module<unicode.html>`_ for UTF-8 support.
+  runnableExamples:
+    doAssert isAlphaNumeric("fooBar") == true
+    doAssert isAlphaNumeric("fooBar1") == true
+    doAssert isAlphaNumeric("foo Bar") == false
+  isImpl isAlphaNumeric
+
+proc isDigit*(s: string): bool {.noSideEffect, procvar,
+  rtl, extern: "nsuIsDigitStr",
+  deprecated: "Deprecated since version 0.20 since its semantics are unclear".} =
+  ## **Deprecated**: Deprecated since version 0.20 since its semantics are unclear
+  ##
+  ## Checks whether or not `s` is a numeric value.
+  ##
+  ## This checks 0-9 ASCII characters only.
+  ## Returns true if all characters in `s` are
+  ## numeric and there is at least one character
+  ## in `s`.
+  runnableExamples:
+    doAssert isDigit("1908") == true
+    doAssert isDigit("fooBar1") == false
+  isImpl isDigit
+
+proc isSpaceAscii*(s: string): bool {.noSideEffect, procvar,
+  rtl, extern: "nsuIsSpaceAsciiStr",
+  deprecated: "Deprecated since version 0.20 since its semantics are unclear".} =
+  ## **Deprecated**: Deprecated since version 0.20 since its semantics are unclear
+  ##
+  ## Checks whether or not `s` is completely whitespace.
+  ##
+  ## Returns true if all characters in `s` are whitespace
+  ## characters and there is at least one character in `s`.
+  runnableExamples:
+    doAssert isSpaceAscii("   ") == true
+    doAssert isSpaceAscii("") == false
+  isImpl isSpaceAscii
+
+template isCaseImpl(s, charProc, skipNonAlpha) =
+  var hasAtleastOneAlphaChar = false
+  if s.len == 0: return false
+  for c in s:
+    if skipNonAlpha:
+      var charIsAlpha = c.isAlphaAscii()
+      if not hasAtleastOneAlphaChar:
+        hasAtleastOneAlphaChar = charIsAlpha
+      if charIsAlpha and (not charProc(c)):
+        return false
+    else:
+      if not charProc(c):
+        return false
+  return if skipNonAlpha: hasAtleastOneAlphaChar else: true
+
+proc isLowerAscii*(s: string, skipNonAlpha: bool): bool {.
+  deprecated: "Deprecated since version 0.20 since its semantics are unclear".} =
+  ## **Deprecated**: Deprecated since version 0.20 since its semantics are unclear
+  ##
+  ## Checks whether ``s`` is lower case.
+  ##
+  ## This checks ASCII characters only.
+  ##
+  ## If ``skipNonAlpha`` is true, returns true if all alphabetical
+  ## characters in ``s`` are lower case.  Returns false if none of the
+  ## characters in ``s`` are alphabetical.
+  ##
+  ## If ``skipNonAlpha`` is false, returns true only if all characters
+  ## in ``s`` are alphabetical and lower case.
+  ##
+  ## For either value of ``skipNonAlpha``, returns false if ``s`` is
+  ## an empty string.
+  ## Use `Unicode module<unicode.html>`_ for UTF-8 support.
+  runnableExamples:
+    doAssert isLowerAscii("1foobar", false) == false
+    doAssert isLowerAscii("1foobar", true) == true
+    doAssert isLowerAscii("1fooBar", true) == false
+  isCaseImpl(s, isLowerAscii, skipNonAlpha)
+
+proc isUpperAscii*(s: string, skipNonAlpha: bool): bool {.
+  deprecated: "Deprecated since version 0.20 since its semantics are unclear".} =
+  ## **Deprecated**: Deprecated since version 0.20 since its semantics are unclear
+  ##
+  ## Checks whether ``s`` is upper case.
+  ##
+  ## This checks ASCII characters only.
+  ##
+  ## If ``skipNonAlpha`` is true, returns true if all alphabetical
+  ## characters in ``s`` are upper case.  Returns false if none of the
+  ## characters in ``s`` are alphabetical.
+  ##
+  ## If ``skipNonAlpha`` is false, returns true only if all characters
+  ## in ``s`` are alphabetical and upper case.
+  ##
+  ## For either value of ``skipNonAlpha``, returns false if ``s`` is
+  ## an empty string.
+  ## Use `Unicode module<unicode.html>`_ for UTF-8 support.
+  runnableExamples:
+    doAssert isUpperAscii("1FOO", false) == false
+    doAssert isUpperAscii("1FOO", true) == true
+    doAssert isUpperAscii("1Foo", true) == false
+  isCaseImpl(s, isUpperAscii, skipNonAlpha)
+
+proc wordWrap*(s: string, maxLineWidth = 80,
+               splitLongWords = true,
+               seps: set[char] = Whitespace,
+               newLine = "\n"): string {.
+               noSideEffect, rtl, extern: "nsuWordWrap",
+               deprecated: "use wrapWords in std/wordwrap instead".} =
+  ## **Deprecated**: use wrapWords in std/wordwrap instead
+  ##
+  ## Word wraps `s`.
+  result = newStringOfCap(s.len + s.len shr 6)
+  var spaceLeft = maxLineWidth
+  var lastSep = ""
+  for word, isSep in tokenize(s, seps):
+    if isSep:
+      lastSep = word
+      spaceLeft = spaceLeft - len(word)
+      continue
+    if len(word) > spaceLeft:
+      if splitLongWords and len(word) > maxLineWidth:
+        result.add(substr(word, 0, spaceLeft-1))
+        var w = spaceLeft
+        var wordLeft = len(word) - spaceLeft
+        while wordLeft > 0:
+          result.add(newLine)
+          var L = min(maxLineWidth, wordLeft)
+          spaceLeft = maxLineWidth - L
+          result.add(substr(word, w, w+L-1))
+          inc(w, L)
+          dec(wordLeft, L)
+      else:
+        spaceLeft = maxLineWidth - len(word)
+        result.add(newLine)
+        result.add(word)
+    else:
+      spaceLeft = spaceLeft - len(word)
+      result.add(lastSep & word)
+      lastSep.setLen(0)
+
+
+
 when isMainModule:
   proc nonStaticTests =
     doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000"
diff --git a/lib/pure/subexes.nim b/lib/pure/subexes.nim
deleted file mode 100644
index 638e71f04..000000000
--- a/lib/pure/subexes.nim
+++ /dev/null
@@ -1,406 +0,0 @@
-#
-#
-#            Nim's Runtime Library
-#        (c) Copyright 2012 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## Nim support for `substitution expressions`:idx: (`subex`:idx:).
-##
-## .. include:: ../../doc/subexes.txt
-##
-
-{.push debugger:off .} # the user does not want to trace a part
-                       # of the standard library!
-
-from strutils import parseInt, cmpIgnoreStyle, Digits
-include "system/inclrtl"
-import system/helpers2
-
-proc findNormalized(x: string, inArray: openarray[string]): int =
-  var i = 0
-  while i < high(inArray):
-    if cmpIgnoreStyle(x, inArray[i]) == 0: return i
-    inc(i, 2) # incrementing by 1 would probably lead to a
-              # security hole...
-  return -1
-
-type
-  SubexError* = object of ValueError ## exception that is raised for
-                                     ## an invalid subex
-
-proc raiseInvalidFormat(msg: string) {.noinline.} =
-  raise newException(SubexError, "invalid format string: " & msg)
-
-type
-  FormatParser = object {.pure, final.}
-    when defined(js):
-      f: string # we rely on the '\0' terminator
-                # which JS's native string doesn't have
-    else:
-      f: cstring
-    num, i, lineLen: int
-
-template call(x: untyped): untyped =
-  p.i = i
-  x
-  i = p.i
-
-template callNoLineLenTracking(x: untyped): untyped =
-  let oldLineLen = p.lineLen
-  p.i = i
-  x
-  i = p.i
-  p.lineLen = oldLineLen
-
-proc getFormatArg(p: var FormatParser, a: openArray[string]): int =
-  const PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\128'..'\255', '_'}
-  var i = p.i
-  var f = p.f
-  case f[i]
-  of '#':
-    result = p.num
-    inc i
-    inc p.num
-  of '1'..'9', '-':
-    var j = 0
-    var negative = f[i] == '-'
-    if negative: inc i
-    while f[i] in Digits:
-      j = j * 10 + ord(f[i]) - ord('0')
-      inc i
-    result = if not negative: j-1 else: a.len-j
-  of 'a'..'z', 'A'..'Z', '\128'..'\255', '_':
-    var name = ""
-    while f[i] in PatternChars:
-      name.add(f[i])
-      inc(i)
-    result = findNormalized(name, a)+1
-  of '$':
-    inc(i)
-    call:
-      result = getFormatArg(p, a)
-    result = parseInt(a[result])-1
-  else:
-    raiseInvalidFormat("'#', '$', number or identifier expected")
-  if result >=% a.len: raiseInvalidFormat(formatErrorIndexBound(result, a.len))
-  p.i = i
-
-proc scanDollar(p: var FormatParser, a: openarray[string], s: var string) {.
-  noSideEffect.}
-
-proc emitChar(p: var FormatParser, x: var string, ch: char) {.inline.} =
-  x.add(ch)
-  if ch == '\L': p.lineLen = 0
-  else: inc p.lineLen
-
-proc emitStrLinear(p: var FormatParser, x: var string, y: string) {.inline.} =
-  for ch in items(y): emitChar(p, x, ch)
-
-proc emitStr(p: var FormatParser, x: var string, y: string) {.inline.} =
-  x.add(y)
-  inc p.lineLen, y.len
-
-proc scanQuote(p: var FormatParser, x: var string, toAdd: bool) =
-  var i = p.i+1
-  var f = p.f
-  while true:
-    if f[i] == '\'':
-      inc i
-      if f[i] != '\'': break
-      inc i
-      if toAdd: emitChar(p, x, '\'')
-    elif f[i] == '\0': raiseInvalidFormat("closing \"'\" expected")
-    else:
-      if toAdd: emitChar(p, x, f[i])
-      inc i
-  p.i = i
-
-proc scanBranch(p: var FormatParser, a: openArray[string],
-                x: var string, choice: int) =
-  var i = p.i
-  var f = p.f
-  var c = 0
-  var elsePart = i
-  var toAdd = choice == 0
-  while true:
-    case f[i]
-    of ']': break
-    of '|':
-      inc i
-      elsePart = i
-      inc c
-      if toAdd: break
-      toAdd = choice == c
-    of '\'':
-      call: scanQuote(p, x, toAdd)
-    of '\0': raiseInvalidFormat("closing ']' expected")
-    else:
-      if toAdd:
-        if f[i] == '$':
-          inc i
-          call: scanDollar(p, a, x)
-        else:
-          emitChar(p, x, f[i])
-          inc i
-      else:
-        inc i
-  if not toAdd and choice >= 0:
-    # evaluate 'else' part:
-    var last = i
-    i = elsePart
-    while true:
-      case f[i]
-      of '|', ']': break
-      of '\'':
-        call: scanQuote(p, x, true)
-      of '$':
-        inc i
-        call: scanDollar(p, a, x)
-      else:
-        emitChar(p, x, f[i])
-        inc i
-    i = last
-  p.i = i+1
-
-proc scanSlice(p: var FormatParser, a: openarray[string]): tuple[x, y: int] =
-  var slice = false
-  var i = p.i
-  var f = p.f
-
-  if f[i] == '{': inc i
-  else: raiseInvalidFormat("'{' expected")
-  if f[i] == '.' and f[i+1] == '.':
-    inc i, 2
-    slice = true
-  else:
-    call: result.x = getFormatArg(p, a)
-    if f[i] == '.' and f[i+1] == '.':
-      inc i, 2
-      slice = true
-  if slice:
-    if f[i] != '}':
-      call: result.y = getFormatArg(p, a)
-    else:
-      result.y = high(a)
-  else:
-    result.y = result.x
-  if f[i] != '}': raiseInvalidFormat("'}' expected")
-  inc i
-  p.i = i
-
-proc scanDollar(p: var FormatParser, a: openarray[string], s: var string) =
-  var i = p.i
-  var f = p.f
-  case f[i]
-  of '$':
-    emitChar p, s, '$'
-    inc i
-  of '*':
-    for j in 0..a.high: emitStr p, s, a[j]
-    inc i
-  of '{':
-    call:
-      let (x, y) = scanSlice(p, a)
-    for j in x..y: emitStr p, s, a[j]
-  of '[':
-    inc i
-    var start = i
-    call: scanBranch(p, a, s, -1)
-    var x: int
-    if f[i] == '{':
-      inc i
-      call: x = getFormatArg(p, a)
-      if f[i] != '}': raiseInvalidFormat("'}' expected")
-      inc i
-    else:
-      call: x = getFormatArg(p, a)
-    var last = i
-    let choice = parseInt(a[x])
-    i = start
-    call: scanBranch(p, a, s, choice)
-    i = last
-  of '\'':
-    var sep = ""
-    callNoLineLenTracking: scanQuote(p, sep, true)
-    if f[i] == '~':
-      # $' '~{1..3}
-      # insert space followed by 1..3 if not empty
-      inc i
-      call:
-        let (x, y) = scanSlice(p, a)
-      var L = 0
-      for j in x..y: inc L, a[j].len
-      if L > 0:
-        emitStrLinear p, s, sep
-        for j in x..y: emitStr p, s, a[j]
-    else:
-      block StringJoin:
-        block OptionalLineLengthSpecifier:
-          var maxLen = 0
-          case f[i]
-          of '0'..'9':
-            while f[i] in Digits:
-              maxLen = maxLen * 10 + ord(f[i]) - ord('0')
-              inc i
-          of '$':
-            # do not skip the '$' here for `getFormatArg`!
-            call:
-              maxLen = getFormatArg(p, a)
-          else: break OptionalLineLengthSpecifier
-          var indent = ""
-          case f[i]
-          of 'i':
-            inc i
-            callNoLineLenTracking: scanQuote(p, indent, true)
-
-            call:
-              let (x, y) = scanSlice(p, a)
-            if maxLen < 1: emitStrLinear(p, s, indent)
-            var items = 1
-            emitStr p, s, a[x]
-            for j in x+1..y:
-              emitStr p, s, sep
-              if items >= maxLen:
-                emitStrLinear p, s, indent
-                items = 0
-              emitStr p, s, a[j]
-              inc items
-          of 'c':
-            inc i
-            callNoLineLenTracking: scanQuote(p, indent, true)
-
-            call:
-              let (x, y) = scanSlice(p, a)
-            if p.lineLen + a[x].len > maxLen: emitStrLinear(p, s, indent)
-            emitStr p, s, a[x]
-            for j in x+1..y:
-              emitStr p, s, sep
-              if p.lineLen + a[j].len > maxLen: emitStrLinear(p, s, indent)
-              emitStr p, s, a[j]
-
-          else: raiseInvalidFormat("unit 'c' (chars) or 'i' (items) expected")
-          break StringJoin
-
-        call:
-          let (x, y) = scanSlice(p, a)
-        emitStr p, s, a[x]
-        for j in x+1..y:
-          emitStr p, s, sep
-          emitStr p, s, a[j]
-  else:
-    call:
-      var x = getFormatArg(p, a)
-    emitStr p, s, a[x]
-  p.i = i
-
-
-type
-  Subex* = distinct string ## string that contains a substitution expression
-
-proc subex*(s: string): Subex =
-  ## constructs a *substitution expression* from `s`. Currently this performs
-  ## no syntax checking but this may change in later versions.
-  result = Subex(s)
-
-proc addf*(s: var string, formatstr: Subex, a: varargs[string, `$`]) {.
-           noSideEffect, rtl, extern: "nfrmtAddf".} =
-  ## The same as ``add(s, formatstr % a)``, but more efficient.
-  var p: FormatParser
-  p.f = formatstr.string
-  var i = 0
-  while i < len(formatstr.string):
-    if p.f[i] == '$':
-      inc i
-      call: scanDollar(p, a, s)
-    else:
-      emitChar(p, s, p.f[i])
-      inc(i)
-
-proc `%` *(formatstr: Subex, a: openarray[string]): string {.noSideEffect,
-  rtl, extern: "nfrmtFormatOpenArray".} =
-  ## The `substitution`:idx: operator performs string substitutions in
-  ## `formatstr` and returns a modified `formatstr`. This is often called
-  ## `string interpolation`:idx:.
-  ##
-  result = newStringOfCap(formatstr.string.len + a.len shl 4)
-  addf(result, formatstr, a)
-
-proc `%` *(formatstr: Subex, a: string): string {.noSideEffect,
-  rtl, extern: "nfrmtFormatSingleElem".} =
-  ## This is the same as ``formatstr % [a]``.
-  result = newStringOfCap(formatstr.string.len + a.len)
-  addf(result, formatstr, [a])
-
-proc format*(formatstr: Subex, a: varargs[string, `$`]): string {.noSideEffect,
-  rtl, extern: "nfrmtFormatVarargs".} =
-  ## The `substitution`:idx: operator performs string substitutions in
-  ## `formatstr` and returns a modified `formatstr`. This is often called
-  ## `string interpolation`:idx:.
-  ##
-  result = newStringOfCap(formatstr.string.len + a.len shl 4)
-  addf(result, formatstr, a)
-
-{.pop.}
-
-when isMainModule:
-  from strutils import replace
-
-  proc `%`(formatstr: string, a: openarray[string]): string =
-    result = newStringOfCap(formatstr.len + a.len shl 4)
-    addf(result, formatstr.Subex, a)
-
-  proc `%`(formatstr: string, a: string): string =
-    result = newStringOfCap(formatstr.len + a.len)
-    addf(result, formatstr.Subex, [a])
-
-
-  doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
-  doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] ==
-           "The cat eats fish."
-
-
-  doAssert "$[abc|def]# $3 $# $#" % ["17", "b", "c"] == "def c b c"
-  doAssert "$[abc|def]# $3 $# $#" % ["1", "b", "c"] == "def c b c"
-  doAssert "$[abc|def]# $3 $# $#" % ["0", "b", "c"] == "abc c b c"
-  doAssert "$[abc|def|]# $3 $# $#" % ["17", "b", "c"] == " c b c"
-
-  doAssert "$[abc|def|]# $3 $# $#" % ["-9", "b", "c"] == " c b c"
-  doAssert "$1($', '{2..})" % ["f", "a", "b"] == "f(a, b)"
-
-  doAssert "$[$1($', '{2..})|''''|fg'$3']1" % ["7", "a", "b"] == "fg$3"
-
-  doAssert "$[$#($', '{#..})|''''|$3]1" % ["0", "a", "b"] == "0(a, b)"
-  doAssert "$' '~{..}" % "" == ""
-  doAssert "$' '~{..}" % "P0" == " P0"
-  doAssert "${$1}" % "1" == "1"
-  doAssert "${$$-1} $$1" % "1" == "1 $1"
-
-  doAssert(("$#($', '10c'\n    '{#..})" % ["doAssert", "longishA", "longish"]).replace(" \n", "\n") ==
-           """doAssert(
-    longishA,
-    longish)""")
-
-  doAssert(("type MyEnum* = enum\n  $', '2i'\n  '{..}" % ["fieldA",
-    "fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"]).replace(" \n", "\n") ==
-    strutils.unindent("""
-      type MyEnum* = enum
-        fieldA, fieldB,
-        FiledClkad, fieldD,
-        fieldE, longishFieldName""", 6))
-
-  doAssert subex"$1($', '{2..})" % ["f", "a", "b", "c"] == "f(a, b, c)"
-
-  doAssert subex"$1 $[files|file|files]{1} copied" % ["1"] == "1 file copied"
-
-  doAssert subex"$['''|'|''''|']']#" % "0" == "'|"
-
-  doAssert((subex("type\n  Enum = enum\n    $', '40c'\n    '{..}") % [
-    "fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"]).replace(" \n", "\n") ==
-    strutils.unindent("""
-      type
-        Enum = enum
-          fieldNameA, fieldNameB, fieldNameC,
-          fieldNameD""", 6))
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim
index 35dc2483c..2b3c08d0d 100644
--- a/lib/pure/terminal.nim
+++ b/lib/pure/terminal.nim
@@ -37,7 +37,7 @@ type
 
 var gTerm {.threadvar.}: PTerminal
 
-proc newTerminal(): PTerminal
+proc newTerminal(): PTerminal {.gcsafe.}
 
 proc getTerminal(): PTerminal {.inline.} =
   if isNil(gTerm):
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 010551b5a..0104a97c1 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -1,35 +1,41 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2017 Nim contributors
+#        (c) Copyright 2018 Nim contributors
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
 ##[
-  This module contains routines and types for dealing with time using a proleptic Gregorian calendar.
-  It's also available for the `JavaScript target <backends.html#the-javascript-target>`_.
+  The ``times`` module contains routines and types for dealing with time using
+  the `proleptic Gregorian calendar<https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar>`_.
+  It's also available for the
+  `JavaScript target <backends.html#backends-the-javascript-target>`_.
 
-  Although the types use nanosecond time resolution, the underlying resolution used by ``getTime()``
-  depends on the platform and backend (JS is limited to millisecond precision).
+  Although the ``times`` module support nanosecond time resolution, the
+  resolution used by ``getTime()`` depends on the platform and backend
+  (JS is limited to millisecond precision).
 
   Examples:
 
   .. code-block:: nim
-
     import times, os
+    # Simple benchmarking
     let time = cpuTime()
-
-    sleep(100)   # replace this with something to be timed
+    sleep(100)   # Replace this with something to be timed
     echo "Time taken: ", cpuTime() - time
 
-    echo "My formatted time: ", format(now(), "d MMMM yyyy HH:mm")
-    echo "Using predefined formats: ", getClockStr(), " ", getDateStr()
+    # Current date & time
+    let now1 = now()     # Current timestamp as a DateTime in local time
+    let now2 = now().utc # Current timestamp as a DateTime in UTC
+    let now3 = getTime() # Current timestamp as a Time
 
-    echo "cpuTime()  float value: ", cpuTime()
-    echo "An hour from now      : ", now() + 1.hours
-    echo "An hour from (UTC) now: ", getTime().utc + initDuration(hours = 1)
+    # Arithmetic using Duration
+    echo "One hour from now      : ", now() + initDuration(hours = 1)
+    # Arithmetic using TimeInterval
+    echo "One year from now      : ", now() + 1.years
+    echo "One month from now     : ", now() + 1.months
 
   Parsing and Formatting Dates
   ----------------------------
@@ -97,14 +103,14 @@
                                                                                                     | ``24 AD -> 24``
                                                                                                     | ``24 BC -> -23``
                                                                                                     | ``12345 AD -> 12345``
-  ``z``          Displays the timezone offset from UTC.                                             | ``GMT+7 -> +7``
-                                                                                                    | ``GMT-5 -> -5``
-  ``zz``         Same as above but with leading 0.                                                  | ``GMT+7 -> +07``
-                                                                                                    | ``GMT-5 -> -05``
-  ``zzz``        Same as above but with ``:mm`` where *mm* represents minutes.                      | ``GMT+7 -> +07:00``
-                                                                                                    | ``GMT-5 -> -05:00``
-  ``zzzz``       Same as above but with ``:ss`` where *ss* represents seconds.                      | ``GMT+7 -> +07:00:00``
-                                                                                                    | ``GMT-5 -> -05:00:00``
+  ``z``          Displays the timezone offset from UTC.                                             | ``UTC+7 -> +7``
+                                                                                                    | ``UTC-5 -> -5``
+  ``zz``         Same as above but with leading 0.                                                  | ``UTC+7 -> +07``
+                                                                                                    | ``UTC-5 -> -05``
+  ``zzz``        Same as above but with ``:mm`` where *mm* represents minutes.                      | ``UTC+7 -> +07:00``
+                                                                                                    | ``UTC-5 -> -05:00``
+  ``zzzz``       Same as above but with ``:ss`` where *ss* represents seconds.                      | ``UTC+7 -> +07:00:00``
+                                                                                                    | ``UTC-5 -> -05:00:00``
   ``g``          Era: AD or BC                                                                      | ``300 AD -> AD``
                                                                                                     | ``300 BC -> BC``
   ``fff``        Milliseconds display                                                               | ``1000000 nanoseconds -> 1``
@@ -117,72 +123,141 @@
   inserted without quoting them: ``:`` ``-`` ``(`` ``)`` ``/`` ``[`` ``]``
   ``,``. A literal ``'`` can be specified with ``''``.
 
-  However you don't need to necessarily separate format patterns, a
+  However you don't need to necessarily separate format patterns, an
   unambiguous format string like ``yyyyMMddhhmmss`` is valid too (although
   only for years in the range 1..9999).
-]##
-
 
-{.push debugger:off.} # the user does not want to trace a part
-                      # of the standard library!
+  Duration vs TimeInterval
+  ----------------------------
+  The ``times`` module exports two similiar types that are both used to
+  represent some amount of time: ``Duration`` and ``TimeInterval``.
+  This section explains how they differ and when one should be prefered over the
+  other (short answer: use ``Duration`` unless support for months and years is
+  needed).
+
+  Duration
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  A ``Duration`` represents a duration of time stored as seconds and
+  nanoseconds. A ``Duration`` is always fully normalized, so
+``initDuration(hours = 1)`` and ``initDuration(minutes = 60)`` are equivilant.
+
+  Arithmetics with a ``Duration`` is very fast, especially when used with the
+  ``Time`` type, since it only involves basic arithmetic. Because ``Duration``
+  is more performant and easier to understand it should generally prefered.
+
+  TimeInterval
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  A ``TimeInterval`` represents some amount of time expressed in calendar
+  units, for example "1 year and 2 days". Since some units cannot be
+  normalized (the length of a year is different for leap years for example),
+  the ``TimeInterval`` type uses seperate fields for every unit. The
+  ``TimeInterval``'s returned form the this module generally don't normalize
+  **anything**, so even units that could be normalized (like seconds,
+  milliseconds and so on) are left untouched.
+
+  Arithmetics with a ``TimeInterval`` can be very slow, because it requires
+  timezone information.
+
+  Since it's slower and more complex, the ``TimeInterval`` type should be
+  avoided unless the program explicitly needs the features it offers that
+  ``Duration`` doesn't have.
+
+  How long is a day?
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  It should be especially noted that the handling of days differs between
+  ``TimeInterval`` and ``Duration``. The ``Duration`` type always treats a day
+  as exactly 86400 seconds. For ``TimeInterval``, it's more complex.
+
+  As an example, consider the amount of time between these two timestamps, both
+  in the same timezone:
+
+    - 2018-03-25T12:00+02:00
+    - 2018-03-26T12:00+01:00
+
+  If only the date & time is considered, it appears that exatly one day has
+  passed. However, the UTC offsets are different, which means that the
+  UTC offset was changed somewhere between. This happens twice each year for
+  timezones that use daylight savings time. Because of this change, the amount
+  of time that has passed is actually 25 hours.
+
+  The ``TimeInterval`` type uses calendar units, and will say that exactly one
+  day has passed. The ``Duration`` type on the other hand normalizes everything
+  to seconds, and will therefore say that 90000 seconds has passed, which is
+  the same as 25 hours.
+]##
 
-import
-  strutils, parseutils, algorithm, math, options, strformat
+import strutils, algorithm, math, options, strformat
 
 include "system/inclrtl"
 
-# This is really bad, but overflow checks are broken badly for
-# ints on the JS backend. See #6752.
 when defined(JS):
+  import jscore
+
+  # This is really bad, but overflow checks are broken badly for
+  # ints on the JS backend. See #6752.
   {.push overflowChecks: off.}
   proc `*`(a, b: int64): int64 =
-    system.`* `(a, b)
+    system.`*`(a, b)
   proc `*`(a, b: int): int =
-    system.`* `(a, b)
+    system.`*`(a, b)
   proc `+`(a, b: int64): int64 =
-    system.`+ `(a, b)
+    system.`+`(a, b)
   proc `+`(a, b: int): int =
-    system.`+ `(a, b)
+    system.`+`(a, b)
   proc `-`(a, b: int64): int64 =
-    system.`- `(a, b)
+    system.`-`(a, b)
   proc `-`(a, b: int): int =
-    system.`- `(a, b)
+    system.`-`(a, b)
   proc inc(a: var int, b: int) =
     system.inc(a, b)
   proc inc(a: var int64, b: int) =
     system.inc(a, b)
   {.pop.}
 
-when defined(posix):
+elif defined(posix):
   import posix
 
   type CTime = posix.Time
 
   var
     realTimeClockId {.importc: "CLOCK_REALTIME", header: "<time.h>".}: Clockid
-    cpuClockId {.importc: "CLOCK_THREAD_CPUTIME_ID", header: "<time.h>".}: Clockid
+    cpuClockId
+      {.importc: "CLOCK_THREAD_CPUTIME_ID", header: "<time.h>".}: Clockid
 
-  proc gettimeofday(tp: var Timeval, unused: pointer = nil) {.
-    importc: "gettimeofday", header: "<sys/time.h>".}
+  proc gettimeofday(tp: var Timeval, unused: pointer = nil)
+      {.importc: "gettimeofday", header: "<sys/time.h>".}
 
   when not defined(freebsd) and not defined(netbsd) and not defined(openbsd):
     var timezone {.importc, header: "<time.h>".}: int
-    tzset()
+    when not defined(valgrind_workaround_10121):
+      tzset()
 
 elif defined(windows):
-  import winlean
+  import winlean, std/time_t
+
+  type CTime = time_t.Time
 
-  when defined(i386) and defined(gcc):
-    type CTime {.importc: "time_t", header: "<time.h>".} = distinct int32
-  else:
-    # newest version of Visual C++ defines time_t to be of 64 bits
-    type CTime {.importc: "time_t", header: "<time.h>".} = distinct int64
   # visual c's c runtime exposes these under a different name
   var timezone {.importc: "_timezone", header: "<time.h>".}: int
 
+  type
+    Tm {.importc: "struct tm", header: "<time.h>", final, pure.} = object
+      tm_sec*: cint   ## Seconds [0,60].
+      tm_min*: cint   ## Minutes [0,59].
+      tm_hour*: cint  ## Hour [0,23].
+      tm_mday*: cint  ## Day of month [1,31].
+      tm_mon*: cint   ## Month of year [0,11].
+      tm_year*: cint  ## Years since 1900.
+      tm_wday*: cint  ## Day of week [0,6] (Sunday =0).
+      tm_yday*: cint  ## Day of year [0,365].
+      tm_isdst*: cint ## Daylight Savings flag.
+
+  proc localtime(a1: var CTime): ptr Tm {.importc, header: "<time.h>".}
+
 type
-  Month* = enum ## Represents a month. Note that the enum starts at ``1``, so ``ord(month)`` will give
-                ## the month number in the range ``[1..12]``.
+  Month* = enum ## Represents a month. Note that the enum starts at ``1``,
+                ## so ``ord(month)`` will give the month number in the
+                ## range ``1..12``.
     mJan = (1, "January")
     mFeb = "February"
     mMar = "March"
@@ -216,13 +291,19 @@ type
     seconds: int64
     nanosecond: NanosecondRange
 
-  DateTime* = object of RootObj ## Represents a time in different parts.
-                                ## Although this type can represent leap
-                                ## seconds, they are generally not supported
-                                ## in this module. They are not ignored,
-                                ## but the ``DateTime``'s returned by
-                                ## procedures in this module will never have
-                                ## a leap second.
+  DateTime* = object of RootObj ## \
+      ## Represents a time in different parts. Although this type can represent
+      ## leap seconds, they are generally not supported in this module. They are
+      ## not ignored, but the ``DateTime``'s returned by procedures in this
+      ## module will never have a leap second.
+      ##
+      ## **Warning**: even though the fields of ``DateTime`` are exported,
+      ## they should never be mutated directly. Doing so is unsafe and will
+      ## result in the ``DateTime`` ending up in an invalid state.
+      ##
+      ## Instead of mutating the fields directly, use the ``Duration``
+      ## and ``TimeInterval`` types for arithmetic and use the ``initDateTime``
+      ## procedure for changing a specific field.
     nanosecond*: NanosecondRange ## The number of nanoseconds after the second,
                                  ## in the range 0 to 999_999_999.
     second*: SecondRange      ## The number of seconds after the minute,
@@ -233,27 +314,48 @@ type
     hour*: HourRange          ## The number of hours past midnight,
                               ## in the range 0 to 23.
     monthday*: MonthdayRange  ## The day of the month, in the range 1 to 31.
-    month*: Month             ## The current month.
-    year*: int                ## The current year, using astronomical year numbering
-                              ## (meaning that before year 1 is year 0, then year -1 and so on).
-    weekday*: WeekDay         ## The current day of the week.
+    month*: Month             ## The month.
+    year*: int                ## The year, using astronomical year numbering
+                              ## (meaning that before year 1 is year 0,
+                              ## then year -1 and so on).
+    weekday*: WeekDay         ## The day of the week.
     yearday*: YeardayRange    ## The number of days since January 1,
                               ## in the range 0 to 365.
     isDst*: bool              ## Determines whether DST is in effect.
                               ## Always false for the JavaScript backend.
-    timezone*: Timezone       ## The timezone represented as an implementation of ``Timezone``.
-    utcOffset*: int           ## The offset in seconds west of UTC, including any offset due to DST.
-                              ## Note that the sign of this number is the opposite
-                              ## of the one in a formatted offset string like ``+01:00``
-                              ## (which would be parsed into the UTC offset ``-3600``).
-
-  TimeInterval* = object ## Represents a non-fixed duration of time. Can be used to add and subtract
-                         ## non-fixed time units from a ``DateTime`` or ``Time``.
-                         ## ``TimeInterval`` doesn't represent a fixed duration of time,
-                         ## since the duration of some units depend on the context (e.g a year
-                         ## can be either 365 or 366 days long). The non-fixed time units are years,
-                         ## months and days.
+    timezone*: Timezone       ## The timezone represented as an implementation
+                              ## of ``Timezone``.
+    utcOffset*: int           ## The offset in seconds west of UTC, including
+                              ## any offset due to DST. Note that the sign of
+                              ## this number is the opposite of the one in a
+                              ## formatted offset string like ``+01:00`` (which
+                              ## would be equivalent to the UTC offset
+                              ## ``-3600``).
+
+  Duration* = object ## Represents a fixed duration of time, meaning a duration
+                     ## that has constant length independent of the context.
+    seconds: int64
+    nanosecond: NanosecondRange
 
+  TimeUnit* = enum ## Different units of time.
+    Nanoseconds, Microseconds, Milliseconds, Seconds, Minutes, Hours, Days,
+    Weeks, Months, Years
+
+  FixedTimeUnit* = range[Nanoseconds..Weeks] ## \
+      ## Subrange of ``TimeUnit`` that only includes units of fixed duration.
+      ## These are the units that can be represented by a ``Duration``.
+
+  TimeInterval* = object ## \
+      ## Represents a non-fixed duration of time. Can be used to add and
+      ## subtract non-fixed time units from a ``DateTime`` or ``Time``.
+      ## Note that ``TimeInterval`` doesn't represent a fixed duration of time,
+      ## since the duration of some units depend on the context (e.g a year
+      ## can be either 365 or 366 days long). The non-fixed time units are
+      ## years, months, days and week.
+      ##
+      ## Note that ``TimeInterval``'s returned from the ``times`` module are
+      ## never normalized. If you want to normalize a time unit, ``Duration``
+      ## should be used instead.
     nanoseconds*: int  ## The number of nanoseconds
     microseconds*: int ## The number of microseconds
     milliseconds*: int ## The number of milliseconds
@@ -265,19 +367,6 @@ type
     months*: int       ## The number of months
     years*: int        ## The number of years
 
-  Duration* = object ## Represents a fixed duration of time.
-                     ## Uses the same time resolution as ``Time``.
-                     ## This type should be prefered over ``TimeInterval`` unless
-                     ## non-static time units is needed.
-    seconds: int64
-    nanosecond: NanosecondRange
-
-  TimeUnit* = enum ## Different units of time.
-    Nanoseconds, Microseconds, Milliseconds, Seconds, Minutes, Hours, Days, Weeks, Months, Years
-
-  FixedTimeUnit* = range[Nanoseconds..Weeks] ## Subrange of ``TimeUnit`` that only includes units of fixed duration.
-                                             ## These are the units that can be represented by a ``Duration``.
-
   Timezone* = ref object ## \
       ## Timezone interface for supporting ``DateTime``'s of arbritary
       ## timezones. The ``times`` module only supplies implementations for the
@@ -304,7 +393,6 @@ const
   secondsInMin = 60
   secondsInHour = 60*60
   secondsInDay = 60*60*24
-  minutesInHour = 60
   rateDiff = 10000000'i64 # 100 nsecs
   # The number of hectonanoseconds between 1601/01/01 (windows epoch)
   # and 1970/01/01 (unix epoch).
@@ -321,8 +409,10 @@ const unitWeights: array[FixedTimeUnit, int64] = [
   7 * secondsInDay * 1e9.int64,
 ]
 
-proc convert*[T: SomeInteger](unitFrom, unitTo: FixedTimeUnit, quantity: T): T {.inline.} =
+proc convert*[T: SomeInteger](unitFrom, unitTo: FixedTimeUnit, quantity: T): T
+    {.inline.} =
   ## Convert a quantity of some duration unit to another duration unit.
+  ## This proc only deals with integers, so the result might be truncated.
   runnableExamples:
     doAssert convert(Days, Hours, 2) == 48
     doAssert convert(Days, Weeks, 13) == 1 # Truncated
@@ -344,21 +434,41 @@ proc normalize[T: Duration|Time](seconds, nanoseconds: int64): T =
   result.nanosecond = nanosecond.int
 
 # Forward declarations
-proc utcTzInfo(time: Time): ZonedTime {.tags: [], raises: [], benign .}
-proc localZonedTimeFromTime(time: Time): ZonedTime {.tags: [], raises: [], benign .}
-proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime {.tags: [], raises: [], benign .}
+proc utcTzInfo(time: Time): ZonedTime
+    {.tags: [], raises: [], benign.}
+proc localZonedTimeFromTime(time: Time): ZonedTime
+    {.tags: [], raises: [], benign.}
+proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime
+    {.tags: [], raises: [], benign.}
 proc initTime*(unix: int64, nanosecond: NanosecondRange): Time
-  {.tags: [], raises: [], benign noSideEffect.}
-
-proc initDuration*(nanoseconds, microseconds, milliseconds,
-                   seconds, minutes, hours, days, weeks: int64 = 0): Duration
-  {.tags: [], raises: [], benign noSideEffect.}
+    {.tags: [], raises: [], benign, noSideEffect.}
 
 proc nanosecond*(time: Time): NanosecondRange =
   ## Get the fractional part of a ``Time`` as the number
   ## of nanoseconds of the second.
   time.nanosecond
 
+proc initDuration*(nanoseconds, microseconds, milliseconds,
+                   seconds, minutes, hours, days, weeks: int64 = 0): Duration =
+  ## Create a new duration.
+  runnableExamples:
+    let dur = initDuration(seconds = 1, milliseconds = 1)
+    doAssert dur.milliseconds == 1
+    doAssert dur.seconds == 1
+
+  let seconds = convert(Weeks, Seconds, weeks) +
+    convert(Days, Seconds, days) +
+    convert(Minutes, Seconds, minutes) +
+    convert(Hours, Seconds, hours) +
+    convert(Seconds, Seconds, seconds) +
+    convert(Milliseconds, Seconds, milliseconds) +
+    convert(Microseconds, Seconds, microseconds) +
+    convert(Nanoseconds, Seconds, nanoseconds)
+  let nanoseconds = (convert(Milliseconds, Nanoseconds, milliseconds mod 1000) +
+    convert(Microseconds, Nanoseconds, microseconds mod 1_000_000) +
+    nanoseconds mod 1_000_000_000).int
+  # Nanoseconds might be negative so we must normalize.
+  result = normalize[Duration](seconds, nanoseconds)
 
 proc weeks*(dur: Duration): int64 {.inline.} =
   ## Number of whole weeks represented by the duration.
@@ -411,9 +521,10 @@ proc fractional*(dur: Duration): Duration {.inline.} =
     doAssert dur.fractional == initDuration(nanoseconds = 5)
   initDuration(nanoseconds = dur.nanosecond)
 
-
-proc fromUnix*(unix: int64): Time {.benign, tags: [], raises: [], noSideEffect.} =
-  ## Convert a unix timestamp (seconds since ``1970-01-01T00:00:00Z``) to a ``Time``.
+proc fromUnix*(unix: int64): Time
+    {.benign, tags: [], raises: [], noSideEffect.} =
+  ## Convert a unix timestamp (seconds since ``1970-01-01T00:00:00Z``)
+  ## to a ``Time``.
   runnableExamples:
     doAssert $fromUnix(0).utc == "1970-01-01T00:00:00Z"
   initTime(unix, 0)
@@ -425,15 +536,16 @@ proc toUnix*(t: Time): int64 {.benign, tags: [], raises: [], noSideEffect.} =
   t.seconds
 
 proc fromWinTime*(win: int64): Time =
-  ## Convert a Windows file time (100-nanosecond intervals since ``1601-01-01T00:00:00Z``)
-  ## to a ``Time``.
+  ## Convert a Windows file time (100-nanosecond intervals since
+  ## ``1601-01-01T00:00:00Z``) to a ``Time``.
   const hnsecsPerSec = convert(Seconds, Nanoseconds, 1) div 100
   let nanos = floorMod(win, hnsecsPerSec) * 100
   let seconds = floorDiv(win - epochDiff, hnsecsPerSec)
   result = initTime(seconds, nanos)
 
 proc toWinTime*(t: Time): int64 =
-  ## Convert ``t`` to a Windows file time (100-nanosecond intervals since ``1601-01-01T00:00:00Z``).
+  ## Convert ``t`` to a Windows file time (100-nanosecond intervals
+  ## since ``1601-01-01T00:00:00Z``).
   result = t.seconds * rateDiff + epochDiff + t.nanosecond div 100
 
 proc isLeapYear*(year: int): bool =
@@ -441,7 +553,7 @@ proc isLeapYear*(year: int): bool =
   year mod 4 == 0 and (year mod 100 != 0 or year mod 400 == 0)
 
 proc getDaysInMonth*(month: Month, year: int): int =
-  ## Get the number of days in a ``month`` of a ``year``.
+  ## Get the number of days in ``month`` of ``year``.
   # http://www.dispersiondesign.com/articles/time/number_of_days_in_a_month
   case month
   of mFeb: result = if isLeapYear(year): 29 else: 28
@@ -452,15 +564,18 @@ proc getDaysInYear*(year: int): int =
   ## Get the number of days in a ``year``
   result = 365 + (if isLeapYear(year): 1 else: 0)
 
-proc assertValidDate(monthday: MonthdayRange, month: Month, year: int) {.inline.} =
+proc assertValidDate(monthday: MonthdayRange, month: Month, year: int)
+    {.inline.} =
   assert monthday <= getDaysInMonth(month, year),
-    $year & "-" & intToStr(ord(month), 2) & "-" & $monthday & " is not a valid date"
+    $year & "-" & intToStr(ord(month), 2) & "-" & $monthday &
+      " is not a valid date"
 
 proc toEpochDay(monthday: MonthdayRange, month: Month, year: int): int64 =
   ## Get the epoch day from a year/month/day date.
-  ## The epoch day is the number of days since 1970/01/01 (it might be negative).
-  assertValidDate monthday, month, year
+  ## The epoch day is the number of days since 1970/01/01
+  ## (it might be negative).
   # Based on http://howardhinnant.github.io/date_algorithms.html
+  assertValidDate monthday, month, year
   var (y, m, d) = (year, ord(month), monthday.int)
   if m <= 2:
     y.dec
@@ -471,9 +586,11 @@ proc toEpochDay(monthday: MonthdayRange, month: Month, year: int): int64 =
   let doe = yoe * 365 + yoe div 4 - yoe div 100 + doy
   return era * 146097 + doe - 719468
 
-proc fromEpochDay(epochday: int64): tuple[monthday: MonthdayRange, month: Month, year: int] =
+proc fromEpochDay(epochday: int64):
+    tuple[monthday: MonthdayRange, month: Month, year: int] =
   ## Get the year/month/day date from a epoch day.
-  ## The epoch day is the number of days since 1970/01/01 (it might be negative).
+  ## The epoch day is the number of days since 1970/01/01
+  ## (it might be negative).
   # Based on http://howardhinnant.github.io/date_algorithms.html
   var z = epochday
   z.inc 719468
@@ -487,19 +604,23 @@ proc fromEpochDay(epochday: int64): tuple[monthday: MonthdayRange, month: Month,
   let m = mp + (if mp < 10: 3 else: -9)
   return (d.MonthdayRange, m.Month, (y + ord(m <= 2)).int)
 
-proc getDayOfYear*(monthday: MonthdayRange, month: Month, year: int): YeardayRange {.tags: [], raises: [], benign .} =
+proc getDayOfYear*(monthday: MonthdayRange, month: Month, year: int):
+    YeardayRange {.tags: [], raises: [], benign.} =
   ## Returns the day of the year.
   ## Equivalent with ``initDateTime(monthday, month, year, 0, 0, 0).yearday``.
   assertValidDate monthday, month, year
-  const daysUntilMonth:     array[Month, int] = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
-  const daysUntilMonthLeap: array[Month, int] = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]
+  const daysUntilMonth: array[Month, int] =
+    [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
+  const daysUntilMonthLeap: array[Month, int] =
+    [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]
 
   if isLeapYear(year):
     result = daysUntilMonthLeap[month] + monthday - 1
   else:
     result = daysUntilMonth[month] + monthday - 1
 
-proc getDayOfWeek*(monthday: MonthdayRange, month: Month, year: int): WeekDay {.tags: [], raises: [], benign .} =
+proc getDayOfWeek*(monthday: MonthdayRange, month: Month, year: int): WeekDay
+    {.tags: [], raises: [], benign.} =
   ## Returns the day of the week enum from day, month and year.
   ## Equivalent with ``initDateTime(monthday, month, year, 0, 0, 0).weekday``.
   assertValidDate monthday, month, year
@@ -511,8 +632,7 @@ proc getDayOfWeek*(monthday: MonthdayRange, month: Month, year: int): WeekDay {.
   # so we must correct for the WeekDay type.
   result = if wd == 0: dSun else: WeekDay(wd - 1)
 
-
-{. pragma: operator, rtl, noSideEffect, benign .}
+{.pragma: operator, rtl, noSideEffect, benign.}
 
 template subImpl[T: Duration|Time](a: Duration|Time, b: Duration|Time): T =
   normalize[T](a.seconds - b.seconds, a.nanosecond - b.nanosecond)
@@ -530,28 +650,6 @@ template lqImpl(a: Duration|Time, b: Duration|Time): bool =
 
 template eqImpl(a: Duration|Time, b: Duration|Time): bool =
   a.seconds == b.seconds and a.nanosecond == b.nanosecond
-
-proc initDuration*(nanoseconds, microseconds, milliseconds,
-                   seconds, minutes, hours, days, weeks: int64 = 0): Duration =
-  runnableExamples:
-    let dur = initDuration(seconds = 1, milliseconds = 1)
-    doAssert dur.milliseconds == 1
-    doAssert dur.seconds == 1
-
-  let seconds = convert(Weeks, Seconds, weeks) +
-    convert(Days, Seconds, days) +
-    convert(Minutes, Seconds, minutes) +
-    convert(Hours, Seconds, hours) +
-    convert(Seconds, Seconds, seconds) +
-    convert(Milliseconds, Seconds, milliseconds) +
-    convert(Microseconds, Seconds, microseconds) +
-    convert(Nanoseconds, Seconds, nanoseconds)
-  let nanoseconds = (convert(Milliseconds, Nanoseconds, milliseconds mod 1000) +
-    convert(Microseconds, Nanoseconds, microseconds mod 1_000_000) +
-    nanoseconds mod 1_000_000_000).int
-  # Nanoseconds might be negative so we must normalize.
-  result = normalize[Duration](seconds, nanoseconds)
-
 const DurationZero* = initDuration() ## \
   ## Zero value for durations. Useful for comparisons.
   ##
@@ -568,7 +666,7 @@ proc toParts*(dur: Duration): DurationParts =
   ##
   ## This procedure is useful for converting ``Duration`` values to strings.
   runnableExamples:
-    var dp = toParts(initDuration(weeks=2, days=1))
+    var dp = toParts(initDuration(weeks = 2, days = 1))
     doAssert dp[Days] == 1
     doAssert dp[Weeks] == 2
     dp = toParts(initDuration(days = -1))
@@ -620,12 +718,14 @@ proc humanizeParts(parts: seq[string]): string =
     result.add "and " & parts[high(parts)]
 
 proc `$`*(dur: Duration): string =
-  ## Human friendly string representation of ``Duration``.
+  ## Human friendly string representation of a ``Duration``.
   runnableExamples:
     doAssert $initDuration(seconds = 2) == "2 seconds"
     doAssert $initDuration(weeks = 1, days = 2) == "1 week and 2 days"
-    doAssert $initDuration(hours = 1, minutes = 2, seconds = 3) == "1 hour, 2 minutes, and 3 seconds"
-    doAssert $initDuration(milliseconds = -1500) == "-1 second and -500 milliseconds"
+    doAssert $initDuration(hours = 1, minutes = 2, seconds = 3) ==
+      "1 hour, 2 minutes, and 3 seconds"
+    doAssert $initDuration(milliseconds = -1500) ==
+      "-1 second and -500 milliseconds"
   var parts = newSeq[string]()
   var numParts = toParts(dur)
 
@@ -663,7 +763,7 @@ proc `<`*(a, b: Duration): bool {.operator.} =
   ## Use ``abs(a) < abs(b)`` to compare the absolute
   ## duration.
   runnableExamples:
-    doAssert initDuration(seconds =  1) < initDuration(seconds = 2)
+    doAssert initDuration(seconds = 1) < initDuration(seconds = 2)
     doAssert initDuration(seconds = -2) < initDuration(seconds = 1)
   ltImpl(a, b)
 
@@ -673,23 +773,25 @@ proc `<=`*(a, b: Duration): bool {.operator.} =
 proc `==`*(a, b: Duration): bool {.operator.} =
   eqImpl(a, b)
 
-proc `*`*(a: int64, b: Duration): Duration {.operator} =
+proc `*`*(a: int64, b: Duration): Duration {.operator.} =
   ## Multiply a duration by some scalar.
   runnableExamples:
     doAssert 5 * initDuration(seconds = 1) == initDuration(seconds = 5)
   normalize[Duration](a * b.seconds, a * b.nanosecond)
 
-proc `*`*(a: Duration, b: int64): Duration {.operator} =
+proc `*`*(a: Duration, b: int64): Duration {.operator.} =
   ## Multiply a duration by some scalar.
   runnableExamples:
     doAssert initDuration(seconds = 1) * 5 == initDuration(seconds = 5)
   b * a
 
-proc `div`*(a: Duration, b: int64): Duration {.operator} =
+proc `div`*(a: Duration, b: int64): Duration {.operator.} =
   ## Integer division for durations.
   runnableExamples:
-    doAssert initDuration(seconds = 3) div 2 == initDuration(milliseconds = 1500)
-    doAssert initDuration(nanoseconds = 3) div 2 == initDuration(nanoseconds = 1)
+    doAssert initDuration(seconds = 3) div 2 ==
+      initDuration(milliseconds = 1500)
+    doAssert initDuration(nanoseconds = 3) div 2 ==
+      initDuration(nanoseconds = 1)
   let carryOver = convert(Seconds, Nanoseconds, a.seconds mod b)
   normalize[Duration](a.seconds div b, (a.nanosecond + carryOver) div b)
 
@@ -718,7 +820,7 @@ proc `<`*(a, b: Time): bool {.operator, extern: "ntLtTime".} =
   ## Returns true iff ``a < b``, that is iff a happened before b.
   ltImpl(a, b)
 
-proc `<=` * (a, b: Time): bool {.operator, extern: "ntLeTime".} =
+proc `<=`*(a, b: Time): bool {.operator, extern: "ntLeTime".} =
   ## Returns true iff ``a <= b``.
   lqImpl(a, b)
 
@@ -787,8 +889,10 @@ proc initDateTime(zt: ZonedTime, zone: Timezone): DateTime =
 
 proc newTimezone*(
       name: string,
-      zonedTimeFromTimeImpl: proc (time: Time): ZonedTime {.tags: [], raises: [], benign.},
-      zonedTimeFromAdjTimeImpl:  proc (adjTime: Time): ZonedTime {.tags: [], raises: [], benign.}
+      zonedTimeFromTimeImpl: proc (time: Time): ZonedTime
+          {.tags: [], raises: [], benign.},
+      zonedTimeFromAdjTimeImpl: proc (adjTime: Time): ZonedTime
+          {.tags: [], raises: [], benign.}
     ): Timezone =
   ## Create a new ``Timezone``.
   ##
@@ -851,11 +955,13 @@ proc `==`*(zone1, zone2: Timezone): bool =
     doAssert local() != utc()
   zone1.name == zone2.name
 
-proc inZone*(time: Time, zone: Timezone): DateTime {.tags: [], raises: [], benign.} =
+proc inZone*(time: Time, zone: Timezone): DateTime
+    {.tags: [], raises: [], benign.} =
   ## Convert ``time`` into a ``DateTime`` using ``zone`` as the timezone.
   result = initDateTime(zone.zonedTimeFromTime(time), zone)
 
-proc inZone*(dt: DateTime, zone: Timezone): DateTime  {.tags: [], raises: [], benign.} =
+proc inZone*(dt: DateTime, zone: Timezone): DateTime
+    {.tags: [], raises: [], benign.} =
   ## Returns a ``DateTime`` representing the same point in time as ``dt`` but
   ## using ``zone`` as the timezone.
   dt.toTime.inZone(zone)
@@ -869,94 +975,38 @@ proc toAdjTime(dt: DateTime): Time =
   result = initTime(seconds, dt.nanosecond)
 
 when defined(JS):
-    type JsDate = object
-    proc newDate(year, month, date, hours, minutes, seconds, milliseconds: int): JsDate {.tags: [], raises: [], importc: "new Date".}
-    proc newDate(): JsDate {.importc: "new Date".}
-    proc newDate(value: float): JsDate {.importc: "new Date".}
-    proc getTimezoneOffset(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
-    proc getDay(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
-    proc getFullYear(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
-    proc getHours(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
-    proc getMilliseconds(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
-    proc getMinutes(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
-    proc getMonth(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
-    proc getSeconds(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
-    proc getTime(js: JsDate): int {.tags: [], raises: [], noSideEffect, benign, importcpp.}
-    proc getDate(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
-    proc getUTCDate(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
-    proc getUTCFullYear(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
-    proc getUTCHours(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
-    proc getUTCMilliseconds(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
-    proc getUTCMinutes(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
-    proc getUTCMonth(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
-    proc getUTCSeconds(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
-    proc getUTCDay(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
-    proc getYear(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
-    proc setFullYear(js: JsDate, year: int): void {.tags: [], raises: [], benign, importcpp.}
-
-    proc localZonedTimeFromTime(time: Time): ZonedTime =
-      let jsDate = newDate(time.seconds.float * 1000)
-      let offset = jsDate.getTimezoneOffset() * secondsInMin
-      result.time = time
-      result.utcOffset = offset
-      result.isDst = false
-
-    proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime =
-      let utcDate = newDate(adjTime.seconds.float * 1000)
-      let localDate = newDate(utcDate.getUTCFullYear(), utcDate.getUTCMonth(), utcDate.getUTCDate(),
-        utcDate.getUTCHours(), utcDate.getUTCMinutes(), utcDate.getUTCSeconds(), 0)
-
-      # This is as dumb as it looks - JS doesn't support years in the range 0-99 in the constructor
-      # because they are assumed to be 19xx...
-      # Because JS doesn't support timezone history, it doesn't really matter in practice.
-      if utcDate.getUTCFullYear() in 0 .. 99:
-        localDate.setFullYear(utcDate.getUTCFullYear())
-
-      result.utcOffset = localDate.getTimezoneOffset() * secondsInMin
-      result.time = adjTime + initDuration(seconds = result.utcOffset)
-      result.isDst = false
+  proc localZonedTimeFromTime(time: Time): ZonedTime =
+    let jsDate = newDate(time.seconds * 1000)
+    let offset = jsDate.getTimezoneOffset() * secondsInMin
+    result.time = time
+    result.utcOffset = offset
+    result.isDst = false
 
-else:
-  when defined(freebsd) or defined(netbsd) or defined(openbsd) or
-      defined(macosx):
-    type
-      StructTm {.importc: "struct tm".} = object
-        second {.importc: "tm_sec".},
-          minute {.importc: "tm_min".},
-          hour {.importc: "tm_hour".},
-          monthday {.importc: "tm_mday".},
-          month {.importc: "tm_mon".},
-          year {.importc: "tm_year".},
-          weekday {.importc: "tm_wday".},
-          yearday {.importc: "tm_yday".},
-          isdst {.importc: "tm_isdst".}: cint
-        gmtoff {.importc: "tm_gmtoff".}: clong
-  else:
-    type
-      StructTm {.importc: "struct tm".} = object
-        second {.importc: "tm_sec".},
-          minute {.importc: "tm_min".},
-          hour {.importc: "tm_hour".},
-          monthday {.importc: "tm_mday".},
-          month {.importc: "tm_mon".},
-          year {.importc: "tm_year".},
-          weekday {.importc: "tm_wday".},
-          yearday {.importc: "tm_yday".},
-          isdst {.importc: "tm_isdst".}: cint
-        when defined(linux) and defined(amd64) or defined(haiku):
-          gmtoff {.importc: "tm_gmtoff".}: clong
-          zone {.importc: "tm_zone".}: cstring
-  type
-    StructTmPtr = ptr StructTm
+  proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime =
+    let utcDate = newDate(adjTime.seconds * 1000)
+    let localDate = newDate(utcDate.getUTCFullYear(), utcDate.getUTCMonth(),
+        utcDate.getUTCDate(), utcDate.getUTCHours(), utcDate.getUTCMinutes(),
+        utcDate.getUTCSeconds(), 0)
+
+    # This is as dumb as it looks - JS doesn't support years in the range
+    # 0-99 in the constructor because they are assumed to be 19xx...
+    # Because JS doesn't support timezone history,
+    # it doesn't really matter in practice.
+    if utcDate.getUTCFullYear() in 0 .. 99:
+      localDate.setFullYear(utcDate.getUTCFullYear())
 
-  proc localtime(timer: ptr CTime): StructTmPtr {. importc: "localtime", header: "<time.h>", tags: [].}
+    result.utcOffset = localDate.getTimezoneOffset() * secondsInMin
+    result.time = adjTime + initDuration(seconds = result.utcOffset)
+    result.isDst = false
 
-  proc toAdjUnix(tm: StructTm): int64 =
-    let epochDay = toEpochday(tm.monthday, (tm.month + 1).Month, tm.year.int + 1900)
+else:
+  proc toAdjUnix(tm: Tm): int64 =
+    let epochDay = toEpochday(tm.tm_mday, (tm.tm_mon + 1).Month,
+                              tm.tm_year.int + 1900)
     result = epochDay * secondsInDay
-    result.inc tm.hour * secondsInHour
-    result.inc tm.minute * 60
-    result.inc tm.second
+    result.inc tm.tm_hour * secondsInHour
+    result.inc tm.tm_min * 60
+    result.inc tm.tm_sec
 
   proc getLocalOffsetAndDst(unix: int64): tuple[offset: int, dst: bool] =
     # Windows can't handle unix < 0, so we fall back to unix = 0.
@@ -964,7 +1014,7 @@ else:
     when defined(windows):
       if unix < 0:
         var a = 0.CTime
-        let tmPtr = localtime(addr(a))
+        let tmPtr = localtime(a)
         if not tmPtr.isNil:
           let tm = tmPtr[]
           return ((0 - tm.toAdjUnix).int, false)
@@ -973,10 +1023,10 @@ else:
     # In case of a 32-bit time_t, we fallback to the closest available
     # timezone information.
     var a = clamp(unix, low(CTime), high(CTime)).CTime
-    let tmPtr = localtime(addr(a))
+    let tmPtr = localtime(a)
     if not tmPtr.isNil:
       let tm = tmPtr[]
-      return ((a.int64 - tm.toAdjUnix).int, tm.isdst > 0)
+      return ((a.int64 - tm.toAdjUnix).int, tm.tm_isdst > 0)
     return (0, false)
 
   proc localZonedTimeFromTime(time: Time): ZonedTime =
@@ -985,7 +1035,7 @@ else:
     result.utcOffset = offset
     result.isDst = dst
 
-  proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime  =
+  proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime =
     var adjUnix = adjTime.seconds
     let past = adjUnix - secondsInDay
     let (pastOffset, _) = getLocalOffsetAndDst(past)
@@ -995,7 +1045,7 @@ else:
 
     var utcOffset: int
     if pastOffset == futureOffset:
-        utcOffset = pastOffset.int
+      utcOffset = pastOffset.int
     else:
       if pastOffset > futureOffset:
         adjUnix -= secondsInHour
@@ -1029,8 +1079,8 @@ proc utc*(): TimeZone =
 proc local*(): TimeZone =
   ## Get the ``Timezone`` implementation for the local timezone.
   runnableExamples:
-   doAssert now().timezone == local()
-   doAssert local().name == "LOCAL"
+    doAssert now().timezone == local()
+    doAssert local().name == "LOCAL"
   if localInstance.isNil:
     localInstance = newTimezone("LOCAL", localZonedTimeFromTime,
       localZonedTimeFromAdjTime)
@@ -1064,7 +1114,8 @@ proc getTime*(): Time {.tags: [TimeEffect], benign.} =
   elif defined(macosx) or defined(freebsd):
     var a: Timeval
     gettimeofday(a)
-    result = initTime(a.tv_sec.int64, convert(Microseconds, Nanoseconds, a.tv_usec.int))
+    result = initTime(a.tv_sec.int64,
+                      convert(Microseconds, Nanoseconds, a.tv_usec.int))
   elif defined(posix):
     var ts: Timespec
     discard clock_gettime(realTimeClockId, ts)
@@ -1085,13 +1136,17 @@ proc initTimeInterval*(nanoseconds, microseconds, milliseconds,
                        days, weeks, months, years: int = 0): TimeInterval =
   ## Creates a new ``TimeInterval``.
   ##
+  ## This proc doesn't perform any normalization! For example,
+  ## ``initTimeInterval(hours = 24)`` and ``initTimeInterval(days = 1)`` are
+  ## not equal.
+  ##
   ## You can also use the convenience procedures called ``milliseconds``,
   ## ``seconds``, ``minutes``, ``hours``, ``days``, ``months``, and ``years``.
-  ##
   runnableExamples:
-    let day = initTimeInterval(hours=24)
+    let day = initTimeInterval(hours = 24)
     let dt = initDateTime(01, mJan, 2000, 12, 00, 00, utc())
     doAssert $(dt + day) == "2000-01-02T12:00:00Z"
+    doAssert initTimeInterval(hours = 24) != initTimeInterval(days = 1)
   result.nanoseconds = nanoseconds
   result.microseconds = microseconds
   result.milliseconds = milliseconds
@@ -1119,7 +1174,7 @@ proc `+`*(ti1, ti2: TimeInterval): TimeInterval =
 proc `-`*(ti: TimeInterval): TimeInterval =
   ## Reverses a time interval
   runnableExamples:
-    let day = -initTimeInterval(hours=24)
+    let day = -initTimeInterval(hours = 24)
     doAssert day.hours == -24
 
   result = TimeInterval(
@@ -1140,9 +1195,9 @@ proc `-`*(ti1, ti2: TimeInterval): TimeInterval =
   ##
   ## Time components are subtracted one-by-one, see output:
   runnableExamples:
-    let ti1 = initTimeInterval(hours=24)
-    let ti2 = initTimeInterval(hours=4)
-    doAssert (ti1 - ti2) == initTimeInterval(hours=20)
+    let ti1 = initTimeInterval(hours = 24)
+    let ti2 = initTimeInterval(hours = 4)
+    doAssert (ti1 - ti2) == initTimeInterval(hours = 20)
 
   result = ti1 + (-ti2)
 
@@ -1159,13 +1214,13 @@ proc getClockStr*(): string {.rtl, extern: "nt$1", tags: [TimeEffect].} =
     ':' & intToStr(dt.second, 2)
 
 proc toParts* (ti: TimeInterval): TimeIntervalParts =
-  ## Converts a `TimeInterval` into an array consisting of its time units,
-  ## starting with nanoseconds and ending with years
+  ## Converts a ``TimeInterval`` into an array consisting of its time units,
+  ## starting with nanoseconds and ending with years.
   ##
   ## This procedure is useful for converting ``TimeInterval`` values to strings.
   ## E.g. then you need to implement custom interval printing
   runnableExamples:
-    var tp = toParts(initTimeInterval(years=1, nanoseconds=123))
+    var tp = toParts(initTimeInterval(years = 1, nanoseconds = 123))
     doAssert tp[Years] == 1
     doAssert tp[Nanoseconds] == 123
 
@@ -1175,9 +1230,10 @@ proc toParts* (ti: TimeInterval): TimeIntervalParts =
     index += 1
 
 proc `$`*(ti: TimeInterval): string =
-  ## Get string representation of `TimeInterval`
+  ## Get string representation of ``TimeInterval``.
   runnableExamples:
-    doAssert $initTimeInterval(years=1, nanoseconds=123) == "1 year and 123 nanoseconds"
+    doAssert $initTimeInterval(years = 1, nanoseconds = 123) ==
+      "1 year and 123 nanoseconds"
     doAssert $initTimeInterval() == "0 nanoseconds"
 
   var parts: seq[string] = @[]
@@ -1203,7 +1259,7 @@ proc milliseconds*(ms: int): TimeInterval {.inline.} =
 proc seconds*(s: int): TimeInterval {.inline.} =
   ## TimeInterval of ``s`` seconds.
   ##
-  ## ``echo getTime() + 5.second``
+  ## ``echo getTime() + 5.seconds``
   initTimeInterval(seconds = s)
 
 proc minutes*(m: int): TimeInterval {.inline.} =
@@ -1242,7 +1298,8 @@ proc years*(y: int): TimeInterval {.inline.} =
   ## ``echo getTime() + 2.years``
   initTimeInterval(years = y)
 
-proc evaluateInterval(dt: DateTime, interval: TimeInterval): tuple[adjDur, absDur: Duration] =
+proc evaluateInterval(dt: DateTime, interval: TimeInterval):
+    tuple[adjDur, absDur: Duration] =
   ## Evaluates how many nanoseconds the interval is worth
   ## in the context of ``dt``.
   ## The result in split into an adjusted diff and an absolute diff.
@@ -1281,10 +1338,10 @@ proc evaluateInterval(dt: DateTime, interval: TimeInterval): tuple[adjDur, absDu
     minutes = interval.minutes,
     hours = interval.hours)
 
-
 proc initDateTime*(monthday: MonthdayRange, month: Month, year: int,
                    hour: HourRange, minute: MinuteRange, second: SecondRange,
-                   nanosecond: NanosecondRange, zone: Timezone = local()): DateTime =
+                   nanosecond: NanosecondRange,
+                   zone: Timezone = local()): DateTime =
   ## Create a new ``DateTime`` in the specified timezone.
   runnableExamples:
     let dt1 = initDateTime(30, mMar, 2017, 00, 00, 00, 00, utc())
@@ -1292,12 +1349,12 @@ proc initDateTime*(monthday: MonthdayRange, month: Month, year: int,
 
   assertValidDate monthday, month, year
   let dt = DateTime(
-    monthday:  monthday,
-    year:  year,
-    month:  month,
-    hour:  hour,
-    minute:  minute,
-    second:  second,
+    monthday: monthday,
+    year: year,
+    month: month,
+    hour: hour,
+    minute: minute,
+    second: second,
     nanosecond: nanosecond
   )
   result = initDateTime(zone.zonedTimeFromAdjTime(dt.toAdjTime), zone)
@@ -1314,14 +1371,15 @@ proc initDateTime*(monthday: MonthdayRange, month: Month, year: int,
 
 proc `+`*(dt: DateTime, interval: TimeInterval): DateTime =
   ## Adds ``interval`` to ``dt``. Components from ``interval`` are added
-  ## in the order of their size, i.e first the ``years`` component, then the ``months``
-  ## component and so on. The returned ``DateTime`` will have the same timezone as the input.
-  ##
-  ## Note that when adding months, monthday overflow is allowed. This means that if the resulting
-  ## month doesn't have enough days it, the month will be incremented and the monthday will be
-  ## set to the number of days overflowed. So adding one month to `31 October` will result in `31 November`,
-  ## which will overflow and result in `1 December`.
+  ## in the order of their size, i.e first the ``years`` component, then the
+  ## ``months`` component and so on. The returned ``DateTime`` will have the
+  ## same timezone as the input.
   ##
+  ## Note that when adding months, monthday overflow is allowed. This means that
+  ## if the resulting month doesn't have enough days it, the month will be
+  ## incremented and the monthday will be set to the number of days overflowed.
+  ## So adding one month to `31 October` will result in `31 November`, which
+  ## will overflow and result in `1 December`.
   runnableExamples:
     let dt = initDateTime(30, mMar, 2017, 00, 00, 00, utc())
     doAssert $(dt + 1.months) == "2017-04-30T00:00:00Z"
@@ -1341,9 +1399,10 @@ proc `+`*(dt: DateTime, interval: TimeInterval): DateTime =
     result = initDateTime(zt, dt.timezone)
 
 proc `-`*(dt: DateTime, interval: TimeInterval): DateTime =
-  ## Subtract ``interval`` from ``dt``. Components from ``interval`` are subtracted
-  ## in the order of their size, i.e first the ``years`` component, then the ``months``
-  ## component and so on. The returned ``DateTime`` will have the same timezone as the input.
+  ## Subtract ``interval`` from ``dt``. Components from ``interval`` are
+  ## subtracted in the order of their size, i.e first the ``years`` component,
+  ## then the ``months`` component and so on. The returned ``DateTime`` will
+  ## have the same timezone as the input.
   runnableExamples:
     let dt = initDateTime(30, mMar, 2017, 00, 00, 00, utc())
     doAssert $(dt - 5.days) == "2017-03-25T00:00:00Z"
@@ -1377,15 +1436,15 @@ proc `-`*(dt1, dt2: DateTime): Duration =
   dt1.toTime - dt2.toTime
 
 proc `<`*(a, b: DateTime): bool =
-  ## Returns true iff ``a < b``, that is iff a happened before b.
+  ## Returns true iff ``a`` happened before ``b``.
   return a.toTime < b.toTime
 
-proc `<=` * (a, b: DateTime): bool =
-  ## Returns true iff ``a <= b``.
+proc `<=`*(a, b: DateTime): bool =
+  ## Returns true iff ``a`` happened before or at the same time as ``b``.
   return a.toTime <= b.toTime
 
 proc `==`*(a, b: DateTime): bool =
-  ## Returns true if ``a == b``, that is if both dates represent the same point in time.
+  ## Returns true iff ``a`` and ``b`` represent the same point in time.
   return a.toTime == b.toTime
 
 proc isStaticInterval(interval: TimeInterval): bool =
@@ -1486,8 +1545,8 @@ proc between*(startDt, endDt: DateTime): TimeInterval =
 
   #Months
   if endDt.month < startDt.month:
-      result.months = endDt.month.int() + 12 - startDt.month.int()
-      endDt.year -= 1
+    result.months = endDt.month.int() + 12 - startDt.month.int()
+    endDt.year -= 1
   else:
     result.months = endDt.month.int() -
       startDt.month.int()
@@ -1602,7 +1661,13 @@ type
       ## be encoded as ``@[Lit.byte, 3.byte, 'f'.byte, 'o'.byte, 'o'.byte]``.
     formatStr: string
 
-const FormatLiterals = { ' ', '-', '/', ':', '(', ')', '[', ']', ',' }
+  TimeParseError* = object of ValueError ## \
+    ## Raised when parsing input using a ``TimeFormat`` fails.
+
+  TimeFormatParseError* = object of ValueError ## \
+    ## Raised when parsing a ``TimeFormat`` string fails.
+
+const FormatLiterals = {' ', '-', '/', ':', '(', ')', '[', ']', ','}
 
 proc `$`*(f: TimeFormat): string =
   ## Returns the format string that was used to construct ``f``.
@@ -1612,9 +1677,34 @@ proc `$`*(f: TimeFormat): string =
   f.formatStr
 
 proc raiseParseException(f: TimeFormat, input: string, msg: string) =
-  raise newException(ValueError,
+  raise newException(TimeParseError,
                      &"Failed to parse '{input}' with format '{f}'. {msg}")
 
+proc parseInt(s: string, b: var int, start = 0, maxLen = int.high,
+              allowSign = false): int =
+  var sign = -1
+  var i = start
+  let stop = start + min(s.high - start + 1, maxLen) - 1
+  if allowSign and i <= stop:
+    if s[i] == '+':
+      inc(i)
+    elif s[i] == '-':
+      inc(i)
+      sign = 1
+  if i <= stop and s[i] in {'0'..'9'}:
+    b = 0
+    while i <= stop and s[i] in {'0'..'9'}:
+      let c = ord(s[i]) - ord('0')
+      if b >= (low(int) + c) div 10:
+        b = b * 10 - c
+      else:
+        return 0
+      inc(i)
+    if sign == -1 and b == low(int):
+      return 0
+    b = b * sign
+    result = i - start
+
 iterator tokens(f: string): tuple[kind: FormatTokenKind, token: string] =
   var i = 0
   var currToken = ""
@@ -1639,15 +1729,15 @@ iterator tokens(f: string): tuple[kind: FormatTokenKind, token: string] =
           i.inc
 
         if i > f.high:
-          raise newException(ValueError,
+          raise newException(TimeFormatParseError,
                              &"Unclosed ' in time format string. " &
                              "For a literal ', use ''.")
         i.inc
         yield (tkLiteral, token)
     of FormatLiterals:
-        yieldCurrToken()
-        yield (tkLiteral, $f[i])
-        i.inc
+      yieldCurrToken()
+      yield (tkLiteral, $f[i])
+      i.inc
     else:
       # Check if the letter being added matches previous accumulated buffer.
       if currToken.len == 0 or currToken[0] == f[i]:
@@ -1696,7 +1786,8 @@ proc stringToPattern(str: string): FormatPattern =
   of "zzz": result = zzz
   of "zzzz": result = zzzz
   of "g": result = g
-  else: raise newException(ValueError, &"'{str}' is not a valid pattern")
+  else: raise newException(TimeFormatParseError,
+                           &"'{str}' is not a valid pattern")
 
 proc initTimeFormat*(format: string): TimeFormat =
   ## Construct a new time format for parsing & formatting time types.
@@ -1715,7 +1806,7 @@ proc initTimeFormat*(format: string): TimeFormat =
       else:
         result.patterns.add(FormatPattern.Lit.byte)
         if token.len > 255:
-          raise newException(ValueError,
+          raise newException(TimeFormatParseError,
                              "Format literal is to long:" & token)
         result.patterns.add(token.len.byte)
         for c in token:
@@ -1804,12 +1895,12 @@ proc formatPattern(dt: DateTime, pattern: FormatPattern, result: var string) =
     else:
       result.add '+' & $year
   of UUUU:
-      result.add $dt.year
+    result.add $dt.year
   of z, zz, zzz, zzzz:
     if dt.timezone != nil and dt.timezone.name == "Etc/UTC":
       result.add 'Z'
     else:
-      result.add  if -dt.utcOffset >= 0: '+' else: '-'
+      result.add if -dt.utcOffset >= 0: '+' else: '-'
       let absOffset = abs(dt.utcOffset)
       case pattern:
       of z:
@@ -1828,20 +1919,15 @@ proc formatPattern(dt: DateTime, pattern: FormatPattern, result: var string) =
         result.add h & ":" & m & ":" & s
       else: assert false
   of g:
-      result.add if dt.year < 1: "BC" else: "AD"
+    result.add if dt.year < 1: "BC" else: "AD"
   of Lit: assert false # Can't happen
 
 proc parsePattern(input: string, pattern: FormatPattern, i: var int,
                   parsed: var ParsedTime): bool =
-  template takeInt(allowedWidth: Slice[int]): int =
+  template takeInt(allowedWidth: Slice[int], allowSign = false): int =
     var sv: int
-    let max = i + allowedWidth.b - 1
-    var pd =
-      if max > input.high:
-        parseInt(input, sv, i)
-      else:
-        parseInt(input[i..max], sv)
-    if pd notin allowedWidth:
+    var pd = parseInt(input, sv, i, allowedWidth.b, allowSign)
+    if pd < allowedWidth.a:
       return false
     i.inc pd
     sv
@@ -1853,11 +1939,13 @@ proc parsePattern(input: string, pattern: FormatPattern, i: var int,
 
   case pattern
   of d:
-    parsed.monthday = some(takeInt(1..2))
-    result = parsed.monthday.get() in MonthdayRange
+    let monthday = takeInt(1..2)
+    parsed.monthday = some(monthday)
+    result = monthday in MonthdayRange
   of dd:
-    parsed.monthday = some(takeInt(2..2))
-    result = parsed.monthday.get() in MonthdayRange
+    let monthday = takeInt(2..2)
+    parsed.monthday = some(monthday)
+    result = monthday in MonthdayRange
   of ddd:
     result = input.substr(i, i+2).toLowerAscii() in [
       "sun", "mon", "tue", "wed", "thu", "fri", "sat"]
@@ -1992,8 +2080,8 @@ proc parsePattern(input: string, pattern: FormatPattern, i: var int,
     result = year > 0
   of yyyy:
     let year =
-      if input[i] in { '+', '-' }:
-        takeInt(4..high(int))
+      if input[i] in {'+', '-'}:
+        takeInt(4..high(int), allowSign = true)
       else:
         takeInt(4..4)
     result = year > 0
@@ -2004,13 +2092,13 @@ proc parsePattern(input: string, pattern: FormatPattern, i: var int,
     result = year > 0
   of uuuu:
     let year =
-      if input[i] in { '+', '-' }:
-        takeInt(4..high(int))
+      if input[i] in {'+', '-'}:
+        takeInt(4..high(int), allowSign = true)
       else:
         takeInt(4..4)
     parsed.year = some(year)
   of UUUU:
-    parsed.year = some(takeInt(1..high(int)))
+    parsed.year = some(takeInt(1..high(int), allowSign = true))
   of z, zz, zzz, zzzz:
     case input[i]
     of '+', '-':
@@ -2055,9 +2143,8 @@ proc parsePattern(input: string, pattern: FormatPattern, i: var int,
     else:
       result = false
   of y, yyy, yyyyy:
-    raise newException(ValueError,
-                      &"The pattern '{pattern}' is only valid for formatting")
-  of Lit: assert false # Can't happen
+    raiseAssert "Pattern is invalid for parsing: " & $pattern
+  of Lit: doAssert false, "Can't happen"
 
 proc toDateTime(p: ParsedTime, zone: Timezone, f: TimeFormat,
                 input: string): DateTime =
@@ -2147,7 +2234,8 @@ proc format*(dt: DateTime, f: TimeFormat): string {.raises: [].} =
       formatPattern(dt, f.patterns[idx].FormatPattern, result = result)
       idx.inc
 
-proc format*(dt: DateTime, f: string): string =
+proc format*(dt: DateTime, f: string): string
+    {.raises: [TimeFormatParseError].} =
   ## Shorthand for constructing a ``TimeFormat`` and using it to format ``dt``.
   ##
   ## See `Parsing and formatting dates`_ for documentation of the
@@ -2163,7 +2251,8 @@ proc format*(dt: DateTime, f: static[string]): string {.raises: [].} =
   const f2 = initTimeFormat(f)
   result = dt.format(f2)
 
-proc format*(time: Time, f: string, zone: Timezone = local()): string {.tags: [].} =
+proc format*(time: Time, f: string, zone: Timezone = local()): string
+    {.raises: [TimeFormatParseError].} =
   ## Shorthand for constructing a ``TimeFormat`` and using it to format
   ## ``time``. Will use the timezone specified by ``zone``.
   ##
@@ -2175,13 +2264,14 @@ proc format*(time: Time, f: string, zone: Timezone = local()): string {.tags: []
     doAssert format(tm, "yyyy-MM-dd'T'HH:mm:ss", utc()) == "1970-01-01T00:00:00"
   time.inZone(zone).format(f)
 
-proc format*(time: Time, f: static[string],
-             zone: Timezone = local()): string {.tags: [].} =
+proc format*(time: Time, f: static[string], zone: Timezone = local()): string
+    {.raises: [].} =
   ## Overload that validates ``f`` at compile time.
   const f2 = initTimeFormat(f)
   result = time.inZone(zone).format(f2)
 
-proc parse*(input: string, f: TimeFormat, zone: Timezone = local()): DateTime =
+proc parse*(input: string, f: TimeFormat, zone: Timezone = local()): DateTime
+    {.raises: [TimeParseError, Defect].} =
   ## Parses ``input`` as a ``DateTime`` using the format specified by ``f``.
   ## If no UTC offset was parsed, then ``input`` is assumed to be specified in
   ## the ``zone`` timezone. If a UTC offset was parsed, the result will be
@@ -2217,11 +2307,12 @@ proc parse*(input: string, f: TimeFormat, zone: Timezone = local()): DateTime =
 
   if patIdx <= f.patterns.high:
     raiseParseException(f, input,
-                        "Parsing ended but there was still patterns remaining")
+                            "Parsing ended but there was still patterns remaining")
 
   result = toDateTime(parsed, zone, f, input)
 
-proc parse*(input, f: string, tz: Timezone = local()): DateTime =
+proc parse*(input, f: string, tz: Timezone = local()): DateTime
+    {.raises: [TimeParseError, TimeFormatParseError, Defect].} =
   ## Shorthand for constructing a ``TimeFormat`` and using it to parse
   ## ``input`` as a ``DateTime``.
   ##
@@ -2233,12 +2324,14 @@ proc parse*(input, f: string, tz: Timezone = local()): DateTime =
   let dtFormat = initTimeFormat(f)
   result = input.parse(dtFormat, tz)
 
-proc parse*(input: string, f: static[string], zone: Timezone = local()): DateTime =
+proc parse*(input: string, f: static[string], zone: Timezone = local()):
+    DateTime {.raises: [TimeParseError, Defect].} =
   ## Overload that validates ``f`` at compile time.
   const f2 = initTimeFormat(f)
   result = input.parse(f2, zone)
 
-proc parseTime*(input, f: string, zone: Timezone): Time =
+proc parseTime*(input, f: string, zone: Timezone): Time
+    {.raises: [TimeParseError, TimeFormatParseError, Defect].} =
   ## Shorthand for constructing a ``TimeFormat`` and using it to parse
   ## ``input`` as a ``DateTime``, then converting it a ``Time``.
   ##
@@ -2249,7 +2342,8 @@ proc parseTime*(input, f: string, zone: Timezone): Time =
     doAssert parseTime(tStr, "yyyy-MM-dd'T'HH:mm:sszzz", utc()) == fromUnix(0)
   parse(input, f, zone).toTime()
 
-proc parseTime*(input: string, f: static[string], zone: Timezone): Time =
+proc parseTime*(input: string, f: static[string], zone: Timezone): Time
+    {.raises: [TimeParseError, Defect].} =
   ## Overload that validates ``format`` at compile time.
   const f2 = initTimeFormat(f)
   result = input.parse(f2, zone).toTime()
@@ -2267,7 +2361,7 @@ proc `$`*(dt: DateTime): string {.tags: [], raises: [], benign.} =
   result = format(dt, "yyyy-MM-dd'T'HH:mm:sszzz")
 
 proc `$`*(time: Time): string {.tags: [], raises: [], benign.} =
-  ## converts a `Time` value to a string representation. It will use the local
+  ## Converts a `Time` value to a string representation. It will use the local
   ## time zone and use the format ``yyyy-MM-dd'T'HH-mm-sszzz``.
   runnableExamples:
     let dt = initDateTime(01, mJan, 1970, 00, 00, 00, local())
@@ -2275,8 +2369,6 @@ proc `$`*(time: Time): string {.tags: [], raises: [], benign.} =
     doAssert $tm == "1970-01-01T00:00:00" & format(dt, "zzz")
   $time.local
 
-{.pop.}
-
 proc countLeapYears*(yearSpan: int): int =
   ## Returns the number of leap years spanned by a given number of years.
   ##
@@ -2318,7 +2410,8 @@ when not defined(JS):
   type
     Clock {.importc: "clock_t".} = distinct int
 
-  proc getClock(): Clock {.importc: "clock", header: "<time.h>", tags: [TimeEffect].}
+  proc getClock(): Clock
+      {.importc: "clock", header: "<time.h>", tags: [TimeEffect].}
 
   var
     clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
@@ -2376,59 +2469,68 @@ when defined(JS):
 # Deprecated procs
 
 when not defined(JS):
-  proc unixTimeToWinTime*(time: CTime): int64 {.deprecated: "Use toWinTime instead".} =
+  proc unixTimeToWinTime*(time: CTime): int64
+      {.deprecated: "Use toWinTime instead".} =
     ## Converts a UNIX `Time` (``time_t``) to a Windows file time
     ##
     ## **Deprecated:** use ``toWinTime`` instead.
     result = int64(time) * rateDiff + epochDiff
 
-  proc winTimeToUnixTime*(time: int64): CTime {.deprecated: "Use fromWinTime instead".} =
+  proc winTimeToUnixTime*(time: int64): CTime
+      {.deprecated: "Use fromWinTime instead".} =
     ## Converts a Windows time to a UNIX `Time` (``time_t``)
     ##
     ## **Deprecated:** use ``fromWinTime`` instead.
     result = CTime((time - epochDiff) div rateDiff)
 
-proc initInterval*(seconds, minutes, hours, days, months,
-                   years: int = 0): TimeInterval {.deprecated.} =
+proc initInterval*(seconds, minutes, hours, days, months, years: int = 0):
+    TimeInterval {.deprecated.} =
   ## **Deprecated since v0.18.0:** use ``initTimeInterval`` instead.
   initTimeInterval(0, 0, 0, seconds, minutes, hours, days, 0, months, years)
 
-proc fromSeconds*(since1970: float): Time {.tags: [], raises: [], benign, deprecated.} =
+proc fromSeconds*(since1970: float): Time
+    {.tags: [], raises: [], benign, deprecated.} =
   ## Takes a float which contains the number of seconds since the unix epoch and
   ## returns a time object.
   ##
   ## **Deprecated since v0.18.0:** use ``fromUnix`` instead
-  let nanos = ((since1970 - since1970.int64.float) * convert(Seconds, Nanoseconds, 1).float).int
+  let nanos = ((since1970 - since1970.int64.float) *
+    convert(Seconds, Nanoseconds, 1).float).int
   initTime(since1970.int64, nanos)
 
-proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], benign, deprecated.} =
+proc fromSeconds*(since1970: int64): Time
+    {.tags: [], raises: [], benign, deprecated.} =
   ## Takes an int which contains the number of seconds since the unix epoch and
   ## returns a time object.
   ##
   ## **Deprecated since v0.18.0:** use ``fromUnix`` instead
   fromUnix(since1970)
 
-proc toSeconds*(time: Time): float {.tags: [], raises: [], benign, deprecated.} =
+proc toSeconds*(time: Time): float
+    {.tags: [], raises: [], benign, deprecated.} =
   ## Returns the time in seconds since the unix epoch.
   ##
   ## **Deprecated since v0.18.0:** use ``toUnix`` instead
   time.seconds.float + time.nanosecond / convert(Seconds, Nanoseconds, 1)
 
-proc getLocalTime*(time: Time): DateTime {.tags: [], raises: [], benign, deprecated.} =
+proc getLocalTime*(time: Time): DateTime
+    {.tags: [], raises: [], benign, deprecated.} =
   ## Converts the calendar time `time` to broken-time representation,
   ## expressed relative to the user's specified time zone.
   ##
   ## **Deprecated since v0.18.0:** use ``local`` instead
   time.local
 
-proc getGMTime*(time: Time): DateTime {.tags: [], raises: [], benign, deprecated.} =
+proc getGMTime*(time: Time): DateTime
+      {.tags: [], raises: [], benign, deprecated.} =
   ## Converts the calendar time `time` to broken-down time representation,
   ## expressed in Coordinated Universal Time (UTC).
   ##
   ## **Deprecated since v0.18.0:** use ``utc`` instead
   time.utc
 
-proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign, deprecated.} =
+proc getTimezone*(): int
+    {.tags: [TimeEffect], raises: [], benign, deprecated.} =
   ## Returns the offset of the local (non-DST) timezone in seconds west of UTC.
   ##
   ## **Deprecated since v0.18.0:** use ``now().utcOffset`` to get the current
@@ -2436,45 +2538,14 @@ proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign, deprecated.}
   when defined(JS):
     return newDate().getTimezoneOffset() * 60
   elif defined(freebsd) or defined(netbsd) or defined(openbsd):
-    var a: CTime
-    discard time(a)
-    let lt = localtime(addr(a))
-    # BSD stores in `gmtoff` offset east of UTC in seconds,
-    # but posix systems using west of UTC in seconds
-    return -(lt.gmtoff)
+    # This is wrong since it will include DST offsets, but the behavior has
+    # always been wrong for bsd and the proc is deprecated so lets ignore it.
+    return now().utcOffset
   else:
     return timezone
 
-proc timeInfoToTime*(dt: DateTime): Time {.tags: [], benign, deprecated.} =
-  ## Converts a broken-down time structure to calendar time representation.
-  ##
-  ## **Deprecated since v0.14.0:** use ``toTime`` instead.
-  dt.toTime
-
-when defined(JS):
-  var start = getTime()
-  proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], benign.} =
-    let dur = getTime() - start
-    result = (convert(Seconds, Milliseconds, dur.seconds) +
-      convert(Nanoseconds, Milliseconds, dur.nanosecond)).int
-else:
-  proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], benign.} =
-    ## get the milliseconds from the start of the program.
-    ##
-    ## **Deprecated since v0.8.10:** use ``epochTime`` or ``cpuTime`` instead.
-    when defined(macosx):
-      result = toInt(toFloat(int(getClock())) / (toFloat(clocksPerSec) / 1000.0))
-    else:
-      result = int(getClock()) div (clocksPerSec div 1000)
-
-proc timeToTimeInterval*(t: Time): TimeInterval {.deprecated.} =
-  ## Converts a Time to a TimeInterval.
-  ##
-  ## **Deprecated since v0.14.0:** use ``toTimeInterval`` instead.
-  # Milliseconds not available from Time
-  t.toTimeInterval()
-
-proc getDayOfWeek*(day, month, year: int): WeekDay  {.tags: [], raises: [], benign, deprecated.} =
+proc getDayOfWeek*(day, month, year: int): WeekDay
+    {.tags: [], raises: [], benign, deprecated.} =
   ## **Deprecated since v0.18.0:** use
   ## ``getDayOfWeek(monthday: MonthdayRange; month: Month; year: int)`` instead.
   getDayOfWeek(day, month.Month, year)
diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim
index c53b68864..a373a9370 100644
--- a/lib/pure/typetraits.nim
+++ b/lib/pure/typetraits.nim
@@ -10,30 +10,13 @@
 ## This module defines compile-time reflection procs for
 ## working with types
 
-proc name*(t: typedesc): string {.magic: "TypeTrait".}
-  ## Returns the name of the given type.
-  ##
-  ## Example:
-  ##
-  ## .. code-block::
-  ##
-  ##   import typetraits
-  ##
-  ##   proc `$`*(T: typedesc): string = name(T)
-  ##
-  ##   template test(x): typed =
-  ##     echo "type: ", type(x), ", value: ", x
-  ##
-  ##   test 42
-  ##   # --> type: int, value: 42
-  ##   test "Foo"
-  ##   # --> type: string, value: Foo
-  ##   test(@['A','B'])
-  ##   # --> type: seq[char], value: @[A, B]
+include "system/helpers" # for `isNamedTuple`
+
+export system.`$`
+export isNamedTuple
 
-proc `$`*(t: typedesc): string =
-  ## An alias for `name`.
-  name(t)
+proc name*(t: typedesc): string {.magic: "TypeTrait".}
+  ## Alias for system.`$`(t) since Nim v0.20.0.
 
 proc arity*(t: typedesc): int {.magic: "TypeTrait".} =
   ## Returns the arity of the given type. This is the number of "type" components or
@@ -64,4 +47,22 @@ proc supportsCopyMem*(t: typedesc): bool {.magic: "TypeTrait".}
 
 
 when isMainModule:
-  doAssert $type(42) == "int"
+  static:
+    doAssert $type(42) == "int"
+    doAssert int.name == "int"
+
+  const a1 = name(int)
+  const a2 = $(int)
+  const a3 = $int
+  doAssert a1 == "int"
+  doAssert a2 == "int"
+  doAssert a3 == "int"
+
+  proc fun[T: typedesc](t: T) =
+    const a1 = name(t)
+    const a2 = $(t)
+    const a3 = $t
+    doAssert a1 == "int"
+    doAssert a2 == "int"
+    doAssert a3 == "int"
+  fun(int)
diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim
index 712cc46c8..27eabecc6 100644
--- a/lib/pure/unicode.nim
+++ b/lib/pure/unicode.nim
@@ -8,6 +8,11 @@
 #
 
 ## This module provides support to handle the Unicode UTF-8 encoding.
+##
+## There are no specialized ``insert``, ``delete``, ``add`` and ``contains``
+## procedures for ``seq[Rune]`` in this module because the generic variants
+## of these procedures in the system module already work with it.
+
 
 {.deadCodeElim: on.}  # dce option deprecated
 
@@ -15,7 +20,7 @@ include "system/inclrtl"
 
 type
   RuneImpl = int32 # underlying type of Rune
-  Rune* = distinct RuneImpl   ## type that can hold any Unicode character
+  Rune* = distinct RuneImpl ## Unicode code point. Can hold any Unicode character.
   Rune16* = distinct int16 ## 16 bit Unicode character
 
 proc `<=%`*(a, b: Rune): bool = return int(a) <=% int(b)
@@ -25,7 +30,12 @@ proc `==`*(a, b: Rune): bool = return int(a) == int(b)
 template ones(n: untyped): untyped = ((1 shl n)-1)
 
 proc runeLen*(s: string): int {.rtl, extern: "nuc$1".} =
-  ## Returns the number of Unicode characters of the string ``s``
+  ## Returns the number of runes of the string ``s``.
+  runnableExamples:
+    let a = "añyóng"
+    doAssert a.runeLen == 6
+    ## note: a.len == 8
+
   var i = 0
   while i < len(s):
     if ord(s[i]) <=% 127: inc(i)
@@ -38,7 +48,12 @@ proc runeLen*(s: string): int {.rtl, extern: "nuc$1".} =
     inc(result)
 
 proc runeLenAt*(s: string, i: Natural): int =
-  ## Returns the number of bytes the rune starting at ``s[i]`` takes
+  ## Returns the number of bytes the rune starting at ``s[i]`` takes.
+  runnableExamples:
+    let a = "añyóng"
+    doAssert a.runeLenAt(0) == 1
+    doAssert a.runeLenAt(1) == 2
+
   if ord(s[i]) <=% 127: result = 1
   elif ord(s[i]) shr 5 == 0b110: result = 2
   elif ord(s[i]) shr 4 == 0b1110: result = 3
@@ -50,7 +65,7 @@ proc runeLenAt*(s: string, i: Natural): int =
 const replRune = Rune(0xFFFD)
 
 template fastRuneAt*(s: string, i: int, result: untyped, doInc = true) =
-  ## Returns the Unicode character ``s[i]`` in ``result``. If ``doInc == true``
+  ## Returns the rune ``s[i]`` in ``result``. If ``doInc == true``
   ## ``i`` is incremented by the number of bytes that have been processed.
   bind ones
   if ord(s[i]) <=% 127:
@@ -152,17 +167,21 @@ proc validateUtf8*(s: string): int =
   return -1
 
 proc runeAt*(s: string, i: Natural): Rune =
-  ## Returns the unicode character in ``s`` at byte index ``i``
+  ## Returns the rune in ``s`` at **byte index** ``i``.
+  runnableExamples:
+    let a = "añyóng"
+    doAssert a.runeAt(1) == "ñ".runeAt(0)
+    doAssert a.runeAt(2) == "ñ".runeAt(1)
+    doAssert a.runeAt(3) == "y".runeAt(0)
   fastRuneAt(s, i, result, false)
 
 template fastToUTF8Copy*(c: Rune, s: var string, pos: int, doInc = true) =
-  ## Copies UTF-8 representation of `c` into the preallocated string `s`
-  ## starting at position `pos`. If `doInc == true`, `pos` is incremented
+  ## Copies UTF-8 representation of ``c`` into the preallocated string ``s``
+  ## starting at position ``pos``. If ``doInc == true``, ``pos`` is incremented
   ## by the number of bytes that have been processed.
   ##
-  ## To be the most efficient, make sure `s` is preallocated
-  ## with an additional amount equal to the byte length of
-  ## `c`.
+  ## To be the most efficient, make sure ``s`` is preallocated
+  ## with an additional amount equal to the byte length of ``c``.
   var i = RuneImpl(c)
   if i <=% 127:
     s.setLen(pos+1)
@@ -207,28 +226,39 @@ template fastToUTF8Copy*(c: Rune, s: var string, pos: int, doInc = true) =
     discard # error, exception?
 
 proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} =
-  ## Converts a rune into its UTF-8 representation
+  ## Converts a rune into its UTF-8 representation.
+  runnableExamples:
+    let a = "añyóng"
+    doAssert a.runeAt(1).toUTF8 == "ñ"
+
   result = ""
   fastToUTF8Copy(c, result, 0, false)
 
 proc add*(s: var string; c: Rune) =
+  ## Adds a rune ``c`` to a string ``s``.
+  runnableExamples:
+    var s = "abc"
+    let c = "ä".runeAt(0)
+    s.add(c)
+    doAssert s == "abcä"
+
   let pos = s.len
   fastToUTF8Copy(c, s, pos, false)
 
 proc `$`*(rune: Rune): string =
-  ## Converts a Rune to a string
+  ## An alias for `toUTF8 <#toUTF8%2CRune>`_.
   rune.toUTF8
 
 proc `$`*(runes: seq[Rune]): string =
-  ## Converts a sequence of Runes to a string
+  ## Converts a sequence of Runes to a string.
   result = ""
   for rune in runes:
     result.add rune
 
 proc runeOffset*(s: string, pos:Natural, start: Natural = 0): int =
-  ## Returns the byte position of unicode character
-  ## at position pos in s with an optional start byte position.
-  ## returns the special value -1 if it runs out of the string
+  ## Returns the byte position of rune
+  ## at position ``pos`` in ``s`` with an optional start byte position.
+  ## Returns the special value -1 if it runs out of the string.
   ##
   ## Beware: This can lead to unoptimized code and slow execution!
   ## Most problems can be solved more efficiently by using an iterator
@@ -244,7 +274,7 @@ proc runeOffset*(s: string, pos:Natural, start: Natural = 0): int =
   return o
 
 proc runeAtPos*(s: string, pos: int): Rune =
-  ## Returns the unicode character at position pos
+  ## Returns the rune at position ``pos``.
   ##
   ## Beware: This can lead to unoptimized code and slow execution!
   ## Most problems can be solved more efficiently by using an iterator
@@ -252,7 +282,7 @@ proc runeAtPos*(s: string, pos: int): Rune =
   fastRuneAt(s, runeOffset(s, pos), result, false)
 
 proc runeStrAtPos*(s: string, pos: Natural): string =
-  ## Returns the unicode character at position pos as UTF8 String
+  ## Returns the rune at position ``pos`` as UTF8 String.
   ##
   ## Beware: This can lead to unoptimized code and slow execution!
   ## Most problems can be solved more efficiently by using an iterator
@@ -262,7 +292,7 @@ proc runeStrAtPos*(s: string, pos: Natural): string =
 
 proc runeReverseOffset*(s: string, rev:Positive): (int, int) =
   ## Returns a tuple with the the byte offset of the
-  ## unicode character at position ``rev`` in s counting
+  ## rune at position ``rev`` in ``s``, counting
   ## from the end (starting with 1) and the total
   ## number of runes in the string. Returns a negative value
   ## for offset if there are to few runes in the string to
@@ -286,13 +316,21 @@ proc runeReverseOffset*(s: string, rev:Positive): (int, int) =
     return (-a, rev.int-a)
   return (x, -a+rev.int)
 
-proc runeSubStr*(s: string, pos:int, len:int = int.high): string =
-  ## Returns the UTF-8 substring starting at codepoint pos
-  ## with len codepoints. If pos or len is negative they count from
-  ## the end of the string. If len is not given it means the longest
+proc runeSubStr*(s: string, pos: int, len: int = int.high): string =
+  ## Returns the UTF-8 substring starting at codepoint ``pos``
+  ## with ``len`` codepoints. If ``pos`` or ``len`` is negative they count from
+  ## the end of the string. If ``len`` is not given it means the longest
   ## possible string.
   ##
-  ## (Needs some examples)
+  runnableExamples:
+    let s = "Hänsel  ««: 10,00€"
+    doAssert(runeSubStr(s, 0, 2) == "Hä")
+    doAssert(runeSubStr(s, 10, 1) == ":")
+    doAssert(runeSubStr(s, -6) == "10,00€")
+    doAssert(runeSubStr(s, 10) == ": 10,00€")
+    doAssert(runeSubStr(s, 12, 5) == "10,00")
+    doAssert(runeSubStr(s, -6, 3) == "10,")
+
   if pos < 0:
     let (o, rl) = runeReverseOffset(s, -pos)
     if len >= rl:
@@ -1321,7 +1359,7 @@ proc binarySearch(c: RuneImpl, tab: openArray[int], len, stride: int): int =
   return -1
 
 proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
-  ## Converts ``c`` into lower case. This works for any Unicode character.
+  ## Converts ``c`` into lower case. This works for any rune.
   ## If possible, prefer ``toLower`` over ``toUpper``.
   var c = RuneImpl(c)
   var p = binarySearch(c, tolowerRanges, len(tolowerRanges) div 3, 3)
@@ -1333,7 +1371,7 @@ proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
   return Rune(c)
 
 proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
-  ## Converts ``c`` into upper case. This works for any Unicode character.
+  ## Converts ``c`` into upper case. This works for any rune.
   ## If possible, prefer ``toLower`` over ``toUpper``.
   var c = RuneImpl(c)
   var p = binarySearch(c, toupperRanges, len(toupperRanges) div 3, 3)
@@ -1345,7 +1383,7 @@ proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
   return Rune(c)
 
 proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
-  ## Converts ``c`` to title case
+  ## Converts ``c`` to title case.
   var c = RuneImpl(c)
   var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2)
   if p >= 0 and c == toTitleSinglets[p]:
@@ -1353,7 +1391,7 @@ proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
   return Rune(c)
 
 proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
-  ## Returns true iff ``c`` is a lower case Unicode character.
+  ## Returns true iff ``c`` is a lower case rune.
   ## If possible, prefer ``isLower`` over ``isUpper``.
   var c = RuneImpl(c)
   # Note: toUpperRanges is correct here!
@@ -1365,7 +1403,7 @@ proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
     return true
 
 proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
-  ## Returns true iff ``c`` is a upper case Unicode character.
+  ## Returns true iff ``c`` is a upper case rune.
   ## If possible, prefer ``isLower`` over ``isUpper``.
   var c = RuneImpl(c)
   # Note: toLowerRanges is correct here!
@@ -1377,7 +1415,7 @@ proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
     return true
 
 proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
-  ## Returns true iff ``c`` is an *alpha* Unicode character (i.e., a letter)
+  ## Returns true iff ``c`` is an *alpha* rune (i.e., a letter)
   if isUpper(c) or isLower(c):
     return true
   var c = RuneImpl(c)
@@ -1389,18 +1427,18 @@ proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
     return true
 
 proc isTitle*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
-  ## Returns true iff ``c`` is a Unicode titlecase character
+  ## Returns true iff ``c`` is a Unicode titlecase character.
   return isUpper(c) and isLower(c)
 
 proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
-  ## Returns true iff ``c`` is a Unicode whitespace character
+  ## Returns true iff ``c`` is a Unicode whitespace character.
   var c = RuneImpl(c)
   var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2)
   if p >= 0 and c >= spaceRanges[p] and c <= spaceRanges[p+1]:
     return true
 
 proc isCombining*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
-  ## Returns true iff ``c`` is a Unicode combining character
+  ## Returns true iff ``c`` is a Unicode combining character.
   var c = RuneImpl(c)
 
   # Optimized to return false immediately for ASCII
@@ -1424,12 +1462,12 @@ template runeCheck(s, runeProc) =
 
 proc isAlpha*(s: string): bool {.noSideEffect, procvar,
   rtl, extern: "nuc$1Str".} =
-  ## Returns true iff `s` contains all alphabetic unicode characters.
+  ## Returns true iff ``s`` contains all alphabetic runes.
   runeCheck(s, isAlpha)
 
 proc isSpace*(s: string): bool {.noSideEffect, procvar,
   rtl, extern: "nuc$1Str".} =
-  ## Returns true iff `s` contains all whitespace unicode characters.
+  ## Returns true iff ``s`` contains all whitespace runes.
   runeCheck(s, isWhiteSpace)
 
 template runeCaseCheck(s, runeProc, skipNonAlpha) =
@@ -1459,7 +1497,7 @@ proc isLower*(s: string, skipNonAlpha: bool): bool {.
   ## Checks whether ``s`` is lower case.
   ##
   ## If ``skipNonAlpha`` is true, returns true if all alphabetical
-  ## runes in ``s`` are lower case.  Returns false if none of the
+  ## runes in ``s`` are lower case. Returns false if none of the
   ## runes in ``s`` are alphabetical.
   ##
   ## If ``skipNonAlpha`` is false, returns true only if all runes in
@@ -1474,7 +1512,7 @@ proc isUpper*(s: string, skipNonAlpha: bool): bool {.
   ## Checks whether ``s`` is upper case.
   ##
   ## If ``skipNonAlpha`` is true, returns true if all alphabetical
-  ## runes in ``s`` are upper case.  Returns false if none of the
+  ## runes in ``s`` are upper case. Returns false if none of the
   ## runes in ``s`` are alphabetical.
   ##
   ## If ``skipNonAlpha`` is false, returns true only if all runes in
@@ -1485,7 +1523,7 @@ proc isUpper*(s: string, skipNonAlpha: bool): bool {.
   runeCaseCheck(s, isUpper, skipNonAlpha)
 
 template convertRune(s, runeProc) =
-  ## Convert runes in `s` using `runeProc` as the converter.
+  ## Convert runes in ``s`` using ``runeProc`` as the converter.
   result = newString(len(s))
 
   var
@@ -1502,20 +1540,20 @@ template convertRune(s, runeProc) =
 
 proc toUpper*(s: string): string {.noSideEffect, procvar,
   rtl, extern: "nuc$1Str".} =
-  ## Converts `s` into upper-case unicode characters.
+  ## Converts ``s`` into upper-case runes.
   convertRune(s, toUpper)
 
 proc toLower*(s: string): string {.noSideEffect, procvar,
   rtl, extern: "nuc$1Str".} =
-  ## Converts `s` into lower-case unicode characters.
+  ## Converts ``s`` into lower-case runes.
   convertRune(s, toLower)
 
 proc swapCase*(s: string): string {.noSideEffect, procvar,
   rtl, extern: "nuc$1".} =
-  ## Swaps the case of unicode characters in `s`
+  ## Swaps the case of runes in ``s``.
   ##
-  ## Returns a new string such that the cases of all unicode characters
-  ## are swapped if possible
+  ## Returns a new string such that the cases of all runes
+  ## are swapped if possible.
 
   var
     i = 0
@@ -1538,7 +1576,7 @@ proc swapCase*(s: string): string {.noSideEffect, procvar,
 
 proc capitalize*(s: string): string {.noSideEffect, procvar,
   rtl, extern: "nuc$1".} =
-  ## Converts the first character of `s` into an upper-case unicode character.
+  ## Converts the first character of ``s`` into an upper-case rune.
   if len(s) == 0:
     return s
 
@@ -1552,10 +1590,10 @@ proc capitalize*(s: string): string {.noSideEffect, procvar,
 
 proc translate*(s: string, replacements: proc(key: string): string): string {.
   rtl, extern: "nuc$1".} =
-  ## Translates words in a string using the `replacements` proc to substitute
-  ## words inside `s` with their replacements
+  ## Translates words in a string using the ``replacements`` proc to substitute
+  ## words inside ``s`` with their replacements.
   ##
-  ## `replacements` is any proc that takes a word and returns
+  ## ``replacements`` is any proc that takes a word and returns
   ## a new word to fill it's place.
 
   # Allocate memory for the new string based on the old one.
@@ -1601,10 +1639,10 @@ proc translate*(s: string, replacements: proc(key: string): string): string {.
 
 proc title*(s: string): string {.noSideEffect, procvar,
   rtl, extern: "nuc$1".} =
-  ## Converts `s` to a unicode title.
+  ## Converts ``s`` to a unicode title.
   ##
   ## Returns a new string such that the first character
-  ## in each word inside `s` is capitalized
+  ## in each word inside ``s`` is capitalized.
 
   var
     i = 0
@@ -1631,10 +1669,10 @@ proc title*(s: string): string {.noSideEffect, procvar,
 proc isTitle*(s: string): bool {.noSideEffect, procvar,
   rtl, extern: "nuc$1Str",
   deprecated: "Deprecated since version 0.20 since its semantics are unclear".}=
-  ## Checks whether or not `s` is a unicode title.
+  ## Checks whether or not ``s`` is a unicode title.
   ##
-  ## Returns true if the first character in each word inside `s`
-  ## are upper case and there is at least one character in `s`.
+  ## Returns true if the first character in each word inside ``s``
+  ## are upper case and there is at least one character in ``s``.
   if s.len == 0:
     return false
 
@@ -1656,7 +1694,7 @@ proc isTitle*(s: string): bool {.noSideEffect, procvar,
       firstRune = true
 
 iterator runes*(s: string): Rune =
-  ## Iterates over any unicode character of the string ``s`` returning runes
+  ## Iterates over any rune of the string ``s`` returning runes.
   var
     i = 0
     result: Rune
@@ -1665,7 +1703,7 @@ iterator runes*(s: string): Rune =
     yield result
 
 iterator utf8*(s: string): string =
-  ## Iterates over any unicode character of the string ``s`` returning utf8 values
+  ## Iterates over any rune of the string ``s`` returning utf8 values.
   var o = 0
   while o < s.len:
     let n = runeLenAt(s, o)
@@ -1673,7 +1711,7 @@ iterator utf8*(s: string): string =
     o += n
 
 proc toRunes*(s: string): seq[Rune] =
-  ## Obtains a sequence containing the Runes in ``s``
+  ## Obtains a sequence containing the Runes in ``s``.
   result = newSeq[Rune]()
   for r in s.runes:
     result.add(r)
@@ -1696,15 +1734,14 @@ proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} =
   result = a.len - b.len
 
 proc reversed*(s: string): string =
-  ## Returns the reverse of ``s``, interpreting it as Unicode characters.
-  ## Unicode combining characters are correctly interpreted as well:
-  ##
-  ## .. code-block:: nim
-  ##
-  ##   assert reversed("Reverse this!") == "!siht esreveR"
-  ##   assert reversed("先秦兩漢") == "漢兩秦先"
-  ##   assert reversed("as⃝df̅") == "f̅ds⃝a"
-  ##   assert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞"
+  ## Returns the reverse of ``s``, interpreting it as runes.
+  ## Unicode combining characters are correctly interpreted as well.
+  runnableExamples:
+    assert reversed("Reverse this!") == "!siht esreveR"
+    assert reversed("先秦兩漢") == "漢兩秦先"
+    assert reversed("as⃝df̅") == "f̅ds⃝a"
+    assert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞"
+
   var
     i = 0
     lastI = 0
@@ -1731,7 +1768,7 @@ proc reversed*(s: string): string =
   reverseUntil(len(s))
 
 proc graphemeLen*(s: string; i: Natural): Natural =
-  ## The number of bytes belonging to 's[i]' including following combining
+  ## The number of bytes belonging to ``s[i]`` including following combining
   ## characters.
   var j = i.int
   var r, r2: Rune
@@ -1744,7 +1781,7 @@ proc graphemeLen*(s: string; i: Natural): Natural =
       result = j-i
 
 proc lastRune*(s: string; last: int): (Rune, int) =
-  ## length of the last rune in 's[0..last]'. Returns the rune and its length
+  ## Length of the last rune in ``s[0..last]``. Returns the rune and its length
   ## in bytes.
   if s[last] <= chr(127):
     result = (Rune(s[last]), 1)
@@ -1778,7 +1815,7 @@ proc stringHasSep(s: string, index: int, sep: Rune): bool =
   return sep == rune
 
 template splitCommon(s, sep, maxsplit: untyped, sepLen: int = -1) =
-  ## Common code for split procedures
+  ## Common code for split procedures.
   var
     last = 0
     splits = maxsplit
@@ -1801,9 +1838,9 @@ template splitCommon(s, sep, maxsplit: untyped, sepLen: int = -1) =
 
 iterator split*(s: string, seps: openarray[Rune] = unicodeSpaces,
   maxsplit: int = -1): string =
-  ## Splits the unicode string `s` into substrings using a group of separators.
+  ## Splits the unicode string ``s`` into substrings using a group of separators.
   ##
-  ## Substrings are separated by a substring containing only `seps`.
+  ## Substrings are separated by a substring containing only ``seps``.
   ##
   ## .. code-block:: nim
   ##   for word in split("this\lis an\texample"):
@@ -1844,7 +1881,7 @@ iterator split*(s: string, seps: openarray[Rune] = unicodeSpaces,
   splitCommon(s, seps, maxsplit)
 
 iterator splitWhitespace*(s: string): string =
-  ## Splits a unicode string at whitespace runes
+  ## Splits a unicode string at whitespace runes.
   splitCommon(s, unicodeSpaces, -1)
 
 template accResult(iter: untyped) =
@@ -1858,9 +1895,9 @@ proc splitWhitespace*(s: string): seq[string] {.noSideEffect,
   accResult(splitWhitespace(s))
 
 iterator split*(s: string, sep: Rune, maxsplit: int = -1): string =
-  ## Splits the unicode string `s` into substrings using a single separator.
+  ## Splits the unicode string ``s`` into substrings using a single separator.
   ##
-  ## Substrings are separated by the rune `sep`.
+  ## Substrings are separated by the rune ``sep``.
   ## The code:
   ##
   ## .. code-block:: nim
@@ -1898,11 +1935,11 @@ proc split*(s: string, sep: Rune, maxsplit: int = -1): seq[string] {.noSideEffec
 proc strip*(s: string, leading = true, trailing = true,
             runes: openarray[Rune] = unicodeSpaces): string {.noSideEffect,
             rtl, extern: "nucStrip".} =
-  ## Strips leading or trailing `runes` from `s` and returns
+  ## Strips leading or trailing ``runes`` from ``s`` and returns
   ## the resulting string.
   ##
-  ## If `leading` is true, leading `runes` are stripped.
-  ## If `trailing` is true, trailing `runes` are stripped.
+  ## If ``leading`` is true, leading ``runes`` are stripped.
+  ## If ``trailing`` is true, trailing ``runes`` are stripped.
   ## If both are false, the string is returned unchanged.
   var
     s_i = 0 ## starting index into string ``s``
@@ -1948,9 +1985,9 @@ proc strip*(s: string, leading = true, trailing = true,
 
 proc repeat*(c: Rune, count: Natural): string {.noSideEffect,
   rtl, extern: "nucRepeatRune".} =
-  ## Returns a string of `count` Runes `c`.
+  ## Returns a string of ``count`` Runes ``c``.
   ##
-  ## The returned string will have a rune-length of `count`.
+  ## The returned string will have a rune-length of ``count``.
   let s = $c
   result = newStringOfCap(count * s.len)
   for i in 0 ..< count:
@@ -1958,11 +1995,11 @@ proc repeat*(c: Rune, count: Natural): string {.noSideEffect,
 
 proc align*(s: string, count: Natural, padding = ' '.Rune): string {.
   noSideEffect, rtl, extern: "nucAlignString".} =
-  ## Aligns a unicode string `s` with `padding`, so that it has a rune-length
-  ## of `count`.
+  ## Aligns a unicode string ``s`` with ``padding``, so that it has a rune-length
+  ## of ``count``.
   ##
-  ## `padding` characters (by default spaces) are added before `s` resulting in
-  ## right alignment. If ``s.runelen >= count``, no spaces are added and `s` is
+  ## ``padding`` characters (by default spaces) are added before ``s`` resulting in
+  ## right alignment. If ``s.runelen >= count``, no spaces are added and ``s`` is
   ## returned unchanged. If you need to left align a string use the `alignLeft
   ## proc <#alignLeft>`_.
   runnableExamples:
@@ -1985,11 +2022,11 @@ proc align*(s: string, count: Natural, padding = ' '.Rune): string {.
 
 proc alignLeft*(s: string, count: Natural, padding = ' '.Rune): string {.
     noSideEffect.} =
-  ## Left-Aligns a unicode string `s` with `padding`, so that it has a
-  ## rune-length of `count`.
+  ## Left-Aligns a unicode string ``s`` with ``padding``, so that it has a
+  ## rune-length of ``count``.
   ##
-  ## `padding` characters (by default spaces) are added after `s` resulting in
-  ## left alignment. If ``s.runelen >= count``, no spaces are added and `s` is
+  ## ``padding`` characters (by default spaces) are added after ``s`` resulting in
+  ## left alignment. If ``s.runelen >= count``, no spaces are added and ``s`` is
   ## returned unchanged. If you need to right align a string use the `align
   ## proc <#align>`_.
   runnableExamples:
diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim
index 135a24e9a..ce147cccc 100644
--- a/lib/pure/unittest.nim
+++ b/lib/pure/unittest.nim
@@ -499,7 +499,7 @@ template test*(name, body) {.dirty.} =
 
     finally:
       if testStatusIMPL == FAILED:
-        programResult += 1
+        programResult = 1
       let testResult = TestResult(
         suiteName: when declared(testSuiteName): testSuiteName else: "",
         testName: name,
@@ -540,7 +540,7 @@ template fail* =
   when declared(testStatusIMPL):
     testStatusIMPL = FAILED
   else:
-    programResult += 1
+    programResult = 1
 
   ensureInitialized()
 
diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim
index d296017dd..bfb411fc8 100644
--- a/lib/pure/uri.nim
+++ b/lib/pure/uri.nim
@@ -8,6 +8,35 @@
 #
 
 ## This module implements URI parsing as specified by RFC 3986.
+##
+## A Uniform Resource Identifier (URI) provides a simple and extensible
+## means for identifying a resource. A URI can be further classified
+## as a locator, a name, or both. The term “Uniform Resource Locator”
+## (URL) refers to the subset of URIs.
+##
+## Basic usage
+## ===========
+##
+## Combine URIs
+## -------------
+## .. code-block::
+##    import uri
+##    let host = parseUri("https://nim-lang.org")
+##    let blog = "/blog.html"
+##    let bloguri = host / blog
+##    assert $host == "https://nim-lang.org"
+##    assert $bloguri == "https://nim-lang.org/blog.html"
+##
+## Access URI item
+## ---------------
+## .. code-block::
+##    import uri
+##    let res = parseUri("sftp://127.0.0.1:4343")
+##    if isAbsolute(res):
+##      echo "Connect to port: " & res.port
+##      # --> Connect to port: 4343
+##    else:
+##      echo "Wrong format"
 
 import strutils, parseutils
 type
@@ -18,44 +47,24 @@ type
     hostname*, port*, path*, query*, anchor*: string
     opaque*: bool
 
-{.push warning[deprecated]: off.}
-proc `$`*(url: Url): string {.deprecated: "use Uri instead".} =
-  ## **Deprecated since 0.9.6**: Use ``Uri`` instead.
-  return string(url)
-
-proc `/`*(a, b: Url): Url {.deprecated: "use Uri instead".} =
-  ## Joins two URLs together, separating them with / if needed.
-  ##
-  ## **Deprecated since 0.9.6**: Use ``Uri`` instead.
-  var urlS = $a
-  var bS = $b
-  if urlS == "": return b
-  if urlS[urlS.len-1] != '/':
-    urlS.add('/')
-  if bS[0] == '/':
-    urlS.add(bS.substr(1))
-  else:
-    urlS.add(bs)
-  result = Url(urlS)
-
-proc add*(url: var Url, a: Url) {.deprecated: "use Uri instead".} =
-  ## Appends url to url.
-  ##
-  ## **Deprecated since 0.9.6**: Use ``Uri`` instead.
-  url = url / a
-{.pop.}
-
 proc encodeUrl*(s: string, usePlus=true): string =
   ## Encodes a URL according to RFC3986.
   ##
   ## This means that characters in the set
   ## ``{'a'..'z', 'A'..'Z', '0'..'9', '-', '.', '_', '~'}`` are
   ## carried over to the result.
-  ## All other characters are encoded as ``''%xx'`` where ``xx``
+  ## All other characters are encoded as ``%xx`` where ``xx``
   ## denotes its hexadecimal value.
   ##
   ## As a special rule, when the value of ``usePlus`` is true,
-  ## spaces are encoded as ``'+'`` instead of ``'%20'``.
+  ## spaces are encoded as ``+`` instead of ``%20``.
+  ##
+  ## **See also:**
+  ## * `decodeUrl proc<#decodeUrl,string>`_
+  runnableExamples:
+    assert encodeUrl("https://nim-lang.org") == "https%3A%2F%2Fnim-lang.org"
+    assert encodeUrl("https://nim-lang.org/this is a test") == "https%3A%2F%2Fnim-lang.org%2Fthis+is+a+test"
+    assert encodeUrl("https://nim-lang.org/this is a test", false) == "https%3A%2F%2Fnim-lang.org%2Fthis%20is%20a%20test"
   result = newStringOfCap(s.len + s.len shr 2) # assume 12% non-alnum-chars
   let fromSpace = if usePlus: "+" else: "%20"
   for c in s:
@@ -70,12 +79,19 @@ proc encodeUrl*(s: string, usePlus=true): string =
 proc decodeUrl*(s: string, decodePlus=true): string =
   ## Decodes a URL according to RFC3986.
   ##
-  ## This means that any ``'%xx'`` (where ``xx`` denotes a hexadecimal
+  ## This means that any ``%xx`` (where ``xx`` denotes a hexadecimal
   ## value) are converted to the character with ordinal number ``xx``,
   ## and every other character is carried over.
   ##
-  ## As a special rule, when the value of ``decodePlus`` is true, ``'+'``
+  ## As a special rule, when the value of ``decodePlus`` is true, ``+``
   ## characters are converted to a space.
+  ##
+  ## **See also:**
+  ## * `encodeUrl proc<#encodeUrl,string>`_
+  runnableExamples:
+    assert decodeUrl("https%3A%2F%2Fnim-lang.org") == "https://nim-lang.org"
+    assert decodeUrl("https%3A%2F%2Fnim-lang.org%2Fthis+is+a+test") == "https://nim-lang.org/this is a test"
+    assert decodeUrl("https%3A%2F%2Fnim-lang.org%2Fthis%20is%20a%20test", false) == "https://nim-lang.org/this is a test"
   proc handleHexChar(c: char, x: var int) {.inline.} =
     case c
     of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
@@ -150,7 +166,14 @@ proc parsePath(uri: string, i: var int, result: var Uri) =
     i.inc parseUntil(uri, result.anchor, {}, i)
 
 proc initUri*(): Uri =
-  ## Initializes a URI.
+  ## Initializes a URI with ``scheme``, ``username``, ``password``,
+  ## ``hostname``, ``port``, ``path``, ``query`` and ``anchor``.
+  ##
+  ## **See also:**
+  ## * `Uri type <#Uri>`_ for available fields in the URI type
+  runnableExamples:
+    var uri: Uri
+    assert initUri() == uri
   result = Uri(scheme: "", username: "", password: "", hostname: "", port: "",
                 path: "", query: "", anchor: "")
 
@@ -163,6 +186,16 @@ proc resetUri(uri: var Uri) =
 
 proc parseUri*(uri: string, result: var Uri) =
   ## Parses a URI. The `result` variable will be cleared before.
+  ##
+  ## **See also:**
+  ## * `Uri type <#Uri>`_ for available fields in the URI type
+  ## * `initUri proc <#initUri,>`_ for initializing a URI
+  runnableExamples:
+    var res = initUri()
+    parseUri("https://nim-lang.org/docs/manual.html", res)
+    assert res.scheme == "https"
+    assert res.hostname == "nim-lang.org"
+    assert res.path == "/docs/manual.html"
   resetUri(result)
 
   var i = 0
@@ -201,6 +234,14 @@ proc parseUri*(uri: string, result: var Uri) =
 
 proc parseUri*(uri: string): Uri =
   ## Parses a URI and returns it.
+  ##
+  ## **See also:**
+  ## * `Uri type <#Uri>`_ for available fields in the URI type
+  runnableExamples:
+    let res = parseUri("ftp://Username:Password@Hostname")
+    assert res.username == "Username"
+    assert res.password == "Password"
+    assert res.scheme == "ftp"
   result = initUri()
   parseUri(uri, result)
 
@@ -251,22 +292,18 @@ proc combine*(base: Uri, reference: Uri): Uri =
   ## This uses the algorithm specified in
   ## `section 5.2.2 of RFC 3986 <http://tools.ietf.org/html/rfc3986#section-5.2.2>`_.
   ##
-  ## This means that the slashes inside the base URI's path as well as reference
-  ## URI's path affect the resulting URI.
-  ##
-  ## For building URIs you may wish to use \`/\` instead.
-  ##
-  ## Examples:
-  ##
-  ## .. code-block::
-  ##   let foo = combine(parseUri("http://example.com/foo/bar"), parseUri("/baz"))
-  ##   assert foo.path == "/baz"
-  ##
-  ##   let bar = combine(parseUri("http://example.com/foo/bar"), parseUri("baz"))
-  ##   assert bar.path == "/foo/baz"
+  ## This means that the slashes inside the base URIs path as well as reference
+  ## URIs path affect the resulting URI.
   ##
-  ##   let bar = combine(parseUri("http://example.com/foo/bar/"), parseUri("baz"))
-  ##   assert bar.path == "/foo/bar/baz"
+  ## **See also:**
+  ## * `/ proc <#/,Uri,string>`_ for building URIs
+  runnableExamples:
+    let foo = combine(parseUri("https://nim-lang.org/foo/bar"), parseUri("/baz"))
+    assert foo.path == "/baz"
+    let bar = combine(parseUri("https://nim-lang.org/foo/bar"), parseUri("baz"))
+    assert bar.path == "/foo/baz"
+    let qux = combine(parseUri("https://nim-lang.org/foo/bar/"), parseUri("baz"))
+    assert qux.path == "/foo/bar/baz"
 
   template setAuthority(dest, src): untyped =
     dest.hostname = src.hostname
@@ -302,32 +339,42 @@ proc combine*(base: Uri, reference: Uri): Uri =
 
 proc combine*(uris: varargs[Uri]): Uri =
   ## Combines multiple URIs together.
+  ##
+  ## **See also:**
+  ## * `/ proc <#/,Uri,string>`_ for building URIs
+  runnableExamples:
+    let foo = combine(parseUri("https://nim-lang.org/blog.html"), parseUri("/install.html"))
+    assert foo.hostname == "nim-lang.org"
+    assert foo.path == "/install.html"
   result = uris[0]
   for i in 1 ..< uris.len:
     result = combine(result, uris[i])
 
 proc isAbsolute*(uri: Uri): bool =
-  ## returns true if URI is absolute, false otherwise
+  ## Returns true if URI is absolute, false otherwise.
+  runnableExamples:
+    let foo = parseUri("https://nim-lang.org")
+    assert isAbsolute(foo) == true
+    let bar = parseUri("nim-lang")
+    assert isAbsolute(bar) == false
   return uri.scheme != "" and (uri.hostname != "" or uri.path != "")
 
 proc `/`*(x: Uri, path: string): Uri =
-  ## Concatenates the path specified to the specified URI's path.
+  ## Concatenates the path specified to the specified URIs path.
   ##
-  ## Contrary to the ``combine`` procedure you do not have to worry about
-  ## the slashes at the beginning and end of the path and URI's path
+  ## Contrary to the `combine proc <#combine,Uri,Uri>`_ you do not have to worry about
+  ## the slashes at the beginning and end of the path and URIs path
   ## respectively.
   ##
-  ## Examples:
-  ##
-  ## .. code-block::
-  ##   let foo = parseUri("http://example.com/foo/bar") / "/baz"
-  ##   assert foo.path == "/foo/bar/baz"
-  ##
-  ##   let bar = parseUri("http://example.com/foo/bar") / "baz"
-  ##   assert bar.path == "/foo/bar/baz"
-  ##
-  ##   let bar = parseUri("http://example.com/foo/bar/") / "baz"
-  ##   assert bar.path == "/foo/bar/baz"
+  ## **See also:**
+  ## * `combine proc <#combine,Uri,Uri>`_
+  runnableExamples:
+    let foo = parseUri("https://nim-lang.org/foo/bar") / "/baz"
+    assert foo.path == "/foo/bar/baz"
+    let bar = parseUri("https://nim-lang.org/foo/bar") / "baz"
+    assert bar.path == "/foo/bar/baz"
+    let qux = parseUri("https://nim-lang.org/foo/bar/") / "baz"
+    assert qux.path == "/foo/bar/baz"
   result = x
 
   if result.path.len == 0:
@@ -348,6 +395,9 @@ proc `/`*(x: Uri, path: string): Uri =
 
 proc `$`*(u: Uri): string =
   ## Returns the string representation of the specified URI object.
+  runnableExamples:
+    let foo = parseUri("https://nim-lang.org")
+    assert $foo == "https://nim-lang.org"
   result = ""
   if u.scheme.len > 0:
     result.add(u.scheme)
diff --git a/lib/std/sha1.nim b/lib/std/sha1.nim
index e7e6697cf..b5660f244 100644
--- a/lib/std/sha1.nim
+++ b/lib/std/sha1.nim
@@ -7,7 +7,32 @@
 #    distribution, for details about the copyright.
 #
 
-## Note: Import ``std/sha1`` to use this module
+## **Note:** Import ``std/sha1`` to use this module
+##
+## SHA-1 (Secure Hash Algorithm 1) is a cryptographic hash function which
+## takes an input and produces a 160-bit (20-byte) hash value known as a
+## message digest.
+##
+## .. code-block::
+##    import std/sha1
+##
+##    let accessName = secureHash("John Doe")
+##    assert $accessName == "AE6E4D1209F17B460503904FAD297B31E9CF6362"
+##
+## .. code-block::
+##    import std/sha1
+##
+##    let
+##      a = secureHashFile("myFile.nim")
+##      b = parseSecureHash("10DFAEBF6BFDBC7939957068E2EFACEC4972933C")
+##
+##    if a == b:
+##      echo "Files match"
+##
+## **See also:**
+## * `base64 module<base64.html>`_ implements a base64 encoder and decoder
+## * `hashes module<hashes.html>`_ for efficient computations of hash values for diverse Nim types
+## * `md5 module<md5.html>`_ implements the MD5 checksum algorithm
 
 import strutils
 from endians import bigEndian32, bigEndian64
@@ -170,23 +195,61 @@ proc finalize(ctx: var Sha1State): Sha1Digest =
 # Public API
 
 proc secureHash*(str: string): SecureHash =
+  ## Generates a ``SecureHash`` from a ``str``.
+  ##
+  ## **See also:**
+  ## * `secureHashFile proc <#secureHashFile,string>`_ for generating a ``SecureHash`` from a file
+  ## * `parseSecureHash proc <#parseSecureHash,string>`_ for converting a string ``hash`` to ``SecureHash``
+  runnableExamples:
+    let hash = secureHash("Hello World")
+    assert hash == parseSecureHash("0A4D55A8D778E5022FAB701977C5D840BBC486D0")
   var state = newSha1State()
   state.update(str)
   SecureHash(state.finalize())
 
 proc secureHashFile*(filename: string): SecureHash =
+  ## Generates a ``SecureHash`` from a file.
+  ##
+  ## **See also:**
+  ## * `secureHash proc <#secureHash,string>`_ for generating a ``SecureHash`` from a string
+  ## * `parseSecureHash proc <#parseSecureHash,string>`_ for converting a string ``hash`` to ``SecureHash``
   secureHash(readFile(filename))
 
 proc `$`*(self: SecureHash): string =
+  ## Returns the string representation of a ``SecureHash``.
+  ##
+  ## **See also:**
+  ## * `secureHash proc <#secureHash,string>`_ for generating a ``SecureHash`` from a string
+  runnableExamples:
+    let hash = secureHash("Hello World")
+    assert $hash == "0A4D55A8D778E5022FAB701977C5D840BBC486D0"
   result = ""
   for v in Sha1Digest(self):
     result.add(toHex(int(v), 2))
 
 proc parseSecureHash*(hash: string): SecureHash =
+  ## Converts a string ``hash`` to ``SecureHash``.
+  ##
+  ## **See also:**
+  ## * `secureHash proc <#secureHash,string>`_ for generating a ``SecureHash`` from a string
+  ## * `secureHashFile proc <#secureHashFile,string>`_ for generating a ``SecureHash`` from a file
+  runnableExamples:
+    let
+      hashStr = "0A4D55A8D778E5022FAB701977C5D840BBC486D0"
+      secureHash = secureHash("Hello World")
+    assert secureHash == parseSecureHash(hashStr)
   for i in 0 ..< Sha1DigestSize:
     Sha1Digest(result)[i] = uint8(parseHexInt(hash[i*2] & hash[i*2 + 1]))
 
 proc `==`*(a, b: SecureHash): bool =
+  ## Checks if two ``SecureHash`` values are identical.
+  runnableExamples:
+    let
+      a = secureHash("Hello World")
+      b = secureHash("Goodbye World")
+      c = parseSecureHash("0A4D55A8D778E5022FAB701977C5D840BBC486D0")
+    assert a != b
+    assert a == c
   # Not a constant-time comparison, but that's acceptable in this context
   Sha1Digest(a) == Sha1Digest(b)
 
diff --git a/lib/std/time_t.nim b/lib/std/time_t.nim
new file mode 100644
index 000000000..37918ee6c
--- /dev/null
+++ b/lib/std/time_t.nim
@@ -0,0 +1,23 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2019 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+when defined(nimdoc):
+  type
+    impl = distinct int64
+    Time* = impl ## \
+      ## Wrapper for ``time_t``. On posix, this is an alias to ``posix.Time``.
+elif defined(windows):
+  when defined(i386) and defined(gcc):
+    type Time* {.importc: "time_t", header: "<time.h>".} = distinct int32
+  else:
+    # newest version of Visual C++ defines time_t to be of 64 bits
+    type Time* {.importc: "time_t", header: "<time.h>".} = distinct int64
+elif defined(posix):
+  import posix
+  export posix.Time
\ No newline at end of file
diff --git a/lib/std/wordwrap.nim b/lib/std/wordwrap.nim
index c7898b339..4b0dc4417 100644
--- a/lib/std/wordwrap.nim
+++ b/lib/std/wordwrap.nim
@@ -24,6 +24,11 @@ proc wrapWords*(s: string, maxLineWidth = 80,
                seps: set[char] = Whitespace,
                newLine = "\n"): string {.noSideEffect.} =
   ## Word wraps `s`.
+  runnableExamples:
+    doAssert "12345678901234567890".wrapWords() == "12345678901234567890"
+    doAssert "123456789012345678901234567890".wrapWords(20) == "12345678901234567890\n1234567890"
+    doAssert "Hello Bob. Hello John.".wrapWords(13, false) == "Hello Bob.\nHello John."
+    doAssert "Hello Bob. Hello John.".wrapWords(13, true, {';'}) == "Hello Bob. He\nllo John."
   result = newStringOfCap(s.len + s.len shr 6)
   var spaceLeft = maxLineWidth
   var lastSep = ""
diff --git a/lib/system.nim b/lib/system.nim
index ea767e27a..d4a86e53b 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -118,6 +118,22 @@ proc defined*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.}
   ##     # Do here programmer friendly expensive sanity checks.
   ##   # Put here the normal code
 
+when defined(nimHasRunnableExamples):
+  proc runnableExamples*(body: untyped) {.magic: "RunnableExamples".}
+    ## A section you should use to mark `runnable example`:idx: code with.
+    ##
+    ## - In normal debug and release builds code within
+    ##   a ``runnableExamples`` section is ignored.
+    ## - The documentation generator is aware of these examples and considers them
+    ##   part of the ``##`` doc comment. As the last step of documentation
+    ##   generation the examples are put into an ``$file_example.nim`` file,
+    ##   compiled and tested. The collected examples are
+    ##   put into their own module to ensure the examples do not refer to
+    ##   non-exported symbols.
+else:
+  template runnableExamples*(body: untyped) =
+    discard
+
 proc declared*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.}
   ## Special compile-time procedure that checks whether `x` is
   ## declared. `x` has to be an identifier or a qualified identifier.
@@ -553,7 +569,12 @@ type
       trace: string
     else:
       trace: seq[StackTraceEntry]
-    raiseId: uint # set when exception is raised
+    when defined(nimBoostrapCsources0_19_0):
+      # see #10315, bootstrap with `nim cpp` from csources gave error:
+      # error: no member named 'raise_id' in 'Exception'
+      raise_id: uint # set when exception is raised
+    else:
+      raiseId: uint # set when exception is raised
     up: ref Exception # used for stacking exceptions. Not exported!
 
   Defect* = object of Exception ## \
@@ -590,7 +611,7 @@ type
     ## Raised when assertion is proved wrong.
     ##
     ## Usually the result of using the `assert() template <#assert>`_.
-  ValueError* = object of Defect ## \
+  ValueError* = object of CatchableError ## \
     ## Raised for string and object conversion errors.
   KeyError* = object of ValueError ## \
     ## Raised if a key cannot be found in a table.
@@ -1479,12 +1500,9 @@ const
   # for string literals, it allows for some optimizations.
 
 {.push profiler: off.}
-when defined(nimKnowsNimvm):
-  let nimvm* {.magic: "Nimvm".}: bool = false
-    ## may be used only in "when" expression.
-    ## It is true in Nim VM context and false otherwise
-else:
-  const nimvm*: bool = false
+let nimvm* {.magic: "Nimvm", compileTime.}: bool = false
+  ## may be used only in "when" expression.
+  ## It is true in Nim VM context and false otherwise
 {.pop.}
 
 proc compileOption*(option: string): bool {.
@@ -1539,7 +1557,7 @@ else:
                                         ## ``string`` if the taint mode is not
                                         ## turned on.
 
-when defined(profiler):
+when defined(profiler) and not defined(nimscript):
   proc nimProfile() {.compilerProc, noinline.}
 when hasThreadSupport:
   {.pragma: rtlThreadVar, threadvar.}
@@ -1555,7 +1573,7 @@ const
     ## is the value that should be passed to `quit <#quit>`_ to indicate
     ## failure.
 
-when defined(nodejs):
+when defined(nodejs) and not defined(nimscript):
   var programResult* {.importc: "process.exitCode".}: int
   programResult = 0
 else:
@@ -1601,7 +1619,7 @@ elif defined(genode):
 
 
 
-elif defined(nodejs):
+elif defined(nodejs) and not defined(nimscript):
   proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit",
     importc: "process.exit", noreturn.}
 
@@ -1692,7 +1710,7 @@ proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} =
   else:
     when defined(js):
       var it : T
-      {.emit: "`x`.splice(`i`, 0, `it`);".}
+      {.emit: "`x` = `x` || []; `x`.splice(`i`, 0, `it`);".}
     else:
       defaultImpl()
   x[i] = item
@@ -1795,21 +1813,26 @@ proc toFloat*(i: int): float {.
 
 proc toBiggestFloat*(i: BiggestInt): BiggestFloat {.
   magic: "ToBiggestFloat", noSideEffect, importc: "toBiggestFloat".}
-  ## converts an biggestint `i` into a ``biggestfloat``. If the conversion
+  ## converts a biggestint `i` into a ``biggestfloat``. If the conversion
   ## fails, `ValueError` is raised. However, on most platforms the
   ## conversion cannot fail.
 
 proc toInt*(f: float): int {.
-  magic: "ToInt", noSideEffect, importc: "toInt".}
+  magic: "ToInt", noSideEffect, importc: "toInt".} =
   ## converts a floating point number `f` into an ``int``. Conversion
-  ## rounds `f` if it does not contain an integer value. If the conversion
-  ## fails (because `f` is infinite for example), `ValueError` is raised.
+  ## rounds `f` half away from 0, see https://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero
+  ## Note that some floating point numbers (e.g. infinity or even 1e19)
+  ## cannot be accurately converted.
+  runnableExamples:
+    doAssert toInt(0.49) == 0
+    doAssert toInt(0.5) == 1
+    doAssert toInt(-0.5) == -1 ## rounding is symmetrical
 
 proc toBiggestInt*(f: BiggestFloat): BiggestInt {.
-  magic: "ToBiggestInt", noSideEffect, importc: "toBiggestInt".}
-  ## converts a biggestfloat `f` into a ``biggestint``. Conversion
-  ## rounds `f` if it does not contain an integer value. If the conversion
-  ## fails (because `f` is infinite for example), `ValueError` is raised.
+  magic: "ToBiggestInt", noSideEffect, importc: "toBiggestInt".} =
+  ## Same as `toInt` but for BiggestFloat to ``BiggestInt``.
+  runnableExamples:
+    doAssert toBiggestInt(0.49) == 0
 
 proc addQuitProc*(quitProc: proc() {.noconv.}) {.
   importc: "atexit", header: "<stdlib.h>".}
@@ -2624,8 +2647,8 @@ proc `==`*[T: tuple|object](x, y: T): bool =
   return true
 
 proc `<=`*[T: tuple](x, y: T): bool =
-  ## generic ``<=`` operator for tuples that is lifted from the components
-  ## of `x` and `y`. This implementation uses `cmp`.
+  ## generic lexicographic ``<=`` operator for tuples that is lifted from the
+  ## components of `x` and `y`. This implementation uses `cmp`.
   for a, b in fields(x, y):
     var c = cmp(a, b)
     if c < 0: return true
@@ -2633,8 +2656,8 @@ proc `<=`*[T: tuple](x, y: T): bool =
   return true
 
 proc `<`*[T: tuple](x, y: T): bool =
-  ## generic ``<`` operator for tuples that is lifted from the components
-  ## of `x` and `y`. This implementation uses `cmp`.
+  ## generic lexicographic ``<`` operator for tuples that is lifted from the
+  ## components of `x` and `y`. This implementation uses `cmp`.
   for a, b in fields(x, y):
     var c = cmp(a, b)
     if c < 0: return true
@@ -2651,19 +2674,28 @@ proc compiles*(x: untyped): bool {.magic: "Compiles", noSideEffect, compileTime.
   ##     echo "'+' for integers is available"
   discard
 
+include "system/helpers" # for `lineInfoToString`, `isNamedTuple`
+
 proc `$`*[T: tuple|object](x: T): string =
   ## generic ``$`` operator for tuples that is lifted from the components
   ## of `x`. Example:
   ##
   ## .. code-block:: nim
   ##   $(23, 45) == "(23, 45)"
+  ##   $(a: 23, b: 45) == "(a: 23, b: 45)"
   ##   $() == "()"
   result = "("
   var firstElement = true
+  const isNamed = T is object or isNamedTuple(T)
+  when not isNamed:
+    var count = 0
   for name, value in fieldPairs(x):
     if not firstElement: result.add(", ")
-    result.add(name)
-    result.add(": ")
+    when isNamed:
+      result.add(name)
+      result.add(": ")
+    else:
+      count.inc
     when compiles($value):
       when value isnot string and value isnot seq and compiles(value.isNil):
         if value.isNil: result.add "nil"
@@ -2673,6 +2705,11 @@ proc `$`*[T: tuple|object](x: T): string =
       firstElement = false
     else:
       result.add("...")
+      firstElement = false
+  when not isNamed:
+    if count == 1:
+      result.add(",") # $(1,) should print as the semantically legal (1,)
+
   result.add(")")
 
 proc collectionToString[T](x: T, prefix, separator, suffix: string): string =
@@ -2711,6 +2748,16 @@ proc `$`*[T](x: seq[T]): string =
   ##   $(@[23, 45]) == "@[23, 45]"
   collectionToString(x, "@[", ", ", "]")
 
+proc `$`*[T, U](x: HSlice[T, U]): string =
+  ## generic ``$`` operator for slices that is lifted from the components
+  ## of `x`. Example:
+  ##
+  ## .. code-block:: nim
+  ##  $(1 .. 5) == "1 .. 5"
+  result = $x.a
+  result.add(" .. ")
+  result.add($x.b)
+
 # ----------------- GC interface ---------------------------------------------
 
 when not defined(nimscript) and hasAlloc:
@@ -2760,8 +2807,8 @@ when not defined(nimscript) and hasAlloc:
 
     when not defined(JS) and not defined(nimscript) and hasAlloc:
       proc nimGC_setStackBottom*(theStackBottom: pointer) {.compilerRtl, noinline, benign.}
-      ## Expands operating GC stack range to `theStackBottom`. Does nothing
-      ## if current stack bottom is already lower than `theStackBottom`.
+        ## Expands operating GC stack range to `theStackBottom`. Does nothing
+        ## if current stack bottom is already lower than `theStackBottom`.
 
   else:
     template GC_disable* =
@@ -3075,7 +3122,7 @@ when not defined(JS): #and not defined(nimscript):
     proc initStackBottom() {.inline, compilerproc.} =
       # WARNING: This is very fragile! An array size of 8 does not work on my
       # Linux 64bit system. -- That's because the stack direction is the other
-      # way round.
+      # way around.
       when declared(nimGC_setStackBottom):
         var locals {.volatile.}: pointer
         locals = addr(locals)
@@ -3147,7 +3194,7 @@ when not defined(JS): #and not defined(nimscript):
         result = x.len - y.len
 
   when defined(nimscript):
-    proc readFile*(filename: string): string {.tags: [ReadIOEffect], benign.}
+    proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.}
       ## Opens a file named `filename` for reading, calls `readAll
       ## <#readAll>`_ and closes the file afterwards. Returns the string.
       ## Raises an IO exception in case of an error. If # you need to call
@@ -3196,14 +3243,15 @@ when not defined(JS): #and not defined(nimscript):
 
     proc open*(f: var File, filename: string,
                mode: FileMode = fmRead, bufSize: int = -1): bool {.tags: [],
-               benign.}
+               raises: [], benign.}
       ## Opens a file named `filename` with given `mode`.
       ##
       ## Default mode is readonly. Returns true iff the file could be opened.
       ## This throws no exception if the file could not be opened.
 
     proc open*(f: var File, filehandle: FileHandle,
-               mode: FileMode = fmRead): bool {.tags: [], benign.}
+               mode: FileMode = fmRead): bool {.tags: [], raises: [],
+               benign.}
       ## Creates a ``File`` from a `filehandle` with given `mode`.
       ##
       ## Default mode is readonly. Returns true iff the file could be opened.
@@ -3212,7 +3260,7 @@ when not defined(JS): #and not defined(nimscript):
                mode: FileMode = fmRead, bufSize: int = -1): File =
       ## Opens a file named `filename` with given `mode`.
       ##
-      ## Default mode is readonly. Raises an ``IO`` exception if the file
+      ## Default mode is readonly. Raises an ``IOError`` if the file
       ## could not be opened.
       if not open(result, filename, mode, bufSize):
         sysFatal(IOError, "cannot open: ", filename)
@@ -3415,6 +3463,10 @@ when not defined(JS): #and not defined(nimscript):
       ## allows you to override the behaviour of your application when CTRL+C
       ## is pressed. Only one such hook is supported.
 
+    when not defined(useNimRtl):
+      proc unsetControlCHook*()
+        ## reverts a call to setControlCHook
+
     proc writeStackTrace*() {.tags: [], gcsafe.}
       ## writes the current stack trace to ``stderr``. This is only works
       ## for debug builds. Since it's usually used for debugging, this
@@ -3431,6 +3483,10 @@ when not defined(JS): #and not defined(nimscript):
     when defined(memtracker):
       include "system/memtracker"
 
+    when defined(gcDestructors):
+      include "core/strs"
+      include "core/seqs"
+
     when hostOS == "standalone":
       include "system/embedded"
     else:
@@ -3479,10 +3535,7 @@ when not defined(JS): #and not defined(nimscript):
     {.pop.}
     {.push stack_trace: off, profiler:off.}
     when hasAlloc:
-      when defined(gcDestructors):
-        include "core/strs"
-        include "core/seqs"
-      else:
+      when not defined(gcDestructors):
         include "system/sysstr"
     {.pop.}
     when hasAlloc: include "system/strmantle"
@@ -3568,7 +3621,7 @@ when not defined(JS): #and not defined(nimscript):
   when defined(endb) and not defined(nimscript):
     include "system/debugger"
 
-  when defined(profiler) or defined(memProfiler):
+  when (defined(profiler) or defined(memProfiler)) and not defined(nimscript):
     include "system/profiler"
   {.pop.} # stacktrace
 
@@ -3609,7 +3662,7 @@ elif defined(JS):
   proc deallocShared(p: pointer) = discard
   proc reallocShared(p: pointer, newsize: Natural): pointer = discard
 
-  when defined(JS):
+  when defined(JS) and not defined(nimscript):
     include "system/jssys"
     include "system/reprjs"
   elif defined(nimscript):
@@ -3833,15 +3886,21 @@ proc gorgeEx*(command: string, input = "", cache = ""): tuple[output: string,
   ## Same as `gorge` but also returns the precious exit code.
   discard
 
-proc `+=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.
+proc `+=`*[T: SomeInteger](x: var T, y: T) {.
   magic: "Inc", noSideEffect.}
-  ## Increments an ordinal
+  ## Increments an integer
+
+proc `+=`*[T: enum|bool](x: var T, y: T) {.
+  magic: "Inc", noSideEffect, deprecated: "use `inc` instead".}
 
-proc `-=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.
+proc `-=`*[T: SomeInteger](x: var T, y: T) {.
   magic: "Dec", noSideEffect.}
   ## Decrements an ordinal
 
-proc `*=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.
+proc `-=`*[T: enum|bool](x: var T, y: T) {.
+  magic: "Dec", noSideEffect, deprecated: "0.20.0, use `dec` instead".}
+
+proc `*=`*[T: SomeInteger](x: var T, y: T) {.
   inline, noSideEffect.} =
   ## Binary `*=` operator for ordinals
   x = x * y
@@ -3919,7 +3978,7 @@ proc instantiationInfo*(index = -1, fullPaths = false): tuple[
 template currentSourcePath*: string = instantiationInfo(-1, true).filename
   ## returns the full file-system path of the current source
 
-proc raiseAssert*(msg: string) {.noinline.} =
+proc raiseAssert*(msg: string) {.noinline, noReturn.} =
   sysFatal(AssertionError, msg)
 
 proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
@@ -3929,8 +3988,6 @@ proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
                                     tags: [].}
   Hide(raiseAssert)(msg)
 
-include "system/helpers" # for `lineInfoToString`
-
 template assertImpl(cond: bool, msg: string, expr: string, enabled: static[bool]) =
   const loc = $instantiationInfo(-1, true)
   bind instantiationInfo
@@ -4326,24 +4383,7 @@ when defined(windows) and appType == "console" and defined(nimSetUtf8CodePage):
     importc: "SetConsoleOutputCP".}
   discard setConsoleOutputCP(65001) # 65001 - utf-8 codepage
 
-
-when defined(nimHasRunnableExamples):
-  proc runnableExamples*(body: untyped) {.magic: "RunnableExamples".}
-    ## A section you should use to mark `runnable example`:idx: code with.
-    ##
-    ## - In normal debug and release builds code within
-    ##   a ``runnableExamples`` section is ignored.
-    ## - The documentation generator is aware of these examples and considers them
-    ##   part of the ``##`` doc comment. As the last step of documentation
-    ##   generation the examples are put into an ``$file_example.nim`` file,
-    ##   compiled and tested. The collected examples are
-    ##   put into their own module to ensure the examples do not refer to
-    ##   non-exported symbols.
-else:
-  template runnableExamples*(body: untyped) =
-    discard
-
-template doAssertRaises*(exception, code: untyped): typed =
+template doAssertRaises*(exception: typedesc, code: untyped): typed =
   ## Raises ``AssertionError`` if specified ``code`` does not raise the
   ## specified exception. Example:
   ##
@@ -4351,16 +4391,24 @@ template doAssertRaises*(exception, code: untyped): typed =
   ##  doAssertRaises(ValueError):
   ##    raise newException(ValueError, "Hello World")
   var wrong = false
-  try:
-    if true:
-      code
-    wrong = true
-  except exception:
-    discard
-  except Exception as exc:
-    raiseAssert(astToStr(exception) &
-                " wasn't raised, another error was raised instead by:\n"&
-                astToStr(code))
+  when Exception is exception:
+    try:
+      if true:
+        code
+      wrong = true
+    except Exception:
+      discard
+  else:
+    try:
+      if true:
+        code
+      wrong = true
+    except exception:
+      discard
+    except Exception as exc:
+      raiseAssert(astToStr(exception) &
+                  " wasn't raised, another error was raised instead by:\n"&
+                  astToStr(code))
   if wrong:
     raiseAssert(astToStr(exception) & " wasn't raised by:\n" & astToStr(code))
 
@@ -4420,3 +4468,12 @@ when defined(genode):
       componentConstructHook(env)
         # Perform application initialization
         # and return to thread entrypoint.
+
+proc `$`*(t: typedesc): string {.magic: "TypeTrait".} =
+  ## Returns the name of the given type.
+  ##
+  ## For more procedures dealing with ``typedesc``, see ``typetraits.nim``.
+  runnableExamples:
+    doAssert $(type(42)) == "int"
+    doAssert $(type("Foo")) == "string"
+    static: doAssert $(type(@['A', 'B'])) == "seq[char]"
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index b090117a9..e938dc475 100644
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -20,7 +20,7 @@ template track(op, address, size) =
 # Each chunk starts at an address that is divisible by the page size.
 
 const
-  InitialMemoryRequest = 128 * PageSize # 0.5 MB
+  nimMinHeapPages {.intdefine.} = 128 # 0.5 MB
   SmallChunkSize = PageSize
   MaxFli = 30
   MaxLog2Sli = 5 # 32, this cannot be increased without changing 'uint32'
@@ -588,8 +588,8 @@ proc getBigChunk(a: var MemRegion, size: int): PBigChunk =
   sysAssert((size and PageMask) == 0, "getBigChunk: unaligned chunk")
   result = findSuitableBlock(a, fl, sl)
   if result == nil:
-    if size < InitialMemoryRequest:
-      result = requestOsChunks(a, InitialMemoryRequest)
+    if size < nimMinHeapPages * PageSize:
+      result = requestOsChunks(a, nimMinHeapPages * PageSize)
       splitChunk(a, result, size)
     else:
       result = requestOsChunks(a, size)
diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim
index 38910dbd6..af34060d8 100644
--- a/lib/system/ansi_c.nim
+++ b/lib/system/ansi_c.nim
@@ -51,7 +51,7 @@ when defined(windows):
 elif defined(macosx) or defined(linux) or defined(freebsd) or
      defined(openbsd) or defined(netbsd) or defined(solaris) or
      defined(dragonfly) or defined(nintendoswitch) or defined(genode) or
-     defined(aix):
+     defined(aix) or hostOS == "standalone":
   const
     SIGABRT = cint(6)
     SIGFPE = cint(8)
diff --git a/lib/system/embedded.nim b/lib/system/embedded.nim
index 4d453fcca..fb89e7f0f 100644
--- a/lib/system/embedded.nim
+++ b/lib/system/embedded.nim
@@ -40,6 +40,7 @@ proc reraiseException() {.compilerRtl.} =
 
 proc writeStackTrace() = discard
 
+proc unsetControlCHook() = discard
 proc setControlCHook(hook: proc () {.noconv.}) = discard
 
 proc closureIterSetupExc(e: ref Exception) {.compilerproc, inline.} =
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 84a1da343..3efefead4 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -536,3 +536,8 @@ proc setControlCHook(hook: proc () {.noconv.}) =
   # ugly cast, but should work on all architectures:
   type SignalHandler = proc (sign: cint) {.noconv, benign.}
   c_signal(SIGINT, cast[SignalHandler](hook))
+
+when not defined(useNimRtl):
+  proc unsetControlCHook() =
+    # proc to unset a hook set by setControlCHook
+    c_signal(SIGINT, signalHandler)
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index fb20edbbb..9ae388aa9 100644
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -17,9 +17,9 @@
 const
   CycleIncrease = 2 # is a multiplicative increase
   InitialCycleThreshold = 4*1024*1024 # X MB because cycle checking is slow
-  ZctThreshold = 500  # we collect garbage if the ZCT's size
-                      # reaches this threshold
-                      # this seems to be a good value
+  InitialZctThreshold = 500  # we collect garbage if the ZCT's size
+                             # reaches this threshold
+                             # this seems to be a good value
   withRealTime = defined(useRealtimeGC)
 
 when withRealTime and not declared(getTicks):
@@ -78,6 +78,7 @@ type
     when nimCoroutines:
       activeStack: ptr GcStack    # current executing coroutine stack.
     cycleThreshold: int
+    zctThreshold: int
     when useCellIds:
       idGenerator: int
     zct: CellSeq             # the zero count table
@@ -253,6 +254,7 @@ proc initGC() =
     when traceGC:
       for i in low(CellState)..high(CellState): init(states[i])
     gch.cycleThreshold = InitialCycleThreshold
+    gch.zctThreshold = InitialZctThreshold
     gch.stat.stackScans = 0
     gch.stat.cycleCollections = 0
     gch.stat.maxThreshold = 0
@@ -771,11 +773,7 @@ proc collectCTBody(gch: var GcHeap) =
         c_fprintf(stdout, "[GC] missed deadline: %ld\n", duration)
 
 proc collectCT(gch: var GcHeap) =
-  # stackMarkCosts prevents some pathological behaviour: Stack marking
-  # becomes more expensive with large stacks and large stacks mean that
-  # cells with RC=0 are more likely to be kept alive by the stack.
-  let stackMarkCosts = max(stackSize() div (16*sizeof(int)), ZctThreshold)
-  if (gch.zct.len >= stackMarkCosts or (cycleGC and
+  if (gch.zct.len >= gch.zctThreshold or (cycleGC and
       getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
       gch.recGcLock == 0:
     when false:
@@ -783,6 +781,7 @@ proc collectCT(gch: var GcHeap) =
       cellsetReset(gch.marked)
       markForDebug(gch)
     collectCTBody(gch)
+    gch.zctThreshold = max(InitialZctThreshold, gch.zct.len * CycleIncrease)
 
 when withRealTime:
   proc toNano(x: int): Nanos {.inline.} =
@@ -793,10 +792,11 @@ when withRealTime:
 
   proc GC_step(gch: var GcHeap, us: int, strongAdvice: bool) =
     gch.maxPause = us.toNano
-    if (gch.zct.len >= ZctThreshold or (cycleGC and
+    if (gch.zct.len >= gch.zctThreshold or (cycleGC and
         getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) or
         strongAdvice:
       collectCTBody(gch)
+      gch.zctThreshold = max(InitialZctThreshold, gch.zct.len * CycleIncrease)
 
   proc GC_step*(us: int, strongAdvice = false, stackSize = -1) {.noinline.} =
     if stackSize >= 0:
diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim
index 565453298..ebd3dada2 100644
--- a/lib/system/gc_common.nim
+++ b/lib/system/gc_common.nim
@@ -418,7 +418,7 @@ proc prepareDealloc(cell: PCell) =
   decTypeSize(cell, t)
 
 proc deallocHeap*(runFinalizers = true; allowGcAfterwards = true) =
-  ## Frees the thread local heap. Runs every finalizer if ``runFinalizers```
+  ## Frees the thread local heap. Runs every finalizer if ``runFinalizers``
   ## is true. If ``allowGcAfterwards`` is true, a minimal amount of allocation
   ## happens to ensure the GC can continue to work after the call
   ## to ``deallocHeap``.
diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim
index d8cb3e2d0..aa5fb6aea 100644
--- a/lib/system/gc_ms.nim
+++ b/lib/system/gc_ms.nim
@@ -485,8 +485,9 @@ proc collectCTBody(gch: var GcHeap) =
   sysAssert(allocInv(gch.region), "collectCT: end")
 
 proc collectCT(gch: var GcHeap; size: int) =
+  let fmem = getFreeMem(gch.region)
   if (getOccupiedMem(gch.region) >= gch.cycleThreshold or
-      size > getFreeMem(gch.region)) and gch.recGcLock == 0:
+      size > fmem and fmem > InitialThreshold) and gch.recGcLock == 0:
     collectCTBody(gch)
 
 when not defined(useNimRtl):
diff --git a/lib/system/gc_regions.nim b/lib/system/gc_regions.nim
index 8a1446944..3b908fb08 100644
--- a/lib/system/gc_regions.nim
+++ b/lib/system/gc_regions.nim
@@ -23,6 +23,21 @@ when defined(nimphpext):
   proc osDeallocPages(p: pointer, size: int) {.inline.} =
     efree(p)
 
+elif defined(useMalloc):
+  proc roundup(x, v: int): int {.inline.} =
+    result = (x + (v-1)) and not (v-1)
+  proc emalloc(size: int): pointer {.importc: "malloc", header: "<stdlib.h>".}
+  proc efree(mem: pointer) {.importc: "free", header: "<stdlib.h>".}
+
+  proc osAllocPages(size: int): pointer {.inline.} =
+    emalloc(size)
+
+  proc osTryAllocPages(size: int): pointer {.inline.} =
+    emalloc(size)
+
+  proc osDeallocPages(p: pointer, size: int) {.inline.} =
+    efree(p)
+
 else:
   include osalloc
 
@@ -108,6 +123,8 @@ template `+!`(p: pointer, s: int): pointer =
 template `-!`(p: pointer, s: int): pointer =
   cast[pointer](cast[int](p) -% s)
 
+const nimMinHeapPages {.intdefine.} = 4
+
 proc allocSlowPath(r: var MemRegion; size: int) =
   # we need to ensure that the underlying linked list
   # stays small. Say we want to grab 16GB of RAM with some
@@ -116,9 +133,8 @@ proc allocSlowPath(r: var MemRegion; size: int) =
   # 8MB, 16MB, 32MB, 64MB, 128MB, 512MB, 1GB, 2GB, 4GB, 8GB,
   # 16GB --> list contains only 20 elements! That's reasonable.
   if (r.totalSize and 1) == 0:
-    r.nextChunkSize =
-      if r.totalSize < 64 * 1024: PageSize*4
-      else: r.nextChunkSize*2
+    r.nextChunkSize = if r.totalSize < 64 * 1024: PageSize*nimMinHeapPages
+                      else: r.nextChunkSize*2
   var s = roundup(size+sizeof(BaseChunk), PageSize)
   var fresh: Chunk
   if s > r.nextChunkSize:
@@ -242,6 +258,13 @@ proc deallocAll*() = tlRegion.deallocAll()
 proc deallocOsPages(r: var MemRegion) = r.deallocAll()
 
 template withScratchRegion*(body: untyped) =
+  let obs = obstackPtr()
+  try:
+    body
+  finally:
+    setObstackPtr(obs)
+
+when false:
   var scratch: MemRegion
   let oldRegion = tlRegion
   tlRegion = scratch
diff --git a/lib/system/helpers.nim b/lib/system/helpers.nim
index fb1218684..a7e47915e 100644
--- a/lib/system/helpers.nim
+++ b/lib/system/helpers.nim
@@ -1,11 +1,28 @@
-## helpers used system.nim and other modules, avoids code duplication while
-## also minimizing symbols exposed in system.nim
+# helpers used system.nim and other modules, avoids code duplication while
+# also minimizing symbols exposed in system.nim
 #
 # TODO: move other things here that should not be exposed in system.nim
 
 proc lineInfoToString(file: string, line, column: int): string =
   file & "(" & $line & ", " & $column & ")"
 
-proc `$`(info: type(instantiationInfo(0))): string =
+type InstantiationInfo = tuple[filename: string, line: int, column: int]
+
+proc `$`(info: InstantiationInfo): string =
   # The +1 is needed here
+  # instead of overriding `$` (and changing its meaning), consider explicit name.
   lineInfoToString(info.fileName, info.line, info.column+1)
+
+proc isNamedTuple(T: type): bool =
+  ## return true for named tuples, false for any other type.
+  when T isnot tuple: result = false
+  else:
+    var t: T
+    for name, _ in t.fieldPairs:
+      when name == "Field0":
+        return compiles(t.Field0)
+      else:
+        return true
+    # empty tuple should be un-named,
+    # see https://github.com/nim-lang/Nim/issues/8861#issue-356631191
+    return false
diff --git a/lib/system/helpers2.nim b/lib/system/helpers2.nim
index 1c9e7c068..c67a2c278 100644
--- a/lib/system/helpers2.nim
+++ b/lib/system/helpers2.nim
@@ -1,3 +1,5 @@
+# imported by other modules, unlike helpers.nim which is included
+
 template formatErrorIndexBound*[T](i, a, b: T): string =
   "index out of bounds: (a:" & $a & ") <= (i:" & $i & ") <= (b:" & $b & ") "
 
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index 8be19e5b8..d7718e4f4 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -46,7 +46,7 @@ proc nimCharToStr(x: char): string {.compilerproc.} =
   result[0] = x
 
 proc isNimException(): bool {.asmNoStackFrame.} =
-  asm "return `lastJSError`.m_type;"
+  asm "return `lastJSError` && `lastJSError`.m_type;"
 
 proc getCurrentException*(): ref Exception {.compilerRtl, benign.} =
   if isNimException(): result = cast[ref Exception](lastJSError)
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index 89bc11d2c..9cc7ab323 100644
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -72,6 +72,8 @@ when defined(boehmgc):
   proc boehmGCincremental {.
     importc: "GC_enable_incremental", boehmGC.}
   proc boehmGCfullCollect {.importc: "GC_gcollect", boehmGC.}
+  proc boehmGC_set_all_interior_pointers(flag: cint) {.
+    importc: "GC_set_all_interior_pointers", boehmGC.}
   proc boehmAlloc(size: int): pointer {.importc: "GC_malloc", boehmGC.}
   proc boehmAllocAtomic(size: int): pointer {.
     importc: "GC_malloc_atomic", boehmGC.}
@@ -148,6 +150,7 @@ when defined(boehmgc):
     proc nimGC_setStackBottom(theStackBottom: pointer) = discard
 
   proc initGC() =
+    boehmGC_set_all_interior_pointers(0)
     boehmGCinit()
     when hasThreadSupport:
       boehmGC_allow_register_threads()
diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim
index fc4b574e4..e879fda83 100644
--- a/lib/system/nimscript.nim
+++ b/lib/system/nimscript.nim
@@ -46,7 +46,7 @@ proc copyDir(src, dest: string) {.
   tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin
 proc createDir(dir: string) {.tags: [WriteIOEffect], raises: [OSError].} =
   builtin
-proc getOsError: string = builtin
+proc getError: string = builtin
 proc setCurrentDir(dir: string) = builtin
 proc getCurrentDir*(): string =
   ## Retrieves the current working directory.
@@ -143,6 +143,7 @@ proc existsDir*(dir: string): bool =
 
 proc selfExe*(): string =
   ## Returns the currently running nim or nimble executable.
+  # TODO: consider making this as deprecated alias of `getCurrentCompilerExe`
   builtin
 
 proc toExe*(filename: string): string =
@@ -177,9 +178,12 @@ var
   mode*: ScriptMode ## Set this to influence how mkDir, rmDir, rmFile etc.
                     ## behave
 
+template checkError(exc: untyped): untyped =
+  let err = getError()
+  if err.len > 0: raise newException(exc, err)
+
 template checkOsError =
-  let err = getOsError()
-  if err.len > 0: raise newException(OSError, err)
+  checkError(OSError)
 
 template log(msg: string, body: untyped) =
   if mode in {ScriptMode.Verbose, ScriptMode.Whatif}:
@@ -331,6 +335,26 @@ proc cppDefine*(define: string) =
   ## needs to be mangled.
   builtin
 
+proc stdinReadLine(): TaintedString {.
+  tags: [ReadIOEffect], raises: [IOError].} =
+  builtin
+
+proc stdinReadAll(): TaintedString {.
+  tags: [ReadIOEffect], raises: [IOError].} =
+  builtin
+
+proc readLineFromStdin*(): TaintedString {.raises: [IOError].} =
+  ## Reads a line of data from stdin - blocks until \n or EOF which happens when stdin is closed
+  log "readLineFromStdin":
+    result = stdinReadLine()
+    checkError(EOFError)
+
+proc readAllFromStdin*(): TaintedString {.raises: [IOError].} =
+  ## Reads all data from stdin - blocks until EOF which happens when stdin is closed
+  log "readAllFromStdin":
+    result = stdinReadAll()
+    checkError(EOFError)
+
 when not defined(nimble):
   template `==?`(a, b: string): bool = cmpIgnoreStyle(a, b) == 0
   template task*(name: untyped; description: string; body: untyped): untyped =
@@ -340,14 +364,15 @@ when not defined(nimble):
     ## .. code-block:: nim
     ##  task build, "default build is via the C backend":
     ##    setCommand "c"
-    proc `name Task`*() = body
+    proc `name Task`*() =
+      setCommand "nop"
+      body
 
     let cmd = getCommand()
     if cmd.len == 0 or cmd ==? "help":
       setCommand "help"
       writeTask(astToStr(name), description)
     elif cmd ==? astToStr(name):
-      setCommand "nop"
       `name Task`()
 
   # nimble has its own implementation for these things.
diff --git a/lib/system/profiler.nim b/lib/system/profiler.nim
index ffd6fd0c5..0649f1176 100644
--- a/lib/system/profiler.nim
+++ b/lib/system/profiler.nim
@@ -13,6 +13,9 @@
 # (except perhaps loops that have no side-effects). At every Nth call a
 # stack trace is taken. A stack tace is a list of cstrings.
 
+when defined(profiler) and defined(memProfiler):
+  {.error: "profiler and memProfiler cannot be defined at the same time (See Embedded Stack Trace Profiler (ESTP) User Guide) for more details".}
+
 {.push profiler: off.}
 
 const
@@ -57,13 +60,13 @@ proc captureStackTrace(f: PFrame, st: var StackTrace) =
     b = b.prev
 
 var
-  profilingRequestedHook*: proc (): bool {.nimcall, benign.}
+  profilingRequestedHook*: proc (): bool {.nimcall, locks: 0, gcsafe.}
     ## set this variable to provide a procedure that implements a profiler in
     ## user space. See the `nimprof` module for a reference implementation.
 
 when defined(memProfiler):
   type
-    MemProfilerHook* = proc (st: StackTrace, requestedSize: int) {.nimcall, benign.}
+    MemProfilerHook* = proc (st: StackTrace, requestedSize: int) {.nimcall, locks: 0, gcsafe.}
 
   var
     profilerHook*: MemProfilerHook
@@ -87,9 +90,10 @@ else:
   proc callProfilerHook(hook: ProfilerHook) {.noinline.} =
     # 'noinline' so that 'nimProfile' does not perform the stack allocation
     # in the common case.
-    var st: StackTrace
-    captureStackTrace(framePtr, st)
-    hook(st)
+    when not defined(nimdoc):
+      var st: StackTrace
+      captureStackTrace(framePtr, st)
+      hook(st)
 
   proc nimProfile() =
     ## This is invoked by the compiler in every loop and on every proc entry!
diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim
index ceaecb4f9..3c681fc53 100644
--- a/lib/system/strmantle.nim
+++ b/lib/system/strmantle.nim
@@ -7,7 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-## Compilerprocs for strings that do not depend on the string implementation.
+# Compilerprocs for strings that do not depend on the string implementation.
 
 proc cmpStrings(a, b: string): int {.inline, compilerProc.} =
   let alen = a.len
diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim
index 20964b166..5b0278d74 100644
--- a/lib/system/sysio.nim
+++ b/lib/system/sysio.nim
@@ -74,10 +74,21 @@ proc raiseEIO(msg: string) {.noinline, noreturn.} =
 proc raiseEOF() {.noinline, noreturn.} =
   sysFatal(EOFError, "EOF reached")
 
+proc strerror(errnum: cint): cstring {.importc, header: "<string.h>".}
+
+when not defined(NimScript):
+  var
+    errno {.importc, header: "<errno.h>".}: cint ## error variable
+
 proc checkErr(f: File) =
-  if c_ferror(f) != 0:
-    c_clearerr(f)
-    raiseEIO("Unknown IO Error")
+  when not defined(NimScript):
+    if c_ferror(f) != 0:
+      let msg = "errno: " & $errno & " `" & $strerror(errno) & "`"
+      c_clearerr(f)
+      raiseEIO(msg)
+  else:
+    # shouldn't happen
+    quit(1)
 
 {.push stackTrace:off, profiler:off.}
 proc readBuffer(f: File, buffer: pointer, len: Natural): int =
diff --git a/lib/system/timers.nim b/lib/system/timers.nim
index dd8350e2d..4cd2fe840 100644
--- a/lib/system/timers.nim
+++ b/lib/system/timers.nim
@@ -49,7 +49,7 @@ elif defined(macosx):
   mach_timebase_info(timeBaseInfo)
 
   proc `-`(a, b: Ticks): Nanos =
-    result = (a.int64 - b.int64)  * timeBaseInfo.numer div timeBaseInfo.denom
+    result = (a.int64 - b.int64) * timeBaseInfo.numer div timeBaseInfo.denom
 
 elif defined(posixRealtime):
   type
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index 3e37b824c..6c480d03a 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -516,9 +516,6 @@ type
     fd_count*: cint # unsigned
     fd_array*: array[0..FD_SETSIZE-1, SocketHandle]
 
-  Timeval* = object
-    tv_sec*, tv_usec*: int32
-
   AddrInfo* = object
     ai_flags*: cint         ## Input flags.
     ai_family*: cint        ## Address family of socket.
@@ -531,6 +528,14 @@ type
 
   SockLen* = cuint
 
+when defined(cpp):
+  type
+    Timeval* {.importc: "timeval", header: "<time.h>".} = object
+      tv_sec*, tv_usec*: int32
+else:
+  type
+    Timeval* = object
+      tv_sec*, tv_usec*: int32
 
 var
   SOMAXCONN* {.importc, header: "winsock2.h".}: cint
diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim
index 2f072d5c7..9ee73a44d 100644
--- a/lib/wrappers/openssl.nim
+++ b/lib/wrappers/openssl.nim
@@ -38,7 +38,11 @@ when useWinVersion:
 
   from winlean import SocketHandle
 else:
-  const versions = "(.1.1|.38|.39|.41|.43|.44|.45|.46|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|)"
+  when defined(osx):
+    # todo: find a better workaround for #10281 (caused by #10230)
+    const versions = "(.1.1|.38|.39|.41|.43|.44|.45|.46|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|)"
+  else:
+    const versions = "(.1.1|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|.46|.45|.44|.43|.41|.39|.38|.10|)"
 
   when defined(macosx):
     const