summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2016-04-19 12:11:18 +0200
committerAndreas Rumpf <rumpf_a@web.de>2016-04-19 12:11:18 +0200
commitef9a9b119dbcdf00eb66a368efc5e07d0d8d4828 (patch)
treea89c552d0de55ead5a6b031ddb4fc2ddbdec2b35
parent4d56b7da5a9558ac45158b5c614e4aa4e922d864 (diff)
parentd7e8b89eb8f159e0220c48cd06233b7a6a060a72 (diff)
downloadNim-ef9a9b119dbcdf00eb66a368efc5e07d0d8d4828.tar.gz
Merge branch 'devel' of github.com:nim-lang/Nim into devel
-rw-r--r--compiler/ccgtypes.nim2
-rw-r--r--compiler/patterns.nim2
-rw-r--r--compiler/transf.nim4
-rw-r--r--compiler/types.nim12
-rw-r--r--lib/core/macros.nim6
-rw-r--r--lib/impure/rdstdin.nim7
-rw-r--r--lib/impure/ssl.nim3
-rw-r--r--lib/nimbase.h2
-rw-r--r--lib/posix/posix.nim14
-rw-r--r--lib/pure/asyncdispatch.nim30
-rw-r--r--lib/pure/asyncfile.nim4
-rw-r--r--lib/pure/asyncnet.nim26
-rw-r--r--lib/pure/base64.nim3
-rw-r--r--lib/pure/collections/tables.nim41
-rw-r--r--lib/pure/httpclient.nim4
-rw-r--r--lib/pure/json.nim66
-rw-r--r--lib/pure/matchers.nim4
-rw-r--r--lib/pure/net.nim104
-rw-r--r--lib/pure/os.nim4
-rw-r--r--lib/pure/strutils.nim90
-rw-r--r--lib/pure/subexes.nim8
-rw-r--r--lib/pure/times.nim92
-rw-r--r--lib/system/gc_ms.nim3
-rw-r--r--lib/windows/winlean.nim2
-rw-r--r--lib/wrappers/openssl.nim4
-rw-r--r--readme.md104
-rw-r--r--tests/async/tasyncfile.nim2
-rw-r--r--tests/cpp/ttemplatetype.nim9
-rw-r--r--tests/js/tclosures.nim51
-rw-r--r--tests/testament/specs.nim9
-rw-r--r--tests/testament/tester.nim12
-rw-r--r--tests/trmacros/tpatterns.nim8
-rw-r--r--tools/website.tmpl12
-rw-r--r--web/assets/style.css11
-rw-r--r--web/news.txt9
35 files changed, 589 insertions, 175 deletions
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 60384be79..ebc3225f2 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -654,7 +654,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
       else:
         result = cppName & "<"
         for i in 1 .. typ.len-2:
-          if i > 1: result.add(", ")
+          if i > 1: result.add(" COMMA ")
           result.add(getTypeDescAux(m, typ.sons[i], check))
         result.add("> ")
       # always call for sideeffects:
diff --git a/compiler/patterns.nim b/compiler/patterns.nim
index 604d3521d..2336e44e7 100644
--- a/compiler/patterns.nim
+++ b/compiler/patterns.nim
@@ -129,7 +129,7 @@ proc matchNested(c: PPatternContext, p, n: PNode, rpn: bool): bool =
       result = bindOrCheck(c, p.sons[2].sym, arglist)
 
 proc matches(c: PPatternContext, p, n: PNode): bool =
-  # hidden conversions (?)
+  let n = skipHidden(n)
   if nfNoRewrite in n.flags:
     result = false
   elif isPatternParam(c, p):
diff --git a/compiler/transf.nim b/compiler/transf.nim
index a4a15ea4a..0647553c6 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -414,8 +414,8 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
         result = newTransNode(nkChckRange, n, 3)
       dest = skipTypes(n.typ, abstractVar)
       result[0] = transform(c, n.sons[1])
-      result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), source).PTransNode
-      result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode
+      result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), dest).PTransNode
+      result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), dest).PTransNode
   of tyFloat..tyFloat128:
     # XXX int64 -> float conversion?
     if skipTypes(n.typ, abstractVar).kind == tyRange:
diff --git a/compiler/types.nim b/compiler/types.nim
index 9aa991086..c9cbfedb1 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -1448,6 +1448,18 @@ proc skipConv*(n: PNode): PNode =
       result = n.sons[1]
   else: discard
 
+proc skipHidden*(n: PNode): PNode =
+  result = n
+  while true:
+    case result.kind
+    of nkHiddenStdConv, nkHiddenSubConv:
+      if result.sons[1].typ.classify == result.typ.classify:
+        result = result.sons[1]
+      else: break
+    of nkHiddenDeref, nkHiddenAddr:
+      result = result.sons[0]
+    else: break
+
 proc skipConvTakeType*(n: PNode): PNode =
   result = n.skipConv
   result.typ = n.typ
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 4522e0fc6..678982a52 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -796,17 +796,17 @@ proc infix*(a: NimNode; op: string;
 proc unpackPostfix*(node: NimNode): tuple[node: NimNode; op: string] {.
   compileTime.} =
   node.expectKind nnkPostfix
-  result = (node[0], $node[1])
+  result = (node[1], $node[0])
 
 proc unpackPrefix*(node: NimNode): tuple[node: NimNode; op: string] {.
   compileTime.} =
   node.expectKind nnkPrefix
-  result = (node[0], $node[1])
+  result = (node[1], $node[0])
 
 proc unpackInfix*(node: NimNode): tuple[left: NimNode; op: string;
                                         right: NimNode] {.compileTime.} =
   assert node.kind == nnkInfix
-  result = (node[0], $node[1], node[2])
+  result = (node[1], $node[0], node[2])
 
 proc copy*(node: NimNode): NimNode {.compileTime.} =
   ## An alias for copyNimTree().
diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim
index 469bb69c5..f722a6b39 100644
--- a/lib/impure/rdstdin.nim
+++ b/lib/impure/rdstdin.nim
@@ -105,7 +105,8 @@ else:
   proc readLineFromStdin*(prompt: string): TaintedString {.
                           tags: [ReadIOEffect, WriteIOEffect].} =
     var buffer = linenoise.readLine(prompt)
-    if isNil(buffer): quit(0)
+    if isNil(buffer):
+      raise newException(IOError, "Linenoise returned nil")
     result = TaintedString($buffer)
     if result.string.len > 0:
       historyAdd(buffer)
@@ -114,12 +115,12 @@ else:
   proc readLineFromStdin*(prompt: string, line: var TaintedString): bool {.
                           tags: [ReadIOEffect, WriteIOEffect].} =
     var buffer = linenoise.readLine(prompt)
-    if isNil(buffer): quit(0)
+    if isNil(buffer):
+      raise newException(IOError, "Linenoise returned nil")
     line = TaintedString($buffer)
     if line.string.len > 0:
       historyAdd(buffer)
     linenoise.free(buffer)
-    # XXX how to determine CTRL+D?
     result = true
 
   proc readPasswordFromStdin*(prompt: string, password: var TaintedString):
diff --git a/lib/impure/ssl.nim b/lib/impure/ssl.nim
index 721e5ce51..e3312d792 100644
--- a/lib/impure/ssl.nim
+++ b/lib/impure/ssl.nim
@@ -9,6 +9,9 @@
 
 ## 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.}
 
diff --git a/lib/nimbase.h b/lib/nimbase.h
index 5a4f403b6..f531f3c49 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -222,6 +222,8 @@ __clang__
 
 /* ----------------------------------------------------------------------- */
 
+#define COMMA ,
+
 #include <limits.h>
 #include <stddef.h>
 
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
index e932d2845..19b068b60 100644
--- a/lib/posix/posix.nim
+++ b/lib/posix/posix.nim
@@ -2627,3 +2627,17 @@ proc utimes*(path: cstring, times: ptr array [2, Timeval]): int {.
   ## Returns zero on success.
   ##
   ## For more information read http://www.unix.com/man-page/posix/3/utimes/.
+
+proc handle_signal(sig: cint, handler: proc (a: cint) {.noconv.}) {.importc: "signal", header: "<signal.h>".} 
+ 
+template onSignal*(signals: varargs[cint], body: untyped): stmt = 
+  ## Setup code to be executed when Unix signals are received. Example: 
+  ## from posix import SIGINT, SIGTERM 
+  ## onSignal(SIGINT, SIGTERM): 
+  ##   echo "bye" 
+ 
+  for s in signals: 
+    handle_signal(s, 
+      proc (sig: cint) {.noconv.} = 
+        body 
+    )
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index cc337452f..01b53cb12 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -1316,6 +1316,23 @@ proc generateExceptionCheck(futSym,
     )
     result.add elseNode
 
+template useVar(result: var NimNode, futureVarNode: NimNode, valueReceiver,
+                rootReceiver: expr, fromNode: NimNode) =
+  ## Params:
+  ##    futureVarNode: The NimNode which is a symbol identifying the Future[T]
+  ##                   variable to yield.
+  ##    fromNode: Used for better debug information (to give context).
+  ##    valueReceiver: The node which defines an expression that retrieves the
+  ##                   future's value.
+  ##
+  ##    rootReceiver: ??? TODO
+  # -> yield future<x>
+  result.add newNimNode(nnkYieldStmt, fromNode).add(futureVarNode)
+  # -> future<x>.read
+  valueReceiver = newDotExpr(futureVarNode, newIdentNode("read"))
+  result.add generateExceptionCheck(futureVarNode, tryStmt, rootReceiver,
+      fromNode)
+
 template createVar(result: var NimNode, futSymName: string,
                    asyncProc: NimNode,
                    valueReceiver, rootReceiver: expr,
@@ -1323,9 +1340,7 @@ template createVar(result: var NimNode, futSymName: string,
   result = newNimNode(nnkStmtList, fromNode)
   var futSym = genSym(nskVar, "future")
   result.add newVarStmt(futSym, asyncProc) # -> var future<x> = y
-  result.add newNimNode(nnkYieldStmt, fromNode).add(futSym) # -> yield future<x>
-  valueReceiver = newDotExpr(futSym, newIdentNode("read")) # -> future<x>.read
-  result.add generateExceptionCheck(futSym, tryStmt, rootReceiver, fromNode)
+  useVar(result, futSym, valueReceiver, rootReceiver, fromNode)
 
 proc processBody(node, retFutureSym: NimNode,
                  subTypeIsVoid: bool,
@@ -1352,7 +1367,11 @@ proc processBody(node, retFutureSym: NimNode,
       case node[1].kind
       of nnkIdent, nnkInfix:
         # await x
-        result = newNimNode(nnkYieldStmt, node).add(node[1]) # -> yield x
+        result = newNimNode(nnkStmtList, node)
+        var futureValue: NimNode
+        result.useVar(node[1], futureValue, futureValue, node)
+        # -> yield x
+        # -> x.read()
       of nnkCall, nnkCommand:
         # await foo(p, x)
         var futureValue: NimNode
@@ -1550,6 +1569,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
   for i in 0 .. <result[4].len:
     if result[4][i].kind == nnkIdent and result[4][i].ident == !"async":
       result[4].del(i)
+  result[4] = newEmptyNode()
   if subtypeIsVoid:
     # Add discardable pragma.
     if returnType.kind == nnkEmpty:
@@ -1559,7 +1579,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
   result[6] = outerProcBody
 
   #echo(treeRepr(result))
-  #if prc[0].getName == "hubConnectionLoop":
+  #if prc[0].getName == "g":
   #  echo(toStrLit(result))
 
 macro async*(prc: stmt): stmt {.immediate.} =
diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim
index c7b9fac18..c91d833fc 100644
--- a/lib/pure/asyncfile.nim
+++ b/lib/pure/asyncfile.nim
@@ -162,7 +162,7 @@ proc read*(f: AsyncFile, size: int): Future[string] =
       # Request completed immediately.
       var bytesRead: DWord
       let overlappedRes = getOverlappedResult(f.fd.Handle,
-          cast[POverlapped](ol)[], bytesRead, false.WinBool)
+          cast[POverlapped](ol), bytesRead, false.WinBool)
       if not overlappedRes.bool:
         let err = osLastError()
         if err.int32 == ERROR_HANDLE_EOF:
@@ -282,7 +282,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
       # Request completed immediately.
       var bytesWritten: DWord
       let overlappedRes = getOverlappedResult(f.fd.Handle,
-          cast[POverlapped](ol)[], bytesWritten, false.WinBool)
+          cast[POverlapped](ol), bytesWritten, false.WinBool)
       if not overlappedRes.bool:
         retFuture.fail(newException(OSError, osErrorMsg(osLastError())))
       else:
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index 6b19a48be..748778566 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -11,7 +11,7 @@
 ## asynchronous dispatcher defined in the ``asyncdispatch`` module.
 ##
 ## SSL
-## ---
+## ----
 ##
 ## SSL can be enabled by compiling with the ``-d:ssl`` flag.
 ##
@@ -62,7 +62,9 @@ import os
 
 export SOBool
 
-when defined(ssl):
+const defineSsl = defined(ssl) or defined(nimdoc)
+
+when defineSsl:
   import openssl
 
 type
@@ -79,7 +81,7 @@ type
     of false: nil
     case isSsl: bool
     of true:
-      when defined(ssl):
+      when defineSsl:
         sslHandle: SslPtr
         sslContext: SslContext
         bioIn: BIO
@@ -125,7 +127,7 @@ proc newAsyncSocket*(domain, sockType, protocol: cint,
                           Domain(domain), SockType(sockType),
                           Protocol(protocol), buffered)
 
-when defined(ssl):
+when defineSsl:
   proc getSslError(handle: SslPtr, err: cint): cint =
     assert err < 0
     var ret = SSLGetError(handle, err.cint)
@@ -186,7 +188,7 @@ proc connect*(socket: AsyncSocket, address: string, port: Port) {.async.} =
   ## or an error occurs.
   await connect(socket.fd.AsyncFD, address, port, socket.domain)
   if socket.isSsl:
-    when defined(ssl):
+    when defineSsl:
       let flags = {SocketFlag.SafeDisconn}
       sslSetConnectState(socket.sslHandle)
       sslLoop(socket, flags, sslDoHandshake(socket.sslHandle))
@@ -197,7 +199,7 @@ template readInto(buf: cstring, size: int, socket: AsyncSocket,
   ## this is a template and not a proc.
   var res = 0
   if socket.isSsl:
-    when defined(ssl):
+    when defineSsl:
       # SSL mode.
       sslLoop(socket, flags,
         sslRead(socket.sslHandle, buf, size.cint))
@@ -274,7 +276,7 @@ proc send*(socket: AsyncSocket, data: string,
   ## data has been sent.
   assert socket != nil
   if socket.isSsl:
-    when defined(ssl):
+    when defineSsl:
       var copy = data
       sslLoop(socket, flags,
         sslWrite(socket.sslHandle, addr copy[0], copy.len.cint))
@@ -426,9 +428,6 @@ proc recvLine*(socket: AsyncSocket,
   ##
   ## **Warning**: ``recvLine`` on unbuffered sockets assumes that the protocol
   ## uses ``\r\L`` to delimit a new line.
-  template addNLIfEmpty(): stmt =
-    if result.len == 0:
-      result.add("\c\L")
   assert SocketFlag.Peek notin flags ## TODO:
 
   # TODO: Optimise this
@@ -456,7 +455,8 @@ proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {.
     of AF_INET6: realaddr = "::"
     of AF_INET:  realaddr = "0.0.0.0"
     else:
-      raiseOSError("Unknown socket address family and no address specified to bindAddr")
+      raise newException(ValueError,
+        "Unknown socket address family and no address specified to bindAddr")
 
   var aiList = getAddrInfo(realaddr, port, socket.domain)
   if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
@@ -468,7 +468,7 @@ proc close*(socket: AsyncSocket) =
   ## Closes the socket.
   defer:
     socket.fd.AsyncFD.closeSocket()
-  when defined(ssl):
+  when defineSsl:
     if socket.isSSL:
       let res = SslShutdown(socket.sslHandle)
       SSLFree(socket.sslHandle)
@@ -478,7 +478,7 @@ proc close*(socket: AsyncSocket) =
         raiseSslError()
   socket.closed = true # TODO: Add extra debugging checks for this.
 
-when defined(ssl):
+when defineSsl:
   proc wrapSocket*(ctx: SslContext, socket: AsyncSocket) =
     ## Wraps a socket in an SSL context. This function effectively turns
     ## ``socket`` into an SSL socket.
diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim
index 32d37ce02..2fc0b1c5e 100644
--- a/lib/pure/base64.nim
+++ b/lib/pure/base64.nim
@@ -90,6 +90,8 @@ template encodeInternal(s: expr, lineLen: int, newLine: string): stmt {.immediat
     if r+4 != result.len:
       setLen(result, r+4)
   else:
+    if r != result.len:
+      setLen(result, r)
     #assert(r == result.len)
     discard
 
@@ -162,4 +164,3 @@ when isMainModule:
                  "asure.", longText]
   for t in items(tests):
     assert decode(encode(t)) == t
-
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index 2ed0d2034..58a789e76 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -663,6 +663,27 @@ proc sort*[A, B](t: OrderedTableRef[A, B],
   ## 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) comlexity.
+  var prev = -1
+  let hc = hash(key)
+  forAllOrderedPairs:
+    if t.data[h].hcode == hc:
+      if t.first == h:
+        t.first = t.data[h].next
+      else:
+        t.data[prev].next = t.data[h].next
+      var zeroValue : type(t.data[h])
+      t.data[h] = zeroValue
+      dec t.counter
+      break
+    else:
+      prev = h
+
+proc del*[A, B](t: var OrderedTableRef[A, B], key: A) =
+  ## deletes `key` from ordered hash table `t`. O(n) comlexity.
+  t[].del(key)
+
 # ------------------------------ count tables -------------------------------
 
 type
@@ -984,6 +1005,26 @@ when isMainModule:
   s3[p1] = 30_000
   s3[p2] = 45_000
 
+  block: # Ordered table should preserve order after deletion
+    var
+      s4 = initOrderedTable[int, int]()
+    s4[1] = 1
+    s4[2] = 2
+    s4[3] = 3
+
+    var prev = 0
+    for i in s4.values:
+      doAssert(prev < i)
+      prev = i
+
+    s4.del(2)
+    doAssert(2 notin s4)
+    doAssert(s4.len == 2)
+    prev = 0
+    for i in s4.values:
+      doAssert(prev < i)
+      prev = i
+
   var
     t1 = initCountTable[string]()
     t2 = initCountTable[string]()
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 603763386..f473e47d1 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -335,7 +335,7 @@ proc addFiles*(p: var MultipartData, xs: openarray[tuple[name, file: string]]):
   var m = newMimetypes()
   for name, file in xs.items:
     var contentType: string
-    let (dir, fName, ext) = splitFile(file)
+    let (_, fName, ext) = splitFile(file)
     if ext.len > 0:
       contentType = m.getMimetype(ext[1..ext.high], nil)
     p.add(name, readFile(file), fName & ext, contentType)
@@ -627,7 +627,7 @@ proc newAsyncHttpClient*(userAgent = defUserAgent,
   result.userAgent = defUserAgent
   result.maxRedirects = maxRedirects
   when defined(ssl):
-    result.sslContext = net.SslContext(sslContext)
+    result.sslContext = sslContext
 
 proc close*(client: AsyncHttpClient) =
   ## Closes any connections held by the HTTP client.
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index b0179cd82..b9da8a0dd 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -56,6 +56,11 @@ import
 export
   tables.`$`
 
+when defined(nimJsonGet):
+  {.pragma: deprecatedGet, deprecated.}
+else:
+  {.pragma: deprecatedGet.}
+
 type
   JsonEventKind* = enum  ## enumeration of all events that may occur when parsing
     jsonError,           ## an error occurred during parsing
@@ -799,16 +804,23 @@ proc len*(n: JsonNode): int =
   of JObject: result = n.fields.len
   else: discard
 
-proc `[]`*(node: JsonNode, name: string): JsonNode {.inline.} =
+proc `[]`*(node: JsonNode, name: string): JsonNode {.inline, deprecatedGet.} =
   ## Gets a field from a `JObject`, which must not be nil.
-  ## If the value at `name` does not exist, returns nil
+  ## If the value at `name` does not exist, raises KeyError.
+  ##
+  ## **Note:** The behaviour of this procedure changed in version 0.14.0. To
+  ## get a list of usages and to restore the old behaviour of this procedure,
+  ## compile with the ``-d:nimJsonGet`` flag.
   assert(not isNil(node))
   assert(node.kind == JObject)
-  result = node.fields.getOrDefault(name)
+  when defined(nimJsonGet):
+    if not node.fields.hasKey(name): return nil
+  result = node.fields[name]
 
 proc `[]`*(node: JsonNode, index: int): JsonNode {.inline.} =
   ## Gets the node at `index` in an Array. Result is undefined if `index`
-  ## is out of bounds
+  ## is out of bounds, but as long as array bound checks are enabled it will
+  ## result in an exception.
   assert(not isNil(node))
   assert(node.kind == JArray)
   return node.elems[index]
@@ -838,20 +850,28 @@ proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} =
 
 proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode =
   ## Traverses the node and gets the given value. If any of the
-  ## keys do not exist, returns nil. Also returns nil if one of the
-  ## intermediate data structures is not an object
+  ## keys do not exist, returns ``nil``. Also returns ``nil`` if one of the
+  ## intermediate data structures is not an object.
   result = node
   for key in keys:
-    if isNil(result) or result.kind!=JObject:
+    if isNil(result) or result.kind != JObject:
       return nil
-    result=result[key]
+    result = result.fields.getOrDefault(key)
+
+proc getOrDefault*(node: JsonNode, key: string): JsonNode =
+  ## Gets a field from a `node`. If `node` is nil or not an object or
+  ## value at `key` does not exist, returns nil
+  if not isNil(node) and node.kind == JObject:
+    result = node.fields.getOrDefault(key)
+
+template simpleGetOrDefault*{`{}`(node, [key])}(node: JsonNode, key: string): JsonNode = node.getOrDefault(key)
 
 proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) =
   ## Traverses the node and tries to set the value at the given location
-  ## to `value` If any of the keys are missing, they are added
+  ## to ``value``. If any of the keys are missing, they are added.
   var node = node
   for i in 0..(keys.len-2):
-    if isNil(node[keys[i]]):
+    if not node.hasKey(keys[i]):
       node[keys[i]] = newJObject()
     node = node[keys[i]]
   node[keys[keys.len-1]] = value
@@ -1217,16 +1237,6 @@ when false:
 # To get that we shall use, obj["json"]
 
 when isMainModule:
-  when not defined(js):
-    var parsed = parseFile("tests/testdata/jsontest.json")
-
-    try:
-      discard parsed["key2"][12123]
-      doAssert(false)
-    except IndexError: doAssert(true)
-
-    var parsed2 = parseFile("tests/testdata/jsontest2.json")
-    doAssert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
 
   let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd", "c": "\ud83c\udf83", "d": "\u00E6"}"""
   # nil passthrough
@@ -1314,3 +1324,19 @@ when isMainModule:
 
   var j4 = %*{"test": nil}
   doAssert j4 == %{"test": newJNull()}
+
+  echo("99% of tests finished. Going to try loading file.")
+
+  # Test loading of file.
+  when not defined(js):
+    var parsed = parseFile("tests/testdata/jsontest.json")
+
+    try:
+      discard parsed["key2"][12123]
+      doAssert(false)
+    except IndexError: doAssert(true)
+
+    var parsed2 = parseFile("tests/testdata/jsontest2.json")
+    doAssert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
+
+  echo("Tests succeeded!")
diff --git a/lib/pure/matchers.nim b/lib/pure/matchers.nim
index 5c28f65a0..7022c21d9 100644
--- a/lib/pure/matchers.nim
+++ b/lib/pure/matchers.nim
@@ -8,6 +8,10 @@
 #
 
 ## This module contains various string matchers for email addresses, etc.
+##
+## **Warning:** This module is deprecated since version 0.14.0.
+{.deprecated.}
+
 {.deadCodeElim: on.}
 
 {.push debugger:off .} # the user does not want to trace a part
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index 394bccee3..5de6667dd 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -8,19 +8,76 @@
 #
 
 ## This module implements a high-level cross-platform sockets interface.
+## The procedures implemented in this module are primarily for blocking sockets.
+## For asynchronous non-blocking sockets use the ``asyncnet`` module together
+## with the ``asyncdispatch`` module.
+##
+## The first thing you will always need to do in order to start using sockets,
+## is to create a new instance of the ``Socket`` type using the ``newSocket``
+## procedure.
+##
+## SSL
+## ====
+##
+## In order to use the SSL procedures defined in this module, you will need to
+## compile your application with the ``-d:ssl`` flag.
+##
+## Examples
+## ========
+##
+## Connecting to a server
+## ----------------------
+##
+## After you create a socket with the ``newSocket`` procedure, you can easily
+## connect it to a server running at a known hostname (or IP address) and port.
+## To do so over TCP, use the example below.
+##
+## .. code-block:: Nim
+##   var socket = newSocket()
+##   socket.connect("google.com", Port(80))
+##
+## UDP is a connectionless protocol, so UDP sockets don't have to explicitly
+## call the ``connect`` procedure. They can simply start sending data
+## immediately.
+##
+## .. code-block:: Nim
+##   var socket = newSocket()
+##   socket.sendTo("192.168.0.1", Port(27960), "status\n")
+##
+## Creating a server
+## -----------------
+##
+## After you create a socket with the ``newSocket`` procedure, you can create a
+## TCP server by calling the ``bindAddr`` and ``listen`` procedures.
+##
+## .. code-block:: Nim
+##   var socket = newSocket()
+##   socket.bindAddr(Port(1234))
+##   socket.listen()
+##
+## You can then begin accepting connections using the ``accept`` procedure.
+##
+## .. code-block:: Nim
+##   var client = newSocket()
+##   var address = ""
+##   while true:
+##     socket.acceptAddr(client, address)
+##     echo("Client connected from: ", address)
+##
 
 {.deadCodeElim: on.}
 import nativesockets, os, strutils, parseutils, times
 export Port, `$`, `==`
 
 const useWinVersion = defined(Windows) or defined(nimdoc)
+const defineSsl = defined(ssl) or defined(nimdoc)
 
-when defined(ssl):
+when defineSsl:
   import openssl
 
 # Note: The enumerations are mapped to Window's constants.
 
-when defined(ssl):
+when defineSsl:
   type
     SslError* = object of Exception
 
@@ -54,7 +111,7 @@ type
       currPos: int # current index in buffer
       bufLen: int # current length of buffer
     of false: nil
-    when defined(ssl):
+    when defineSsl:
       case isSsl: bool
       of true:
         sslHandle: SSLPtr
@@ -160,7 +217,7 @@ proc newSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
     raiseOSError(osLastError())
   result = newSocket(fd, domain, sockType, protocol, buffered)
 
-when defined(ssl):
+when defineSsl:
   CRYPTO_malloc_init()
   SslLibraryInit()
   SslLoadErrorStrings()
@@ -301,7 +358,7 @@ proc socketError*(socket: Socket, err: int = -1, async = false,
   ## error was caused by no data being available to be read.
   ##
   ## If ``err`` is not lower than 0 no exception will be raised.
-  when defined(ssl):
+  when defineSsl:
     if socket.isSSL:
       if err <= 0:
         var ret = SSLGetError(socket.sslHandle, err.cint)
@@ -334,7 +391,7 @@ proc socketError*(socket: Socket, err: int = -1, async = false,
           raiseSSLError()
         else: raiseSSLError("Unknown Error")
 
-  if err == -1 and not (when defined(ssl): socket.isSSL else: false):
+  if err == -1 and not (when defineSsl: socket.isSSL else: false):
     var lastE = if lastError.int == -1: getSocketError(socket) else: lastError
     if async:
       when useWinVersion:
@@ -414,7 +471,7 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
     client.isBuffered = server.isBuffered
 
     # Handle SSL.
-    when defined(ssl):
+    when defineSsl:
       if server.isSSL:
         # We must wrap the client sock in a ssl context.
 
@@ -425,7 +482,7 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
     # Client socket is set above.
     address = $inet_ntoa(sockAddress.sin_addr)
 
-when false: #defined(ssl):
+when false: #defineSsl:
   proc acceptAddrSSL*(server: Socket, client: var Socket,
                       address: var string): SSLAcceptResult {.
                       tags: [ReadIOEffect].} =
@@ -444,7 +501,7 @@ when false: #defined(ssl):
     ## ``AcceptNoClient`` will be returned when no client is currently attempting
     ## to connect.
     template doHandshake(): stmt =
-      when defined(ssl):
+      when defineSsl:
         if server.isSSL:
           client.setBlocking(false)
           # We must wrap the client sock in a ssl context.
@@ -495,7 +552,7 @@ proc accept*(server: Socket, client: var Socket,
 proc close*(socket: Socket) =
   ## Closes a socket.
   try:
-    when defined(ssl):
+    when defineSsl:
       if socket.isSSL:
         ErrClearError()
         # As we are closing the underlying socket immediately afterwards,
@@ -547,8 +604,9 @@ proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) {
   var valuei = cint(if value: 1 else: 0)
   setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei)
 
-when defined(ssl):
-  proc handshake*(socket: Socket): bool {.tags: [ReadIOEffect, WriteIOEffect].} =
+when defineSsl:
+  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.
@@ -557,6 +615,8 @@ when defined(ssl):
     ## ``True`` whenever handshake completed successfully.
     ##
     ## A ESSL 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)
@@ -594,7 +654,7 @@ proc hasDataBuffered*(s: Socket): bool =
   if s.isBuffered:
     result = s.bufLen > 0 and s.currPos != s.bufLen
 
-  when defined(ssl):
+  when defineSsl:
     if s.isSSL and not result:
       result = s.sslHasPeekChar
 
@@ -608,7 +668,7 @@ proc select(readfd: Socket, timeout = 500): int =
 
 proc readIntoBuf(socket: Socket, flags: int32): int =
   result = 0
-  when defined(ssl):
+  when defineSsl:
     if socket.isSSL:
       result = SSLRead(socket.sslHandle, addr(socket.buffer), int(socket.buffer.high))
     else:
@@ -658,7 +718,7 @@ proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ReadIOEffect]
 
     result = read
   else:
-    when defined(ssl):
+    when defineSsl:
       if socket.isSSL:
         if socket.sslHasPeekChar:
           copyMem(data, addr(socket.sslPeekChar), 1)
@@ -696,7 +756,7 @@ proc waitFor(socket: Socket, waited: var float, timeout, size: int,
     if timeout - int(waited * 1000.0) < 1:
       raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
 
-    when defined(ssl):
+    when defineSsl:
       if socket.isSSL:
         if socket.hasDataBuffered:
           # sslPeekChar is present.
@@ -764,7 +824,7 @@ proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} =
 
     c = socket.buffer[socket.currPos]
   else:
-    when defined(ssl):
+    when defineSsl:
       if socket.isSSL:
         if not socket.sslHasPeekChar:
           result = SSLRead(socket.sslHandle, addr(socket.sslPeekChar), 1)
@@ -872,7 +932,7 @@ proc send*(socket: Socket, data: pointer, size: int): int {.
   ##
   ## **Note**: This is a low-level version of ``send``. You likely should use
   ## the version below.
-  when defined(ssl):
+  when defineSsl:
     if socket.isSSL:
       return SSLWrite(socket.sslHandle, cast[cstring](data), size)
 
@@ -943,7 +1003,7 @@ proc sendTo*(socket: Socket, address: string, port: Port,
 
 proc isSsl*(socket: Socket): bool =
   ## Determines whether ``socket`` is a SSL socket.
-  when defined(ssl):
+  when defineSsl:
     result = socket.isSSL
   else:
     result = false
@@ -1253,7 +1313,7 @@ proc connect*(socket: Socket, address: string,
   dealloc(aiList)
   if not success: raiseOSError(lastError)
 
-  when defined(ssl):
+  when defineSsl:
     if socket.isSSL:
       # RFC3546 for SNI specifies that IP addresses are not allowed.
       if not isIpAddress(address):
@@ -1314,8 +1374,10 @@ proc connect*(socket: Socket, address: string, port = Port(0),
   if selectWrite(s, timeout) != 1:
     raise newException(TimeoutError, "Call to 'connect' timed out.")
   else:
-    when defined(ssl):
+    when defineSsl:
       if socket.isSSL:
         socket.fd.setBlocking(true)
+        {.warning[Deprecated]: off.}
         doAssert socket.handshake()
+        {.warning[Deprecated]: on.}
   socket.fd.setBlocking(true)
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 470559e17..dee227c69 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -129,7 +129,7 @@ proc raiseOSError*(errorCode: OSErrorCode; additionalInfo = "") {.noinline.} =
   if additionalInfo.len == 0:
     e.msg = osErrorMsg(errorCode)
   else:
-    e.msg = additionalInfo & " " & osErrorMsg(errorCode)
+    e.msg = osErrorMsg(errorCode) & "\nAdditional info: " & additionalInfo
   if e.msg == "":
     e.msg = "unknown OS error"
   raise e
@@ -1452,7 +1452,7 @@ template rawToFormalFileInfo(rawInfo, formalInfo): expr =
   ## 'rawInfo' is either a 'TBY_HANDLE_FILE_INFORMATION' structure on Windows,
   ## or a 'Stat' structure on posix
   when defined(Windows):
-    template toTime(e): expr = winTimeToUnixTime(rdFileTime(e))
+    template toTime(e: FILETIME): expr {.gensym.} = winTimeToUnixTime(rdFileTime(e)) # local templates default to bind semantics
     template merge(a, b): expr = a or (b shl 32)
     formalInfo.id.device = rawInfo.dwVolumeSerialNumber
     formalInfo.id.file = merge(rawInfo.nFileIndexLow, rawInfo.nFileIndexHigh)
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index eebadf4c0..a5a4ee509 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -784,8 +784,7 @@ 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 currently does not preserve the specific new line characters
-  ## used.
+  ## **Note:** This does not preserve the new line characters used in ``s``.
   result = ""
   var i = 0
   for line in s.splitLines():
@@ -796,32 +795,39 @@ proc indent*(s: string, count: Natural, padding: string = " "): string
     result.add(line)
     i.inc
 
-proc unindent*(s: string, eatAllIndent = false): string {.
-               noSideEffect, rtl, extern: "nsuUnindent".} =
-  ## Unindents `s`.
-  result = newStringOfCap(s.len)
+proc unindent*(s: string, count: Natural, padding: string = " "): string
+    {.noSideEffect, rtl, extern: "nsuUnindent".} =
+  ## Unindents each line in ``s`` by ``count`` amount of ``padding``.
+  ##
+  ## **Note:** This does not preserve the new line characters used in ``s``.
+  result = ""
   var i = 0
-  var pattern = true
-  var indent = 0
-  while s[i] == ' ': inc i
-  var level = if i == 0: -1 else: i
-  while i < s.len:
-    if s[i] == ' ':
-      if i > 0 and s[i-1] in {'\l', '\c'}:
-        pattern = true
-        indent = 0
-      if pattern:
-        inc(indent)
-        if indent > level and not eatAllIndent:
-          result.add(s[i])
-        if level < 0: level = indent
-      else:
-        # a space somewhere: do not delete
-        result.add(s[i])
-    else:
-      pattern = false
-      result.add(s[i])
-    inc i
+  for line in s.splitLines():
+    if i != 0:
+      result.add("\n")
+    var indentCount = 0
+    for j in 0..<count.int:
+      indentCount.inc
+      if line[j .. j + <padding.len] != padding:
+        indentCount = j
+        break
+    result.add(line[indentCount*padding.len .. ^1])
+    i.inc
+
+proc unindent*(s: string): string
+    {.noSideEffect, rtl, extern: "nsuUnindentAll".} =
+  ## Removes all indentation composed of whitespace from each line in ``s``.
+  ##
+  ## For example:
+  ##
+  ## .. code-block:: nim
+  ##   const x = """
+  ##     Hello
+  ##     There
+  ##   """.unindent()
+  ##
+  ##   doAssert x == "Hello\nThere\n"
+  unindent(s, 1000) # TODO: Passing a 1000 is a bit hackish.
 
 proc startsWith*(s, prefix: string): bool {.noSideEffect,
   rtl, extern: "nsuStartsWith".} =
@@ -1743,3 +1749,33 @@ when isMainModule:
   doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz"
   doAssert join([1, 2, 3]) == "123"
   doAssert join(@[1, 2, 3], ", ") == "1, 2, 3"
+
+  doAssert """~~!!foo
+~~!!bar
+~~!!baz""".unindent(2, "~~!!") == "foo\nbar\nbaz"
+
+  doAssert """~~!!foo
+~~!!bar
+~~!!baz""".unindent(2, "~~!!aa") == "~~!!foo\n~~!!bar\n~~!!baz"
+  doAssert """~~foo
+~~  bar
+~~  baz""".unindent(4, "~") == "foo\n  bar\n  baz"
+  doAssert """foo
+bar
+    baz
+  """.unindent(4) == "foo\nbar\nbaz\n"
+  doAssert """foo
+    bar
+    baz
+  """.unindent(2) == "foo\n  bar\n  baz\n"
+  doAssert """foo
+    bar
+    baz
+  """.unindent(100) == "foo\nbar\nbaz\n"
+
+  doAssert """foo
+    foo
+    bar
+  """.unindent() == "foo\nfoo\nbar\n"
+
+  echo("strutils tests passed")
diff --git a/lib/pure/subexes.nim b/lib/pure/subexes.nim
index 5824ace81..22f29b77c 100644
--- a/lib/pure/subexes.nim
+++ b/lib/pure/subexes.nim
@@ -390,11 +390,11 @@ when isMainModule:
 
   doAssert(("type MyEnum* = enum\n  $', '2i'\n  '{..}" % ["fieldA",
     "fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"]).replace(" \n", "\n") ==
-    strutils.unindent """
+    strutils.unindent("""
       type MyEnum* = enum
         fieldA, fieldB,
         FiledClkad, fieldD,
-        fieldE, longishFieldName""")
+        fieldE, longishFieldName""", 6))
 
   doAssert subex"$1($', '{2..})" % ["f", "a", "b", "c"] == "f(a, b, c)"
 
@@ -404,8 +404,8 @@ when isMainModule:
 
   doAssert((subex("type\n  Enum = enum\n    $', '40c'\n    '{..}") % [
     "fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"]).replace(" \n", "\n") ==
-    strutils.unindent """
+    strutils.unindent("""
       type
         Enum = enum
           fieldNameA, fieldNameB, fieldNameC,
-          fieldNameD""")
+          fieldNameD""", 6))
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 29ae52d47..e0ee884a8 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -182,7 +182,16 @@ proc getGMTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], benign.}
   ## converts the calendar time `t` to broken-down time representation,
   ## expressed in Coordinated Universal Time (UTC).
 
-proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], benign.}
+proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], benign, deprecated.}
+  ## converts a broken-down time structure to
+  ## calendar time representation. The function ignores the specified
+  ## contents of the structure members `weekday` and `yearday` and recomputes
+  ## them from the other information in the broken-down time structure.
+  ##
+  ## **Warning:** This procedure is deprecated since version 0.14.0.
+  ## Use ``toTime`` instead.
+
+proc toTime*(timeInfo: TimeInfo): Time {.tags: [], benign.}
   ## converts a broken-down time structure to
   ## calendar time representation. The function ignores the specified
   ## contents of the structure members `weekday` and `yearday` and recomputes
@@ -356,7 +365,7 @@ proc `+`*(a: TimeInfo, interval: TimeInterval): TimeInfo =
   ##
   ## **Note:** This has been only briefly tested and it may not be
   ## very accurate.
-  let t = toSeconds(timeInfoToTime(a))
+  let t = toSeconds(toTime(a))
   let secs = toSeconds(a, interval)
   result = getLocalTime(fromSeconds(t + secs))
 
@@ -365,7 +374,7 @@ proc `-`*(a: TimeInfo, interval: TimeInterval): TimeInfo =
   ##
   ## **Note:** This has been only briefly tested, it is inaccurate especially
   ## when you subtract so much that you reach the Julian calendar.
-  let t = toSeconds(timeInfoToTime(a))
+  let t = toSeconds(toTime(a))
   var intval: TimeInterval
   intval.milliseconds = - interval.milliseconds
   intval.seconds = - interval.seconds
@@ -517,6 +526,11 @@ when not defined(JS):
     # because the header of mktime is broken in my version of libc
     return mktime(timeInfoToTM(cTimeInfo))
 
+  proc toTime(timeInfo: TimeInfo): Time =
+    var cTimeInfo = timeInfo # for C++ we have to make a copy,
+    # because the header of mktime is broken in my version of libc
+    return mktime(timeInfoToTM(cTimeInfo))
+
   proc toStringTillNL(p: cstring): string =
     result = ""
     var i = 0
@@ -618,7 +632,16 @@ elif defined(JS):
     result.setFullYear(timeInfo.year)
     result.setDate(timeInfo.monthday)
 
-  proc `$`(timeInfo: TimeInfo): string = return $(timeInfoToTime(timeInfo))
+  proc toTime*(timeInfo: TimeInfo): Time =
+    result = internGetTime()
+    result.setSeconds(timeInfo.second)
+    result.setMinutes(timeInfo.minute)
+    result.setHours(timeInfo.hour)
+    result.setMonth(ord(timeInfo.month))
+    result.setFullYear(timeInfo.year)
+    result.setDate(timeInfo.monthday)
+
+  proc `$`(timeInfo: TimeInfo): string = return $(toTime(timeInfo))
   proc `$`(time: Time): string = return $time.toLocaleString()
 
   proc `-` (a, b: Time): int64 =
@@ -708,24 +731,24 @@ proc years*(y: int): TimeInterval {.inline.} =
 
 proc `+=`*(t: var Time, ti: TimeInterval) =
   ## modifies `t` by adding the interval `ti`
-  t = timeInfoToTime(getLocalTime(t) + ti)
+  t = toTime(getLocalTime(t) + ti)
 
 proc `+`*(t: Time, ti: TimeInterval): Time =
   ## adds the interval `ti` to Time `t`
   ## by converting to localTime, adding the interval, and converting back
   ##
   ## ``echo getTime() + 1.day``
-  result = timeInfoToTime(getLocalTime(t) + ti)
+  result = toTime(getLocalTime(t) + ti)
 
 proc `-=`*(t: var Time, ti: TimeInterval) =
   ## modifies `t` by subtracting the interval `ti`
-  t = timeInfoToTime(getLocalTime(t) - ti)
+  t = toTime(getLocalTime(t) - ti)
 
 proc `-`*(t: Time, ti: TimeInterval): Time =
   ## adds the interval `ti` to Time `t`
   ##
   ## ``echo getTime() - 1.day``
-  result = timeInfoToTime(getLocalTime(t) - ti)
+  result = toTime(getLocalTime(t) - ti)
 
 proc formatToken(info: TimeInfo, token: string, buf: var string) =
   ## Helper of the format proc to parse individual tokens.
@@ -1193,7 +1216,7 @@ proc parse*(value, layout: string): TimeInfo =
         parseToken(info, token, value, j)
         token = ""
   # Reset weekday as it might not have been provided and the default may be wrong
-  info.weekday = getLocalTime(timeInfoToTime(info)).weekday
+  info.weekday = getLocalTime(toTime(info)).weekday
   return info
 
 # Leap year calculations are adapted from:
@@ -1204,7 +1227,7 @@ proc parse*(value, layout: string): TimeInfo =
 proc countLeapYears*(yearSpan: int): int =
   ## Returns the number of leap years spanned by a given number of years.
   ##
-  ## Note: for leap years, start date is assumed to be 1 AD.
+  ## **Note:** For leap years, start date is assumed to be 1 AD.
   ## counts the number of leap years up to January 1st of a given year.
   ## Keep in mind that if specified year is a leap year, the leap day
   ## has not happened before January 1st of that year.
@@ -1239,13 +1262,14 @@ proc getDayOfWeek*(day, month, year: int): WeekDay =
     y = year - a
     m = month + (12*a) - 2
     d = (day + y + (y div 4) - (y div 100) + (y div 400) + (31*m) div 12) mod 7
-  # The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc. so we must correct
-  # for the WeekDay type.
+  # The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc.
+  # so we must correct for the WeekDay type.
   if d == 0: return dSun
   result = (d-1).WeekDay
 
 proc getDayOfWeekJulian*(day, month, year: int): WeekDay =
-  ## Returns the day of the week enum from day, month and year, according to the Julian calendar.
+  ## Returns the day of the week enum from day, month and year,
+  ## according to the Julian calendar.
   # Day & month start from one.
   let
     a = (14 - month) div 12
@@ -1254,8 +1278,11 @@ proc getDayOfWeekJulian*(day, month, year: int): WeekDay =
     d = (5 + day + y + (y div 4) + (31*m) div 12) mod 7
   result = d.WeekDay
 
-proc timeToTimeInfo*(t: Time): TimeInfo =
+proc timeToTimeInfo*(t: Time): TimeInfo {.deprecated.} =
   ## Converts a Time to TimeInfo.
+  ##
+  ## **Warning:** This procedure is deprecated since version 0.14.0.
+  ## Use ``getLocalTime`` or ``getGMTime`` instead.
   let
     secs = t.toSeconds().int
     daysSinceEpoch = secs div secondsInDay
@@ -1286,34 +1313,21 @@ proc timeToTimeInfo*(t: Time): TimeInfo =
     s = daySeconds mod secondsInMin
   result = TimeInfo(year: y, yearday: yd, month: m, monthday: md, weekday: wd, hour: h, minute: mi, second: s)
 
-proc timeToTimeInterval*(t: Time): TimeInterval =
+proc timeToTimeInterval*(t: Time): TimeInterval {.deprecated.} =
   ## Converts a Time to a TimeInterval.
+  ##
+  ## **Warning:** This procedure is deprecated since version 0.14.0.
+  ## Use ``toTimeInterval`` instead.
+  # Milliseconds not available from Time
+  var tInfo = t.getLocalTime()
+  initInterval(0, tInfo.second, tInfo.minute, tInfo.hour, tInfo.weekday.ord, tInfo.month.ord, tInfo.year)
 
-  let
-    secs = t.toSeconds().int
-    daysSinceEpoch = secs div secondsInDay
-    (yearsSinceEpoch, daysRemaining) = countYearsAndDays(daysSinceEpoch)
-    daySeconds = secs mod secondsInDay
-
-  result.years = yearsSinceEpoch + epochStartYear
-
-  var
-    mon = mJan
-    days = daysRemaining
-    daysInMonth = getDaysInMonth(mon, result.years)
-
-  # calculate month and day remainder
-  while days > daysInMonth and mon <= mDec:
-    days -= daysInMonth
-    mon.inc
-    daysInMonth = getDaysInMonth(mon, result.years)
-
-  result.months = mon.int + 1 # month is 1 indexed int
-  result.days = days
-  result.hours = daySeconds div secondsInHour + 1
-  result.minutes = (daySeconds mod secondsInHour) div secondsInMin
-  result.seconds = daySeconds mod secondsInMin
+proc toTimeInterval*(t: Time): TimeInterval =
+  ## Converts a Time to a TimeInterval.
   # Milliseconds not available from Time
+  var tInfo = t.getLocalTime()
+  initInterval(0, tInfo.second, tInfo.minute, tInfo.hour, tInfo.weekday.ord, tInfo.month.ord, tInfo.year)
+
 
 when isMainModule:
   # this is testing non-exported function
diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim
index c764571b1..ec69f6e5f 100644
--- a/lib/system/gc_ms.nim
+++ b/lib/system/gc_ms.nim
@@ -28,6 +28,9 @@ template mulThreshold(x): expr {.immediate.} = x * 2
 
 when defined(memProfiler):
   proc nimProfile(requestedSize: int)
+  
+when hasThreadSupport:
+  import sharedlist
 
 type
   WalkOp = enum
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index 5e899dd1a..a08a067fa 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -769,7 +769,7 @@ proc getQueuedCompletionStatus*(CompletionPort: Handle,
                                 dwMilliseconds: DWORD): WINBOOL{.stdcall,
     dynlib: "kernel32", importc: "GetQueuedCompletionStatus".}
 
-proc getOverlappedResult*(hFile: Handle, lpOverlapped: OVERLAPPED,
+proc getOverlappedResult*(hFile: Handle, lpOverlapped: POVERLAPPED,
               lpNumberOfBytesTransferred: var DWORD, bWait: WINBOOL): WINBOOL{.
     stdcall, dynlib: "kernel32", importc: "GetOverlappedResult".}
 
diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim
index 05843e2d3..635d52a64 100644
--- a/lib/wrappers/openssl.nim
+++ b/lib/wrappers/openssl.nim
@@ -260,7 +260,7 @@ proc OpenSSL_add_all_algorithms*(){.cdecl, dynlib: DLLUtilName, importc: "OPENSS
 
 proc OPENSSL_config*(configName: cstring){.cdecl, dynlib: DLLSSLName, importc.}
 
-when not useWinVersion:
+when not useWinVersion and not defined(macosx):
   proc CRYPTO_set_mem_functions(a,b,c: pointer){.cdecl,
     dynlib: DLLUtilName, importc.}
 
@@ -532,7 +532,7 @@ proc md5_File* (file: string): string {.raises: [IOError,Exception].} =
 
   result = hexStr(buf)
 
-proc md5_Str* (str:string): string {.raises:[IOError].} =
+proc md5_Str*(str:string): string =
   ##Generate MD5 hash for a string. Result is a 32 character
   #hex string with lowercase characters
   var
diff --git a/readme.md b/readme.md
index 27b2273f0..fbaa5fd32 100644
--- a/readme.md
+++ b/readme.md
@@ -1,18 +1,9 @@
-# Nim Compiler
-
-[![Join the Chat at irc.freenode.net#nim](https://img.shields.io/badge/IRC-join_chat_in_%23nim-blue.svg)](https://webchat.freenode.net/?channels=nim)
-[![Get help](https://img.shields.io/badge/Forum-get%20help-4eb899.svg)](http://forum.nim-lang.org)
-[![Stackoverflow](https://img.shields.io/badge/stackoverflow-use_%23nim_tag-yellow.svg)](http://stackoverflow.com/questions/tagged/nim?sort=newest&pageSize=15)
-[![Follow @nim_lang!](https://img.shields.io/twitter/follow/nim_lang.svg?style=social)](https://twitter.com/nim_lang)
-
-[![Travis](https://img.shields.io/travis/nim-lang/Nim.svg)](https://travis-ci.org/nim-lang/Nim)
-
-[![Contribute to Nim via Gratipay!](https://img.shields.io/gratipay/team/nim.svg)](https://gratipay.com/nim/)
-[![Bountysource](https://img.shields.io/bountysource/team/nim/activity.svg)](https://www.bountysource.com/teams/nim)
-
+# <img src="https://raw.githubusercontent.com/nim-lang/assets/master/Art/logo-crown.png" width="36"> Nim [![Build Status](https://travis-ci.org/nim-lang/Nim.svg?branch=devel)](https://travis-ci.org/nim-lang/Nim)
 
 This repo contains the Nim compiler, Nim's stdlib, tools and
-documentation.
+documentation. For more information about Nim, including downloads
+and documentation for the latest release, check out
+[Nim's website](http://nim-lang.org).
 
 ## Compiling
 Compiling the Nim compiler is quite straightforward. Because
@@ -48,14 +39,15 @@ $ bin/nim c koch
 $ ./koch boot -d:release
 ```
 
-``koch install [dir]`` may then be used to install Nim, but lots of things
-don't work then so don't do that. Add it to your PATH instead. More ``koch``
-related options are documented in [doc/koch.txt](doc/koch.txt).
+You should then add the ``bin`` directory to your PATH, to make it easily
+executable on your system.
 
 The above steps can be performed on Windows in a similar fashion, the
 ``build.bat`` and ``build64.bat`` (for x86_64 systems) are provided to be used
 instead of ``build.sh``.
 
+The ``koch`` tool is the Nim build tool, more ``koch`` related options are
+documented in [doc/koch.txt](doc/koch.txt).
 
 ## Nimble
 [Nimble](https://github.com/nim-lang/nimble) is Nim's package manager. For the
@@ -66,12 +58,80 @@ the easiest way of installing Nimble is via:
 $ nim e install_nimble.nims
 ```
 
-## Getting help
-A [forum](http://forum.nim-lang.org/) is available if you have any
-questions, and you can also get help in the IRC channel on
-[Freenode](irc://irc.freenode.net/nim) in #nim. If you ask questions on
-[StackOverflow use the nim
-tag](http://stackoverflow.com/questions/tagged/nim).
+**Warning:** If you install Nimble this way, you will not be able to use binary
+Nimble packages or update Nimble easily.
+The [Nimble readme](https://github.com/nim-lang/nimble#installation)
+provides thorough instructions on how to install Nimble, so that this isn't a
+problem.
+
+## Community
+[![Join the Chat at irc.freenode.net#nim](https://img.shields.io/badge/IRC-join_chat_in_%23nim-blue.svg)](https://webchat.freenode.net/?channels=nim)
+[![Get help](https://img.shields.io/badge/Forum-get%20help-4eb899.svg)](http://forum.nim-lang.org)
+[![Stackoverflow](https://img.shields.io/badge/stackoverflow-use_%23nim_tag-yellow.svg)](http://stackoverflow.com/questions/tagged/nim?sort=newest&pageSize=15)
+[![Follow @nim_lang!](https://img.shields.io/twitter/follow/nim_lang.svg?style=social)](https://twitter.com/nim_lang)
+
+* The [forum](http://forum.nim-lang.org/) - the best place to ask questions and to discuss Nim.
+* [IRC (Freenode#nim)](https://webchat.freenode.net/?channels=nim) - the best place to discuss
+  Nim in real-time, this is also where most development decision get made!
+* [Stackoverflow](http://stackoverflow.com/questions/tagged/nim)
+
+## Contributing
+
+[![Contribute to Nim via Gratipay!](https://img.shields.io/gratipay/team/nim.svg)](https://gratipay.com/nim/)
+[![Bountysource](https://img.shields.io/bountysource/team/nim/activity.svg)](https://www.bountysource.com/teams/nim)
+
+We welcome everyone's contributions to Nim. No matter how small or large
+the contribution is, anything from small spelling fixes to large modules
+intended to be included in the standard library are accepted. Before
+you get started, you should know the following about this repositories
+structure:
+
+* ``bin/``, ``build/`` - these directories are empty, but are used when Nim is built.
+* ``compiler/`` - the compiler source code, all the Nim source code files in this
+  directory implement the compiler. This also includes nimfix, and plugins
+  which live in ``compiler/nimfix`` and ``compiler/plugins``
+  respectively. Nimsuggest used to live in the ``compiler`` directory also,
+  but was moved to https://github.com/nim-lang/nimsuggest.
+* ``config/`` - the configuration for the compiler and documentation generator.
+* ``doc/`` - the documentation files in reStructuredText format.
+* ``lib/`` - where the standard library lives.
+    * ``pure/`` - modules in the standard library written in pure Nim.
+    * ``impure/`` - modules in the standard library written in pure Nim which
+      depend on libraries written in other languages.
+    * ``wrappers/`` - modules which wrap libraries written in other languages.
+* ``tests/`` - contains tests for the compiler and standard library, organised by
+    category.
+* ``tools/`` - the tools including ``niminst`` and ``nimweb``, most of these are invoked
+    via ``koch``.
+* ``web/`` - the Nim website (http://nim-lang.org).
+* ``koch.nim`` - tool used to bootstrap Nim, generate C sources, build the website, documentation
+  and more.
+
+Most importantly, the ``koch`` tool can be used to run the test suite. To do so compile it first
+by executing ``nim c koch``, then execute ``./koch tests``. The test suite takes a while to run,
+but you can run specific tests by specifying a category to run, for example ``./koch tests cat async``.
+
+Make sure that the tests all pass before
+[submitting your pull request](https://help.github.com/articles/using-pull-requests/).
+If you're short on time, you can
+just run the tests specific to your change. Just run the category which corresponds to the change
+you've made. When you create your pull request, Travis CI will verify that all the tests pass
+anyway.
+
+If you're looking for things to do, take a look at our
+[issue tracker](https://github.com/nim-lang/Nim/issues). There is always plenty of issues
+labelled [``Easy``](https://github.com/nim-lang/Nim/labels/Easy), these should be a good
+starting point if this is your first contribution to Nim.
+
+You can also help with the development of Nim by making donations. You can do so
+in many ways:
+
+* [Gratipay](https://gratipay.com/nim/)
+* [Bountysource](https://www.bountysource.com/teams/nim)
+* Bitcoin - 1BXfuKM2uvoD6mbx4g5xM3eQhLzkCK77tJ
+
+Finally, if you have any questions feel free to submit a question on the issue tracker,
+on the [Nim forum](http://forum.nim-lang.org), or on IRC.
 
 ## License
 The compiler and the standard library are licensed under the MIT license,
diff --git a/tests/async/tasyncfile.nim b/tests/async/tasyncfile.nim
index 05cda5e5f..26a9bb391 100644
--- a/tests/async/tasyncfile.nim
+++ b/tests/async/tasyncfile.nim
@@ -24,7 +24,7 @@ proc main() {.async.} =
     var file = openAsync(fn, fmAppend)
     await file.write("\ntest2")
     let errorTest = file.readAll()
-    await errorTest
+    echo await errorTest
     doAssert errorTest.failed
     file.close()
     file = openAsync(fn, fmRead)
diff --git a/tests/cpp/ttemplatetype.nim b/tests/cpp/ttemplatetype.nim
new file mode 100644
index 000000000..7f56a225d
--- /dev/null
+++ b/tests/cpp/ttemplatetype.nim
@@ -0,0 +1,9 @@
+type
+  Map {.importcpp: "std::map", header: "<map>".} [T,U] = object
+
+proc cInitMap(T: typedesc, U: typedesc): Map[T,U] {.importcpp: "std::map<'*1,'*2>()", nodecl.}
+
+proc initMap[T, U](): Map[T, U] =
+  result = cInitMap(T, U)
+
+var x: Map[cstring, cint] = initMap[cstring, cint]()
diff --git a/tests/js/tclosures.nim b/tests/js/tclosures.nim
new file mode 100644
index 000000000..c0d93814c
--- /dev/null
+++ b/tests/js/tclosures.nim
@@ -0,0 +1,51 @@
+discard """
+  action: run
+"""
+
+import math, strutils
+const consolePrefix = "jsCallbacks"
+
+asm """
+    var callback = []
+    function regCallback (fn) { callback.push (fn); }
+    function runCallbacks () {
+        var result = "\n"
+        var n = 0
+        for (var fn in callback) {
+            n += 1
+            result += "("+String (n)+")"
+            result += callback [fn] ()
+            result += "\n"
+        }
+        return result
+    }
+    function print (text) { console.log (text); }
+"""
+
+proc consoleprint (str:cstring): void {.importc: "print", noDecl.}
+proc print* (a: varargs[string, `$`]) = consoleprint "$1: $2" % [consolePrefix, join (a, " ")]
+
+type CallbackProc {.importc.} = proc () : cstring
+
+proc regCallback (fn:CallbackProc) {.importc.}
+proc runCallbacks ():cstring {.importc.}
+
+proc `*` (s:string, n:Natural) : string = s.repeat (n)
+
+proc outer (i:Natural) : (string, int) =
+    let c = $char (random (93) + 33)
+    let n = random (40)
+    let s = c * n
+    proc inner () : cstring = ("[$1]" % $n) & s & " <--"
+    regCallback (inner)
+    return (s, n)
+
+var expected = "\n"
+for i in 1 .. 10:
+    let (s, n) = outer (i)
+    expected &= ("($1)[$2]" % [$i, $n]) & s & " <--"
+    expected &= "\n"
+
+let results = runCallbacks ()
+
+doAssert(expected == results)
diff --git a/tests/testament/specs.nim b/tests/testament/specs.nim
index bab17d2cd..3f40a5342 100644
--- a/tests/testament/specs.nim
+++ b/tests/testament/specs.nim
@@ -107,6 +107,15 @@ proc specDefaults*(result: var TSpec) =
   result.tline = 0
   result.tcolumn = 0
 
+proc parseTargets*(value: string): set[TTarget] =
+  for v in value.normalize.split:
+    case v
+    of "c": result.incl(targetC)
+    of "cpp", "c++": result.incl(targetCpp)
+    of "objc": result.incl(targetObjC)
+    of "js": result.incl(targetJS)
+    else: echo "target ignored: " & v
+
 proc parseSpec*(filename: string): TSpec =
   specDefaults(result)
   result.file = filename
diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim
index b1e8ac099..da1c6fc2d 100644
--- a/tests/testament/tester.nim
+++ b/tests/testament/tester.nim
@@ -33,6 +33,7 @@ Options:
   --print                   also print results to the console
   --failing                 only show failing/ignored tests
   --pedantic                return non-zero status code if there are failures
+  --targets:"c c++ js objc" run tests for specified targets (default: all)
 """ % resultsFile
 
 type
@@ -60,6 +61,8 @@ let
   pegSuccess = peg"'Hint: operation successful'.*"
   pegOfInterest = pegLineError / pegOtherError
 
+var targets = {low(TTarget)..high(TTarget)}
+
 proc callCompiler(cmdTemplate, filename, options: string,
                   target: TTarget): TSpec =
   let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target],
@@ -275,6 +278,11 @@ proc analyzeAndConsolidateOutput(s: string): string =
 
 proc testSpec(r: var TResults, test: TTest) =
   # major entry point for a single test
+  if test.target notin targets:
+    r.addResult(test, "", "", reIgnored)
+    inc(r.skipped)
+    return
+
   let tname = test.name.addFileExt(".nim")
   inc(r.total)
   var expected: TSpec
@@ -336,7 +344,7 @@ proc testSpec(r: var TResults, test: TTest) =
                         reExitCodesDiffer)
       return
 
-    if bufB != expectedOut:
+    if bufB != expectedOut and expected.action != actionRunNoSpec:
       if not (expected.substr and expectedOut in bufB):
         given.err = reOutputsDiffer
         r.addResult(test, expected.outp, bufB, reOutputsDiffer)
@@ -394,6 +402,7 @@ proc main() =
   var optPrintResults = false
   var optFailing = false
   var optPedantic = false
+
   var p = initOptParser()
   p.next()
   while p.kind == cmdLongoption:
@@ -401,6 +410,7 @@ proc main() =
     of "print", "verbose": optPrintResults = true
     of "failing": optFailing = true
     of "pedantic": optPedantic = true
+    of "targets": targets = parseTargets(p.val.string)
     else: quit Usage
     p.next()
   if p.kind != cmdArgument: quit Usage
diff --git a/tests/trmacros/tpatterns.nim b/tests/trmacros/tpatterns.nim
index 6bc8772e3..907973637 100644
--- a/tests/trmacros/tpatterns.nim
+++ b/tests/trmacros/tpatterns.nim
@@ -1,6 +1,7 @@
 discard """
   output: '''48
-hel'''
+hel
+lo'''
 """
 
 template optZero{x+x}(x: int): int = x*3
@@ -15,3 +16,8 @@ s[0] = "hello"
 s[0] = substr(s[0], 0, 2)
 
 echo s[0]
+
+# Test varargs matching
+proc someVarargProc(k: varargs[string]) = doAssert(false) # this should not get called
+template someVarargProcSingleArg{someVarargProc([a])}(a: string) = echo a
+someVarargProc("lo")
diff --git a/tools/website.tmpl b/tools/website.tmpl
index 50152a051..6ae975839 100644
--- a/tools/website.tmpl
+++ b/tools/website.tmpl
@@ -6,13 +6,23 @@
   <head>
     <meta http-equiv="content-type" content="text/html; charset=utf-8">
     <title>$c.projectTitle</title>
-    <link rel="stylesheet" type="text/css" href="assets/style.css" />
+    <link rel="stylesheet" type="text/css" href="assets/style.css?t=2221" />
     <link rel="shortcut icon" href="assets/images/favicon.ico">
   #if len(rss) > 0:
     <link href="$rss" title="Recent changes" type="application/atom+xml" rel="alternate">
   #end if
   </head>
   <body>
+    <div id="bountysource">
+      <a href="https://salt.bountysource.com/teams/nim">
+      <div class="page-layout" style="padding: 2pt 2pt 2pt 30pt">
+  	<img src="assets/bountysource/bountysource.png" style="width: 20px; float: left;">
+        <span style="margin-left: 10pt; float: left; margin-top: 2pt;">Fund Nim and help us develop it further!</span>
+        <img src="https://api.bountysource.com/badge/team?team_id=19072&style=raised" style="margin-top: 2pt; margin-left: 10pt"/>
+      </div>
+      </a>
+    </div>
+
     <header id="head">
       <div class="page-layout tall">
         <div id="head-logo"></div>
diff --git a/web/assets/style.css b/web/assets/style.css
index 529358ec9..98bf12a9a 100644
--- a/web/assets/style.css
+++ b/web/assets/style.css
@@ -563,3 +563,14 @@ pre .end { background:url("images/tabEnd.png") no-repeat left bottom; }
     border-collapse: collapse;
     text-align: left;
     border-spacing: 0px; }
+
+#bountysource {
+    width: 100%;
+    height: 30px;
+    background-color: #19975d;
+}
+
+#bountysource a, #bountysource a:visited, #bountysource a:hover {
+  color: #1a1a1a;
+
+}
diff --git a/web/news.txt b/web/news.txt
index 82ed4fe44..0a83503c1 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -23,6 +23,15 @@ Changes affecting backwards compatibility
 - Procedures in ``mersenne.nim`` (Mersenne Twister implementation) no longer
   accept and produce ``int`` values which have platform-dependent size -
   they use ``uint32`` instead.
+- The ``strutils.unindent`` procedure has been rewritten. Its parameters now
+  match the parameters of ``strutils.indent``. See issue [#4037](https://github.com/nim-lang/Nim/issues/4037)
+  for more details.
+- The ``matchers`` module has been deprecated. See issue [#2446](https://github.com/nim-lang/Nim/issues/2446)
+  for more details.
+- The ``json.[]`` no longer returns ``nil`` when a key is not found. Instead it
+  raises a ``KeyError`` exception. You can compile with the ``-d:nimJsonGet``
+  flag to get a list of usages of ``[]``, as well as to restore the operator's
+  previous behaviour.
 
 
 Library Additions