summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/base/lex.nim73
-rw-r--r--lib/contnrs.nim12
-rw-r--r--lib/ecmas/dom.nim450
-rw-r--r--lib/ecmasys.nim527
-rw-r--r--lib/generics.nim170
-rw-r--r--lib/hashes.nim97
-rw-r--r--lib/lexbase.nim186
-rw-r--r--lib/macros.nim176
-rw-r--r--lib/parsecfg.nim366
-rw-r--r--lib/parseopt.nim154
-rw-r--r--lib/smallalc.nim19
-rw-r--r--lib/strtabs.nim210
-rw-r--r--lib/tinalloc.nim72
-rw-r--r--lib/wz_jsgraphics.js1107
14 files changed, 3619 insertions, 0 deletions
diff --git a/lib/base/lex.nim b/lib/base/lex.nim
new file mode 100644
index 000000000..34f0c32a8
--- /dev/null
+++ b/lib/base/lex.nim
@@ -0,0 +1,73 @@
+# Lexer generator for Nimrod
+#   (c) 2008 Andreas Rumpf
+
+# Stress testing for the macro feature
+
+# the syntax that should be supported is:
+
+# template numpostfix = 
+#   '\'' & 'F'|'f'|'i'|'I' & "32"|"64"|"8"|"16"
+# template edigits = 
+#   'e'|'E' & +digits
+# tokens(
+#   tkIdent: +UniIdentStart & *UniIdentRest,
+#   tkHexNumber: '0' & ('x'|'X') & +hexDigits & ?( numpostfix ),
+#   tkOctNumber: '0' & ('c'|'C') & +octDigits & ?( numpostfix ),
+#   tkBinNumber: '0' & ('b'|'B') & +binDigits & ?( numpostfix ),
+#   tkIntNumber: +digits & ?( numpostfix ), 
+#   tkFloatNumber: +digits & ('.' & +digits & ?(edigits) | edigits) & ?(numpostfix),
+#   
+# )
+# actions(
+#   tkIdent: lookup
+# ) 
+# 
+
+#
+#  match inputstream
+#  of +('A'..'Z' | '_' | 'a'..'z') *('A'..'Z' | '_' | 'a'..'z' | '0'..'9') :
+#    
+#    x = inputstream[pos..length]
+#  of '0' 'x' +('0'..'9' | 'a'..'f' | '_' | 'A'..'F') : 
+#    y = ...
+
+const
+  AsciiLetter = {'A'..'Z', 'a'..'z'}
+  uniLetter = AsciiLetter + {'\128'..'\255'}
+  digits = {'0'..'9'}
+  hexDigits = {'0'..'9', 'a'..'f', 'A'..'F'}
+  octDigits = {'0'..'7'}
+  binDigits = {'0'..'1'}
+  AsciiIdentStart = AsciiLetter + {'_'} 
+  AsciiIdentRest = AsciiIdentStart + Digits
+  UniIdentStart = UniLetter + {'_'} 
+  UniIdentRest = UniIdentStart + Digits
+
+# --> if match(s, +AsciiIdentStart & *AsciiIdentRest): 
+
+#  Regular expressions in Nimrod itself!
+#  -------------------------------------
+#  
+#  'a' -- matches the character a
+#  'a'..'z'  -- range operator '-'
+#  'A' | 'B' -- alternative operator |
+#  * 'a' -- prefix * is needed
+#  + 'a' -- prefix + is needed
+#  ? 'a' -- prefix ? is needed
+#  *? prefix is needed
+#  +? prefix is needed
+#  letter  -- character classes with real names!
+#  letters
+#  white
+#  whites
+#  any   -- any character
+#  ()    -- are Nimrod syntax
+#  ! 'a'-'z'
+#  
+#  -- concatentation via proc call:
+#  
+#  re('A' 'Z' *word  )
+
+macro re(n: expr): expr = 
+  
+  result = newCall("magic_re", x)
diff --git a/lib/contnrs.nim b/lib/contnrs.nim
new file mode 100644
index 000000000..c4db5a316
--- /dev/null
+++ b/lib/contnrs.nim
@@ -0,0 +1,12 @@
+# Container library for Nimrod
+# Implemented with macros, because generics sucks in many ways
+
+# Data structures for now:
+# TTable, TSet, TList
+# Algorithms: Trees, hashing,
+
+TTable[key, val, [Algorithm]]
+
+macro TTable(n: typeexpr): typeexpr =
+
+
diff --git a/lib/ecmas/dom.nim b/lib/ecmas/dom.nim
new file mode 100644
index 000000000..6d9224c26
--- /dev/null
+++ b/lib/ecmas/dom.nim
@@ -0,0 +1,450 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2006 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Declaration of the Document Object Model for the ECMAScript backend.
+##  (c) 2008 Andreas Rumpf
+
+when not defined(ecmascript):
+  {.error: "This module only works on the ECMAScript platform".}
+
+type
+  TEventHandlers* {.importc.} = object of TObject
+    onabort*: proc (event: ref TEvent)
+    onblur*: proc (event: ref TEvent)
+    onchange*: proc (event: ref TEvent)
+    onclick*: proc (event: ref TEvent)
+    ondblclick*: proc (event: ref TEvent)
+    onerror*: proc (event: ref TEvent)
+    onfocus*: proc (event: ref TEvent)
+    onkeydown*: proc (event: ref TEvent)
+    onkeypress*: proc (event: ref TEvent)
+    onkeyup*: proc (event: ref TEvent)
+    onload*: proc (event: ref TEvent)
+    onmousedown*: proc (event: ref TEvent)
+    onmousemove*: proc (event: ref TEvent)
+    onmouseout*: proc (event: ref TEvent)
+    onmouseover*: proc (event: ref TEvent)
+    onmouseup*: proc (event: ref TEvent)
+    onreset*: proc (event: ref TEvent)
+    onselect*: proc (event: ref TEvent)
+    onsubmit*: proc (event: ref TEvent)
+    onunload*: proc (event: ref TEvent)
+
+  TWindow* {.importc.} = object of TEventHandlers
+    document*: ref TDocument
+    event*: ref TEvent
+    history*: ref THistory
+    location*: ref TLocation
+    closed*: bool
+    defaultStatus*: cstring
+    innerHeight*, innerWidth*: int
+    locationbar*: ref TLocationBar
+    menubar*: ref TMenuBar
+    name*: cstring
+    outerHeight*, outerWidth*: int
+    pageXOffset*, pageYOffset*: int
+    personalbar*: ref TPersonalBar
+    scrollbars*: ref TScrollBars
+    statusbar*: ref TStatusBar
+    status*: cstring
+    toolbar*: ref TToolBar
+
+    alert*: proc (msg: cstring)
+    back*: proc ()
+    blur*: proc ()
+    captureEvents*: proc (eventMask: int)
+    clearInterval*: proc (interval: ref TInterval)
+    clearTimeout*: proc (timeout: ref TTimeOut)
+    close*: proc ()
+    confirm*: proc (msg: cstring): bool
+    disableExternalCapture*: proc ()
+    enableExternalCapture*: proc ()
+    find*: proc (text: cstring, caseSensitive = false, backwards = false)
+    focus*: proc ()
+    forward*: proc ()
+    handleEvent*: proc (e: ref TEvent)
+    home*: proc ()
+    moveBy*: proc (x, y: int)
+    moveTo*: proc (x, y: int)
+    open*: proc (uri, windowname: cstring,
+                 properties: cstring = nil): ref TWindow
+    print*: proc ()
+    prompt*: proc (text, default: cstring): cstring
+    releaseEvents*: proc (eventMask: int)
+    resizeBy*: proc (x, y: int)
+    resizeTo*: proc (x, y: int)
+    routeEvent*: proc (event: ref TEvent)
+    scrollBy*: proc (x, y: int)
+    scrollTo*: proc (x, y: int)
+    setInterval*: proc (code: cstring, pause: int): ref TInterval
+    setTimeout*: proc (code: cstring, pause: int): ref TTimeOut
+    stop*: proc ()
+    frames*: seq[TFrame]
+
+  TFrame* {.importc.} = object of TWindow
+
+  TDocument* {.importc.} = object of TEventHandlers
+    alinkColor*: cstring
+    bgColor*: cstring
+    charset*: cstring
+    cookie*: cstring
+    defaultCharset*: cstring
+    fgColor*: cstring
+    lastModified*: cstring
+    linkColor*: cstring
+    referrer*: cstring
+    title*: cstring
+    URL*: cstring
+    vlinkColor*: cstring
+    captureEvents*: proc (eventMask: int)
+    createAttribute*: proc (identifier: cstring): ref TNode
+    createElement*: proc (identifier: cstring): ref TNode
+    createTextNode*: proc (identifier: cstring): ref TNode
+    getElementById*: proc (id: cstring): ref TNode
+    getElementsByName*: proc (name: cstring): seq[ref TNode]
+    getElementsByTagName*: proc (name: cstring): seq[ref TNode]
+    getSelection*: proc (): cstring
+    handleEvent*: proc (event: ref TEvent)
+    open*: proc ()
+    releaseEvents*: proc (eventMask: int)
+    routeEvent*: proc (event: ref TEvent)
+    write*: proc (text: cstring)
+    writeln*: proc (text: cstring)
+    anchors*: seq[ref TAnchor]
+    forms*: seq[ref TForm]
+    images*: seq[ref TImage]
+    applets*: seq[ref TApplet]
+    embeds*: seq[ref TEmbed]
+    links*: seq[ref TLink]
+
+  TLink* {.importc.} = object of TObject
+    name*: cstring
+    target*: cstring
+    text*: cstring
+    x*: int
+    y*: int
+
+  TEmbed* {.importc.} = object of TObject
+    height*: int
+    hspace*: int
+    name*: cstring
+    src*: cstring
+    width*: int
+    `type`*: cstring
+    vspace*: int
+    play*: proc ()
+    stop*: proc ()
+
+  TAnchor* {.importc.} = object of TObject
+    name*: cstring
+    text*: cstring
+    x*, y*: int
+
+  TApplet* {.importc.} = object of TObject
+
+  TElement* {.importc.} = object of TEventHandlers
+    checked*: bool
+    defaultChecked*: bool
+    defaultValue*: cstring
+    disabled*: bool
+    form*: ref TForm
+    name*: cstring
+    readOnly*: bool
+    `type`*: cstring
+    value*: cstring
+    blur*: proc ()
+    click*: proc ()
+    focus*: proc ()
+    handleEvent*: proc (event: ref TEvent)
+    select*: proc ()
+    options*: seq[ref TOption]
+
+  TOption* {.importc.} = object of TObject
+    defaultSelected*: bool
+    selected*: bool
+    selectedIndex*: int
+    text*: cstring
+    value*: cstring
+
+  TForm* {.importc.} = object of TEventHandlers
+    action*: cstring
+    encoding*: cstring
+    `method`*: cstring
+    name*: cstring
+    target*: cstring
+    handleEvent*: proc (event: ref TEvent)
+    reset*: proc ()
+    submit*: proc ()
+    elements*: seq[ref TElement]
+
+  TImage* {.importc.} = object of TEventHandlers
+    border*: int
+    complete*: bool
+    height*: int
+    hspace*: int
+    lowsrc*: cstring
+    name*: cstring
+    src*: cstring
+    vspace*: int
+    width*: int
+    handleEvent*: proc (event: ref TEvent)
+
+  TNodeType* = enum
+    ElementNode = 1,
+    AttributeNode,
+    TextNode,
+    CDATANode,
+    EntityRefNode,
+    EntityNode,
+    ProcessingInstructionNode,
+    CommentNode,
+    DocumentNode,
+    DocumentTypeNode,
+    DocumentFragmentNode,
+    NotationNode
+  TNode* {.importc.} = object of TObject
+    attributes*: seq[ref TNode]
+    childNodes*: seq[ref TNode]
+    data*: cstring
+    firstChild*: ref TNode
+    lastChild*: ref TNode
+    nextSibling*: ref TNode
+    nodeName*: cstring
+    nodeType*: TNodeType
+    nodeValue*: cstring
+    parentNode*: ref TNode
+    previousSibling*: ref TNode
+    appendChild*: proc (child: ref TNode)
+    appendData*: proc (data: cstring)
+    cloneNode*: proc (copyContent: bool)
+    deleteData*: proc (start, len: int)
+    getAttribute*: proc (attr: cstring): cstring
+    getAttributeNode*: proc (attr: cstring): ref TNode
+    getElementsByTagName*: proc (): seq[ref TNode]
+    hasChildNodes*: proc (): bool
+    insertBefore*: proc (newNode, before: ref TNode)
+    insertData*: proc (position: int, data: cstring)
+    removeAttribute*: proc (attr: cstring)
+    removeAttributeNode*: proc (attr: ref TNode)
+    removeChild*: proc (child: ref TNode)
+    replaceChild*: proc (newNode, oldNode: ref TNode)
+    replaceData*: proc (start, len: int, text: cstring)
+    setAttribute*: proc (name, value: cstring)
+    setAttributeNode*: proc (attr: ref TNode)
+    style*: ref TStyle
+
+  TStyle* {.importc.} = object of TObject
+    background*: cstring
+    backgroundAttachment*: cstring
+    backgroundColor*: cstring
+    backgroundImage*: cstring
+    backgroundPosition*: cstring
+    backgroundRepeat*: cstring
+    border*: cstring
+    borderBottom*: cstring
+    borderBottomColor*: cstring
+    borderBottomStyle*: cstring
+    borderBottomWidth*: cstring
+    borderColor*: cstring
+    borderLeft*: cstring
+    borderLeftColor*: cstring
+    borderLeftStyle*: cstring
+    borderLeftWidth*: cstring
+    borderRight*: cstring
+    borderRightColor*: cstring
+    borderRightStyle*: cstring
+    borderRightWidth*: cstring
+    borderStyle*: cstring
+    borderTop*: cstring
+    borderTopColor*: cstring
+    borderTopStyle*: cstring
+    borderTopWidth*: cstring
+    borderWidth*: cstring
+    bottom*: cstring
+    captionSide*: cstring
+    clear*: cstring
+    clip*: cstring
+    color*: cstring
+    cursor*: cstring
+    direction*: cstring
+    display*: cstring
+    emptyCells*: cstring
+    cssFloat*: cstring
+    font*: cstring
+    fontFamily*: cstring
+    fontSize*: cstring
+    fontStretch*: cstring
+    fontStyle*: cstring
+    fontVariant*: cstring
+    fontWeight*: cstring
+    height*: cstring
+    left*: cstring
+    letterSpacing*: cstring
+    lineHeight*: cstring
+    listStyle*: cstring
+    listStyleImage*: cstring
+    listStylePosition*: cstring
+    listStyleType*: cstring
+    margin*: cstring
+    marginBottom*: cstring
+    marginLeft*: cstring
+    marginRight*: cstring
+    marginTop*: cstring
+    maxHeight*: cstring
+    maxWidth*: cstring
+    minHeight*: cstring
+    minWidth*: cstring
+    overflow*: cstring
+    padding*: cstring
+    paddingBottom*: cstring
+    paddingLeft*: cstring
+    paddingRight*: cstring
+    paddingTop*: cstring
+    pageBreakAfter*: cstring
+    pageBreakBefore*: cstring
+    position*: cstring
+    right*: cstring
+    scrollbar3dLightColor*: cstring
+    scrollbarArrowColor*: cstring
+    scrollbarBaseColor*: cstring
+    scrollbarDarkshadowColor*: cstring
+    scrollbarFaceColor*: cstring
+    scrollbarHighlightColor*: cstring
+    scrollbarShadowColor*: cstring
+    scrollbarTrackColor*: cstring
+    tableLayout*: cstring
+    textAlign*: cstring
+    textDecoration*: cstring
+    textIndent*: cstring
+    textTransform*: cstring
+    top*: cstring
+    verticalAlign*: cstring
+    visibility*: cstring
+    width*: cstring
+    wordSpacing*: cstring
+    zIndex*: int
+    getAttribute*: proc (attr: cstring, caseSensitive=false): cstring
+    removeAttribute*: proc (attr: cstring, caseSensitive=false)
+    setAttribute*: proc (attr, value: cstring, caseSensitive=false)
+
+  TEvent* {.importc.} = object of TObject
+    altKey*, ctrlKey*, shiftKey*: bool
+    button*: int
+    clientX*, clientY*: int
+    keyCode*: int
+    layerX*, layerY*: int
+    modifiers*: int
+    ALT_MASK*, CONTROL_MASK*, SHIFT_MASK*, META_MASK*: int
+    offsetX*, offsetY*: int
+    pageX*, pageY*: int
+    screenX*, screenY*: int
+    which*: int
+    `type`*: cstring
+    x*, y*: int
+    ABORT*: int
+    BLUR*: int
+    CHANGE*: int
+    CLICK*: int
+    DBLCLICK*: int
+    DRAGDROP*: int
+    ERROR*: int
+    FOCUS*: int
+    KEYDOWN*: int
+    KEYPRESS*: int
+    KEYUP*: int
+    LOAD*: int
+    MOUSEDOWN*: int
+    MOUSEMOVE*: int
+    MOUSEOUT*: int
+    MOUSEOVER*: int
+    MOUSEUP*: int
+    MOVE*: int
+    RESET*: int
+    RESIZE*: int
+    SELECT*: int
+    SUBMIT*: int
+    UNLOAD*: int
+
+  TLocation* {.importc.} = object of TObject
+    hash*: cstring
+    host*: cstring
+    hostname*: cstring
+    href*: cstring
+    pathname*: cstring
+    port*: cstring
+    protocol*: cstring
+    search*: cstring
+    reload*: proc ()
+    replace*: proc (s: cstring)
+
+  THistory* {.importc.} = object of TObject
+    length*: int
+    back*: proc ()
+    forward*: proc ()
+    go*: proc (pagesToJump: int)
+
+  TNavigator* {.importc.} = object of TObject
+    appCodeName*: cstring
+    appName*: cstring
+    appVersion*: cstring
+    cookieEnabled*: bool
+    language*: cstring
+    platform*: cstring
+    userAgent*: cstring
+    javaEnabled*: proc (): bool
+    mimeTypes*: seq[ref TMimeType]
+
+  TPlugin* {.importc.} = object of TObject
+    description*: cstring
+    filename*: cstring
+    name*: cstring
+
+  TMimeType* {.importc.} = object of TObject
+    description*: cstring
+    enabledPlugin*: ref TPlugin
+    suffixes*: seq[cstring]
+    `type`*: cstring
+
+  TLocationBar* {.importc.} = object of TObject
+    visible*: bool
+  TMenuBar* = TLocationBar
+  TPersonalBar* = TLocationBar
+  TScrollBars* = TLocationBar
+  TToolBar* = TLocationBar
+  TStatusBar* = TLocationBar
+
+  TScreen* {.importc.} = object of TObject
+    availHeight*: int
+    availWidth*: int
+    colorDepth*: int
+    height*: int
+    pixelDepth*: int
+    width*: int
+
+  TTimeOut* {.importc.} = object of TObject
+  TInterval* {.importc.} = object of TObject
+
+var
+  window* {.importc, nodecl.}: ref TWindow
+  document* {.importc, nodecl.}: ref TDocument
+  navigator* {.importc, nodecl.}: ref TNavigator
+  screen* {.importc, nodecl.}: ref TScreen
+
+proc decodeURI*(uri: cstring): cstring {.importc, nodecl.}
+proc encodeURI*(uri: cstring): cstring {.importc, nodecl.}
+
+proc escape*(uri: cstring): cstring {.importc, nodecl.}
+proc unescape*(uri: cstring): cstring {.importc, nodecl.}
+
+proc decodeURIComponent*(uri: cstring): cstring {.importc, nodecl.}
+proc encodeURIComponent*(uri: cstring): cstring {.importc, nodecl.}
+proc isFinite(x: biggestFloat): bool {.importc, nodecl.}
+proc isNaN(x: biggestFloat): bool {.importc, nodecl.}
+proc parseFloat(s: cstring): biggestFloat {.importc, nodecl.}
+proc parseInt(s: cstring): int {.importc, nodecl.}
diff --git a/lib/ecmasys.nim b/lib/ecmasys.nim
new file mode 100644
index 000000000..10a6247d4
--- /dev/null
+++ b/lib/ecmasys.nim
@@ -0,0 +1,527 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2008 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Stubs for the GC interface:
+
+proc GC_disable() = nil
+proc GC_enable() = nil
+proc GC_fullCollect() = nil
+proc GC_setStrategy(strategy: TGC_Strategy) = nil
+proc GC_enableMarkAndSweep() = nil
+proc GC_disableMarkAndSweep() = nil
+
+proc getOccupiedMem(): int = return -1
+proc getFreeMem(): int = return -1
+proc getTotalMem(): int = return -1
+
+proc alert(s: cstring) {.importc, nodecl.}
+
+type
+  PSafePoint = ptr TSafePoint
+  TSafePoint {.compilerproc, final.} = object
+    prev: PSafePoint # points to next safe point
+    exc: ref E_Base
+
+  PCallFrame = ptr TCallFrame
+  TCallFrame {.importc, nodecl, final.} = object
+    prev: PCallFrame
+    procname: CString
+    line: int # current line number
+    filename: CString
+
+var
+  framePtr {.importc, nodecl, volatile.}: PCallFrame
+  excHandler {.importc, nodecl, volatile.}: PSafePoint = nil
+    # list of exception handlers
+    # a global variable for the root of all try blocks
+
+{.push stacktrace: off.}
+proc nimBoolToStr(x: bool): string {.compilerproc.} =
+  if x: result = "true"
+  else: result = "false"
+
+proc nimCharToStr(x: char): string {.compilerproc.} =
+  result = newString(1)
+  result[0] = x
+
+proc getCurrentExceptionMsg(): string =
+  if excHandler != nil: return $excHandler.exc.msg
+  return ""
+
+proc auxWriteStackTrace(f: PCallFrame): string =
+  type
+    TTempFrame = tuple[procname: CString, line: int]
+  var
+    it = f
+    i = 0
+    total = 0
+    tempFrames: array [0..63, TTempFrame]
+  while it != nil and i <= high(tempFrames):
+    tempFrames[i].procname = it.procname
+    tempFrames[i].line = it.line
+    inc(i)
+    inc(total)
+    it = it.prev
+  while it != nil:
+    inc(total)
+    it = it.prev
+  result = ""
+  # if the buffer overflowed print '...':
+  if total != i:
+    add(result, "(")
+    add(result, $(total-i))
+    add(result, " calls omitted) ...\n")
+  for j in countdown(i-1, 0):
+    add(result, tempFrames[j].procname)
+    if tempFrames[j].line > 0:
+      add(result, ", line: ")
+      add(result, $tempFrames[j].line)
+    add(result, "\n")
+
+proc rawWriteStackTrace(): string =
+  if framePtr == nil:
+    result = "No stack traceback available\n"
+  else:
+    result = "Traceback (most recent call last)\n"& auxWriteStackTrace(framePtr)
+    framePtr = nil
+
+proc raiseException(e: ref E_Base, ename: cstring) {.compilerproc, pure.} =
+  e.name = ename
+  if excHandler != nil:
+    excHandler.exc = e
+  else:
+    var buf = rawWriteStackTrace()
+    if e.msg != nil and e.msg[0] != '\0':
+      add(buf, "Error: unhandled exception: ")
+      add(buf, e.msg)
+    else:
+      add(buf, "Error: unhandled exception")
+    add(buf, " [")
+    add(buf, ename)
+    add(buf, "]\n")
+    alert(buf)
+  asm """throw `e`;"""
+
+proc reraiseException() =
+  if excHandler == nil:
+    raise newException(ENoExceptionToReraise, "no exception to reraise")
+  else:
+    asm """throw excHandler.exc;"""
+
+proc raiseOverflow {.exportc: "raiseOverflow", noreturn.} =
+  raise newException(EOverflow, "over- or underflow")
+
+proc raiseDivByZero {.exportc: "raiseDivByZero", noreturn.} =
+  raise newException(EDivByZero, "divison by zero")
+
+proc raiseRangeError() {.compilerproc, noreturn.} =
+  raise newException(EOutOfRange, "value out of range")
+
+proc raiseIndexError() {.compilerproc, noreturn.} =
+  raise newException(EInvalidIndex, "index out of bounds")
+
+proc raiseFieldError(f: string) {.compilerproc, noreturn.} =
+  raise newException(EInvalidField, f & " is not accessible")
+
+
+
+proc SetConstr() {.varargs, pure, compilerproc.} =
+  asm """
+    var result = {};
+    for (var i = 0; i < arguments.length; ++i) {
+      var x = arguments[i];
+      if (typeof(x) == "object") {
+        for (var j = x[0]; j <= x[1]; ++j) {
+          result[j] = true;
+        }
+      } else {
+        result[x] = true;
+      }
+    }
+    return result;
+  """
+
+proc cstrToNimstr(c: cstring): string {.pure, compilerproc.} =
+  asm """
+    var result = [];
+    for (var i = 0; i < `c`.length; ++i) {
+      result[i] = `c`.charCodeAt(i);
+    }
+    result[result.length] = 0; // terminating zero
+    return result;
+  """
+
+proc toEcmaStr(s: string): cstring {.pure, compilerproc.} =
+  asm """
+    var len = `s`.length-1;
+    var result = new Array(len);
+    var fcc = String.fromCharCode;
+    for (var i = 0; i < len; ++i) {
+      result[i] = fcc(`s`[i]);
+    }
+    return result.join("");
+  """
+
+proc mnewString(len: int): string {.pure, compilerproc.} =
+  asm """
+    var result = new Array(`len`+1);
+    result[0] = 0;
+    result[`len`] = 0;
+    return result;
+  """
+
+proc SetCard(a: int): int {.compilerproc, pure.} =
+  # argument type is a fake
+  asm """
+    var result = 0;
+    for (var elem in `a`) { ++result; }
+    return result;
+  """
+
+proc SetEq(a, b: int): bool {.compilerproc, pure.} =
+  asm """
+    for (var elem in `a`) { if (!`b`[elem]) return false; }
+    for (var elem in `b`) { if (!`a`[elem]) return false; }
+    return true;
+  """
+
+proc SetLe(a, b: int): bool {.compilerproc, pure.} =
+  asm """
+    for (var elem in `a`) { if (!`b`[elem]) return false; }
+    return true;
+  """
+
+proc SetLt(a, b: int): bool {.compilerproc.} =
+  result = SetLe(a, b) and not SetEq(a, b)
+
+proc SetMul(a, b: int): int {.compilerproc, pure.} =
+  asm """
+    var result = {};
+    for (var elem in `a`) {
+      if (`b`[elem]) { result[elem] = true; }
+    }
+    return result;
+  """
+
+proc SetPlus(a, b: int): int {.compilerproc, pure.} =
+  asm """
+    var result = {};
+    for (var elem in `a`) { result[elem] = true; }
+    for (var elem in `b`) { result[elem] = true; }
+    return result;
+  """
+
+proc SetMinus(a, b: int): int {.compilerproc, pure.} =
+  asm """
+    var result = {};
+    for (var elem in `a`) {
+      if (!`b`[elem]) { result[elem] = true; }
+    }
+    return result;
+  """
+
+proc cmpStrings(a, b: string): int {.pure, compilerProc.} =
+  asm """
+    if (`a` == `b`) return 0;
+    if (!`a`) return -1;
+    if (!`b`) return 1;
+    for (var i = 0; i < `a`.length-1; ++i) {
+      var result = `a`[i] - `b`[i];
+      if (result != 0) return result;
+    }
+    return 0;
+  """
+
+proc cmp(x, y: string): int = return cmpStrings(x, y)
+
+proc eqStrings(a, b: string): bool {.pure, compilerProc.} =
+  asm """
+    if (`a == `b`) return true;
+    if ((!`a`) || (!`b`)) return false;
+    var alen = `a`.length;
+    if (alen != `b`.length) return false;
+    for (var i = 0; i < alen; ++i)
+      if (`a`[i] != `b`[i]) return false;
+    return true;
+  """
+
+type
+  TDocument {.importc.} = object of TObject
+    write: proc (text: cstring)
+    writeln: proc (text: cstring)
+    createAttribute: proc (identifier: cstring): ref TNode
+    createElement: proc (identifier: cstring): ref TNode
+    createTextNode: proc (identifier: cstring): ref TNode
+    getElementById: proc (id: cstring): ref TNode
+    getElementsByName: proc (name: cstring): seq[ref TNode]
+    getElementsByTagName: proc (name: cstring): seq[ref TNode]
+
+  TNodeType* = enum
+    ElementNode = 1,
+    AttributeNode,
+    TextNode,
+    CDATANode,
+    EntityRefNode,
+    EntityNode,
+    ProcessingInstructionNode,
+    CommentNode,
+    DocumentNode,
+    DocumentTypeNode,
+    DocumentFragmentNode,
+    NotationNode
+  TNode* {.importc.} = object of TObject
+    attributes*: seq[ref TNode]
+    childNodes*: seq[ref TNode]
+    data*: cstring
+    firstChild*: ref TNode
+    lastChild*: ref TNode
+    nextSibling*: ref TNode
+    nodeName*: cstring
+    nodeType*: TNodeType
+    nodeValue*: cstring
+    parentNode*: ref TNode
+    previousSibling*: ref TNode
+    appendChild*: proc (child: ref TNode)
+    appendData*: proc (data: cstring)
+    cloneNode*: proc (copyContent: bool)
+    deleteData*: proc (start, len: int)
+    getAttribute*: proc (attr: cstring): cstring
+    getAttributeNode*: proc (attr: cstring): ref TNode
+    getElementsByTagName*: proc (): seq[ref TNode]
+    hasChildNodes*: proc (): bool
+    insertBefore*: proc (newNode, before: ref TNode)
+    insertData*: proc (position: int, data: cstring)
+    removeAttribute*: proc (attr: cstring)
+    removeAttributeNode*: proc (attr: ref TNode)
+    removeChild*: proc (child: ref TNode)
+    replaceChild*: proc (newNode, oldNode: ref TNode)
+    replaceData*: proc (start, len: int, text: cstring)
+    setAttribute*: proc (name, value: cstring)
+    setAttributeNode*: proc (attr: ref TNode)
+    
+var
+  document {.importc, nodecl.}: ref TDocument
+
+proc ewriteln(x: cstring) = 
+  var node = document.getElementsByTagName("body")[0]
+  if node != nil: 
+    node.appendChild(document.createTextNode(x))
+    node.appendChild(document.createElement("br"))
+  else: 
+    raise newException(EInvalidValue, "<body> element does not exist yet!")
+
+proc echo*(x: int) = ewriteln($x)
+proc echo*(x: float) = ewriteln($x)
+proc echo*(x: bool) = ewriteln(if x: cstring("true") else: cstring("false"))
+proc echo*(x: string) = ewriteln(x)
+proc echo*(x: cstring) = ewriteln(x)
+
+proc echo[Ty](x: Ty) =
+  echo(x)
+
+# Arithmetic:
+proc addInt(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    var result = `a` + `b`;
+    if (result > 2147483647 || result < -2147483648) raiseOverflow();
+    return result;
+  """
+
+proc subInt(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    var result = `a` - `b`;
+    if (result > 2147483647 || result < -2147483648) raiseOverflow();
+    return result;
+  """
+
+proc mulInt(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    var result = `a` * `b`;
+    if (result > 2147483647 || result < -2147483648) raiseOverflow();
+    return result;
+  """
+
+proc divInt(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    if (`b` == 0) raiseDivByZero();
+    if (`b` == -1 && `a` == 2147483647) raiseOverflow();
+    return Math.floor(`a` / `b`);
+  """
+
+proc modInt(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    if (`b` == 0) raiseDivByZero();
+    if (`b` == -1 && `a` == 2147483647) raiseOverflow();
+    return Math.floor(`a` % `b`);
+  """
+
+
+
+proc addInt64(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    var result = `a` + `b`;
+    if (result > 9223372036854775807
+    || result < -9223372036854775808) raiseOverflow();
+    return result;
+  """
+
+proc subInt64(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    var result = `a` - `b`;
+    if (result > 9223372036854775807
+    || result < -9223372036854775808) raiseOverflow();
+    return result;
+  """
+
+proc mulInt64(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    var result = `a` * `b`;
+    if (result > 9223372036854775807
+    || result < -9223372036854775808) raiseOverflow();
+    return result;
+  """
+
+proc divInt64(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    if (`b` == 0) raiseDivByZero();
+    if (`b` == -1 && `a` == 9223372036854775807) raiseOverflow();
+    return Math.floor(`a` / `b`);
+  """
+
+proc modInt64(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    if (`b` == 0) raiseDivByZero();
+    if (`b` == -1 && `a` == 9223372036854775807) raiseOverflow();
+    return Math.floor(`a` % `b`);
+  """
+
+proc nimMin(a, b: int): int {.compilerproc.} = return if a <= b: a else: b
+proc nimMax(a, b: int): int {.compilerproc.} = return if a >= b: a else: b
+
+proc internalAssert(file: cstring, line: int) {.pure, compilerproc.} =
+  var
+    e: ref EAssertionFailed
+  new(e)
+  asm """`e`.message = "[Assertion failure] file: "+`file`+", line: "+`line`"""
+  raise e
+
+include hti
+
+proc isFatPointer(ti: PNimType): bool =
+  # This has to be consistens with the code generator!
+  return ti.base.kind notin {tyRecord, tyRecordConstr, tyObject,
+    tyArray, tyArrayConstr, tyPureObject, tyTuple,
+    tyEmptySet, tyOpenArray, tySet, tyVar, tyRef, tyPtr}
+
+proc NimCopy(x: pointer, ti: PNimType): pointer {.compilerproc.}
+
+proc NimCopyAux(dest, src: Pointer, n: ptr TNimNode) {.exportc.} =
+  case n.kind
+  of nkNone: assert(false)
+  of nkSlot:
+    asm "`dest`[`n`.offset] = NimCopy(`src`[`n`.offset], `n`.typ);"
+  of nkList:
+    for i in 0..n.len-1:
+      NimCopyAux(dest, src, n.sons[i])
+  of nkCase:
+    asm """
+      `dest`[`n`.offset] = NimCopy(`src`[`n`.offset], `n`.typ);
+      for (var i = 0; i < `n`.sons.length; ++i) {
+        NimCopyAux(`dest`, `src`, `n`.sons[i][1]);
+      }
+    """
+
+proc NimCopy(x: pointer, ti: PNimType): pointer =
+  case ti.kind
+  of tyPtr, tyRef, tyVar, tyNil:
+    if not isFatPointer(ti):
+      result = x
+    else:
+      asm """
+        `result` = [null, 0];
+        `result`[0] = `x`[0];
+        `result`[1] = `x`[1];
+      """
+  of tyEmptySet, tySet:
+    asm """
+      `result` = {};
+      for (var key in `x`) { `result`[key] = `x`[key]; }
+    """
+  of tyPureObject, tyTuple, tyObject:
+    if ti.base != nil: result = NimCopy(x, ti.base)
+    elif ti.kind == tyObject:
+      asm "`result` = {m_type: `ti`};"
+    else:
+      asm "`result` = {};"
+    NimCopyAux(result, x, ti.node)
+  of tySequence, tyArrayConstr, tyOpenArray, tyArray:
+    asm """
+      `result` = new Array(`x`.length);
+      for (var i = 0; i < `x`.length; ++i) {
+        `result`[i] = NimCopy(`x`[i], `ti`.base);
+      }
+    """
+  of tyString:
+    asm "`result` = `x`.slice(0);"
+  else:
+    result = x
+
+
+proc ArrayConstr(len: int, value: pointer, typ: PNimType): pointer {.
+                 pure, compilerproc.} =
+  # types are fake
+  asm """
+    var result = new Array(`len`);
+    for (var i = 0; i < `len`; ++i) result[i] = NimCopy(`value`, `typ`);
+    return result;
+  """
+
+proc chckIndx(i, a, b: int): int {.compilerproc.} =
+  if i >= a and i <= b: return i
+  else: raiseIndexError()
+
+proc chckRange(i, a, b: int): int {.compilerproc.} =
+  if i >= a and i <= b: return i
+  else: raiseRangeError()
+
+proc chckObj(obj, subclass: PNimType) {.compilerproc.} =
+  # checks if obj is of type subclass:
+  var x = obj
+  if x == subclass: return # optimized fast path
+  while x != subclass:
+    if x == nil:
+      raise newException(EInvalidObjectConversion, "invalid object conversion")
+    x = x.base
+
+{.pop.}
+
+#proc AddU($1, $2)
+#SubU($1, $2)
+#MulU($1, $2)
+#DivU($1, $2)
+#ModU($1, $2)
+#AddU64($1, $2)
+#SubU64($1, $2)
+#MulU64($1, $2)
+#DivU64($1, $2)
+#ModU64($1, $2)
+#LeU($1, $2)
+#LtU($1, $2)
+#LeU64($1, $2)
+#LtU64($1, $2)
+#Ze($1)
+#Ze64($1)
+#ToU8($1)
+#ToU16($1)
+#ToU32($1)
+
+#NegInt($1)
+#NegInt64($1)
+#AbsInt($1)
+#AbsInt64($1)
diff --git a/lib/generics.nim b/lib/generics.nim
new file mode 100644
index 000000000..10e55f5bd
--- /dev/null
+++ b/lib/generics.nim
@@ -0,0 +1,170 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2008 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains basic abstract data types.
+
+type
+  TListItem[T] = object
+    next, prev: ref TListItem[T]
+    data: T
+
+  TList*[T] = ref TListItem[T]
+#  TIndex*[T] = object
+
+#proc succ*[T](i: TIndex[T]): TIndex[T] =
+#  result = i.next
+
+#proc pred*[T](i: TIndex[T]): TIndex[T] =
+#  result = i.prev
+
+#proc getIndex*[T](c: TList[T]): TIndex[TList[T]] =
+#  return c
+
+proc init*[T](c: var TList[T]) {.inline.} =
+  c = nil
+
+iterator items*[T](c: TList[T]): var T {.inline.} =
+  var it = c
+  while it != nil:
+    yield it.data
+    it = it.next
+
+proc add*[T](c: var TList[T], item: T) {.inline.} =
+  var it: ref TListItem[T]
+  new(it)
+  it.data = item
+  it.prev = c.prev
+  it.next = c.next
+  c = it
+
+proc incl*[T](c: var TList[T], item: T) =
+  for i in items(c):
+    if i == item: return
+  add(c, item)
+
+proc excl*[T](c: var TList[T], item: T) =
+  var it: TList[T] = c
+  while it != nil:
+    if it.data == item:
+      # remove from list
+    it = it.next
+
+proc del*[T](c: var TList[T], item: T) {.inline.} = excl(c, item)
+
+proc hash*(p: pointer): int {.inline.} =
+  # Returns the hash value of a pointer. This is very fast.
+  return cast[TAddress](p) shr 3
+
+proc hash*(x: int): int {.inline.} = return x
+proc hash*(x: char): int {.inline.} = return ord(x)
+proc hash*(x: bool): int {.inline.} = return ord(x)
+
+proc hash*(s: string): int =
+  # The generic hash table implementation work on a type `T` that has a hash
+  # proc. Predefined for string, pointers, int, char, bool.
+  var h = 0
+  for i in 0..s.len-1:
+    h = h +% Ord(s[i])
+    h = h +% h shl 10
+    h = h xor (h shr 6)
+  h = h +% h shl 3
+  h = h xor (h shr 11)
+  h = h +% h shl 15
+  result = h
+
+proc isNil*(x: int): bool {.inline.} = return x == low(int)
+proc nilValue*(x: int): int {.inline.} = return low(int)
+proc nilValue*(x: pointer): pointer {.inline.} = return nil
+proc nilValue*(x: string): string {.inline.} = return nil
+proc nilValue*[T](x: seq[T]): seq[T] {.inline.} = return nil
+proc nilValue*(x: float): float {.inline.} = return NaN
+
+proc mustRehash(len, counter: int): bool =
+  assert(len > counter)
+  result = (len * 2 < counter * 3) or (len-counter < 4)
+
+proc nextTry(h, maxHash: int): int {.inline.} =
+  return ((5*%h) +% 1) and maxHash
+
+type
+  TPair*[TKey, TValue] = tuple[key: TKey, val: TValue]
+  TTable*[TKey, TValue] =
+      object of TObject ## A table which stores (key, value)
+                        ## pairs. The used algorithm is hashing.
+    d: seq[TPair[TKey, TValue]]
+    counter: natural
+
+const
+  growthFactor = 2 # must be power of two
+
+proc init*[TKey, TValue](t: var TTable[TKey, TValue], capacity: natural = 32) =
+  t.d = [] # XXX
+  setLen(t.d, capacity)
+
+proc len*[TKey, TValue](t: TTable[TKey, TValue]): natural = return t.counter
+
+iterator pairs*[TKey,TValue](t: TTable[TKey,TValue]): TPair[TKey, TValue] =
+  for i in 0..t.d.len-1:
+    if not isNil(t.d[i].key):
+      yield (t.d[i].key, t.d[i].val)
+
+proc TableRawGet[TKey, TValue](t: TTable[TKey, TValue], key: TKey): int =
+  var h = hash(key) and high(t.d)
+  while not isNil(t.d[h].key):
+    if t.d[h].key == key: return h
+    h = nextTry(h, high(t.d))
+  return -1
+
+proc `[]`*[TKey, TValue](t: TTable[TKey, TValue], key: TKey): TValue =
+  var index = TableRawGet(t, key)
+  return if index >= 0: t.d[index].val else: nilValue(t.d[0].val)
+
+proc TableRawInsert[TKey, TValue](data: var seq[TPair[TKey, TValue]],
+                                  key: TKey, val: TValue) =
+  var h = hash(key) and high(data)
+  while not isNil(data[h].key):
+    assert(data[h].key != key)
+    h = nextTry(h, high(data))
+  assert(isNil(data[h].key))
+  data[h].key = key
+  data[h].val = val
+
+proc TableEnlarge[TKey, TValue](t: var TTable[TKey, TValue]) =
+  var n: seq[TPair[TKey,TValue]] = []
+  setLen(n, len(t.d) * growthFactor) # XXX
+  for i in 0..high(t.d):
+    if not isNil(t.d[i].key):
+      TableRawInsert(n, t.d[i].key, t.d[i].val)
+  swap(t.d, n)
+
+proc `[]=`*[TKey, TValue](t: var TTable[TKey, TValue], key: TKey, val: TValue) =
+  var index = TableRawGet(t, key)
+  if index >= 0:
+    t.d[index].val = val
+  else:
+    if mustRehash(len(t.d), t.counter): TableEnlarge(t)
+    TableRawInsert(t.d, key, val)
+    inc(t.counter)
+
+proc add*[TKey, TValue](t: var TTable[TKey, TValue], key: TKey, val: TValue) =
+  if mustRehash(len(t.d), t.counter): TableEnlarge(t)
+  TableRawInsert(t.d, key, val)
+  inc(t.counter)
+
+proc test =
+  var
+    t: TTable[string, int]
+  init(t)
+  t["key1"] = 1
+  t["key2"] = 2
+  t["key3"] = 3
+  for key, val in pairs(t):
+    echo(key & " = " & $val)
+
+test()
diff --git a/lib/hashes.nim b/lib/hashes.nim
new file mode 100644
index 000000000..ed7871008
--- /dev/null
+++ b/lib/hashes.nim
@@ -0,0 +1,97 @@
+#

+#

+#            Nimrod's Runtime Library

+#        (c) Copyright 2008 Andreas Rumpf

+#

+#    See the file "copying.txt", included in this

+#    distribution, for details about the copyright.

+#

+

+## This module implements efficient computations of hash values for diverse

+## Nimrod types.

+

+import 

+  strutils

+

+type 

+  THash* = int ## a hash value; hash tables using these values should 

+               ## always have a size of a power of two and can use the ``and``

+               ## operator instead of ``mod`` for truncation of the hash value.

+

+proc concHash(h: THash, val: int): THash {.inline.} = 

+  result = h +% val

+  result = result +% result shl 10

+  result = result xor (result shr 6)

+

+proc finishHash(h: THash): THash {.inline.} = 

+  result = h +% h shl 3

+  result = result xor (result shr 11)

+  result = result +% result shl 15

+

+proc hashData*(Data: Pointer, Size: int): THash = 

+  ## hashes an array of bytes of size `size`

+  var 

+    h: THash

+    p: cstring

+    i, s: int

+  h = 0

+  p = cast[cstring](Data)

+  i = 0

+  s = size

+  while s > 0: 

+    h = concHash(h, ord(p[i]))

+    Inc(i)

+    Dec(s)

+  result = finishHash(h)

+

+proc hash*(x: Pointer): THash {.inline.} = 

+  ## efficient hashing of pointers

+  result = (cast[THash](x)) shr 3 # skip the alignment

+  

+proc hash*(x: int): THash {.inline.} = 

+  ## efficient hashing of integers

+  result = x

+

+proc hash*(x: int64): THash {.inline.} = 

+  ## efficient hashing of integers

+  result = toU32(x)

+

+proc hash*(x: char): THash {.inline.} = 

+  ## efficient hashing of characters

+  result = ord(x)

+

+proc hash*(x: string): THash = 

+  ## efficient hashing of strings

+  var h: THash

+  h = 0

+  for i in 0..x.len-1: 

+    h = concHash(h, ord(x[i]))

+  result = finishHash(h)

+  

+proc hashIgnoreStyle*(x: string): THash = 

+  ## efficient hashing of strings; style is ignored

+  var 

+    h: THash

+    c: Char

+  h = 0

+  for i in 0..x.len-1: 

+    c = x[i]

+    if c == '_': 

+      continue                # skip _

+    if c in {'A'..'Z'}: 

+      c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()

+    h = concHash(h, ord(c))

+  result = finishHash(h)

+

+proc hashIgnoreCase*(x: string): THash = 

+  ## efficient hashing of strings; case is ignored

+  var 

+    h: THash

+    c: Char

+  h = 0

+  for i in 0..x.len-1: 

+    c = x[i]

+    if c in {'A'..'Z'}: 

+      c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()

+    h = concHash(h, ord(c))

+  result = finishHash(h)

diff --git a/lib/lexbase.nim b/lib/lexbase.nim
new file mode 100644
index 000000000..d2522359f
--- /dev/null
+++ b/lib/lexbase.nim
@@ -0,0 +1,186 @@
+#

+#

+#           The Nimrod Compiler

+#        (c) Copyright 2008 Andreas Rumpf

+#

+#    See the file "copying.txt", included in this

+#    distribution, for details about the copyright.

+#

+

+## This module implements a base object of a lexer with efficient buffer

+## handling. In fact I believe that this is the most efficient method of

+## buffer handling that exists! Only at line endings checks are necessary

+## if the buffer needs refilling.

+

+import 

+  strutils

+

+const 

+  EndOfFile* = '\0'           ## end of file marker

+                              # A little picture makes everything clear :-)

+                              #  buf:

+                              #  "Example Text\n ha!"   bufLen = 17

+                              #   ^pos = 0     ^ sentinel = 12

+                              #

+  NewLines* = {'\c', '\L'}

+

+type 

+  TBaseLexer* = object of TObject ## the base lexer. Inherit your lexer from

+                                  ## this object.

+    bufpos*: int              ## the current position within the buffer

+    buf*: cstring             ## the buffer itself

+    bufLen*: int              ## length of buffer in characters

+    f*: tfile                 ## the file that is read

+    LineNumber*: int          ## the current line number

+    sentinel: int

+    lineStart: int            # index of last line start in buffer

+    fileOpened: bool

+

+proc initBaseLexer*(L: var TBaseLexer, filename: string, bufLen: int = 8192): bool

+  ## inits the TBaseLexer object with a file to scan

+

+proc initBaseLexerFromBuffer*(L: var TBaseLexer, buffer: string)

+  ## inits the TBaseLexer with a buffer to scan

+

+proc deinitBaseLexer*(L: var TBaseLexer)

+  ## deinitializes the base lexer. This needs to be called to close the file.

+

+proc getCurrentLine*(L: TBaseLexer, marker: bool = true): string

+  ## retrieves the current line. 

+

+proc getColNumber*(L: TBaseLexer, pos: int): int

+  ## retrieves the current column. 

+  

+proc HandleCR*(L: var TBaseLexer, pos: int): int

+  ## Call this if you scanned over '\c' in the buffer; it returns the the

+  ## position to continue the scanning from. `pos` must be the position

+  ## of the '\c'.

+proc HandleLF*(L: var TBaseLexer, pos: int): int

+  ## Call this if you scanned over '\L' in the buffer; it returns the the

+  ## position to continue the scanning from. `pos` must be the position

+  ## of the '\L'.

+  

+# implementation

+

+const 

+  chrSize = sizeof(char)

+

+proc deinitBaseLexer(L: var TBaseLexer) = 

+  dealloc(L.buf)

+  if L.fileOpened: closeFile(L.f)

+  

+proc FillBuffer(L: var TBaseLexer) = 

+  var 

+    charsRead, toCopy, s: int # all are in characters,

+                              # not bytes (in case this

+                              # is not the same)

+    oldBufLen: int

+  # we know here that pos == L.sentinel, but not if this proc

+  # is called the first time by initBaseLexer()

+  assert(L.sentinel < L.bufLen)

+  toCopy = L.BufLen - L.sentinel - 1

+  assert(toCopy >= 0)

+  if toCopy > 0: 

+    MoveMem(L.buf, addr(L.buf[L.sentinel + 1]), toCopy * chrSize) # "moveMem" handles overlapping regions

+  charsRead = ReadBuffer(L.f, addr(L.buf[toCopy]), (L.sentinel + 1) * chrSize) div

+      chrSize

+  s = toCopy + charsRead

+  if charsRead < L.sentinel + 1: 

+    L.buf[s] = EndOfFile      # set end marker

+    L.sentinel = s

+  else: 

+    # compute sentinel:

+    dec(s)                    # BUGFIX (valgrind)

+    while true: 

+      assert(s < L.bufLen)

+      while (s >= 0) and not (L.buf[s] in NewLines): Dec(s)

+      if s >= 0: 

+        # we found an appropriate character for a sentinel:

+        L.sentinel = s

+        break 

+      else: 

+        # rather than to give up here because the line is too long,

+        # double the buffer's size and try again:

+        oldBufLen = L.BufLen

+        L.bufLen = L.BufLen * 2

+        L.buf = cast[cstring](realloc(L.buf, L.bufLen * chrSize))

+        assert(L.bufLen - oldBuflen == oldBufLen)

+        charsRead = ReadBuffer(L.f, addr(L.buf[oldBufLen]), oldBufLen * chrSize) div

+            chrSize

+        if charsRead < oldBufLen: 

+          L.buf[oldBufLen + charsRead] = EndOfFile

+          L.sentinel = oldBufLen + charsRead

+          break 

+        s = L.bufLen - 1

+

+proc fillBaseLexer(L: var TBaseLexer, pos: int): int = 

+  assert(pos <= L.sentinel)

+  if pos < L.sentinel: 

+    result = pos + 1          # nothing to do

+  else: 

+    fillBuffer(L)

+    L.bufpos = 0              # XXX: is this really correct?

+    result = 0

+  L.lineStart = result

+

+proc HandleCR(L: var TBaseLexer, pos: int): int = 

+  assert(L.buf[pos] == '\c')

+  inc(L.linenumber)

+  result = fillBaseLexer(L, pos)

+  if L.buf[result] == '\L': 

+    result = fillBaseLexer(L, result)

+

+proc HandleLF(L: var TBaseLexer, pos: int): int = 

+  assert(L.buf[pos] == '\L')

+  inc(L.linenumber)

+  result = fillBaseLexer(L, pos) #L.lastNL := result-1; // BUGFIX: was: result;

+  

+proc skip_UTF_8_BOM(L: var TBaseLexer) = 

+  if (L.buf[0] == '\xEF') and (L.buf[1] == '\xBB') and (L.buf[2] == '\xBF'): 

+    inc(L.bufpos, 3)

+    inc(L.lineStart, 3)

+

+proc initBaseLexer(L: var TBaseLexer, filename: string, bufLen: int = 8192): bool = 

+  assert(bufLen > 0)

+  L.bufpos = 0

+  L.bufLen = bufLen

+  L.buf = cast[cstring](alloc(bufLen * chrSize))

+  L.sentinel = bufLen - 1

+  L.lineStart = 0

+  L.linenumber = 1            # lines start at 1

+  L.fileOpened = openFile(L.f, filename)

+  result = L.fileOpened

+  if result: 

+    fillBuffer(L)

+    skip_UTF_8_BOM(L)

+

+proc initBaseLexerFromBuffer(L: var TBaseLexer, buffer: string) = 

+  L.bufpos = 0

+  L.bufLen = len(buffer) + 1

+  L.buf = cast[cstring](alloc(L.bufLen * chrSize))

+  L.sentinel = L.bufLen - 1

+  L.lineStart = 0

+  L.linenumber = 1            # lines start at 1

+  L.fileOpened = false

+  if L.bufLen > 0: 

+    copyMem(L.buf, cast[pointer](buffer), L.bufLen)

+    L.buf[L.bufLen - 1] = EndOfFile

+  else: 

+    L.buf[0] = EndOfFile

+  skip_UTF_8_BOM(L)

+

+proc getColNumber(L: TBaseLexer, pos: int): int = 

+  result = pos - L.lineStart

+  assert(result >= 0)

+

+proc getCurrentLine(L: TBaseLexer, marker: bool = true): string = 

+  var i: int

+  result = ""

+  i = L.lineStart

+  while not (L.buf[i] in {'\c', '\L', EndOfFile}): 

+    add(result, L.buf[i])

+    inc(i)

+  add(result, "\n")

+  if marker: 

+    add(result, RepeatChar(getColNumber(L, L.bufpos)) & "^\n")

+  

diff --git a/lib/macros.nim b/lib/macros.nim
new file mode 100644
index 000000000..af5e0d17d
--- /dev/null
+++ b/lib/macros.nim
@@ -0,0 +1,176 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2008 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+## This module contains the interface to the compiler's abstract syntax tree.
+## Abstract syntax trees should be modified in macros.
+
+#[[[cog
+#def toEnum(name, elems, prefix):
+#  body = ""
+#  counter = 0
+#  for e in elems:
+#    if counter % 4 == 0: p = "\n    "
+#    else: p = ""
+#    body += p + prefix + e[2:] + ', '
+#    counter += 1
+#
+#  return "  TNimrod%s* = enum%s\n  TNim%ss* = set[TNimrod%s]\n" \
+#            % (name, body.rstrip(", "), name, name)
+#
+#enums = eval(file("data/ast.yml").read())
+#cog.out("type\n")
+#i = 0
+#for key, val in enums.iteritems():
+#  if key.endswith("Flag"): continue
+#  cog.out(toEnum(key, val, ["nnk", "nty", "nsk"][i]))
+#  i += 1
+#]]]
+type
+  TNimrodNodeKind* = enum
+    nnkNone, nnkEmpty, nnkIdent, nnkSym, 
+    nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit, 
+    nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkFloatLit, 
+    nnkFloat32Lit, nnkFloat64Lit, nnkStrLit, nnkRStrLit, 
+    nnkTripleStrLit, nnkMetaNode, nnkNilLit, nnkDotCall, 
+    nnkCommand, nnkCall, nnkGenericCall, nnkExplicitTypeListCall, 
+    nnkExprEqExpr, nnkExprColonExpr, nnkIdentDefs, nnkInfix, 
+    nnkPrefix, nnkPostfix, nnkPar, nnkCurly, 
+    nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange, 
+    nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr, 
+    nnkElifExpr, nnkElseExpr, nnkLambda, nnkAccQuoted, 
+    nnkHeaderQuoted, nnkTableConstr, nnkQualified, nnkHiddenStdConv, 
+    nnkHiddenSubConv, nnkHiddenCallConv, nnkConv, nnkCast, 
+    nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv, 
+    nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange, 
+    nnkStringToCString, nnkCStringToString, nnkPassAsOpenArray, nnkAsgn, 
+    nnkDefaultTypeParam, nnkGenericParams, nnkFormalParams, nnkOfInherit, 
+    nnkModule, nnkProcDef, nnkConverterDef, nnkMacroDef, 
+    nnkTemplateDef, nnkIteratorDef, nnkOfBranch, nnkElifBranch, 
+    nnkExceptBranch, nnkElse, nnkMacroStmt, nnkAsmStmt, 
+    nnkPragma, nnkIfStmt, nnkWhenStmt, nnkForStmt, 
+    nnkWhileStmt, nnkCaseStmt, nnkVarSection, nnkConstSection, 
+    nnkConstDef, nnkTypeSection, nnkTypeDef, nnkYieldStmt, 
+    nnkTryStmt, nnkFinally, nnkRaiseStmt, nnkReturnStmt, 
+    nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkDiscardStmt, 
+    nnkStmtList, nnkImportStmt, nnkFromStmt, nnkImportAs, 
+    nnkIncludeStmt, nnkAccessStmt, nnkCommentStmt, nnkStmtListExpr, 
+    nnkBlockExpr, nnkVm, nnkTypeOfExpr, nnkObjectTy, 
+    nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen, 
+    nnkRefTy, nnkPtrTy, nnkVarTy, nnkProcTy, 
+    nnkEnumTy, nnkEnumFieldDef, nnkReturnToken
+  TNimNodeKinds* = set[TNimrodNodeKind]
+  TNimrodTypeKind* = enum
+    ntyNone, ntyBool, ntyChar, ntyEmptySet, 
+    ntyArrayConstr, ntyNil, ntyGeneric, ntyGenericInst, 
+    ntyGenericParam, ntyEnum, ntyAnyEnum, ntyArray, 
+    ntyObject, ntyTuple, ntySet, ntyRange, 
+    ntyPtr, ntyRef, ntyVar, ntySequence, 
+    ntyProc, ntyPointer, ntyOpenArray, ntyString, 
+    ntyCString, ntyForward, ntyInt, ntyInt8, 
+    ntyInt16, ntyInt32, ntyInt64, ntyFloat, 
+    ntyFloat32, ntyFloat64, ntyFloat128
+  TNimTypeKinds* = set[TNimrodTypeKind]
+  TNimrodSymKind* = enum
+    nskUnknownSym, nskConditional, nskDynLib, nskParam, 
+    nskTypeParam, nskTemp, nskType, nskConst, 
+    nskVar, nskProc, nskIterator, nskConverter, 
+    nskMacro, nskTemplate, nskField, nskEnumField, 
+    nskForVar, nskModule, nskLabel
+  TNimSymKinds* = set[TNimrodSymKind]
+#[[[end]]]
+
+type
+  TNimrodNode {.final.} = object   # hidden
+  TNimrodSymbol {.final.} = object # hidden
+  TNimrodType {.final.} = object   # hidden
+  PNimrodType* {.compilerproc.} = ref TNimrodType
+  PNimrodSymbol* {.compilerproc.} = ref TNimrodSymbol
+  PNimrodNode* {.compilerproc.} = ref TNimrodNode
+  expr* = PNimrodNode
+  stmt* = PNimrodNode
+
+# Nodes should be reference counted to make the `copy` operation very fast!
+# However, this is difficult to achieve: modify(n[0][1]) should propagate to
+# its father. How to do this without back references?
+
+proc `[]`* (n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild".}
+proc `[]=`* (n: PNimrodNode, i: int, child: PNimrodNode) {.magic: "NSetChild".}
+  ## provide access to `n`'s children
+
+type
+  TNimrodIdent = object of TObject
+
+converter StrToIdent*(s: string): TNimrodIdent {.magic: "StrToIdent".}
+proc `$`*(i: TNimrodIdent): string {.magic: "IdentToStr".}
+proc `==`* (a, b: TNimrodIdent): bool {.magic: "EqIdent".}
+
+proc len*(n: PNimrodNode): int {.magic: "NLen".}
+
+## returns the number of children that a node has
+proc add*(father, child: PNimrodNode) {.magic: "NAdd".}
+proc add*(father: PNimrodNode, child: openArray[PNimrodNode]) {.magic: "NAddMultiple".}
+proc del*(father: PNimrodNode, idx = 0, n = 1) {.magic: "NDel".}
+proc kind*(n: PNimrodNode): TNimrodNodeKind {.magic: "NKind".}
+
+proc intVal*(n: PNimrodNode): biggestInt {.magic: "NIntVal".}
+proc floatVal*(n: PNimrodNode): biggestFloat {.magic: "NFloatVal".}
+proc symbol*(n: PNimrodNode): PNimrodSymbol {.magic: "NSymbol".}
+proc ident*(n: PNimrodNode): TNimrodIdent {.magic: "NIdent".}
+proc typ*(n: PNimrodNode): PNimrodType {.magic: "NGetType".}
+proc strVal*(n: PNimrodNode): string  {.magic: "NStrVal".}
+
+proc `intVal=`*(n: PNimrodNode, val: biggestInt) {.magic: "NSetIntVal".}
+proc `floatVal=`*(n: PNimrodNode, val: biggestFloat) {.magic: "NSetFloatVal".}
+proc `symbol=`*(n: PNimrodNode, val: PNimrodSymbol) {.magic: "NSetSymbol".}
+proc `ident=`*(n: PNimrodNode, val: TNimrodIdent) {.magic: "NSetIdent".}
+proc `typ=`*(n: PNimrodNode, typ: PNimrodType) {.magic: "NSetType".}
+proc `strVal=`*(n: PNimrodNode, val: string) {.magic: "NSetStrVal".}
+
+proc newNimNode*(kind: TNimrodNodeKind,
+                 n: PNimrodNode=nil): PNimrodNode {.magic: "NNewNimNode".}
+proc copyNimNode*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimNode".}
+proc copyNimTree*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimTree".}
+
+proc error*(msg: string) {.magic: "NError".}
+proc warning*(msg: string) {.magic: "NWarning".}
+proc hint*(msg: string) {.magic: "NHint".}
+
+proc newStrLitNode*(s: string): PNimrodNode {.nodecl.} = 
+  result = newNimNode(nnkStrLit)
+  result.strVal = s
+
+proc newIntLitNode*(i: biggestInt): PNimrodNode {.nodecl.} = 
+  result = newNimNode(nnkIntLit)
+  result.intVal = i
+
+proc newIntLitNode*(f: biggestFloat): PNimrodNode {.nodecl.} = 
+  result = newNimNode(nnkFloatLit)
+  result.floatVal = f
+
+proc newIdentNode*(i: TNimrodIdent): PNimrodNode {.nodecl.} = 
+  result = newNimNode(nnkIdent)
+  result.ident = i
+
+proc toStrLit*(n: PNimrodNode): PNimrodNode {.nodecl.} = 
+  return newStrLitNode(repr(n))
+
+proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.nodecl.} =
+  if n.kind != k: error("macro expects a node of kind: " & repr(k))
+
+proc expectMinLen*(n: PNimrodNode, min: int) {.nodecl.} =
+  if n.len < min: error("macro expects a node with " & $min & " children")
+
+proc newCall*(theProc: TNimrodIdent,
+              args: openArray[PNimrodNode]): PNimrodNode {.nodecl.} =
+  ## produces a new call node. `theProc` is the proc that is called with
+  ## the arguments ``args[0..]``.
+  result = newNimNode(nnkCall)
+  result.add(newIdentNode(theProc))
+  result.add(args)
diff --git a/lib/parsecfg.nim b/lib/parsecfg.nim
new file mode 100644
index 000000000..96305349e
--- /dev/null
+++ b/lib/parsecfg.nim
@@ -0,0 +1,366 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2008 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## The ``parsecfg`` module implements a high performance configuration file 
+## parser. The configuration file's syntax is similar to the Windows ``.ini`` 
+## format, but much more powerful, as it is not a line based parser. String 
+## literals, raw string literals and triple quote string literals are supported 
+## as in the Nimrod programming language.
+
+## This is an example of how a configuration file may look like:
+##
+## .. include:: doc/mytest.cfg
+##     :literal:
+## The file ``tests/tparscfg.nim`` demonstrates how to use the 
+## configuration file parser:
+##
+## .. code-block:: nimrod
+##     :file: tests/tparscfg.nim
+
+
+import 
+  hashes, strutils, lexbase
+
+type 
+  TCfgEventKind* = enum ## enumation of all events that may occur when parsing
+    cfgEof,             ## end of file reached
+    cfgSectionStart,    ## a ``[section]`` has been parsed
+    cfgKeyValuePair,    ## a ``key=value`` pair has been detected
+    cfgOption,          ## a ``--key=value`` command line option
+    cfgError            ## an error ocurred during parsing
+    
+  TCfgEvent* = object of TObject ## describes a parsing event
+    case kind*: TCfgEventKind    ## the kind of the event
+    of cfgEof: dummy: string
+    of cfgSectionStart: 
+      section*: string           ## `section` contains the name of the 
+                                 ## parsed section start (syntax: ``[section]``)
+    of cfgKeyValuePair, cfgOption: 
+      key*, value*: string       ## contains the (key, value) pair if an option
+                                 ## of the form ``--key: value`` or an ordinary
+                                 ## ``key= value`` pair has been parsed.
+                                 ## ``value==""`` if it was not specified in the
+                                 ## configuration file.
+    of cfgError:                 ## the parser encountered an error: `msg`
+      msg*: string               ## contains the error message. No exceptions
+                                 ## are thrown if a parse error occurs.
+  
+  TTokKind = enum 
+    tkInvalid, tkEof,        
+    tkSymbol, tkEquals, tkColon, tkBracketLe, tkBracketRi, tkDashDash
+  TToken{.final.} = object   # a token
+    kind: TTokKind           # the type of the token
+    literal: string          # the parsed (string) literal
+  
+  TParserState = enum 
+    startState, commaState
+  TCfgParser* = object of TBaseLexer ## the parser object.
+    tok: TToken
+    state: TParserState
+    filename: string
+
+proc Open*(c: var TCfgParser, filename: string): bool
+  ## initializes the parser, open the file for reading and returns true if
+  ## successful (the file has been found).
+
+proc OpenFromBuffer*(c: var TCfgParser, buf: string)
+  ## initializes the parser with a buffer. This cannot fail.
+
+proc close*(c: var TCfgParser)
+  ## closes the parser `c`.
+
+proc next*(c: var TCfgParser): TCfgEvent
+  ## retrieves the first/next event. This controls the parser.
+
+proc getColumn*(c: TCfgParser): int
+  ## get the current column the parser has arrived at.
+
+proc getLine*(c: TCfgParser): int
+  ## get the current line the parser has arrived at.
+  
+proc getFilename*(c: TCfgParser): string
+  ## get the filename of the file that the parser processes.
+
+
+# implementation
+
+const 
+  SymChars: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF'} 
+  
+proc rawGetTok(c: var TCfgParser, tok: var TToken)
+proc open(c: var TCfgParser, filename: string): bool = 
+  result = initBaseLexer(c, filename)
+  c.filename = filename
+  c.state = startState
+  c.tok.kind = tkInvalid
+  c.tok.literal = ""
+  if result: rawGetTok(c, c.tok)
+  
+proc openFromBuffer(c: var TCfgParser, buf: string) = 
+  initBaseLexerFromBuffer(c, buf)
+  c.filename = "buffer"
+  c.state = startState
+  c.tok.kind = tkInvalid
+  c.tok.literal = ""
+  rawGetTok(c, c.tok)
+
+proc close(c: var TCfgParser) = 
+  deinitBaseLexer(c)
+
+proc getColumn(c: TCfgParser): int = 
+  result = getColNumber(c, c.bufPos)
+
+proc getLine(c: TCfgParser): int = 
+  result = c.linenumber
+
+proc getFilename(c: TCfgParser): string = 
+  result = c.filename
+
+proc handleHexChar(c: var TCfgParser, xi: var int) = 
+  case c.buf[c.bufpos]
+  of '0'..'9': 
+    xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'))
+    inc(c.bufpos)
+  of 'a'..'f': 
+    xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10)
+    inc(c.bufpos)
+  of 'A'..'F': 
+    xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
+    inc(c.bufpos)
+  else: 
+    nil
+
+proc handleDecChars(c: var TCfgParser, xi: var int) = 
+  while c.buf[c.bufpos] in {'0'..'9'}: 
+    xi = (xi * 10) + (ord(c.buf[c.bufpos]) - ord('0'))
+    inc(c.bufpos)
+
+proc getEscapedChar(c: var TCfgParser, tok: var TToken) = 
+  var xi: int
+  inc(c.bufpos)               # skip '\'
+  case c.buf[c.bufpos]
+  of 'n', 'N': 
+    tok.literal = tok.literal & nl
+    Inc(c.bufpos)
+  of 'r', 'R', 'c', 'C': 
+    add(tok.literal, '\c')
+    Inc(c.bufpos)
+  of 'l', 'L': 
+    add(tok.literal, '\L')
+    Inc(c.bufpos)
+  of 'f', 'F': 
+    add(tok.literal, '\f')
+    inc(c.bufpos)
+  of 'e', 'E': 
+    add(tok.literal, '\e')
+    Inc(c.bufpos)
+  of 'a', 'A': 
+    add(tok.literal, '\a')
+    Inc(c.bufpos)
+  of 'b', 'B': 
+    add(tok.literal, '\b')
+    Inc(c.bufpos)
+  of 'v', 'V': 
+    add(tok.literal, '\v')
+    Inc(c.bufpos)
+  of 't', 'T': 
+    add(tok.literal, '\t')
+    Inc(c.bufpos)
+  of '\'', '\"': 
+    add(tok.literal, c.buf[c.bufpos])
+    Inc(c.bufpos)
+  of '\\': 
+    add(tok.literal, '\\')
+    Inc(c.bufpos)
+  of 'x', 'X': 
+    inc(c.bufpos)
+    xi = 0
+    handleHexChar(c, xi)
+    handleHexChar(c, xi)
+    add(tok.literal, Chr(xi))
+  of '0'..'9': 
+    xi = 0
+    handleDecChars(c, xi)
+    if (xi <= 255): add(tok.literal, Chr(xi))
+    else: tok.kind = tkInvalid
+  else: tok.kind = tkInvalid
+  
+proc HandleCRLF(c: var TCfgParser, pos: int): int = 
+  case c.buf[pos]
+  of '\c': result = lexbase.HandleCR(c, pos)
+  of '\L': result = lexbase.HandleLF(c, pos)
+  else: result = pos
+  
+proc getString(c: var TCfgParser, tok: var TToken, rawMode: bool) = 
+  var 
+    pos: int
+    ch: Char
+    buf: cstring
+  pos = c.bufPos + 1          # skip "
+  buf = c.buf                 # put `buf` in a register
+  tok.kind = tkSymbol
+  if (buf[pos] == '\"') and (buf[pos + 1] == '\"'): 
+    # long string literal:
+    inc(pos, 2)               # skip ""
+                              # skip leading newline:
+    pos = HandleCRLF(c, pos)
+    while true: 
+      case buf[pos]
+      of '\"': 
+        if (buf[pos + 1] == '\"') and (buf[pos + 2] == '\"'): break 
+        add(tok.literal, '\"')
+        Inc(pos)
+      of '\c', '\L': 
+        pos = HandleCRLF(c, pos)
+        tok.literal = tok.literal & nl
+      of lexbase.EndOfFile: 
+        tok.kind = tkInvalid
+        break 
+      else: 
+        add(tok.literal, buf[pos])
+        Inc(pos)
+    c.bufpos = pos +
+        3                     # skip the three """
+  else: 
+    # ordinary string literal
+    while true: 
+      ch = buf[pos]
+      if ch == '\"': 
+        inc(pos)              # skip '"'
+        break 
+      if ch in {'\c', '\L', lexbase.EndOfFile}: 
+        tok.kind = tkInvalid
+        break 
+      if (ch == '\\') and not rawMode: 
+        c.bufPos = pos
+        getEscapedChar(c, tok)
+        pos = c.bufPos
+      else: 
+        add(tok.literal, ch)
+        Inc(pos)
+    c.bufpos = pos
+
+proc getSymbol(c: var TCfgParser, tok: var TToken) = 
+  var 
+    pos: int
+    buf: cstring
+  pos = c.bufpos
+  buf = c.buf
+  while true: 
+    add(tok.literal, buf[pos])
+    Inc(pos)
+    if not (buf[pos] in SymChars): break 
+  c.bufpos = pos
+  tok.kind = tkSymbol
+
+proc skip(c: var TCfgParser) = 
+  var 
+    buf: cstring
+    pos: int
+  pos = c.bufpos
+  buf = c.buf
+  while true: 
+    case buf[pos]
+    of ' ', '\t': 
+      Inc(pos)
+    of '#', ';': 
+      while not (buf[pos] in {'\c', '\L', lexbase.EndOfFile}): inc(pos)
+    of '\c', '\L': 
+      pos = HandleCRLF(c, pos)
+    else: 
+      break                   # EndOfFile also leaves the loop
+  c.bufpos = pos
+
+proc rawGetTok(c: var TCfgParser, tok: var TToken) = 
+  tok.kind = tkInvalid
+  setlen(tok.literal, 0)
+  skip(c)
+  case c.buf[c.bufpos]
+  of '=': 
+    tok.kind = tkEquals
+    inc(c.bufpos)
+  of '-': 
+    inc(c.bufPos)
+    if c.buf[c.bufPos] == '-': inc(c.bufPos)
+    tok.kind = tkDashDash
+    tok.literal = "--"
+  of ':': 
+    tok.kind = tkColon
+    inc(c.bufpos)
+    tok.literal = ":"
+  of 'r', 'R': 
+    if c.buf[c.bufPos + 1] == '\"': 
+      Inc(c.bufPos)
+      getString(c, tok, true)
+    else: 
+      getSymbol(c, tok)
+  of '[': 
+    tok.kind = tkBracketLe
+    inc(c.bufpos)
+    tok.literal = "]"
+  of ']': 
+    tok.kind = tkBracketRi
+    Inc(c.bufpos)
+    tok.literal = "]"
+  of '\"': 
+    getString(c, tok, false)
+  of lexbase.EndOfFile: 
+    tok.kind = tkEof
+  else: getSymbol(c, tok)
+  
+proc errorStr(c: TCfgParser, msg: string): string = 
+  result = `%`("$1($2, $3) Error: $4", 
+               [c.filename, toString(getLine(c)), toString(getColumn(c)), msg])
+
+proc getKeyValPair(c: var TCfgParser, kind: TCfgEventKind): TCfgEvent = 
+  if c.tok.kind == tkSymbol: 
+    result.kind = kind
+    result.key = c.tok.literal
+    result.value = ""
+    rawGetTok(c, c.tok)
+    if c.tok.kind in {tkEquals, tkColon}: 
+      rawGetTok(c, c.tok)
+      if c.tok.kind == tkSymbol: 
+        result.value = c.tok.literal
+      else: 
+        result.kind = cfgError
+        result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
+      rawGetTok(c, c.tok)
+  else: 
+    result.kind = cfgError
+    result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
+    rawGetTok(c, c.tok)
+
+proc next(c: var TCfgParser): TCfgEvent = 
+  case c.tok.kind  
+  of tkEof: 
+    result.kind = cfgEof
+  of tkDashDash: 
+    rawGetTok(c, c.tok)
+    result = getKeyValPair(c, cfgOption)
+  of tkSymbol: 
+    result = getKeyValPair(c, cfgKeyValuePair)
+  of tkBracketLe: 
+    rawGetTok(c, c.tok)
+    if c.tok.kind == tkSymbol: 
+      result.kind = cfgSectionStart
+      result.section = c.tok.literal
+    else: 
+      result.kind = cfgError
+      result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
+    rawGetTok(c, c.tok)
+    if c.tok.kind == tkBracketRi: 
+      rawGetTok(c, c.tok)
+    else: 
+      result.kind = cfgError
+      result.msg = errorStr(c, "\']\' expected, but found: " & c.tok.literal)
+  of tkInvalid, tkEquals, tkColon, tkBracketRi: 
+    result.kind = cfgError
+    result.msg = errorStr(c, "invalid token: " & c.tok.literal)
+    rawGetTok(c, c.tok)
diff --git a/lib/parseopt.nim b/lib/parseopt.nim
new file mode 100644
index 000000000..243b7497f
--- /dev/null
+++ b/lib/parseopt.nim
@@ -0,0 +1,154 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2008 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module provides the standard Nimrod command line parser.
+## It supports one convenience iterator over all command line options and some
+## lower-level features.
+
+{.push debugger: off.}
+
+import 
+  os, strutils
+
+type 
+  TCmdLineKind* = enum        ## the detected command line token
+    cmdEnd,                   ## end of command line reached
+    cmdArgument,              ## argument detected
+    cmdLongoption,            ## a long option ``--option`` detected
+    cmdShortOption            ## a short option ``-c`` detected
+  TOptParser* = 
+      object of TObject ## this object implements the command line parser  
+    cmd: string
+    pos: int
+    inShortState: bool
+    kind*: TCmdLineKind       ## the dected command line token
+    key*, val*: string        ## key and value pair; ``key`` is the option
+                              ## or the argument, ``value`` is not "" if
+                              ## the option was given a value
+
+proc init*(cmdline: string = ""): TOptParser
+  ## inits the option parser. If ``cmdline == ""``, the real command line
+  ## (as provided by the ``OS`` module) is taken.
+
+proc next*(p: var TOptParser)
+  ## parses the first or next option; ``p.kind`` describes what token has been
+  ## parsed. ``p.key`` and ``p.val`` are set accordingly.
+
+proc getRestOfCommandLine*(p: TOptParser): string
+  ## retrieves the rest of the command line that has not been parsed yet.
+
+# implementation
+
+proc init(cmdline: string = ""): TOptParser = 
+  result.pos = strStart
+  result.inShortState = false
+  if cmdline != "": 
+    result.cmd = cmdline
+  else: 
+    result.cmd = ""
+    for i in countup(1, ParamCount()): 
+      result.cmd = result.cmd & quoteIfSpaceExists(paramStr(i)) & ' '
+  result.kind = cmdEnd
+  result.key = ""
+  result.val = ""
+
+proc parseWord(s: string, i: int, w: var string, 
+               delim: TCharSet = {'\x09', ' ', '\0'}): int = 
+  result = i
+  if s[result] == '\"': 
+    inc(result)
+    while not (s[result] in {'\0', '\"'}): 
+      add(w, s[result])
+      inc(result)
+    if s[result] == '\"': inc(result)
+  else: 
+    while not (s[result] in delim): 
+      add(w, s[result])
+      inc(result)
+
+proc handleShortOption(p: var TOptParser) = 
+  var i: int
+  i = p.pos
+  p.kind = cmdShortOption
+  add(p.key, p.cmd[i])
+  inc(i)
+  p.inShortState = true
+  while p.cmd[i] in {'\x09', ' '}: 
+    inc(i)
+    p.inShortState = false
+  if p.cmd[i] in {':', '='}: 
+    inc(i)
+    p.inShortState = false
+    while p.cmd[i] in {'\x09', ' '}: inc(i)
+    i = parseWord(p.cmd, i, p.val)
+  if p.cmd[i] == '\0': p.inShortState = false
+  p.pos = i
+
+proc next(p: var TOptParser) = 
+  var i: int
+  i = p.pos
+  while p.cmd[i] in {'\x09', ' '}: inc(i)
+  p.pos = i
+  setlen(p.key, 0)
+  setlen(p.val, 0)
+  if p.inShortState: 
+    handleShortOption(p)
+    return 
+  case p.cmd[i]
+  of '\0': 
+    p.kind = cmdEnd
+  of '-': 
+    inc(i)
+    if p.cmd[i] == '-': 
+      p.kind = cmdLongOption
+      inc(i)
+      i = parseWord(p.cmd, i, p.key, {'\0', ' ', '\x09', ':', '='})
+      while p.cmd[i] in {'\x09', ' '}: inc(i)
+      if p.cmd[i] in {':', '='}: 
+        inc(i)
+        while p.cmd[i] in {'\x09', ' '}: inc(i)
+        p.pos = parseWord(p.cmd, i, p.val)
+      else: 
+        p.pos = i
+    else: 
+      p.pos = i
+      handleShortOption(p)
+  else: 
+    p.kind = cmdArgument
+    p.pos = parseWord(p.cmd, i, p.key)
+
+proc getRestOfCommandLine(p: TOptParser): string = 
+  result = strip(copy(p.cmd, p.pos + strStart, len(p.cmd) - 1)) 
+
+iterator getopt*(): tuple[kind: TCmdLineKind, key, val: string] =
+  ##this is an convenience iterator for iterating over the command line.
+  ##This uses the TOptParser object. Example:
+  ##
+  ## .. code-block:: nimrod
+  ##   var
+  ##     filename = ""
+  ##   for kind, key, val in getopt():
+  ##     case kind
+  ##     of cmdArgument: 
+  ##       filename = key
+  ##     of cmdLongOption, cmdShortOption:
+  ##       case key
+  ##       of "help", "h": writeHelp()
+  ##       of "version", "v": writeVersion()
+  ##     of cmdEnd: assert(false) # cannot happen
+  ##   if filename == "":
+  ##     # no filename has been given, so we show the help:
+  ##     writeHelp()
+  var p = init()
+  while true:
+    next(p)
+    if p.kind == cmdEnd: break
+    yield (p.kind, p.key, p.val)
+
+{.pop.}
diff --git a/lib/smallalc.nim b/lib/smallalc.nim
new file mode 100644
index 000000000..b5a99db35
--- /dev/null
+++ b/lib/smallalc.nim
@@ -0,0 +1,19 @@
+# Handle small allocations efficiently
+# We allocate and manage memory by pages. All objects within a page belong to
+# the same type. Thus, we safe the type field. Minimum requested block is
+# 8 bytes. Alignment is 8 bytes. 
+
+
+type
+  TChunk {.pure.} = object
+    kind: TChunkKind
+    prev, next: ptr TChunk
+    
+  TSmallChunk = object of TChunk # all objects of the same size
+    typ: PNimType
+    free: int
+    data: array [0.., int]
+  
+proc allocSmall(typ: PNimType): pointer =
+  
+  
\ No newline at end of file
diff --git a/lib/strtabs.nim b/lib/strtabs.nim
new file mode 100644
index 000000000..dd57fdd17
--- /dev/null
+++ b/lib/strtabs.nim
@@ -0,0 +1,210 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2008 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+##  The ``strtabs`` module implements an efficient hash table that is a mapping
+##  from strings to strings. Supports a case-sensitive, case-insensitive and
+##  style-insensitive mode. An efficient string substitution operator  ``%``
+##  for the string table is also provided.
+  
+import 
+  os, hashes, strutils
+
+type 
+  TStringTableMode* = enum    # describes the tables operation mode
+    modeCaseSensitive,        # the table is case sensitive
+    modeCaseInsensitive,      # the table is case insensitive
+    modeStyleInsensitive      # the table is style insensitive
+  TKeyValuePair = tuple[key, val: string]
+  TKeyValuePairSeq = seq[TKeyValuePair]
+  TStringTable* = object of TObject
+    counter: int
+    data: TKeyValuePairSeq
+    mode: TStringTableMode
+
+  PStringTable* = ref TStringTable ## use this type to declare string tables
+
+proc newStringTable*(keyValuePairs: openarray[string], 
+                     mode: TStringTableMode = modeCaseSensitive): PStringTable
+  ## creates a new string table with given key value pairs.
+  ## Example::
+  ##   var mytab = newStringTable("key1", "val1", "key2", "val2", 
+  ##                              modeCaseInsensitive)
+
+proc newStringTable*(mode: TStringTableMode = modeCaseSensitive): PStringTable
+  ## creates a new string table that is empty.
+                     
+proc `[]=`*(t: PStringTable, key, val: string)
+  ## puts a (key, value)-pair into `t`.
+
+proc `[]`*(t: PStringTable, key: string): string
+  ## retrieves the value at ``t[key]``. If `key` is not in `t`, "" is returned
+  ## and no exception is raised. One can check with ``hasKey`` whether the key
+  ## exists.
+
+proc hasKey*(t: PStringTable, key: string): bool
+  ## returns true iff `key` is in the table `t`.
+
+proc len*(t: PStringTable): int =
+  ## returns the number of keys in `t`.
+  result = t.counter
+
+iterator pairs*(t: PStringTable): tuple[key, value: string] = 
+  ## iterates over any (key, value) pair in the table `t`.
+  for h in 0..high(t.data):
+    if not isNil(t.data[h].key):
+      yield (t.data[h].key, t.data[h].val)
+
+type 
+  TFormatFlag* = enum         # flags for the `%` operator
+    useEnvironment,           # use environment variable if the ``$key``
+                              # is not found in the table
+    useEmpty,                 # use the empty string as a default, thus it
+                              # won't throw an exception if ``$key`` is not
+                              # in the table
+    useKey                    # do not replace ``$key`` if it is not found
+                              # in the table (or in the environment)
+
+proc `%`*(f: string, t: PStringTable, flags: set[TFormatFlag] = {}): string
+  ## The `%` operator for string tables.
+
+# implementation
+
+const 
+  growthFactor = 2
+  startSize = 64
+
+proc newStringTable(mode: TStringTableMode = modeCaseSensitive): PStringTable = 
+  new(result)
+  result.mode = mode
+  result.counter = 0
+  result.data = []
+  setlen(result.data, startSize) # XXX
+
+proc newStringTable(keyValuePairs: openarray[string], 
+                    mode: TStringTableMode = modeCaseSensitive): PStringTable = 
+  result = newStringTable(mode)
+  var i = 0
+  while i < high(keyValuePairs): 
+    result[keyValuePairs[i]] = keyValuePairs[i + 1]
+    inc(i, 2)
+
+proc myhash(t: PStringTable, key: string): THash = 
+  case t.mode
+  of modeCaseSensitive: result = hashes.hash(key)
+  of modeCaseInsensitive: result = hashes.hashIgnoreCase(key)
+  of modeStyleInsensitive: result = hashes.hashIgnoreStyle(key)
+  
+proc myCmp(t: PStringTable, a, b: string): bool = 
+  case t.mode
+  of modeCaseSensitive: result = cmp(a, b) == 0
+  of modeCaseInsensitive: result = cmpIgnoreCase(a, b) == 0
+  of modeStyleInsensitive: result = cmpIgnoreStyle(a, b) == 0
+  
+proc mustRehash(length, counter: int): bool = 
+  assert(length > counter)
+  result = (length * 2 < counter * 3) or (length - counter < 4)
+
+const 
+  EmptySeq = []
+
+proc nextTry(h, maxHash: THash): THash = 
+  result = ((5 * h) + 1) and maxHash # For any initial h in range(maxHash), repeating that maxHash times
+                                     # generates each int in range(maxHash) exactly once (see any text on
+                                     # random-number generation for proof).
+  
+proc RawGet(t: PStringTable, key: string): int = 
+  var h: THash
+  h = myhash(t, key) and high(t.data) # start with real hash value
+  while not isNil(t.data[h].key): 
+    if mycmp(t, t.data[h].key, key): 
+      return h
+    h = nextTry(h, high(t.data))
+  result = - 1
+
+proc `[]`(t: PStringTable, key: string): string = 
+  var index: int
+  index = RawGet(t, key)
+  if index >= 0: result = t.data[index].val
+  else: result = ""
+  
+proc hasKey(t: PStringTable, key: string): bool = 
+  result = rawGet(t, key) >= 0
+
+proc RawInsert(t: PStringTable, data: var TKeyValuePairSeq, key, val: string) = 
+  var h: THash
+  h = myhash(t, key) and high(data)
+  while not isNil(data[h].key): 
+    h = nextTry(h, high(data))
+  data[h].key = key
+  data[h].val = val
+
+proc Enlarge(t: PStringTable) = 
+  var n: TKeyValuePairSeq
+  n = emptySeq
+  setlen(n, len(t.data) * growthFactor)
+  for i in countup(0, high(t.data)): 
+    if not isNil(t.data[i].key): RawInsert(t, n, t.data[i].key, t.data[i].val)
+  swap(t.data, n)
+
+proc `[]=`(t: PStringTable, key, val: string) = 
+  var index = RawGet(t, key)
+  if index >= 0: 
+    t.data[index].val = val
+  else: 
+    if mustRehash(len(t.data), t.counter): Enlarge(t)
+    RawInsert(t, t.data, key, val)
+    inc(t.counter)
+
+proc RaiseFormatException(s: string) = 
+  var e: ref EInvalidValue
+  new(e)
+  e.msg = "format string: key not found: " & s
+  raise e
+
+proc getValue(t: PStringTable, flags: set[TFormatFlag], key: string): string = 
+  if hasKey(t, key): return t[key]
+  if useEnvironment in flags: result = os.getEnv(key)
+  else: result = ""
+  if (result == ""): 
+    if useKey in flags: result = '$' & key
+    elif not (useEmpty in flags): raiseFormatException(key)
+  
+proc `%`(f: string, t: PStringTable, flags: set[TFormatFlag] = {}): string = 
+  const 
+    PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF'}
+  var 
+    i, j: int
+    key: string
+  result = ""
+  i = strStart
+  while i <= len(f) + strStart - 1: 
+    if f[i] == '$': 
+      case f[i + 1]
+      of '$': 
+        add(result, '$')
+        inc(i, 2)
+      of '{': 
+        j = i + 1
+        while (j <= len(f) + strStart - 1) and (f[j] != '}'): inc(j)
+        key = copy(f, i + 2, j - 1)
+        result = result & getValue(t, flags, key)
+        i = j + 1
+      of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '_': 
+        j = i + 1
+        while (j <= len(f) + strStart - 1) and (f[j] in PatternChars): inc(j)
+        key = copy(f, i+1, j - 1)
+        result = result & getValue(t, flags, key)
+        i = j
+      else: 
+        add(result, f[i])
+        inc(i)
+    else: 
+      add(result, f[i])
+      inc(i)
+  
diff --git a/lib/tinalloc.nim b/lib/tinalloc.nim
new file mode 100644
index 000000000..27a1e0b00
--- /dev/null
+++ b/lib/tinalloc.nim
@@ -0,0 +1,72 @@
+# Memory handling for small objects
+
+const
+  minRequestSize = 2 * sizeof(pointer) # minimal block is 16 bytes
+  pageSize = 1024 * sizeof(int)
+  pageBits = pageSize div minRequestSize
+  pageMask = pageSize-1
+
+  bitarraySize = pageBits div (sizeof(int)*8)
+  dataSize = pageSize - (bitarraySize+6) * sizeof(pointer)
+
+type
+  TMinRequest {.final.} = object
+    next, prev: ptr TMinRequest  # stores next free bit
+
+  TChunk {.pure.} = object # a chunk manages at least a page
+    size: int              # lowest bit signals if it is a small chunk (0) or
+                           # a big chunk (1)
+    typ: PNimType
+    next, prev: ptr TChunk
+    nextOfSameType: ptr TChunk
+
+  TSmallChunk = object of TChunk ## manages pageSize bytes for a type and a 
+                                 ## fixed size
+    free: int                    ## index of first free bit
+    bits: array[0..bitarraySize-1, int]
+    data: array[0..dataSize div minRequestSize - 1, TMinRequest]
+  
+  PSmallChunk = ptr TSmallChunk
+
+assert(sizeof(TSmallChunk) == pageSize)
+
+proc getNewChunk(size: int, typ: PNimType): PSmallChunk =
+  result = cast[PSmallChunk](getPages(1))
+  result.size = PageSize
+  result.typ = typ
+  result.next = chunkHead
+  result.prev = nil
+  chunkHead.prev = result
+  chunkHead = result.next
+  result.nextOfSameType = cast[PSmallChunk](typ.chunk)
+  typ.chunk = result
+  result.free = addr(result.data[0])
+  result.data[0].next = addr(result.data[1])
+  result.data[0].prev = nil
+  result.data[high(result.data)].next = nil
+  result.data[high(result.data)].prev = addr(result.data[high(result.data)-1])
+  for i in 1..high(result.data)-1:
+    result.data[i].next = addr(result.data[i+1])
+    result.data[i].prev = addr(result.data[i-1])
+
+proc newSmallObj(size: int, typ: PNimType): pointer =
+  var chunk = cast[PSmallChunk](typ.chunk)
+  if chunk == nil or chunk.free <= 0: 
+    if chunk.free < 0: GC_collect()
+    chunk = getNewChunk(size, typ)
+    chunk.nextOfSameType = typ.chunk
+    typ.chunk = chunk
+  var idx = chunk.free
+  setBit(chunk.bits[idx /% bitarraySize], idx %% bitarraySize)
+  result = cast[pointer](cast[TAddress](addr(chunk.data)) + 
+                        minRequestSize * idx)
+  var res = cast[PMinRequest](result)
+  chunk.free = res.next
+  res.next
+  
+proc freeObj(obj: pointer) = 
+  var chunk = cast[PChunk](cast[TAddress(obj) and not pageMask)
+  if size and 1 == 0: # small chunk  
+    var idx = (cast[TAddress](obj) shr pageShift) div minRequestSize
+    resetBit(chunk.bits[idx /% bitarraySize], idx %% bitarraySize)
+  
diff --git a/lib/wz_jsgraphics.js b/lib/wz_jsgraphics.js
new file mode 100644
index 000000000..f4ba47b53
--- /dev/null
+++ b/lib/wz_jsgraphics.js
@@ -0,0 +1,1107 @@
+/* This notice must be untouched at all times.

+

+wz_jsgraphics.js    v. 3.03

+The latest version is available at

+http://www.walterzorn.com

+or http://www.devira.com

+or http://www.walterzorn.de

+

+Copyright (c) 2002-2004 Walter Zorn. All rights reserved.

+Created 3. 11. 2002 by Walter Zorn (Web: http://www.walterzorn.com )

+Last modified: 28. 1. 2008

+

+Performance optimizations for Internet Explorer

+by Thomas Frank and John Holdsworth.

+fillPolygon method implemented by Matthieu Haller.

+

+High Performance JavaScript Graphics Library.

+Provides methods

+- to draw lines, rectangles, ellipses, polygons

+  with specifiable line thickness,

+- to fill rectangles, polygons, ellipses and arcs

+- to draw text.

+NOTE: Operations, functions and branching have rather been optimized

+to efficiency and speed than to shortness of source code.

+

+LICENSE: LGPL

+

+This library is free software; you can redistribute it and/or

+modify it under the terms of the GNU Lesser General Public

+License (LGPL) as published by the Free Software Foundation; either

+version 2.1 of the License, or (at your option) any later version.

+

+This library is distributed in the hope that it will be useful,

+but WITHOUT ANY WARRANTY; without even the implied warranty of

+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

+Lesser General Public License for more details.

+

+You should have received a copy of the GNU Lesser General Public

+License along with this library; if not, write to the Free Software

+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA,

+or see http://www.gnu.org/copyleft/lesser.html

+*/

+

+

+var jg_ok, jg_ie, jg_fast, jg_dom, jg_moz;

+

+

+function _chkDHTM(x, i)

+{

+  x = document.body || null;

+  jg_ie = x && typeof x.insertAdjacentHTML != "undefined" && document.createElement;

+  jg_dom = (x && !jg_ie &&

+    typeof x.appendChild != "undefined" &&

+    typeof document.createRange != "undefined" &&

+    typeof (i = document.createRange()).setStartBefore != "undefined" &&

+    typeof i.createContextualFragment != "undefined");

+  jg_fast = jg_ie && document.all && !window.opera;

+  jg_moz = jg_dom && typeof x.style.MozOpacity != "undefined";

+  jg_ok = !!(jg_ie || jg_dom);

+}

+

+function _pntCnvDom()

+{

+  var x = this.wnd.document.createRange();

+  x.setStartBefore(this.cnv);

+  x = x.createContextualFragment(jg_fast? this._htmRpc() : this.htm);

+  if(this.cnv) this.cnv.appendChild(x);

+  this.htm = "";

+}

+

+function _pntCnvIe()

+{

+  if(this.cnv) this.cnv.insertAdjacentHTML("BeforeEnd", jg_fast? this._htmRpc() : this.htm);

+  this.htm = "";

+}

+

+function _pntDoc()

+{

+  this.wnd.document.write(jg_fast? this._htmRpc() : this.htm);

+  this.htm = '';

+}

+

+function _pntN()

+{

+  ;

+}

+

+function _mkDiv(x, y, w, h)

+{

+  this.htm += '<div style="position:absolute;'+

+    'left:' + x + 'px;'+

+    'top:' + y + 'px;'+

+    'width:' + w + 'px;'+

+    'height:' + h + 'px;'+

+    'clip:rect(0,'+w+'px,'+h+'px,0);'+

+    'background-color:' + this.color +

+    (!jg_moz? ';overflow:hidden' : '')+

+    ';"><\/div>';

+}

+

+function _mkDivIe(x, y, w, h)

+{

+  this.htm += '%%'+this.color+';'+x+';'+y+';'+w+';'+h+';';

+}

+

+function _mkDivPrt(x, y, w, h)

+{

+  this.htm += '<div style="position:absolute;'+

+    'border-left:' + w + 'px solid ' + this.color + ';'+

+    'left:' + x + 'px;'+

+    'top:' + y + 'px;'+

+    'width:0px;'+

+    'height:' + h + 'px;'+

+    'clip:rect(0,'+w+'px,'+h+'px,0);'+

+    'background-color:' + this.color +

+    (!jg_moz? ';overflow:hidden' : '')+

+    ';"><\/div>';

+}

+

+var _regex =  /%%([^;]+);([^;]+);([^;]+);([^;]+);([^;]+);/g;

+function _htmRpc()

+{

+  return this.htm.replace(

+    _regex,

+    '<div style="overflow:hidden;position:absolute;background-color:'+

+    '$1;left:$2;top:$3;width:$4;height:$5"></div>\n');

+}

+

+function _htmPrtRpc()

+{

+  return this.htm.replace(

+    _regex,

+    '<div style="overflow:hidden;position:absolute;background-color:'+

+    '$1;left:$2;top:$3;width:$4;height:$5;border-left:$4px solid $1"></div>\n');

+}

+

+function _mkLin(x1, y1, x2, y2)

+{

+  if(x1 > x2)

+  {

+    var _x2 = x2;

+    var _y2 = y2;

+    x2 = x1;

+    y2 = y1;

+    x1 = _x2;

+    y1 = _y2;

+  }

+  var dx = x2-x1, dy = Math.abs(y2-y1),

+  x = x1, y = y1,

+  yIncr = (y1 > y2)? -1 : 1;

+

+  if(dx >= dy)

+  {

+    var pr = dy<<1,

+    pru = pr - (dx<<1),

+    p = pr-dx,

+    ox = x;

+    while(dx > 0)

+    {--dx;

+      ++x;

+      if(p > 0)

+      {

+        this._mkDiv(ox, y, x-ox, 1);

+        y += yIncr;

+        p += pru;

+        ox = x;

+      }

+      else p += pr;

+    }

+    this._mkDiv(ox, y, x2-ox+1, 1);

+  }

+

+  else

+  {

+    var pr = dx<<1,

+    pru = pr - (dy<<1),

+    p = pr-dy,

+    oy = y;

+    if(y2 <= y1)

+    {

+      while(dy > 0)

+      {--dy;

+        if(p > 0)

+        {

+          this._mkDiv(x++, y, 1, oy-y+1);

+          y += yIncr;

+          p += pru;

+          oy = y;

+        }

+        else

+        {

+          y += yIncr;

+          p += pr;

+        }

+      }

+      this._mkDiv(x2, y2, 1, oy-y2+1);

+    }

+    else

+    {

+      while(dy > 0)

+      {--dy;

+        y += yIncr;

+        if(p > 0)

+        {

+          this._mkDiv(x++, oy, 1, y-oy);

+          p += pru;

+          oy = y;

+        }

+        else p += pr;

+      }

+      this._mkDiv(x2, oy, 1, y2-oy+1);

+    }

+  }

+}

+

+function _mkLin2D(x1, y1, x2, y2)

+{

+  if(x1 > x2)

+  {

+    var _x2 = x2;

+    var _y2 = y2;

+    x2 = x1;

+    y2 = y1;

+    x1 = _x2;

+    y1 = _y2;

+  }

+  var dx = x2-x1, dy = Math.abs(y2-y1),

+  x = x1, y = y1,

+  yIncr = (y1 > y2)? -1 : 1;

+

+  var s = this.stroke;

+  if(dx >= dy)

+  {

+    if(dx > 0 && s-3 > 0)

+    {

+      var _s = (s*dx*Math.sqrt(1+dy*dy/(dx*dx))-dx-(s>>1)*dy) / dx;

+      _s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;

+    }

+    else var _s = s;

+    var ad = Math.ceil(s/2);

+

+    var pr = dy<<1,

+    pru = pr - (dx<<1),

+    p = pr-dx,

+    ox = x;

+    while(dx > 0)

+    {--dx;

+      ++x;

+      if(p > 0)

+      {

+        this._mkDiv(ox, y, x-ox+ad, _s);

+        y += yIncr;

+        p += pru;

+        ox = x;

+      }

+      else p += pr;

+    }

+    this._mkDiv(ox, y, x2-ox+ad+1, _s);

+  }

+

+  else

+  {

+    if(s-3 > 0)

+    {

+      var _s = (s*dy*Math.sqrt(1+dx*dx/(dy*dy))-(s>>1)*dx-dy) / dy;

+      _s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;

+    }

+    else var _s = s;

+    var ad = Math.round(s/2);

+

+    var pr = dx<<1,

+    pru = pr - (dy<<1),

+    p = pr-dy,

+    oy = y;

+    if(y2 <= y1)

+    {

+      ++ad;

+      while(dy > 0)

+      {--dy;

+        if(p > 0)

+        {

+          this._mkDiv(x++, y, _s, oy-y+ad);

+          y += yIncr;

+          p += pru;

+          oy = y;

+        }

+        else

+        {

+          y += yIncr;

+          p += pr;

+        }

+      }

+      this._mkDiv(x2, y2, _s, oy-y2+ad);

+    }

+    else

+    {

+      while(dy > 0)

+      {--dy;

+        y += yIncr;

+        if(p > 0)

+        {

+          this._mkDiv(x++, oy, _s, y-oy+ad);

+          p += pru;

+          oy = y;

+        }

+        else p += pr;

+      }

+      this._mkDiv(x2, oy, _s, y2-oy+ad+1);

+    }

+  }

+}

+

+function _mkLinDott(x1, y1, x2, y2)

+{

+  if(x1 > x2)

+  {

+    var _x2 = x2;

+    var _y2 = y2;

+    x2 = x1;

+    y2 = y1;

+    x1 = _x2;

+    y1 = _y2;

+  }

+  var dx = x2-x1, dy = Math.abs(y2-y1),

+  x = x1, y = y1,

+  yIncr = (y1 > y2)? -1 : 1,

+  drw = true;

+  if(dx >= dy)

+  {

+    var pr = dy<<1,

+    pru = pr - (dx<<1),

+    p = pr-dx;

+    while(dx > 0)

+    {--dx;

+      if(drw) this._mkDiv(x, y, 1, 1);

+      drw = !drw;

+      if(p > 0)

+      {

+        y += yIncr;

+        p += pru;

+      }

+      else p += pr;

+      ++x;

+    }

+  }

+  else

+  {

+    var pr = dx<<1,

+    pru = pr - (dy<<1),

+    p = pr-dy;

+    while(dy > 0)

+    {--dy;

+      if(drw) this._mkDiv(x, y, 1, 1);

+      drw = !drw;

+      y += yIncr;

+      if(p > 0)

+      {

+        ++x;

+        p += pru;

+      }

+      else p += pr;

+    }

+  }

+  if(drw) this._mkDiv(x, y, 1, 1);

+}

+

+function _mkOv(left, top, width, height)

+{

+  var a = (++width)>>1, b = (++height)>>1,

+  wod = width&1, hod = height&1,

+  cx = left+a, cy = top+b,

+  x = 0, y = b,

+  ox = 0, oy = b,

+  aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,

+  st = (aa2>>1)*(1-(b<<1)) + bb2,

+  tt = (bb2>>1) - aa2*((b<<1)-1),

+  w, h;

+  while(y > 0)

+  {

+    if(st < 0)

+    {

+      st += bb2*((x<<1)+3);

+      tt += bb4*(++x);

+    }

+    else if(tt < 0)

+    {

+      st += bb2*((x<<1)+3) - aa4*(y-1);

+      tt += bb4*(++x) - aa2*(((y--)<<1)-3);

+      w = x-ox;

+      h = oy-y;

+      if((w&2) && (h&2))

+      {

+        this._mkOvQds(cx, cy, x-2, y+2, 1, 1, wod, hod);

+        this._mkOvQds(cx, cy, x-1, y+1, 1, 1, wod, hod);

+      }

+      else this._mkOvQds(cx, cy, x-1, oy, w, h, wod, hod);

+      ox = x;

+      oy = y;

+    }

+    else

+    {

+      tt -= aa2*((y<<1)-3);

+      st -= aa4*(--y);

+    }

+  }

+  w = a-ox+1;

+  h = (oy<<1)+hod;

+  y = cy-oy;

+  this._mkDiv(cx-a, y, w, h);

+  this._mkDiv(cx+ox+wod-1, y, w, h);

+}

+

+function _mkOv2D(left, top, width, height)

+{

+  var s = this.stroke;

+  width += s+1;

+  height += s+1;

+  var a = width>>1, b = height>>1,

+  wod = width&1, hod = height&1,

+  cx = left+a, cy = top+b,

+  x = 0, y = b,

+  aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,

+  st = (aa2>>1)*(1-(b<<1)) + bb2,

+  tt = (bb2>>1) - aa2*((b<<1)-1);

+

+  if(s-4 < 0 && (!(s-2) || width-51 > 0 && height-51 > 0))

+  {

+    var ox = 0, oy = b,

+    w, h,

+    pxw;

+    while(y > 0)

+    {

+      if(st < 0)

+      {

+        st += bb2*((x<<1)+3);

+        tt += bb4*(++x);

+      }

+      else if(tt < 0)

+      {

+        st += bb2*((x<<1)+3) - aa4*(y-1);

+        tt += bb4*(++x) - aa2*(((y--)<<1)-3);

+        w = x-ox;

+        h = oy-y;

+

+        if(w-1)

+        {

+          pxw = w+1+(s&1);

+          h = s;

+        }

+        else if(h-1)

+        {

+          pxw = s;

+          h += 1+(s&1);

+        }

+        else pxw = h = s;

+        this._mkOvQds(cx, cy, x-1, oy, pxw, h, wod, hod);

+        ox = x;

+        oy = y;

+      }

+      else

+      {

+        tt -= aa2*((y<<1)-3);

+        st -= aa4*(--y);

+      }

+    }

+    this._mkDiv(cx-a, cy-oy, s, (oy<<1)+hod);

+    this._mkDiv(cx+a+wod-s, cy-oy, s, (oy<<1)+hod);

+  }

+

+  else

+  {

+    var _a = (width-(s<<1))>>1,

+    _b = (height-(s<<1))>>1,

+    _x = 0, _y = _b,

+    _aa2 = (_a*_a)<<1, _aa4 = _aa2<<1, _bb2 = (_b*_b)<<1, _bb4 = _bb2<<1,

+    _st = (_aa2>>1)*(1-(_b<<1)) + _bb2,

+    _tt = (_bb2>>1) - _aa2*((_b<<1)-1),

+

+    pxl = new Array(),

+    pxt = new Array(),

+    _pxb = new Array();

+    pxl[0] = 0;

+    pxt[0] = b;

+    _pxb[0] = _b-1;

+    while(y > 0)

+    {

+      if(st < 0)

+      {

+        pxl[pxl.length] = x;

+        pxt[pxt.length] = y;

+        st += bb2*((x<<1)+3);

+        tt += bb4*(++x);

+      }

+      else if(tt < 0)

+      {

+        pxl[pxl.length] = x;

+        st += bb2*((x<<1)+3) - aa4*(y-1);

+        tt += bb4*(++x) - aa2*(((y--)<<1)-3);

+        pxt[pxt.length] = y;

+      }

+      else

+      {

+        tt -= aa2*((y<<1)-3);

+        st -= aa4*(--y);

+      }

+

+      if(_y > 0)

+      {

+        if(_st < 0)

+        {

+          _st += _bb2*((_x<<1)+3);

+          _tt += _bb4*(++_x);

+          _pxb[_pxb.length] = _y-1;

+        }

+        else if(_tt < 0)

+        {

+          _st += _bb2*((_x<<1)+3) - _aa4*(_y-1);

+          _tt += _bb4*(++_x) - _aa2*(((_y--)<<1)-3);

+          _pxb[_pxb.length] = _y-1;

+        }

+        else

+        {

+          _tt -= _aa2*((_y<<1)-3);

+          _st -= _aa4*(--_y);

+          _pxb[_pxb.length-1]--;

+        }

+      }

+    }

+

+    var ox = -wod, oy = b,

+    _oy = _pxb[0],

+    l = pxl.length,

+    w, h;

+    for(var i = 0; i < l; i++)

+    {

+      if(typeof _pxb[i] != "undefined")

+      {

+        if(_pxb[i] < _oy || pxt[i] < oy)

+        {

+          x = pxl[i];

+          this._mkOvQds(cx, cy, x, oy, x-ox, oy-_oy, wod, hod);

+          ox = x;

+          oy = pxt[i];

+          _oy = _pxb[i];

+        }

+      }

+      else

+      {

+        x = pxl[i];

+        this._mkDiv(cx-x, cy-oy, 1, (oy<<1)+hod);

+        this._mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);

+        ox = x;

+        oy = pxt[i];

+      }

+    }

+    this._mkDiv(cx-a, cy-oy, 1, (oy<<1)+hod);

+    this._mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);

+  }

+}

+

+function _mkOvDott(left, top, width, height)

+{

+  var a = (++width)>>1, b = (++height)>>1,

+  wod = width&1, hod = height&1, hodu = hod^1,

+  cx = left+a, cy = top+b,

+  x = 0, y = b,

+  aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,

+  st = (aa2>>1)*(1-(b<<1)) + bb2,

+  tt = (bb2>>1) - aa2*((b<<1)-1),

+  drw = true;

+  while(y > 0)

+  {

+    if(st < 0)

+    {

+      st += bb2*((x<<1)+3);

+      tt += bb4*(++x);

+    }

+    else if(tt < 0)

+    {

+      st += bb2*((x<<1)+3) - aa4*(y-1);

+      tt += bb4*(++x) - aa2*(((y--)<<1)-3);

+    }

+    else

+    {

+      tt -= aa2*((y<<1)-3);

+      st -= aa4*(--y);

+    }

+    if(drw && y >= hodu) this._mkOvQds(cx, cy, x, y, 1, 1, wod, hod);

+    drw = !drw;

+  }

+}

+

+function _mkRect(x, y, w, h)

+{

+  var s = this.stroke;

+  this._mkDiv(x, y, w, s);

+  this._mkDiv(x+w, y, s, h);

+  this._mkDiv(x, y+h, w+s, s);

+  this._mkDiv(x, y+s, s, h-s);

+}

+

+function _mkRectDott(x, y, w, h)

+{

+  this.drawLine(x, y, x+w, y);

+  this.drawLine(x+w, y, x+w, y+h);

+  this.drawLine(x, y+h, x+w, y+h);

+  this.drawLine(x, y, x, y+h);

+}

+

+function jsgFont()

+{

+  this.PLAIN = 'font-weight:normal;';

+  this.BOLD = 'font-weight:bold;';

+  this.ITALIC = 'font-style:italic;';

+  this.ITALIC_BOLD = this.ITALIC + this.BOLD;

+  this.BOLD_ITALIC = this.ITALIC_BOLD;

+}

+var Font = new jsgFont();

+

+function jsgStroke()

+{

+  this.DOTTED = -1;

+}

+var Stroke = new jsgStroke();

+

+function jsGraphics(cnv, wnd)

+{

+  this.setColor = function(x)

+  {

+    this.color = x.toLowerCase();

+  };

+

+  this.setStroke = function(x)

+  {

+    this.stroke = x;

+    if(!(x+1))

+    {

+      this.drawLine = _mkLinDott;

+      this._mkOv = _mkOvDott;

+      this.drawRect = _mkRectDott;

+    }

+    else if(x-1 > 0)

+    {

+      this.drawLine = _mkLin2D;

+      this._mkOv = _mkOv2D;

+      this.drawRect = _mkRect;

+    }

+    else

+    {

+      this.drawLine = _mkLin;

+      this._mkOv = _mkOv;

+      this.drawRect = _mkRect;

+    }

+  };

+

+  this.setPrintable = function(arg)

+  {

+    this.printable = arg;

+    if(jg_fast)

+    {

+      this._mkDiv = _mkDivIe;

+      this._htmRpc = arg? _htmPrtRpc : _htmRpc;

+    }

+    else this._mkDiv = arg? _mkDivPrt : _mkDiv;

+  };

+

+  this.setFont = function(fam, sz, sty)

+  {

+    this.ftFam = fam;

+    this.ftSz = sz;

+    this.ftSty = sty || Font.PLAIN;

+  };

+

+  this.drawPolyline = this.drawPolyLine = function(x, y)

+  {

+    for (var i=x.length - 1; i;)

+    {--i;

+      this.drawLine(x[i], y[i], x[i+1], y[i+1]);

+    }

+  };

+

+  this.fillRect = function(x, y, w, h)

+  {

+    this._mkDiv(x, y, w, h);

+  };

+

+  this.drawPolygon = function(x, y)

+  {

+    this.drawPolyline(x, y);

+    this.drawLine(x[x.length-1], y[x.length-1], x[0], y[0]);

+  };

+

+  this.drawEllipse = this.drawOval = function(x, y, w, h)

+  {

+    this._mkOv(x, y, w, h);

+  };

+

+  this.fillEllipse = this.fillOval = function(left, top, w, h)

+  {

+    var a = w>>1, b = h>>1,

+    wod = w&1, hod = h&1,

+    cx = left+a, cy = top+b,

+    x = 0, y = b, oy = b,

+    aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,

+    st = (aa2>>1)*(1-(b<<1)) + bb2,

+    tt = (bb2>>1) - aa2*((b<<1)-1),

+    xl, dw, dh;

+    if(w) while(y > 0)

+    {

+      if(st < 0)

+      {

+        st += bb2*((x<<1)+3);

+        tt += bb4*(++x);

+      }

+      else if(tt < 0)

+      {

+        st += bb2*((x<<1)+3) - aa4*(y-1);

+        xl = cx-x;

+        dw = (x<<1)+wod;

+        tt += bb4*(++x) - aa2*(((y--)<<1)-3);

+        dh = oy-y;

+        this._mkDiv(xl, cy-oy, dw, dh);

+        this._mkDiv(xl, cy+y+hod, dw, dh);

+        oy = y;

+      }

+      else

+      {

+        tt -= aa2*((y<<1)-3);

+        st -= aa4*(--y);

+      }

+    }

+    this._mkDiv(cx-a, cy-oy, w, (oy<<1)+hod);

+  };

+

+  this.fillArc = function(iL, iT, iW, iH, fAngA, fAngZ)

+  {

+    var a = iW>>1, b = iH>>1,

+    iOdds = (iW&1) | ((iH&1) << 16),

+    cx = iL+a, cy = iT+b,

+    x = 0, y = b, ox = x, oy = y,

+    aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,

+    st = (aa2>>1)*(1-(b<<1)) + bb2,

+    tt = (bb2>>1) - aa2*((b<<1)-1),

+    // Vars for radial boundary lines

+    xEndA, yEndA, xEndZ, yEndZ,

+    iSects = (1 << (Math.floor((fAngA %= 360.0)/180.0) << 3))

+        | (2 << (Math.floor((fAngZ %= 360.0)/180.0) << 3))

+        | ((fAngA >= fAngZ) << 16),

+    aBndA = new Array(b+1), aBndZ = new Array(b+1);

+    

+    // Set up radial boundary lines

+    fAngA *= Math.PI/180.0;

+    fAngZ *= Math.PI/180.0;

+    xEndA = cx+Math.round(a*Math.cos(fAngA));

+    yEndA = cy+Math.round(-b*Math.sin(fAngA));

+    _mkLinVirt(aBndA, cx, cy, xEndA, yEndA);

+    xEndZ = cx+Math.round(a*Math.cos(fAngZ));

+    yEndZ = cy+Math.round(-b*Math.sin(fAngZ));

+    _mkLinVirt(aBndZ, cx, cy, xEndZ, yEndZ);

+

+    while(y > 0)

+    {

+      if(st < 0) // Advance x

+      {

+        st += bb2*((x<<1)+3);

+        tt += bb4*(++x);

+      }

+      else if(tt < 0) // Advance x and y

+      {

+        st += bb2*((x<<1)+3) - aa4*(y-1);

+        ox = x;

+        tt += bb4*(++x) - aa2*(((y--)<<1)-3);

+        this._mkArcDiv(ox, y, oy, cx, cy, iOdds, aBndA, aBndZ, iSects);

+        oy = y;

+      }

+      else // Advance y

+      {

+        tt -= aa2*((y<<1)-3);

+        st -= aa4*(--y);

+        if(y && (aBndA[y] != aBndA[y-1] || aBndZ[y] != aBndZ[y-1]))

+        {

+          this._mkArcDiv(x, y, oy, cx, cy, iOdds, aBndA, aBndZ, iSects);

+          ox = x;

+          oy = y;

+        }

+      }

+    }

+    this._mkArcDiv(x, 0, oy, cx, cy, iOdds, aBndA, aBndZ, iSects);

+    if(iOdds >> 16) // Odd height

+    {

+      if(iSects >> 16) // Start-angle > end-angle

+      {

+        var xl = (yEndA <= cy || yEndZ > cy)? (cx - x) : cx;

+        this._mkDiv(xl, cy, x + cx - xl + (iOdds & 0xffff), 1);

+      }

+      else if((iSects & 0x01) && yEndZ > cy)

+        this._mkDiv(cx - x, cy, x, 1);

+    }

+  };

+

+/* fillPolygon method, implemented by Matthieu Haller.

+This javascript function is an adaptation of the gdImageFilledPolygon for Walter Zorn lib.

+C source of GD 1.8.4 found at http://www.boutell.com/gd/

+

+THANKS to Kirsten Schulz for the polygon fixes!

+

+The intersection finding technique of this code could be improved

+by remembering the previous intertersection, and by using the slope.

+That could help to adjust intersections to produce a nice

+interior_extrema. */

+  this.fillPolygon = function(array_x, array_y)

+  {

+    var i;

+    var y;

+    var miny, maxy;

+    var x1, y1;

+    var x2, y2;

+    var ind1, ind2;

+    var ints;

+

+    var n = array_x.length;

+    if(!n) return;

+

+    miny = array_y[0];

+    maxy = array_y[0];

+    for(i = 1; i < n; i++)

+    {

+      if(array_y[i] < miny)

+        miny = array_y[i];

+

+      if(array_y[i] > maxy)

+        maxy = array_y[i];

+    }

+    for(y = miny; y <= maxy; y++)

+    {

+      var polyInts = new Array();

+      ints = 0;

+      for(i = 0; i < n; i++)

+      {

+        if(!i)

+        {

+          ind1 = n-1;

+          ind2 = 0;

+        }

+        else

+        {

+          ind1 = i-1;

+          ind2 = i;

+        }

+        y1 = array_y[ind1];

+        y2 = array_y[ind2];

+        if(y1 < y2)

+        {

+          x1 = array_x[ind1];

+          x2 = array_x[ind2];

+        }

+        else if(y1 > y2)

+        {

+          y2 = array_y[ind1];

+          y1 = array_y[ind2];

+          x2 = array_x[ind1];

+          x1 = array_x[ind2];

+        }

+        else continue;

+

+         //  Modified 11. 2. 2004 Walter Zorn

+        if((y >= y1) && (y < y2))

+          polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);

+

+        else if((y == maxy) && (y > y1) && (y <= y2))

+          polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);

+      }

+      polyInts.sort(_CompInt);

+      for(i = 0; i < ints; i+=2)

+        this._mkDiv(polyInts[i], y, polyInts[i+1]-polyInts[i]+1, 1);

+    }

+  };

+

+  this.drawString = function(txt, x, y)

+  {

+    this.htm += '<div style="position:absolute;white-space:nowrap;'+

+      'left:' + x + 'px;'+

+      'top:' + y + 'px;'+

+      'font-family:' +  this.ftFam + ';'+

+      'font-size:' + this.ftSz + ';'+

+      'color:' + this.color + ';' + this.ftSty + '">'+

+      txt +

+      '<\/div>';

+  };

+

+/* drawStringRect() added by Rick Blommers.

+Allows to specify the size of the text rectangle and to align the

+text both horizontally (e.g. right) and vertically within that rectangle */

+  this.drawStringRect = function(txt, x, y, width, halign)

+  {

+    this.htm += '<div style="position:absolute;overflow:hidden;'+

+      'left:' + x + 'px;'+

+      'top:' + y + 'px;'+

+      'width:'+width +'px;'+

+      'text-align:'+halign+';'+

+      'font-family:' +  this.ftFam + ';'+

+      'font-size:' + this.ftSz + ';'+

+      'color:' + this.color + ';' + this.ftSty + '">'+

+      txt +

+      '<\/div>';

+  };

+

+  this.drawImage = function(imgSrc, x, y, w, h, a)

+  {

+    this.htm += '<div style="position:absolute;'+

+      'left:' + x + 'px;'+

+      'top:' + y + 'px;'+

+      // w (width) and h (height) arguments are now optional.

+      // Added by Mahmut Keygubatli, 14.1.2008

+      (w? ('width:' +  w + 'px;') : '') +

+      (h? ('height:' + h + 'px;'):'')+'">'+

+      '<img src="' + imgSrc +'"'+ (w ? (' width="' + w + '"'):'')+ (h ? (' height="' + h + '"'):'') + (a? (' '+a) : '') + '>'+

+      '<\/div>';

+  };

+

+  this.clear = function()

+  {

+    this.htm = "";

+    if(this.cnv) this.cnv.innerHTML = "";

+  };

+

+  this._mkOvQds = function(cx, cy, x, y, w, h, wod, hod)

+  {

+    var xl = cx - x, xr = cx + x + wod - w, yt = cy - y, yb = cy + y + hod - h;

+    if(xr > xl+w)

+    {

+      this._mkDiv(xr, yt, w, h);

+      this._mkDiv(xr, yb, w, h);

+    }

+    else

+      w = xr - xl + w;

+    this._mkDiv(xl, yt, w, h);

+    this._mkDiv(xl, yb, w, h);

+  };

+  

+  this._mkArcDiv = function(x, y, oy, cx, cy, iOdds, aBndA, aBndZ, iSects)

+  {

+    var xrDef = cx + x + (iOdds & 0xffff), y2, h = oy - y, xl, xr, w;

+

+    if(!h) h = 1;

+    x = cx - x;

+

+    if(iSects & 0xff0000) // Start-angle > end-angle

+    {

+      y2 = cy - y - h;

+      if(iSects & 0x00ff)

+      {

+        if(iSects & 0x02)

+        {

+          xl = Math.max(x, aBndZ[y]);

+          w = xrDef - xl;

+          if(w > 0) this._mkDiv(xl, y2, w, h);

+        }

+        if(iSects & 0x01)

+        {

+          xr = Math.min(xrDef, aBndA[y]);

+          w = xr - x;

+          if(w > 0) this._mkDiv(x, y2, w, h);

+        }

+      }

+      else

+        this._mkDiv(x, y2, xrDef - x, h);

+      y2 = cy + y + (iOdds >> 16);

+      if(iSects & 0xff00)

+      {

+        if(iSects & 0x0100)

+        {

+          xl = Math.max(x, aBndA[y]);

+          w = xrDef - xl;

+          if(w > 0) this._mkDiv(xl, y2, w, h);

+        }

+        if(iSects & 0x0200)

+        {

+          xr = Math.min(xrDef, aBndZ[y]);

+          w = xr - x;

+          if(w > 0) this._mkDiv(x, y2, w, h);

+        }

+      }

+      else

+        this._mkDiv(x, y2, xrDef - x, h);

+    }

+    else

+    {

+      if(iSects & 0x00ff)

+      {

+        if(iSects & 0x02)

+          xl = Math.max(x, aBndZ[y]);

+        else

+          xl = x;

+        if(iSects & 0x01)

+          xr = Math.min(xrDef, aBndA[y]);

+        else

+          xr = xrDef;

+        y2 = cy - y - h;

+        w = xr - xl;

+        if(w > 0) this._mkDiv(xl, y2, w, h);

+      }

+      if(iSects & 0xff00)

+      {

+        if(iSects & 0x0100)

+          xl = Math.max(x, aBndA[y]);

+        else

+          xl = x;

+        if(iSects & 0x0200)

+          xr = Math.min(xrDef, aBndZ[y]);

+        else

+          xr = xrDef;

+        y2 = cy + y + (iOdds >> 16);

+        w = xr - xl;

+        if(w > 0) this._mkDiv(xl, y2, w, h);

+      }

+    }

+  };

+

+  this.setStroke(1);

+  this.setFont("verdana,geneva,helvetica,sans-serif", "12px", Font.PLAIN);

+  this.color = "#000000";

+  this.htm = "";

+  this.wnd = wnd || window;

+

+  if(!jg_ok) _chkDHTM();

+  if(jg_ok)

+  {

+    if(cnv)

+    {

+      if(typeof(cnv) == "string")

+        this.cont = document.all? (this.wnd.document.all[cnv] || null)

+          : document.getElementById? (this.wnd.document.getElementById(cnv) || null)

+          : null;

+      else if(cnv == window.document)

+        this.cont = document.getElementsByTagName("body")[0];

+      // If cnv is a direct reference to a canvas DOM node

+      // (option suggested by Andreas Luleich)

+      else this.cont = cnv;

+      // Create new canvas inside container DIV. Thus the drawing and clearing

+      // methods won't interfere with the container's inner html.

+      // Solution suggested by Vladimir.

+      this.cnv = this.wnd.document.createElement("div");

+      this.cnv.style.fontSize=0;

+      this.cont.appendChild(this.cnv);

+      this.paint = jg_dom? _pntCnvDom : _pntCnvIe;

+    }

+    else

+      this.paint = _pntDoc;

+  }

+  else

+    this.paint = _pntN;

+

+  this.setPrintable(false);

+}

+

+function _mkLinVirt(aLin, x1, y1, x2, y2)

+{

+  var dx = Math.abs(x2-x1), dy = Math.abs(y2-y1),

+  x = x1, y = y1,

+  xIncr = (x1 > x2)? -1 : 1,

+  yIncr = (y1 > y2)? -1 : 1,

+  p,

+  i = 0;

+  if(dx >= dy)

+  {

+    var pr = dy<<1,

+    pru = pr - (dx<<1);

+    p = pr-dx;

+    while(dx > 0)

+    {--dx;

+      if(p > 0)    //  Increment y

+      {

+        aLin[i++] = x;

+        y += yIncr;

+        p += pru;

+      }

+      else p += pr;

+      x += xIncr;

+    }

+  }

+  else

+  {

+    var pr = dx<<1,

+    pru = pr - (dy<<1);

+    p = pr-dy;

+    while(dy > 0)

+    {--dy;

+      y += yIncr;

+      aLin[i++] = x;

+      if(p > 0)    //  Increment x

+      {

+        x += xIncr;

+        p += pru;

+      }

+      else p += pr;

+    }

+  }

+  for(var len = aLin.length, i = len-i; i;)

+    aLin[len-(i--)] = x;

+};

+

+function _CompInt(x, y)

+{

+  return(x - y);

+}

+