summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/deprecated/core/unsigned.nim (renamed from lib/core/unsigned.nim)0
-rw-r--r--lib/deprecated/pure/actors.nim (renamed from lib/pure/actors.nim)0
-rw-r--r--lib/deprecated/pure/actors.nim.cfg (renamed from lib/pure/actors.nim.cfg)0
-rw-r--r--lib/deprecated/pure/asyncio.nim (renamed from lib/pure/asyncio.nim)0
-rw-r--r--lib/deprecated/pure/ftpclient.nim (renamed from lib/pure/ftpclient.nim)13
-rw-r--r--lib/deprecated/pure/parseurl.nim (renamed from lib/pure/parseurl.nim)0
-rw-r--r--lib/deprecated/pure/rawsockets.nim14
-rw-r--r--lib/deprecated/pure/sockets.nim (renamed from lib/pure/sockets.nim)7
-rw-r--r--lib/impure/graphics.nim577
-rw-r--r--lib/posix/kqueue.nim71
-rw-r--r--lib/posix/posix.nim6
-rw-r--r--lib/pure/asyncdispatch.nim73
-rw-r--r--lib/pure/asyncftpclient.nim75
-rw-r--r--lib/pure/asynchttpserver.nim6
-rw-r--r--lib/pure/asyncnet.nim12
-rw-r--r--lib/pure/base64.nim37
-rw-r--r--lib/pure/basic2d.nim8
-rw-r--r--lib/pure/basic3d.nim2
-rw-r--r--lib/pure/collections/critbits.nim8
-rw-r--r--lib/pure/collections/sequtils.nim203
-rw-r--r--lib/pure/coro.nim2
-rw-r--r--lib/pure/coro.nimcfg1
-rw-r--r--lib/pure/future.nim4
-rw-r--r--lib/pure/hashes.nim74
-rw-r--r--lib/pure/httpclient.nim8
-rw-r--r--lib/pure/json.nim9
-rw-r--r--lib/pure/logging.nim27
-rw-r--r--lib/pure/math.nim31
-rw-r--r--lib/pure/md5.nim2
-rw-r--r--lib/pure/memfiles.nim13
-rw-r--r--lib/pure/nativesockets.nim (renamed from lib/pure/rawsockets.nim)51
-rw-r--r--lib/pure/net.nim13
-rw-r--r--lib/pure/options.nim64
-rw-r--r--lib/pure/os.nim12
-rw-r--r--lib/pure/ospaths.nim50
-rw-r--r--lib/pure/osproc.nim140
-rw-r--r--lib/pure/rationals.nim69
-rw-r--r--lib/pure/selectors.nim94
-rw-r--r--lib/pure/streams.nim35
-rw-r--r--lib/pure/strtabs.nim6
-rw-r--r--lib/pure/strutils.nim200
-rw-r--r--lib/pure/subexes.nim19
-rw-r--r--lib/pure/unicode.nim40
-rw-r--r--lib/pure/uri.nim10
-rw-r--r--lib/pure/xmltree.nim13
-rw-r--r--lib/system.nim135
-rw-r--r--lib/system/alloc.nim60
-rw-r--r--lib/system/gc_common.nim18
-rw-r--r--lib/system/mmdisp.nim46
-rw-r--r--lib/system/nimscript.nim5
-rw-r--r--lib/system/threads.nim61
-rw-r--r--lib/windows/winlean.nim34
52 files changed, 1508 insertions, 950 deletions
diff --git a/lib/core/unsigned.nim b/lib/deprecated/core/unsigned.nim
index 93a29e1c9..93a29e1c9 100644
--- a/lib/core/unsigned.nim
+++ b/lib/deprecated/core/unsigned.nim
diff --git a/lib/pure/actors.nim b/lib/deprecated/pure/actors.nim
index f0791f954..f0791f954 100644
--- a/lib/pure/actors.nim
+++ b/lib/deprecated/pure/actors.nim
diff --git a/lib/pure/actors.nim.cfg b/lib/deprecated/pure/actors.nim.cfg
index c6bb9c545..c6bb9c545 100644
--- a/lib/pure/actors.nim.cfg
+++ b/lib/deprecated/pure/actors.nim.cfg
diff --git a/lib/pure/asyncio.nim b/lib/deprecated/pure/asyncio.nim
index 5fd45b215..5fd45b215 100644
--- a/lib/pure/asyncio.nim
+++ b/lib/deprecated/pure/asyncio.nim
diff --git a/lib/pure/ftpclient.nim b/lib/deprecated/pure/ftpclient.nim
index 778ba6857..1188c0795 100644
--- a/lib/pure/ftpclient.nim
+++ b/lib/deprecated/pure/ftpclient.nim
@@ -11,9 +11,14 @@ include "system/inclrtl"
 import sockets, strutils, parseutils, times, os, asyncio
 
 from asyncnet import nil
-from rawsockets import nil
+from nativesockets import nil
 from asyncdispatch import PFuture
-
+## **Note**: This module is deprecated since version 0.11.3.
+## You should use the async version of this module
+## `asyncftpclient <asyncftpclient.html>`_.
+##
+## ----
+##
 ## This module **partially** implements an FTP client as specified
 ## by `RFC 959 <http://tools.ietf.org/html/rfc959>`_.
 ##
@@ -36,6 +41,8 @@ from asyncdispatch import PFuture
 ## **Warning:** The API of this module is unstable, and therefore is subject
 ## to change.
 
+{.deprecated.}
+
 type
   FtpBase*[SockType] = ref FtpBaseObj[SockType]
   FtpBaseObj*[SockType] = object
@@ -48,7 +55,7 @@ type
     user*, pass*: string
     address*: string
     when SockType is asyncnet.AsyncSocket:
-      port*: rawsockets.Port
+      port*: nativesockets.Port
     else:
       port*: Port
 
diff --git a/lib/pure/parseurl.nim b/lib/deprecated/pure/parseurl.nim
index 6d58e8a73..6d58e8a73 100644
--- a/lib/pure/parseurl.nim
+++ b/lib/deprecated/pure/parseurl.nim
diff --git a/lib/deprecated/pure/rawsockets.nim b/lib/deprecated/pure/rawsockets.nim
new file mode 100644
index 000000000..ee77b232e
--- /dev/null
+++ b/lib/deprecated/pure/rawsockets.nim
@@ -0,0 +1,14 @@
+import nativesockets
+export nativesockets
+
+{.warning: "rawsockets module is deprecated, use nativesockets instead".}
+
+template newRawSocket*(domain, sockType, protocol: cint): expr =
+  {.warning: "newRawSocket is deprecated, use newNativeSocket instead".}
+  newNativeSocket(domain, sockType, protocol)
+
+template newRawSocket*(domain: Domain = AF_INET,
+                       sockType: SockType = SOCK_STREAM,
+                       protocol: Protocol = IPPROTO_TCP): expr =
+  {.warning: "newRawSocket is deprecated, use newNativeSocket instead".}
+  newNativeSocket(domain, sockType, protocol)
diff --git a/lib/pure/sockets.nim b/lib/deprecated/pure/sockets.nim
index 29f0bf87d..5d6fa0078 100644
--- a/lib/pure/sockets.nim
+++ b/lib/deprecated/pure/sockets.nim
@@ -9,7 +9,7 @@
 
 ## **Warning:** Since version 0.10.2 this module is deprecated.
 ## Use the `net <net.html>`_ or the
-## `rawsockets <rawsockets.html>`_ module instead.
+## `nativesockets <nativesockets.html>`_ module instead.
 ##
 ## This module implements portable sockets, it supports a mix of different types
 ## of sockets. Sockets are buffered by default meaning that data will be
@@ -314,10 +314,7 @@ when defined(ssl):
     of protSSLv23:
       newCTX = SSL_CTX_new(SSLv23_method()) # SSlv2,3 and TLS1 support.
     of protSSLv2:
-      when not defined(linux) and not defined(OpenBSD):
-        newCTX = SSL_CTX_new(SSLv2_method())
-      else:
-        raiseSslError()
+      raiseSslError("SSLv2 is no longer secure and has been deprecated, use protSSLv3")
     of protSSLv3:
       newCTX = SSL_CTX_new(SSLv3_method())
     of protTLSv1:
diff --git a/lib/impure/graphics.nim b/lib/impure/graphics.nim
deleted file mode 100644
index 8bd769fd8..000000000
--- a/lib/impure/graphics.nim
+++ /dev/null
@@ -1,577 +0,0 @@
-#
-#
-#            Nim's Runtime Library
-#        (c) Copyright 2012 Andreas Rumpf, Dominik Picheta
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## This module implements graphical output for Nim; the current
-## implementation uses SDL but the interface is meant to support multiple
-## backends some day. There is no need to init SDL as this module does that
-## implicitly.
-
-import colors, math
-from sdl import PSurface # Bug
-from sdl_ttf import openFont, closeFont
-
-type
-  Rect* = tuple[x, y, width, height: int]
-  Point* = tuple[x, y: int]
-
-  PSurface* = ref Surface ## a surface to draw onto
-  Surface* {.pure, final.} = object
-    w*, h*: Natural
-    s*: sdl.PSurface
-
-  EGraphics* = object of IOError
-
-  Font {.pure, final.} = object
-    f: sdl_ttf.PFont
-    color: sdl.Color
-  PFont* = ref Font ## represents a font
-{.deprecated: [TSurface: Surface, TFont: Font, TRect: Rect, TPoint: Point].}
-
-proc toSdlColor*(c: Color): sdl.Color =
-  ## Convert colors.Color to sdl.Color
-  var x = c.extractRGB
-  result.r = x.r and 0xff
-  result.g = x.g and 0xff
-  result.b = x.b and 0xff
-
-proc createSdlColor*(sur: PSurface, c: Color, alpha: int = 0): int32 =
-  ## Creates a color using ``sdl.MapRGBA``.
-  var x = c.extractRGB
-  return sdl.mapRGBA(sur.s.format, x.r and 0xff, x.g and 0xff,
-                     x.b and 0xff, alpha and 0xff)
-
-proc toSdlRect*(r: Rect): sdl.Rect =
-  ## Convert ``graphics.Rect`` to ``sdl.Rect``.
-  result.x = int16(r.x)
-  result.y = int16(r.y)
-  result.w = uint16(r.width)
-  result.h = uint16(r.height)
-
-proc raiseEGraphics =
-  raise newException(EGraphics, $sdl.getError())
-
-proc surfaceFinalizer(s: PSurface) = sdl.freeSurface(s.s)
-
-proc newSurface*(width, height: int): PSurface =
-  ## creates a new surface.
-  new(result, surfaceFinalizer)
-  result.w = width
-  result.h = height
-  result.s = sdl.createRGBSurface(sdl.SWSURFACE, width, height,
-      32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0)
-  if result.s == nil:
-    raiseEGraphics()
-
-  assert(not sdl.mustLock(result.s))
-
-proc fontFinalizer(f: PFont) = closeFont(f.f)
-
-proc newFont*(name = "VeraMono.ttf", size = 9, color = colBlack): PFont =
-  ## Creates a new font object. Raises ``EIO`` if the font cannot be loaded.
-  new(result, fontFinalizer)
-  result.f = openFont(name, size.cint)
-  if result.f == nil:
-    raise newException(IOError, "Could not open font file: " & name)
-  result.color = toSdlColor(color)
-
-var
-  defaultFont*: PFont ## default font that is used; this needs to initialized
-                      ## by the client!
-
-proc initDefaultFont*(name = "VeraMono.ttf", size = 9, color = colBlack) =
-  ## initializes the `defaultFont` var.
-  defaultFont = newFont(name, size, color)
-
-proc newScreenSurface*(width, height: int): PSurface =
-  ## Creates a new screen surface
-  new(result, surfaceFinalizer)
-  result.w = width
-  result.h = height
-  result.s = sdl.setVideoMode(width, height, 0, 0)
-  if result.s == nil:
-    raiseEGraphics()
-
-proc writeToBMP*(sur: PSurface, filename: string) =
-  ## Saves the contents of the surface `sur` to the file `filename` as a
-  ## BMP file.
-  if sdl.saveBMP(sur.s, filename) != 0:
-    raise newException(IOError, "cannot write: " & filename)
-
-type
-  Pixels = array[0..1000_000-1, int32]
-  PPixels = ptr Pixels
-{.deprecated: [TPixels: Pixels].}
-
-template setPix(video, pitch, x, y, col: expr): stmt =
-  video[y * pitch + x] = int32(col)
-
-template getPix(video, pitch, x, y: expr): expr =
-  colors.Color(video[y * pitch + x])
-
-const
-  ColSize = 4
-
-proc getPixel(sur: PSurface, x, y: Natural): colors.Color {.inline.} =
-  assert x <% sur.w
-  assert y <% sur.h
-  result = getPix(cast[PPixels](sur.s.pixels), sur.s.pitch.int div ColSize,
-                  x, y)
-
-proc setPixel(sur: PSurface, x, y: Natural, col: colors.Color) {.inline.} =
-  assert x <% sur.w
-  assert y <% sur.h
-  var pixs = cast[PPixels](sur.s.pixels)
-  #pixs[y * (sur.s.pitch div colSize) + x] = int(col)
-  setPix(pixs, sur.s.pitch.int div ColSize, x, y, col)
-
-proc `[]`*(sur: PSurface, p: Point): Color =
-  ## get pixel at position `p`. No range checking is done!
-  result = getPixel(sur, p.x, p.y)
-
-proc `[]`*(sur: PSurface, x, y: int): Color =
-  ## get pixel at position ``(x, y)``. No range checking is done!
-  result = getPixel(sur, x, y)
-
-proc `[]=`*(sur: PSurface, p: Point, col: Color) =
-  ## set the pixel at position `p`. No range checking is done!
-  setPixel(sur, p.x, p.y, col)
-
-proc `[]=`*(sur: PSurface, x, y: int, col: Color) =
-  ## set the pixel at position ``(x, y)``. No range checking is done!
-  setPixel(sur, x, y, col)
-
-proc blit*(destSurf: PSurface, destRect: Rect, srcSurf: PSurface,
-           srcRect: Rect) =
-  ## Copies ``srcSurf`` into ``destSurf``
-  var destTRect, srcTRect: sdl.Rect
-
-  destTRect.x = int16(destRect.x)
-  destTRect.y = int16(destRect.y)
-  destTRect.w = uint16(destRect.width)
-  destTRect.h = uint16(destRect.height)
-
-  srcTRect.x = int16(srcRect.x)
-  srcTRect.y = int16(srcRect.y)
-  srcTRect.w = uint16(srcRect.width)
-  srcTRect.h = uint16(srcRect.height)
-
-  if sdl.blitSurface(srcSurf.s, addr(srcTRect), destSurf.s, addr(destTRect)) != 0:
-    raiseEGraphics()
-
-proc textBounds*(text: string, font = defaultFont): tuple[width, height: int] =
-  var w, h: cint
-  if sdl_ttf.sizeUTF8(font.f, text, w, h) < 0: raiseEGraphics()
-  result.width = int(w)
-  result.height = int(h)
-
-proc drawText*(sur: PSurface, p: Point, text: string, font = defaultFont) =
-  ## Draws text with a transparent background, at location ``p`` with the given
-  ## font.
-  var textSur: PSurface # This surface will have the text drawn on it
-  new(textSur, surfaceFinalizer)
-
-  # Render the text
-  textSur.s = sdl_ttf.renderTextBlended(font.f, text, font.color)
-  # Merge the text surface with sur
-  sur.blit((p.x, p.y, sur.w, sur.h), textSur, (0, 0, sur.w, sur.h))
-
-proc drawText*(sur: PSurface, p: Point, text: string,
-               bg: Color, font = defaultFont) =
-  ## Draws text, at location ``p`` with font ``font``. ``bg``
-  ## is the background color.
-  var textSur: PSurface # This surface will have the text drawn on it
-  new(textSur, surfaceFinalizer)
-  textSur.s = sdl_ttf.renderTextShaded(font.f, text, font.color, toSdlColor(bg))
-  # Merge the text surface with sur
-  sur.blit((p.x, p.y, sur.w, sur.h), textSur, (0, 0, sur.w, sur.h))
-
-proc drawCircle*(sur: PSurface, p: Point, r: Natural, color: Color) =
-  ## draws a circle with center `p` and radius `r` with the given color
-  ## onto the surface `sur`.
-  var video = cast[PPixels](sur.s.pixels)
-  var pitch = sur.s.pitch.int div ColSize
-  var a = 1 - r
-  var py = r
-  var px = 0
-  var x = p.x
-  var y = p.y
-  while px <= py + 1:
-    if x+px <% sur.w:
-      if y+py <% sur.h: setPix(video, pitch, x+px, y+py, color)
-      if y-py <% sur.h: setPix(video, pitch, x+px, y-py, color)
-
-    if x-px <% sur.w:
-      if y+py <% sur.h: setPix(video, pitch, x-px, y+py, color)
-      if y-py <% sur.h: setPix(video, pitch, x-px, y-py, color)
-
-    if x+py <% sur.w:
-      if y+px <% sur.h: setPix(video, pitch, x+py, y+px, color)
-      if y-px <% sur.h: setPix(video, pitch, x+py, y-px, color)
-
-    if x-py <% sur.w:
-      if y+px <% sur.h: setPix(video, pitch, x-py, y+px, color)
-      if y-px <% sur.h: setPix(video, pitch, x-py, y-px, color)
-
-    if a < 0:
-      a = a + (2 * px + 3)
-    else:
-      a = a + (2 * (px - py) + 5)
-      py = py - 1
-    px = px + 1
-
-proc `>-<`(val: int, s: PSurface): int {.inline.} =
-  return if val < 0: 0 elif val >= s.w: s.w-1 else: val
-
-proc `>|<`(val: int, s: PSurface): int {.inline.} =
-  return if val < 0: 0 elif val >= s.h: s.h-1 else: val
-
-proc drawLine*(sur: PSurface, p1, p2: Point, color: Color) =
-  ## draws a line between the two points `p1` and `p2` with the given color
-  ## onto the surface `sur`.
-  var stepx, stepy: int = 0
-  var x0 = p1.x >-< sur
-  var x1 = p2.x >-< sur
-  var y0 = p1.y >|< sur
-  var y1 = p2.y >|< sur
-  var dy = y1 - y0
-  var dx = x1 - x0
-  if dy < 0:
-    dy = -dy
-    stepy = -1
-  else:
-    stepy = 1
-  if dx < 0:
-    dx = -dx
-    stepx = -1
-  else:
-    stepx = 1
-  dy = dy * 2
-  dx = dx * 2
-  var video = cast[PPixels](sur.s.pixels)
-  var pitch = sur.s.pitch.int div ColSize
-  setPix(video, pitch, x0, y0, color)
-  if dx > dy:
-    var fraction = dy - (dx div 2)
-    while x0 != x1:
-      if fraction >= 0:
-        y0 = y0 + stepy
-        fraction = fraction - dx
-      x0 = x0 + stepx
-      fraction = fraction + dy
-      setPix(video, pitch, x0, y0, color)
-  else:
-    var fraction = dx - (dy div 2)
-    while y0 != y1:
-      if fraction >= 0:
-        x0 = x0 + stepx
-        fraction = fraction - dy
-      y0 = y0 + stepy
-      fraction = fraction + dx
-      setPix(video, pitch, x0, y0, color)
-
-proc drawHorLine*(sur: PSurface, x, y, w: Natural, color: Color) =
-  ## draws a horizontal line from (x,y) to (x+w-1, y).
-  var video = cast[PPixels](sur.s.pixels)
-  var pitch = sur.s.pitch.int div ColSize
-
-  if y >= 0 and y <= sur.s.h:
-    for i in 0 .. min(sur.s.w-x, w)-1:
-      setPix(video, pitch, x + i, y, color)
-
-proc drawVerLine*(sur: PSurface, x, y, h: Natural, color: Color) =
-  ## draws a vertical line from (x,y) to (x, y+h-1).
-  var video = cast[PPixels](sur.s.pixels)
-  var pitch = sur.s.pitch.int div ColSize
-
-  if x >= 0 and x <= sur.s.w:
-    for i in 0 .. min(sur.s.h-y, h)-1:
-      setPix(video, pitch, x, y + i, color)
-
-proc fillCircle*(s: PSurface, p: Point, r: Natural, color: Color) =
-  ## draws a circle with center `p` and radius `r` with the given color
-  ## onto the surface `sur` and fills it.
-  var a = 1 - r
-  var py: int = r
-  var px = 0
-  var x = p.x
-  var y = p.y
-  while px <= py:
-    # Fill up the middle half of the circle
-    drawVerLine(s, x + px, y, py + 1, color)
-    drawVerLine(s, x + px, y - py, py, color)
-    if px != 0:
-      drawVerLine(s, x - px, y, py + 1, color)
-      drawVerLine(s, x - px, y - py, py, color)
-    if a < 0:
-      a = a + (2 * px + 3)
-    else:
-      a = a + (2 * (px - py) + 5)
-      py = py - 1
-      # Fill up the left/right half of the circle
-      if py >= px:
-        drawVerLine(s, x + py + 1, y, px + 1, color)
-        drawVerLine(s, x + py + 1, y - px, px, color)
-        drawVerLine(s, x - py - 1, y, px + 1, color)
-        drawVerLine(s, x - py - 1, y - px,  px, color)
-    px = px + 1
-
-proc drawRect*(sur: PSurface, r: Rect, color: Color) =
-  ## draws a rectangle.
-  var video = cast[PPixels](sur.s.pixels)
-  var pitch = sur.s.pitch.int div ColSize
-  if (r.x >= 0 and r.x <= sur.s.w) and (r.y >= 0 and r.y <= sur.s.h):
-    var minW = min(sur.s.w - r.x, r.width)
-    var minH = min(sur.s.h - r.y, r.height)
-
-    # Draw Top
-    for i in 0 .. minW - 1:
-      setPix(video, pitch, r.x + i, r.y, color)
-      setPix(video, pitch, r.x + i, r.y + minH - 1, color) # Draw bottom
-
-    # Draw left side
-    for i in 0 .. minH - 1:
-      setPix(video, pitch, r.x, r.y + i, color)
-      setPix(video, pitch, r.x + minW - 1, r.y + i, color) # Draw right side
-
-proc fillRect*(sur: PSurface, r: Rect, col: Color) =
-  ## Fills a rectangle using sdl's ``FillRect`` function.
-  var rect = toSdlRect(r)
-  if sdl.fillRect(sur.s, addr(rect), sur.createSdlColor(col)) == -1:
-    raiseEGraphics()
-
-proc plot4EllipsePoints(sur: PSurface, cx, cy, x, y: Natural, col: Color) =
-  var video = cast[PPixels](sur.s.pixels)
-  var pitch = sur.s.pitch.int div ColSize
-  if cx+x <= sur.s.w-1:
-    if cy+y <= sur.s.h-1: setPix(video, pitch, cx+x, cy+y, col)
-    if cy-y <= sur.s.h-1: setPix(video, pitch, cx+x, cy-y, col)
-  if cx-x <= sur.s.w-1:
-    if cy+y <= sur.s.h-1: setPix(video, pitch, cx-x, cy+y, col)
-    if cy-y <= sur.s.h-1: setPix(video, pitch, cx-x, cy-y, col)
-
-proc drawEllipse*(sur: PSurface, cx, cy, xRadius, yRadius: Natural,
-                  col: Color) =
-  ## Draws an ellipse, ``CX`` and ``CY`` specify the center X and Y of the
-  ## ellipse, ``XRadius`` and ``YRadius`` specify half the width and height
-  ## of the ellipse.
-  var
-    x, y: Natural
-    xChange, yChange: int
-    ellipseError: Natural
-    twoASquare, twoBSquare: Natural
-    stoppingX, stoppingY: Natural
-
-  twoASquare = 2 * xRadius * xRadius
-  twoBSquare = 2 * yRadius * yRadius
-  x = xRadius
-  y = 0
-  xChange = yRadius * yRadius * (1 - 2 * xRadius)
-  yChange = xRadius * xRadius
-  ellipseError = 0
-  stoppingX = twoBSquare * xRadius
-  stoppingY = 0
-
-  while stoppingX >=  stoppingY: # 1st set of points, y` > - 1
-    sur.plot4EllipsePoints(cx, cy, x, y, col)
-    inc(y)
-    inc(stoppingY, twoASquare)
-    inc(ellipseError, yChange)
-    inc(yChange, twoASquare)
-    if (2 * ellipseError + xChange) > 0 :
-      dec(x)
-      dec(stoppingX, twoBSquare)
-      inc(ellipseError, xChange)
-      inc(xChange, twoBSquare)
-
-  # 1st point set is done; start the 2nd set of points
-  x = 0
-  y = yRadius
-  xChange = yRadius * yRadius
-  yChange = xRadius * xRadius * (1 - 2 * yRadius)
-  ellipseError = 0
-  stoppingX = 0
-  stoppingY = twoASquare * yRadius
-  while stoppingX <= stoppingY:
-    sur.plot4EllipsePoints(cx, cy, x, y, col)
-    inc(x)
-    inc(stoppingX, twoBSquare)
-    inc(ellipseError, xChange)
-    inc(xChange,twoBSquare)
-    if (2 * ellipseError + yChange) > 0:
-      dec(y)
-      dec(stoppingY, twoASquare)
-      inc(ellipseError, yChange)
-      inc(yChange,twoASquare)
-
-
-proc plotAA(sur: PSurface, x, y: int, c: float, color: Color) =
-  if (x > 0 and x < sur.s.w) and (y > 0 and y < sur.s.h):
-    var video = cast[PPixels](sur.s.pixels)
-    var pitch = sur.s.pitch.int div ColSize
-
-    var pixColor = getPix(video, pitch, x, y)
-
-    setPix(video, pitch, x, y,
-           pixColor.intensity(1.0 - c) + color.intensity(c))
-
-
-template ipart(x: expr): expr = floor(x)
-template cround(x: expr): expr = ipart(x + 0.5)
-template fpart(x: expr): expr = x - ipart(x)
-template rfpart(x: expr): expr = 1.0 - fpart(x)
-
-proc drawLineAA*(sur: PSurface, p1, p2: Point, color: Color) =
-  ## Draws a anti-aliased line from ``p1`` to ``p2``, using Xiaolin Wu's
-  ## line algorithm
-  var (x1, x2, y1, y2) = (p1.x.toFloat(), p2.x.toFloat(),
-                          p1.y.toFloat(), p2.y.toFloat())
-  var dx = x2 - x1
-  var dy = y2 - y1
-
-  var ax = dx
-  if ax < 0'f64:
-    ax = 0'f64 - ax
-  var ay = dy
-  if ay < 0'f64:
-    ay = 0'f64 - ay
-
-  if ax < ay:
-    swap(x1, y1)
-    swap(x2, y2)
-    swap(dx, dy)
-
-  template doPlot(x, y: int, c: float, color: Color): stmt =
-    if ax < ay:
-      sur.plotAA(y, x, c, color)
-    else:
-      sur.plotAA(x, y, c, color)
-
-  if x2 < x1:
-    swap(x1, x2)
-    swap(y1, y2)
-
-  var gradient = dy / dx
-  # handle first endpoint
-  var xend = cround(x1)
-  var yend = y1 + gradient * (xend - x1)
-  var xgap = rfpart(x1 + 0.5)
-  var xpxl1 = int(xend) # this will be used in the main loop
-  var ypxl1 = int(ipart(yend))
-  doPlot(xpxl1, ypxl1, rfpart(yend)*xgap, color)
-  doPlot(xpxl1, ypxl1 + 1, fpart(yend)*xgap, color)
-  var intery = yend + gradient # first y-intersection for the main loop
-
-  # handle second endpoint
-  xend = cround(x2)
-  yend = y2 + gradient * (xend - x2)
-  xgap = fpart(x2 + 0.5)
-  var xpxl2 = int(xend) # this will be used in the main loop
-  var ypxl2 = int(ipart(yend))
-  doPlot(xpxl2, ypxl2, rfpart(yend) * xgap, color)
-  doPlot(xpxl2, ypxl2 + 1, fpart(yend) * xgap, color)
-
-  # main loop
-  var x = xpxl1 + 1
-  while x <= xpxl2-1:
-    doPlot(x, int(ipart(intery)), rfpart(intery), color)
-    doPlot(x, int(ipart(intery)) + 1, fpart(intery), color)
-    intery = intery + gradient
-    inc(x)
-
-proc fillSurface*(sur: PSurface, color: Color) =
-  ## Fills the entire surface with ``color``.
-  if sdl.fillRect(sur.s, nil, sur.createSdlColor(color)) == -1:
-    raiseEGraphics()
-
-template withEvents*(surf: PSurface, event: expr, actions: stmt): stmt {.
-  immediate.} =
-  ## Simple template which creates an event loop. ``Event`` is the name of the
-  ## variable containing the Event object.
-  while true:
-    var event: sdl.Event
-    if sdl.waitEvent(addr(event)) == 1:
-      actions
-
-if sdl.init(sdl.INIT_VIDEO) < 0: raiseEGraphics()
-if sdl_ttf.init() < 0: raiseEGraphics()
-
-when not defined(testing) and isMainModule:
-  var surf = newScreenSurface(800, 600)
-
-  surf.fillSurface(colWhite)
-
-  # Draw the shapes
-  surf.drawLineAA((150, 170), (400, 471), colTan)
-  surf.drawLine((100, 170), (400, 471), colRed)
-
-  surf.drawEllipse(200, 300, 200, 30, colSeaGreen)
-  surf.drawHorLine(1, 300, 400, colViolet)
-  # Check if the ellipse is the size it's suppose to be.
-  surf.drawVerLine(200, 300 - 30 + 1, 60, colViolet) # ^^ | i suppose it is
-
-  surf.drawEllipse(400, 300, 300, 300, colOrange)
-  surf.drawEllipse(5, 5, 5, 5, colGreen)
-
-  surf.drawHorLine(5, 5, 900, colRed)
-  surf.drawVerLine(5, 60, 800, colRed)
-  surf.drawCircle((600, 500), 60, colRed)
-
-  surf.fillRect((50, 50, 100, 100), colFuchsia)
-  surf.fillRect((150, 50, 100, 100), colGreen)
-  surf.drawRect((50, 150, 100, 100), colGreen)
-  surf.drawRect((150, 150, 100, 100), colAqua)
-  surf.drawRect((250, 150, 100, 100), colBlue)
-  surf.drawHorLine(250, 150, 100, colRed)
-
-  surf.drawLineAA((592, 160), (592, 280), colPurple)
-
-  #surf.drawText((300, 300), "TEST", colMidnightBlue)
-  #var textSize = textBounds("TEST")
-  #surf.drawText((300, 300 + textSize.height), $textSize.width & ", " &
-  #  $textSize.height, colDarkGreen)
-
-  var mouseStartX = -1
-  var mouseStartY = -1
-  withEvents(surf, event):
-    var eventp = addr(event)
-    case event.kind:
-    of sdl.QUITEV:
-      break
-    of sdl.KEYDOWN:
-      var evk = sdl.evKeyboard(eventp)
-      if evk.keysym.sym == sdl.K_LEFT:
-        surf.drawHorLine(395, 300, 50, colBlack)
-        echo("Drawing")
-      elif evk.keysym.sym == sdl.K_ESCAPE:
-        break
-      else:
-        echo(evk.keysym.sym)
-    of sdl.MOUSEBUTTONDOWN:
-      var mbd = sdl.evMouseButton(eventp)
-      if mouseStartX == -1 or mouseStartY == -1:
-        mouseStartX = int(mbd.x)
-        mouseStartY = int(mbd.y)
-      else:
-        surf.drawLineAA((mouseStartX, mouseStartY), (int(mbd.x), int(mbd.y)), colPurple)
-        mouseStartX = -1
-        mouseStartY = -1
-
-    of sdl.MOUSEMOTION:
-      var mm = sdl.evMouseMotion(eventp)
-      if mouseStartX != -1 and mouseStartY != -1:
-        surf.drawLineAA((mouseStartX, mouseStartY), (int(mm.x), int(mm.y)), colPurple)
-      #echo(mm.x, " ", mm.y, " ", mm.yrel)
-
-    else:
-      discard "echo(event.kind)"
-
-    sdl.updateRect(surf.s, 0, 0, 800, 600)
-
-  surf.writeToBMP("test.bmp")
-  sdl.quit()
diff --git a/lib/posix/kqueue.nim b/lib/posix/kqueue.nim
new file mode 100644
index 000000000..511ada9ac
--- /dev/null
+++ b/lib/posix/kqueue.nim
@@ -0,0 +1,71 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Adam Strzelecki
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+{.deadCodeElim:on.}
+
+from posix import Timespec
+
+# Filters:
+const
+  EVFILT_READ*     = -1
+  EVFILT_WRITE*    = -2
+  EVFILT_AIO*      = -3
+  EVFILT_VNODE*    = -4
+  EVFILT_PROC*     = -5
+  EVFILT_SIGNAL*   = -6
+  EVFILT_TIMER*    = -7
+  EVFILT_MACHPORT* = -8
+  EVFILT_FS*       = -9
+  EVFILT_USER*     = -10
+  # -11 is unused
+  EVFILT_VM*       = -12
+
+# Actions:
+const
+  EV_ADD*      = 0x0001 ## Add event to queue (implies enable).
+                        ## Re-adding an existing element modifies it.
+  EV_DELETE*   = 0x0002 ## Delete event from queue.
+  EV_ENABLE*   = 0x0004 ## Enable event.
+  EV_DISABLE*  = 0x0008 ## Disable event (not reported).
+
+# Flags:
+const
+  EV_ONESHOT*  = 0x0010 ## Only report one occurrence.
+  EV_CLEAR*    = 0x0020 ## Clear event state after reporting.
+  EV_RECEIPT*  = 0x0040 ## Force EV_ERROR on success, data == 0
+  EV_DISPATCH* = 0x0080 ## Disable event after reporting.
+
+# Return values:
+const
+  EV_EOF*      = 0x8000 ## EOF detected
+  EV_ERROR*    = 0x4000 ## Error, data contains errno
+
+type
+  KEvent* {.importc: "struct kevent",
+            header: "<sys/event.h>", pure, final.} = object
+    ident*: cuint    ## identifier for this event  (uintptr_t)
+    filter*: cshort  ## filter for event
+    flags*: cushort  ## general flags
+    fflags*: cuint   ## filter-specific flags
+    data*: cuint     ## filter-specific data  (intptr_t)
+    #udata*: ptr void ## opaque user data identifier
+
+proc kqueue*(): cint {.importc: "kqueue", header: "<sys/event.h>".}
+  ## Creates new queue and returns its descriptor.
+
+proc kevent*(kqFD: cint,
+             changelist: ptr KEvent, nchanges: cint,
+             eventlist: ptr KEvent, nevents: cint, timeout: ptr Timespec): cint
+     {.importc: "kevent", header: "<sys/event.h>".}
+  ## Manipulates queue for given ``kqFD`` descriptor.
+
+proc EV_SET*(event: ptr KEvent, ident: cuint, filter: cshort, flags: cushort,
+             fflags: cuint, data: cuint, udata: ptr void)
+     {.importc: "EV_SET", header: "<sys/event.h>".}
+  ## Fills event with given data.
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
index 8486fa04f..5f1dfcfcd 100644
--- a/lib/posix/posix.nim
+++ b/lib/posix/posix.nim
@@ -1810,7 +1810,7 @@ proc ntohs*(a1: int16): int16 {.importc, header: "<arpa/inet.h>".}
 proc inet_addr*(a1: cstring): InAddrT {.importc, header: "<arpa/inet.h>".}
 proc inet_ntoa*(a1: InAddr): cstring {.importc, header: "<arpa/inet.h>".}
 proc inet_ntop*(a1: cint, a2: pointer, a3: cstring, a4: int32): cstring {.
-  importc, header: "<arpa/inet.h>".}
+  importc:"(char *)$1", header: "<arpa/inet.h>".}
 proc inet_pton*(a1: cint, a2: cstring, a3: pointer): cint {.
   importc, header: "<arpa/inet.h>".}
 
@@ -2381,7 +2381,7 @@ proc sched_setscheduler*(a1: Pid, a2: cint, a3: var Sched_param): cint {.
 proc sched_yield*(): cint {.importc, header: "<sched.h>".}
 
 proc strerror*(errnum: cint): cstring {.importc, header: "<string.h>".}
-proc hstrerror*(herrnum: cint): cstring {.importc, header: "<netdb.h>".}
+proc hstrerror*(herrnum: cint): cstring {.importc:"(char *)$1", header: "<netdb.h>".}
 
 proc FD_CLR*(a1: cint, a2: var TFdSet) {.importc, header: "<sys/select.h>".}
 proc FD_ISSET*(a1: cint | SocketHandle, a2: var TFdSet): cint {.
@@ -2565,7 +2565,7 @@ proc endprotoent*() {.importc, header: "<netdb.h>".}
 proc endservent*() {.importc, header: "<netdb.h>".}
 proc freeaddrinfo*(a1: ptr AddrInfo) {.importc, header: "<netdb.h>".}
 
-proc gai_strerror*(a1: cint): cstring {.importc, header: "<netdb.h>".}
+proc gai_strerror*(a1: cint): cstring {.importc:"(char *)$1", header: "<netdb.h>".}
 
 proc getaddrinfo*(a1, a2: cstring, a3: ptr AddrInfo,
                   a4: var ptr AddrInfo): cint {.importc, header: "<netdb.h>".}
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index d91507a85..cc337452f 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -11,7 +11,7 @@ include "system/inclrtl"
 
 import os, oids, tables, strutils, macros, times
 
-import rawsockets, net
+import nativesockets, net
 
 export Port, SocketFlag
 
@@ -475,7 +475,7 @@ when defined(windows) or defined(nimdoc):
                       addr bytesRet, nil, nil) == 0
 
   proc initAll() =
-    let dummySock = newRawSocket()
+    let dummySock = newNativeSocket()
     if not initPointer(dummySock, connectExPtr, WSAID_CONNECTEX):
       raiseOSError(osLastError())
     if not initPointer(dummySock, acceptExPtr, WSAID_ACCEPTEX):
@@ -528,7 +528,7 @@ when defined(windows) or defined(nimdoc):
                   RemoteSockaddr, RemoteSockaddrLength)
 
   proc connect*(socket: AsyncFD, address: string, port: Port,
-    domain = rawsockets.AF_INET): Future[void] =
+    domain = nativesockets.AF_INET): Future[void] =
     ## Connects ``socket`` to server at ``address:port``.
     ##
     ## Returns a ``Future`` which will complete when the connection succeeds
@@ -611,7 +611,7 @@ when defined(windows) or defined(nimdoc):
     var retFuture = newFuture[string]("recv")
     var dataBuf: TWSABuf
     dataBuf.buf = cast[cstring](alloc0(size))
-    dataBuf.len = size
+    dataBuf.len = size.ULONG
 
     var bytesReceived: Dword
     var flagsio = flags.toOSFlags().Dword
@@ -706,7 +706,7 @@ when defined(windows) or defined(nimdoc):
     #buf[] = '\0'
     var dataBuf: TWSABuf
     dataBuf.buf = buf
-    dataBuf.len = size
+    dataBuf.len = size.ULONG
 
     var bytesReceived: Dword
     var flagsio = flags.toOSFlags().Dword
@@ -777,7 +777,7 @@ when defined(windows) or defined(nimdoc):
 
     var dataBuf: TWSABuf
     dataBuf.buf = data # since this is not used in a callback, this is fine
-    dataBuf.len = data.len
+    dataBuf.len = data.len.ULONG
 
     var bytesReceived, lowFlags: Dword
     var ol = PCustomOverlapped()
@@ -827,7 +827,7 @@ when defined(windows) or defined(nimdoc):
     verifyPresence(socket)
     var retFuture = newFuture[tuple[address: string, client: AsyncFD]]("acceptAddr")
 
-    var clientSock = newRawSocket()
+    var clientSock = newNativeSocket()
     if clientSock == osInvalidSocket: raiseOSError(osLastError())
 
     const lpOutputLen = 1024
@@ -900,17 +900,17 @@ when defined(windows) or defined(nimdoc):
 
     return retFuture
 
-  proc newAsyncRawSocket*(domain, sockType, protocol: cint): AsyncFD =
+  proc newAsyncNativeSocket*(domain, sockType, protocol: cint): AsyncFD =
     ## Creates a new socket and registers it with the dispatcher implicitly.
-    result = newRawSocket(domain, sockType, protocol).AsyncFD
+    result = newNativeSocket(domain, sockType, protocol).AsyncFD
     result.SocketHandle.setBlocking(false)
     register(result)
 
-  proc newAsyncRawSocket*(domain: Domain = rawsockets.AF_INET,
-               sockType: SockType = SOCK_STREAM,
-               protocol: Protocol = IPPROTO_TCP): AsyncFD =
+  proc newAsyncNativeSocket*(domain: Domain = nativesockets.AF_INET,
+                             sockType: SockType = SOCK_STREAM,
+                             protocol: Protocol = IPPROTO_TCP): AsyncFD =
     ## Creates a new socket and registers it with the dispatcher implicitly.
-    result = newRawSocket(domain, sockType, protocol).AsyncFD
+    result = newNativeSocket(domain, sockType, protocol).AsyncFD
     result.SocketHandle.setBlocking(false)
     register(result)
 
@@ -973,18 +973,18 @@ else:
     var data = PData(fd: fd, readCBs: @[], writeCBs: @[])
     p.selector.register(fd.SocketHandle, {}, data.RootRef)
 
-  proc newAsyncRawSocket*(domain: cint, sockType: cint,
-      protocol: cint): AsyncFD =
-    result = newRawSocket(domain, sockType, protocol).AsyncFD
+  proc newAsyncNativeSocket*(domain: cint, sockType: cint,
+                             protocol: cint): AsyncFD =
+    result = newNativeSocket(domain, sockType, protocol).AsyncFD
     result.SocketHandle.setBlocking(false)
     when defined(macosx):
       result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
     register(result)
 
-  proc newAsyncRawSocket*(domain: Domain = AF_INET,
-               sockType: SockType = SOCK_STREAM,
-               protocol: Protocol = IPPROTO_TCP): AsyncFD =
-    result = newRawSocket(domain, sockType, protocol).AsyncFD
+  proc newAsyncNativeSocket*(domain: Domain = AF_INET,
+                             sockType: SockType = SOCK_STREAM,
+                             protocol: Protocol = IPPROTO_TCP): AsyncFD =
+    result = newNativeSocket(domain, sockType, protocol).AsyncFD
     result.SocketHandle.setBlocking(false)
     when defined(macosx):
       result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
@@ -992,8 +992,8 @@ else:
 
   proc closeSocket*(sock: AsyncFD) =
     let disp = getGlobalDispatcher()
-    sock.SocketHandle.close()
     disp.selector.unregister(sock.SocketHandle)
+    sock.SocketHandle.close()
 
   proc unregister*(fd: AsyncFD) =
     getGlobalDispatcher().selector.unregister(fd.SocketHandle)
@@ -1468,16 +1468,25 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
   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 == nnkIdent:
-    error("Expected return type of 'Future' got '" & $returnType & "'")
-  elif returnType.kind == nnkBracketExpr:
-    if $returnType[0] != "Future":
-      error("Expected return type of 'Future' got '" & $returnType[0] & "'")
+  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
-        (returnType.kind == nnkBracketExpr and
-         returnType[1].kind == nnkIdent and returnType[1].ident == !"void")
+        (baseType.kind == nnkIdent and returnType[1].ident == !"void")
 
   var outerProcBody = newNimNode(nnkStmtList, prc[6])
 
@@ -1485,7 +1494,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
   var retFutureSym = genSym(nskVar, "retFuture")
   var subRetType =
     if returnType.kind == nnkEmpty: newIdentNode("void")
-    else: returnType[1]
+    else: baseType
   outerProcBody.add(
     newVarStmt(retFutureSym,
       newCall(
@@ -1509,7 +1518,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
       newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.}
 
     procBody.insert(1, newNimNode(nnkVarSection, prc[6]).add(
-      newIdentDefs(newIdentNode("result"), returnType[1]))) # -> var result: T
+      newIdentDefs(newIdentNode("result"), baseType))) # -> var result: T
 
     procBody.insert(2, newNimNode(nnkPragma).add(
       newIdentNode("pop"))) # -> {.pop.})
@@ -1550,8 +1559,8 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
   result[6] = outerProcBody
 
   #echo(treeRepr(result))
-  if prc[0].getName == "hubConnectionLoop":
-    echo(toStrLit(result))
+  #if prc[0].getName == "hubConnectionLoop":
+  #  echo(toStrLit(result))
 
 macro async*(prc: stmt): stmt {.immediate.} =
   ## Macro which processes async procedures into the appropriate
diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim
index fe4577ed9..b806f4235 100644
--- a/lib/pure/asyncftpclient.nim
+++ b/lib/pure/asyncftpclient.nim
@@ -6,23 +6,74 @@
 #    distribution, for details about the copyright.
 #
 
-## This module implement an asynchronous FTP client.
+## This module implements an asynchronous FTP client. It allows you to connect
+## to an FTP server and perform operations on it such as for example:
 ##
-## Examples
-## --------
+## * The upload of new files.
+## * The removal of existing files.
+## * Download of files.
+## * Changing of files' permissions.
+## * Navigation through the FTP server's directories.
 ##
-## .. code-block::nim
+## Connecting to an FTP server
+## ------------------------
 ##
-##      var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test")
-##      proc main(ftp: AsyncFtpClient) {.async.} =
+## In order to begin any sort of transfer of files you must first
+## connect to an FTP server. You can do so with the ``connect`` procedure.
+##
+##   .. code-block::nim
+##      import asyncdispatch, asyncftpclient
+##      proc main() {.async.} =
+##        var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test")
+##        await ftp.connect()
+##        echo("Connected")
+##      waitFor(main())
+##
+## A new ``main`` async procedure must be declared to allow the use of the
+## ``await`` keyword. The connection will complete asynchronously and the
+## client will be connected after the ``await ftp.connect()`` call.
+##
+## Uploading a new file
+## --------------------
+##
+## After a connection is made you can use the ``store`` procedure to upload
+## a new file to the FTP server. Make sure to check you are in the correct
+## working directory before you do so with the ``pwd`` procedure, you can also
+## instead specify an absolute path.
+##
+##   .. code-block::nim
+##      import asyncdispatch, asyncftpclient
+##      proc main() {.async.} =
+##        var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test")
 ##        await ftp.connect()
-##        echo await ftp.pwd()
-##        echo await ftp.listDirs()
-##        await ftp.store("payload.jpg", "payload.jpg")
-##        await ftp.retrFile("payload.jpg", "payload2.jpg")
-##        echo("Finished")
+##        let currentDir = await ftp.pwd()
+##        assert currentDir == "/home/user/"
+##        await ftp.store("file.txt", "file.txt")
+##        echo("File finished uploading")
+##      waitFor(main())
 ##
-##      waitFor main(ftp)
+## Checking the progress of a file transfer
+## ----------------------------------------
+##
+## The progress of either a file upload or a file download can be checked
+## by specifying a ``onProgressChanged`` procedure to the ``store`` or
+## ``retrFile`` procedures.
+##
+##   .. code-block::nim
+##      import asyncdispatch, asyncftpclient
+##
+##      proc onProgressChanged(total, progress: BiggestInt,
+##                              speed: float): Future[void] =
+##        echo("Uploaded ", progress, " of ", total, " bytes")
+##        echo("Current speed: ", speed, " kb/s")
+##
+##      proc main() {.async.} =
+##        var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test")
+##        await ftp.connect()
+##        await ftp.store("file.txt", "/home/user/file.txt", onProgressChanged)
+##        echo("File finished uploading")
+##      waitFor(main())
+
 
 import asyncdispatch, asyncnet, strutils, parseutils, os, times
 
diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim
index aa7d458b3..5d74896bf 100644
--- a/lib/pure/asynchttpserver.nim
+++ b/lib/pure/asynchttpserver.nim
@@ -67,6 +67,12 @@ type
     Http409 = "409 Conflict",
     Http410 = "410 Gone",
     Http411 = "411 Length Required",
+    Http412 = "412 Precondition Failed",
+    Http413 = "413 Request Entity Too Large",
+    Http414 = "414 Request-URI Too Long",
+    Http415 = "415 Unsupported Media Type",
+    Http416 = "416 Requested Range Not Satisfiable",
+    Http417 = "417 Expectation Failed",
     Http418 = "418 I'm a teapot",
     Http500 = "500 Internal Server Error",
     Http501 = "501 Not Implemented",
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index ba314af10..6b19a48be 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -56,7 +56,7 @@
 ##
 
 import asyncdispatch
-import rawsockets
+import nativesockets
 import net
 import os
 
@@ -112,8 +112,8 @@ proc newAsyncSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
   ##
   ## This procedure will also create a brand new file descriptor for
   ## this socket.
-  result = newAsyncSocket(newAsyncRawSocket(domain, sockType, protocol), domain,
-      sockType, protocol, buffered)
+  result = newAsyncSocket(newAsyncNativeSocket(domain, sockType, protocol),
+                          domain, sockType, protocol, buffered)
 
 proc newAsyncSocket*(domain, sockType, protocol: cint,
     buffered = true): AsyncSocket =
@@ -121,8 +121,9 @@ proc newAsyncSocket*(domain, sockType, protocol: cint,
   ##
   ## This procedure will also create a brand new file descriptor for
   ## this socket.
-  result = newAsyncSocket(newAsyncRawSocket(domain, sockType, protocol),
-      Domain(domain), SockType(sockType), Protocol(protocol), buffered)
+  result = newAsyncSocket(newAsyncNativeSocket(domain, sockType, protocol),
+                          Domain(domain), SockType(sockType),
+                          Protocol(protocol), buffered)
 
 when defined(ssl):
   proc getSslError(handle: SslPtr, err: cint): cint =
@@ -432,6 +433,7 @@ proc recvLine*(socket: AsyncSocket,
 
   # TODO: Optimise this
   var resString = newFutureVar[string]("asyncnet.recvLine")
+  resString.mget() = ""
   await socket.recvLineInto(resString, flags)
   result = resString.mget()
 
diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim
index deab39c7c..32d37ce02 100644
--- a/lib/pure/base64.nim
+++ b/lib/pure/base64.nim
@@ -8,6 +8,38 @@
 #
 
 ## This module implements a base64 encoder and decoder.
+##
+## Encoding data
+## -------------
+##
+## In order to encode some text simply call the ``encode`` procedure:
+##
+##   .. code-block::nim
+##      import base64
+##      let encoded = encode("Hello World")
+##      echo(encoded) # SGVsbG8gV29ybGQ=
+##
+## Apart from strings you can also encode lists of integers or characters:
+##
+##   .. code-block::nim
+##      import base64
+##      let encodedInts = encode([1,2,3])
+##      echo(encodedInts) # AQID
+##      let encodedChars = encode(['h','e','y'])
+##      echo(encodedChars) # aGV5
+##
+## The ``encode`` procedure takes an ``openarray`` so both arrays and sequences
+## can be passed as parameters.
+##
+## Decoding data
+## -------------
+##
+## To decode a base64 encoded data string simply call the ``decode``
+## procedure:
+##
+##   .. code-block::nim
+##      import base64
+##      echo(decode("SGVsbG8gV29ybGQ=")) # Hello World
 
 const
   cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
@@ -64,11 +96,16 @@ template encodeInternal(s: expr, lineLen: int, newLine: string): stmt {.immediat
 proc encode*[T:SomeInteger|char](s: openarray[T], lineLen = 75, newLine="\13\10"): string =
   ## encodes `s` into base64 representation. After `lineLen` characters, a
   ## `newline` is added.
+  ##
+  ## This procedure encodes an openarray (array or sequence) of either integers
+  ## or characters.
   encodeInternal(s, lineLen, newLine)
 
 proc encode*(s: string, lineLen = 75, newLine="\13\10"): string =
   ## encodes `s` into base64 representation. After `lineLen` characters, a
   ## `newline` is added.
+  ##
+  ## This procedure encodes a string.
   encodeInternal(s, lineLen, newLine)
 
 proc decodeByte(b: char): int {.inline.} =
diff --git a/lib/pure/basic2d.nim b/lib/pure/basic2d.nim
index ad8f8653d..7d74424fa 100644
--- a/lib/pure/basic2d.nim
+++ b/lib/pure/basic2d.nim
@@ -18,6 +18,8 @@ import strutils
 ##
 ## Quick start example:
 ##
+## .. code-block:: nim
+##
 ##   # Create a matrix which first rotates, then scales and at last translates
 ##
 ##   var m:Matrix2d=rotate(DEG90) & scale(2.0) & move(100.0,200.0)
@@ -93,11 +95,11 @@ let
   IDMATRIX*:Matrix2d=matrix2d(1.0,0.0,0.0,1.0,0.0,0.0)
     ## Quick access to an identity matrix
   ORIGO*:Point2d=point2d(0.0,0.0)
-    ## Quick acces to point (0,0)
+    ## Quick access to point (0,0)
   XAXIS*:Vector2d=vector2d(1.0,0.0)
-    ## Quick acces to an 2d x-axis unit vector
+    ## Quick access to an 2d x-axis unit vector
   YAXIS*:Vector2d=vector2d(0.0,1.0)
-    ## Quick acces to an 2d y-axis unit vector
+    ## Quick access to an 2d y-axis unit vector
 
 
 # ***************************************
diff --git a/lib/pure/basic3d.nim b/lib/pure/basic3d.nim
index 7fea54d58..424c191f8 100644
--- a/lib/pure/basic3d.nim
+++ b/lib/pure/basic3d.nim
@@ -23,6 +23,8 @@ import times
 ##
 ## Quick start example:
 ##
+## .. code-block:: nim
+##
 ##   # Create a matrix which first rotates, then scales and at last translates
 ##
 ##   var m:Matrix3d=rotate(PI,vector3d(1,1,2.5)) & scale(2.0) & move(100.0,200.0,300.0)
diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim
index 424bcdcca..09b20fd45 100644
--- a/lib/pure/collections/critbits.nim
+++ b/lib/pure/collections/critbits.nim
@@ -123,6 +123,14 @@ proc containsOrIncl*(c: var CritBitTree[void], key: string): bool =
   var n = rawInsert(c, key)
   result = c.count == oldCount
 
+proc inc*(c: var CritBitTree[int]; key: string) =
+  ## counts the 'key'.
+  let oldCount = c.count
+  var n = rawInsert(c, key)
+  if c.count == oldCount:
+    # not a new key:
+    inc n.val
+
 proc incl*(c: var CritBitTree[void], key: string) =
   ## includes `key` in `c`.
   discard rawInsert(c, key)
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index e6ea19a6b..fd012e811 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -47,7 +47,7 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
       result[i] = itm
       inc(i)
 
-proc repeat*[T](s: seq[T], n: Natural): seq[T] =
+proc cycle*[T](s: seq[T], n: Natural): seq[T] =
   ## Returns a new sequence with the items of `s` repeated `n` times.
   ##
   ## Example:
@@ -56,15 +56,29 @@ proc repeat*[T](s: seq[T], n: Natural): seq[T] =
   ##
   ##   let
   ##     s = @[1, 2, 3]
-  ##     total = s.repeat(3)
+  ##     total = s.cycle(3)
   ##   assert total == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
   result = newSeq[T](n * s.len)
   var o = 0
-  for x in 1..n:
+  for x in 0..<n:
     for e in s:
       result[o] = e
       inc o
 
+proc repeat*[T](x: T, n: Natural): seq[T] =
+  ## Returns a new sequence with the item `x` repeated `n` times.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:
+  ##
+  ##   let
+  ##     total = repeat(5, 3)
+  ##   assert total == @[5, 5, 5]
+  result = newSeq[T](n)
+  for i in 0..<n:
+    result[i] = x
+
 proc deduplicate*[T](seq1: seq[T]): seq[T] =
   ## Returns a new sequence without duplicates.
   ##
@@ -169,6 +183,77 @@ proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
       first = last
 
 
+proc map*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}):
+                                                            seq[S]{.inline.} =
+  ## Returns a new sequence with the results of `op` applied to every item in
+  ## `data`.
+  ##
+  ## Since the input is not modified you can use this version of ``map`` to
+  ## transform the type of the elements in the input sequence. Example:
+  ##
+  ## .. code-block:: nim
+  ##   let
+  ##     a = @[1, 2, 3, 4]
+  ##     b = map(a, proc(x: int): string = $x)
+  ##   assert b == @["1", "2", "3", "4"]
+  newSeq(result, data.len)
+  for i in 0..data.len-1: result[i] = op(data[i])
+
+proc map*[T](data: var openArray[T], op: proc (x: var T) {.closure.})
+                                                              {.deprecated.} =
+  ## Applies `op` to every item in `data` modifying it directly.
+  ##
+  ## Note that this version of ``map`` requires your input and output types to
+  ## be the same, since they are modified in-place. Example:
+  ##
+  ## .. code-block:: nim
+  ##   var a = @["1", "2", "3", "4"]
+  ##   echo repr(a)
+  ##   # --> ["1", "2", "3", "4"]
+  ##   map(a, proc(x: var string) = x &= "42")
+  ##   echo repr(a)
+  ##   # --> ["142", "242", "342", "442"]
+  ## **Deprecated since version 0.12.0:** Use the ``apply`` proc instead.
+  for i in 0..data.len-1: op(data[i])
+
+proc apply*[T](data: var seq[T], op: proc (x: var T) {.closure.})
+                                                              {.inline.} =
+  ## Applies `op` to every item in `data` modifying it directly.
+  ##
+  ## Note that this requires your input and output types to
+  ## be the same, since they are modified in-place.
+  ## The parameter function takes a ``var T`` type parameter.
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##   var a = @["1", "2", "3", "4"]
+  ##   echo repr(a)
+  ##   # --> ["1", "2", "3", "4"]
+  ##   map(a, proc(x: var string) = x &= "42")
+  ##   echo repr(a)
+  ##   # --> ["142", "242", "342", "442"]
+  ##
+  for i in 0..data.len-1: op(data[i])
+
+proc apply*[T](data: var seq[T], op: proc (x: T): T {.closure.})
+                                                              {.inline.} =
+  ## Applies `op` to every item in `data` modifying it directly.
+  ##
+  ## Note that this requires your input and output types to
+  ## be the same, since they are modified in-place.
+  ## The parameter function takes and returns a ``T`` type variable.
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##   var a = @["1", "2", "3", "4"]
+  ##   echo repr(a)
+  ##   # --> ["1", "2", "3", "4"]
+  ##   map(a, proc(x: string): string = x & "42")
+  ##   echo repr(a)
+  ##   # --> ["142", "242", "342", "442"]
+  ##
+  for i in 0..data.len-1: data[i] = op(data[i])
+
 
 iterator filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): T =
   ## Iterates through a sequence and yields every item that fulfills the
@@ -181,11 +266,12 @@ iterator filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): T =
   ##   for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
   ##     echo($n)
   ##   # echoes 4, 8, 4 in separate lines
-  for i in countup(0, len(seq1)-1):
-    var item = seq1[i]
-    if pred(item): yield seq1[i]
+  for i in 0..<seq1.len:
+    if pred(seq1[i]):
+      yield seq1[i]
 
-proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T] =
+proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T]
+                                                                  {.inline.} =
   ## Returns a new sequence with all the items that fulfilled the predicate.
   ##
   ## Example:
@@ -197,9 +283,13 @@ proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T] =
   ##     f2 = filter(colors) do (x: string) -> bool : x.len > 5
   ##   assert f1 == @["red", "black"]
   ##   assert f2 == @["yellow"]
-  accumulateResult(filter(seq1, pred))
+  result = newSeq[T]()
+  for i in 0..<seq1.len:
+    if pred(seq1[i]):
+      result.add(seq1[i])
 
-proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.}) =
+proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.})
+                                                                {.inline.} =
   ## Keeps the items in the passed sequence if they fulfilled the predicate.
   ## Same as the ``filter`` proc, but modifies the sequence directly.
   ##
@@ -213,7 +303,7 @@ proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.}) =
   for i in 0 .. <len(seq1):
     if pred(seq1[i]):
       if pos != i:
-        seq1[pos] = seq1[i]
+        shallowCopy(seq1[pos], seq1[i])
       inc(pos)
   setLen(seq1, pos)
 
@@ -268,7 +358,7 @@ proc insert*[T](dest: var seq[T], src: openArray[T], pos=0) =
     inc(j)
 
 
-template filterIt*(seq1, pred: expr): expr {.immediate.} =
+template filterIt*(seq1, pred: expr): expr =
   ## Returns a new sequence with all the items that fulfilled the predicate.
   ##
   ## Unlike the `proc` version, the predicate needs to be an expression using
@@ -282,12 +372,12 @@ template filterIt*(seq1, pred: expr): expr {.immediate.} =
   ##      notAcceptable = filterIt(temperatures, it > 50 or it < -10)
   ##    assert acceptable == @[-2.0, 24.5, 44.31]
   ##    assert notAcceptable == @[-272.15, 99.9, -113.44]
-  var result {.gensym.}: type(seq1) = @[]
+  var result {.gensym.} = newSeq[type(seq1[0])]()
   for it {.inject.} in items(seq1):
     if pred: result.add(it)
   result
 
-template keepItIf*(varSeq, pred: expr) =
+template keepItIf*(varSeq: seq, pred: expr) =
   ## Convenience template around the ``keepIf`` proc to reduce typing.
   ##
   ## Unlike the `proc` version, the predicate needs to be an expression using
@@ -303,7 +393,7 @@ template keepItIf*(varSeq, pred: expr) =
     let it {.inject.} = varSeq[i]
     if pred:
       if pos != i:
-        varSeq[pos] = varSeq[i]
+        shallowCopy(varSeq[pos], varSeq[i])
       inc(pos)
   setLen(varSeq, pos)
 
@@ -320,14 +410,19 @@ template toSeq*(iter: expr): expr {.immediate.} =
   ##       if x mod 2 == 1:
   ##         result = true)
   ##   assert odd_numbers == @[1, 3, 5, 7, 9]
-  ##
-  ## **Note**: Since this is an immediate macro, you cannot always invoke this
-  ## as ``x.toSeq``, depending on the ``x``.
-  ## See `this <manual.html#limitations-of-the-method-call-syntax>`_
-  ## for an explanation.
-  var result {.gensym.}: seq[type(iter)] = @[]
-  for x in iter: add(result, x)
-  result
+  
+  when compiles(iter.len):
+    var i = 0
+    var result = newSeq[type(iter)](iter.len)
+    for x in iter:
+      result[i] = x
+      inc i
+    result
+  else:
+    var result: seq[type(iter)] = @[]
+    for x in iter:
+      result.add(x)
+    result
 
 template foldl*(sequence, operation: expr): expr =
   ## Template to fold a sequence from left to right, returning the accumulation.
@@ -358,7 +453,7 @@ template foldl*(sequence, operation: expr): expr =
   assert sequence.len > 0, "Can't fold empty sequences"
   var result {.gensym.}: type(sequence[0])
   result = sequence[0]
-  for i in countup(1, sequence.len - 1):
+  for i in 1..<sequence.len:
     let
       a {.inject.} = result
       b {.inject.} = sequence[i]
@@ -401,7 +496,7 @@ template foldr*(sequence, operation: expr): expr =
     result = operation
   result
 
-template mapIt*(seq1, typ, op: expr): expr =
+template mapIt*(seq1, typ, op: expr): expr {.deprecated.}=
   ## Convenience template around the ``map`` proc to reduce typing.
   ##
   ## The template injects the ``it`` variable which you can use directly in an
@@ -414,13 +509,45 @@ template mapIt*(seq1, typ, op: expr): expr =
   ##     nums = @[1, 2, 3, 4]
   ##     strings = nums.mapIt(string, $(4 * it))
   ##   assert strings == @["4", "8", "12", "16"]
+  ## **Deprecated since version 0.12.0:** Use the ``mapIt(seq1, op)``
+  ##   template instead.
   var result {.gensym.}: seq[typ] = @[]
   for it {.inject.} in items(seq1):
     result.add(op)
   result
 
-template mapIt*(varSeq, op: expr) =
-  ## Convenience template around the mutable ``map`` proc to reduce typing.
+
+template mapIt*(seq1, op: expr): expr =
+  ## Convenience template around the ``map`` proc to reduce typing.
+  ##
+  ## The template injects the ``it`` variable which you can use directly in an
+  ## expression. Example:
+  ##
+  ## .. code-block::
+  ##   let
+  ##     nums = @[1, 2, 3, 4]
+  ##     strings = nums.mapIt($(4 * it))
+  ##   assert strings == @["4", "8", "12", "16"]
+  type outType = type((
+    block:
+      var it{.inject.}: type(items(seq1));
+      op))
+  var result: seq[outType]
+  when compiles(seq1.len):
+    let s = seq1
+    var i = 0
+    result = newSeq[outType](s.len)
+    for it {.inject.} in s:
+      result[i] = op
+      i += 1
+  else:
+    result = @[]
+    for it {.inject.} in seq1:
+      result.add(op)
+  result
+
+template applyIt*(varSeq, op: expr) =
+  ## Convenience template around the mutable ``apply`` proc to reduce typing.
   ##
   ## The template injects the ``it`` variable which you can use directly in an
   ## expression. The expression has to return the same type as the sequence you
@@ -428,12 +555,14 @@ template mapIt*(varSeq, op: expr) =
   ##
   ## .. code-block::
   ##   var nums = @[1, 2, 3, 4]
-  ##   nums.mapIt(it * 3)
+  ##   nums.applyIt(it * 3)
   ##   assert nums[0] + nums[3] == 15
-  for i in 0 .. <len(varSeq):
+  for i in 0 .. <varSeq.len:
     let it {.inject.} = varSeq[i]
     varSeq[i] = op
 
+
+
 template newSeqWith*(len: int, init: expr): expr =
   ## creates a new sequence, calling `init` to initialize each value. Example:
   ##
@@ -568,8 +697,8 @@ when isMainModule:
   block: # mapIt tests
     var
       nums = @[1, 2, 3, 4]
-      strings = nums.mapIt(string, $(4 * it))
-    nums.mapIt(it * 3)
+      strings = nums.mapIt($(4 * it))
+    nums.applyIt(it * 3)
     assert nums[0] + nums[3] == 15
 
   block: # distribute tests
@@ -605,15 +734,19 @@ when isMainModule:
     seq2D[0][1] = true
     doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
 
-  block: # repeat tests
+  block: # cycle tests
     let
       a = @[1, 2, 3]
       b: seq[int] = @[]
 
-    doAssert a.repeat(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
-    doAssert a.repeat(0) == @[]
-    #doAssert a.repeat(-1) == @[] # will not compile!
-    doAssert b.repeat(3) == @[]
+    doAssert a.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
+    doAssert a.cycle(0) == @[]
+    #doAssert a.cycle(-1) == @[] # will not compile!
+    doAssert b.cycle(3) == @[]
+
+  block: # repeat tests
+    assert repeat(10, 5) == @[10, 10, 10, 10, 10]
+    assert repeat(@[1,2,3], 2) == @[@[1,2,3], @[1,2,3]]
 
   when not defined(testing):
     echo "Finished doc tests"
diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim
index 8fa529474..c5724f26f 100644
--- a/lib/pure/coro.nim
+++ b/lib/pure/coro.nim
@@ -119,7 +119,7 @@ proc wait*(c: proc(), interval=0.01) =
   while alive(c):
     suspend interval
 
-when isMainModule:
+when defined(nimCoroutines) and isMainModule:
   var stackCheckValue = 1100220033
   proc c2()
 
diff --git a/lib/pure/coro.nimcfg b/lib/pure/coro.nimcfg
new file mode 100644
index 000000000..b011bc585
--- /dev/null
+++ b/lib/pure/coro.nimcfg
@@ -0,0 +1 @@
+-d:nimCoroutines
diff --git a/lib/pure/future.nim b/lib/pure/future.nim
index 661afd7b3..4767266e5 100644
--- a/lib/pure/future.nim
+++ b/lib/pure/future.nim
@@ -75,7 +75,7 @@ macro `=>`*(p, b: expr): expr {.immediate.} =
         identDefs.add(newEmptyNode())
       of nnkIdent:
         identDefs.add(c)
-        identDefs.add(newEmptyNode())
+        identDefs.add(newIdentNode("auto"))
         identDefs.add(newEmptyNode())
       of nnkInfix:
         if c[0].kind == nnkIdent and c[0].ident == !"->":
@@ -93,7 +93,7 @@ macro `=>`*(p, b: expr): expr {.immediate.} =
   of nnkIdent:
     var identDefs = newNimNode(nnkIdentDefs)
     identDefs.add(p)
-    identDefs.add(newEmptyNode())
+    identDefs.add(newIdentNode("auto"))
     identDefs.add(newEmptyNode())
     params.add(identDefs)
   of nnkInfix:
diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim
index 61c16129b..11af81149 100644
--- a/lib/pure/hashes.nim
+++ b/lib/pure/hashes.nim
@@ -8,9 +8,10 @@
 #
 
 ## This module implements efficient computations of hash values for diverse
-## Nim types. All the procs are based on these two building blocks: the `!&
-## proc <#!&>`_ used to start or mix a hash value, and the `!$ proc <#!$>`_
-## used to *finish* the hash value.  If you want to implement hash procs for
+## Nim types. All the procs are based on these two building blocks:
+## - `!& proc <#!&>`_ used to start or mix a hash value, and
+## - `!$ proc <#!$>`_ used to *finish* the hash value.
+## If you want to implement hash procs for
 ## your custom types you will end up writing the following kind of skeleton of
 ## code:
 ##
@@ -108,7 +109,7 @@ proc hash*(x: int): Hash {.inline.} =
   result = x
 
 proc hash*(x: int64): Hash {.inline.} =
-  ## efficient hashing of integers
+  ## efficient hashing of int64 integers
   result = toU32(x)
 
 proc hash*(x: char): Hash {.inline.} =
@@ -126,6 +127,16 @@ proc hash*(x: string): Hash =
     h = h !& ord(x[i])
   result = !$h
 
+proc hash*(sBuf: string, sPos, ePos: int): Hash =
+  ## efficient hashing of a string buffer, from starting
+  ## position `sPos` to ending position `ePos`
+  ##
+  ## ``hash(myStr, 0, myStr.high)`` is equivalent to ``hash(myStr)``
+  var h: Hash = 0
+  for i in sPos..ePos:
+    h = h !& ord(sBuf[i])
+  result = !$h
+
 proc hashIgnoreStyle*(x: string): Hash =
   ## efficient hashing of strings; style is ignored
   var h: Hash = 0
@@ -145,6 +156,27 @@ proc hashIgnoreStyle*(x: string): Hash =
 
   result = !$h
 
+proc hashIgnoreStyle*(sBuf: string, sPos, ePos: int): Hash =
+  ## efficient hashing of a string buffer, from starting
+  ## position `sPos` to ending position `ePos`; style is ignored
+  ##
+  ## ``hashIgnoreStyle(myBuf, 0, myBuf.high)`` is equivalent
+  ## to ``hashIgnoreStyle(myBuf)``
+  var h: Hash = 0
+  var i = sPos
+  while i <= ePos:
+    var c = sBuf[i]
+    if c == '_':
+      inc(i)
+    elif isMagicIdentSeparatorRune(cstring(sBuf), i):
+      inc(i, magicIdentSeparatorRuneByteWidth)
+    else:
+      if c in {'A'..'Z'}:
+        c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
+      h = h !& ord(c)
+      inc(i)
+  result = !$h
+
 proc hashIgnoreCase*(x: string): Hash =
   ## efficient hashing of strings; case is ignored
   var h: Hash = 0
@@ -155,7 +187,22 @@ proc hashIgnoreCase*(x: string): Hash =
     h = h !& ord(c)
   result = !$h
 
+proc hashIgnoreCase*(sBuf: string, sPos, ePos: int): Hash =
+  ## efficient hashing of a string buffer, from starting
+  ## position `sPos` to ending position `ePos`; case is ignored
+  ##
+  ## ``hashIgnoreCase(myBuf, 0, myBuf.high)`` is equivalent
+  ## to ``hashIgnoreCase(myBuf)``
+  var h: Hash = 0
+  for i in sPos..ePos:
+    var c = sBuf[i]
+    if c in {'A'..'Z'}:
+      c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
+    h = h !& ord(c)
+  result = !$h
+
 proc hash*(x: float): Hash {.inline.} =
+  ## efficient hashing of floats.
   var y = x + 1.0
   result = cast[ptr Hash](addr(y))[]
 
@@ -173,10 +220,29 @@ proc hash*[T: tuple](x: T): Hash =
   result = !$result
 
 proc hash*[A](x: openArray[A]): Hash =
+  ## efficient hashing of arrays and sequences.
   for it in items(x): result = result !& hash(it)
   result = !$result
 
+proc hash*[A](aBuf: openArray[A], sPos, ePos: int): Hash =
+  ## efficient hashing of portions of arrays and sequences.
+  ##
+  ## ``hash(myBuf, 0, myBuf.high)`` is equivalent to ``hash(myBuf)``
+  for i in sPos..ePos:
+    result = result !& hash(aBuf[i])
+  result = !$result
+
 proc hash*[A](x: set[A]): Hash =
+  ## efficient hashing of sets.
   for it in items(x): result = result !& hash(it)
   result = !$result
 
+when isMainModule:
+  doAssert( hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13) )
+  doAssert( hashIgnoreCase("aa bb aaaa1234") == hash("aa bb aaaa1234") )
+  doAssert( hashIgnoreStyle("aa bb aaaa1234") == hashIgnoreCase("aa bb aaaa1234") )
+  let xx = @['H','e','l','l','o']
+  let ss = "Hello"
+  doAssert( hash(xx) == hash(ss) )
+  doAssert( hash(xx) == hash(xx, 0, xx.high) )
+  doAssert( hash(ss) == hash(ss, 0, ss.high) )
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 30b838b7e..a5d4ec1a1 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -81,7 +81,7 @@
 
 import net, strutils, uri, parseutils, strtabs, base64, os, mimetypes, math
 import asyncnet, asyncdispatch
-import rawsockets
+import nativesockets
 
 type
   Response* = tuple[
@@ -764,10 +764,10 @@ proc newConnection(client: AsyncHttpClient, url: Uri) {.async.} =
     let port =
       if url.port == "":
         if url.scheme.toLower() == "https":
-          rawsockets.Port(443)
+          nativesockets.Port(443)
         else:
-          rawsockets.Port(80)
-      else: rawsockets.Port(url.port.parseInt)
+          nativesockets.Port(80)
+      else: nativesockets.Port(url.port.parseInt)
 
     if url.scheme.toLower() == "https":
       when defined(ssl):
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index abf6305f2..06d5a13e2 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -622,9 +622,12 @@ proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
 proc getFNum*(n: JsonNode, default: float = 0.0): float =
   ## Retrieves the float value of a `JFloat JsonNode`.
   ##
-  ## Returns ``default`` if ``n`` is not a ``JFloat``, or if ``n`` is nil.
-  if n.isNil or n.kind != JFloat: return default
-  else: return n.fnum
+  ## Returns ``default`` if ``n`` is not a ``JFloat`` or ``JInt``, or if ``n`` is nil.
+  if n.isNil: return default
+  case n.kind
+  of JFloat: return n.fnum
+  of JInt: return float(n.num)
+  else: return default
 
 proc getBVal*(n: JsonNode, default: bool = false): bool =
   ## Retrieves the bool value of a `JBool JsonNode`.
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
index 7a900daae..aa55b5ade 100644
--- a/lib/pure/logging.nim
+++ b/lib/pure/logging.nim
@@ -77,7 +77,7 @@ type
                                         ## console
 
   FileLogger* = ref object of Logger ## logger that writes the messages to a file
-    f: File
+    file*: File  ## the wrapped file.
 
   RollingFileLogger* = ref object of FileLogger ## logger that writes the
                                                 ## messages to a file and
@@ -92,7 +92,9 @@ type
 {.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger,
     PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].}
 
-proc substituteLog(frmt: string, level: Level, args: varargs[string, `$`]): string =
+proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): string =
+  ## Format a log message using the ``frmt`` format string, ``level`` and varargs.
+  ## See the module documentation for the format string syntax.
   var msgLen = 0
   for arg in args:
     msgLen += arg.len
@@ -124,7 +126,7 @@ proc substituteLog(frmt: string, level: Level, args: varargs[string, `$`]): stri
 
 method log*(logger: Logger, level: Level, args: varargs[string, `$`]) {.
             raises: [Exception],
-            tags: [TimeEffect, WriteIOEffect, ReadIOEffect].} =
+            tags: [TimeEffect, WriteIOEffect, ReadIOEffect], base.} =
   ## Override this method in custom loggers. Default implementation does
   ## nothing.
   discard
@@ -133,15 +135,17 @@ method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) =
   ## Logs to the console using ``logger`` only.
   if 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 >= logger.levelThreshold:
-    writeLine(logger.f, substituteLog(logger.fmtStr, level, args))
+    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, ext) = splitFile(getAppFilename())
+  var (path, name, _) = splitFile(getAppFilename())
   result = changeFileExt(path / name, "log")
 
 proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): ConsoleLogger =
@@ -160,14 +164,14 @@ proc newFileLogger*(filename = defaultFilename(),
   ## (-1: use system defaults, 0: unbuffered, >0: fixed buffer size).
   new(result)
   result.levelThreshold = levelThreshold
-  result.f = open(filename, mode, bufSize = bufSize)
+  result.file = open(filename, mode, bufSize = bufSize)
   result.fmtStr = fmtStr
 
 # ------
 
 proc countLogLines(logger: RollingFileLogger): int =
   result = 0
-  for line in logger.f.lines():
+  for line in logger.file.lines():
     result.inc()
 
 proc countFiles(filename: string): int =
@@ -200,7 +204,7 @@ proc newRollingFileLogger*(filename = defaultFilename(),
   result.fmtStr = fmtStr
   result.maxLines = maxLines
   result.bufSize = bufSize
-  result.f = open(filename, mode, bufSize=result.bufSize)
+  result.file = open(filename, mode, bufSize=result.bufSize)
   result.curLine = 0
   result.baseName = filename
   result.baseMode = mode
@@ -222,13 +226,14 @@ method log*(logger: RollingFileLogger, level: Level, args: varargs[string, `$`])
   ## Logs to a file using rolling ``logger`` only.
   if level >= logger.levelThreshold:
     if logger.curLine >= logger.maxLines:
-      logger.f.close()
+      logger.file.close()
       rotate(logger)
       logger.logFiles.inc
       logger.curLine = 0
-      logger.f = open(logger.baseName, logger.baseMode, bufSize = logger.bufSize)
+      logger.file = open(logger.baseName, logger.baseMode, bufSize = logger.bufSize)
 
-    writeLine(logger.f, substituteLog(logger.fmtStr, level, args))
+    writeLine(logger.file, substituteLog(logger.fmtStr, level, args))
+    if level in {lvlError, lvlFatal}: flushFile(logger.file)
     logger.curLine.inc
 
 # --------
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index c1d5c9439..391a880ae 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -21,6 +21,20 @@ include "system/inclrtl"
 {.push debugger:off .} # the user does not want to trace a part
                        # of the standard library!
 
+proc binom*(n, k: int): int {.noSideEffect.} =
+  ## Computes the binomial coefficient
+  if k <= 0: return 1
+  if 2*k > n: return binom(n, n-k)
+  result = n
+  for i in countup(2, k):
+    result = (result * (n + 1 - i)) div i
+
+proc fac*(n: int): int {.noSideEffect.} =
+  ## Computes the faculty/factorial function.
+  result = 1
+  for i in countup(2, n):
+    result = result * i
+
 {.push checks:off, line_dir:off, stack_trace:off.}
 
 when defined(Posix) and not defined(haiku):
@@ -72,21 +86,6 @@ proc classify*(x: float): FloatClass =
   return fcNormal
   # XXX: fcSubnormal is not detected!
 
-
-proc binom*(n, k: int): int {.noSideEffect.} =
-  ## Computes the binomial coefficient
-  if k <= 0: return 1
-  if 2*k > n: return binom(n, n-k)
-  result = n
-  for i in countup(2, k):
-    result = (result * (n + 1 - i)) div i
-
-proc fac*(n: int): int {.noSideEffect.} =
-  ## Computes the faculty/factorial function.
-  result = 1
-  for i in countup(2, n):
-    result = result * i
-
 proc isPowerOfTwo*(x: int): bool {.noSideEffect.} =
   ## Returns true, if `x` is a power of two, false otherwise.
   ## Zero and negative numbers are not a power of two.
@@ -476,7 +475,7 @@ when isMainModule and not defined(JS):
     return sqrt(num)
 
   # check gamma function
-  assert(tgamma(5.0) == 24.0) # 4!
+  assert($tgamma(5.0) == $24.0) # 4!
   assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0
   assert(erf(6.0) > erf(5.0))
   assert(erfc(6.0) < erfc(5.0))
diff --git a/lib/pure/md5.nim b/lib/pure/md5.nim
index 5ee301b15..44b9ed0d4 100644
--- a/lib/pure/md5.nim
+++ b/lib/pure/md5.nim
@@ -9,8 +9,6 @@
 
 ## Module for computing MD5 checksums.
 
-import unsigned
-
 type
   MD5State = array[0..3, uint32]
   MD5Block = array[0..15, uint32]
diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim
index 27b989597..b9c574944 100644
--- a/lib/pure/memfiles.nim
+++ b/lib/pure/memfiles.nim
@@ -32,8 +32,9 @@ type
     size*: int       ## size of the memory mapped file
 
     when defined(windows):
-      fHandle: int
-      mapHandle: int
+      fHandle: Handle
+      mapHandle: Handle
+      wasOpened: bool   ## only close if wasOpened
     else:
       handle: cint
 
@@ -115,7 +116,8 @@ proc open*(filename: string, mode: FileMode = fmRead,
     template callCreateFile(winApiProc, filename: expr): expr =
       winApiProc(
         filename,
-        if readonly: GENERIC_READ else: GENERIC_ALL,
+        # GENERIC_ALL != (GENERIC_READ or GENERIC_WRITE)
+        if readonly: GENERIC_READ else: GENERIC_READ or GENERIC_WRITE,
         FILE_SHARE_READ,
         nil,
         if newFileSize != -1: CREATE_ALWAYS else: OPEN_EXISTING,
@@ -172,6 +174,8 @@ proc open*(filename: string, mode: FileMode = fmRead,
       if mappedSize != -1: result.size = min(fileSize, mappedSize).int
       else: result.size = fileSize.int
 
+    result.wasOpened = true
+
   else:
     template fail(errCode: OSErrorCode, msg: expr) =
       rollback()
@@ -226,7 +230,7 @@ proc close*(f: var MemFile) =
   var lastErr: OSErrorCode
 
   when defined(windows):
-    if f.fHandle != INVALID_HANDLE_VALUE:
+    if f.fHandle != INVALID_HANDLE_VALUE and f.wasOpened:
       error = unmapViewOfFile(f.mem) == 0
       lastErr = osLastError()
       error = (closeHandle(f.mapHandle) == 0) or error
@@ -243,6 +247,7 @@ proc close*(f: var MemFile) =
   when defined(windows):
     f.fHandle = 0
     f.mapHandle = 0
+    f.wasOpened = false
   else:
     f.handle = 0
 
diff --git a/lib/pure/rawsockets.nim b/lib/pure/nativesockets.nim
index f5860ef28..c9e067a3e 100644
--- a/lib/pure/rawsockets.nim
+++ b/lib/pure/nativesockets.nim
@@ -93,8 +93,8 @@ when useWinVersion:
     IOC_IN* = int(-2147483648)
     FIONBIO* = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or
                              (102 shl 8) or 126
-    rawAfInet = winlean.AF_INET
-    rawAfInet6 = winlean.AF_INET6
+    nativeAfInet = winlean.AF_INET
+    nativeAfInet6 = winlean.AF_INET6
 
   proc ioctlsocket*(s: SocketHandle, cmd: clong,
                    argptr: ptr clong): cint {.
@@ -102,8 +102,8 @@ when useWinVersion:
 else:
   let
     osInvalidSocket* = posix.INVALID_SOCKET
-    rawAfInet = posix.AF_INET
-    rawAfInet6 = posix.AF_INET6
+    nativeAfInet = posix.AF_INET
+    nativeAfInet6 = posix.AF_INET6
 
 proc `==`*(a, b: Port): bool {.borrow.}
   ## ``==`` for ports.
@@ -157,12 +157,14 @@ else:
     result = cint(ord(p))
 
 
-proc newRawSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
-             protocol: Protocol = IPPROTO_TCP): SocketHandle =
+proc newNativeSocket*(domain: Domain = AF_INET,
+                      sockType: SockType = SOCK_STREAM,
+                      protocol: Protocol = IPPROTO_TCP): SocketHandle =
   ## Creates a new socket; returns `InvalidSocket` if an error occurs.
   socket(toInt(domain), toInt(sockType), toInt(protocol))
 
-proc newRawSocket*(domain: cint, sockType: cint, protocol: cint): SocketHandle =
+proc newNativeSocket*(domain: cint, sockType: cint,
+                      protocol: cint): SocketHandle =
   ## Creates a new socket; returns `InvalidSocket` if an error occurs.
   ##
   ## Use this overload if one of the enums specified above does
@@ -201,7 +203,9 @@ proc getAddrInfo*(address: string, port: Port, domain: Domain = AF_INET,
   hints.ai_family = toInt(domain)
   hints.ai_socktype = toInt(sockType)
   hints.ai_protocol = toInt(protocol)
-  hints.ai_flags = AI_V4MAPPED
+  # https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=198092
+  when not defined(freebsd):
+    hints.ai_flags = AI_V4MAPPED
   var gaiResult = getaddrinfo(address, $port, addr(hints), result)
   if gaiResult != 0'i32:
     when useWinVersion:
@@ -229,17 +233,17 @@ proc ntohs*(x: int16): int16 =
   when cpuEndian == bigEndian: result = x
   else: result = (x shr 8'i16) or (x shl 8'i16)
 
-proc htonl*(x: int32): int32 =
+template htonl*(x: int32): expr =
   ## Converts 32-bit integers from host to network byte order. On machines
   ## where the host byte order is the same as network byte order, this is
   ## a no-op; otherwise, it performs a 4-byte swap operation.
-  result = rawsockets.ntohl(x)
+  nativesockets.ntohl(x)
 
-proc htons*(x: int16): int16 =
+template htons*(x: int16): expr =
   ## Converts 16-bit positive integers from host to network byte order.
   ## On machines where the host byte order is the same as network byte
   ## order, this is a no-op; otherwise, it performs a 2-byte swap operation.
-  result = rawsockets.ntohs(x)
+  nativesockets.ntohs(x)
 
 proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} =
   ## Searches the database from the beginning and finds the first entry for
@@ -280,7 +284,7 @@ proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} =
 
   when useWinVersion:
     var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
-                                  cint(rawsockets.AF_INET))
+                                  cint(AF_INET))
     if s == nil: raiseOSError(osLastError())
   else:
     var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).Socklen,
@@ -330,9 +334,9 @@ proc getSockDomain*(socket: SocketHandle): Domain =
   if getsockname(socket, cast[ptr SockAddr](addr(name)),
                  addr(namelen)) == -1'i32:
     raiseOSError(osLastError())
-  if name.sa_family == rawAfInet:
+  if name.sa_family == nativeAfInet:
     result = AF_INET
-  elif name.sa_family == rawAfInet6:
+  elif name.sa_family == nativeAfInet6:
     result = AF_INET6
   else:
     raiseOSError(osLastError(), "unknown socket family in getSockFamily")
@@ -340,12 +344,11 @@ proc getSockDomain*(socket: SocketHandle): Domain =
 
 proc getAddrString*(sockAddr: ptr SockAddr): string =
   ## return the string representation of address within sockAddr
-  if sockAddr.sa_family == rawAfInet:
+  if sockAddr.sa_family == nativeAfInet:
     result = $inet_ntoa(cast[ptr Sockaddr_in](sockAddr).sin_addr)
-  elif sockAddr.sa_family == rawAfInet6:
+  elif sockAddr.sa_family == nativeAfInet6:
     when not useWinVersion:
       # TODO: Windows
-      var v6addr = cast[ptr Sockaddr_in6](sockAddr).sin6_addr
       result = newString(posix.INET6_ADDRSTRLEN)
       let addr6 = addr cast[ptr Sockaddr_in6](sockAddr).sin6_addr
       discard posix.inet_ntop(posix.AF_INET6, addr6, result.cstring,
@@ -369,7 +372,7 @@ proc getSockName*(socket: SocketHandle): Port =
   if getsockname(socket, cast[ptr SockAddr](addr(name)),
                  addr(namelen)) == -1'i32:
     raiseOSError(osLastError())
-  result = Port(rawsockets.ntohs(name.sin_port))
+  result = Port(nativesockets.ntohs(name.sin_port))
 
 proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
   ## returns the socket's local address and port number.
@@ -386,7 +389,8 @@ proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
     if getsockname(socket, cast[ptr SockAddr](addr(name)),
                    addr(namelen)) == -1'i32:
       raiseOSError(osLastError())
-    result = ($inet_ntoa(name.sin_addr), Port(rawsockets.ntohs(name.sin_port)))
+    result = ($inet_ntoa(name.sin_addr),
+              Port(nativesockets.ntohs(name.sin_port)))
   of AF_INET6:
     var name: Sockaddr_in6
     when useWinVersion:
@@ -402,7 +406,7 @@ proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
     if inet_ntop(name.sin6_family.cint,
                  addr name, buf.cstring, sizeof(buf).int32).isNil:
       raiseOSError(osLastError())
-    result = ($buf, Port(rawsockets.ntohs(name.sin6_port)))
+    result = ($buf, Port(nativesockets.ntohs(name.sin6_port)))
   else:
     raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr")
 
@@ -421,7 +425,8 @@ proc getPeerAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
     if getpeername(socket, cast[ptr SockAddr](addr(name)),
                    addr(namelen)) == -1'i32:
       raiseOSError(osLastError())
-    result = ($inet_ntoa(name.sin_addr), Port(rawsockets.ntohs(name.sin_port)))
+    result = ($inet_ntoa(name.sin_addr),
+              Port(nativesockets.ntohs(name.sin_port)))
   of AF_INET6:
     var name: Sockaddr_in6
     when useWinVersion:
@@ -437,7 +442,7 @@ proc getPeerAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
     if inet_ntop(name.sin6_family.cint,
                  addr name, buf.cstring, sizeof(buf).int32).isNil:
       raiseOSError(osLastError())
-    result = ($buf, Port(rawsockets.ntohs(name.sin6_port)))
+    result = ($buf, Port(nativesockets.ntohs(name.sin6_port)))
   else:
     raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr")
 
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index 0ce5b4d25..d1016011e 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -10,7 +10,7 @@
 ## This module implements a high-level cross-platform sockets interface.
 
 {.deadCodeElim: on.}
-import rawsockets, os, strutils, unsigned, parseutils, times
+import nativesockets, os, strutils, unsigned, parseutils, times
 export Port, `$`, `==`
 
 const useWinVersion = defined(Windows) or defined(nimdoc)
@@ -145,7 +145,7 @@ proc newSocket*(domain, sockType, protocol: cint, buffered = true): Socket =
   ## Creates a new socket.
   ##
   ## If an error occurs EOS will be raised.
-  let fd = newRawSocket(domain, sockType, protocol)
+  let fd = newNativeSocket(domain, sockType, protocol)
   if fd == osInvalidSocket:
     raiseOSError(osLastError())
   result = newSocket(fd, domain.Domain, sockType.SockType, protocol.Protocol,
@@ -156,7 +156,7 @@ proc newSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
   ## Creates a new socket.
   ##
   ## If an error occurs EOS will be raised.
-  let fd = newRawSocket(domain, sockType, protocol)
+  let fd = newNativeSocket(domain, sockType, protocol)
   if fd == osInvalidSocket:
     raiseOSError(osLastError())
   result = newSocket(fd, domain, sockType, protocol, buffered)
@@ -223,10 +223,7 @@ when defined(ssl):
     of protSSLv23:
       newCTX = SSL_CTX_new(SSLv23_method()) # SSlv2,3 and TLS1 support.
     of protSSLv2:
-      when not defined(linux):
-        newCTX = SSL_CTX_new(SSLv2_method())
-      else:
-        raiseSslError()
+      raiseSslError("SSLv2 is no longer secure and has been deprecated, use protSSLv3")
     of protSSLv3:
       newCTX = SSL_CTX_new(SSLv3_method())
     of protTLSv1:
@@ -357,7 +354,7 @@ proc listen*(socket: Socket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
   ## queue of pending connections.
   ##
   ## Raises an EOS error upon failure.
-  if rawsockets.listen(socket.fd, backlog) < 0'i32:
+  if nativesockets.listen(socket.fd, backlog) < 0'i32:
     raiseOSError(osLastError())
 
 proc bindAddr*(socket: Socket, port = Port(0), address = "") {.
diff --git a/lib/pure/options.nim b/lib/pure/options.nim
index ef01e1260..3122d58b1 100644
--- a/lib/pure/options.nim
+++ b/lib/pure/options.nim
@@ -108,6 +108,36 @@ proc get*[T](self: Option[T]): T =
     raise UnpackError(msg : "Can't obtain a value from a `none`")
   self.val
 
+proc get*[T](self: Option[T], otherwise: T): T =
+  ## Returns the contents of this option or `otherwise` if the option is none.
+  if self.isSome:
+    self.val
+  else:
+    otherwise
+
+
+proc map*[T](self: Option[T], callback: proc (input: T)) =
+  ## Applies a callback to the value in this Option
+  if self.has:
+    callback(self.val)
+
+proc map*[T, R](self: Option[T], callback: proc (input: T): R): Option[R] =
+  ## Applies a callback to the value in this Option and returns an option
+  ## containing the new value. If this option is None, None will be returned
+  if self.has:
+    some[R]( callback(self.val) )
+  else:
+    none(R)
+
+proc filter*[T](self: Option[T], callback: proc (input: T): bool): Option[T] =
+  ## Applies a callback to the value in this Option. If the callback returns
+  ## `true`, the option is returned as a Some. If it returns false, it is
+  ## returned as a None.
+  if self.has and not callback(self.val):
+    none(T)
+  else:
+    self
+
 
 proc `==`*(a, b: Option): bool =
   ## Returns ``true`` if both ``Option``s are ``none``,
@@ -115,8 +145,16 @@ proc `==`*(a, b: Option): bool =
   (a.has and b.has and a.val == b.val) or (not a.has and not b.has)
 
 
+proc `$`*[T]( self: Option[T] ): string =
+  ## Returns the contents of this option or `otherwise` if the option is none.
+  if self.has:
+    "Some(" & $self.val & ")"
+  else:
+    "None[" & T.name & "]"
+
+
 when isMainModule:
-  import unittest
+  import unittest, sequtils
 
   suite "optionals":
     # work around a bug in unittest
@@ -158,3 +196,27 @@ when isMainModule:
         check false
       when compiles(none(string) == none(int)):
         check false
+
+    test "get with a default value":
+      check( some("Correct").get("Wrong") == "Correct" )
+      check( stringNone.get("Correct") == "Correct" )
+
+    test "$":
+      check( $(some("Correct")) == "Some(Correct)" )
+      check( $(stringNone) == "None[string]" )
+
+    test "map with a void result":
+      var procRan = 0
+      some(123).map(proc (v: int) = procRan = v)
+      check procRan == 123
+      intNone.map(proc (v: int) = check false)
+
+    test "map":
+      check( some(123).map(proc (v: int): int = v * 2) == some(246) )
+      check( intNone.map(proc (v: int): int = v * 2).isNone )
+
+    test "filter":
+      check( some(123).filter(proc (v: int): bool = v == 123) == some(123) )
+      check( some(456).filter(proc (v: int): bool = v == 123).isNone )
+      check( intNone.filter(proc (v: int): bool = check false).isNone )
+
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index f413371cb..c01228563 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -810,11 +810,12 @@ type
 
 {.deprecated: [TPathComponent: PathComponent].}
 
-iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {.
+iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: string] {.
   tags: [ReadDirEffect].} =
   ## walks over the directory `dir` and yields for each directory or file in
   ## `dir`. The component type and full path for each item is returned.
-  ## Walking is not recursive.
+  ## Walking is not recursive. If ``relative`` is true the resulting path is
+  ## shortened to be relative to ``dir``.
   ## Example: This directory structure::
   ##   dirA / dirB / fileB1.txt
   ##        / dirC
@@ -843,7 +844,9 @@ iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {.
             k = pcDir
           if (f.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32:
             k = succ(k)
-          yield (k, dir / extractFilename(getFilename(f)))
+          let xx = if relative: extractFilename(getFilename(f))
+                   else: dir / extractFilename(getFilename(f))
+          yield (k, xx)
         if findNextFile(h, f) == 0'i32: break
       findClose(h)
   else:
@@ -855,7 +858,8 @@ iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {.
         var y = $x.d_name
         if y != "." and y != "..":
           var s: Stat
-          y = dir / y
+          if not relative:
+            y = dir / y
           var k = pcFile
 
           when defined(linux) or defined(macosx) or defined(bsd):
diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim
index 99f6bcd4d..e9f5bee0a 100644
--- a/lib/pure/ospaths.nim
+++ b/lib/pure/ospaths.nim
@@ -10,6 +10,10 @@
 # Included by the ``os`` module but a module in its own right for NimScript
 # support.
 
+when isMainModule:
+  {.pragma: rtl.}
+  import strutils
+
 when defined(nimscript) or (defined(nimdoc) and not declared(os)):
   {.pragma: rtl.}
   {.push hint[ConvFromXtoItselfNotNeeded]:off.}
@@ -22,8 +26,10 @@ when not declared(getEnv) or defined(nimscript):
                                               ## to an environment variable
 
     ReadDirEffect* = object of ReadIOEffect   ## effect that denotes a write
-                                              ## operation to the directory structure
-    WriteDirEffect* = object of WriteIOEffect ## effect that denotes a write operation to
+                                              ## operation to the directory
+                                              ## structure
+    WriteDirEffect* = object of WriteIOEffect ## effect that denotes a write
+                                              ## operation to
                                               ## the directory structure
 
     OSErrorCode* = distinct int32 ## Specifies an OS Error Code.
@@ -59,13 +65,13 @@ when not declared(getEnv) or defined(nimscript):
       AltSep* = '/'
         ## An alternative character used by the operating system to separate
         ## pathname components, or the same as `DirSep` if only one separator
-        ## character exists. This is set to '/' on Windows systems where `DirSep`
-        ## is a backslash.
+        ## character exists. This is set to '/' on Windows systems
+        ## where `DirSep` is a backslash.
 
       PathSep* = ':'
         ## The character conventionally used by the operating system to separate
-        ## search patch components (as in PATH), such as ':' for POSIX or ';' for
-        ## Windows.
+        ## search patch components (as in PATH), such as ':' for POSIX
+        ## or ';' for Windows.
 
       FileSystemCaseSensitive* = true
         ## true if the file system is case sensitive, false otherwise. Used by
@@ -100,7 +106,8 @@ when not declared(getEnv) or defined(nimscript):
     #  MacOS directory separator is a colon ":" which is the only character not
     #  allowed in filenames.
     #
-    #  A path containing no colon or which begins with a colon is a partial path.
+    #  A path containing no colon or which begins with a colon is a partial
+    #  path.
     #  E.g. ":kalle:petter" ":kalle" "kalle"
     #
     #  All other paths are full (absolute) paths. E.g. "HD:kalle:" "HD:"
@@ -202,9 +209,9 @@ when not declared(getEnv) or defined(nimscript):
 
   proc joinPath*(parts: varargs[string]): string {.noSideEffect,
     rtl, extern: "nos$1OpenArray".} =
-    ## The same as `joinPath(head, tail)`, but works with any number of directory
-    ## parts. You need to pass at least one element or the proc will assert in
-    ## debug builds and crash on release builds.
+    ## The same as `joinPath(head, tail)`, but works with any number of
+    ## directory parts. You need to pass at least one element or the proc
+    ## will assert in debug builds and crash on release builds.
     result = parts[0]
     for i in 1..high(parts):
       result = joinPath(result, parts[i])
@@ -312,8 +319,8 @@ when not declared(getEnv) or defined(nimscript):
       if inclusive: yield path
 
   proc `/../` * (head, tail: string): string {.noSideEffect.} =
-    ## The same as ``parentDir(head) / tail`` unless there is no parent directory.
-    ## Then ``head / tail`` is performed instead.
+    ## The same as ``parentDir(head) / tail`` unless there is no parent
+    ## directory. Then ``head / tail`` is performed instead.
     let sepPos = parentDirPos(head)
     if sepPos >= 0:
       result = substr(head, 0, sepPos-1) / tail
@@ -496,7 +503,8 @@ when defined(nimdoc) and not declared(os):
   proc existsFile(x: string): bool = discard
 
 when declared(getEnv) or defined(nimscript):
-  proc getHomeDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect].} =
+  proc getHomeDir*(): string {.rtl, extern: "nos$1",
+    tags: [ReadEnvEffect, ReadIOEffect].} =
     ## Returns the home directory of the current user.
     ##
     ## This proc is wrapped by the expandTilde proc for the convenience of
@@ -504,18 +512,21 @@ when declared(getEnv) or defined(nimscript):
     when defined(windows): return string(getEnv("USERPROFILE")) & "\\"
     else: return string(getEnv("HOME")) & "/"
 
-  proc getConfigDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect].} =
+  proc getConfigDir*(): string {.rtl, extern: "nos$1",
+    tags: [ReadEnvEffect, ReadIOEffect].} =
     ## Returns the config directory of the current user for applications.
     when defined(windows): return string(getEnv("APPDATA")) & "\\"
     else: return string(getEnv("HOME")) & "/.config/"
 
-  proc getTempDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect].} =
+  proc getTempDir*(): string {.rtl, extern: "nos$1",
+    tags: [ReadEnvEffect, ReadIOEffect].} =
     ## Returns the temporary directory of the current user for applications to
     ## save temporary files in.
     when defined(windows): return string(getEnv("TEMP")) & "\\"
     else: return "/tmp/"
 
-  proc expandTilde*(path: string): string {.tags: [ReadEnvEffect].} =
+  proc expandTilde*(path: string): string {.
+    tags: [ReadEnvEffect, ReadIOEffect].} =
     ## Expands a path starting with ``~/`` to a full path.
     ##
     ## If `path` starts with the tilde character and is followed by `/` or `\\`
@@ -523,8 +534,8 @@ when declared(getEnv) or defined(nimscript):
     ## the getHomeDir() proc, otherwise the input path will be returned without
     ## modification.
     ##
-    ## The behaviour of this proc is the same on the Windows platform despite not
-    ## having this convention. Example:
+    ## The behaviour of this proc is the same on the Windows platform despite
+    ## not having this convention. Example:
     ##
     ## .. code-block:: nim
     ##   let configFile = expandTilde("~" / "appname.cfg")
@@ -545,7 +556,8 @@ when declared(getEnv) or defined(nimscript):
           yield substr(s, first, last-1)
           inc(last)
 
-  proc findExe*(exe: string): string {.tags: [ReadDirEffect, ReadEnvEffect].} =
+  proc findExe*(exe: string): string {.
+    tags: [ReadDirEffect, ReadEnvEffect, ReadIOEffect].} =
     ## Searches for `exe` in the current working directory and then
     ## in directories listed in the ``PATH`` environment variable.
     ## Returns "" if the `exe` cannot be found. On DOS-like platforms, `exe`
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index 7431be702..fa20afff0 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -24,6 +24,20 @@ when defined(linux):
   import linux
 
 type
+  ProcessOption* = enum ## options that can be passed `startProcess`
+    poEchoCmd,           ## echo the command before execution
+    poUsePath,           ## Asks system to search for executable using PATH environment
+                         ## variable.
+                         ## On Windows, this is the default.
+    poEvalCommand,       ## Pass `command` directly to the shell, without quoting.
+                         ## Use it only if `command` comes from trused source.
+    poStdErrToStdOut,    ## merge stdout and stderr to the stdout stream
+    poParentStreams,     ## use the parent's streams
+    poInteractive        ## optimize the buffer handling for responsiveness for
+                         ## UI applications. Currently this only affects
+                         ## Windows: Named pipes are used so that you can peek
+                         ## at the process' output streams.
+
   ProcessObj = object of RootObj
     when defined(windows):
       fProcessHandle: Handle
@@ -34,18 +48,10 @@ type
       inStream, outStream, errStream: Stream
       id: Pid
     exitCode: cint
+    options: set[ProcessOption]
 
   Process* = ref ProcessObj ## represents an operating system process
 
-  ProcessOption* = enum ## options that can be passed `startProcess`
-    poEchoCmd,           ## echo the command before execution
-    poUsePath,           ## Asks system to search for executable using PATH environment
-                         ## variable.
-                         ## On Windows, this is the default.
-    poEvalCommand,       ## Pass `command` directly to the shell, without quoting.
-                         ## Use it only if `command` comes from trused source.
-    poStdErrToStdOut,    ## merge stdout and stderr to the stdout stream
-    poParentStreams      ## use the parent's streams
 
 {.deprecated: [TProcess: ProcessObj, PProcess: Process,
   TProcessOption: ProcessOption].}
@@ -242,7 +248,8 @@ proc countProcessors*(): int {.rtl, extern: "nosp$1".} =
 proc execProcesses*(cmds: openArray[string],
                     options = {poStdErrToStdOut, poParentStreams},
                     n = countProcessors(),
-                    beforeRunEvent: proc(idx: int) = nil): int
+                    beforeRunEvent: proc(idx: int) = nil,
+                    afterRunEvent: proc(idx: int, p: Process) = nil): int
                     {.rtl, extern: "nosp$1",
                     tags: [ExecIOEffect, TimeEffect, ReadEnvEffect, RootEffect]} =
   ## executes the commands `cmds` in parallel. Creates `n` processes
@@ -272,6 +279,7 @@ proc execProcesses*(cmds: openArray[string],
             err.add("\n")
           echo(err)
         result = max(waitForExit(q[r]), result)
+        if afterRunEvent != nil: afterRunEvent(r, q[r])
         if q[r] != nil: close(q[r])
         if beforeRunEvent != nil:
           beforeRunEvent(i)
@@ -285,6 +293,7 @@ proc execProcesses*(cmds: openArray[string],
           if not running(q[r]):
             #echo(outputStream(q[r]).readLine())
             result = max(waitForExit(q[r]), result)
+            if afterRunEvent != nil: afterRunEvent(r, q[r])
             if q[r] != nil: close(q[r])
             if beforeRunEvent != nil:
               beforeRunEvent(i)
@@ -293,6 +302,7 @@ proc execProcesses*(cmds: openArray[string],
             if i > high(cmds): break
     for j in 0..m-1:
       result = max(waitForExit(q[j]), result)
+      if afterRunEvent != nil: afterRunEvent(j, q[j])
       if q[j] != nil: close(q[j])
   else:
     for i in 0..high(cmds):
@@ -300,9 +310,10 @@ proc execProcesses*(cmds: openArray[string],
         beforeRunEvent(i)
       var p = startProcess(cmds[i], options=options + {poEvalCommand})
       result = max(waitForExit(p), result)
+      if afterRunEvent != nil: afterRunEvent(i, p)
       close(p)
 
-proc select*(readfds: var seq[Process], timeout = 500): int
+proc select*(readfds: var seq[Process], timeout = 500): int {.benign.}
   ## `select` with a sensible Nim interface. `timeout` is in milliseconds.
   ## Specify -1 for no timeout. Returns the number of processes that are
   ## ready to read from. The processes that are ready to be read from are
@@ -352,7 +363,7 @@ when defined(Windows) and not defined(useNimRtl):
     # TRUE and n (>0) bytes returned (good data).
     # FALSE and bytes returned undefined (system error).
     if a == 0 and br != 0: raiseOSError(osLastError())
-    s.atTheEnd = br < bufLen
+    s.atTheEnd = br == 0 #< bufLen
     result = br
 
   proc hsWriteData(s: Stream, buffer: pointer, bufLen: int) =
@@ -394,13 +405,68 @@ when defined(Windows) and not defined(useNimRtl):
   #var
   #  O_WRONLY {.importc: "_O_WRONLY", header: "<fcntl.h>".}: int
   #  O_RDONLY {.importc: "_O_RDONLY", header: "<fcntl.h>".}: int
+  proc myDup(h: Handle; inherit: WinBool=1): Handle =
+    let thisProc = getCurrentProcess()
+    if duplicateHandle(thisProc, h,
+                       thisProc, addr result,0,inherit,
+                       DUPLICATE_SAME_ACCESS) == 0:
+      raiseOSError(osLastError())
+
+  proc createAllPipeHandles(si: var STARTUPINFO;
+                            stdin, stdout, stderr: var Handle) =
+    var sa: SECURITY_ATTRIBUTES
+    sa.nLength = sizeof(SECURITY_ATTRIBUTES).cint
+    sa.lpSecurityDescriptor = nil
+    sa.bInheritHandle = 1
+    let pipeOutName = newWideCString(r"\\.\pipe\stdout")
+    let pipeInName = newWideCString(r"\\.\pipe\stdin")
+    let pipeOut = createNamedPipe(pipeOutName,
+      dwOpenMode=PIPE_ACCESS_INBOUND or FILE_FLAG_WRITE_THROUGH,
+      dwPipeMode=PIPE_NOWAIT,
+      nMaxInstances=1,
+      nOutBufferSize=1024, nInBufferSize=1024,
+      nDefaultTimeOut=0,addr sa)
+    if pipeOut == INVALID_HANDLE_VALUE:
+      raiseOSError(osLastError())
+    let pipeIn = createNamedPipe(pipeInName,
+      dwOpenMode=PIPE_ACCESS_OUTBOUND or FILE_FLAG_WRITE_THROUGH,
+      dwPipeMode=PIPE_NOWAIT,
+      nMaxInstances=1,
+      nOutBufferSize=1024, nInBufferSize=1024,
+      nDefaultTimeOut=0,addr sa)
+    if pipeIn == INVALID_HANDLE_VALUE:
+      raiseOSError(osLastError())
+
+    si.hStdOutput = createFileW(pipeOutName,
+        FILE_WRITE_DATA or SYNCHRONIZE, 0, addr sa,
+        OPEN_EXISTING, # very important flag!
+        FILE_ATTRIBUTE_NORMAL,
+        0 # no template file for OPEN_EXISTING
+      )
+    if si.hStdOutput == INVALID_HANDLE_VALUE:
+      raiseOSError(osLastError())
+    si.hStdError = myDup(si.hStdOutput)
+    si.hStdInput = createFileW(pipeInName,
+        FILE_READ_DATA or SYNCHRONIZE, 0, addr sa,
+        OPEN_EXISTING, # very important flag!
+        FILE_ATTRIBUTE_NORMAL,
+        0 # no template file for OPEN_EXISTING
+      )
+    if si.hStdOutput == INVALID_HANDLE_VALUE:
+      raiseOSError(osLastError())
+
+    stdin = myDup(pipeIn, 0)
+    stdout = myDup(pipeOut, 0)
+    discard closeHandle(pipeIn)
+    discard closeHandle(pipeOut)
+    stderr = stdout
 
   proc createPipeHandles(rdHandle, wrHandle: var Handle) =
-    var piInheritablePipe: SECURITY_ATTRIBUTES
-    piInheritablePipe.nLength = sizeof(SECURITY_ATTRIBUTES).cint
-    piInheritablePipe.lpSecurityDescriptor = nil
-    piInheritablePipe.bInheritHandle = 1
-    if createPipe(rdHandle, wrHandle, piInheritablePipe, 1024) == 0'i32:
+    var sa: SECURITY_ATTRIBUTES
+    sa.nLength = sizeof(SECURITY_ATTRIBUTES).cint
+    sa.lpSecurityDescriptor = nil
+    sa.bInheritHandle = 1
+    if createPipe(rdHandle, wrHandle, sa, 1024) == 0'i32:
       raiseOSError(osLastError())
 
   proc fileClose(h: Handle) {.inline.} =
@@ -417,16 +483,20 @@ when defined(Windows) and not defined(useNimRtl):
       success: int
       hi, ho, he: Handle
     new(result)
+    result.options = options
     si.cb = sizeof(si).cint
     if poParentStreams notin options:
       si.dwFlags = STARTF_USESTDHANDLES # STARTF_USESHOWWINDOW or
-      createPipeHandles(si.hStdInput, hi)
-      createPipeHandles(ho, si.hStdOutput)
-      if poStdErrToStdOut in options:
-        si.hStdError = si.hStdOutput
-        he = ho
+      if poInteractive notin options:
+        createPipeHandles(si.hStdInput, hi)
+        createPipeHandles(ho, si.hStdOutput)
+        if poStdErrToStdOut in options:
+          si.hStdError = si.hStdOutput
+          he = ho
+        else:
+          createPipeHandles(he, si.hStdError)
       else:
-        createPipeHandles(he, si.hStdError)
+        createAllPipeHandles(si, hi, ho, he)
       result.inHandle = FileHandle(hi)
       result.outHandle = FileHandle(ho)
       result.errHandle = FileHandle(he)
@@ -469,6 +539,7 @@ when defined(Windows) and not defined(useNimRtl):
 
     if e != nil: dealloc(e)
     if success == 0:
+      if poInteractive in result.options: close(result)
       const errInvalidParameter = 87.int
       const errFileNotFound = 2.int
       if lastError.int in {errInvalidParameter, errFileNotFound}:
@@ -482,12 +553,12 @@ when defined(Windows) and not defined(useNimRtl):
     result.id = procInfo.dwProcessId
 
   proc close(p: Process) =
-    when false:
-      # somehow this does not work on Windows:
+    if poInteractive in p.options:
+      # somehow this is not always required on Windows:
       discard closeHandle(p.inHandle)
       discard closeHandle(p.outHandle)
       discard closeHandle(p.errHandle)
-      discard closeHandle(p.FProcessHandle)
+      #discard closeHandle(p.FProcessHandle)
 
   proc suspend(p: Process) =
     discard suspendThread(p.fProcessHandle)
@@ -564,7 +635,7 @@ when defined(Windows) and not defined(useNimRtl):
     assert readfds.len <= MAXIMUM_WAIT_OBJECTS
     var rfds: WOHandleArray
     for i in 0..readfds.len()-1:
-      rfds[i] = readfds[i].fProcessHandle
+      rfds[i] = readfds[i].outHandle #fProcessHandle
 
     var ret = waitForMultipleObjects(readfds.len.int32,
                                      addr(rfds), 0'i32, timeout.int32)
@@ -578,6 +649,11 @@ when defined(Windows) and not defined(useNimRtl):
       readfds.del(i)
       return 1
 
+  proc hasData*(p: Process): bool =
+    var x: int32
+    if peekNamedPipe(p.outHandle, lpTotalBytesAvail=addr x):
+      result = x > 0
+
 elif not defined(useNimRtl):
   const
     readIdx = 0
@@ -635,6 +711,7 @@ elif not defined(useNimRtl):
     var
       pStdin, pStdout, pStderr: array [0..1, cint]
     new(result)
+    result.options = options
     result.exitCode = -3 # for ``waitForExit``
     if poParentStreams notin options:
       if pipe(pStdin) != 0'i32 or pipe(pStdout) != 0'i32 or
@@ -960,6 +1037,15 @@ elif not defined(useNimRtl):
 
     pruneProcessSet(readfds, (rd))
 
+  proc hasData*(p: Process): bool =
+    var rd: TFdSet
+
+    FD_ZERO(rd)
+    let m = max(0, int(p.outHandle))
+    FD_SET(cint(p.outHandle), rd)
+
+    result = int(select(cint(m+1), addr(rd), nil, nil, nil)) == 1
+
 
 proc execCmdEx*(command: string, options: set[ProcessOption] = {
                 poStdErrToStdOut, poUsePath}): tuple[
diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim
index 60d09c71a..72c64befc 100644
--- a/lib/pure/rationals.nim
+++ b/lib/pure/rationals.nim
@@ -18,8 +18,9 @@ type Rational*[T] = object
   ## a rational number, consisting of a numerator and denominator
   num*, den*: T
 
-proc initRational*[T](num, den: T): Rational[T] =
+proc initRational*[T:SomeInteger](num, den: T): Rational[T] =
   ## Create a new rational number.
+  assert(den != 0, "a denominator of zero value is invalid")
   result.num = num
   result.den = den
 
@@ -33,11 +34,68 @@ proc `$`*[T](x: Rational[T]): string =
   ## Turn a rational number into a string.
   result = $x.num & "/" & $x.den
 
-proc toRational*[T](x: T): Rational[T] =
+proc toRational*[T:SomeInteger](x: T): Rational[T] =
   ## Convert some integer `x` to a rational number.
   result.num = x
   result.den = 1
 
+proc toRationalSub(x: float, n: int): Rational[int] =
+  var
+    a = 0
+    b, c, d = 1
+  result = 0 // 1   # rational 0
+  while b <= n and d <= n:
+    let ac = (a+c)
+    let bd = (b+d)
+    # scale by 1000 so not overflow for high precision
+    let mediant = (ac/1000) / (bd/1000)
+    if x == mediant:
+      if bd <= n:
+        result.num = ac
+        result.den = bd
+        return result
+      elif d > b:
+        result.num = c
+        result.den = d
+        return result
+      else:
+        result.num = a
+        result.den = b
+        return result
+    elif x > mediant:
+      a = ac
+      b = bd
+    else:
+      c = ac
+      d = bd
+  if (b > n):
+    return initRational(c, d)
+  return initRational(a, b)
+
+proc toRational*(x: float, n: int = high(int)): Rational[int] =
+  ## Calculate the best rational numerator and denominator
+  ## that approximates to `x`, where the denominator is
+  ## smaller than `n` (default is the largest possible
+  ## int to give maximum resolution)
+  ##
+  ## The algorithm is based on the Farey sequence named
+  ## after John Farey
+  ##
+  ## .. code-block:: Nim
+  ##  import math, rationals
+  ##  for i in 1..10:
+  ##    let t = (10 ^ (i+3)).int
+  ##    let x = toRational(PI, t)
+  ##    let newPI = x.num / x.den
+  ##    echo x, " ", newPI, " error: ", PI - newPI, "  ", t
+  if x > 1:
+    result = toRationalSub(1.0/x, n)
+    swap(result.num, result.den)
+  elif x == 1.0:
+    result = 1 // 1
+  else:
+    result = toRationalSub(x, n)
+
 proc toFloat*[T](x: Rational[T]): float =
   ## Convert a rational number `x` to a float.
   x.num / x.den
@@ -47,7 +105,7 @@ proc toInt*[T](x: Rational[T]): int =
   ## `x` does not contain an integer value.
   x.num div x.den
 
-proc reduce*[T](x: var Rational[T]) =
+proc reduce*[T:SomeInteger](x: var Rational[T]) =
   ## Reduce rational `x`.
   let common = gcd(x.num, x.den)
   if x.den > 0:
@@ -287,3 +345,8 @@ when isMainModule:
   assert toRational(5) == 5//1
   assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7
   assert toInt(z) == 0
+
+  assert toRational(0.98765432) == 12345679 // 12500000
+  assert toRational(0.1, 1000000) == 1 // 10
+  assert toRational(0.9, 1000000) == 9 // 10
+  assert toRational(PI) == 80143857 // 25510582
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
index bfc393a96..ca969c761 100644
--- a/lib/pure/selectors.nim
+++ b/lib/pure/selectors.nim
@@ -13,6 +13,8 @@ import os, unsigned, hashes
 
 when defined(linux):
   import posix, epoll
+elif defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd):
+  import posix, kqueue, times
 elif defined(windows):
   import winlean
 else:
@@ -79,7 +81,6 @@ when defined(nimdoc):
   proc `[]`*(s: Selector, fd: SocketHandle): SelectorKey =
     ## Retrieves the selector key for ``fd``.
 
-
 elif defined(linux):
   type
     Selector* = object
@@ -99,15 +100,13 @@ elif defined(linux):
     result.data.fd = fd.cint
 
   proc register*(s: var Selector, fd: SocketHandle, events: set[Event],
-      data: SelectorData) =
+                 data: SelectorData) =
     var event = createEventStruct(events, fd)
     if events != {}:
       if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fd, addr(event)) != 0:
         raiseOSError(osLastError())
 
-    var key = SelectorKey(fd: fd, events: events, data: data)
-
-    s.fds[fd] = key
+    s.fds[fd] = SelectorKey(fd: fd, events: events, data: data)
 
   proc update*(s: var Selector, fd: SocketHandle, events: set[Event]) =
     if s.fds[fd].events != events:
@@ -154,11 +153,6 @@ elif defined(linux):
       raiseOSError(err)
 
   proc select*(s: var Selector, timeout: int): seq[ReadyInfo] =
-    ##
-    ## The ``events`` field of the returned ``key`` contains the original events
-    ## for which the ``fd`` was bound. This is contrary to the ``events`` field
-    ## of the ``TReadyInfo`` tuple which determines which events are ready
-    ## on the ``fd``.
     result = @[]
     let evNum = epoll_wait(s.epollFD, addr s.events[0], 64.cint, timeout.cint)
     if evNum < 0:
@@ -204,6 +198,86 @@ elif defined(linux):
     ## Retrieves the selector key for ``fd``.
     return s.fds[fd]
 
+elif defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd):
+  type
+    Selector* = object
+      kqFD: cint
+      events: array[64, KEvent]
+      when MultiThreaded:
+        fds: SharedTable[SocketHandle, SelectorKey]
+      else:
+        fds: Table[SocketHandle, SelectorKey]
+
+  template modifyKQueue(kqFD: cint, fd: SocketHandle, event: Event,
+                        op: cushort) =
+    var kev = KEvent(ident:  fd.cuint,
+                     filter: if event == EvRead: EVFILT_READ else: EVFILT_WRITE,
+                     flags:  op)
+    if kevent(kqFD, addr kev, 1, nil, 0, nil) == -1:
+      raiseOSError(osLastError())
+
+  proc register*(s: var Selector, fd: SocketHandle, events: set[Event],
+                 data: SelectorData) =
+    for event in events:
+      modifyKQueue(s.kqFD, fd, event, EV_ADD)
+    s.fds[fd] = SelectorKey(fd: fd, events: events, data: data)
+
+  proc update*(s: var Selector, fd: SocketHandle, events: set[Event]) =
+    let previousEvents = s.fds[fd].events
+    if previousEvents != events:
+      for event in events-previousEvents:
+        modifyKQueue(s.kqFD, fd, event, EV_ADD)
+      for event in previousEvents-events:
+        modifyKQueue(s.kqFD, fd, event, EV_DELETE)
+      s.fds.mget(fd).events = events
+
+  proc unregister*(s: var Selector, fd: SocketHandle) =
+    for event in s.fds[fd].events:
+      modifyKQueue(s.kqFD, fd, event, EV_DELETE)
+    s.fds.del(fd)
+
+  proc close*(s: var Selector) =
+    when MultiThreaded: deinitSharedTable(s.fds)
+    if s.kqFD.close() != 0: raiseOSError(osLastError())
+
+  proc select*(s: var Selector, timeout: int): seq[ReadyInfo] =
+    result = @[]
+    var tv = Timespec(tv_sec: timeout.Time, tv_nsec: 0)
+    let evNum = kevent(s.kqFD, nil, 0, addr s.events[0], 64.cint, addr tv)
+    if evNum < 0:
+      let err = osLastError()
+      if err.cint == EINTR:
+        return @[]
+      raiseOSError(err)
+    if evNum == 0: return @[]
+    for i in 0 .. <evNum:
+      let fd = s.events[i].ident.SocketHandle
+
+      var evSet: set[Event] = {}
+      if  (s.events[i].flags and EV_EOF) != 0: evSet = evSet + {EvError}
+      if   s.events[i].filter == EVFILT_READ:  evSet = evSet + {EvRead}
+      elif s.events[i].filter == EVFILT_WRITE: evSet = evSet + {EvWrite}
+      let selectorKey = s.fds[fd]
+      assert selectorKey.fd != 0.SocketHandle
+      result.add((selectorKey, evSet))
+
+  proc newSelector*(): Selector =
+    result.kqFD = kqueue()
+    if result.kqFD < 0:
+      raiseOSError(osLastError())
+    when MultiThreaded:
+      result.fds = initSharedTable[SocketHandle, SelectorKey]()
+    else:
+      result.fds = initTable[SocketHandle, SelectorKey]()
+
+  proc contains*(s: Selector, fd: SocketHandle): bool =
+    ## Determines whether selector contains a file descriptor.
+    s.fds.hasKey(fd) # and s.fds[fd].events != {}
+
+  proc `[]`*(s: Selector, fd: SocketHandle): SelectorKey =
+    ## Retrieves the selector key for ``fd``.
+    return s.fds[fd]
+
 elif not defined(nimdoc):
   # TODO: kqueue for bsd/mac os x.
   type
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index 8aa8d35d8..38e91fee4 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -11,6 +11,26 @@
 ## the `FileStream` and the `StringStream` which implement the stream
 ## interface for Nim file objects (`File`) and strings. Other modules
 ## may provide other implementations for this standard stream interface.
+##
+## Examples:
+##
+## .. code-block:: Nim
+##
+##  import streams
+##  var
+##    ss = newStringStream("""The first line
+##  the second line
+##  the third line""")
+##    line = ""
+##  while ss.readLine(line):
+##    echo line
+##  ss.close()
+##
+##  var fs = newFileStream("somefile.txt", fmRead)
+##  if not isNil(fs):
+##    while fs.readLine(line):
+##      echo line
+##    fs.close()
 
 include "system/inclrtl"
 
@@ -81,6 +101,19 @@ proc readData*(s: Stream, buffer: pointer, bufLen: int): int =
   ## low level proc that reads data into an untyped `buffer` of `bufLen` size.
   result = s.readDataImpl(s, buffer, bufLen)
 
+proc readAll*(s: Stream): string =
+  ## Reads all available data.
+  const bufferSize = 1000
+  result = newString(bufferSize)
+  var r = 0
+  while true:
+    let readBytes = readData(s, addr(result[r]), bufferSize)
+    if readBytes < bufferSize:
+      setLen(result, r+readBytes)
+      break
+    inc r, bufferSize
+    setLen(result, r+bufferSize)
+
 proc readData*(s, unused: Stream, buffer: pointer,
                bufLen: int): int {.deprecated.} =
   ## low level proc that reads data into an untyped `buffer` of `bufLen` size.
@@ -371,7 +404,7 @@ when not defined(js):
     result.writeDataImpl = fsWriteData
     result.flushImpl = fsFlush
 
-  proc newFileStream*(filename: string, mode: FileMode): FileStream =
+  proc newFileStream*(filename: string, mode: FileMode = fmRead): FileStream =
     ## creates a new stream from the file named `filename` with the mode `mode`.
     ## If the file cannot be opened, nil is returned. See the `system
     ## <system.html>`_ module for a list of available FileMode enums.
diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim
index 86f81aa43..1ce9067a7 100644
--- a/lib/pure/strtabs.nim
+++ b/lib/pure/strtabs.nim
@@ -173,6 +173,9 @@ proc clear*(s: StringTableRef, mode: StringTableMode) =
   s.mode = mode
   s.counter = 0
   s.data.setLen(startSize)
+  for i in 0..<s.data.len:
+    if not isNil(s.data[i].key):
+      s.data[i].key = nil
 
 proc newStringTable*(keyValuePairs: varargs[string],
                      mode: StringTableMode): StringTableRef {.
@@ -248,3 +251,6 @@ when isMainModule:
   x.mget("11") = "23"
   assert x["11"] == "23"
 
+  x.clear(modeCaseInsensitive)
+  x["11"] = "22"
+  assert x["11"] == "22"
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index d1c09f43d..a78fed4b9 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -60,6 +60,132 @@ const
     ##   doAssert "01234".find(invalid) == -1
     ##   doAssert "01A34".find(invalid) == 2
 
+proc isAlpha*(c: char): bool {.noSideEffect, procvar,
+  rtl, extern: "nsuIsAlphaChar".}=
+  ## Checks whether or not `c` is alphabetical.
+  ##
+  ## This checks a-z, A-Z ASCII characters only.
+  return c in Letters
+
+proc isAlphaNumeric*(c: char): bool {.noSideEffect, procvar,
+  rtl, extern: "nsuIsAlphaNumericChar".}=
+  ## Checks whether or not `c` is alphanumeric.
+  ##
+  ## This checks a-z, A-Z, 0-9 ASCII characters only.
+  return c in Letters or c in Digits
+
+proc isDigit*(c: char): bool {.noSideEffect, procvar,
+  rtl, extern: "nsuIsDigitChar".}=
+  ## Checks whether or not `c` is a number.
+  ##
+  ## This checks 0-9 ASCII characters only.
+  return c in Digits
+
+proc isSpace*(c: char): bool {.noSideEffect, procvar,
+  rtl, extern: "nsuIsSpaceChar".}=
+  ## Checks whether or not `c` is a whitespace character.
+  return c in Whitespace
+
+proc isLower*(c: char): bool {.noSideEffect, procvar,
+  rtl, extern: "nsuIsLowerChar".}=
+  ## Checks whether or not `c` is a lower case character.
+  ##
+  ## This checks ASCII characters only.
+  return c in {'a'..'z'}
+
+proc isUpper*(c: char): bool {.noSideEffect, procvar,
+  rtl, extern: "nsuIsUpperChar".}=
+  ## Checks whether or not `c` is an upper case character.
+  ##
+  ## This checks ASCII characters only.
+  return c in {'A'..'Z'}
+
+proc isAlpha*(s: string): bool {.noSideEffect, procvar,
+  rtl, extern: "nsuIsAlphaStr".}=
+  ## Checks whether or not `s` is alphabetical.
+  ##
+  ## This checks a-z, A-Z ASCII characters only.
+  ## Returns true if all characters in `s` are
+  ## alphabetic and there is at least one character
+  ## in `s`.
+  if s.len() == 0:
+    return false
+
+  result = true
+  for c in s:
+    result = c.isAlpha() and result
+
+proc isAlphaNumeric*(s: string): bool {.noSideEffect, procvar,
+  rtl, extern: "nsuIsAlphaNumericStr".}=
+  ## Checks whether or not `s` is alphanumeric.
+  ##
+  ## This checks a-z, A-Z, 0-9 ASCII characters only.
+  ## Returns true if all characters in `s` are
+  ## alpanumeric and there is at least one character
+  ## in `s`.
+  if s.len() == 0:
+    return false
+
+  result = true
+  for c in s:
+    result = c.isAlphaNumeric() and result
+
+proc isDigit*(s: string): bool {.noSideEffect, procvar,
+  rtl, extern: "nsuIsDigitStr".}=
+  ## Checks whether or not `s` is a numeric value.
+  ##
+  ## This checks 0-9 ASCII characters only.
+  ## Returns true if all characters in `s` are
+  ## numeric and there is at least one character
+  ## in `s`.
+  if s.len() == 0:
+    return false
+
+  result = true
+  for c in s:
+    result = c.isDigit() and result
+
+proc isSpace*(s: string): bool {.noSideEffect, procvar,
+  rtl, extern: "nsuIsSpaceStr".}=
+  ## Checks whether or not `s` is completely whitespace.
+  ##
+  ## Returns true if all characters in `s` are whitespace
+  ## characters and there is at least one character in `s`.
+  if s.len() == 0:
+    return false
+
+  result = true
+  for c in s:
+    result = c.isSpace() and result
+
+proc isLower*(s: string): bool {.noSideEffect, procvar,
+  rtl, extern: "nsuIsLowerStr".}=
+  ## Checks whether or not `s` contains all lower case characters.
+  ##
+  ## This checks ASCII characters only.
+  ## Returns true if all characters in `s` are lower case
+  ## and there is at least one character  in `s`.
+  if s.len() == 0:
+    return false
+
+  result = true
+  for c in s:
+    result = c.isLower() and result
+
+proc isUpper*(s: string): bool {.noSideEffect, procvar,
+  rtl, extern: "nsuIsUpperStr".}=
+  ## Checks whether or not `s` contains all upper case characters.
+  ##
+  ## This checks ASCII characters only.
+  ## Returns true if all characters in `s` are upper case
+  ## and there is at least one character in `s`.
+  if s.len() == 0:
+    return false
+
+  result = true
+  for c in s:
+    result = c.isUpper() and result
+
 proc toLower*(c: char): char {.noSideEffect, procvar,
   rtl, extern: "nsuToLowerChar".} =
   ## Converts `c` into lower case.
@@ -169,7 +295,8 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
     inc(j)
 
 
-proc strip*(s: string, leading = true, trailing = true, chars: set[char] = Whitespace): string
+proc strip*(s: string, leading = true, trailing = true,
+            chars: set[char] = Whitespace): string
   {.noSideEffect, rtl, extern: "nsuStrip".} =
   ## Strips `chars` from `s` and returns the resulting string.
   ##
@@ -504,7 +631,8 @@ proc repeat*(c: char, count: Natural): string {.noSideEffect,
   ##
   ## .. code-block:: nim
   ##   proc tabexpand(indent: int, text: string, tabsize: int = 4) =
-  ##     echo '\t'.repeat(indent div tabsize), ' '.repeat(indent mod tabsize), text
+  ##     echo '\t'.repeat(indent div tabsize), ' '.repeat(indent mod tabsize),
+  ##         text
   ##
   ##   tabexpand(4, "At four")
   ##   tabexpand(5, "At five")
@@ -533,11 +661,13 @@ template spaces*(n: Natural): string =  repeat(' ',n)
   ##   echo text1 & spaces(max(0, width - text1.len)) & "|"
   ##   echo text2 & spaces(max(0, width - text2.len)) & "|"
 
-proc repeatChar*(count: Natural, c: char = ' '): string {.deprecated.} = repeat(c, count)
+proc repeatChar*(count: Natural, c: char = ' '): string {.deprecated.} =
   ## deprecated: use repeat() or spaces()
+  repeat(c, count)
 
-proc repeatStr*(count: Natural, s: string): string {.deprecated.} = repeat(s, count)
+proc repeatStr*(count: Natural, s: string): string {.deprecated.} =
   ## deprecated: use repeat(string, count) or string.repeat(count)
+  repeat(s, count)
 
 proc align*(s: string, count: Natural, padding = ' '): string {.
   noSideEffect, rtl, extern: "nsuAlignString".} =
@@ -850,8 +980,8 @@ proc rfind*(s: string, sub: char, start: int = -1): int {.noSideEffect,
     if sub == s[i]: return i
   return -1
 
-proc count*(s: string, sub: string, overlapping: bool = false): int {.noSideEffect,
-  rtl, extern: "nsuCountString".} =
+proc count*(s: string, sub: string, overlapping: bool = false): int {.
+  noSideEffect, rtl, extern: "nsuCountString".} =
   ## Count the occurrences of a substring `sub` in the string `s`.
   ## Overlapping occurrences of `sub` only count when `overlapping`
   ## is set to true.
@@ -1449,7 +1579,8 @@ proc removeSuffix*(s: var string, chars: set[char] = Newlines) {.
 
   s.setLen(last + 1)
 
-proc removeSuffix*(s: var string, c: char) {.rtl, extern: "nsuRemoveSuffixChar".} =
+proc removeSuffix*(s: var string, c: char) {.
+  rtl, extern: "nsuRemoveSuffixChar".} =
   ## Removes a single character (in-place) from a string.
   ## .. code-block:: nim
   ##   var
@@ -1515,8 +1646,61 @@ when isMainModule:
   doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo"
   doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo"
   doAssert strip("stripme but don't strip this stripme",
-                 chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) == " but don't strip this "
+                 chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) ==
+                 " but don't strip this "
   doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo"
   doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos"
 
   doAssert "  foo\n  bar".indent(4, "Q") == "QQQQ  foo\nQQQQ  bar"
+
+  doAssert isAlpha('r')
+  doAssert isAlpha('A')
+  doAssert(not isAlpha('$'))
+
+  doAssert isAlpha("Rasp")
+  doAssert isAlpha("Args")
+  doAssert(not isAlpha("$Tomato"))
+  
+  doAssert isAlphaNumeric('3')
+  doAssert isAlphaNumeric('R')
+  doAssert(not isAlphaNumeric('!'))
+
+  doAssert isAlphaNumeric("34ABc")
+  doAssert isAlphaNumeric("Rad")
+  doAssert isAlphaNumeric("1234")
+  doAssert(not isAlphaNumeric("@nose"))
+
+  doAssert isDigit('3')
+  doAssert(not isDigit('a'))
+  doAssert(not isDigit('%'))
+
+  doAssert isDigit("12533")
+  doAssert(not isDigit("12.33"))
+  doAssert(not isDigit("A45b"))
+
+  doAssert isSpace('\t')
+  doAssert isSpace('\l')
+  doAssert(not isSpace('A'))
+
+  doAssert isSpace("\t\l \v\r\f")
+  doAssert isSpace("       ")
+  doAssert(not isSpace("ABc   \td"))
+
+  doAssert isLower('a')
+  doAssert isLower('z')
+  doAssert(not isLower('A'))
+  doAssert(not isLower('5'))
+  doAssert(not isLower('&'))
+
+  doAssert isLower("abcd")
+  doAssert(not isLower("abCD"))
+  doAssert(not isLower("33aa"))
+
+  doAssert isUpper('A')
+  doAssert(not isUpper('b'))
+  doAssert(not isUpper('5'))
+  doAssert(not isUpper('%'))
+
+  doAssert isUpper("ABC")
+  doAssert(not isUpper("AAcc"))
+  doAssert(not isUpper("A#$"))
diff --git a/lib/pure/subexes.nim b/lib/pure/subexes.nim
index 2d1adc0eb..5824ace81 100644
--- a/lib/pure/subexes.nim
+++ b/lib/pure/subexes.nim
@@ -351,6 +351,7 @@ proc format*(formatstr: Subex, a: varargs[string, `$`]): string {.noSideEffect,
 {.pop.}
 
 when isMainModule:
+  from strutils import replace
 
   proc `%`(formatstr: string, a: openarray[string]): string =
     result = newStringOfCap(formatstr.len + a.len shl 4)
@@ -382,18 +383,18 @@ when isMainModule:
   doAssert "${$1}" % "1" == "1"
   doAssert "${$$-1} $$1" % "1" == "1 $1"
 
-  doAssert "$#($', '10c'\n    '{#..})" % ["doAssert", "longishA", "longish"] ==
+  doAssert(("$#($', '10c'\n    '{#..})" % ["doAssert", "longishA", "longish"]).replace(" \n", "\n") ==
            """doAssert(
     longishA,
-    longish)"""
+    longish)""")
 
-  assert "type MyEnum* = enum\n  $', '2i'\n  '{..}" % ["fieldA",
-    "fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"] ==
+  doAssert(("type MyEnum* = enum\n  $', '2i'\n  '{..}" % ["fieldA",
+    "fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"]).replace(" \n", "\n") ==
     strutils.unindent """
       type MyEnum* = enum
         fieldA, fieldB,
         FiledClkad, fieldD,
-        fieldE, longishFieldName"""
+        fieldE, longishFieldName""")
 
   doAssert subex"$1($', '{2..})" % ["f", "a", "b", "c"] == "f(a, b, c)"
 
@@ -401,12 +402,10 @@ when isMainModule:
 
   doAssert subex"$['''|'|''''|']']#" % "0" == "'|"
 
-  assert subex("type\n  Enum = enum\n    $', '40c'\n    '{..}") % [
-    "fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"] ==
+  doAssert((subex("type\n  Enum = enum\n    $', '40c'\n    '{..}") % [
+    "fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"]).replace(" \n", "\n") ==
     strutils.unindent """
       type
         Enum = enum
           fieldNameA, fieldNameB, fieldNameC,
-          fieldNameD"""
-
-
+          fieldNameD""")
diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim
index 396957f6c..b059a7315 100644
--- a/lib/pure/unicode.nim
+++ b/lib/pure/unicode.nim
@@ -1319,15 +1319,43 @@ proc reversed*(s: string): string =
 
   reverseUntil(len(s))
 
+proc graphemeLen*(s: string; i: Natural): Natural =
+  ## The number of bytes belonging to 's[i]' including following combining
+  ## characters.
+  var j = i.int
+  var r, r2: Rune
+  if j < s.len:
+    fastRuneAt(s, j, r, true)
+    result = j-i
+    while j < s.len:
+      fastRuneAt(s, j, r2, true)
+      if not isCombining(r2): break
+      result = j-i
+
+proc lastRune*(s: string; last: int): (Rune, int) =
+  ## length of the last rune in 's[0..last]'. Returns the rune and its length
+  ## in bytes.
+  if s[last] <= chr(127):
+    result = (Rune(s[last]), 1)
+  else:
+    var L = 0
+    while last-L >= 0 and ord(s[last-L]) shr 6 == 0b10: inc(L)
+    var r: Rune
+    fastRuneAt(s, last-L, r, false)
+    result = (r, L+1)
+
 when isMainModule:
   let
     someString = "öÑ"
     someRunes = @[runeAt(someString, 0), runeAt(someString, 2)]
     compared = (someString == $someRunes)
-  assert compared == true
+  doAssert compared == true
 
-  assert reversed("Reverse this!") == "!siht esreveR"
-  assert reversed("先秦兩漢") == "漢兩秦先"
-  assert reversed("as⃝df̅") == "f̅ds⃝a"
-  assert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞"
-  assert len(toRunes("as⃝df̅")) == runeLen("as⃝df̅")
+  doAssert reversed("Reverse this!") == "!siht esreveR"
+  doAssert reversed("先秦兩漢") == "漢兩秦先"
+  doAssert reversed("as⃝df̅") == "f̅ds⃝a"
+  doAssert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞"
+  doAssert len(toRunes("as⃝df̅")) == runeLen("as⃝df̅")
+  const test = "as⃝"
+  doAssert lastRune(test, test.len-1)[1] == 3
+  doAssert graphemeLen("è", 0) == 2
diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim
index 492de3b46..abb1a462d 100644
--- a/lib/pure/uri.nim
+++ b/lib/pure/uri.nim
@@ -142,6 +142,7 @@ proc parseUri*(uri: string): Uri =
   parseUri(uri, result)
 
 proc removeDotSegments(path: string): string =
+  if path.len == 0: return ""
   var collection: seq[string] = @[]
   let endsWithSlash = path[path.len-1] == '/'
   var i = 0
@@ -432,3 +433,12 @@ when isMainModule:
   block:
     let test = parseUri("http://example.com/foo/") / "/bar/asd"
     doAssert test.path == "/foo/bar/asd"
+
+  # removeDotSegments tests
+  block:
+    # empty test
+    doAssert removeDotSegments("") == ""
+
+  # bug #3207
+  block:
+    doAssert parseUri("http://qq/1").combine(parseUri("https://qqq")).`$` == "https://qqq"
diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim
index 1c8573986..7c97a0a56 100644
--- a/lib/pure/xmltree.nim
+++ b/lib/pure/xmltree.nim
@@ -104,10 +104,23 @@ proc tag*(n: XmlNode): string {.inline.} =
   assert n.k == xnElement
   result = n.fTag
 
+proc `tag=`*(n: XmlNode, tag: string) {.inline.} =
+  ## sets the tag name of `n`. `n` has to be an ``xnElement`` node.
+  assert n.k == xnElement
+  n.fTag = tag
+
 proc add*(father, son: XmlNode) {.inline.} =
   ## adds the child `son` to `father`.
   add(father.s, son)
 
+proc insert*(father, son: XmlNode, index: int) {.inline.} =
+  ## insert the child `son` to a given position in `father`.
+  assert father.k == xnElement and son.k == xnElement
+  if len(father.s) > index:
+    insert(father.s, son, index)
+  else:
+    insert(father.s, son, len(father.s))
+
 proc len*(n: XmlNode): int {.inline.} =
   ## returns the number `n`'s children.
   if n.k == xnElement: result = len(n.s)
diff --git a/lib/system.nim b/lib/system.nim
index 8f529b8c0..89de08c6f 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -221,11 +221,21 @@ proc high*[T](x: T): T {.magic: "High", noSideEffect.}
   ## the highest possible value of an ordinal value `x`. As a special
   ## semantic rule, `x` may also be a type identifier.
   ## ``high(int)`` is Nim's way of writing `INT_MAX`:idx: or `MAX_INT`:idx:.
+  ##
+  ## .. code-block:: nim
+  ##  var arr = [1,2,3,4,5,6,7]
+  ##  high(arr) #=> 6
+  ##  high(2) #=> 9223372036854775807
 
 proc low*[T](x: T): T {.magic: "Low", noSideEffect.}
   ## returns the lowest possible index of an array, a sequence, a string or
   ## the lowest possible value of an ordinal value `x`. As a special
   ## semantic rule, `x` may also be a type identifier.
+  ##
+  ## .. code-block:: nim
+  ##  var arr = [1,2,3,4,5,6,7]
+  ##  high(arr) #=> 0
+  ##  high(2) #=> -9223372036854775808
 
 type
   range*{.magic: "Range".}[T] ## Generic type to construct range types.
@@ -243,7 +253,7 @@ when defined(nimArrIdx):
   # :array|openarray|string|seq|cstring|tuple
   proc `[]`*[I: Ordinal;T](a: T; i: I): T {.
     noSideEffect, magic: "ArrGet".}
-  proc `[]=`*[I: Ordinal;T,S](a: var T; i: I;
+  proc `[]=`*[I: Ordinal;T,S](a: T; i: I;
     x: S) {.noSideEffect, magic: "ArrPut".}
   proc `=`*[T](dest: var T; src: T) {.noSideEffect, magic: "Asgn".}
 
@@ -584,6 +594,10 @@ proc sizeof*[T](x: T): int {.magic: "SizeOf", noSideEffect.}
   ## its usage is discouraged - using ``new`` for the most cases suffices
   ## that one never needs to know ``x``'s size. As a special semantic rule,
   ## ``x`` may also be a type identifier (``sizeof(int)`` is valid).
+  ##
+  ## .. code-block:: nim
+  ##  sizeof('A') #=> 1
+  ##  sizeof(2) #=> 8
 
 when defined(nimtypedescfixed):
   proc sizeof*(x: typedesc): int {.magic: "SizeOf", noSideEffect.}
@@ -610,11 +624,21 @@ proc inc*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Inc", noSideEffect.
   ## increments the ordinal ``x`` by ``y``. If such a value does not
   ## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
   ## short notation for: ``x = succ(x, y)``.
+  ##
+  ## .. code-block:: nim
+  ##  var i = 2
+  ##  inc(i) #=> 3
+  ##  inc(i, 3) #=> 6
 
 proc dec*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Dec", noSideEffect.}
   ## decrements the ordinal ``x`` by ``y``. If such a value does not
   ## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
   ## short notation for: ``x = pred(x, y)``.
+  ##
+  ## .. code-block:: nim
+  ##  var i = 2
+  ##  dec(i) #=> 1
+  ##  dec(i, 3) #=> -2
 
 proc newSeq*[T](s: var seq[T], len: Natural) {.magic: "NewSeq", noSideEffect.}
   ## creates a new sequence of type ``seq[T]`` with length ``len``.
@@ -659,11 +683,22 @@ proc len*[T](x: seq[T]): int {.magic: "LengthSeq", noSideEffect.}
   ## returns the length of an array, an openarray, a sequence or a string.
   ## This is roughly the same as ``high(T)-low(T)+1``, but its resulting type is
   ## always an int.
+  ##
+  ## .. code-block:: nim
+  ##  var arr = [1,1,1,1,1]
+  ##  len(arr) #=> 5
+  ##  for i in 0..<arr.len:
+  ##    echo arr[i] #=> 1,1,1,1,1
 
 # set routines:
 proc incl*[T](x: var set[T], y: T) {.magic: "Incl", noSideEffect.}
   ## includes element ``y`` to the set ``x``. This is the same as
   ## ``x = x + {y}``, but it might be more efficient.
+  ##
+  ## .. code-block:: nim
+  ##  var a = initSet[int](4)
+  ##  a.incl(2) #=> {2}
+  ##  a.incl(3) #=> {2, 3}
 
 template incl*[T](s: var set[T], flags: set[T]) =
   ## includes the set of flags to the set ``x``.
@@ -672,6 +707,10 @@ template incl*[T](s: var set[T], flags: set[T]) =
 proc excl*[T](x: var set[T], y: T) {.magic: "Excl", noSideEffect.}
   ## excludes element ``y`` to the set ``x``. This is the same as
   ## ``x = x - {y}``, but it might be more efficient.
+  ##
+  ## .. code-block:: nim
+  ##  var b = {2,3,5,6,12,545}
+  ##  b.excl(5)  #=> {2,3,6,12,545}
 
 template excl*[T](s: var set[T], flags: set[T]) =
   ## excludes the set of flags to ``x``.
@@ -680,12 +719,22 @@ template excl*[T](s: var set[T], flags: set[T]) =
 proc card*[T](x: set[T]): int {.magic: "Card", noSideEffect.}
   ## returns the cardinality of the set ``x``, i.e. the number of elements
   ## in the set.
+  ##
+  ## .. code-block:: nim
+  ##  var i = {1,2,3,4}
+  ##  card(i) #=> 4
 
 proc ord*[T](x: T): int {.magic: "Ord", noSideEffect.}
   ## returns the internal int value of an ordinal value ``x``.
+  ##
+  ## .. code-block:: nim
+  ##  ord('A') #=> 65
 
 proc chr*(u: range[0..255]): char {.magic: "Chr", noSideEffect.}
   ## converts an int in the range 0..255 to a character.
+  ##
+  ## .. code-block:: nim
+  ##  chr(65) #=> A
 
 # --------------------------------------------------------------------------
 # built-in operators
@@ -1207,10 +1256,19 @@ proc compileOption*(option, arg: string): bool {.
   ##     echo "compiled with optimization for size and uses Boehm's GC"
 
 const
-  hasThreadSupport = compileOption("threads")
+  hasThreadSupport = compileOption("threads") and not defined(nimscript)
   hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own
   taintMode = compileOption("taintmode")
 
+when defined(boehmgc):
+  when defined(windows):
+    const boehmLib = "boehmgc.dll"
+  elif defined(macosx):
+    const boehmLib = "libgc.dylib"
+  else:
+    const boehmLib = "libgc.so.1"
+  {.pragma: boehmGC, noconv, dynlib: boehmLib.}
+
 when taintMode:
   type TaintedString* = distinct string ## a distinct string type that
                                         ## is `tainted`:idx:. It is an alias for
@@ -1290,6 +1348,10 @@ proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
   ## containers should also call their adding proc `add` for consistency.
   ## Generic code becomes much easier to write if the Nim naming scheme is
   ## respected.
+  ##
+  ## .. code-block:: nim
+  ##   var s: seq[string] = @["test2","test2"]
+  ##   s.add("test") #=> @[test2, test2, test]
   let xl = x.len
   setLen(x, xl + y.len)
   for i in 0..high(y): x[xl+i] = y[i]
@@ -1304,6 +1366,10 @@ proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".}
 proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
   ## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
   ## This is an O(1) operation.
+  ##
+  ## .. code-block:: nim
+  ##  var i = @[1,2,3,4,5]
+  ##  i.del(2) #=> @[1, 2, 5, 4]
   let xl = x.len - 1
   shallowCopy(x[i], x[xl])
   setLen(x, xl)
@@ -1311,6 +1377,10 @@ proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
 proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
   ## deletes the item at index `i` by moving ``x[i+1..]`` by one position.
   ## This is an O(n) operation.
+  ##
+  ## .. code-block:: nim
+  ##  var i = @[1,2,3,4,5]
+  ##  i.delete(2) #=> @[1, 2, 4, 5]
   template defaultImpl =
     let xl = x.len
     for j in i..xl-2: shallowCopy(x[j], x[j+1])
@@ -1326,6 +1396,10 @@ proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
 
 proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} =
   ## inserts `item` into `x` at position `i`.
+  ##
+  ## .. code-block:: nim
+  ##  var i = @[1,2,3,4,5]
+  ##  i.insert(2,4) #=> @[1, 2, 3, 4, 2, 5]
   template defaultImpl =
     let xl = x.len
     setLen(x, xl+1)
@@ -1346,6 +1420,12 @@ proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.}
   ## takes any Nim variable and returns its string representation. It
   ## works even for complex data graphs with cycles. This is a great
   ## debugging tool.
+  ##
+  ## .. code-block:: nim
+  ##  var s: seq[string] = @["test2","test2"]
+  ##  var i = @[1,2,3,4,5]
+  ##  repr(s) #=> 0x1055eb050[0x1055ec050"test2", 0x1055ec078"test2"]
+  ##  repr(i) #=> 0x1055ed050[1, 2, 3, 4, 5]
 
 type
   ByteAddress* = int
@@ -2089,53 +2169,6 @@ proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} =
   result = s[L]
   setLen(s, L)
 
-proc each*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] {.
-  deprecated.} =
-  ## The well-known ``map`` operation from functional programming. Applies
-  ## `op` to every item in `data` and returns the result as a sequence.
-  ##
-  ## **Deprecated since version 0.9:** Use the ``map`` proc instead.
-  newSeq(result, data.len)
-  for i in 0..data.len-1: result[i] = op(data[i])
-
-proc each*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) {.
-  deprecated.} =
-  ## The well-known ``map`` operation from functional programming. Applies
-  ## `op` to every item in `data` modifying it directly.
-  ##
-  ## **Deprecated since version 0.9:** Use the ``map`` proc instead.
-  for i in 0..data.len-1: op(data[i])
-
-proc map*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] =
-  ## Returns a new sequence with the results of `op` applied to every item in
-  ## `data`.
-  ##
-  ## Since the input is not modified you can use this version of ``map`` to
-  ## transform the type of the elements in the input sequence. Example:
-  ##
-  ## .. code-block:: nim
-  ##   let
-  ##     a = @[1, 2, 3, 4]
-  ##     b = map(a, proc(x: int): string = $x)
-  ##   assert b == @["1", "2", "3", "4"]
-  newSeq(result, data.len)
-  for i in 0..data.len-1: result[i] = op(data[i])
-
-proc map*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) =
-  ## Applies `op` to every item in `data` modifying it directly.
-  ##
-  ## Note that this version of ``map`` requires your input and output types to
-  ## be the same, since they are modified in-place. Example:
-  ##
-  ## .. code-block:: nim
-  ##   var a = @["1", "2", "3", "4"]
-  ##   echo repr(a)
-  ##   # --> ["1", "2", "3", "4"]
-  ##   map(a, proc(x: var string) = x &= "42")
-  ##   echo repr(a)
-  ##   # --> ["142", "242", "342", "442"]
-  for i in 0..data.len-1: op(data[i])
-
 iterator fields*[T: tuple|object](x: T): RootObj {.
   magic: "Fields", noSideEffect.}
   ## iterates over every field of `x`. Warning: This really transforms
@@ -2235,7 +2268,9 @@ proc `$`*[T: tuple|object](x: T): string =
     firstElement = false
   result.add(")")
 
-proc collectionToString[T](x: T, b, e: string): string =
+proc collectionToString[T: set | seq](x: T, b, e: string): string =
+  when x is seq:
+    if x.isNil: return "nil"
   result = b
   var firstElement = true
   for value in items(x):
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index 13a10e46f..3ebbc8c1e 100644
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -27,10 +27,60 @@ sysAssert(roundup(65, 8) == 72, "roundup broken 2")
 # some platforms have really weird unmap behaviour: unmap(blockStart, PageSize)
 # really frees the whole block. Happens for Linux/PowerPC for example. Amd64
 # and x86 are safe though; Windows is special because MEM_RELEASE can only be
-# used with a size of 0:
-const weirdUnmap = not (defined(amd64) or defined(i386)) or defined(windows)
+# used with a size of 0. We also allow unmapping to be turned off with
+# -d:nimAllocNoUnmap:
+const doNotUnmap = not (defined(amd64) or defined(i386)) or
+                   defined(windows) or defined(nimAllocNoUnmap)
 
-when defined(posix):
+
+when defined(emscripten):
+  const
+    PROT_READ  = 1             # page can be read
+    PROT_WRITE = 2             # page can be written
+    MAP_PRIVATE = 2'i32        # Changes are private
+
+  var MAP_ANONYMOUS {.importc: "MAP_ANONYMOUS", header: "<sys/mman.h>".}: cint
+  type 
+    PEmscriptenMMapBlock = ptr EmscriptenMMapBlock
+    EmscriptenMMapBlock {.pure, inheritable.} = object
+      realSize: int        # size of previous chunk; for coalescing
+      realPointer: pointer     # if < PageSize it is a small chunk
+
+  proc mmap(adr: pointer, len: int, prot, flags, fildes: cint,
+            off: int): pointer {.header: "<sys/mman.h>".}
+
+  proc munmap(adr: pointer, len: int) {.header: "<sys/mman.h>".}
+
+  proc osAllocPages(block_size: int): pointer {.inline.} =
+    let realSize = block_size + sizeof(EmscriptenMMapBlock) + PageSize + 1
+    result = mmap(nil, realSize, PROT_READ or PROT_WRITE,
+                             MAP_PRIVATE or MAP_ANONYMOUS, -1, 0)
+    if result == nil or result == cast[pointer](-1):
+      raiseOutOfMem()
+
+    let realPointer = result
+    let pos = cast[int](result)
+
+    # Convert pointer to PageSize correct one.
+    var new_pos = cast[ByteAddress](pos) +% (PageSize - (pos %% PageSize))
+    if (new_pos-pos)< sizeof(EmscriptenMMapBlock):
+      new_pos = new_pos +% PageSize
+    result = cast[pointer](new_pos)
+
+    var mmapDescrPos = cast[ByteAddress](result) -% sizeof(EmscriptenMMapBlock)
+
+    var mmapDescr = cast[EmscriptenMMapBlock](mmapDescrPos)
+    mmapDescr.realSize = realSize
+    mmapDescr.realPointer = realPointer
+
+    c_fprintf(c_stdout, "[Alloc] size %d %d realSize:%d realPos:%d\n", block_size, cast[int](result), realSize, cast[int](realPointer))
+
+  proc osDeallocPages(p: pointer, size: int) {.inline} =
+    var mmapDescrPos = cast[ByteAddress](p) -% sizeof(EmscriptenMMapBlock)
+    var mmapDescr = cast[EmscriptenMMapBlock](mmapDescrPos)
+    munmap(mmapDescr.realPointer, mmapDescr.realSize)
+
+elif defined(posix):
   const
     PROT_READ  = 1             # page can be read
     PROT_WRITE = 2             # page can be written
@@ -478,7 +528,7 @@ proc freeBigChunk(a: var MemRegion, c: PBigChunk) =
           excl(a.chunkStarts, pageIndex(c))
           c = cast[PBigChunk](le)
 
-  if c.size < ChunkOsReturn or weirdUnmap:
+  if c.size < ChunkOsReturn or doNotUnmap:
     incl(a, a.chunkStarts, pageIndex(c))
     updatePrevSize(a, c, c.size)
     listAdd(a.freeChunksList, c)
@@ -762,7 +812,7 @@ proc deallocOsPages(a: var MemRegion) =
   # we free every 'ordinarily' allocated page by iterating over the page bits:
   for p in elements(a.chunkStarts):
     var page = cast[PChunk](p shl PageShift)
-    when not weirdUnmap:
+    when not doNotUnmap:
       var size = if page.size < PageSize: PageSize else: page.size
       osDeallocPages(page, size)
     else:
diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim
index ceb362378..47e8b4b1f 100644
--- a/lib/system/gc_common.nim
+++ b/lib/system/gc_common.nim
@@ -95,7 +95,9 @@ proc setupForeignThreadGc*() =
 # ----------------- stack management --------------------------------------
 #  inspired from Smart Eiffel
 
-when defined(sparc):
+when defined(emscripten):
+  const stackIncreases = true
+elif defined(sparc):
   const stackIncreases = false
 elif defined(hppa) or defined(hp9000) or defined(hp9000s300) or
      defined(hp9000s700) or defined(hp9000s800) or defined(hp9000s820):
@@ -162,9 +164,9 @@ elif stackIncreases:
   proc isOnStack(p: pointer): bool =
     var stackTop {.volatile.}: pointer
     stackTop = addr(stackTop)
-    var a = cast[TAddress](gch.stackBottom)
-    var b = cast[TAddress](stackTop)
-    var x = cast[TAddress](p)
+    var a = cast[ByteAddress](gch.stackBottom)
+    var b = cast[ByteAddress](stackTop)
+    var x = cast[ByteAddress](p)
     result = a <=% x and x <=% b
 
   var
@@ -173,14 +175,14 @@ elif stackIncreases:
       # in a platform independent way
 
   template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} =
-    var registers: C_JmpBuf
+    var registers {.noinit.}: C_JmpBuf
     if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
-      var max = cast[TAddress](gch.stackBottom)
-      var sp = cast[TAddress](addr(registers)) +% jmpbufSize -% sizeof(pointer)
+      var max = cast[ByteAddress](gch.stackBottom)
+      var sp = cast[ByteAddress](addr(registers)) +% jmpbufSize -% sizeof(pointer)
       # sp will traverse the JMP_BUF as well (jmp_buf size is added,
       # otherwise sp would be below the registers structure).
       while sp >=% max:
-        gcMark(gch, cast[ppointer](sp)[])
+        gcMark(gch, cast[PPointer](sp)[])
         sp = sp -% sizeof(pointer)
 
 else:
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index 8a946716d..1c13f3ff8 100644
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -66,41 +66,34 @@ proc raiseOutOfMem() {.noinline.} =
   quit(1)
 
 when defined(boehmgc):
-  when defined(windows):
-    const boehmLib = "boehmgc.dll"
-  elif defined(macosx):
-    const boehmLib = "libgc.dylib"
-  else:
-    const boehmLib = "libgc.so.1"
-
-  proc boehmGCinit {.importc: "GC_init", dynlib: boehmLib.}
-  proc boehmGC_disable {.importc: "GC_disable", dynlib: boehmLib.}
-  proc boehmGC_enable {.importc: "GC_enable", dynlib: boehmLib.}
+  proc boehmGCinit {.importc: "GC_init", boehmGC.}
+  proc boehmGC_disable {.importc: "GC_disable", boehmGC.}
+  proc boehmGC_enable {.importc: "GC_enable", boehmGC.}
   proc boehmGCincremental {.
-    importc: "GC_enable_incremental", dynlib: boehmLib.}
-  proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.}
-  proc boehmAlloc(size: int): pointer {.
-    importc: "GC_malloc", dynlib: boehmLib.}
+    importc: "GC_enable_incremental", boehmGC.}
+  proc boehmGCfullCollect {.importc: "GC_gcollect", boehmGC.}
+  proc boehmAlloc(size: int): pointer {.importc: "GC_malloc", boehmGC.}
   proc boehmAllocAtomic(size: int): pointer {.
-    importc: "GC_malloc_atomic", dynlib: boehmLib.}
+    importc: "GC_malloc_atomic", boehmGC.}
   proc boehmRealloc(p: pointer, size: int): pointer {.
-    importc: "GC_realloc", dynlib: boehmLib.}
-  proc boehmDealloc(p: pointer) {.importc: "GC_free", dynlib: boehmLib.}
+    importc: "GC_realloc", boehmGC.}
+  proc boehmDealloc(p: pointer) {.importc: "GC_free", boehmGC.}
+  when hasThreadSupport:
+    proc boehmGC_allow_register_threads {.
+      importc: "GC_allow_register_threads", boehmGC.}
 
-  proc boehmGetHeapSize: int {.importc: "GC_get_heap_size", dynlib: boehmLib.}
+  proc boehmGetHeapSize: int {.importc: "GC_get_heap_size", boehmGC.}
     ## Return the number of bytes in the heap.  Excludes collector private
     ## data structures. Includes empty blocks and fragmentation loss.
     ## Includes some pages that were allocated but never written.
 
-  proc boehmGetFreeBytes: int {.importc: "GC_get_free_bytes", dynlib: boehmLib.}
+  proc boehmGetFreeBytes: int {.importc: "GC_get_free_bytes", boehmGC.}
     ## Return a lower bound on the number of free bytes in the heap.
 
-  proc boehmGetBytesSinceGC: int {.importc: "GC_get_bytes_since_gc",
-    dynlib: boehmLib.}
+  proc boehmGetBytesSinceGC: int {.importc: "GC_get_bytes_since_gc", boehmGC.}
     ## Return the number of bytes allocated since the last collection.
 
-  proc boehmGetTotalBytes: int {.importc: "GC_get_total_bytes",
-    dynlib: boehmLib.}
+  proc boehmGetTotalBytes: int {.importc: "GC_get_total_bytes", boehmGC.}
     ## Return the total number of bytes allocated in this process.
     ## Never decreases.
 
@@ -157,7 +150,9 @@ when defined(boehmgc):
     proc setStackBottom(theStackBottom: pointer) = discard
 
   proc initGC() =
-    when defined(macosx): boehmGCinit()
+    boehmGCinit()
+    when hasThreadSupport:
+      boehmGC_allow_register_threads()
 
   proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
     if ntfNoRefs in typ.flags: result = allocAtomic(size)
@@ -204,9 +199,6 @@ elif defined(gogc):
   else:
     const goLib = "libgo.so"
 
-  proc `div`[T: SomeUnsignedInt](x, y: T): T {.magic: "DivU", noSideEffect.}
-  proc `-`[T: SomeUnsignedInt](x, y: T): T {.magic: "SubU", noSideEffect.}
-
   proc roundup(x, v: int): int {.inline.} =
     result = (x + (v-1)) and not (v-1)
 
diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim
index 4841749a9..22430348c 100644
--- a/lib/system/nimscript.nim
+++ b/lib/system/nimscript.nim
@@ -31,7 +31,8 @@ proc moveFile(src, dest: string) {.
   tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin
 proc copyFile(src, dest: string) {.
   tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin
-proc createDir(dir: string) {.tags: [WriteIOEffect], raises: [OSError].} = builtin
+proc createDir(dir: string) {.tags: [WriteIOEffect], raises: [OSError].} =
+  builtin
 proc getOsError: string = builtin
 proc setCurrentDir(dir: string) = builtin
 proc getCurrentDir(): string = builtin
@@ -56,7 +57,7 @@ proc getCommand*(): string =
   ## "c", "js", "build", "help".
   builtin
 
-proc setCommand*(cmd: string) =
+proc setCommand*(cmd: string; project="") =
   ## Sets the Nim command that should be continued with after this Nimscript
   ## has finished.
   builtin
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
index c7cb8d9df..c5de841f8 100644
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -304,22 +304,53 @@ type
 when not defined(boehmgc) and not hasSharedHeap and not defined(gogc):
   proc deallocOsPages()
 
+when defined(boehmgc):
+  type GCStackBaseProc = proc(sb: pointer, t: pointer) {.noconv.}
+  proc boehmGC_call_with_stack_base(sbp: GCStackBaseProc, p: pointer)
+    {.importc: "GC_call_with_stack_base", boehmGC.}
+  proc boehmGC_register_my_thread(sb: pointer)
+    {.importc: "GC_register_my_thread", boehmGC.}
+  proc boehmGC_unregister_my_thread()
+    {.importc: "GC_unregister_my_thread", boehmGC.}
+
+  proc threadProcWrapDispatch[TArg](sb: pointer, thrd: pointer) {.noconv.} =
+    boehmGC_register_my_thread(sb)
+    let thrd = cast[ptr Thread[TArg]](thrd)
+    when TArg is void:
+      thrd.dataFn()
+    else:
+      thrd.dataFn(thrd.data)
+    boehmGC_unregister_my_thread()
+else:
+  proc threadProcWrapDispatch[TArg](thrd: ptr Thread[TArg]) =
+    when TArg is void:
+      thrd.dataFn()
+    else:
+      thrd.dataFn(thrd.data)
+
+proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) =
+  when defined(boehmgc):
+    boehmGC_call_with_stack_base(threadProcWrapDispatch[TArg], thrd)
+  elif not defined(nogc) and not defined(gogc):
+    var p {.volatile.}: proc(a: ptr Thread[TArg]) {.nimcall.} =
+      threadProcWrapDispatch[TArg]
+    when not hasSharedHeap:
+      # init the GC for refc/markandsweep
+      setStackBottom(addr(p))
+      initGC()
+    when declared(registerThread):
+      thrd.stackBottom = addr(thrd)
+      registerThread(thrd)
+    p(thrd)
+    when declared(registerThread): unregisterThread(thrd)
+    when declared(deallocOsPages): deallocOsPages()
+  else:
+    threadProcWrapDispatch(thrd)
+
 template threadProcWrapperBody(closure: expr) {.immediate.} =
   when declared(globalsSlot): threadVarSetValue(globalsSlot, closure)
-  var t = cast[ptr Thread[TArg]](closure)
-  when useStackMaskHack:
-    var tls: ThreadLocalStorage
-  when not defined(boehmgc) and not defined(gogc) and not defined(nogc) and not hasSharedHeap:
-    # init the GC for this thread:
-    setStackBottom(addr(t))
-    initGC()
-  when declared(registerThread):
-    t.stackBottom = addr(t)
-    registerThread(t)
-  when TArg is void: t.dataFn()
-  else: t.dataFn(t.data)
-  when declared(registerThread): unregisterThread(t)
-  when declared(deallocOsPages): deallocOsPages()
+  var thrd = cast[ptr Thread[TArg]](closure)
+  threadProcWrapStackFrame(thrd)
   # Since an unhandled exception terminates the whole process (!), there is
   # no need for a ``try finally`` here, nor would it be correct: The current
   # exception is tried to be re-raised by the code-gen after the ``finally``!
@@ -327,7 +358,7 @@ template threadProcWrapperBody(closure: expr) {.immediate.} =
   # page!
 
   # mark as not running anymore:
-  t.dataFn = nil
+  thrd.dataFn = nil
 
 {.push stack_trace:off.}
 when defined(windows):
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index 84dac6d79..89d86c62a 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -18,7 +18,7 @@ const
 type
   Handle* = int
   LONG* = int32
-  ULONG* = int
+  ULONG* = int32
   PULONG* = ptr int
   WINBOOL* = int32
   DWORD* = int32
@@ -108,6 +108,13 @@ const
 
   CREATE_UNICODE_ENVIRONMENT* = 1024'i32
 
+  PIPE_ACCESS_DUPLEX* = 0x00000003'i32
+  PIPE_ACCESS_INBOUND* = 1'i32
+  PIPE_ACCESS_OUTBOUND* = 2'i32
+  PIPE_NOWAIT* = 0x00000001'i32
+  SYNCHRONIZE* = 0x00100000'i32
+  FILE_FLAG_WRITE_THROUGH* = 0x80000000'i32
+
 proc closeHandle*(hObject: Handle): WINBOOL {.stdcall, dynlib: "kernel32",
     importc: "CloseHandle".}
 
@@ -125,6 +132,19 @@ proc createPipe*(hReadPipe, hWritePipe: var Handle,
                  nSize: int32): WINBOOL{.
     stdcall, dynlib: "kernel32", importc: "CreatePipe".}
 
+proc createNamedPipe*(lpName: WideCString,
+                     dwOpenMode, dwPipeMode, nMaxInstances, nOutBufferSize,
+                     nInBufferSize, nDefaultTimeOut: int32,
+                     lpSecurityAttributes: ptr SECURITY_ATTRIBUTES): Handle {.
+    stdcall, dynlib: "kernel32", importc: "CreateNamedPipeW".}
+
+proc peekNamedPipe*(hNamedPipe: Handle, lpBuffer: pointer=nil,
+                    nBufferSize: int32 = 0,
+                    lpBytesRead: ptr int32 = nil,
+                    lpTotalBytesAvail: ptr int32 = nil,
+                    lpBytesLeftThisMessage: ptr int32 = nil): bool {.
+    stdcall, dynlib: "kernel32", importc: "PeekNamedPipe".}
+
 when useWinUnicode:
   proc createProcessW*(lpApplicationName, lpCommandLine: WideCString,
                      lpProcessAttributes: ptr SECURITY_ATTRIBUTES,
@@ -615,12 +635,24 @@ const
 
   FILE_FLAG_BACKUP_SEMANTICS* = 33554432'i32
   FILE_FLAG_OPEN_REPARSE_POINT* = 0x00200000'i32
+  DUPLICATE_SAME_ACCESS* = 2
+  FILE_READ_DATA* = 0x00000001 # file & pipe
+  FILE_WRITE_DATA* = 0x00000002 # file & pipe
 
 # Error Constants
 const
   ERROR_ACCESS_DENIED* = 5
   ERROR_HANDLE_EOF* = 38
 
+proc duplicateHandle*(hSourceProcessHandle: HANDLE, hSourceHandle: HANDLE,
+                      hTargetProcessHandle: HANDLE,
+                      lpTargetHandle: ptr HANDLE,
+                      dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,
+                      dwOptions: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",
+    importc: "DuplicateHandle".}
+proc getCurrentProcess*(): HANDLE{.stdcall, dynlib: "kernel32",
+                                   importc: "GetCurrentProcess".}
+
 when useWinUnicode:
   proc createFileW*(lpFileName: WideCString, dwDesiredAccess, dwShareMode: DWORD,
                     lpSecurityAttributes: pointer,