summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim4
-rw-r--r--compiler/ccgexprs.nim11
-rw-r--r--compiler/ccgstmts.nim1
-rw-r--r--compiler/cgen.nim36
-rw-r--r--compiler/semcall.nim114
-rw-r--r--compiler/semfold.nim3
-rw-r--r--compiler/semtypinst.nim12
-rw-r--r--compiler/suggest.nim11
-rw-r--r--lib/pure/asyncdispatch.nim369
-rw-r--r--lib/pure/asyncmacro.nim373
-rw-r--r--lib/pure/logging.nim244
-rw-r--r--lib/upcoming/asyncdispatch.nim368
-rw-r--r--readme.md5
-rw-r--r--tests/async/config.nims2
-rw-r--r--tests/overload/importA.nim5
-rw-r--r--tests/overload/importB.nim15
-rw-r--r--tests/overload/timport.nim7
-rw-r--r--tests/testament/categories.nim14
-rw-r--r--tools/nimweb.nim10
-rw-r--r--tools/website.tmpl27
-rw-r--r--web/assets/news/images/survey/10_needs.pngbin0 -> 39707 bytes
-rw-r--r--web/assets/news/images/survey/book.pngbin0 -> 54231 bytes
-rw-r--r--web/assets/news/images/survey/book_opinion.pngbin0 -> 39312 bytes
-rw-r--r--web/assets/news/images/survey/breakage.pngbin0 -> 42032 bytes
-rw-r--r--web/assets/news/images/survey/difficulty_fixing_breakage.pngbin0 -> 31324 bytes
-rw-r--r--web/assets/news/images/survey/domains.pngbin0 -> 59065 bytes
-rw-r--r--web/assets/news/images/survey/ex_nim.pngbin0 -> 45423 bytes
-rw-r--r--web/assets/news/images/survey/languages.pngbin0 -> 84839 bytes
-rw-r--r--web/assets/news/images/survey/learning_resources.pngbin0 -> 39711 bytes
-rw-r--r--web/assets/news/images/survey/nim_appeal.pngbin0 -> 54043 bytes
-rw-r--r--web/assets/news/images/survey/nim_displeasing.pngbin0 -> 52584 bytes
-rw-r--r--web/assets/news/images/survey/nim_domains.pngbin0 -> 58405 bytes
-rw-r--r--web/assets/news/images/survey/nimble_opinion.pngbin0 -> 41325 bytes
-rw-r--r--web/assets/news/images/survey/non_user.pngbin0 -> 45695 bytes
-rw-r--r--web/assets/news/images/survey/planning_to_use_at_work.pngbin65840 -> 47859 bytes
-rw-r--r--web/assets/news/images/survey/project_size_nim_rust.pngbin44455 -> 44546 bytes
-rw-r--r--web/assets/news/images/survey/upgrades_broke_things.pngbin71148 -> 0 bytes
-rw-r--r--web/assets/style.css14
-rw-r--r--web/bountysource.nim72
-rw-r--r--web/inactive_sponsors.csv44
-rw-r--r--web/news.rst3
-rw-r--r--web/news/2016_09_03_nim_community_survey_results.rst699
-rw-r--r--web/news/nim_community_survey_results.rst317
-rw-r--r--web/sponsors.csv65
-rw-r--r--web/ticker.html10
45 files changed, 1548 insertions, 1307 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 347060248..131c2a38f 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -437,7 +437,7 @@ type
     nfExplicitCall # x.y() was used instead of x.y
     nfExprCall  # this is an attempt to call a regular expression
     nfIsRef     # this node is a 'ref' node; used for the VM
-    nfIsCursor  # this node is attached a cursor; used for idetools
+    nfPreventCg # this node should be ignored by the codegen
 
   TNodeFlags* = set[TNodeFlag]
   TTypeFlag* = enum   # keep below 32 for efficiency reasons (now: 28)
@@ -925,7 +925,7 @@ const
     skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}
   PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
                                       nfDotSetter, nfDotField,
-                                      nfIsRef, nfIsCursor, nfLL}
+                                      nfIsRef, nfPreventCg, nfLL}
   namePos* = 0
   patternPos* = 1    # empty except for term rewriting macros
   genericParamsPos* = 2
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index e1ee6f1de..0ba775b25 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -2084,11 +2084,14 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
   of nkCaseStmt: genCase(p, n, d)
   of nkReturnStmt: genReturnStmt(p, n)
   of nkBreakStmt: genBreakStmt(p, n)
-  of nkAsgn: genAsgn(p, n, fastAsgn=false)
+  of nkAsgn:
+    if nfPreventCg notin n.flags:
+      genAsgn(p, n, fastAsgn=false)
   of nkFastAsgn:
-    # transf is overly aggressive with 'nkFastAsgn', so we work around here.
-    # See tests/run/tcnstseq3 for an example that would fail otherwise.
-    genAsgn(p, n, fastAsgn=p.prc != nil)
+    if nfPreventCg notin n.flags:
+      # transf is overly aggressive with 'nkFastAsgn', so we work around here.
+      # See tests/run/tcnstseq3 for an example that would fail otherwise.
+      genAsgn(p, n, fastAsgn=p.prc != nil)
   of nkDiscardStmt:
     if n.sons[0].kind != nkEmpty:
       genLineDir(p, n)
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 1b21e641a..294235ae9 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -359,6 +359,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
       linefmt(p, cpsStmts, "#popCurrentException();$n")
 
 proc genReturnStmt(p: BProc, t: PNode) =
+  if nfPreventCg in t.flags: return
   p.beforeRetNeeded = true
   genLineDir(p, t)
   if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0])
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 4a3113edf..7333c77c3 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -616,6 +616,24 @@ proc closureSetup(p: BProc, prc: PSym) =
   linefmt(p, cpsStmts, "$1 = ($2) ClEnv;$n",
           rdLoc(env.loc), getTypeDesc(p.module, env.typ))
 
+proc easyResultAsgn(n: PNode): PNode =
+  const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt} +
+                    declarativeDefs
+  case n.kind
+  of nkStmtList, nkStmtListExpr:
+    var i = 0
+    while i < n.len and n[i].kind in harmless: inc i
+    if i < n.len: result = easyResultAsgn(n[i])
+  of nkAsgn, nkFastAsgn:
+    if n[0].kind == nkSym and skResult == n[0].sym.kind:
+      incl n.flags, nfPreventCg
+      return n[1]
+  of nkReturnStmt:
+    if n.len > 0:
+      result = easyResultAsgn(n[0])
+      if result != nil: incl n.flags, nfPreventCg
+  else: discard
+
 proc genProcAux(m: BModule, prc: PSym) =
   var p = newProc(prc, m)
   var header = genProcHeader(m, prc)
@@ -627,11 +645,17 @@ proc genProcAux(m: BModule, prc: PSym) =
     var res = prc.ast.sons[resultPos].sym # get result symbol
     if not isInvalidReturnType(prc.typ.sons[0]):
       if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
-      # declare the result symbol:
-      assignLocalVar(p, res)
-      assert(res.loc.r != nil)
+      if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(prc.getBody); val != nil):
+        var decl = localVarDecl(p, res)
+        var a: TLoc
+        initLocExprSingleUse(p, val, a)
+        linefmt(p, cpsStmts, "$1 = $2;$n", decl, rdLoc(a))
+      else:
+        # declare the result symbol:
+        assignLocalVar(p, res)
+        assert(res.loc.r != nil)
+        initLocalVar(p, res, immediateAsgn=false)
       returnStmt = rfmt(nil, "\treturn $1;$n", rdLoc(res.loc))
-      initLocalVar(p, res, immediateAsgn=false)
     else:
       fillResult(res)
       assignParam(p, res)
@@ -791,12 +815,12 @@ proc addIntTypes(result: var Rope) {.inline.} =
 proc getCopyright(cfile: string): Rope =
   if optCompileOnly in gGlobalOptions:
     result = ("/* Generated by Nim Compiler v$1 */$N" &
-        "/*   (c) 2015 Andreas Rumpf */$N" &
+        "/*   (c) 2016 Andreas Rumpf */$N" &
         "/* The generated code is subject to the original license. */$N") %
         [rope(VersionAsString)]
   else:
     result = ("/* Generated by Nim Compiler v$1 */$N" &
-        "/*   (c) 2015 Andreas Rumpf */$N" &
+        "/*   (c) 2016 Andreas Rumpf */$N" &
         "/* The generated code is subject to the original license. */$N" &
         "/* Compiled for: $2, $3, $4 */$N" &
         "/* Command for C compiler:$n   $5 */$N") %
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index b3fc020b1..5f7e5084b 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -34,55 +34,85 @@ proc sameMethodDispatcher(a, b: PSym): bool =
 
 proc determineType(c: PContext, s: PSym)
 
+proc initCandidateSymbols(c: PContext, headSymbol: PNode,
+                       initialBinding: PNode,
+                       filter: TSymKinds,
+                       best, alt: var TCandidate,
+                       o: var TOverloadIter): seq[tuple[s: PSym, scope: int]] =
+  result = @[]
+  var symx = initOverloadIter(o, c, headSymbol)
+  while symx != nil:
+    if symx.kind in filter:
+      result.add((symx, o.lastOverloadScope))
+      symx = nextOverloadIter(o, c, headSymbol)
+  if result.len > 0:
+    initCandidate(c, best, result[0].s, initialBinding, result[0].scope)
+    initCandidate(c, alt, result[0].s, initialBinding, result[0].scope)
+    best.state = csNoMatch
+
 proc pickBestCandidate(c: PContext, headSymbol: PNode,
                        n, orig: PNode,
                        initialBinding: PNode,
                        filter: TSymKinds,
                        best, alt: var TCandidate,
                        errors: var CandidateErrors) =
-  while true:
-    block pickAttempt:
-      var o: TOverloadIter
-      var sym = initOverloadIter(o, c, headSymbol)
-      # Thanks to the lazy semchecking for operands, we need to check whether
-      # 'initCandidate' modifies the symbol table (via semExpr).
-      # This can occur in cases like 'init(a, 1, (var b = new(Type2); b))'
-      let counterInitial = c.currentScope.symbols.counter
+  var o: TOverloadIter
+  var sym = initOverloadIter(o, c, headSymbol)
+  var scope = o.lastOverloadScope
+  # Thanks to the lazy semchecking for operands, we need to check whether
+  # 'initCandidate' modifies the symbol table (via semExpr).
+  # This can occur in cases like 'init(a, 1, (var b = new(Type2); b))'
+  let counterInitial = c.currentScope.symbols.counter
+  var syms: seq[tuple[s: PSym, scope: int]]
+  var nextSymIndex = 0
+  while sym != nil:
+    if sym.kind in filter:
       # Initialise 'best' and 'alt' with the first available symbol
-      while sym != nil:
-        if sym.kind in filter:
-          initCandidate(c, best, sym, initialBinding, o.lastOverloadScope)
-          initCandidate(c, alt, sym, initialBinding, o.lastOverloadScope)
-          best.state = csNoMatch
-          break
-        else:
-          sym = nextOverloadIter(o, c, headSymbol)
-      var z: TCandidate
-      while sym != nil:
-        if sym.kind notin filter:
-          sym = nextOverloadIter(o, c, headSymbol)
-          continue
-        determineType(c, sym)
-        initCandidate(c, z, sym, initialBinding, o.lastOverloadScope)
-        if c.currentScope.symbols.counter != counterInitial: break pickAttempt
-        matches(c, n, orig, z)
-        if errors != nil:
-          errors.safeAdd((sym, int z.mutabilityProblem))
-          if z.errors != nil:
-            for err in z.errors:
-              errors.add(err)
-        if z.state == csMatch:
-          # little hack so that iterators are preferred over everything else:
-          if sym.kind == skIterator: inc(z.exactMatches, 200)
-          case best.state
-          of csEmpty, csNoMatch: best = z
-          of csMatch:
-            var cmp = cmpCandidates(best, z)
-            if cmp < 0: best = z   # x is better than the best so far
-            elif cmp == 0: alt = z # x is as good as the best so far
-            else: discard
-        sym = nextOverloadIter(o, c, headSymbol)
-    break # pick attempt was successful
+      initCandidate(c, best, sym, initialBinding, scope)
+      initCandidate(c, alt, sym, initialBinding, scope)
+      best.state = csNoMatch
+      break
+    else:
+      sym = nextOverloadIter(o, c, headSymbol)
+      scope = o.lastOverloadScope
+  var z: TCandidate
+  while sym != nil:
+    if sym.kind notin filter:
+      sym = nextOverloadIter(o, c, headSymbol)
+      scope = o.lastOverloadScope
+      continue
+    determineType(c, sym)
+    initCandidate(c, z, sym, initialBinding, scope)
+    if c.currentScope.symbols.counter == counterInitial or syms != nil:
+      matches(c, n, orig, z)
+      if errors != nil:
+        errors.safeAdd((sym, int z.mutabilityProblem))
+        if z.errors != nil:
+          for err in z.errors:
+            errors.add(err)
+      if z.state == csMatch:
+        # little hack so that iterators are preferred over everything else:
+        if sym.kind == skIterator: inc(z.exactMatches, 200)
+        case best.state
+        of csEmpty, csNoMatch: best = z
+        of csMatch:
+          var cmp = cmpCandidates(best, z)
+          if cmp < 0: best = z   # x is better than the best so far
+          elif cmp == 0: alt = z # x is as good as the best so far
+    else:
+      # Symbol table has been modified. Restart and pre-calculate all syms
+      # before any further candidate init and compare. SLOW, but rare case.
+      syms = initCandidateSymbols(c, headSymbol, initialBinding, filter, best, alt, o)
+    if syms == nil:
+      sym = nextOverloadIter(o, c, headSymbol)
+      scope = o.lastOverloadScope
+    elif nextSymIndex < syms.len:
+      # rare case: retrieve the next pre-calculated symbol
+      sym = syms[nextSymIndex].s
+      scope = syms[nextSymIndex].scope
+      nextSymIndex += 1
+    else:
+      break
 
 proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
   # Gives a detailed error message; this is separated from semOverloadedCall,
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 1cb726053..42fa60781 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -514,7 +514,8 @@ proc foldConv*(n, a: PNode; check = false): PNode =
     else:
       result = a
       result.typ = n.typ
-    if check: rangeCheck(n, result.intVal)
+    if check and result.kind in {nkCharLit..nkUInt64Lit}:
+      rangeCheck(n, result.intVal)
   of tyFloat..tyFloat64:
     case skipTypes(a.typ, abstractRange).kind
     of tyInt..tyInt64, tyEnum, tyBool, tyChar:
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 12620d55d..b42d58474 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -86,7 +86,7 @@ type
 
 proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType
 proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
-proc replaceTypeVarsN*(cl: var TReplTypeVars, n: PNode): PNode
+proc replaceTypeVarsN*(cl: var TReplTypeVars, n: PNode; start=0): PNode
 
 template checkMetaInvariants(cl: TReplTypeVars, t: PType) =
   when false:
@@ -151,7 +151,7 @@ proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode =
 
   return n
 
-proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
+proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode =
   if n == nil: return
   result = copyNode(n)
   if n.typ != nil:
@@ -195,7 +195,9 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
     var length = sonsLen(n)
     if length > 0:
       newSons(result, length)
-      for i in countup(0, length - 1):
+      if start > 0:
+        result.sons[0] = n.sons[0]
+      for i in countup(start, length - 1):
         result.sons[i] = replaceTypeVarsN(cl, n.sons[i])
 
 proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
@@ -462,8 +464,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
               r = skipTypes(r2, {tyPtr, tyRef})
           result.sons[i] = r
           propagateToOwner(result, r)
-
-      result.n = replaceTypeVarsN(cl, result.n)
+      # bug #4677: Do not instantiate effect lists
+      result.n = replaceTypeVarsN(cl, result.n, ord(result.kind==tyProc))
 
       case result.kind
       of tyArray:
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index f331fce69..52f00550b 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -413,17 +413,16 @@ proc safeSemExpr*(c: PContext, n: PNode): PNode =
     result = ast.emptyNode
 
 proc suggestExpr*(c: PContext, node: PNode) =
-  if nfIsCursor notin node.flags:
-    if gTrackPos.line < 0: return
-    var cp = inCheckpoint(node.info)
-    if cp == cpNone: return
+  if gTrackPos.line < 0: return
+  var cp = inCheckpoint(node.info)
+  if cp == cpNone: return
   var outputs = 0
   # This keeps semExpr() from coming here recursively:
   if c.compilesContextId > 0: return
   inc(c.compilesContextId)
 
   if gIdeCmd == ideSug:
-    var n = if nfIsCursor in node.flags: node else: findClosestDot(node)
+    var n = findClosestDot(node)
     if n == nil: n = node
     if n.kind == nkDotExpr:
       var obj = safeSemExpr(c, n.sons[0])
@@ -436,7 +435,7 @@ proc suggestExpr*(c: PContext, node: PNode) =
       suggestEverything(c, n, outputs)
 
   elif gIdeCmd == ideCon:
-    var n = if nfIsCursor in node.flags: node else: findClosestCall(node)
+    var n = findClosestCall(node)
     if n == nil: n = node
     if n.kind in nkCallKinds:
       var a = copyNode(n)
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 79bc1b96d..6bea8e817 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -9,7 +9,7 @@
 
 include "system/inclrtl"
 
-import os, oids, tables, strutils, macros, times, heapqueue
+import os, oids, tables, strutils, times, heapqueue
 
 import nativesockets, net, queues
 
@@ -827,14 +827,17 @@ when defined(windows) or defined(nimdoc):
     var retFuture = newFuture[void]("send")
 
     var dataBuf: TWSABuf
-    dataBuf.buf = data # since this is not used in a callback, this is fine
+    dataBuf.buf = data
     dataBuf.len = data.len.ULONG
+    GC_ref(data) # we need to protect data until send operation is completed
+                 # or failed.
 
     var bytesReceived, lowFlags: Dword
     var ol = PCustomOverlapped()
     GC_ref(ol)
     ol.data = CompletionData(fd: socket, cb:
       proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
+        GC_unref(data) # if operation completed `data` must be released.
         if not retFuture.finished:
           if errcode == OSErrorCode(-1):
             retFuture.complete()
@@ -851,6 +854,8 @@ when defined(windows) or defined(nimdoc):
       let err = osLastError()
       if err.int32 != ERROR_IO_PENDING:
         GC_unref(ol)
+        GC_unref(data) # if operation failed `data` must be released, because
+                       # completion routine will not be called.
         if flags.isDisconnectionError(err):
           retFuture.complete()
         else:
@@ -1577,365 +1582,7 @@ proc accept*(socket: AsyncFD,
   return retFut
 
 # -- Await Macro
-
-proc skipUntilStmtList(node: NimNode): NimNode {.compileTime.} =
-  # Skips a nest of StmtList's.
-  result = node
-  if node[0].kind == nnkStmtList:
-    result = skipUntilStmtList(node[0])
-
-proc skipStmtList(node: NimNode): NimNode {.compileTime.} =
-  result = node
-  if node[0].kind == nnkStmtList:
-    result = node[0]
-
-template createCb(retFutureSym, iteratorNameSym,
-                   name: untyped) =
-  var nameIterVar = iteratorNameSym
-  #{.push stackTrace: off.}
-  proc cb {.closure,gcsafe.} =
-    try:
-      if not nameIterVar.finished:
-        var next = nameIterVar()
-        if next == nil:
-          assert retFutureSym.finished, "Async procedure's (" &
-                 name & ") return Future was not finished."
-        else:
-          next.callback = cb
-    except:
-      if retFutureSym.finished:
-        # Take a look at tasyncexceptions for the bug which this fixes.
-        # That test explains it better than I can here.
-        raise
-      else:
-        retFutureSym.fail(getCurrentException())
-  cb()
-  #{.pop.}
-proc generateExceptionCheck(futSym,
-    tryStmt, rootReceiver, fromNode: NimNode): NimNode {.compileTime.} =
-  if tryStmt.kind == nnkNilLit:
-    result = rootReceiver
-  else:
-    var exceptionChecks: seq[tuple[cond, body: NimNode]] = @[]
-    let errorNode = newDotExpr(futSym, newIdentNode("error"))
-    for i in 1 .. <tryStmt.len:
-      let exceptBranch = tryStmt[i]
-      if exceptBranch[0].kind == nnkStmtList:
-        exceptionChecks.add((newIdentNode("true"), exceptBranch[0]))
-      else:
-        var exceptIdentCount = 0
-        var ifCond: NimNode
-        for i in 0 .. <exceptBranch.len:
-          let child = exceptBranch[i]
-          if child.kind == nnkIdent:
-            let cond = infix(errorNode, "of", child)
-            if exceptIdentCount == 0:
-              ifCond = cond
-            else:
-              ifCond = infix(ifCond, "or", cond)
-          else:
-            break
-          exceptIdentCount.inc
-
-        expectKind(exceptBranch[exceptIdentCount], nnkStmtList)
-        exceptionChecks.add((ifCond, exceptBranch[exceptIdentCount]))
-    # -> -> else: raise futSym.error
-    exceptionChecks.add((newIdentNode("true"),
-        newNimNode(nnkRaiseStmt).add(errorNode)))
-    # Read the future if there is no error.
-    # -> else: futSym.read
-    let elseNode = newNimNode(nnkElse, fromNode)
-    elseNode.add newNimNode(nnkStmtList, fromNode)
-    elseNode[0].add rootReceiver
-
-    let ifBody = newStmtList()
-    ifBody.add newCall(newIdentNode("setCurrentException"), errorNode)
-    ifBody.add newIfStmt(exceptionChecks)
-    ifBody.add newCall(newIdentNode("setCurrentException"), newNilLit())
-
-    result = newIfStmt(
-      (newDotExpr(futSym, newIdentNode("failed")), ifBody)
-    )
-    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,
-                   fromNode: NimNode) =
-  result = newNimNode(nnkStmtList, fromNode)
-  var futSym = genSym(nskVar, "future")
-  result.add newVarStmt(futSym, asyncProc) # -> var future<x> = y
-  useVar(result, futSym, valueReceiver, rootReceiver, fromNode)
-
-proc processBody(node, retFutureSym: NimNode,
-                 subTypeIsVoid: bool,
-                 tryStmt: NimNode): NimNode {.compileTime.} =
-  #echo(node.treeRepr)
-  result = node
-  case node.kind
-  of nnkReturnStmt:
-    result = newNimNode(nnkStmtList, node)
-    if node[0].kind == nnkEmpty:
-      if not subTypeIsVoid:
-        result.add newCall(newIdentNode("complete"), retFutureSym,
-            newIdentNode("result"))
-      else:
-        result.add newCall(newIdentNode("complete"), retFutureSym)
-    else:
-      let x = node[0].processBody(retFutureSym, subTypeIsVoid, tryStmt)
-      if x.kind == nnkYieldStmt: result.add x
-      else:
-        result.add newCall(newIdentNode("complete"), retFutureSym, x)
-
-    result.add newNimNode(nnkReturnStmt, node).add(newNilLit())
-    return # Don't process the children of this return stmt
-  of nnkCommand, nnkCall:
-    if node[0].kind == nnkIdent and node[0].ident == !"await":
-      case node[1].kind
-      of nnkIdent, nnkInfix, nnkDotExpr:
-        # await x
-        # await x or y
-        result = newNimNode(nnkYieldStmt, node).add(node[1]) # -> yield x
-      of nnkCall, nnkCommand:
-        # await foo(p, x)
-        # await foo p, x
-        var futureValue: NimNode
-        result.createVar("future" & $node[1][0].toStrLit, node[1], futureValue,
-                  futureValue, node)
-      else:
-        error("Invalid node kind in 'await', got: " & $node[1].kind)
-    elif node.len > 1 and node[1].kind == nnkCommand and
-         node[1][0].kind == nnkIdent and node[1][0].ident == !"await":
-      # foo await x
-      var newCommand = node
-      result.createVar("future" & $node[0].toStrLit, node[1][1], newCommand[1],
-                newCommand, node)
-
-  of nnkVarSection, nnkLetSection:
-    case node[0][2].kind
-    of nnkCommand:
-      if node[0][2][0].kind == nnkIdent and node[0][2][0].ident == !"await":
-        # var x = await y
-        var newVarSection = node # TODO: Should this use copyNimNode?
-        result.createVar("future" & $node[0][0].ident, node[0][2][1],
-          newVarSection[0][2], newVarSection, node)
-    else: discard
-  of nnkAsgn:
-    case node[1].kind
-    of nnkCommand:
-      if node[1][0].ident == !"await":
-        # x = await y
-        var newAsgn = node
-        result.createVar("future" & $node[0].toStrLit, node[1][1], newAsgn[1], newAsgn, node)
-    else: discard
-  of nnkDiscardStmt:
-    # discard await x
-    if node[0].kind == nnkCommand and node[0][0].kind == nnkIdent and
-          node[0][0].ident == !"await":
-      var newDiscard = node
-      result.createVar("futureDiscard_" & $toStrLit(node[0][1]), node[0][1],
-                newDiscard[0], newDiscard, node)
-  of nnkTryStmt:
-    # try: await x; except: ...
-    result = newNimNode(nnkStmtList, node)
-    template wrapInTry(n, tryBody: expr) =
-      var temp = n
-      n[0] = tryBody
-      tryBody = temp
-
-      # Transform ``except`` body.
-      # TODO: Could we perform some ``await`` transformation here to get it
-      # working in ``except``?
-      tryBody[1] = processBody(n[1], retFutureSym, subTypeIsVoid, nil)
-
-    proc processForTry(n: NimNode, i: var int,
-                       res: NimNode): bool {.compileTime.} =
-      ## Transforms the body of the tryStmt. Does not transform the
-      ## body in ``except``.
-      ## Returns true if the tryStmt node was transformed into an ifStmt.
-      result = false
-      var skipped = n.skipStmtList()
-      while i < skipped.len:
-        var processed = processBody(skipped[i], retFutureSym,
-                                    subTypeIsVoid, n)
-
-        # Check if we transformed the node into an exception check.
-        # This suggests skipped[i] contains ``await``.
-        if processed.kind != skipped[i].kind or processed.len != skipped[i].len:
-          processed = processed.skipUntilStmtList()
-          expectKind(processed, nnkStmtList)
-          expectKind(processed[2][1], nnkElse)
-          i.inc
-
-          if not processForTry(n, i, processed[2][1][0]):
-            # We need to wrap the nnkElse nodes back into a tryStmt.
-            # As they are executed if an exception does not happen
-            # inside the awaited future.
-            # The following code will wrap the nodes inside the
-            # original tryStmt.
-            wrapInTry(n, processed[2][1][0])
-
-          res.add processed
-          result = true
-        else:
-          res.add skipped[i]
-          i.inc
-    var i = 0
-    if not processForTry(node, i, result):
-      # If the tryStmt hasn't been transformed we can just put the body
-      # back into it.
-      wrapInTry(node, result)
-    return
-  else: discard
-
-  for i in 0 .. <result.len:
-    result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, nil)
-
-proc getName(node: NimNode): string {.compileTime.} =
-  case node.kind
-  of nnkPostfix:
-    return $node[1].ident
-  of nnkIdent:
-    return $node.ident
-  of nnkEmpty:
-    return "anonymous"
-  else:
-    error("Unknown name.")
-
-proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
-  ## This macro transforms a single procedure into a closure iterator.
-  ## The ``async`` macro supports a stmtList holding multiple async procedures.
-  if prc.kind notin {nnkProcDef, nnkLambda}:
-      error("Cannot transform this node kind into an async proc." &
-            " Proc definition or lambda node expected.")
-
-  hint("Processing " & prc[0].getName & " as an async proc.")
-
-  let returnType = prc[3][0]
-  var baseType: NimNode
-  # Verify that the return type is a Future[T]
-  if returnType.kind == nnkBracketExpr:
-    let fut = repr(returnType[0])
-    if fut != "Future":
-      error("Expected return type of 'Future' got '" & fut & "'")
-    baseType = returnType[1]
-  elif returnType.kind in nnkCallKinds and $returnType[0] == "[]":
-    let fut = repr(returnType[1])
-    if fut != "Future":
-      error("Expected return type of 'Future' got '" & fut & "'")
-    baseType = returnType[2]
-  elif returnType.kind == nnkEmpty:
-    baseType = returnType
-  else:
-    error("Expected return type of 'Future' got '" & repr(returnType) & "'")
-
-  let subtypeIsVoid = returnType.kind == nnkEmpty or
-        (baseType.kind == nnkIdent and returnType[1].ident == !"void")
-
-  var outerProcBody = newNimNode(nnkStmtList, prc[6])
-
-  # -> var retFuture = newFuture[T]()
-  var retFutureSym = genSym(nskVar, "retFuture")
-  var subRetType =
-    if returnType.kind == nnkEmpty: newIdentNode("void")
-    else: baseType
-  outerProcBody.add(
-    newVarStmt(retFutureSym,
-      newCall(
-        newNimNode(nnkBracketExpr, prc[6]).add(
-          newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`.
-          subRetType),
-      newLit(prc[0].getName)))) # Get type from return type of this proc
-
-  # -> iterator nameIter(): FutureBase {.closure.} =
-  # ->   {.push warning[resultshadowed]: off.}
-  # ->   var result: T
-  # ->   {.pop.}
-  # ->   <proc_body>
-  # ->   complete(retFuture, result)
-  var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter")
-  var procBody = prc[6].processBody(retFutureSym, subtypeIsVoid, nil)
-  # don't do anything with forward bodies (empty)
-  if procBody.kind != nnkEmpty:
-    if not subtypeIsVoid:
-      procBody.insert(0, newNimNode(nnkPragma).add(newIdentNode("push"),
-        newNimNode(nnkExprColonExpr).add(newNimNode(nnkBracketExpr).add(
-          newIdentNode("warning"), newIdentNode("resultshadowed")),
-        newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.}
-
-      procBody.insert(1, newNimNode(nnkVarSection, prc[6]).add(
-        newIdentDefs(newIdentNode("result"), baseType))) # -> var result: T
-
-      procBody.insert(2, newNimNode(nnkPragma).add(
-        newIdentNode("pop"))) # -> {.pop.})
-
-      procBody.add(
-        newCall(newIdentNode("complete"),
-          retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result)
-    else:
-      # -> complete(retFuture)
-      procBody.add(newCall(newIdentNode("complete"), retFutureSym))
-
-    var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
-                                  procBody, nnkIteratorDef)
-    closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure"))
-    outerProcBody.add(closureIterator)
-
-    # -> createCb(retFuture)
-    #var cbName = newIdentNode("cb")
-    var procCb = getAst createCb(retFutureSym, iteratorNameSym,
-                         newStrLitNode(prc[0].getName))
-    outerProcBody.add procCb
-
-    # -> return retFuture
-    outerProcBody.add newNimNode(nnkReturnStmt, prc[6][prc[6].len-1]).add(retFutureSym)
-
-  result = prc
-
-  # Remove the 'async' pragma.
-  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:
-      # Add Future[void]
-      result[3][0] = parseExpr("Future[void]")
-  if procBody.kind != nnkEmpty:
-    result[6] = outerProcBody
-  #echo(treeRepr(result))
-  #if prc[0].getName == "testInfix":
-  #  echo(toStrLit(result))
-
-macro async*(prc: untyped): untyped =
-  ## Macro which processes async procedures into the appropriate
-  ## iterators and yield statements.
-  if prc.kind == nnkStmtList:
-    for oneProc in prc:
-      result = newStmtList()
-      result.add asyncSingleProc(oneProc)
-  else:
-    result = asyncSingleProc(prc)
-  when defined(nimDumpAsync):
-    echo repr result
+include asyncmacro
 
 proc recvLine*(socket: AsyncFD): Future[string] {.async.} =
   ## Reads a line of data from ``socket``. Returned future will complete once
diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim
new file mode 100644
index 000000000..28e3e2a16
--- /dev/null
+++ b/lib/pure/asyncmacro.nim
@@ -0,0 +1,373 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## AsyncMacro
+## *************
+## `asyncdispatch` module depends on the `asyncmacro` module to work properly.
+
+import macros
+
+proc skipUntilStmtList(node: NimNode): NimNode {.compileTime.} =
+  # Skips a nest of StmtList's.
+  result = node
+  if node[0].kind == nnkStmtList:
+    result = skipUntilStmtList(node[0])
+
+proc skipStmtList(node: NimNode): NimNode {.compileTime.} =
+  result = node
+  if node[0].kind == nnkStmtList:
+    result = node[0]
+
+template createCb(retFutureSym, iteratorNameSym,
+                   name: untyped) =
+  var nameIterVar = iteratorNameSym
+  #{.push stackTrace: off.}
+  proc cb {.closure,gcsafe.} =
+    try:
+      if not nameIterVar.finished:
+        var next = nameIterVar()
+        if next == nil:
+          assert retFutureSym.finished, "Async procedure's (" &
+                 name & ") return Future was not finished."
+        else:
+          next.callback = cb
+    except:
+      if retFutureSym.finished:
+        # Take a look at tasyncexceptions for the bug which this fixes.
+        # That test explains it better than I can here.
+        raise
+      else:
+        retFutureSym.fail(getCurrentException())
+  cb()
+  #{.pop.}
+proc generateExceptionCheck(futSym,
+    tryStmt, rootReceiver, fromNode: NimNode): NimNode {.compileTime.} =
+  if tryStmt.kind == nnkNilLit:
+    result = rootReceiver
+  else:
+    var exceptionChecks: seq[tuple[cond, body: NimNode]] = @[]
+    let errorNode = newDotExpr(futSym, newIdentNode("error"))
+    for i in 1 .. <tryStmt.len:
+      let exceptBranch = tryStmt[i]
+      if exceptBranch[0].kind == nnkStmtList:
+        exceptionChecks.add((newIdentNode("true"), exceptBranch[0]))
+      else:
+        var exceptIdentCount = 0
+        var ifCond: NimNode
+        for i in 0 .. <exceptBranch.len:
+          let child = exceptBranch[i]
+          if child.kind == nnkIdent:
+            let cond = infix(errorNode, "of", child)
+            if exceptIdentCount == 0:
+              ifCond = cond
+            else:
+              ifCond = infix(ifCond, "or", cond)
+          else:
+            break
+          exceptIdentCount.inc
+
+        expectKind(exceptBranch[exceptIdentCount], nnkStmtList)
+        exceptionChecks.add((ifCond, exceptBranch[exceptIdentCount]))
+    # -> -> else: raise futSym.error
+    exceptionChecks.add((newIdentNode("true"),
+        newNimNode(nnkRaiseStmt).add(errorNode)))
+    # Read the future if there is no error.
+    # -> else: futSym.read
+    let elseNode = newNimNode(nnkElse, fromNode)
+    elseNode.add newNimNode(nnkStmtList, fromNode)
+    elseNode[0].add rootReceiver
+
+    let ifBody = newStmtList()
+    ifBody.add newCall(newIdentNode("setCurrentException"), errorNode)
+    ifBody.add newIfStmt(exceptionChecks)
+    ifBody.add newCall(newIdentNode("setCurrentException"), newNilLit())
+
+    result = newIfStmt(
+      (newDotExpr(futSym, newIdentNode("failed")), ifBody)
+    )
+    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,
+                   fromNode: NimNode) =
+  result = newNimNode(nnkStmtList, fromNode)
+  var futSym = genSym(nskVar, "future")
+  result.add newVarStmt(futSym, asyncProc) # -> var future<x> = y
+  useVar(result, futSym, valueReceiver, rootReceiver, fromNode)
+
+proc processBody(node, retFutureSym: NimNode,
+                 subTypeIsVoid: bool,
+                 tryStmt: NimNode): NimNode {.compileTime.} =
+  #echo(node.treeRepr)
+  result = node
+  case node.kind
+  of nnkReturnStmt:
+    result = newNimNode(nnkStmtList, node)
+    if node[0].kind == nnkEmpty:
+      if not subTypeIsVoid:
+        result.add newCall(newIdentNode("complete"), retFutureSym,
+            newIdentNode("result"))
+      else:
+        result.add newCall(newIdentNode("complete"), retFutureSym)
+    else:
+      let x = node[0].processBody(retFutureSym, subTypeIsVoid, tryStmt)
+      if x.kind == nnkYieldStmt: result.add x
+      else:
+        result.add newCall(newIdentNode("complete"), retFutureSym, x)
+
+    result.add newNimNode(nnkReturnStmt, node).add(newNilLit())
+    return # Don't process the children of this return stmt
+  of nnkCommand, nnkCall:
+    if node[0].kind == nnkIdent and node[0].ident == !"await":
+      case node[1].kind
+      of nnkIdent, nnkInfix, nnkDotExpr:
+        # await x
+        # await x or y
+        result = newNimNode(nnkYieldStmt, node).add(node[1]) # -> yield x
+      of nnkCall, nnkCommand:
+        # await foo(p, x)
+        # await foo p, x
+        var futureValue: NimNode
+        result.createVar("future" & $node[1][0].toStrLit, node[1], futureValue,
+                  futureValue, node)
+      else:
+        error("Invalid node kind in 'await', got: " & $node[1].kind)
+    elif node.len > 1 and node[1].kind == nnkCommand and
+         node[1][0].kind == nnkIdent and node[1][0].ident == !"await":
+      # foo await x
+      var newCommand = node
+      result.createVar("future" & $node[0].toStrLit, node[1][1], newCommand[1],
+                newCommand, node)
+
+  of nnkVarSection, nnkLetSection:
+    case node[0][2].kind
+    of nnkCommand:
+      if node[0][2][0].kind == nnkIdent and node[0][2][0].ident == !"await":
+        # var x = await y
+        var newVarSection = node # TODO: Should this use copyNimNode?
+        result.createVar("future" & $node[0][0].ident, node[0][2][1],
+          newVarSection[0][2], newVarSection, node)
+    else: discard
+  of nnkAsgn:
+    case node[1].kind
+    of nnkCommand:
+      if node[1][0].ident == !"await":
+        # x = await y
+        var newAsgn = node
+        result.createVar("future" & $node[0].toStrLit, node[1][1], newAsgn[1], newAsgn, node)
+    else: discard
+  of nnkDiscardStmt:
+    # discard await x
+    if node[0].kind == nnkCommand and node[0][0].kind == nnkIdent and
+          node[0][0].ident == !"await":
+      var newDiscard = node
+      result.createVar("futureDiscard_" & $toStrLit(node[0][1]), node[0][1],
+                newDiscard[0], newDiscard, node)
+  of nnkTryStmt:
+    # try: await x; except: ...
+    result = newNimNode(nnkStmtList, node)
+    template wrapInTry(n, tryBody: expr) =
+      var temp = n
+      n[0] = tryBody
+      tryBody = temp
+
+      # Transform ``except`` body.
+      # TODO: Could we perform some ``await`` transformation here to get it
+      # working in ``except``?
+      tryBody[1] = processBody(n[1], retFutureSym, subTypeIsVoid, nil)
+
+    proc processForTry(n: NimNode, i: var int,
+                       res: NimNode): bool {.compileTime.} =
+      ## Transforms the body of the tryStmt. Does not transform the
+      ## body in ``except``.
+      ## Returns true if the tryStmt node was transformed into an ifStmt.
+      result = false
+      var skipped = n.skipStmtList()
+      while i < skipped.len:
+        var processed = processBody(skipped[i], retFutureSym,
+                                    subTypeIsVoid, n)
+
+        # Check if we transformed the node into an exception check.
+        # This suggests skipped[i] contains ``await``.
+        if processed.kind != skipped[i].kind or processed.len != skipped[i].len:
+          processed = processed.skipUntilStmtList()
+          expectKind(processed, nnkStmtList)
+          expectKind(processed[2][1], nnkElse)
+          i.inc
+
+          if not processForTry(n, i, processed[2][1][0]):
+            # We need to wrap the nnkElse nodes back into a tryStmt.
+            # As they are executed if an exception does not happen
+            # inside the awaited future.
+            # The following code will wrap the nodes inside the
+            # original tryStmt.
+            wrapInTry(n, processed[2][1][0])
+
+          res.add processed
+          result = true
+        else:
+          res.add skipped[i]
+          i.inc
+    var i = 0
+    if not processForTry(node, i, result):
+      # If the tryStmt hasn't been transformed we can just put the body
+      # back into it.
+      wrapInTry(node, result)
+    return
+  else: discard
+
+  for i in 0 .. <result.len:
+    result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, nil)
+
+proc getName(node: NimNode): string {.compileTime.} =
+  case node.kind
+  of nnkPostfix:
+    return $node[1].ident
+  of nnkIdent:
+    return $node.ident
+  of nnkEmpty:
+    return "anonymous"
+  else:
+    error("Unknown name.")
+
+proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
+  ## This macro transforms a single procedure into a closure iterator.
+  ## The ``async`` macro supports a stmtList holding multiple async procedures.
+  if prc.kind notin {nnkProcDef, nnkLambda}:
+      error("Cannot transform this node kind into an async proc." &
+            " Proc definition or lambda node expected.")
+
+  hint("Processing " & prc[0].getName & " as an async proc.")
+
+  let returnType = prc[3][0]
+  var baseType: NimNode
+  # Verify that the return type is a Future[T]
+  if returnType.kind == nnkBracketExpr:
+    let fut = repr(returnType[0])
+    if fut != "Future":
+      error("Expected return type of 'Future' got '" & fut & "'")
+    baseType = returnType[1]
+  elif returnType.kind in nnkCallKinds and $returnType[0] == "[]":
+    let fut = repr(returnType[1])
+    if fut != "Future":
+      error("Expected return type of 'Future' got '" & fut & "'")
+    baseType = returnType[2]
+  elif returnType.kind == nnkEmpty:
+    baseType = returnType
+  else:
+    error("Expected return type of 'Future' got '" & repr(returnType) & "'")
+
+  let subtypeIsVoid = returnType.kind == nnkEmpty or
+        (baseType.kind == nnkIdent and returnType[1].ident == !"void")
+
+  var outerProcBody = newNimNode(nnkStmtList, prc[6])
+
+  # -> var retFuture = newFuture[T]()
+  var retFutureSym = genSym(nskVar, "retFuture")
+  var subRetType =
+    if returnType.kind == nnkEmpty: newIdentNode("void")
+    else: baseType
+  outerProcBody.add(
+    newVarStmt(retFutureSym,
+      newCall(
+        newNimNode(nnkBracketExpr, prc[6]).add(
+          newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`.
+          subRetType),
+      newLit(prc[0].getName)))) # Get type from return type of this proc
+
+  # -> iterator nameIter(): FutureBase {.closure.} =
+  # ->   {.push warning[resultshadowed]: off.}
+  # ->   var result: T
+  # ->   {.pop.}
+  # ->   <proc_body>
+  # ->   complete(retFuture, result)
+  var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter")
+  var procBody = prc[6].processBody(retFutureSym, subtypeIsVoid, nil)
+  # don't do anything with forward bodies (empty)
+  if procBody.kind != nnkEmpty:
+    if not subtypeIsVoid:
+      procBody.insert(0, newNimNode(nnkPragma).add(newIdentNode("push"),
+        newNimNode(nnkExprColonExpr).add(newNimNode(nnkBracketExpr).add(
+          newIdentNode("warning"), newIdentNode("resultshadowed")),
+        newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.}
+
+      procBody.insert(1, newNimNode(nnkVarSection, prc[6]).add(
+        newIdentDefs(newIdentNode("result"), baseType))) # -> var result: T
+
+      procBody.insert(2, newNimNode(nnkPragma).add(
+        newIdentNode("pop"))) # -> {.pop.})
+
+      procBody.add(
+        newCall(newIdentNode("complete"),
+          retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result)
+    else:
+      # -> complete(retFuture)
+      procBody.add(newCall(newIdentNode("complete"), retFutureSym))
+
+    var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
+                                  procBody, nnkIteratorDef)
+    closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure"))
+    outerProcBody.add(closureIterator)
+
+    # -> createCb(retFuture)
+    #var cbName = newIdentNode("cb")
+    var procCb = getAst createCb(retFutureSym, iteratorNameSym,
+                         newStrLitNode(prc[0].getName))
+    outerProcBody.add procCb
+
+    # -> return retFuture
+    outerProcBody.add newNimNode(nnkReturnStmt, prc[6][prc[6].len-1]).add(retFutureSym)
+
+  result = prc
+
+  # Remove the 'async' pragma.
+  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:
+      # Add Future[void]
+      result[3][0] = parseExpr("Future[void]")
+  if procBody.kind != nnkEmpty:
+    result[6] = outerProcBody
+  #echo(treeRepr(result))
+  #if prc[0].getName == "testInfix":
+  #  echo(toStrLit(result))
+
+macro async*(prc: untyped): untyped =
+  ## Macro which processes async procedures into the appropriate
+  ## iterators and yield statements.
+  if prc.kind == nnkStmtList:
+    for oneProc in prc:
+      result = newStmtList()
+      result.add asyncSingleProc(oneProc)
+  else:
+    result = asyncSingleProc(prc)
+  when defined(nimDumpAsync):
+    echo repr result
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
index 6a27e6af8..b23b1e5bb 100644
--- a/lib/pure/logging.nim
+++ b/lib/pure/logging.nim
@@ -47,7 +47,9 @@
 ## **Warning:** The global list of handlers is a thread var, this means that
 ## the handlers must be re-added in each thread.
 
-import strutils, os, times
+import strutils, times
+when not defined(js):
+  import os
 
 type
   Level* = enum  ## logging level
@@ -77,21 +79,24 @@ type
   ConsoleLogger* = ref object of Logger ## logger that writes the messages to the
                                         ## console
 
-  FileLogger* = ref object of Logger ## logger that writes the messages to a file
-    file*: File  ## the wrapped file.
+when not defined(js):
+  type
+    FileLogger* = ref object of Logger ## logger that writes the messages to a file
+      file*: File  ## the wrapped file.
 
-  RollingFileLogger* = ref object of FileLogger ## logger that writes the
-                                                ## messages to a file and
-                                                ## performs log rotation
-    maxLines: int # maximum number of lines
-    curLine : int
-    baseName: string # initial filename
-    baseMode: FileMode # initial file mode
-    logFiles: int # how many log files already created, e.g. basename.1, basename.2...
-    bufSize: int # size of output buffer (-1: use system defaults, 0: unbuffered, >0: fixed buffer size)
+    RollingFileLogger* = ref object of FileLogger ## logger that writes the
+                                                  ## messages to a file and
+                                                  ## performs log rotation
+      maxLines: int # maximum number of lines
+      curLine : int
+      baseName: string # initial filename
+      baseMode: FileMode # initial file mode
+      logFiles: int # how many log files already created, e.g. basename.1, basename.2...
+      bufSize: int # size of output buffer (-1: use system defaults, 0: unbuffered, >0: fixed buffer size)
 
-{.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger,
-    PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].}
+  {.deprecated: [PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].}
+
+{.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger].}
 
 var
   level {.threadvar.}: Level   ## global log filter
@@ -112,7 +117,7 @@ proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): str
     else:
       inc(i)
       var v = ""
-      var app = getAppFilename()
+      let app = when defined(js): "" else: getAppFilename()
       while frmt[i] in IdentChars:
         v.add(toLower(frmt[i]))
         inc(i)
@@ -121,8 +126,10 @@ proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): str
       of "time": result.add(getClockStr())
       of "datetime": result.add(getDateStr() & "T" & getClockStr())
       of "app":  result.add(app)
-      of "appdir": result.add(app.splitFile.dir)
-      of "appname": result.add(app.splitFile.name)
+      of "appdir":
+        when not defined(js): result.add(app.splitFile.dir)
+      of "appname":
+        when not defined(js): result.add(app.splitFile.name)
       of "levelid": result.add(LevelNames[level][0])
       of "levelname": result.add(LevelNames[level])
       else: discard
@@ -139,19 +146,13 @@ method log*(logger: Logger, level: Level, args: varargs[string, `$`]) {.
 method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) =
   ## Logs to the console using ``logger`` only.
   if level >= logging.level and level >= logger.levelThreshold:
-    writeLine(stdout, substituteLog(logger.fmtStr, level, args))
-    if level in {lvlError, lvlFatal}: flushFile(stdout)
-
-method log*(logger: FileLogger, level: Level, args: varargs[string, `$`]) =
-  ## Logs to a file using ``logger`` only.
-  if level >= logging.level and level >= logger.levelThreshold:
-    writeLine(logger.file, substituteLog(logger.fmtStr, level, args))
-    if level in {lvlError, lvlFatal}: flushFile(logger.file)
-
-proc defaultFilename*(): string =
-  ## Returns the default filename for a logger.
-  var (path, name, _) = splitFile(getAppFilename())
-  result = changeFileExt(path / name, "log")
+    let ln = substituteLog(logger.fmtStr, level, args)
+    when defined(js):
+      let cln: cstring = ln
+      {.emit: "console.log(`cln`);".}
+    else:
+      writeLine(stdout, ln)
+      if level in {lvlError, lvlFatal}: flushFile(stdout)
 
 proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): ConsoleLogger =
   ## Creates a new console logger. This logger logs to the console.
@@ -159,87 +160,99 @@ proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): Console
   result.fmtStr = fmtStr
   result.levelThreshold = levelThreshold
 
-proc newFileLogger*(filename = defaultFilename(),
-                    mode: FileMode = fmAppend,
-                    levelThreshold = lvlAll,
-                    fmtStr = defaultFmtStr,
-                    bufSize: int = -1): FileLogger =
-  ## Creates a new file logger. This logger logs to a file.
-  ## Use ``bufSize`` as size of the output buffer when writing the file
-  ## (-1: use system defaults, 0: unbuffered, >0: fixed buffer size).
-  new(result)
-  result.levelThreshold = levelThreshold
-  result.file = open(filename, mode, bufSize = bufSize)
-  result.fmtStr = fmtStr
-
-# ------
-
-proc countLogLines(logger: RollingFileLogger): int =
-  result = 0
-  for line in logger.file.lines():
-    result.inc()
-
-proc countFiles(filename: string): int =
-  # Example: file.log.1
-  result = 0
-  let (dir, name, ext) = splitFile(filename)
-  for kind, path in walkDir(dir):
-    if kind == pcFile:
-      let llfn = name & ext & ExtSep
-      if path.extractFilename.startsWith(llfn):
-        let numS = path.extractFilename[llfn.len .. ^1]
-        try:
-          let num = parseInt(numS)
-          if num > result:
-            result = num
-        except ValueError: discard
-
-proc newRollingFileLogger*(filename = defaultFilename(),
-                           mode: FileMode = fmReadWrite,
-                           levelThreshold = lvlAll,
-                           fmtStr = defaultFmtStr,
-                           maxLines = 1000,
-                           bufSize: int = -1): RollingFileLogger =
-  ## Creates a new rolling file logger. Once a file reaches ``maxLines`` lines
-  ## a new log file will be started and the old will be renamed.
-  ## Use ``bufSize`` as size of the output buffer when writing the file
-  ## (-1: use system defaults, 0: unbuffered, >0: fixed buffer size).
-  new(result)
-  result.levelThreshold = levelThreshold
-  result.fmtStr = fmtStr
-  result.maxLines = maxLines
-  result.bufSize = bufSize
-  result.file = open(filename, mode, bufSize=result.bufSize)
-  result.curLine = 0
-  result.baseName = filename
-  result.baseMode = mode
-
-  result.logFiles = countFiles(filename)
-
-  if mode == fmAppend:
-    # We need to get a line count because we will be appending to the file.
-    result.curLine = countLogLines(result)
-
-proc rotate(logger: RollingFileLogger) =
-  let (dir, name, ext) = splitFile(logger.baseName)
-  for i in countdown(logger.logFiles, 0):
-    let srcSuff = if i != 0: ExtSep & $i else: ""
-    moveFile(dir / (name & ext & srcSuff),
-             dir / (name & ext & ExtSep & $(i+1)))
-
-method log*(logger: RollingFileLogger, level: Level, args: varargs[string, `$`]) =
-  ## Logs to a file using rolling ``logger`` only.
-  if level >= logging.level and level >= logger.levelThreshold:
-    if logger.curLine >= logger.maxLines:
-      logger.file.close()
-      rotate(logger)
-      logger.logFiles.inc
-      logger.curLine = 0
-      logger.file = open(logger.baseName, logger.baseMode, bufSize = logger.bufSize)
-
-    writeLine(logger.file, substituteLog(logger.fmtStr, level, args))
-    if level in {lvlError, lvlFatal}: flushFile(logger.file)
-    logger.curLine.inc
+when not defined(js):
+  method log*(logger: FileLogger, level: Level, args: varargs[string, `$`]) =
+    ## Logs to a file using ``logger`` only.
+    if level >= logging.level and level >= logger.levelThreshold:
+      writeLine(logger.file, substituteLog(logger.fmtStr, level, args))
+      if level in {lvlError, lvlFatal}: flushFile(logger.file)
+
+  proc defaultFilename*(): string =
+    ## Returns the default filename for a logger.
+    var (path, name, _) = splitFile(getAppFilename())
+    result = changeFileExt(path / name, "log")
+
+  proc newFileLogger*(filename = defaultFilename(),
+                      mode: FileMode = fmAppend,
+                      levelThreshold = lvlAll,
+                      fmtStr = defaultFmtStr,
+                      bufSize: int = -1): FileLogger =
+    ## Creates a new file logger. This logger logs to a file.
+    ## Use ``bufSize`` as size of the output buffer when writing the file
+    ## (-1: use system defaults, 0: unbuffered, >0: fixed buffer size).
+    new(result)
+    result.levelThreshold = levelThreshold
+    result.file = open(filename, mode, bufSize = bufSize)
+    result.fmtStr = fmtStr
+
+  # ------
+
+  proc countLogLines(logger: RollingFileLogger): int =
+    result = 0
+    for line in logger.file.lines():
+      result.inc()
+
+  proc countFiles(filename: string): int =
+    # Example: file.log.1
+    result = 0
+    let (dir, name, ext) = splitFile(filename)
+    for kind, path in walkDir(dir):
+      if kind == pcFile:
+        let llfn = name & ext & ExtSep
+        if path.extractFilename.startsWith(llfn):
+          let numS = path.extractFilename[llfn.len .. ^1]
+          try:
+            let num = parseInt(numS)
+            if num > result:
+              result = num
+          except ValueError: discard
+
+  proc newRollingFileLogger*(filename = defaultFilename(),
+                            mode: FileMode = fmReadWrite,
+                            levelThreshold = lvlAll,
+                            fmtStr = defaultFmtStr,
+                            maxLines = 1000,
+                            bufSize: int = -1): RollingFileLogger =
+    ## Creates a new rolling file logger. Once a file reaches ``maxLines`` lines
+    ## a new log file will be started and the old will be renamed.
+    ## Use ``bufSize`` as size of the output buffer when writing the file
+    ## (-1: use system defaults, 0: unbuffered, >0: fixed buffer size).
+    new(result)
+    result.levelThreshold = levelThreshold
+    result.fmtStr = fmtStr
+    result.maxLines = maxLines
+    result.bufSize = bufSize
+    result.file = open(filename, mode, bufSize=result.bufSize)
+    result.curLine = 0
+    result.baseName = filename
+    result.baseMode = mode
+
+    result.logFiles = countFiles(filename)
+
+    if mode == fmAppend:
+      # We need to get a line count because we will be appending to the file.
+      result.curLine = countLogLines(result)
+
+  proc rotate(logger: RollingFileLogger) =
+    let (dir, name, ext) = splitFile(logger.baseName)
+    for i in countdown(logger.logFiles, 0):
+      let srcSuff = if i != 0: ExtSep & $i else: ""
+      moveFile(dir / (name & ext & srcSuff),
+              dir / (name & ext & ExtSep & $(i+1)))
+
+  method log*(logger: RollingFileLogger, level: Level, args: varargs[string, `$`]) =
+    ## Logs to a file using rolling ``logger`` only.
+    if level >= logging.level and level >= logger.levelThreshold:
+      if logger.curLine >= logger.maxLines:
+        logger.file.close()
+        rotate(logger)
+        logger.logFiles.inc
+        logger.curLine = 0
+        logger.file = open(logger.baseName, logger.baseMode, bufSize = logger.bufSize)
+
+      writeLine(logger.file, substituteLog(logger.fmtStr, level, args))
+      if level in {lvlError, lvlFatal}: flushFile(logger.file)
+      logger.curLine.inc
 
 # --------
 
@@ -323,10 +336,11 @@ proc getLogFilter*(): Level =
 
 when not defined(testing) and isMainModule:
   var L = newConsoleLogger()
-  var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
-  var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr)
+  when not defined(js):
+    var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
+    var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr)
+    addHandler(fL)
+    addHandler(rL)
   addHandler(L)
-  addHandler(fL)
-  addHandler(rL)
   for i in 0 .. 25:
     info("hello", i)
diff --git a/lib/upcoming/asyncdispatch.nim b/lib/upcoming/asyncdispatch.nim
index 3c11e082f..ce44e8a6a 100644
--- a/lib/upcoming/asyncdispatch.nim
+++ b/lib/upcoming/asyncdispatch.nim
@@ -9,7 +9,7 @@
 
 include "system/inclrtl"
 
-import os, oids, tables, strutils, macros, times, heapqueue
+import os, oids, tables, strutils, times, heapqueue
 
 import nativesockets, net, queues
 
@@ -796,14 +796,17 @@ when defined(windows) or defined(nimdoc):
     var retFuture = newFuture[void]("send")
 
     var dataBuf: TWSABuf
-    dataBuf.buf = data # since this is not used in a callback, this is fine
+    dataBuf.buf = data
     dataBuf.len = data.len.ULONG
+    GC_ref(data) # we need to protect data until send operation is completed
+                 # or failed.
 
     var bytesReceived, lowFlags: Dword
     var ol = PCustomOverlapped()
     GC_ref(ol)
     ol.data = CompletionData(fd: socket, cb:
       proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
+        GC_unref(data) # if operation completed `data` must be released.
         if not retFuture.finished:
           if errcode == OSErrorCode(-1):
             retFuture.complete()
@@ -820,6 +823,8 @@ when defined(windows) or defined(nimdoc):
       let err = osLastError()
       if err.int32 != ERROR_IO_PENDING:
         GC_unref(ol)
+        GC_unref(data) # if operation failed `data` must be released, because
+                       # completion routine will not be called.
         if flags.isDisconnectionError(err):
           retFuture.complete()
         else:
@@ -952,7 +957,7 @@ when defined(windows) or defined(nimdoc):
     let dwLocalAddressLength = Dword(sizeof (Sockaddr_in) + 16)
     let dwRemoteAddressLength = Dword(sizeof(Sockaddr_in) + 16)
 
-    template completeAccept(): stmt {.immediate, dirty.} =
+    template completeAccept() {.dirty.} =
       var listenSock = socket
       let setoptRet = setsockopt(clientSock, SOL_SOCKET,
           SO_UPDATE_ACCEPT_CONTEXT, addr listenSock,
@@ -972,7 +977,7 @@ when defined(windows) or defined(nimdoc):
          client: clientSock.AsyncFD)
       )
 
-    template failAccept(errcode): stmt =
+    template failAccept(errcode) =
       if flags.isDisconnectionError(errcode):
         var newAcceptFut = acceptAddr(socket, flags)
         newAcceptFut.callback =
@@ -1748,360 +1753,7 @@ proc accept*(socket: AsyncFD,
   return retFut
 
 # -- Await Macro
-
-proc skipUntilStmtList(node: NimNode): NimNode {.compileTime.} =
-  # Skips a nest of StmtList's.
-  result = node
-  if node[0].kind == nnkStmtList:
-    result = skipUntilStmtList(node[0])
-
-proc skipStmtList(node: NimNode): NimNode {.compileTime.} =
-  result = node
-  if node[0].kind == nnkStmtList:
-    result = node[0]
-
-template createCb(retFutureSym, iteratorNameSym,
-                   name: expr): stmt {.immediate.} =
-  var nameIterVar = iteratorNameSym
-  #{.push stackTrace: off.}
-  proc cb {.closure,gcsafe.} =
-    try:
-      if not nameIterVar.finished:
-        var next = nameIterVar()
-        if next == nil:
-          assert retFutureSym.finished, "Async procedure's (" &
-                 name & ") return Future was not finished."
-        else:
-          next.callback = cb
-    except:
-      if retFutureSym.finished:
-        # Take a look at tasyncexceptions for the bug which this fixes.
-        # That test explains it better than I can here.
-        raise
-      else:
-        retFutureSym.fail(getCurrentException())
-  cb()
-  #{.pop.}
-proc generateExceptionCheck(futSym,
-    tryStmt, rootReceiver, fromNode: NimNode): NimNode {.compileTime.} =
-  if tryStmt.kind == nnkNilLit:
-    result = rootReceiver
-  else:
-    var exceptionChecks: seq[tuple[cond, body: NimNode]] = @[]
-    let errorNode = newDotExpr(futSym, newIdentNode("error"))
-    for i in 1 .. <tryStmt.len:
-      let exceptBranch = tryStmt[i]
-      if exceptBranch[0].kind == nnkStmtList:
-        exceptionChecks.add((newIdentNode("true"), exceptBranch[0]))
-      else:
-        var exceptIdentCount = 0
-        var ifCond: NimNode
-        for i in 0 .. <exceptBranch.len:
-          let child = exceptBranch[i]
-          if child.kind == nnkIdent:
-            let cond = infix(errorNode, "of", child)
-            if exceptIdentCount == 0:
-              ifCond = cond
-            else:
-              ifCond = infix(ifCond, "or", cond)
-          else:
-            break
-          exceptIdentCount.inc
-
-        expectKind(exceptBranch[exceptIdentCount], nnkStmtList)
-        exceptionChecks.add((ifCond, exceptBranch[exceptIdentCount]))
-    # -> -> else: raise futSym.error
-    exceptionChecks.add((newIdentNode("true"),
-        newNimNode(nnkRaiseStmt).add(errorNode)))
-    # Read the future if there is no error.
-    # -> else: futSym.read
-    let elseNode = newNimNode(nnkElse, fromNode)
-    elseNode.add newNimNode(nnkStmtList, fromNode)
-    elseNode[0].add rootReceiver
-
-    let ifBody = newStmtList()
-    ifBody.add newCall(newIdentNode("setCurrentException"), errorNode)
-    ifBody.add newIfStmt(exceptionChecks)
-    ifBody.add newCall(newIdentNode("setCurrentException"), newNilLit())
-
-    result = newIfStmt(
-      (newDotExpr(futSym, newIdentNode("failed")), ifBody)
-    )
-    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,
-                   fromNode: NimNode) =
-  result = newNimNode(nnkStmtList, fromNode)
-  var futSym = genSym(nskVar, "future")
-  result.add newVarStmt(futSym, asyncProc) # -> var future<x> = y
-  useVar(result, futSym, valueReceiver, rootReceiver, fromNode)
-
-proc processBody(node, retFutureSym: NimNode,
-                 subTypeIsVoid: bool,
-                 tryStmt: NimNode): NimNode {.compileTime.} =
-  #echo(node.treeRepr)
-  result = node
-  case node.kind
-  of nnkReturnStmt:
-    result = newNimNode(nnkStmtList, node)
-    if node[0].kind == nnkEmpty:
-      if not subTypeIsVoid:
-        result.add newCall(newIdentNode("complete"), retFutureSym,
-            newIdentNode("result"))
-      else:
-        result.add newCall(newIdentNode("complete"), retFutureSym)
-    else:
-      result.add newCall(newIdentNode("complete"), retFutureSym,
-        node[0].processBody(retFutureSym, subTypeIsVoid, tryStmt))
-
-    result.add newNimNode(nnkReturnStmt, node).add(newNilLit())
-    return # Don't process the children of this return stmt
-  of nnkCommand, nnkCall:
-    if node[0].kind == nnkIdent and node[0].ident == !"await":
-      case node[1].kind
-      of nnkIdent, nnkInfix, nnkDotExpr:
-        # await x
-        # await x or y
-        result = newNimNode(nnkYieldStmt, node).add(node[1]) # -> yield x
-      of nnkCall, nnkCommand:
-        # await foo(p, x)
-        # await foo p, x
-        var futureValue: NimNode
-        result.createVar("future" & $node[1][0].toStrLit, node[1], futureValue,
-                  futureValue, node)
-      else:
-        error("Invalid node kind in 'await', got: " & $node[1].kind)
-    elif node.len > 1 and node[1].kind == nnkCommand and
-         node[1][0].kind == nnkIdent and node[1][0].ident == !"await":
-      # foo await x
-      var newCommand = node
-      result.createVar("future" & $node[0].toStrLit, node[1][1], newCommand[1],
-                newCommand, node)
-
-  of nnkVarSection, nnkLetSection:
-    case node[0][2].kind
-    of nnkCommand:
-      if node[0][2][0].kind == nnkIdent and node[0][2][0].ident == !"await":
-        # var x = await y
-        var newVarSection = node # TODO: Should this use copyNimNode?
-        result.createVar("future" & $node[0][0].ident, node[0][2][1],
-          newVarSection[0][2], newVarSection, node)
-    else: discard
-  of nnkAsgn:
-    case node[1].kind
-    of nnkCommand:
-      if node[1][0].ident == !"await":
-        # x = await y
-        var newAsgn = node
-        result.createVar("future" & $node[0].toStrLit, node[1][1], newAsgn[1], newAsgn, node)
-    else: discard
-  of nnkDiscardStmt:
-    # discard await x
-    if node[0].kind == nnkCommand and node[0][0].kind == nnkIdent and
-          node[0][0].ident == !"await":
-      var newDiscard = node
-      result.createVar("futureDiscard_" & $toStrLit(node[0][1]), node[0][1],
-                newDiscard[0], newDiscard, node)
-  of nnkTryStmt:
-    # try: await x; except: ...
-    result = newNimNode(nnkStmtList, node)
-    template wrapInTry(n, tryBody: expr) =
-      var temp = n
-      n[0] = tryBody
-      tryBody = temp
-
-      # Transform ``except`` body.
-      # TODO: Could we perform some ``await`` transformation here to get it
-      # working in ``except``?
-      tryBody[1] = processBody(n[1], retFutureSym, subTypeIsVoid, nil)
-
-    proc processForTry(n: NimNode, i: var int,
-                       res: NimNode): bool {.compileTime.} =
-      ## Transforms the body of the tryStmt. Does not transform the
-      ## body in ``except``.
-      ## Returns true if the tryStmt node was transformed into an ifStmt.
-      result = false
-      var skipped = n.skipStmtList()
-      while i < skipped.len:
-        var processed = processBody(skipped[i], retFutureSym,
-                                    subTypeIsVoid, n)
-
-        # Check if we transformed the node into an exception check.
-        # This suggests skipped[i] contains ``await``.
-        if processed.kind != skipped[i].kind or processed.len != skipped[i].len:
-          processed = processed.skipUntilStmtList()
-          expectKind(processed, nnkStmtList)
-          expectKind(processed[2][1], nnkElse)
-          i.inc
-
-          if not processForTry(n, i, processed[2][1][0]):
-            # We need to wrap the nnkElse nodes back into a tryStmt.
-            # As they are executed if an exception does not happen
-            # inside the awaited future.
-            # The following code will wrap the nodes inside the
-            # original tryStmt.
-            wrapInTry(n, processed[2][1][0])
-
-          res.add processed
-          result = true
-        else:
-          res.add skipped[i]
-          i.inc
-    var i = 0
-    if not processForTry(node, i, result):
-      # If the tryStmt hasn't been transformed we can just put the body
-      # back into it.
-      wrapInTry(node, result)
-    return
-  else: discard
-
-  for i in 0 .. <result.len:
-    result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, nil)
-
-proc getName(node: NimNode): string {.compileTime.} =
-  case node.kind
-  of nnkPostfix:
-    return $node[1].ident
-  of nnkIdent:
-    return $node.ident
-  of nnkEmpty:
-    return "anonymous"
-  else:
-    error("Unknown name.")
-
-proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
-  ## This macro transforms a single procedure into a closure iterator.
-  ## The ``async`` macro supports a stmtList holding multiple async procedures.
-  if prc.kind notin {nnkProcDef, nnkLambda}:
-      error("Cannot transform this node kind into an async proc." &
-            " Proc definition or lambda node expected.")
-
-  hint("Processing " & prc[0].getName & " as an async proc.")
-
-  let returnType = prc[3][0]
-  var baseType: NimNode
-  # Verify that the return type is a Future[T]
-  if returnType.kind == nnkBracketExpr:
-    let fut = repr(returnType[0])
-    if fut != "Future":
-      error("Expected return type of 'Future' got '" & fut & "'")
-    baseType = returnType[1]
-  elif returnType.kind in nnkCallKinds and $returnType[0] == "[]":
-    let fut = repr(returnType[1])
-    if fut != "Future":
-      error("Expected return type of 'Future' got '" & fut & "'")
-    baseType = returnType[2]
-  elif returnType.kind == nnkEmpty:
-    baseType = returnType
-  else:
-    error("Expected return type of 'Future' got '" & repr(returnType) & "'")
-
-  let subtypeIsVoid = returnType.kind == nnkEmpty or
-        (baseType.kind == nnkIdent and returnType[1].ident == !"void")
-
-  var outerProcBody = newNimNode(nnkStmtList, prc[6])
-
-  # -> var retFuture = newFuture[T]()
-  var retFutureSym = genSym(nskVar, "retFuture")
-  var subRetType =
-    if returnType.kind == nnkEmpty: newIdentNode("void")
-    else: baseType
-  outerProcBody.add(
-    newVarStmt(retFutureSym,
-      newCall(
-        newNimNode(nnkBracketExpr, prc[6]).add(
-          newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`.
-          subRetType),
-      newLit(prc[0].getName)))) # Get type from return type of this proc
-
-  # -> iterator nameIter(): FutureBase {.closure.} =
-  # ->   {.push warning[resultshadowed]: off.}
-  # ->   var result: T
-  # ->   {.pop.}
-  # ->   <proc_body>
-  # ->   complete(retFuture, result)
-  var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter")
-  var procBody = prc[6].processBody(retFutureSym, subtypeIsVoid, nil)
-  if not subtypeIsVoid:
-    procBody.insert(0, newNimNode(nnkPragma).add(newIdentNode("push"),
-      newNimNode(nnkExprColonExpr).add(newNimNode(nnkBracketExpr).add(
-        newIdentNode("warning"), newIdentNode("resultshadowed")),
-      newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.}
-
-    procBody.insert(1, newNimNode(nnkVarSection, prc[6]).add(
-      newIdentDefs(newIdentNode("result"), baseType))) # -> var result: T
-
-    procBody.insert(2, newNimNode(nnkPragma).add(
-      newIdentNode("pop"))) # -> {.pop.})
-
-    procBody.add(
-      newCall(newIdentNode("complete"),
-        retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result)
-  else:
-    # -> complete(retFuture)
-    procBody.add(newCall(newIdentNode("complete"), retFutureSym))
-
-  var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
-                                procBody, nnkIteratorDef)
-  closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure"))
-  outerProcBody.add(closureIterator)
-
-  # -> createCb(retFuture)
-  #var cbName = newIdentNode("cb")
-  var procCb = newCall(bindSym"createCb", retFutureSym, iteratorNameSym,
-                       newStrLitNode(prc[0].getName))
-  outerProcBody.add procCb
-
-  # -> return retFuture
-  outerProcBody.add newNimNode(nnkReturnStmt, prc[6][prc[6].len-1]).add(retFutureSym)
-
-  result = prc
-
-  # Remove the 'async' pragma.
-  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:
-      # Add Future[void]
-      result[3][0] = parseExpr("Future[void]")
-
-  result[6] = outerProcBody
-
-  #echo(treeRepr(result))
-  #if prc[0].getName == "testInfix":
-  #  echo(toStrLit(result))
-
-macro async*(prc: stmt): stmt {.immediate.} =
-  ## Macro which processes async procedures into the appropriate
-  ## iterators and yield statements.
-  if prc.kind == nnkStmtList:
-    for oneProc in prc:
-      result = newStmtList()
-      result.add asyncSingleProc(oneProc)
-  else:
-    result = asyncSingleProc(prc)
+include asyncmacro
 
 proc recvLine*(socket: AsyncFD): Future[string] {.async.} =
   ## Reads a line of data from ``socket``. Returned future will complete once
diff --git a/readme.md b/readme.md
index f56b054d6..204b51906 100644
--- a/readme.md
+++ b/readme.md
@@ -68,13 +68,16 @@ 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)
+[![Join the Gitter channel](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/nim-lang/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
+* [IRC (Freenode#nim)](https://webchat.freenode.net/?channels=nim) - a place to discuss
   Nim in real-time, this is also where most development decision get made!
+* [Gitter](https://gitter.im/nim-lang/Nim) allows to discuss Nim from your browser, one click to join.
+  There is a bridge between Gitter and IRC channels.
 * [Stackoverflow](http://stackoverflow.com/questions/tagged/nim)
 
 ## Contributing
diff --git a/tests/async/config.nims b/tests/async/config.nims
new file mode 100644
index 000000000..97c2e0aa4
--- /dev/null
+++ b/tests/async/config.nims
@@ -0,0 +1,2 @@
+when defined(upcoming):
+  patchFile("stdlib", "asyncdispatch", "$lib/upcoming/asyncdispatch")
diff --git a/tests/overload/importA.nim b/tests/overload/importA.nim
new file mode 100644
index 000000000..f045d11b4
--- /dev/null
+++ b/tests/overload/importA.nim
@@ -0,0 +1,5 @@
+type
+  Field* = object
+    elemSize*: int
+
+template `+`*(x: untyped, y: Field): untyped = x
diff --git a/tests/overload/importB.nim b/tests/overload/importB.nim
new file mode 100644
index 000000000..2dc3adf7a
--- /dev/null
+++ b/tests/overload/importB.nim
@@ -0,0 +1,15 @@
+type
+  Foo*[T] = object
+    v*: T
+
+template `+`*(x: Foo, y: Foo): untyped = x
+
+template newvar*(r: untyped): untyped {.dirty.} =
+  var r: float
+
+template t1*(x: Foo): untyped =
+  newvar(y1)
+  x
+template t2*(x: Foo): untyped =
+  newvar(y2)
+  x
diff --git a/tests/overload/timport.nim b/tests/overload/timport.nim
new file mode 100644
index 000000000..8ea65e54d
--- /dev/null
+++ b/tests/overload/timport.nim
@@ -0,0 +1,7 @@
+# issue 4675
+import importA  # comment this out to make it work
+import importB
+
+var x: Foo[float]
+var y: Foo[float]
+let r = t1(x) + t2(y)
diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim
index 29b6d9aba..3ed2f2196 100644
--- a/tests/testament/categories.nim
+++ b/tests/testament/categories.nim
@@ -202,6 +202,14 @@ proc ioTests(r: var TResults, cat: Category, options: string) =
   testSpec c, makeTest("tests/system/helpers/readall_echo", options, cat)
   testSpec r, makeTest("tests/system/io", options, cat)
 
+# ------------------------- async tests ---------------------------------------
+proc asyncTests(r: var TResults, cat: Category, options: string) =
+  template test(filename: untyped) =
+    testSpec r, makeTest(filename, options, cat)
+    testSpec r, makeTest(filename, options & " -d:upcoming", cat)
+  for t in os.walkFiles("tests/async/t*.nim"):
+    test(t)
+
 # ------------------------- debugger tests ------------------------------------
 
 proc debuggerTests(r: var TResults, cat: Category, options: string) =
@@ -228,8 +236,8 @@ proc jsTests(r: var TResults, cat: Category, options: string) =
                    "varres/tvartup", "misc/tints", "misc/tunsignedinc"]:
     test "tests/" & testfile & ".nim"
 
-  for testfile in ["pure/strutils", "pure/json", "pure/random", "pure/times"]:
-    test "lib/" & testfile & ".nim"
+  for testfile in ["strutils", "json", "random", "times", "logging"]:
+    test "lib/pure/" & testfile & ".nim"
 
 # ------------------------- manyloc -------------------------------------------
 #proc runSpecialTests(r: var TResults, options: string) =
@@ -390,6 +398,8 @@ proc processCategory(r: var TResults, cat: Category, options: string, fileGlob:
     threadTests r, cat, options & " --threads:on"
   of "io":
     ioTests r, cat, options
+  of "async":
+    asyncTests r, cat, options
   of "lib":
     testStdlib(r, "lib/pure/*.nim", options, cat)
     testStdlib(r, "lib/packages/docutils/highlite", options, cat)
diff --git a/tools/nimweb.nim b/tools/nimweb.nim
index 4cf7020c2..cef4df1c6 100644
--- a/tools/nimweb.nim
+++ b/tools/nimweb.nim
@@ -94,7 +94,8 @@ Compile_options:
   rYearMonthDay = r"(\d{4})_(\d{2})_(\d{2})"
   rssUrl = "http://nim-lang.org/news.xml"
   rssNewsUrl = "http://nim-lang.org/news.html"
-  sponsors = "web/sponsors.csv"
+  activeSponsors = "web/sponsors.csv"
+  inactiveSponsors = "web/inactive_sponsors.csv"
   validAnchorCharacters = Letters + Digits
 
 
@@ -446,8 +447,9 @@ proc readSponsors(sponsorsFile: string): seq[Sponsor] =
         since: parser.row[5], level: parser.row[6].parseInt))
   parser.close()
 
-proc buildSponsors(c: var TConfigData, sponsorsFile: string, outputDir: string) =
-  let sponsors = generateSponsors(readSponsors(sponsorsFile))
+proc buildSponsors(c: var TConfigData, outputDir: string) =
+  let sponsors = generateSponsorsPage(readSponsors(activeSponsors),
+                                      readSponsors(inactiveSponsors))
   let outFile = outputDir / "sponsors.html"
   var f: File
   if open(f, outFile, fmWrite):
@@ -500,7 +502,7 @@ proc buildWebsite(c: var TConfigData) =
     buildPage(c, file, if file == "question": "FAQ" else: file, rss)
   copyDir("web/assets", "web/upload/assets")
   buildNewsRss(c, "web/upload")
-  buildSponsors(c, sponsors, "web/upload")
+  buildSponsors(c, "web/upload")
   buildNews(c, "web/news", "web/upload/news")
 
 proc main(c: var TConfigData) =
diff --git a/tools/website.tmpl b/tools/website.tmpl
index cf2c72a60..87e1b151c 100644
--- a/tools/website.tmpl
+++ b/tools/website.tmpl
@@ -66,7 +66,7 @@
             </a>
           </div>
           <div id="slide1" class="niaslide">
-            <a href="news.html#Z2016-01-27-nim-in-action-is-now-available">
+            <a href="news/2016_01_27_nim_in_action_is_now_available.html">
               <img src="${rootDir}assets/niminaction/banner.jpg" alt="New in Manning Early Access Program: Nim in Action!"/>
             </a>
           </div>
@@ -218,14 +218,9 @@ runForever()
 </html>
 #end proc
 #
+#
 #proc generateSponsors(sponsors: seq[Sponsor]): string =
 #result = ""
-<h1 id="our-current-sponsors">Our Current Sponsors</h1>
-<p>This page lists the companies and individuals that are, very kindly, contributing a
-monthly amount to help sustain Nim's development. For more details take a
-look at the <a href="https://salt.bountysource.com/teams/nim">Bountysource campaign</a>.</p>
-<p class="lastUpdate">Last updated: ${getTime().getGMTime().format("dd/MM/yyyy")}</p>
-<dl>
 #for sponsor in sponsors:
   <dt class="level-${sponsor.level}">
     #if sponsor.url.len > 0:
@@ -248,6 +243,24 @@ look at the <a href="https://salt.bountysource.com/teams/nim">Bountysource campa
     Donated $$${sponsor.allTime} in total since ${sponsor.since}
   </dd>
 #end for
+#end proc
+#proc generateSponsorsPage(activeSponsors, inactiveSponsors: seq[Sponsor]): string =
+#result = ""
+<h1 id="our-current-sponsors">Our Current Sponsors</h1>
+<p>This section lists the companies and individuals that are, very kindly, contributing a
+monthly amount to help sustain Nim's development. For more details take a
+look at the <a href="https://salt.bountysource.com/teams/nim">Bountysource campaign</a>.</p>
+<p class="lastUpdate">Last updated: ${getTime().getGMTime().format("dd/MM/yyyy")}</p>
+<dl>
+${generateSponsors(activeSponsors)}
+</dl>
+#
+<h1 id="our-past-sponsors">Our Past Sponsors</h1>
+<p>This section lists the companies and individuals that have contributed
+money in the past to help sustain Nim's development. For more details take a
+look at the <a href="https://salt.bountysource.com/teams/nim">Bountysource campaign</a>.</p>
+<dl>
+${generateSponsors(inactiveSponsors)}
 </dl>
 #
 #end proc
diff --git a/web/assets/news/images/survey/10_needs.png b/web/assets/news/images/survey/10_needs.png
new file mode 100644
index 000000000..67d568552
--- /dev/null
+++ b/web/assets/news/images/survey/10_needs.png
Binary files differdiff --git a/web/assets/news/images/survey/book.png b/web/assets/news/images/survey/book.png
new file mode 100644
index 000000000..5bb418e63
--- /dev/null
+++ b/web/assets/news/images/survey/book.png
Binary files differdiff --git a/web/assets/news/images/survey/book_opinion.png b/web/assets/news/images/survey/book_opinion.png
new file mode 100644
index 000000000..4e56ab26e
--- /dev/null
+++ b/web/assets/news/images/survey/book_opinion.png
Binary files differdiff --git a/web/assets/news/images/survey/breakage.png b/web/assets/news/images/survey/breakage.png
new file mode 100644
index 000000000..5eb4c5289
--- /dev/null
+++ b/web/assets/news/images/survey/breakage.png
Binary files differdiff --git a/web/assets/news/images/survey/difficulty_fixing_breakage.png b/web/assets/news/images/survey/difficulty_fixing_breakage.png
new file mode 100644
index 000000000..022aa00ed
--- /dev/null
+++ b/web/assets/news/images/survey/difficulty_fixing_breakage.png
Binary files differdiff --git a/web/assets/news/images/survey/domains.png b/web/assets/news/images/survey/domains.png
new file mode 100644
index 000000000..50b1ed7ff
--- /dev/null
+++ b/web/assets/news/images/survey/domains.png
Binary files differdiff --git a/web/assets/news/images/survey/ex_nim.png b/web/assets/news/images/survey/ex_nim.png
new file mode 100644
index 000000000..50082ea8b
--- /dev/null
+++ b/web/assets/news/images/survey/ex_nim.png
Binary files differdiff --git a/web/assets/news/images/survey/languages.png b/web/assets/news/images/survey/languages.png
new file mode 100644
index 000000000..db35f9bd4
--- /dev/null
+++ b/web/assets/news/images/survey/languages.png
Binary files differdiff --git a/web/assets/news/images/survey/learning_resources.png b/web/assets/news/images/survey/learning_resources.png
new file mode 100644
index 000000000..39f533ad0
--- /dev/null
+++ b/web/assets/news/images/survey/learning_resources.png
Binary files differdiff --git a/web/assets/news/images/survey/nim_appeal.png b/web/assets/news/images/survey/nim_appeal.png
new file mode 100644
index 000000000..4f53e1447
--- /dev/null
+++ b/web/assets/news/images/survey/nim_appeal.png
Binary files differdiff --git a/web/assets/news/images/survey/nim_displeasing.png b/web/assets/news/images/survey/nim_displeasing.png
new file mode 100644
index 000000000..b7232df04
--- /dev/null
+++ b/web/assets/news/images/survey/nim_displeasing.png
Binary files differdiff --git a/web/assets/news/images/survey/nim_domains.png b/web/assets/news/images/survey/nim_domains.png
new file mode 100644
index 000000000..2d8fc6652
--- /dev/null
+++ b/web/assets/news/images/survey/nim_domains.png
Binary files differdiff --git a/web/assets/news/images/survey/nimble_opinion.png b/web/assets/news/images/survey/nimble_opinion.png
new file mode 100644
index 000000000..3fe76326e
--- /dev/null
+++ b/web/assets/news/images/survey/nimble_opinion.png
Binary files differdiff --git a/web/assets/news/images/survey/non_user.png b/web/assets/news/images/survey/non_user.png
new file mode 100644
index 000000000..b5324b69c
--- /dev/null
+++ b/web/assets/news/images/survey/non_user.png
Binary files differdiff --git a/web/assets/news/images/survey/planning_to_use_at_work.png b/web/assets/news/images/survey/planning_to_use_at_work.png
index be3a50467..b3e2001c3 100644
--- a/web/assets/news/images/survey/planning_to_use_at_work.png
+++ b/web/assets/news/images/survey/planning_to_use_at_work.png
Binary files differdiff --git a/web/assets/news/images/survey/project_size_nim_rust.png b/web/assets/news/images/survey/project_size_nim_rust.png
index 41e3ec8b1..4bc0e6b47 100644
--- a/web/assets/news/images/survey/project_size_nim_rust.png
+++ b/web/assets/news/images/survey/project_size_nim_rust.png
Binary files differdiff --git a/web/assets/news/images/survey/upgrades_broke_things.png b/web/assets/news/images/survey/upgrades_broke_things.png
deleted file mode 100644
index 28a8ee3f0..000000000
--- a/web/assets/news/images/survey/upgrades_broke_things.png
+++ /dev/null
Binary files differdiff --git a/web/assets/style.css b/web/assets/style.css
index af32fad07..2e166530d 100644
--- a/web/assets/style.css
+++ b/web/assets/style.css
@@ -516,12 +516,11 @@ pre .end { background:url("images/tabEnd.png") no-repeat left bottom; }
       padding:5px 30px;
       margin-bottom:20px;
       border:8px solid rgba(0,0,0,.8);
-      border-right-width:16px;
+      border-right-width:0;
       border-top-width:0;
       border-bottom-width:0;
       border-radius:3px;
-      background:rgba(0,0,0,0.1);
-      box-shadow:1px 3px 12px rgba(0,0,0,.4); }
+      background:rgba(0,0,0,0.1); }
     .standout h2 { margin-bottom:10px; padding-bottom:10px; border-bottom:1px dashed rgba(0,0,0,.8); }
     .standout li { margin:0 !important; padding-top:10px; border-top:1px dashed rgba(0,0,0,.2); }
     .standout ul { padding-bottom:5px; }
@@ -611,6 +610,15 @@ p.lastUpdate {
   color: #6d6d6d;
 }
 
+/* quotes */
+
+blockquote {
+  padding: 0px 8px;
+  margin: 10px 0px;
+  border-left: 2px solid rgb(61, 61, 61);
+  color: rgb(109, 109, 109);
+}
+
 /* News articles */
 
 .metadata {
diff --git a/web/bountysource.nim b/web/bountysource.nim
index a4f76417e..1d47cea56 100644
--- a/web/bountysource.nim
+++ b/web/bountysource.nim
@@ -29,12 +29,6 @@ proc newBountySource(team, token: string): BountySource =
   result.client.headers["Referer"] = "https://salt.bountysource.com/teams/nim/admin/supporters"
   result.client.headers["Origin"] = "https://salt.bountysource.com/"
 
-proc getSupportLevels(self: BountySource): Future[JsonNode] {.async.} =
-  let response = await self.client.get(apiUrl &
-    "/support_levels?supporters_for_team=" & self.team)
-  doAssert response.status.startsWith($Http200) # TODO: There should be a ==
-  return parseJson(response.body)
-
 proc getSupporters(self: BountySource): Future[JsonNode] {.async.} =
   let response = await self.client.get(apiUrl &
     "/supporters?order=monthly&per_page=200&team_slug=" & self.team)
@@ -47,26 +41,21 @@ proc getGithubUser(username: string): Future[JsonNode] {.async.} =
   if response.status.startsWith($Http200):
     return parseJson(response.body)
   else:
+    echo("Could not get Github user: ", username, ". ", response.status)
     return nil
 
-proc processLevels(supportLevels: JsonNode) =
-  var before = supportLevels.elems.len
-  supportLevels.elems.keepIf(
-    item => item["status"].getStr == "active" and
-      item["owner"]["display_name"].getStr != "Anonymous"
+proc processSupporters(supporters: JsonNode) =
+  var before = supporters.elems.len
+  supporters.elems.keepIf(
+    item => item["display_name"].getStr != "Anonymous"
   )
-  echo("Found ", before - supportLevels.elems.len, " sponsors that cancelled or didn't pay.")
-  echo("Found ", supportLevels.elems.len, " active sponsors!")
+  echo("Discarded ", before - supporters.elems.len, " anonymous sponsors.")
+  echo("Found ", supporters.elems.len, " named sponsors.")
 
-  supportLevels.elems.sort(
-    (x, y) => cmp(y["amount"].getFNum, x["amount"].getFNum)
+  supporters.elems.sort(
+    (x, y) => cmp(y["alltime_amount"].getFNum, x["alltime_amount"].getFNum)
   )
 
-proc getSupporter(supporters: JsonNode, displayName: string): JsonNode =
-  for supporter in supporters:
-    if supporter["display_name"].getStr == displayName:
-      return supporter
-  doAssert false
 
 proc quote(text: string): string =
   if {' ', ','} in text:
@@ -81,7 +70,7 @@ proc getLevel(amount: float): int =
     if amount.int <= i:
       result = i
 
-proc writeCsv(sponsors: seq[Sponsor]) =
+proc writeCsv(sponsors: seq[Sponsor], filename="sponsors.new.csv") =
   var csv = ""
   csv.add "logo, name, url, this_month, all_time, since, level\n"
   for sponsor in sponsors:
@@ -91,7 +80,8 @@ proc writeCsv(sponsors: seq[Sponsor]) =
       $sponsor.allTime.int, sponsor.since.format("MMM d, yyyy").quote,
       $sponsor.amount.getLevel
     ]
-  writeFile("sponsors.new.csv", csv)
+  writeFile(filename, csv)
+  echo("Written csv file to ", filename)
 
 when isMainModule:
   if paramCount() == 0:
@@ -105,14 +95,13 @@ when isMainModule:
 
   echo("Getting sponsors...")
   let supporters = waitFor bountysource.getSupporters()
-
-  var supportLevels = waitFor bountysource.getSupportLevels()
-  processLevels(supportLevels)
+  processSupporters(supporters)
 
   echo("Generating sponsors list... (please be patient)")
-  var sponsors: seq[Sponsor] = @[]
-  for supportLevel in supportLevels:
-    let name = supportLevel["owner"]["display_name"].getStr
+  var activeSponsors: seq[Sponsor] = @[]
+  var inactiveSponsors: seq[Sponsor] = @[]
+  for supporter in supporters:
+    let name = supporter["display_name"].getStr
     var url = ""
     let ghUser = waitFor getGithubUser(name)
     if not ghUser.isNil:
@@ -124,21 +113,28 @@ when isMainModule:
     if url.len > 0 and not url.startsWith("http"):
       url = "http://" & url
 
-    let amount = supportLevel["amount"].getFNum
+    let amount = supporter["monthly_amount"].getFNum()
     # Only show URL when user donated at least $5.
     if amount < 5:
       url = ""
 
-    let supporter = getSupporter(supporters, supportLevel["owner"]["display_name"].getStr)
+    #let supporter = getSupporter(supporters,
+    #                             supportLevel["owner"]["display_name"].getStr)
+    #if supporter.isNil: continue
     var logo = ""
     if amount >= 75:
       discard # TODO
 
-    sponsors.add(Sponsor(name: name, url: url, logo: logo, amount: amount,
-      allTime: supporter["alltime_amount"].getFNum(),
-      since: parse(supporter["created_at"].getStr, "yyyy-MM-dd'T'hh:mm:ss")
-    ))
-
-  echo("Generated ", sponsors.len, " sponsors")
-  writeCsv(sponsors)
-  echo("Written csv file to sponsors.new.csv")
+    let sponsor = Sponsor(name: name, url: url, logo: logo, amount: amount,
+        allTime: supporter["alltime_amount"].getFNum(),
+        since: parse(supporter["created_at"].getStr, "yyyy-MM-dd'T'hh:mm:ss")
+      )
+    if supporter["monthly_amount"].getFNum > 0.0:
+      activeSponsors.add(sponsor)
+    else:
+      inactiveSponsors.add(sponsor)
+
+  echo("Generated ", activeSponsors.len, " active sponsors")
+  echo("Generated ", inactiveSponsors.len, " inactive sponsors")
+  writeCsv(activeSponsors)
+  writeCsv(inactiveSponsors, "inactive_sponsors.new.csv")
diff --git a/web/inactive_sponsors.csv b/web/inactive_sponsors.csv
new file mode 100644
index 000000000..929882ff4
--- /dev/null
+++ b/web/inactive_sponsors.csv
@@ -0,0 +1,44 @@
+logo, name, url, this_month, all_time, since, level
+,mikra,,0,400,"Apr 28, 2016",1
+,linkmonitor,,0,180,"Jan 28, 2016",1
+,"Benny Luypaert",,0,100,"Apr 10, 2016",1
+,"Chris Heller",,0,100,"May 19, 2016",1
+,PhilipWitte,,0,100,"Aug 5, 2016",1
+,Boxifier,,0,75,"Apr 12, 2016",1
+,iolloyd,,0,75,"Apr 29, 2016",1
+,WilRubin,,0,50,"Aug 11, 2015",1
+,rb01,,0,50,"May 4, 2016",1
+,TedSinger,,0,45,"Apr 9, 2016",1
+,martinbbjerregaard,,0,35,"Jun 9, 2016",1
+,benbve,,0,30,"Jul 12, 2016",1
+,barcharcraz,,0,25,"Jun 2, 2016",1
+,"Landon Bass",,0,25,"Jun 7, 2016",1
+,jimrichards,,0,25,"Jun 8, 2016",1
+,jjzazuet,,0,25,"Jul 10, 2016",1
+,zolern,,0,20,"Apr 15, 2016",1
+,mirek,,0,15,"Apr 9, 2016",1
+,rickc,,0,15,"Jul 31, 2016",1
+,jpkx1984,,0,13,"Jul 11, 2016",1
+,vlkrav,,0,12,"Aug 9, 2015",1
+,tebanep,,0,12,"Aug 7, 2016",1
+,McSpiros,,0,10,"Apr 6, 2016",1
+,"Brandon Hunter",,0,10,"Apr 7, 2016",1
+,funny-falcon,,0,10,"Apr 7, 2016",1
+,teroz,,0,10,"Apr 8, 2016",1
+,iLikeLego,,0,10,"Apr 16, 2016",1
+,Angluca,,0,10,"May 3, 2016",1
+,calind,,0,10,"Jun 7, 2016",1
+,goldenreign,,0,10,"Jun 10, 2016",1
+,kteza1,,0,10,"Jun 10, 2016",1
+,cinnabardk,,0,10,"Aug 6, 2016",1
+,reddec,,0,10,"Aug 31, 2016",1
+,niv,,0,5,"Apr 6, 2016",1
+,goniz,,0,5,"Apr 7, 2016",1
+,genunix,,0,5,"Apr 12, 2016",1
+,CynepHy6,,0,5,"Apr 14, 2016",1
+,ivanflorentin,,0,5,"May 3, 2016",1
+,stevenyhw,,0,5,"May 20, 2016",1
+,"Sanjay Singh",,0,5,"Jun 6, 2016",1
+,yuttie,,0,5,"Jun 7, 2016",1
+,hron,,0,5,"Jun 11, 2016",1
+,laszlowaty,,0,5,"Jun 17, 2016",1
diff --git a/web/news.rst b/web/news.rst
index 95822a459..2b43034cc 100644
--- a/web/news.rst
+++ b/web/news.rst
@@ -2,6 +2,9 @@
 News
 ====
 
+`2016-09-03 Nim Community Survey results <news/2016_09_03_nim_community_survey_results.html>`_
+===================================
+
 `2016-08-06 BountySource Update: The Road to v1.0 <news/2016_08_06_bountysource_update_the_road_to_v10.html>`_
 ===================================
 
diff --git a/web/news/2016_09_03_nim_community_survey_results.rst b/web/news/2016_09_03_nim_community_survey_results.rst
new file mode 100644
index 000000000..106dce0e4
--- /dev/null
+++ b/web/news/2016_09_03_nim_community_survey_results.rst
@@ -0,0 +1,699 @@
+Nim Community Survey Results
+============================
+
+.. container:: metadata
+
+  Posted by Dominik Picheta on 3 September 2016
+
+We have recently closed the 2016 Nim Community Survey. I am happy to
+say that we have received exactly 790 responses, huge thanks go to the people
+that took the time to respond. We're incredibly thankful for this very valuable
+feedback.
+
+This survey was inspired in part by the
+`2016 State of Rust <https://blog.rust-lang.org/2016/06/30/State-of-Rust-Survey-2016.html>`_
+survey. You will note that many of the questions were modelled after
+Rust's survey. One of the reasons for doing this was to allow us to easily
+compare our results against the results obtained in the Rust survey. In
+addition, we of course also liked many of their questions.
+
+Our survey ran from the 23rd of June 2016 until the 8th of August 2016. The
+response numbers are impressive considering Nim's community size; at 790 they
+make up just over 25% of the Rust survey's responses.
+
+The goal of this survey was to primarily determine how our community is using
+Nim, in order to better understand how we should be improving it. In particular,
+we wanted to know what people feel is missing from Nim in the lead up to
+version 1.0. We have also asked our respondents about how well the Nim tools
+worked, the challenges of adopting Nim, the resources that they used to learn
+Nim and more.
+
+It is my hope that we will be able to run a similar survey in a years time,
+doing so should give us an idea of whether we are improving.
+With these general facts in mind, let's begin looking at specific questions.
+
+How did you find out about Nim?
+-------------------------------
+
+The rationale for the first question was simple, we wanted to know where our
+respondents found out about Nim. This is an interesting question for us, as
+we do occassionally get users asking us why it took so long for them to hear
+about Nim. It allows us to see how effective each website is at spreading the
+word about Nim.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/nim_found.png">
+    <img src="../assets/news/images/survey/nim_found.png" alt="How did you find out about Nim?" style="width:100%"/>
+  </a>
+
+The majority of our respondents found Nim via Reddit, HackerNews or a search
+engine such as Google. These results are not altogether surprising. There were
+also a lot of "Other" responses, some of which were a bit more
+interesting. These included multiple mentions of habrahabr.ru, Dr. Dobb's,
+and lobste.rs.
+
+Do you use Nim?
+---------------
+
+Just like the Rust survey creators, we wanted to ensure that our survey was
+open to both Nim users as well people who never used Nim. In addition to
+those two groups, we have also included a third group of people: ex-Nim
+users. All three are interesting, for many different reasons.
+Nim users can tell us how they are using Nim and also how Nim's
+tooling can improve. Ex-Nim users give us an
+idea of why they stopped using Nim. Finally, respondents who never used Nim
+can tell us the reasons for not adopting it.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/do_you_use_nim.png">
+    <img src="../assets/news/images/survey/do_you_use_nim.png" alt="Do you use Nim?" style="width:100%"/>
+  </a>
+
+It's nice to see that we have such a good range of respondents. The Rust survey
+had a much larger number of Rust users amongst their respondents, with
+no distinction between users that never used Rust and users that stopped using
+Rust.
+
+Should we consider your answers to be invalid?
+----------------------------------------------
+
+This was something I thought would be interesting to have, after I saw it
+being used in another survey. While it does pinpoint possibly
+invalid respondents, I have opted against filtering those out. Mainly because
+that would require re-creating each of the charts generated by Google Forms
+manually.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/reliability.png">
+    <img src="../assets/news/images/survey/reliability.png" alt="Should we consider your answers to be invalid?" style="width:100%"/>
+  </a>
+
+According to the responses to this question, around 94% of our responses
+can be considered reliable.
+
+Nim users
+---------
+
+The following questions were answered only by the 38.9% of our respondents
+who identified themselves as Nim users.
+
+How long have you been using Nim?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/nim_time.png">
+    <img src="../assets/news/images/survey/nim_time.png" alt="How long have you been using Nim?" style="width:100%"/>
+  </a>
+
+A large proportion of our Nim users were new. This is good news as it means that
+our community is growing, with a large proportion of new Nim users that could
+become long-term Nimians. In total, more than 35% of Nim users can be considered
+new having used Nim for less than 3 months. With 18% of Nim users that can
+be considered very new having used Nim for less than a month.
+This could suggest that 18% of our users have only just found out about Nim in
+the last week or so and have not yet got the chance to use it extensively.
+
+The high percentages of long term Nim users are encouraging.
+They suggest
+that many users are continuing to use Nim after making it through the first
+few months. The sharp drop at 7-9 months is interesting, but may simply be
+due to the fact that there were fewer newcomers during that period, or it
+could be because our respondents are more likely to estimate that they have
+been using Nim for a year or half a year rather than the awkward 7-9 months.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/nim_time_rust.png">
+    <img src="../assets/news/images/survey/nim_time_rust.png" alt="Time using Nim and Rust" style="width:100%"/>
+  </a>
+
+The results for Nim and Rust are actually remarkably similar. They both show a
+drop at 7-9 months, although Rust's isn't as dramatic. Nim on the other hand
+has a significantly higher percentage of new Nim users.
+
+Do you use Nim at work?
+~~~~~~~~~~~~~~~~~~~~~~~
+
+An important aspect of a language's adoption is whether it is being used for
+"real" work. We wanted to know how many people are using Nim in their day
+jobs and under what circumstances it is used.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/nim_at_work.png">
+    <img src="../assets/news/images/survey/nim_at_work.png" alt="Do you use Nim at work?" style="width:100%"/>
+  </a>
+
+While a vast majority of our users are not using Nim at work, more than 25%
+of them are. It's encouraging to see such a high number already, even before
+we have released version 1.0. In fact, this percentage is likely close to 30%,
+because many of the "Other" responses mention using Nim for the likes of
+internal tools or small scripts to help with the respondent's work.
+
+.. raw::html
+
+  <a href="https://blog.rust-lang.org/images/2016-06-Survey/rust_at_work.png">
+    <img src="https://blog.rust-lang.org/images/2016-06-Survey/rust_at_work.png" alt="Do you use Rust at work?" style="width:100%"/>
+  </a>
+
+Interestingly, a larger percentage of Nim users are using Nim at work than
+Rust users. The sample sizes are of course vastly different, but it's still an
+interesting result. Combined, nearly 1/5th of Rust users are using Rust
+commercially whereas more than a quarter of Nim users are using Nim
+commercially.
+
+Approximately how large are all the Nim projects that you work on?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Finding out how large the Nim projects worked on by Nim users are is also
+very valuable.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/project_size.png">
+    <img src="../assets/news/images/survey/project_size.png" alt="Nim project size for all users" style="width:100%"/>
+  </a>
+
+This shows us that currently Nim is primarily being used for small scripts and
+applications, with nearly 60% of the projects consisting of less than 1,000
+lines of code. This makes sense as many of our users are not using Nim
+professionally, but are doing so in their spare time.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/project_size_work.png">
+    <img src="../assets/news/images/survey/project_size_work.png" alt="Nim project size for work users" style="width:100%"/>
+  </a>
+
+The numbers for part-time and full-time work users of Nim tell a different
+story. Over 70% of the projects written by full-time users are between 10,001
+and 100,000 lines of code. Part-time users show a slightly different trend,
+with many more small projects, the majority being between 1,000 and
+10,000 lines of code.
+
+Overall it's good to see that there is a few large projects out there which are
+composed of more than 100,000 lines of code. We expect to see the amount of
+large projects to grow with time, especially with version 1.0 on the way.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/project_size_nim_rust.png">
+    <img src="../assets/news/images/survey/project_size_nim_rust.png" alt="Nim project size for work users (Nim vs. Rust)" style="width:100%"/>
+  </a>
+
+In comparison to Rust the proportion of project sizes for full-time users is
+vastly different. This is likely due to our small sample size. Project sizes for
+part-time users between Rust and Nim are somewhat similar, with differences of
+around 10% for each project size.
+
+Do you plan to try to use Nim at work?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/planning_to_use_at_work.png">
+    <img src="../assets/news/images/survey/planning_to_use_at_work.png" alt="Planning to use Nim at work?" style="width:100%"/>
+  </a>
+
+It's also encouraging to see that over 50% of Nim users are planning to use
+Nim at work! This is slightly more than Rust's 40% and should help Nim's
+adoption into even more areas.
+
+Nim and its tools
+~~~~~~~~~~~~~~~~~
+
+In this section of the survey, we wanted to find out the tools that Nim
+users are utilising when developing Nim applications.
+
+What editor(s) do you use when writing Nim?
+___________________________________________
+
+Programmers are very specific when it comes to their editor of choice, because
+of that it's good to know which editor is most popular among our community.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/editors.png">
+    <img src="../assets/news/images/survey/editors.png" alt="Editors used by Nim users" style="width:100%"/>
+  </a>
+
+Looks like Vim is the winner with almost 30%. Followed by Sublime Text and
+Emacs. Aporia, the Nim IDE, gets a respectable 15.5%. There was
+also more than
+17% of answers which included "Other" editors, such as: Notepad++, Geany, gedit,
+and Kate.
+
+What operating system(s) do you compile for and run your Nim projects on?
+_________________________________________________________________________
+
+This question gave us information about the most popular target operating
+systems, as well as some of the more obscure ones. We have asked this question
+to find out the platforms on which Nim applications run on most frequently.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/target_os.png">
+    <img src="../assets/news/images/survey/target_os.png" alt="Target operating systems" style="width:100%"/>
+  </a>
+
+This question allowed multiple choices, so each percentage is out of the total
+number of respondents for this question. For example, 80.7% of the
+respondents selected "Linux" but only 26.6% selected OS X.
+
+This makes Linux by far the most popular target for Nim applications.
+Some "Other" targets included: BSD (OpenBSD, FreeBSD), iOS, Android, and
+JavaScript.
+It's great to see Nim being used on such a wide variety of platforms.
+
+What operating system(s) do you develop Nim projects on?
+________________________________________________________
+
+With this question, we wanted to know what operating systems are used for
+development.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/dev_os.png">
+    <img src="../assets/news/images/survey/dev_os.png" alt="Development operating systems" style="width:100%"/>
+  </a>
+
+This question also allowed multiple choices and ended up with very similar
+results.
+
+You can see that Linux is also the most popular developmental
+platform for Nim. But it's more popular as a target platform.
+
+Which version(s) of Nim do you use for your applications?
+_________________________________________________________
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/nim_versions.png">
+    <img src="../assets/news/images/survey/nim_versions.png" alt="Version use" style="width:100%"/>
+  </a>
+
+At the time of this survey, version 0.14.2 was the latest stable release.
+It's no wonder that it is the most commonly used release of Nim. It's good to
+see that the older versions are not used as often. The high use of ``Git HEAD (devel)``
+(nightly builds) isn't surprising, Nim is still evolving rapidly and our
+release schedule is not regular or frequent.
+
+Once we go past the 1.0 release, we expect to see much less use of the unstable
+``devel`` branch.
+
+Has upgrading to a new version of the Nim compiler broken your code?
+____________________________________________________________________
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/breakage.png">
+    <img src="../assets/news/images/survey/breakage.png" alt="Breakage" style="width:100%"/>
+  </a>
+
+Despite the unstable nature of Nim in the lead up to version 1.0, whenever
+we make breaking changes we do our best to deprecate things and ensure that
+old code continues to work for our users. Of course sometimes this is not
+possible and other times it is simply easier to add a breaking change.
+
+This question was asked to determine how much our user base is affected by
+breaking changes between Nim versions. We decided to have three possible
+answers for this question in order to give us an idea how frequent the
+breakage was.
+
+It's incredible to see that over 50% of our users have not experienced any
+breakage after upgrading. We expect this number to increase significantly
+after version 1.0 is released. Of the users that did experience breakage,
+over 80% of them said that it was a rare occurrence.
+
+In comparison to Rust, our results show that there was a higher percentage of
+users experiencing breakage as a result of an upgrade. This is to be expected,
+because Nim is still in its pre-1.0 period, whereas Rust 1.0 has been released
+over a year ago now.
+
+Unfortunately while we are still in this pre-1.0 period, releases will likely
+introduce breaking changes as we refine certain aspects of Nim such as its
+standard library, so the number of users experiencing breaking changes may
+increase.
+
+If so, how much work did it take to fix it?
+___________________________________________
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/difficulty_fixing_breakage.png">
+    <img src="../assets/news/images/survey/difficulty_fixing_breakage.png" alt="difficulty fixing breakage" style="width:100%"/>
+  </a>
+
+Thankfully most of the breakage experienced by Nim users was very easy to fix.
+
+
+If you used Nimble, do you like it?
+___________________________________
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/nimble_opinion.png">
+    <img src="../assets/news/images/survey/nimble_opinion.png" alt="Do you like Nimble?" style="width:100%"/>
+  </a>
+
+Nimble is the Nim package manager, a tool that is very important in Nim's
+ecosystem as it allows developers to easily install dependencies for their
+software.
+
+The majority of respondents rated it as a 4, showing us that the majority does
+like Nimble. With over 55% rating it a 4 or 5. This percentage isn't as
+overwhelming as the 94.1% of users that rated Cargo a 4 or 5 in the Rust
+survey. Based on these results I think that we definitely need to do a
+better job with Nimble.
+
+In our next survey, it might be a good idea to ask more questions about Nimble
+to determine how exactly it can be improved.
+
+What aspects of Nim do you find most appealing?
+_______________________________________________
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/nim_appeal.png">
+    <img src="../assets/news/images/survey/nim_appeal.png" alt="What aspects of Nim do you find most appealing?" style="width:100%"/>
+  </a>
+
+We were interested to know the features of Nim that appeal most to our users.
+More than 80% of our respondents selected "Execution Speed" as one of the
+features that appeal to them. With "Development Speed" and "Readability"
+tying for second place and "Metaprogramming" at third place.
+
+The options given to our respondents are rather predictable,
+they do show us which of these features have the highest appeal though.
+What's more interesting are the "Other" answers.
+
+By far the most popular "Other" answer was related to Nim's compilation to C.
+Many users mentioned that they like how easy it is to interface with C
+libraries and the great portability that compiling to C offers.
+
+What aspects of Nim do you find most displeasing?
+_________________________________________________
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/nim_displeasing.png">
+    <img src="../assets/news/images/survey/nim_displeasing.png" alt="What aspects of Nim do you find most displeasing?" style="width:100%"/>
+  </a>
+
+It was only natural to ask this question. The results are almost perfectly
+opposite to the previous question's answers, with almost 50% of respondents
+selecting "Debugging Tools"
+as the most displeasing aspect of Nim. With "Documentation" and "Testing Tools"
+in second and third place respectively. There is also a much larger number of
+"Other" answers to this question.
+
+The "Other" answers for this question vary a lot. Here is a selection of
+them, ordered by frequency:
+
+* Small community size.
+* Lack of in-depth tutorials.
+* Quality of error messages.
+* Forward declarations and no cyclic imports.
+* Bugs in the standard library.
+* No good IDE.
+* No REPL.
+* No major version.
+* Bugs in the compiler.
+* Lack of libraries.
+* Difficulty installing on Windows.
+* Non-intuitive semantics of various constructs.
+* Lack of immutable collections.
+* Async/await not being production ready.
+* Lack of shared collections for threads.
+* No Haxe target.
+* Memory safety.
+
+We hope that we can improve these things with time. Many of these issues are
+already being worked on, including the removal of the need for forward
+declarations. Some of these issues like our small community size are difficult
+to fix, but we will nonetheless do our best.
+
+
+Previous Nim users
+~~~~~~~~~~~~~~~~~~
+
+For users that have used Nim before but decided against using it, we asked just
+one specific question. The proportion of our respondents that answered it
+was 24%.
+
+Why did you stop using Nim?
+___________________________
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/ex_nim.png">
+    <img src="../assets/news/images/survey/ex_nim.png" alt="I stopped using Nim because..." style="width:100%"/>
+  </a>
+
+Again, this question got a lot of "Other" answers. Apart from that, the
+most popular reason for leaving Nim is that it is not stable. Followed by the
+a lack of needed libraries and packages and the instability of the
+standard library.
+
+* Lack of IDE support.
+* Style insensitive.
+* Documentation.
+* Dislike the syntax.
+* Community is too small.
+* Missing language features (for example RAII).
+* No opportunities to use it at work.
+* Messy standard library.
+
+The first item, "Lack of IDE support", was mentioned by multiple respondents.
+In the future we should look into ensuring that major IDEs have plugins which
+enable easy Nim development.
+
+Based on some of the "Other" answers, it seems that many of the respondents
+have not used Nim for very long, for example many respondents complained about
+installation issues which they would have run into before getting a chance to
+use Nim. Because of this I would consider them not
+ex-Nim users but developers that have not had a chance to try Nim fully.
+Next time we should also ask how long the respondent has used Nim for to get a
+better idea of whether they had a chance to use Nim for extended periods of
+time.
+
+Non-Nim users
+~~~~~~~~~~~~~
+
+We also wanted to know the reasons why developers decided against using Nim.
+
+Why do you not use Nim?
+_______________________
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/non_user.png">
+    <img src="../assets/news/images/survey/non_user.png" alt="I don't use Nim because..." style="width:100%"/>
+  </a>
+
+The most common reason that people have for not using Nim is that it is
+not yet ready for production. Thankfully this will improve with time.
+IDE support is also a prominent factor just as we've seen in previous results.
+
+There is also a lot of "Other" answers, let's have a look at a selection of
+them. Some of the most prominent ones, in order of frequency, include:
+
+* No time to use/learn it
+* Syntax
+* Documentation is incomplete
+* Garbage Collection
+* Prefer functional paradigm
+* Small community
+* Style insensitivity/Case insensitivity
+
+One respondent made a very good suggestion: they said that the
+"Do you use Nim?" question should have included "No, but I intend to" as
+an answer. Definitely something we will do in the next survey. Indeed, many
+respondents mentioned that they were planning on trying out Nim but that they
+just have no time to do so, this is very encouraging!
+
+Learning Resources
+~~~~~~~~~~~~~~~~~~
+
+We wanted to get an idea of how Nim users are learning Nim. Every respondent
+answered this question, no matter what they answered for the "Do you use Nim?"
+question.
+
+Which learning resources, if any, did you use to learn Nim?
+___________________________________________________________
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/learning_resources.png">
+    <img src="../assets/news/images/survey/learning_resources.png" alt="learning resources" style="width:100%"/>
+  </a>
+
+The idea behind this question was to understand which learning resources
+were most popular among our user base. The
+`Nim tutorial <http://nim-lang.org/docs/tut1.html>`_ is by far the most
+popular. In previous questions, we saw respondents mentioning that the Nim
+tutorial does not go into enough detail about Nim. Thanks to this information
+we can come to the conclusion that the tutorial needs to be improved
+significantly to make sure that it gives our users the necessary information
+to use Nim effectively.
+
+Indeed, many users also use the
+`Nim manual <http://nim-lang.org/docs/manual.html>`_ to learn Nim.
+This manual has been
+written as a specification and so is not ideal for teaching Nim. Many of
+the concepts in the Nim manual need to be explained in a lot more detail in
+the Nim tutorial.
+
+Of course, it's exciting to see our respondents using other materials to learn
+Nim. In particular I am excited to see that over 15% of the respondents have
+used
+`Nim in Action <https://manning.com/books/nim-in-action?a_aid=niminaction&a_bid=78a27e81>`_
+to learn Nim. I expect that more and more users will pick up the book after it
+is fully published.
+
+Nim in Action
+_____________
+
+As the author of
+`Nim in Action <https://manning.com/books/nim-in-action?a_aid=niminaction&a_bid=78a27e81>`_,
+I wanted to get some statistics surrounding
+my book. With this in mind, I have created some questions relating to it.
+
+Have you read Nim in Action?
+____________________________
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/book.png">
+    <img src="../assets/news/images/survey/book.png" alt="Have you read Nim in Action?" style="width:100%"/>
+  </a>
+
+It's good to see that over 50% of respondents have read the book or are at least
+planning to read it. Keep in mind that this question was answered by all
+respondents, not just Nim users.
+
+.. container:: standout
+
+  Are you interested in purchasing a copy of
+  `Nim in Action <https://manning.com/books/nim-in-action?a_aid=niminaction&a_bid=78a27e81>`_?
+  If so, you can use code ``wm090416lt`` to get 50% off the printed book today only!
+  If you purchase it now you will get access to an early access copy of
+  Nim in Action in eBook form and will be able to take part in the development
+  of this book.
+
+Did you enjoy Nim in Action?
+____________________________
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/book_opinion.png">
+    <img src="../assets/news/images/survey/book_opinion.png" alt="Did you enjoy Nim in Action?" style="width:100%"/>
+  </a>
+
+Of the people that read Nim in Action it's nice to see that almost 70% have
+enjoyed it.
+
+Nim's future
+~~~~~~~~~~~~
+
+What improvements are needed before Nim v1.0 can be released?
+_____________________________________________________________
+
+We were interested to know what our users believe is needed before
+Nim version 1.0 can be released.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/10_needs.png">
+    <img src="../assets/news/images/survey/10_needs.png" alt="What is needed before 1.0 can be released?" style="width:100%"/>
+  </a>
+
+It appears that the standard library is the biggest concern. With more than half
+of all respondents selecting "The standard library needs to reviewed and
+any problems with it fixed". This is in fact something we are already planning
+to address, so it's good to see that the majority agrees with us.
+
+A large proportion of users also believes that the language is great as-is
+and that we should focus on stabilising the compiler. This somewhat contradicts
+the majority. But perhaps most of them thought that "The language" excludes the
+standard library.
+
+For this question, we decided to give our respondents a dedicated place to
+give general feedback about what they feel is needed before v1.0 can be
+released. We received over 200 responses to that. Many of these responses
+reflect what we have already seen: that the documentation needs to improve,
+that we need a good Nim IDE, stability for experimental features such as
+concepts, the standard library needs to be cleaned up.
+
+Unfortunately many respondents used this question to say what needs to be fixed
+in Nim in general, not what is definitely necessary before 1.0 can be released.
+
+Community demographics
+~~~~~~~~~~~~~~~~~~~~~~
+
+What domain do you work in currently?
+_____________________________________
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/domains.png">
+    <img src="../assets/news/images/survey/domains.png" alt="Work domains" style="width:100%"/>
+  </a>
+
+
+Nim users are working in a wide variety of domains. It is encouraging to see
+people from so many different backgrounds taking part in this survey.
+
+What programming languages are you most comfortable with?
+_________________________________________________________
+
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/languages.png">
+    <img src="../assets/news/images/survey/languages.png" alt="Programming languages" style="width:100%"/>
+  </a>
+
+Python and C are the top two programming languages that our respondents are
+most comfortable with. This is not altogether surprising.
+
+Last words
+~~~~~~~~~~
+
+At the end of the survey we gave our respondents a chance to speak their mind
+about anything they wish, with a simple question: "Anything else you'd like
+to tell us?"
+
+There was a lot of great feedback given in this question from people who
+obviously really care deeply about Nim. There is too much to outline here,
+but rest assurred that we will take it all into account and do our best to
+act on it.
+
+In addition to feedback, we were also overwhelmed by the amount of positive
+comments in the answers to this
+question. There was a lot of support from the community thanking us for our
+work and determination.
+
+I'll let some quotes speak for themselves:
+
+.. raw::html
+
+  <blockquote>You rock, seriously.</blockquote>
+  <blockquote>Nim rocks! Keep it up! Thank you very much!</blockquote>
+  <blockquote>You've made great progress on the language without any corporate backing, that is amazing. I wish Nim becomes one of the top used languages in a few years.</blockquote>
+  <blockquote>Nim is elegant and wonderful! Keep at it!</blockquote>
+
+Our community is truly brilliant. We thank each and every one of you for
+filling out this survey and hope that you will help us tackle some of the
+challenges that face Nim.
+
+This survey was a good place to give us feedback, but please don't wait for
+the next one. We are always looking to hear more from you and we hope that you
+will participate in discussions relating to this survey as well the future
+of Nim.
+
+Thanks for reading, and have a good day!
diff --git a/web/news/nim_community_survey_results.rst b/web/news/nim_community_survey_results.rst
deleted file mode 100644
index 49656f20a..000000000
--- a/web/news/nim_community_survey_results.rst
+++ /dev/null
@@ -1,317 +0,0 @@
-Nim Community Survey Results
-============================
-
-.. container:: metadata
-
-  Posted by Dominik Picheta on 20/08/2016
-
-We have recently closed the 2016 Nim Community Survey. I am happy to
-say that we have received exactly 790 responses, huge thanks go to the people
-that took the time to respond. We're very thankful for this very valuable
-feedback.
-
-This survey was inspired in part by the
-`2016 State of Rust <https://blog.rust-lang.org/2016/06/30/State-of-Rust-Survey-2016.html>`_
-survey. You will note that many of the questions were modelled after
-Rust's survey. One of the reasons for doing this was to allow us to easily
-compare our results against the results obtained in the Rust survey. In
-addition, we of course also liked many of their questions.
-
-Our survey ran from the 23rd of June 2016 until the 8th of August 2016. The
-response numbers are impressive considering Nim's community size; at 790 they
-make up just over 25% of the Rust survey's responses.
-
-The goal of this survey was to primarily determine how our community is using
-Nim, in order to better understand how we should be improving it. In particular,
-we wanted to know what people feel is missing from Nim in the lead up to
-version 1.0. We have also asked our respondents about how well the Nim tools
-worked, the challenges of adopting Nim, the resources that they used to learn
-Nim and more.
-
-It is my hope that we will be able to run a similar survey in a years time,
-doing so should give us an idea of whether we are improving.
-With these general facts in mind, let's begin looking at specific questions.
-
-How did you find out about Nim?
--------------------------------
-
-The rationale for the first question was simple, we wanted to know where our
-respondents found out about Nim. This is an interesting question for us, as
-we do occassionally get users asking us why it took so long for them to hear
-about Nim. It allows us to see how effective each website is at spreading the
-word about Nim.
-
-.. raw::html
-
-  <a href="../assets/news/images/survey/nim_found.png">
-    <img src="../assets/news/images/survey/nim_found.png" alt="How did you find out about Nim?" style="width:100%"/>
-  </a>
-
-The majority of our respondents found Nim via Reddit, HackerNews or a search
-engine such as Google. These results are not altogether surprising. There were
-also a lot of "Other" responses, some of which were a bit more
-interesting. These included multiple mentions of habrahabr.ru, Dr. Dobb's,
-and lobste.rs.
-
-Do you use Nim?
----------------
-
-Just like the Rust survey creators, we wanted to ensure that our survey was
-open to both Nim users as well people who never used Nim. In addition to
-those two groups, we have also included a third group of people: ex-Nim
-users. All three are interesting, for many different reasons.
-Nim users can tell us how they are using Nim and also how Nim's
-tooling can improve. Ex-Nim users give us an
-idea of why they stopped using Nim. Finally, respondents who never used Nim
-can tell us the reasons for not adopting it.
-
-.. raw::html
-
-  <a href="../assets/news/images/survey/do_you_use_nim.png">
-    <img src="../assets/news/images/survey/do_you_use_nim.png" alt="Do you use Nim?" style="width:100%"/>
-  </a>
-
-It's nice to see that we have such a good range of respondents. The Rust survey
-had a much larger number of Rust users amongst their respondents, with
-no distinction between users that never used Rust and users that stopped using
-Rust.
-
-.. raw::html
-
-  <a href="https://blog.rust-lang.org/images/2016-06-Survey/do_you_use_rust.png">
-    <img src="https://blog.rust-lang.org/images/2016-06-Survey/do_you_use_rust.png" alt="Do you use Rust?" style="width:100%"/>
-  </a>
-
-Should we consider your answers to be invalid?
-----------------------------------------------
-
-This was something I thought would be interesting to have, after I saw it
-being used in another survey. While it does pinpoint possibly
-invalid respondents, I have opted against filtering those out. Mainly because
-that would require re-creating each of the charts generated by Google Forms
-manually.
-
-.. raw::html
-
-  <a href="../assets/news/images/survey/reliability.png">
-    <img src="../assets/news/images/survey/reliability.png" alt="Should we consider your answers to be invalid?" style="width:100%"/>
-  </a>
-
-According to the responses to this question, around 94% of our responses
-can be considered reliable.
-
-Nim users
----------
-
-The following questions were answered only by the 38.9% of our respondents
-who identified themselves as Nim users.
-
-How long have you been using Nim?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. raw::html
-
-  <a href="../assets/news/images/survey/nim_time.png">
-    <img src="../assets/news/images/survey/nim_time.png" alt="How long have you been using Nim?" style="width:100%"/>
-  </a>
-
-A large proportion of our Nim users were new. This is good news as it means that
-our community is growing, with a large proportion of new Nim users that could
-become long-term Nimians. In total, more than 35% of Nim users can be considered
-new having used Nim for less than 3 months. With 18% of Nim users that can
-be considered very new having used Nim for less than a month.
-This could suggest that 18% of our users have only just found out about Nim in
-the last week or so and have not yet got the chance to use it extensively.
-
-The high percentages of long term Nim users are encouraging.
-They suggest
-that many users are continuing to use Nim after making it through the first
-few months. The sharp drop at 7-9 months is interesting, but may simply be
-due to the fact that there were fewer newcomers during that period, or it
-could be because our respondents are more likely to estimate that they have
-been using Nim for a year or half a year rather than the awkward 7-9 months.
-
-.. raw::html
-
-  <a href="../assets/news/images/survey/nim_time_rust.png">
-    <img src="../assets/news/images/survey/nim_time_rust.png" alt="Time using Nim and Rust" style="width:100%"/>
-  </a>
-
-The results for Nim and Rust are actually remarkably similar. They both show a
-drop at 7-9 months, although Rust's isn't as dramatic. Nim on the other hand
-has a significantly higher percentage of new Nim users.
-
-Do you use Nim at work?
-~~~~~~~~~~~~~~~~~~~~~~~
-
-An important aspect of a language's adoption is whether it is being used for
-"real" work. We wanted to know how many people are using Nim in their day
-jobs and under what circumstances it is used.
-
-.. raw::html
-
-  <a href="../assets/news/images/survey/nim_at_work.png">
-    <img src="../assets/news/images/survey/nim_at_work.png" alt="Do you use Nim at work?" style="width:100%"/>
-  </a>
-
-While a vast majority of our users are not using Nim at work, more than 25%
-of them are. It's encouraging to see such a high number already, even before
-we have released version 1.0. In fact, this percentage is likely close to 30%,
-because many of the "Other" responses mention using Nim for the likes of
-internal tools or small scripts to help with the respondent's work.
-
-.. raw::html
-
-  <a href="https://blog.rust-lang.org/images/2016-06-Survey/rust_at_work.png">
-    <img src="https://blog.rust-lang.org/images/2016-06-Survey/rust_at_work.png" alt="Do you use Rust at work?" style="width:100%"/>
-  </a>
-
-Interestingly, a larger percentage of Nim users are using Nim at work than
-Rust users. The sample sizes are of course vastly different, but it's still an
-interesting result. Combined, nearly 1/5th of Rust users are using Rust
-commercially whereas more than a quarter of Nim users are using Nim
-commercially.
-
-Approximately how large are all the Nim projects that you work on?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Finding out how large the Nim projects worked on by Nim users are is also
-very valuable.
-
-.. raw::html
-
-  <a href="../assets/news/images/survey/project_size.png">
-    <img src="../assets/news/images/survey/project_size.png" alt="Nim project size for all users" style="width:100%"/>
-  </a>
-
-This shows us that currently Nim is primarily being used for small scripts and
-applications, with nearly 60% of the projects consisting of less than 1,000
-lines of code. This makes sense as many of our users are not using Nim
-professionally, but are doing so in their spare time.
-
-.. raw::html
-
-  <a href="../assets/news/images/survey/project_size_work.png">
-    <img src="../assets/news/images/survey/project_size_work.png" alt="Nim project size for work users" style="width:100%"/>
-  </a>
-
-The numbers for part-time and full-time work users of Nim tell a different
-story. Over 70% of the projects written by full-time users are between 10,001
-and 100,000 lines of code. Part-time users show a slightly different trend,
-with many more small projects, the majority being between 1,000 and
-10,000 lines of code.
-
-Overall it's good to see that there is a few large projects out there which are
-composed of more than 100,000 lines of code. We expect to see the amount of
-large projects to grow with time, especially with version 1.0 on the way.
-
-.. raw::html
-
-  <a href="../assets/news/images/survey/project_size_nim_rust.png">
-    <img src="../assets/news/images/survey/project_size_nim_rust.png" alt="Nim project size for work users (Nim vs. Rust)" style="width:100%"/>
-  </a>
-
-In comparison to Rust the proportion of project sizes for full-time users is
-vastly different. This is likely due to our small sample size. Project sizes for
-part-time users between Rust and Nim are somewhat similar, with differences of
-around 10% for each project size.
-
-Do you plan to try to use Nim at work?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. raw::html
-
-  <a href="../assets/news/images/survey/planning_to_use_at_work.png">
-    <img src="../assets/news/images/survey/planning_to_use_at_work.png" alt="Planning to use Nim at work?" style="width:100%"/>
-  </a>
-
-It's also encouraging to see that over 50% of Nim users are planning to use
-Nim at work! This is slightly more than Rust's 40% and should help Nim's
-adoption into even more areas.
-
-Nim and its tools
-~~~~~~~~~~~~~~~~~
-
-In this section of the survey, we wanted to find out the tools that Nim
-users are utilising when developing Nim applications.
-
-What editor(s) do you use when writing Nim?
-___________________________________________
-
-Programmers are very specific when it comes to their editor of choice, because
-of that it's good to know which editor is most popular among our community.
-
-.. raw::html
-
-  <a href="../assets/news/images/survey/editors.png">
-    <img src="../assets/news/images/survey/editors.png" alt="Editors used by Nim users" style="width:100%"/>
-  </a>
-
-Looks like Vim is the winner with almost 30%. Followed by Sublime Text and
-Visual Studio Code. Aporia, the Nim IDE, gets a respectable 15.5%. There was
-also more than
-17% of answers which included "Other" editors, such as: Notepad++, Geany, gedit,
-and Kate.
-
-What operating system(s) do you compile for and run your Nim projects on?
-_________________________________________________________________________
-
-This question gave us information about the most popular target operating
-systems, as well as some of the more obscure ones. We have asked this question
-to find out the platforms on which Nim applications run on most frequently.
-
-.. raw::html
-
-  <a href="../assets/news/images/survey/target_os.png">
-    <img src="../assets/news/images/survey/target_os.png" alt="Target operating systems" style="width:100%"/>
-  </a>
-
-This question allowed multiple choices, so each percentage is out of the total
-number of respondents for this question. For example, 80.7% of the
-respondents selected "Linux" but only 26.6% selected OS X.
-
-This makes Linux by far the most popular target for Nim applications.
-Some "Other" targets included: BSD (OpenBSD, FreeBSD), iOS, Android, and
-JavaScript.
-It's great to see Nim being used on such a wide variety of platforms.
-
-What operating system(s) do you develop Nim projects on?
-________________________________________________________
-
-With this question, we wanted to know what operating systems are used for
-development.
-
-.. raw::html
-
-  <a href="../assets/news/images/survey/dev_os.png">
-    <img src="../assets/news/images/survey/dev_os.png" alt="Development operating systems" style="width:100%"/>
-  </a>
-
-This question also allowed multiple choices and ended up with very similar
-results.
-
-You can see that Linux is also the most popular developmental
-platform for Nim. But it's more popular as a target platform.
-
-Which version(s) of Nim do you use for your applications?
-_________________________________________________________
-
-.. raw::html
-
-  <a href="../assets/news/images/survey/nim_versions.png">
-    <img src="../assets/news/images/survey/nim_versions.png" alt="Version use" style="width:100%"/>
-  </a>
-
-At the time of this survey, version 0.14.2 was the latest stable release.
-It's no wonder that it is the most commonly used release of Nim. It's good to
-see that the older versions are not used as often. The high use of ``Git HEAD (devel)``
-(nightly builds) isn't surprising, Nim is still evolving rapidly and our
-release schedule is not regular or frequent.
-
-Once we go past the 1.0 release, we expect to see much less use of the unstable
-``devel`` branch.
-
-
-
-
-
diff --git a/web/sponsors.csv b/web/sponsors.csv
index ac35b284c..fe0261d17 100644
--- a/web/sponsors.csv
+++ b/web/sponsors.csv
@@ -1,31 +1,36 @@
 logo, name, url, this_month, all_time, since, level
-assets/bountysource/secondspectrum.png,Second Spectrum,http://www.secondspectrum.com/,250,750,"May 5, 2016",250
-assets/bountysource/xored.svg,"Xored Software, Inc.",http://xored.com/,250,500,"Jun 20, 2016",250
-,avsej,http://avsej.net,75,85,"Jun 10, 2016",75
-,shkolnick-kun,https://github.com/shkolnick-kun,75,75,"Jul 6, 2016",75
-,flyx,http://flyx.org,35,140,"Apr 7, 2016",75
-,endragor,https://github.com/endragor,25,100,"Apr 7, 2016",25
-,euantorano,http://euantorano.co.uk,25,50,"Jun 7, 2016",25
-,FedericoCeratto,http://firelet.net,25,100,"Apr 7, 2016",25
-,"Adrian Veith",,25,100,"Apr 20, 2016",25
-,xxlabaza,https://github.com/xxlabaza,25,45,"Jun 17, 2016",25
-,"Yuriy Glukhov",,25,100,"Apr 6, 2016",25
-,"Jonathan Arnett",,10,30,"May 20, 2016",10
-,"Oskari Timperi",,10,20,"Jun 8, 2016",10
-,zachaysan,http://venn.lc,10,20,"Jun 7, 2016",10
-,"Matthew Baulch",,10,20,"Jun 7, 2016",10
-,RationalG,https://github.com/RationalG,10,20,"Jun 17, 2016",10
-,btbytes,https://www.btbytes.com/,10,40,"Apr 6, 2016",10
-,niebaopeng,https://github.com/niebaopeng,10,30,"Apr 15, 2016",10
-,moigagoo,http://sloth-ci.com,5,15,"May 13, 2016",5
-,calind,http://calindon.net,5,10,"Jun 7, 2016",5
-,swalf,https://github.com/swalf,5,35,"May 9, 2016",5
-,johnnovak,http://www.johnnovak.net/,5,20,"Apr 29, 2016",5
-,RyanMarcus,http://rmarcus.info,5,5,"Jul 19, 2016",5
-,Blumenversand,https://blumenversender.com/,5,5,"Jul 21, 2016",5
-,lenzenmi,https://github.com/lenzenmi,5,5,"Jul 28, 2016",5
-,"Handojo Goenadi",,5,20,"Apr 19, 2016",5
-,"Date in Asia",,5,5,"Jul 30, 2016",5
-,"Matthew Newton",,5,20,"Apr 20, 2016",5
-,"Michael D. Sklaroff",,1,4,"Apr 27, 2016",1
-,"Svend Knudsen",,1,4,"Apr 11, 2016",1
+,bogen,https://github.com/bogen,250,1010,"Jul 23, 2016",250
+assets/bountysource/secondspectrum.png,Second Spectrum,http://www.secondspectrum.com/,250,1000,"May 5, 2016",250
+assets/bountysource/xored.svg,"Xored Software, Inc.",http://xored.com/,250,750,"Jun 20, 2016",250
+,flyx,http://flyx.org,35,175,"Apr 7, 2016",75
+,shkolnick-kun,https://github.com/shkolnick-kun,75,150,"Jul 6, 2016",75
+,"Yuriy Glukhov",,25,125,"Apr 6, 2016",25
+,endragor,https://github.com/endragor,25,125,"Apr 7, 2016",25
+,FedericoCeratto,http://firelet.net,25,125,"Apr 7, 2016",25
+,"Adrian Veith",,25,125,"Apr 20, 2016",25
+,avsej,http://avsej.net,25,110,"Jun 10, 2016",25
+,euantorano,http://euantorano.co.uk,25,75,"Jun 7, 2016",25
+,xxlabaza,https://github.com/xxlabaza,25,70,"Jun 17, 2016",25
+,btbytes,https://www.btbytes.com/,10,50,"Apr 6, 2016",10
+,niebaopeng,https://github.com/niebaopeng,10,40,"Apr 15, 2016",10
+,"pyloor ",https://schwarz-weiss.cc/,10,40,"May 16, 2016",10
+,"Jonathan Arnett",,10,40,"May 20, 2016",10
+,swalf,https://github.com/swalf,5,40,"May 9, 2016",5
+,zachaysan,http://venn.lc,10,30,"Jun 7, 2016",10
+,"Matthew Baulch",,10,30,"Jun 7, 2016",10
+,"Oskari Timperi",,10,30,"Jun 8, 2016",10
+,RationalG,https://github.com/RationalG,10,30,"Jun 17, 2016",10
+,"Handojo Goenadi",,5,25,"Apr 19, 2016",5
+,"Matthew Newton",,5,25,"Apr 20, 2016",5
+,johnnovak,http://www.johnnovak.net/,5,25,"Apr 29, 2016",5
+,moigagoo,http://sloth-ci.com,5,20,"May 13, 2016",5
+,RyanMarcus,http://rmarcus.info,5,10,"Jul 19, 2016",5
+,Blumenversand,https://github.com/blumenversand,5,10,"Jul 21, 2016",5
+,lenzenmi,https://github.com/lenzenmi,5,10,"Jul 28, 2016",5
+,DateinAsia,,5,10,"Jul 30, 2016",5
+,pandada8,https://github.com/pandada8,5,5,"Aug 12, 2016",5
+,abeaumont,http://alfredobeaumont.org/blog,5,5,"Aug 12, 2016",5
+,"Svend Knudsen",,1,5,"Apr 11, 2016",1
+,"Michael D. Sklaroff",,1,5,"Apr 27, 2016",1
+,nicck,,1,1,"Aug 9, 2016",1
+
diff --git a/web/ticker.html b/web/ticker.html
index ecbfb5e3f..7a1d620d3 100644
--- a/web/ticker.html
+++ b/web/ticker.html
@@ -1,3 +1,8 @@
+<a class="news" href="$1news/2016_09_03_nim_community_survey_results.html">
+  <h4>September 3, 2016</h4>
+  <p>Nim Community Survey results</p>
+</a>
+
 <a class="news" href="$1news/2016_08_06_bountysource_update_the_road_to_v10.html">
   <h4>August 6, 2016</h4>
   <p>BountySource Update: The Road to v1.0</p>
@@ -17,9 +22,4 @@
   <h4>June 04, 2016</h4>
   <p>Meet our BountySource sponsors</p>
 </a>
-
-<a class="news" href="$1news/2016_01_27_nim_in_action_is_now_available.html">
-  <h4>January 27, 2016</h4>
-  <p>Nim in Action is now available!</p>
-</a>
 <a href="$1news.html" class="blue">See All News...</a>